<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:planet="http://planet.intertwingly.net/" xmlns:indexing="urn:atom-extension:indexing" indexing:index="no"><access:restriction xmlns:access="http://www.bloglines.com/about/specs/fac-1.0" relationship="deny"/>
  <title>Planet 5</title>
  <updated>2010-03-15T06:00:12Z</updated>
  <generator uri="http://intertwingly.net/code/venus/">Venus</generator>
  <author>
    <name>Uriel</name>
    <email>uriel99@gmail.com</email>
  </author>
  <id>http://planet5.cat-v.org/atom.xml</id>
  <link href="http://planet5.cat-v.org/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://planet5.cat-v.org" rel="alternate"/>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-3068200525784858253</id>
    <link href="http://reneefrench.blogspot.com/feeds/3068200525784858253/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=3068200525784858253" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/3068200525784858253" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/3068200525784858253" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/03/bahrain-10.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://3.bp.blogspot.com/_va9O40qIhaE/S5xjrv1qgLI/AAAAAAAACYI/1EZ_--jUrAg/s1600-h/hdaydogescsm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5448339252438532274" src="http://3.bp.blogspot.com/_va9O40qIhaE/S5xjrv1qgLI/AAAAAAAACYI/1EZ_--jUrAg/s320/hdaydogescsm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 258px; height: 320px;"/></a>bahrain 10<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-3068200525784858253?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-03-14T15:18:00Z</updated>
    <published>2010-03-14T15:18:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="f1 days"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="story z"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="tonal drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-8883876137037296834</id>
    <link href="http://reneefrench.blogspot.com/feeds/8883876137037296834/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=8883876137037296834" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/8883876137037296834" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/8883876137037296834" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/03/bahrain-quali-10.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://3.bp.blogspot.com/_va9O40qIhaE/S5wYcbEn87I/AAAAAAAACYA/0XV5KWlRIHs/s1600-h/citrover.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5448256525794014130" src="http://3.bp.blogspot.com/_va9O40qIhaE/S5wYcbEn87I/AAAAAAAACYA/0XV5KWlRIHs/s320/citrover.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 320px; height: 234px;"/></a><br/><div>bahrain quali 10</div><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-8883876137037296834?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-03-13T22:59:26Z</updated>
    <published>2010-03-13T22:57:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="f1 days"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="photographs"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-3554831124714595104</id>
    <link href="http://reneefrench.blogspot.com/feeds/3554831124714595104/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=3554831124714595104" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/3554831124714595104" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/3554831124714595104" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/03/lynde.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://1.bp.blogspot.com/_va9O40qIhaE/S5rYqYYTnKI/AAAAAAAACXo/zJmSepRgw_8/s1600-h/hdaydogpeeksm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5447904921868541090" src="http://1.bp.blogspot.com/_va9O40qIhaE/S5rYqYYTnKI/AAAAAAAACXo/zJmSepRgw_8/s320/hdaydogpeeksm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 257px; height: 320px;"/></a>lynde<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-3554831124714595104?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-03-13T00:14:14Z</updated>
    <published>2010-03-13T00:13:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="story z"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="tonal drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:40001</id>
    <link href="http://blog.notdot.net/2010/03/Please-stand-by" rel="alternate" type="text/html"/>
    <title>Please stand by</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Due to unforseen technical difficulties, today's blog post has been delayed. Look for it next week, where I'll describe what you can do to get started writing an app for the new <a href="http://www.google.com/enterprise/marketplace/home">Apps Marketplace</a> right now.</p>

<p>In other news, I'm spending most of next week travelling, so I won't be able to keep up my usual thrice-weekly updates. Regular blogging will resume the following week. Sorry!</p>

<p><a href="http://www.flickr.com/photos/julep67/2082499014/"><img src="http://farm3.static.flickr.com/2302/2082499014_9f98347191_o.gif" style="border: none;"/></a></p></div>
    </content>
    <updated>2010-03-12T16:51:18Z</updated>
    <published>2010-03-12T16:51:17Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-03-12T16:51:18Z</updated>
    </source>
  </entry>

  <entry xml:lang="ja">
    <id>http://golang.jp/?p=1252</id>
    <link href="http://golang.jp/2010/03/1252" rel="alternate" type="text/html"/>
    <title>実践Go言語(part11)</title>
    <summary>実践Go言語(Effective Go)の翻訳、11回目です。
前回までの訳は実践Go言語[日本語訳]にまとめてあります。

埋込み
Go言語には型によるサブクラス化という典型的な概念はありませんが、構造体またはインタフ [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><a href="http://golang.org/doc/effective_go.html" target="_blank">実践Go言語(Effective Go)</a>の翻訳、11回目です。<br/>
前回までの訳は<a href="http://golang.jp/effective_go">実践Go言語[日本語訳]</a>にまとめてあります。</p>
<hr/>
<h2 id="embedding">埋込み</h2>
<p>Go言語には型によるサブクラス化という典型的な概念はありませんが、構造体またはインタフェースに型を埋込み、実装を「借りる」仕組みがあります。</p>
<p>インタフェースの埋込みはとても単純です。下は以前説明した<code>io.Reader</code>と<code>io.Writer</code>インタフェースの定義です。</p>
<pre>type Reader interface {
    Read(p []byte) (n int, err os.Error)
}

type Writer interface {
    Write(p []byte) (n int, err os.Error)
}</pre>
<p><code>io</code>パッケージではこれと同じように、オブジェクトに対しメソッドの実装を規定するためのインタフェースが、他にもいくつかエクスポートされています。たとえば、<code>Read</code>と<code>Write</code>両方を持つインタフェース<code>io.ReadWriter</code>があります。これら2つのメソッドを明示的に記述することで<code>io.ReadWriter</code>を定義することもできますが、次のようにして2つのインタフェースを埋込んで新しいインタフェースを作成するほうがより簡単で、意図が伝わりやすくなります。</p>
<pre>// ReadWriteは、基本的なメソッドReadとWriteをグルーピングしたインタフェース
type ReadWriter interface {
    Reader
    Writer
}</pre>
<p>このようにすることで、<code>Reader</code>が行えること、および<code>Writer</code>が行えることを<code>ReadWriter</code>が兼ね備えていて、このインタフェースが埋込みインタフェース（メソッド群内に共通のメソッドを持っていてはならない）の結合により作られていることが見て取れます。ただしインタフェース内に埋込むことができるのはインタフェースだけです。</p>
<p>この基本的な考え方は構造体にもあてはまりますが、構造体の場合はより広範囲に渡る影響があります。<code>bufio</code>パッケージは2つの構造体型、<code>bufio.Reader</code>と<code>bufio.Writer</code>を持ち、当然それぞれパッケージ<code>io</code>の対応するインタフェースを実装しています。<code>bufio</code>ではさらに埋込みを利用して、ひとつの構造体に<code>Reader</code>と<code>Writer</code>を組み込んでバッファ付きの読み書きを実装しています。下の例で構造体内に型を列挙していますが、このときフィールド名は付けていません。</p>
<pre>// ReadWriterは、ReaderとWriterのポインタを格納している
// これはio.ReadWriterの実装
type ReadWriter struct {
    *Reader
    *Writer
}</pre>
<p>この構造体はこう書き換えることも可能です。</p>
<pre>type ReadWriter struct {
    reader *Reader
    writer *Writer
}</pre>
<p>ただこうした場合は、下のようにして呼び出しを転送するメソッドを用意し、フィールド内の各メソッドを実装し<code>io</code>インタフェースを満たすようにしなければなりません。</p>
<pre>func (rw *ReadWriter) Read(p []byte) (n int, err os.Error) {
    return rw.reader.Read(p)
}</pre>
<p>しかし、直接構造体を埋込んでしまえば、この冗長な記述は要らなくなります。埋込まれた型が持っているメソッドは自動で持ち上げられるため、すなわち<code>bufio.ReadWriter</code>は<code>bufio.Reader</code>と <code>bufio.Writer</code>のメソッドを持つだけでなく、3つのインタフェース(<code>io.Reader</code>、<code>io.Writer</code>、<code>io.ReadWriter</code>)の全てを満たすようになります。</p>
<p>埋込みとサブクラス化では大きな違いがあります。型を埋込んでいるとき、埋込んだ型が持っているメソッドは埋込み先のメソッドともなりますが、実行しているメソッドのレシーバは埋込み先の型ではなく、あくまで元の型です。サンプルコードの <code>bufio.ReadWriter</code>の<code>Read</code>メソッドが実行されることと、先程の転送メソッドが実行されることは結果としてまったく同じです。(レシーバは<code>ReadWriter</code>フィールドの<code>reader</code>で、<code>ReadWriter</code>自身ではありません。)</p>
<p>また、埋込みを使うことで少し扱いやすくもなります。下の例では、通常の名前付きフィールドと並んで、埋込みフィールドを記述しています。</p>
<pre>type Job struct {
    Command string
    *log.Logger
}</pre>
<p>これで<code>Job</code>型は、<code>log.Logger</code>型が持つ<code>Log</code>、<code>Logf</code>といったメソッドを持つようになりました。もちろん、<code>Logger</code>にフィールド名を与えることはできますが、それは必須ではありません。これで、<code>Job</code>を使ってログが記録できるようになりました。</p>
<pre>job.Log("starting now...")</pre>
<p>この<code>Logger</code>は普通の構造体フィールドであるため、いままで通りの方法で初期化が行えます。</p>
<pre>func NewJob(command string, logger *log.Logger) *Job {
    return &amp;Job{command, logger}
}</pre>
<p>埋込まれているフィールドを直接参照しなければならないときは、フィールドの型名(パッケージ名は不要)をフィールド名として用います。つまり<code>Job</code>型である変数<code>job</code>の<code>*log.Logger</code>にアクセスしたいときは<code>job.Logger</code>と書きます。これは<code>Logger</code>のメソッドに手を加えたいときに役立ちます。</p>
<pre>func (job *Job) Logf(format string, args ...) {
    job.Logger.Logf("%q: %s", job.Command, fmt.Sprintf(format, args))
}</pre>
<p>型を埋込むことで名前の競合が発生する恐れがありますが、その解決ルールは単純です。最初に、フィールドまたはメソッド<code>X</code>は、その他の、より深い入れ子内にある<code>X</code>を隠蔽します。たとえば<code>log.Logger</code>に<code>Command</code>と名づけられたフィールドまたはメソッドが含まれていても、<code>Job</code>の<code>Command</code>フィールドがそれより優先されます。</p>
<p>2番目として、同一の入れ子階層に同じ名前が現れたとき、通常ではエラーとなります。たとえば<code>Job</code>構造体に、<code>Logger</code>と名づけられた別のフィールドまたはメソッドが含まれているとき<code>log.Logger</code>の埋め込みは不正です。ただし、このとき重複した名前が、型定義より外側のプログラムから一切アクセスされなければ大丈夫です。この決まりによって、埋め込まれた型へ外部から変更を加えてもある程度保護されます。つまり、フィールドの追加で他の型が持つフィールドとかち合ってしまっても、どちらのフィールドも一切使用されることがなければ何ら問題ありません。</p></div>
    </content>
    <updated>2010-03-12T07:46:49Z</updated>
    <category term="&#x30C9;&#x30AD;&#x30E5;&#x30E1;&#x30F3;&#x30C8;"/>
    <category term="&#x5B9F;&#x8DF5;Go&#x8A00;&#x8A9E;"/>
    <author>
      <name>noboru</name>
    </author>
    <source>
      <id>http://golang.jp</id>
      <link href="http://golang.jp/feed" rel="self" type="application/atom+xml"/>
      <link href="http://golang.jp" rel="alternate" type="text/html"/>
      <subtitle>プログラミング言語Goの情報サイト</subtitle>
      <title>Google's Go Guide</title>
      <updated>2010-03-12T08:00:14Z</updated>
    </source>
  </entry>

  <entry xml:lang="en-us">
    <id>http://twitter.com/_rsc/statuses/10354146672</id>
    <link href="http://twitter.com/_rsc/statuses/10354146672" rel="alternate" type="text/html"/>
    <title>_rsc: http://swtch.com/~rsc/regexp/regexp3.html</title>
    <summary>_rsc: http://swtch.com/~rsc/regexp/regexp3.html</summary>
    <updated>2010-03-12T03:25:06Z</updated>
    <source>
      <id>http://twitter.com/_rsc</id>
      <author>
        <name>RSC</name>
      </author>
      <link href="http://twitter.com/_rsc" rel="alternate" type="text/html"/>
      <link href="http://twitter.com/statuses/user_timeline/22455722.rss" rel="self" type="application/atom+xml"/>
      <subtitle>Twitter updates from Russ Cox / _rsc.</subtitle>
      <title>Twitter / _rsc</title>
      <updated>2010-03-15T06:00:09Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-8082954141980125536.post-965766124780243969</id>
    <link href="http://swtch.com/~rsc/regexp/regexp3.html" rel="related" type="text/html"/>
    <link href="http://research.swtch.com/feeds/965766124780243969/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=8082954141980125536&amp;postID=965766124780243969" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default/965766124780243969" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default/965766124780243969" rel="self" type="application/atom+xml"/>
    <link href="http://research.swtch.com/2010/03/regular-expression-article-3.html" rel="alternate" type="text/html"/>
    <title>Regular Expression Article #3</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p class="lp">In January 2007 I posted an article on my web site titled “<a href="http://swtch.com/~rsc/regexp/regexp1.html">Regular Expression Matching Can Be Simple And Fast.</a>”  I intended this to be the first of three; the second would explain how to do submatching using automata, and the third would explain how to make a really fast DFA.  I posted the <a href="http://swtch.com/~rsc/regexp/regexp2.html">second article</a> a few months ago.
</p>

<p class="pp">
Today, the <a href="http://swtch.com/~rsc/regexp/regexp3.html">third and final article</a> is available, along with an open source production implementation called <a href="http://code.google.com/p/re2">RE2</a>.
</p><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/8082954141980125536-965766124780243969?l=research.swtch.com" width="1"/></div></div>
    </content>
    <updated>2010-03-11T18:30:01Z</updated>
    <published>2010-03-11T18:30:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="theory"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="code"/>
    <author>
      <name>rsc</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/06357099531993534337</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-8082954141980125536</id>
      <author>
        <name>rsc</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/06357099531993534337</uri>
      </author>
      <link href="http://research.swtch.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://research.swtch.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Computer programming links, collected by
<a href="http://swtch.com/~rsc/">Russ Cox</a>.  Updated sporadically.</div>
      </subtitle>
      <title>research!rsc</title>
      <updated>2010-03-11T20:33:15Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-8683303211775274915</id>
    <link href="http://reneefrench.blogspot.com/feeds/8683303211775274915/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=8683303211775274915" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/8683303211775274915" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/8683303211775274915" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/03/blog-post.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://4.bp.blogspot.com/_va9O40qIhaE/S5iVxKB5iyI/AAAAAAAACXg/HKI4Irfe05w/s1600-h/thewlis5.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5447268421043063586" src="http://4.bp.blogspot.com/_va9O40qIhaE/S5iVxKB5iyI/AAAAAAAACXg/HKI4Irfe05w/s320/thewlis5.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 281px; height: 320px;"/></a><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-8683303211775274915?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-03-11T07:53:56Z</updated>
    <published>2010-03-12T07:03:00Z</published>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-7314960751207943195</id>
    <link href="http://reneefrench.blogspot.com/feeds/7314960751207943195/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=7314960751207943195" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/7314960751207943195" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/7314960751207943195" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/03/fluid.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://3.bp.blogspot.com/_va9O40qIhaE/S5iS3npCoxI/AAAAAAAACXY/J4YTB4vd3Oc/s1600-h/doc44sm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5447265233536197394" src="http://3.bp.blogspot.com/_va9O40qIhaE/S5iS3npCoxI/AAAAAAAACXY/J4YTB4vd3Oc/s320/doc44sm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 214px; height: 320px;"/></a>fluid<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-7314960751207943195?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-03-11T06:51:32Z</updated>
    <published>2010-03-11T06:50:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="waiting room drawings"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="line drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:39001</id>
    <link href="http://blog.notdot.net/2010/03/Interactive-tables-for-fun-and-er-fun" rel="alternate" type="text/html"/>
    <title>Interactive tables for fun and, er, fun.</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Recently, I've been pondering, with some workmates, the practicality of putting together our own <a href="http://www.google.com/search?sourceid=chrome&amp;ie=UTF-8&amp;q=interactive+table">interactive table</a>, similar to the <a href="http://www.microsoft.com/surface/">Microsoft Surface</a> or the <a href="http://www.reactable.com/">reactable</a>.</p>

<p>There are a number of variations on how to build one, but the one we're planning on trying seems to be the simplest: Build a custom table with a frosted glass or perspex top, and place a projector in the base, projecting onto the bottom of the frosted surface. Additionally, have a camera under the table, pointing at the surface, to detect touches and objects.</p>

<p>There are a number of variations on this theme. <a href="http://trackmate.media.mit.edu/">trackmate</a> is a system of 2d barcodes and open source software that allows you to tag and track objects. Their <a href="http://www.instructables.com/id/Trackmate_Portable_Plexi_Cliffhanger/">example configurations</a> involve a frosted plexiglass surface, with even illumination and a camera placed underneath. None of them directly support surfaces with images projected onto them, though.</p>

<p><a href="http://www.instructables.com/id/Interactive-Multitouch-Display/">This instructable</a> demonstrates the construction of a multitouch table that supports both touch detection and a projector, through a technique called <a href="http://www.cs.nyu.edu/~jhan/ftirsense/">frustrated total internal reflection</a>. It relies on a strip of infra-red LEDs along the edge of the panel, and touching the panel disrupts the internal reflection, allowing an infra-red camera under the table to detect your touches. Since it uses infra-red, it's not affected by the projector.</p>

<p>A good overview of different techniques for multitouch tables is available <a href="http://nuigroup.com/forums/viewthread/1982/">here</a>.</p>

<p>The projector is another consideration: There's limited space in the table, if we want it to be a reasonable height, but most projectors will only create a fairly small image at those distances. One solution is a <a href="http://www.projectorpeople.com/resources/short-throw.asp">short throw projector</a> - a projector with a particularly wide angle lens. Some of these can produce an image over a meter wide at a distance of only about 70cm (a typical height for a table)! They're not even much more expensive than regular projectors, these days.</p>

<p>Our ideal interactive table would combine several of these features: We want to be able to interact with it with fingers, but we also want to be able to place tagged objects on it and have them recognized. Unfortunately, nobody seems to have tried this approach yet: The trackmate examples all use even visible-light illumination to read the tags, while the multitouch examples use infra-red illumination for detecting touches, which isn't going to work for reading printed tags.</p>

<p>My thus-far hypothetical approach is a hybrid: I'd like to use regular visible light illumination provided by the projector, and, after calibrating the two devices, subtract the projected image from the image recorded by the camera, and feed the difference to the routines for recognizing touches and tags. While I hope this will work, it'll take some tests to be certain.</p>

<p>On the software side of things, there are a number of libraries available. <a href="http://trackmate.media.mit.edu/">trackmate</a>, as already mentioned, tracks custom 2d barcodes, while <a href="http://nuigroup.com/touchlib/tutorials/">touchlib</a> takes care of recognizing and tracking 'blobs' such as fingers. At a lower level, libraries like <a href="http://opencv.willowgarage.com/documentation/">opencv</a> provide primitives for doing image processing yourself.</p>

<p>Finally, what applications do we want to use this for? Besides all the stuff we can already run (mostly demos, so far), what I would really like to use this for is augmented boardgaming. I have two games in mind to start: The 18xx series of games, and RPGs.</p>

<p>The goals for RPGs are fairly straightforward: Provide an interface to simulate tactical movement for battles, where the DM can control things and players can interact with the grid. Additionally, provide some utilities for tracking all the things that usually require manual bookkeeping. Finally, for extra bonus points, be able to recognize dice thrown on the surface, so players can roll the dice and have the computer recognize the outcome.</p>

<p>My goal with the <a href="http://www.boardgamegeek.com/boardgame/1208/1851">18xx</a> games are a bit more involved. I'd like to implement a complete interactive-table version of them, starting with simulating just the board. The board in the 18xx games uses hexagonal tiles, which presents challenges all of its own - there don't seem to be any robust tile engines for Python.  Pygame Utilities <a href="http://code.google.com/p/pgu/source/browse/trunk/pgu/hexvid.py">has one</a>, but it's incomplete, and PGU is no longer maintained. <a href="http://wiki.fifengine.de/">fife</a> may have one, but it dies with a bus error any time I try to run a demo on my mac. Unless someone surfaces with a recommendation of another one, it looks like I might have to write my own, which will at least be an interesting challenge. <a href="http://www-cs-students.stanford.edu/~amitp/gameprog.html#hex">This page</a> links to a lot of useful resources on handling hex grids on a computer.</p>

<p>Hex tile editors are similarly sparse, with most of them being written for windows or dos(!) and unmaintained. The <a href="http://mapeditor.org/">tiled</a> map editor is quite a nice looking editor which claims not to support hexagonal tiles, until you look closer, and notice that it exists in two versions - the 'new' QT version and the 'old' Java version. The Java version, while no longer maintained, is perfectly usable, and supports hex tiles. It also has quite a nice output format. Huzzah!</p>

<p>In terms of how this will interface with the interactive table, what I'd like is a simulation of the board, with real physical hex tiles that you can place down to lay new track. Once you've placed the tiles you want to, and oriented them the way you want, you can tap a 'submit' button, and the game will read the trackmate codes from the bottom of the tiles, figure out what they are and how they're facing, and add them to its own view of the board. You can then remove the physical tiles. This seems like the best of both worlds, as you get the intuitive usage of the game, without the clutter of easily knocked tiles on the board all the time. The game can then do routing and so forth for other game phases entirely in the computer, allowing you to simply tap on tiles to set up a route.</p>

<p>That's it for now. Apologies for the lack of a 'real' blog post - a combination of busy-ness, other things on my mind, and lack of inspiration for a 'real' post led to this braindump instead. If you have any ideas or suggestions about our interactive table project or about implementing a hex tile engine, please speak up in the comments!</p></div>
    </content>
    <updated>2010-03-10T14:55:11Z</updated>
    <published>2010-03-10T14:51:31Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-03-12T16:51:18Z</updated>
    </source>
  </entry>

  <entry xml:lang="ja">
    <id>http://golang.jp/?p=1245</id>
    <link href="http://golang.jp/2010/03/1245" rel="alternate" type="text/html"/>
    <title>実践Go言語(part10)</title>
    <summary>実践Go言語(Effective Go)の翻訳、10回目です。
前回までの訳は実践Go言語[日本語訳]にまとめてあります。

インタフェースとそれ以外の型
インタフェース
Go言語のインタフェースは、オブジェクトの振舞い [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><a href="http://golang.org/doc/effective_go.html" target="_blank">実践Go言語(Effective Go)</a>の翻訳、10回目です。<br/>
前回までの訳は<a href="http://golang.jp/effective_go">実践Go言語[日本語訳]</a>にまとめてあります。</p>
<hr/>
<h2 id="interfaces_and_types">インタフェースとそれ以外の型</h2>
<h3 id="interfaces">インタフェース</h3>
<p>Go言語のインタフェースは、オブジェクトの振舞いを規定する手立てです。このセクションではインタフェースにより実現できることすべてを説明します。今まですでに2、3の簡単な例を見てきました。たとえばカスタム出力は<code>String</code>メソッドを実装することで作られ、一方<code>Fprintf</code>は<code>Write</code>メソッドによって出力先をどこへでも変更できます。Go言語のコードでは、通常インタフェースは1～2個のメソッドしか持たず、また<code>Write</code>メソッドを持つ<code>io.Writer</code>のようにたいていメソッド名と関連した名前が付けられます。</p>
<p>型には複数のインタフェースを実装することができます。たとえばあるコレクション型が<code>Len()</code>、<code>Less(i, j int) bool</code>、<code>Swap(i, j int)</code>メソッドを持つ<code>sort.Interface</code>を実装していれば<code>sort</code>パッケージのルーチンを使ってソートが可能になり、その上さらに独自の出力メソッドを実装することもできます。下の例の<code>Sequence</code>型は、少々不自然ですがこれらをすべて実装しています。</p>
<pre>type Sequence []int

// sort.Interfaceに必要な全メソッドを実装
func (s Sequence) Len() int {
    return len(s)
}
func (s Sequence) Less(i, j int) bool {
    return s[i] &lt; s[j]
}
func (s Sequence) Swap(i, j int) {
    s[i], s[j] = s[j], s[i]
}

// 出力用メソッド - 出力前に要素を並び替え
func (s Sequence) String() string {
    sort.Sort(s)
    str := "["
    for i, elem := range s {
        if i &gt; 0 {
            str += " "
        }
        str += fmt.Sprint(elem)
    }
    return str + "]"
}</pre>
<h3 id="conversions">変換</h3>
<p>さきほどの<code>Sequence</code>の<code>String</code>メソッドを変更して、<code>Sprint</code>が本来持っているスライス出力機能を利用するようにしました。<code>Sprint</code>を呼び出す前に<code>Sequence</code>を純粋な<code>[]int</code>に変換することで、既存の処理を利用することが可能になります。</p>
<pre>func (s Sequence) String() string {
    sort.Sort(s)
    return fmt.Sprint([]int(s))
}</pre>
<p>このとき変換が行われ、<code>s</code>がただのスライスとみなされるため、スライスに規定されている書式で文字列が返されます。ここで変換を行われなければ、<code>Sprint</code>は<code>Sequence</code>の<code>String</code>メソッドを見つけ出し、呼び出しを無限に繰り返してしまいます。この2つの型(<code>Sequence</code>と<code>[]int</code>)は名前を除けば同一であるため、これらの型の間における変換は問題なく行われます。この変換では新しい値が作られることはなく、既存の値が一時的に新しい型を持つかのような働きをします。(これと異なる変換もあります。たとえば整数を浮動小数点へ変換したときは新しく値が作成されます。)</p>
<p>Go言語のプログラムでは、異なるメソッド群を使用するために式の型を変換することがよく行われます。例として、既存の型<code>sort.IntArray</code>を使ってサンプルプログラム全体を下のように軽量化することが可能です。</p>
<pre>type Sequence []int

// 出力用メソッド - 出力する前に要素を並び替え
func (s Sequence) String() string {
    sort.IntArray(s).Sort()
    return fmt.Sprint([]int(s))
}</pre>
<p>これで、<code>Sequence</code>に複数のインタフェース(ソートと出力)を実装する代わりに、データを複数の型(<code>Sequence</code>、 <code>sort.IntArray</code>、<code>[]int</code>)に変換できることを利用して各機能を実現できるようになりました。このような使い方をすることは実際にはほとんどありませんが効果的な使い方です。</p>
<h3 id="generality">概説</h3>
<p>ある型がインタフェースをひとつだけ実装していて、そのインタフェースのメソッド以外にエクスポートされたメソッドを持たないならば、型自体のエクスポートは不要です。インタフェースだけをエクスポートすることで、次の点を明白にすることができます。ひとつは、重要なのは実装ではなく振舞いであること。もうひとつは、振舞いは同じでも異なる機能を持った別個の実装であることです。また、共通メソッドを実装している各箇所で、その都度ドキュメントを記述する手間が省けるという利点もあります。</p>
<p>このような場合は、コンストラクタは実装している型ではなく、インタフェース値を返さなければなりません。一例として、ハッシュライブラリの<code>crc32.NewIEEE()</code>と<code>adler32.New()</code>では、双方とも<code>hash.Hash32</code>インタフェース型の値を返します。Go言語プログラムでこのハッシュアルゴリズムをAdler-32からCRC-32に変更するために必要なのは、コンストラクタの呼び出しを入れ替えるだけです。それ以外のコードは、ハッシュアルゴリズムの変更による影響を受けません。</p>
<p>同様のアプローチにより、<code>crypto/block</code>パッケージのストリーム暗号アルゴリズムは、一連のブロック暗号から独立しています。これらは特定の実装を返すのではなく、<code>bufio</code>パッケージにならって<code>Cipher</code>インタフェースをラップした<code>hash.Hash</code>、<code>io.Reader</code>、<code>io.Writer</code>いずれかのインタフェース値を返します。</p>
<p>下は<code>crypto/block</code>内のインタフェースです。</p>
<pre>type Cipher interface {
    BlockSize() int
    Encrypt(src, dst []byte)
    Decrypt(src, dst []byte)
}

// NewECBDecrypterは、rからデータを読み込み、
// c内の電子コードブック(ECB)モードを使って復号化を行うReaderを返します。
func NewECBDecrypter(c Cipher, r io.Reader) io.Reader

// NewCBCDecrypterは、rからデータを読み込み、
// c内の暗号ブロックチェイニング(CBC)モードと初期化ベクタivを使って
// 復号化を行うReaderを返します。
func NewCBCDecrypter(c Cipher, iv []byte, r io.Reader) io.Reader</pre>
<p><code>NewECBDecrypter</code>および<code>NewCBCReader</code>で扱うことができるのは、特定の暗号化アルゴリズムやデータソースではなく、どの<code>Cipher</code>インタフェースの実装であっても、またどの<code>io.Reader</code>でも適用することが可能です。これらは<code>io.Reader</code>インタフェース値を返すため、ECB暗号化をCBC暗号化と入れ替えるときは部分的な変更だけですみます。コンストラクタを呼び出している箇所は変更が必要ですが、その周囲のコードではコンストラクタから返されるのは<code>io.Reader</code>だけとみなしていれば違いに気づくことさえないでしょう。</p>
<h3 id="interface_methods">インタフェースとメソッド</h3>
<p>ほぼすべての型に対してメソッドを付け加えることができるので、これはすなわち、どのインタフェースであっても、ほとんどの型に実装可能であると言えます。この実例のひとつが、<code>Handler</code>インタフェースを定めている<code>http</code>パッケージにあります。<code>Handler</code>を実装しているすべてのオブジェクトで、HTTPリクエストを処理することが可能です。</p>
<pre>type Handler interface {
    ServeHTTP(*Conn, *Request)
}</pre>
<p>ここでは簡略化のため、POSTは無視してHTTPリクエストが常にGETであると仮定します。 (この簡略化がハンドラの書き方に影響を及ぼすことはありません。) 下は、ページの訪問回数を単に数えるだけのハンドラの実装一式です。</p>
<pre>// 単純なカウントサーバ
type Counter struct {
    n int
}

func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
    ctr.n++
    fmt.Fprintf(c, "counter = %d\n", ctr.n)
}</pre>
<p>(今回のテーマを気にとめつつ、<code>Fprintf</code>がどのようにしてHTTP接続を出力するか注意してみてください。)<br/>
参考までに、こういったサーバをURLパスに割り当てる手順です。</p>
<pre>import "http"
...
ctr := new(Counter)
http.Handle("/counter", ctr)</pre>
<p>ところで、なぜ<code>Counter</code>を構造体としているのでしょうか。必要なのは整数ひとつだけのはずです。(ただし値が増えたことを呼び出し側にも伝わるように、レシーバはポインタである必要があります。)</p>
<pre>// 単純なカウントサーバ
type Counter int

func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
    *ctr++
    fmt.Fprintf(c, "counter = %d\n", *ctr)
}</pre>
<p>自作プログラムが内部ステータスを持っていて、そこにページが訪問されたことを通知しなければならないとしたらどうすればよいでしょうか。このようなときは、次のようにチャネルとウェブページとを関連付けてください。</p>
<pre>// 訪問がある度に通知を送信するチャネル
// (たぶんバッファリングされている必要がある)
type Chan chan *http.Request

func (ch Chan) ServeHTTP(c *http.Conn, req *http.Request) {
    ch &lt;- req
    fmt.Fprint(c, "notification sent")
}</pre>
<p>最後に、パス<code>/args</code>を訪問したときにサーバプログラムを起動した際に与えられた引数を出力するようにしてみましょう。引数の出力関数は下のように簡単に書けます。</p>
<pre>func ArgServer() {
    for i, s := range os.Args {
        fmt.Println(s)
    }
}</pre>
<p>これをHTTPサーバへ変更していきます。さきほどの<code>ArgServer</code>関数を適当な型(値は何でも良い)のメソッドとすることもできますが、それより良い方法があります。メソッドはポインタとインタフェース以外すべての型に定義することができるため、関数に対してメソッドを書くことも可能です。<code>http</code>パッケージには、下のコードが含まれています。</p>
<pre>// HandlerFunc型は、通常の関数をHTTPハンドラとして
// 使用可能にするためのアダプタです。
// fが適切なシグネチャを持つ関数であれば、HandlerFunc(f)は
// fを呼び出すハンドラオブジェクトとなります。
type HandlerFunc func(*Conn, *Request)

// ServeHTTPはf(c, req)を呼び出す
func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) {
    f(c, req)
}</pre>
<p><code>HandlerFunc</code>は<code>ServeHTTP</code>メソッドを持つ型であるため、この型の値はHTTPリクエストを処理できます。メソッドの実装を見てください。このメソッドのレシーバは関数<code>f</code>であり、メソッド内で<code>f</code>を呼び出しています。これは少々風変わりではありますが、前出のチャネルをレシーバとしてそのチャネルへ送信するメソッドと大差ありません。</p>
<p><code>ArgServer</code>をHTTPサーバにするため、まずは正しいシグネチャを持つように修正します。</p>
<pre>// 引数サーバ
func ArgServer(c *http.Conn, req *http.Request) {
    for i, s := range os.Args {
        fmt.Fprintln(c, s)
    }
}</pre>
<p>これで<code>ArgServer</code>は<code>HandlerFunc</code>と同じシグネチャを持つようになったので、以前<code>Sequence</code>を<code>IntArray.Sort</code>を使用するため<code>IntArray</code>に変換したときと同様に、<code>ArgServer</code>を<code>HandlerFunc</code>内のメソッドを使用するために<code>HandlerFunc</code>型に変換可能になりました。このセットアップを行うコードは次のように簡潔に書けます。</p>
<pre>http.Handle("/args", http.HandlerFunc(ArgServer))</pre>
<p>誰かが<code>/args</code>ページを訪問したときに呼び出されるハンドラは、値は<code>ArgServer</code>で型は<code>HandlerFunc</code>となりました。まず、HTTPサーバによって<code>ArgServer</code>をレシーバとして<code>HandlerFunc</code>型の<code>ServeHTTP</code>メソッドが実行され、続いて<code>HandlerFunc.ServeHTTP</code>内の<code>f(c, req)</code>を通して<code>ArgServer</code>が呼び出されます。そのあと引数の表示が行われます。</p>
<p>このセクションで、構造体、整数、チャネル、関数を使ってHTTPサーバを作成したのは、インタフェースがまさにメソッド群であり、(ほとんど)すべての型に対して定義できることを示すためです。</p></div>
    </content>
    <updated>2010-03-10T04:44:45Z</updated>
    <category term="&#x30C9;&#x30AD;&#x30E5;&#x30E1;&#x30F3;&#x30C8;"/>
    <category term="&#x5B9F;&#x8DF5;Go&#x8A00;&#x8A9E;"/>
    <author>
      <name>noboru</name>
    </author>
    <source>
      <id>http://golang.jp</id>
      <link href="http://golang.jp/feed" rel="self" type="application/atom+xml"/>
      <link href="http://golang.jp" rel="alternate" type="text/html"/>
      <subtitle>プログラミング言語Goの情報サイト</subtitle>
      <title>Google's Go Guide</title>
      <updated>2010-03-12T08:00:13Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-8711207045350727549</id>
    <link href="http://reneefrench.blogspot.com/feeds/8711207045350727549/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=8711207045350727549" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/8711207045350727549" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/8711207045350727549" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/03/dean.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://4.bp.blogspot.com/_va9O40qIhaE/S5cX1C0ePnI/AAAAAAAACXA/z6xNuKO2l34/s1600-h/thornbirds1.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5446848474385366642" src="http://4.bp.blogspot.com/_va9O40qIhaE/S5cX1C0ePnI/AAAAAAAACXA/z6xNuKO2l34/s320/thornbirds1.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 163px; height: 320px;"/></a>dean<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-8711207045350727549?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-03-10T03:54:15Z</updated>
    <published>2010-03-10T03:53:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="line drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://netherstone.org/golang/netbsd/blog/?p=40</id>
    <link href="http://netherstone.org/golang/netbsd/blog/?p=40" rel="alternate" type="text/html"/>
    <title>Not sleeping, just resting</title>
    <summary>Another “no news” post.  As I gather minutes here and there I’m still working in the syscall package.  (Backups are good.  Up to the minute backups are best …)
My minutes are limited right now due to a family illness.  (Prognosis very good, but some way to go.)
I’ve been making some small [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Another “no news” post.  As I gather minutes here and there I’m still working in the syscall package.  (Backups are good.  Up to the minute backups are best …)</p>
<p>My minutes are limited right now due to a family illness.  (Prognosis very good, but some way to go.)</p>
<p>I’ve been making some small non-porting related contributions to Go which haven’t required as much mental energy to at least stay in touch.</p></div>
    </content>
    <updated>2010-03-10T02:48:34Z</updated>
    <category term="Go"/>
    <category term="Personal"/>
    <author>
      <name>admin</name>
    </author>
    <source>
      <id>http://netherstone.org/golang/netbsd/blog</id>
      <link href="http://netherstone.org/golang/netbsd/blog/?feed=rss2" rel="self" type="application/atom+xml"/>
      <link href="http://netherstone.org/golang/netbsd/blog" rel="alternate" type="text/html"/>
      <subtitle>Of course it runs on NetBSD!</subtitle>
      <title>Porting Go to NetBSD</title>
      <updated>2010-03-10T03:00:10Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://www.airs.com/blog/?p=329</id>
    <link href="http://www.airs.com/blog/archives/329" rel="alternate" type="text/html"/>
    <title>High Mimetic</title>
    <summary>Roger Zelazny, in discussing why he liked to write science fiction, referred to Northrop Frye’s theory of modes.  In Zelazny’s interpretation, Frye described characters in fiction in four modes:

The mythic mode is stories about gods.
The high mimetic mode is stories about heroes, people who are better than ordinary humans.
The low mimetic mode is stories [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Roger Zelazny, in discussing why he liked to write science fiction, referred to Northrop Frye’s theory of modes.  In Zelazny’s interpretation, Frye described characters in fiction in four modes:</p>
<ol>
<li>The mythic mode is stories about gods.</li>
<li>The high mimetic mode is stories about heroes, people who are better than ordinary humans.</li>
<li>The low mimetic mode is stories about ordinary people.</li>
<li>The ironic mode is stories about people who are worse than ordinary people–criminals, buffoons.</li>
</ol>
<p>(Frye also talked about a romantic mode but Zelazny doesn’t mention it.)</p>
<p>Zelazny said that he liked science fiction because it let him write literature in the mythic or high mimetic mode.  Certainly many of his stories are about gods or people with great powers.  Zelazny argued that literature today outside of science fiction is mainly confined to the low mimetic and the ironic mode.  There are many superb stories about ordinary people.  There are few stories about remarkable people which are not history and are not genre stories like science fiction or romances.</p>
<p>This started me thinking about other areas where stories are told in the high mimetic mode.  Superhero comics are obviously told entirely in that mode.  Another place we see it is a certain set of action movies: James Bond, for example, is a high mimetic mode character.  But these stories, while enjoyable, rarely rise to the level of good literature.</p>
<p>An exception is The Hurt Locker.  This excellent movie, which well deserved the Oscars it just won, is a straight-up action movie.  It passed one of the acid tests of the action movie: I saw it twice, and I didn’t see anything the second time around that I missed the first time.  With artistic movies I often get a new perspective on a second viewing; with action movies I rarely do.  The movie also operates in the high mimetic mode: the protagonist, William James, is a heroic character.  He is not a perfect human being, but he is exceptionally capable and brave.</p>
<p>But despite the high mimetic mode character, the movie does not operate as a standard hero’s journey, there is no evil mastermind or any identified antagonist.  The movie is simply a collection of relatively unrelated incidents which reveal the characters.  James does come to understand himself better during the movie—or, since we really only hear his inner thoughts in one scene, perhaps he understood himself all along.  The combination of literary techniques with high mimetic mode make this a genuinely exceptional movie.</p>
<p>Zelazny, of course, used the same approach throughout his career, with varying degrees of success.</p></div>
    </content>
    <updated>2010-03-09T07:31:34Z</updated>
    <category term="Random"/>
    <author>
      <name>Ian Lance Taylor</name>
    </author>
    <source>
      <id>http://www.airs.com/blog</id>
      <link href="http://www.airs.com/blog/feed" rel="self" type="application/atom+xml"/>
      <link href="http://www.airs.com/blog" rel="alternate" type="text/html"/>
      <subtitle>Ian Lance Taylor</subtitle>
      <title>Airs - Ian Lance Taylor</title>
      <updated>2010-03-09T08:00:16Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-2340194644247545559</id>
    <link href="http://reneefrench.blogspot.com/feeds/2340194644247545559/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=2340194644247545559" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2340194644247545559" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2340194644247545559" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/03/loop.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://4.bp.blogspot.com/_va9O40qIhaE/S5XR_xhNZlI/AAAAAAAACW4/EeHFafcfcec/s1600-h/hdaymovbed60sm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5446490217929074258" src="http://4.bp.blogspot.com/_va9O40qIhaE/S5XR_xhNZlI/AAAAAAAACW4/EeHFafcfcec/s320/hdaymovbed60sm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 320px; height: 223px;"/></a><br/><div>loop</div><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-2340194644247545559?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-03-09T04:44:03Z</updated>
    <published>2010-03-09T04:43:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="line drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-8082954141980125536.post-5277957312261188150</id>
    <link href="http://research.swtch.com/feeds/5277957312261188150/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=8082954141980125536&amp;postID=5277957312261188150" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default/5277957312261188150" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default/5277957312261188150" rel="self" type="application/atom+xml"/>
    <link href="http://research.swtch.com/2010/03/formal-logic-club.html" rel="alternate" type="text/html"/>
    <title>Formal Logic Club</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p class="lp">I've been laughing at this for weeks.  It's too good not to share.</p>
<br/>

<blockquote title="(The most important question about any formal logic system is whether it is consistent.  An inconsistent formal system admits proofs of any statement at all&#x2014;for example, that 2 + 3 = 4&#x2014;which would make it not terribly useful.  G&#xF6;del proved that any interesting formal system can only prove its own consistency if it is in fact inconsistent.)">
<p class="lp">
The first rule of Formal Logic Club is you do not prove the consistency of Formal Logic Club.
</p>
<br/>

<p class="lp">
The second rule of Formal Logic Club is you do not prove the inconsistency of Formal Logic Club.
</p>

<p class="pp">— <a href="http://laboratorium.net/archive/2000/08/14/formal_logic_cl">James Grimmelmann</a>
</p>
<br/>
</blockquote>

<p class="lp">
(Yes, this looks like <a href="http://xkcd.com/703/">http://xkcd.com/703/</a>,
but it beat xkcd to the punchline by ten years, and it's funnier.)
</p>
<br/><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/8082954141980125536-5277957312261188150?l=research.swtch.com" width="1"/></div></div>
    </content>
    <updated>2010-03-08T17:00:00Z</updated>
    <published>2010-03-08T17:00:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="theory"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="self-reference"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="undecidability"/>
    <author>
      <name>rsc</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/06357099531993534337</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-8082954141980125536</id>
      <author>
        <name>rsc</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/06357099531993534337</uri>
      </author>
      <link href="http://research.swtch.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://research.swtch.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Computer programming links, collected by
<a href="http://swtch.com/~rsc/">Russ Cox</a>.  Updated sporadically.</div>
      </subtitle>
      <title>research!rsc</title>
      <updated>2010-03-11T20:33:15Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:26002</id>
    <link href="http://blog.notdot.net/2010/03/Using-the-ereporter-module-for-easy-error-reporting-in-App-Engine" rel="alternate" type="text/html"/>
    <title>Using the ereporter module for easy error reporting in App Engine</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>One little known package in the google.appengine.ext package is <a href="http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/ereporter/ereporter.py">ereporter</a>. This package exists to make it easier to get summaries of errors generated by your Python App Engine app, and today we'll show you how.</p>

<p>Far too often for new webapps, error reports for live webapps are a catch-as-catch-can type practice, with reports coming in from dedicated users, and whenever you think to check the logs page of your app. A lot of bugs can slip through this way, however, with exceptions going unnoticed to everyone but the users who experience them, then walk away in disgust, never to return again. With ereporter, however, we'll demonstrate how to set up a simple handler that takes care of capturing all the exceptions that occur in your app, and emailing a daily report to you, summarizing what went wrong.</p>

<p>Installing ereporter consists of 3 stages: Modifying your handler script, modifying your app.yaml, and adding a cron job. Let's start by modifying your handler script(s). Add the following to the top of all your handler scripts (that is, scripts that are mentioned in app.yaml):</p>

<pre class="prettyprint">import logging
from google.appengine.ext import ereporter

ereporter.register_logger()</pre>

<p>The register_logger call causes ereporter to instantiate itself, and hook into the Python logging framework, where it will capture any calls to logging.exception. The webapp framework calls this function to log any uncaught exceptions, and your framework probably does too. If you want, you can also use logging.exception yourself, whenever you want an exception report added to ereporter.</p>

<p>Now that ereporter can capture your exceptions, we need to add the components it requires to send you the daily email. First up is the new handler in app.yaml:</p>

<pre class="prettyprint">handlers:
- url: /_ereporter/.*
  script: $PYTHON_LIB/google/appengine/ext/ereporter/report_generator.py
  login: admin</pre>

<p>This handler will be the target of a cron job that calls it once a day, to generate the daily exception report. Add the cron job to cron.yaml:</p>

<pre class="prettyprint">cron:
- description: Daily exception report
  url: /_ereporter?sender=you@yourdomain.com
  schedule: every day 00:00</pre>

<p>You need to replace the email address <em>you@yourdomain.com</em> with the address of any of the administrators of your app. A to address is not required, as the tool emails the report to all the admins of the app, but you still have to specify a valid sender address.</p>

<p>That's all there is to it - you'll now get nicely formatted HTML exception reports for your app, with exceptions broken down by app version and exception source. If an exception occurs multiple times in the same location, ereporter will roll them up into one entry, with a sample stacktrace and an approximate count of occurrences, to make it easier to see what the biggest problems your app is encountering are.</p>

<p>The report generator takes a few more options that control its output - for details, see <a href="http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/ereporter/ereporter.py">the source code</a>.</p></div>
    </content>
    <updated>2010-03-08T14:41:24Z</updated>
    <published>2010-03-08T14:41:24Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-03-12T16:51:18Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-2401158040778543701</id>
    <link href="http://reneefrench.blogspot.com/feeds/2401158040778543701/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=2401158040778543701" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2401158040778543701" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2401158040778543701" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/03/loud-room.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://3.bp.blogspot.com/_va9O40qIhaE/S5RX_oeyTBI/AAAAAAAACWw/RK6UsZ5sWes/s1600-h/chat1.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5446074600107691026" src="http://3.bp.blogspot.com/_va9O40qIhaE/S5RX_oeyTBI/AAAAAAAACWw/RK6UsZ5sWes/s320/chat1.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 240px; height: 320px;"/></a>loud room<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-2401158040778543701?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-03-08T01:51:27Z</updated>
    <published>2010-03-08T01:50:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="notes"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-2988139719406634621</id>
    <link href="http://reneefrench.blogspot.com/feeds/2988139719406634621/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=2988139719406634621" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2988139719406634621" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2988139719406634621" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/03/somers-town.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://4.bp.blogspot.com/_va9O40qIhaE/S5H2xE7YYaI/AAAAAAAACWo/rDLZbuH68uk/s1600-h/thewlis3sm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5445404747464466850" src="http://4.bp.blogspot.com/_va9O40qIhaE/S5H2xE7YYaI/AAAAAAAACWo/rDLZbuH68uk/s320/thewlis3sm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 210px; height: 320px;"/></a>somers town<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-2988139719406634621?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-03-06T06:34:29Z</updated>
    <published>2010-03-06T18:27:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="notes"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://swtools.wordpress.com/?p=212</id>
    <link href="http://swtools.wordpress.com/2010/03/05/nb%e2%80%94search-and-index-notes-in-files-by-keyword/" rel="alternate" type="text/html"/>
    <title>nb—search and index notes in files by keyword</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">[Download a UTF-8 version of this file.]

nb name search index keyword
nb—search and index notes in files by keyword

nb keyword

nb description search keyword path file line acme
Nb searches for the given keyword in each nbindex file listed in
$HOME/nbindexes.  If it finds a match, nb prints the path, filename,
and line number of the indexed file in [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=swtools.wordpress.com&amp;blog=201050&amp;post=212&amp;subd=swtools&amp;ref=&amp;feed=1"/></div>
    </summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>[Download a UTF-8 version of <a href="http://dl.dropbox.com/u/502901/nb.1">this file</a>.]</p>
<pre>nb name search index keyword
nb—search and index notes in files by keyword

nb keyword

nb description search keyword path file line acme
Nb searches for the given keyword in each nbindex file listed in
$HOME/nbindexes.  If it finds a match, nb prints the path, filename,
and line number of the indexed file in the format acme uses to refer to
lines in a file.

nb file format store index line path file line acme nbindexes
This file is an example.  Nb searches all files in the current directory
for lines which begin “^nb ”, and copies them into the file nbindex.
Each match is listed with its filename, and line number, e.g. for acme
to show the line on a right-click of the mouse.  It then adds the
path and filename of the current directory’s nbindex file to the file
$HOME/nbindexes.

By convention I use 1 blank line to separate paragraphs after an nb
line, and 2 blank lines to separate nb lines, but nb doesn’t care about
this.

nb nbindex example search keyword
This is the nbindex file for this file.

	nb.1:1 name search index keyword
	nb.1:5 keyword
	nb.1:8 description search keyword path file line acme
	nb.1:15 file format store index line path file line acme nbindexes
	nb.1:28 nbindex example search keyword
	nb.1:50 source plan9port rc script
	nb.1:70 port plan9port rc shell script grëp
	nb.1:75 author jason.catena@gmail.com
	nb.1:78 bugs

This is the output of the command “nb keyword”.  It lists the full
path since it may refer to files anywhere in the filesystem.

	/usr/local/plan9/bin/nb.1:1 name search index keyword
	/usr/local/plan9/bin/nb.1:5 keyword
	/usr/local/plan9/bin/nb.1:8 description search keyword path file line acme
	/usr/local/plan9/bin/nb.1:28 nbindex example search keyword

nb source plan9port rc script
#!/usr/local/plan9/bin/rc
flag e +

catalog=$HOME^'/nbindexes'
if(test -r $catalog &amp;&amp; ! ~ $1 ''){
	list=`{cat $catalog}
	grëp $* $list | sed 's,nbindex:[0-9]+: ,,'
}

grep -n '^nb ' * &gt;[2]/dev/null | sed 's,: ?nb +, ,' &gt; nbindex
echo `{pwd}^'/nbindex' &gt;&gt; $catalog
if(~ $TMPDIR ''){
	TMPDIR=/var/tmp
}
tmp=$TMPDIR^'/nbindexes.'^$USER^'.'^$pid
sort -u $catalog &gt; $tmp
mv $tmp $catalog

nb port plan9port rc shell script grëp
Nb in written in plan9port’s rc, but should be straightforward to port
to any shell.  Use grep instead of grëp.

nb author jason.catena@gmail.com

nb bugs
Nb generates the index after it searches, to present results immediately,
so it does not show changes since its last run.  If you want to see
the latest changes, then run nb with no parameters before you supply a
keyword (e.g. in acme, middle-click on nb after you edit an nb line or
following text).
</pre>
<br/>  <a href="http://feeds.wordpress.com/1.0/gocomments/swtools.wordpress.com/212/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/swtools.wordpress.com/212/"/></a> <a href="http://feeds.wordpress.com/1.0/godelicious/swtools.wordpress.com/212/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/swtools.wordpress.com/212/"/></a> <a href="http://feeds.wordpress.com/1.0/gostumble/swtools.wordpress.com/212/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/swtools.wordpress.com/212/"/></a> <a href="http://feeds.wordpress.com/1.0/godigg/swtools.wordpress.com/212/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/swtools.wordpress.com/212/"/></a> <a href="http://feeds.wordpress.com/1.0/goreddit/swtools.wordpress.com/212/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/swtools.wordpress.com/212/"/></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=swtools.wordpress.com&amp;blog=201050&amp;post=212&amp;subd=swtools&amp;ref=&amp;feed=1"/></div>
    </content>
    <updated>2010-03-05T19:34:12Z</updated>
    <category term="Uncategorized"/>
    <author>
      <name>catena</name>
    </author>
    <source>
      <id>http://swtools.wordpress.com</id>
      <logo>http://www.gravatar.com/blavatar/1b0e7838e53455cdcc9f41b08c0f496d?s=96&amp;d=http://s2.wp.com/i/buttonw-com.png</logo>
      <link href="http://swtools.wordpress.com/feed/" rel="self" type="application/atom+xml"/>
      <link href="http://swtools.wordpress.com" rel="alternate" type="text/html"/>
      <link href="http://swtools.wordpress.com/osd.xml" rel="search" type="application/opensearchdescription+xml"/>
      <link href="http://swtools.wordpress.com/?pushpress=hub" rel="hub" type="text/html"/>
      <subtitle>Do one thing well, and work together.</subtitle>
      <title>Software Tools</title>
      <updated>2010-03-05T21:00:03Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-8082954141980125536.post-1448279655084128167</id>
    <link href="http://research.swtch.com/feeds/1448279655084128167/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=8082954141980125536&amp;postID=1448279655084128167" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default/1448279655084128167" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default/1448279655084128167" rel="self" type="application/atom+xml"/>
    <link href="http://research.swtch.com/2010/03/utf-8-bits-bytes-and-benefits.html" rel="alternate" type="text/html"/>
    <title>UTF-8: Bits, Bytes, and Benefits</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p class="pp">
UTF-8 is a way to encode Unicode code points—integer values from
0 through 10FFFF—into a byte stream,
and it is far simpler than many people realize.
The easiest way to make it confusing or complicated
is to treat it as a black box, never looking inside.
So let's start by looking inside.  Here it is:
</p>

<center>
<table border="0" cellpadding="0" cellspacing="5">
<tbody><tr height="10"><th colspan="4"/></tr>
<tr><th align="center" colspan="2">Unicode code points</th><th width="10"/><th align="center">UTF-8 encoding (binary)</th></tr>
<tr height="10"><td colspan="4"/></tr>
<tr><td align="right">00-7F</td><td>(7 bits)</td><td/><td align="right">0<i>tuvwxyz</i></td></tr>
<tr><td align="right">0080-07FF</td><td>(11 bits)</td><td/><td align="right">110<i>pqrst</i> 10<i>uvwxyz</i></td></tr>
<tr><td align="right">0800-FFFF</td><td>(16 bits)</td><td/><td align="right">1110<i>jklm</i> 10<i>npqrst</i> 10<i>uvwxyz</i></td></tr>
<tr><td align="right" valign="top">010000-10FFFF</td><td>(21 bits)</td><td/><td align="right" valign="top">11110<i>efg</i> 10<i>hijklm</i> 10<i>npqrst</i> 10<i>uvwxyz</i></td>
</tr><tr height="10"><td colspan="4"/></tr>
</tbody></table>
</center>

<p class="lp">
The convenient properties of UTF-8 are all consequences of the choice of encoding.
</p>

<ol>
<li><i>All ASCII files are already UTF-8 files.</i><br/>
The first 128 Unicode code points are the 7-bit ASCII character set,
and UTF-8 preserves their one-byte encoding.
</li>

<li><i>ASCII bytes always represent themselves in UTF-8 files.  They never appear as part of other UTF-8 sequences.</i><br/>
All the non-ASCII UTF-8 sequences consist of bytes
with the high bit set, so if you see the byte 0x7A in a UTF-8 file,
you can be sure it represents the character <code>z</code>.
</li>

<li><i>ASCII bytes are always represented as themselves in UTF-8 files.  They cannot be hidden inside multibyte UTF-8 sequences.</i><br/>
The ASCII <code>z</code> 01111010 cannot be encoded as a two-byte UTF-8 sequence
11000001 10111010.  Code points must be encoded using the shortest
possible sequence.
A corollary is that decoders must detect long-winded sequences as invalid.
In practice, it is useful for a decoder to use the Unicode replacement
character, code point FFFD, as the decoding of an invalid UTF-8 sequence
rather than stop processing the text.
</li>

<li><i>UTF-8 is self-synchronizing.</i><br/>
Let's call a byte of the form 10<i>xxxxxx</i>
a continuation byte.
Every UTF-8 sequence is a byte that is not a continuation byte
followed by zero or more continuation bytes.
If you start processing a UTF-8 file at an arbitrary point,
you might not be at the beginning of a UTF-8 encoding,
but you can easily find one: skip over
continuation bytes until you find a non-continuation byte.
(The same applies to scanning backward.)
</li>

<li><i>Substring search is just byte string search.</i><br/>
Properties 2, 3, and 4 imply that given a string
of correctly encoded UTF-8, the only way those bytes
can appear in a larger UTF-8 text is when they represent the
same code points.  So you can use any 8-bit safe byte at a time 
search function, like <code>strchr</code> or <code>strstr</code>, to run the search.
</li>

<li><i>Most programs that handle 8-bit files safely can handle UTF-8 safely.</i><br/>
This also follows from Properties 2, 3, and 4.
I say “most” programs, because programs that
take apart a byte sequence expecting one character per byte
will not behave correctly, but very few programs do that.
It is far more common to split input at newline characters,
or split whitespace-separated fields, or do other similar parsing
around specific ASCII characters.
For example, Unix tools like cat, cmp, cp, diff, echo, head, tail, and tee
can process UTF-8 files as if they were plain ASCII files.
Most operating system kernels should also be able to handle
UTF-8 file names without any special arrangement, since the
only operations done on file names are comparisons
and splitting at <code>/</code>.
In contrast, tools like grep, sed, and wc, which inspect arbitrary
individual characters, do need modification.
</li>

<li><i>UTF-8 sequences sort in code point order.</i><br/>
You can verify this by inspecting the encodings in the table above.
This means that Unix tools like join, ls, and sort (without options) don't need to handle
UTF-8 specially.
</li>

<li><i>UTF-8 has no “byte order.”</i><br/>
UTF-8 is a byte encoding.  It is not little endian or big endian.
Unicode defines a byte order mark (BOM) code point FFFE,
which are used to determine the byte order of a stream of
raw 16-bit values, like UCS-2 or UTF-16.
It has no place in a UTF-8 file.
Some programs like to write a UTF-8-encoded BOM
at the beginning of UTF-8 files, but this is unnecessary
(and annoying to programs that don't expect it).
</li>
</ol>

<p class="lp">
UTF-8 does give up the ability to do random
access using code point indices.
Programs that need to jump to the <i>n</i>th
Unicode code point in a file or on a line—text editors are the canonical example—will
typically convert incoming UTF-8 to an internal representation
like an array of code points and then convert back to UTF-8
for output,
but most programs are simpler when written to manipulate UTF-8 directly.
</p>

<p class="pp">
Programs that make UTF-8 more complicated than it needs to be
are typically trying to be too general,
not wanting to make assumptions that might not be true of
other encodings.
But there are good tools to convert other encodings to UTF-8,
and it is slowly becoming the standard encoding:
even the fraction of web pages
written in UTF-8 is
<a href="http://googleblog.blogspot.com/2010/01/unicode-nearing-50-of-web.html">nearing 50%</a>.
UTF-8 was explicitly designed
to have these nice properties.  Take advantage of them.
</p>

<p class="pp">
For more on UTF-8, see “<a href="http://plan9.bell-labs.com/sys/doc/utf.html">Hello World
or
Καλημέρα κόσμε
or
こんにちは 世界</a>,” by Rob Pike
and Ken Thompson, and also this <a href="http://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt">history</a>.
</p>

<br/>

<font size="-1">
<p class="lp">
Notes: Property 6 assumes the tools do not strip the high bit from each byte.
Such mangling was common years ago but is very uncommon now.
Property 7 assumes the comparison is done treating
the bytes as unsigned, but such behavior is mandated
by the ANSI C standard for <code>memcmp</code>,
<code>strcmp</code>, and <code>strncmp</code>.
</p>
</font><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/8082954141980125536-1448279655084128167?l=research.swtch.com" width="1"/></div></div>
    </content>
    <updated>2010-03-05T18:03:46Z</updated>
    <published>2010-03-05T17:00:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="bit twiddling"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Bell Labs"/>
    <author>
      <name>rsc</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/06357099531993534337</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-8082954141980125536</id>
      <author>
        <name>rsc</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/06357099531993534337</uri>
      </author>
      <link href="http://research.swtch.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://research.swtch.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Computer programming links, collected by
<a href="http://swtch.com/~rsc/">Russ Cox</a>.  Updated sporadically.</div>
      </subtitle>
      <title>research!rsc</title>
      <updated>2010-03-11T20:33:15Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-3922464996068172394</id>
    <link href="http://reneefrench.blogspot.com/feeds/3922464996068172394/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=3922464996068172394" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/3922464996068172394" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/3922464996068172394" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/03/thewlis-2.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://2.bp.blogspot.com/_va9O40qIhaE/S5DHmO9_pvI/AAAAAAAACWg/DDS7f3bwdY8/s1600-h/thewlis2sm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5445071409158006514" src="http://2.bp.blogspot.com/_va9O40qIhaE/S5DHmO9_pvI/AAAAAAAACWg/DDS7f3bwdY8/s320/thewlis2sm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 204px; height: 320px;"/></a>thewlis 2<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-3922464996068172394?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-03-05T14:57:00Z</updated>
    <published>2010-03-05T14:57:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="notes"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://netherstone.org/golang/netbsd/blog/?p=39</id>
    <link href="http://netherstone.org/golang/netbsd/blog/?p=39" rel="alternate" type="text/html"/>
    <title>Still working …</title>
    <summary>Distracted by reinstalling my notebook and some Real Life “stuff”, the slow progress continues.
I have a script that largely massages syscalls.master into something I want to work on.
Further work is needed on types, on deciding what system calls not to expose, and which system calls need wrapping.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Distracted by reinstalling my notebook and some Real Life “stuff”, the slow progress continues.</p>
<p>I have a script that largely massages syscalls.master into something I want to work on.</p>
<p>Further work is needed on types, on deciding what system calls not to expose, and which system calls need wrapping.</p></div>
    </content>
    <updated>2010-03-05T11:46:50Z</updated>
    <category term="Uncategorized"/>
    <category term="Go"/>
    <category term="golang"/>
    <category term="NetBSD"/>
    <author>
      <name>admin</name>
    </author>
    <source>
      <id>http://netherstone.org/golang/netbsd/blog</id>
      <link href="http://netherstone.org/golang/netbsd/blog/?feed=rss2" rel="self" type="application/atom+xml"/>
      <link href="http://netherstone.org/golang/netbsd/blog" rel="alternate" type="text/html"/>
      <subtitle>Of course it runs on NetBSD!</subtitle>
      <title>Porting Go to NetBSD</title>
      <updated>2010-03-10T03:00:10Z</updated>
    </source>
  </entry>

  <entry xml:lang="ja">
    <id>http://golang.jp/?p=1239</id>
    <link href="http://golang.jp/2010/03/1239" rel="alternate" type="text/html"/>
    <title>実践Go言語(part9)</title>
    <summary>実践Go言語(Effective Go)の翻訳、9回目です。
前回までの訳は実践Go言語[日本語訳]にまとめてあります。

メソッド
ポインタ vs. 値
メソッドは、名前がつけられていればポインタとインタフェースを除く [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><a href="http://golang.org/doc/effective_go.html" target="_blank">実践Go言語(Effective Go)</a>の翻訳、9回目です。<br/>
前回までの訳は<a href="http://golang.jp/effective_go">実践Go言語[日本語訳]</a>にまとめてあります。</p>
<hr/>
<h2 id="methods">メソッド</h2>
<h3 id="pointers_vs_values">ポインタ vs. 値</h3>
<p>メソッドは、名前がつけられていればポインタとインタフェースを除くすべての型に定義することができます。（レシーバは構造体である必要はありません。）</p>
<p>以前、スライスの説明のところで書いた<code>Append</code>関数を今度はスライスのメソッドとして定義してみます。これにはまず、メソッドと結びつけるために新たに名前付きの型を宣言し、メソッドにこの型のレシーバを定義します。</p>
<pre>type ByteSlice []byte

func (slice ByteSlice) Append(data []byte) []byte {
    // 本体部分は前と全く同じ
}</pre>
<p>このままでは、更新したスライスをメソッドから返す必要がまだ残っています。レシーバとして<code>ByteSlice</code>へのポインタを受け取るようメソッドを定義しなおすことによって、その問題を回避できます。こうすれば呼び出し元のスライスに対しメソッド内から上書き可能になります。</p>
<pre>func (p *ByteSlice) Append(data []byte) {
    slice := *p
    // 本体部分は上とおなじだが、returnは除外
    *p = slice
}</pre>
<p>実のところ、もう少し改善可能です。たとえば、この関数を標準的な<code>Write</code>メソッドに合わせるように変更すると下のようになります。</p>
<pre>func (p *ByteSlice) Write(data []byte) (n int, err os.Error) {
    slice := *p
    // これも上と同じ
    *p = slice
    return len(data), nil
}</pre>
<p>このようにすることで<code>*ByteSlice</code>型は、利便性の高い標準インタフェース<code>io.Writer</code>を満たすようになり、下の例のようにスライスに対し出力することが可能となります。</p>
<pre>    var b ByteSlice
    fmt.Fprintf(&amp;b, "This hour has %d days\n", 7)</pre>
<p>上で<code>ByteSlice</code>のアドレスを渡しているのは、<code>*ByteSlice</code>でなければ<code>io.Writer</code>インタフェースを満たさないためです。レシーバとしてポインタまたは値のどちらを受け取るかによって、次の違いがあります。レシーバとして値を受け取るメソッドでは、ポインタまたは値で呼び出すことができますが、ポインタを受け取るメソッドでは、ポインタでしか呼び出すことができません。これは後者ではメソッド内でレシーバを変更可能であるためです。(複製された値に加えた変更は破棄されてしまうため。）</p>
<p>ちなみに、<code>Write</code>をバイトのスライスで使うというアイデアは<code>bytes.Buffer</code>で実装済です。</p></div>
    </content>
    <updated>2010-03-05T06:38:05Z</updated>
    <category term="&#x30C9;&#x30AD;&#x30E5;&#x30E1;&#x30F3;&#x30C8;"/>
    <category term="&#x5B9F;&#x8DF5;Go&#x8A00;&#x8A9E;"/>
    <author>
      <name>noboru</name>
    </author>
    <source>
      <id>http://golang.jp</id>
      <link href="http://golang.jp/feed" rel="self" type="application/atom+xml"/>
      <link href="http://golang.jp" rel="alternate" type="text/html"/>
      <subtitle>プログラミング言語Goの情報サイト</subtitle>
      <title>Google's Go Guide</title>
      <updated>2010-03-12T08:00:14Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-2964933986624951539</id>
    <link href="http://reneefrench.blogspot.com/feeds/2964933986624951539/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=2964933986624951539" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2964933986624951539" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2964933986624951539" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/03/8349000-po.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://1.bp.blogspot.com/_va9O40qIhaE/S5CJ2TLhITI/AAAAAAAACWY/Qo_kpq7FG5I/s1600-h/stones82sm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5445003515445453106" src="http://1.bp.blogspot.com/_va9O40qIhaE/S5CJ2TLhITI/AAAAAAAACWY/Qo_kpq7FG5I/s320/stones82sm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 320px; height: 278px;"/></a>8349000 po<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-2964933986624951539?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-03-05T04:35:07Z</updated>
    <published>2010-03-05T04:33:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="tonal drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="ja">
    <id>http://golang.jp/?p=1235</id>
    <link href="http://golang.jp/2010/03/1235" rel="alternate" type="text/html"/>
    <title>実践Go言語(part8)</title>
    <summary>実践Go言語(Effective Go)の翻訳、8回目です。
前回までの訳は実践Go言語[日本語訳]にまとめてあります。

初期化
初期化において、Go言語とCやC++言語では見かけ上それほど差がないように見えますが、G [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><a href="http://golang.org/doc/effective_go.html" target="_blank">実践Go言語(Effective Go)</a>の翻訳、8回目です。<br/>
前回までの訳は<a href="http://golang.jp/effective_go">実践Go言語[日本語訳]</a>にまとめてあります。</p>
<hr/>
<h2 id="initialization">初期化</h2>
<p>初期化において、Go言語とCやC++言語では見かけ上それほど差がないように見えますが、Go言語の初期化はより強力です。複合構造体は初期化を行いながら構築することが可能です。また異なるパッケージ間においてもオブジェクトの初期化順序は正しく取り扱われます。</p>
<h3 id="constants">定数</h3>
<p>Go言語における定数は、その名の通り「定数」です。定数はコンパイル時に作成されます。これは定数が関数内でローカルに定義されているときも同様です。ただし定数となり得るのは数値、文字列、論理値だけです。定数はコンパイル時に作成されるという制約上、コンパイラによって評価可能な定数式でなければなりません。たとえば<code>1&lt;&lt;3</code>は定数式ですが、<code>math.Sin(math.Pi/4)</code>は定数式ではありません。これは後者を評価するためには<code>math.Sin</code>の呼び出しが必要となるためです。</p>
<p>Go言語での定数の列挙には<code>iota</code>列挙子を使います。<code>iota</code>は式の一部となって、かつその式は暗黙的に繰り返すことができるので値の複雑なセットも簡単に作成することができます。</p>
<pre>type ByteSize float64
const (
    _ = iota  // 一番目の値はブランク識別子に代入して無視
    KB ByteSize = 1&lt;&lt;(10*iota)
    MB
    GB
    TB
    PB
    EB
    ZB
    YB
)</pre>
<p><code>String</code>のようなメソッドを型と結びつけることができるので、型の一部として上のような値を出力用に自前で自動フォーマットすることが可能になります。</p>
<pre>func (b ByteSize) String() string {
    switch {
    case b &gt;= YB:
        return fmt.Sprintf("%.2fYB", b/YB)
    case b &gt;= ZB:
        return fmt.Sprintf("%.2fZB", b/ZB)
    case b &gt;= EB:
        return fmt.Sprintf("%.2fEB", b/EB)
    case b &gt;= PB:
        return fmt.Sprintf("%.2fPB", b/PB)
    case b &gt;= TB:
        return fmt.Sprintf("%.2fTB", b/TB)
    case b &gt;= GB:
        return fmt.Sprintf("%.2fGB", b/GB)
    case b &gt;= MB:
        return fmt.Sprintf("%.2fMB", b/MB)
    case b &gt;= KB:
        return fmt.Sprintf("%.2fKB", b/KB)
    }
    return fmt.Sprintf("%.2fB", b)
}</pre>
<p>式<code>YB</code>の出力は<code>1.00YB</code>になり、<code>ByteSize(1e13)</code>の出力は<code>9.09TB</code>となります。</p>
<h3 id="variables">変数</h3>
<p>変数は、定数と同じように初期化することができますが、変数のイニシャライザは通常の式であり、実行時に評価されます。</p>
<pre>var (
    HOME = os.Getenv("HOME")
    USER = os.Getenv("USER")
    GOROOT = os.Getenv("GOROOT")
)</pre>
<h3 id="init">init関数</h3>
<p>最後になりますが、各ソースファイルにはそれぞれ必要に応じて、セットアップのために<code>init()</code>関数を定義することができます。ひとつだけ制約があり、初期化中にゴルーチンを起動することはできますが、初期化が完了するまで実行は開始しません。すなわち、初期化処理中に実行されるスレッドは常にひとつだけです。</p>
<p><code>init()</code>関数は、パッケージでインポートしている他のパッケージが初期化されたあと、パッケージ内で宣言されているすべての変数のイニシャライザが評価されたあとに呼び出されます。<code>init()</code>関数の一般的な使い方は、宣言としては記述できないような初期化処理を行うほか、処理の実行開始直前に、プログラムのステートの妥当性チェックおよびステートの修正を行います。</p>
<pre>func init() {
    if USER == "" {
        log.Exit("$USER not set")
    }
    if HOME == "" {
        HOME = "/usr/" + USER
    }
    if GOROOT == "" {
        GOROOT = HOME + "/go"
    }
    // GOROOTはコマンドラインから--gorrotフラグを指定することで上書き可能
    flag.StringVar(&amp;GOROOT, "goroot", GOROOT, "Go root directory")
}</pre></div>
    </content>
    <updated>2010-03-04T09:00:57Z</updated>
    <category term="&#x30C9;&#x30AD;&#x30E5;&#x30E1;&#x30F3;&#x30C8;"/>
    <category term="&#x5B9F;&#x8DF5;Go&#x8A00;&#x8A9E;"/>
    <author>
      <name>noboru</name>
    </author>
    <source>
      <id>http://golang.jp</id>
      <link href="http://golang.jp/feed" rel="self" type="application/atom+xml"/>
      <link href="http://golang.jp" rel="alternate" type="text/html"/>
      <subtitle>プログラミング言語Goの情報サイト</subtitle>
      <title>Google's Go Guide</title>
      <updated>2010-03-12T08:00:13Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-7271053592768591031</id>
    <link href="http://reneefrench.blogspot.com/feeds/7271053592768591031/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=7271053592768591031" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/7271053592768591031" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/7271053592768591031" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/03/earnow.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://3.bp.blogspot.com/_va9O40qIhaE/S49sVvwHZvI/AAAAAAAACWQ/APdNsKNpnzo/s1600-h/assnakescape.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5444689595365549810" src="http://3.bp.blogspot.com/_va9O40qIhaE/S49sVvwHZvI/AAAAAAAACWQ/APdNsKNpnzo/s320/assnakescape.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 296px; height: 320px;"/></a>earnow<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-7271053592768591031?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-03-04T08:16:47Z</updated>
    <published>2010-03-03T09:16:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="tonal drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:38001</id>
    <link href="http://blog.notdot.net/2010/03/Announcing-the-SQLite-datastore-stub-for-the-Python-App-Engine-SDK" rel="alternate" type="text/html"/>
    <title>Announcing the SQLite datastore stub for the Python App Engine SDK</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>For the past couple of weeks, I've been working on one of those projects that seems to suck up every available moment (and some that technically aren't). Now, however, it's largely done, and as an extra bonus, I've been given permission to release it as an early preview for those that are interested.</p>

<p>The code in question is a new implementation of the local datastore for the Python App Engine SDK. While some of you are probably delighted at the news, I expect most of you are puzzled. Why do we need a new local datastore implementation? Let me explain.</p>

<p>The purpose of the local stubs in the App Engine SDK is to exactly replicate the behaviour of the production environment, and in general they do that very well. A specific non-goal is replicating the performance characteristics of the production environment, or being as scalable as the production environment - the stubs are designed for testing, not production use.</p>

<p>The Python SDK's datastore implementation operates by storing the entire contents of your development datastore in memory. It writes changes to disk so that it can reload your datastore when the dev_appserver is restarted, but the in-memory copy is the primary source for all operations. Queries are executed by iterating over every entity of the right kind and filtering based on the criteria you specify.</p>

<p>Despite the use of a linear scan, this straightforward implementation is more than sufficient for most developers. The amount of test data one typically wants to load is fairly small, and it's hard to beat the performance you get from having everything stored in memory. Problems arise, however, when you need to load a larger than normal amount of test data into your app. As soon as the amount of stored data (including storage and indexing overhead) exceeds your available physical memory, performance slows down dramatically, as the dev_appserver has to page bits of the datastore to and from disk. Startup performance can be impacted, too, since the datastore stub has to read the entire datastore off disk each time the dev_appserver is started.</p>

<p>The new local datastore implementation fixes both these issues by rewriting the datastore stub to use SQLite as a backend. Data is stored by SQLite on disk, so memory consumption should not be a problem, and startup times will likewise be unaffected by the size of the local datastore. Here's what you can expect with the new datastore stub:</p>

<ul>
  <li>Improved startup times if you store a lot of data in your local datastore.</li>
  <li>Improved performance if you store a lot of data in your local datastore.</li>
  <li>Lower memory consumption.</li>
</ul>

<p>Equally importantly, though, here's what you <em>shouldn't</em> expect:</p>

<ul>
  <li>Performance improvements when dealing with small amounts of data. Although a linear scan for all queries sounds inefficient, it really is hard to beat keeping all your data in memory for speed - so if you have relatively little data, you may not see much or any improvement.</li>
  <li>A relational schema. If you open up the SQLite database created by the dev_appserver, don't expect it to be laid out with a table per kind, and columns for properties. More on how the datastore <em>is</em> structured later, if you're interested.</li>
</ul>

<p>Also, please bear in mind that this is pre-release code. It may wipe out all your data. It may cause the spontaneous generation of a black hole which swallows your cat. It may even work as expected! Nearly anything could happen.</p>

<p>Without further ado, you can get the patch and instructions on how to use it <a href="https://sites.google.com/site/sqlitedatastorestub/">here</a>. Feedback is appreciated - either in the groups, or right here on my blog.</p>

<h3>How it works</h3>

<p>What follows is a description of some of the internal workings of the datastore_sqlite_stub. If you just want to use it, you can stop now - otherwise, read on!</p>

<p>The basic structure of the SQLite stub is very similar to that used by the production datastore. An 'Entities' table holds all the entities, indexed by entity type and the 'path' component of their key. An 'EntitiesByProperty' table stores every indexed property for every entity, with columns for kind, property name, property value, and the path of the entity this row refers to.</p>

<p>All permitted queries can be executed by selecting from the Entities table, with some number of joins to the EntitesByProperty table. For example, a kind-only query or an ancestor-only query can be satisfied by the Entities table alone. A single property query requires a single join to the EntitiesByProperty table, constrained to find only entities with the correct kind, property name, and value (or range of values). Finally, multiple property queries are satisfied by using multiple joins to the EntitiesByProperty table, one for each required property. Unlike the production datastore, composite indexes aren't (currently) implemented, so queries that would normally require a composite indexes use the aforementioned strategy, leaving it up to the DB to find an efficient query plan.</p>

<p>Another difference from the production datastore is that data in the SQLite stub is partitioned by app ID - so each app has its own Entity and EntitiesByProperty tables.</p>

<h3>Data representation and indexing</h3>

<p>Data representation provides a particular challenge when it comes to indexing. App Engine provides a wide array of <a href="http://code.google.com/appengine/docs/python/datastore/typesandpropertyclasses.html">data types</a>, and since the datastore is schemaless, any field can potentially contain any datatype.</p>

<p>Unlike most relational databases, SQLite uses a dynamic typing system, whereby any field can be of any data type - types declared in CREATE TABLE statements merely define 'affinities'. At first glance, this would appear to solve our problem - we can simply store the values as you would expect, and SQLite will allow us. We immediately run into a couple of problems, however.</p>

<p>The first problem is that SQLite doesn't provide the same sorting characteristics as the App Engine datastore. For example, while App Engine sorts all integers before all floats, SQLite sorts them by their magnitude. This could be remedied by splitting the column into two parts - the type and the value - and sorting by them and selecting on them both, were it not for the second issue...</p>

<p>The second issue is that SQLite doesn't implement all the data types App Engine provides - for example, <a href="http://code.google.com/appengine/docs/python/datastore/keyclass.html">Key</a> and <a href="http://code.google.com/appengine/docs/python/datastore/typesandpropertyclasses.html#GeoPt">GeoPt</a>. In order to be completely consistent with production, the ordering on these properties is important, too - it's not enough to be able to check for equality. Given that, it looks like we're going to need an alternative encoding scheme.</p>

<p>At first glance, Protocol Buffers seem like they should be it. Given the same values for fields, the Protocol Buffer encoder will always create the same binary PB, so we can definitely compare for equality. Individual fields of a Protocol Buffer are emitted in order, too, so thanks to the way the App Engine PBs are designed, in theory we ought to sort each data type correctly as well. This brilliant idea, alas, is torpedoed by several practical issues with sorting Protocol Buffers:</p>

<ol>
  <li>PBs encode fixed length fields like integers and floats little-endian, which doesn't sort correctly.</li>
  <li>Variable length integers are encoded using a <a href="http://code.google.com/apis/protocolbuffers/docs/encoding.html#varints">scheme</a> that likewise does not preserve ordering of the number being encoded.</li>
  <li>Strings are length-prefixed, which means strings are compared first based on size, then on contents - 'aaa' sorts after 'z'!</li>
</ol>

<p>In production, App Engine solves this by using a special encoding for Protocol Buffers that preserves the desired ordering properties - and that's the approach the SQLite stub takes, too. Here's how it deals with each of the three issues outlined above:</p>

<ol>
  <li>Fixed length numbers are encoded big-endian, so they sort as expected. Further, the sign bit is flipped, and the entire value is inverted with a bitwise NOT if it's negative, to ensure that negative numbers sort smaller than positive numbers.</li>
  <li>Variable length integers are encoded by a special scheme that uses the first byte to indicate the sign of the number and the number of bytes that follow. Small values (between -119 and 119) are encoded in a single byte to save space.</li>
  <li>Strings are escaped instead of being length prefixed. Nulls in a string (\0) are replaced with the escape sequence \1\1, while \1 bytes are replaced with \1\2. Strings are then terminated with a null byte. This encoding is reversible, but ensures the strings still sort in the same order as they did previously.</li>
</ol>

<p>With a Protocol Buffer encoder that implements those tweaks, we can simply encode the fields we want to index using it, and insert them as BLOB fields into the database. The encoding ensures that SQLite can sort them as byte values, without needing to interpret or understand them, and the sort order will come out as expected.</p>

<p>That's it for the description of the internals. If you decide to try out the new local datastore, please do provide feedback - here, or in the <a href="http://groups.google.com/group/google-appengine-python">official group</a>.</p></div>
    </content>
    <updated>2010-03-03T14:49:54Z</updated>
    <published>2010-03-03T14:49:06Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-03-12T16:51:18Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://www.airs.com/blog/?p=327</id>
    <link href="http://www.airs.com/blog/archives/327" rel="alternate" type="text/html"/>
    <title>Signed or Unsigned</title>
    <summary>C has always permitted comparisons between any integer type, and C++ follows its lead.  Comparing signed types to signed types is straightforward: you sign extend the smaller type.  Likewise, when comparing unsigned types to unsigned types, you zero extend.  When comparing signed and unsigned types, the rules are less clear.
The C standard [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>C has always permitted comparisons between any integer type, and C++ follows its lead.  Comparing signed types to signed types is straightforward: you sign extend the smaller type.  Likewise, when comparing unsigned types to unsigned types, you zero extend.  When comparing signed and unsigned types, the rules are less clear.</p>
<p>The C standard specifies a type ordering: long long &gt; long &gt; int &gt; short &gt; char.  If the unsigned type appears in that ordering before the signed type, then the signed value is converted to the unsigned type.  Note that this happens even if the types are the same size (e.g., either long long and long or long and int are often the same size).  Otherwise, if the signed type is larger than the unsigned type, in the sense of having more bits, then the unsigned value is converted to the signed type.  Otherwise both values are converted to the unsigned type which corresponds to the signed type.</p>
<p>Pre-standard K&amp;R C used a different rule, but that is old enough now that we no longer have to worry about it.</p>
<p>What this rule means is that if you write portable code, such that you don’t know the sizes of types, you can not predict whether the comparison will be done as a signed comparison or an unsigned comparison.  Therefore, the gcc compiler has an option <code>-Wsign-compare</code>.  However, this option is sufficiently awkward to avoid that it is not part of <code>-Wall</code>, though it is part of <code>-Wextra</code> (the difference between <code>-Wall</code> and <code>-Wextra</code> is that the former gives warnings for which false positives are easy to avoid through simple code changes; the latter gives warnings which are generally useful but for which false positives are harder to avoid).</p>
<p>There are good reasons to use signed types: they don’t have odd behaviour around zero, so you can write <code>i &lt; limit - 1</code> without worrying about the case <code>limit == 0</code>.  There are good reasons to use unsigned types for things like the number of elements in a container: you get the full range of sizes, rather than limiting yourself to only the positive half.  In particular, the C++ standard containers use unsigned types as their size.  Combining these two rules gets you in trouble with portable code.  The only reasonable answer I can see for portable code is to use <code>-Wsign-compare</code> and work around the many false positive warnings.</p>
<p>Go avoids these problems in two ways.  First, there are no implicit conversions, so you can never be surprised by having a comparison become unsigned when you expected signed.  You have to explicitly say which type of conversion you mean.  Second, Go intentionally discards half of memory, and takes the philosophy that if you want a container which can hold more values than fit in a signed int, you should write a special purpose large container.</p></div>
    </content>
    <updated>2010-03-03T14:15:54Z</updated>
    <category term="Programming"/>
    <author>
      <name>Ian Lance Taylor</name>
    </author>
    <source>
      <id>http://www.airs.com/blog</id>
      <link href="http://www.airs.com/blog/feed" rel="self" type="application/atom+xml"/>
      <link href="http://www.airs.com/blog" rel="alternate" type="text/html"/>
      <subtitle>Ian Lance Taylor</subtitle>
      <title>Airs - Ian Lance Taylor</title>
      <updated>2010-03-09T08:00:16Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-3572284592825852374</id>
    <link href="http://reneefrench.blogspot.com/feeds/3572284592825852374/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=3572284592825852374" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/3572284592825852374" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/3572284592825852374" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/03/1231111.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://4.bp.blogspot.com/_va9O40qIhaE/S411hJIIcfI/AAAAAAAACWI/uw7RFSVFDRs/s1600-h/snowbeesm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5444136736806957554" src="http://4.bp.blogspot.com/_va9O40qIhaE/S411hJIIcfI/AAAAAAAACWI/uw7RFSVFDRs/s320/snowbeesm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 320px; height: 225px;"/></a>1231111<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-3572284592825852374?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-03-02T20:31:44Z</updated>
    <published>2010-03-02T20:25:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="tonal drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-261037472283732641</id>
    <link href="http://reneefrench.blogspot.com/feeds/261037472283732641/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=261037472283732641" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/261037472283732641" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/261037472283732641" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/03/broken-citroen.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://1.bp.blogspot.com/_va9O40qIhaE/S41zSMxJDoI/AAAAAAAACWA/B5FhcP8RkBE/s1600-h/dwcampion.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5444134281062977154" src="http://1.bp.blogspot.com/_va9O40qIhaE/S41zSMxJDoI/AAAAAAAACWA/B5FhcP8RkBE/s320/dwcampion.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 240px; height: 320px;"/></a>broken citroen<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-261037472283732641?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-03-02T20:25:10Z</updated>
    <published>2010-03-01T20:21:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="notes"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="ja">
    <id>http://golang.jp/?p=1228</id>
    <link href="http://golang.jp/2010/03/1228" rel="alternate" type="text/html"/>
    <title>実践Go言語(part7)</title>
    <summary>実践Go言語(Effective Go)の翻訳、7回目です。
前回までの訳は実践Go言語[日本語訳]にまとめてあります。

データ
new()による割り当て
Go言語の基本的なメモリ割り当てには、new()とmake() [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><a href="http://golang.org/doc/effective_go.html" target="_blank">実践Go言語(Effective Go)</a>の翻訳、7回目です。<br/>
前回までの訳は<a href="http://golang.jp/effective_go">実践Go言語[日本語訳]</a>にまとめてあります。</p>
<hr/>
<h2 id="data">データ</h2>
<h3 id="allocation_new">new()による割り当て</h3>
<p>Go言語の基本的なメモリ割り当てには、<code>new()</code>と<code>make()</code>の2つがあります。これら2つはそれぞれ異なる働きをし、適用先の型も別となります。混乱させてしまうかもしれませんがルールは単純です。</p>
<p>まず<code>new()</code>について説明します。これは組み込み関数であり、他の言語における<code>new()</code>と基本的に同じです。<code>new(T)</code>は、型<code>T</code>の新しいアイテム用にゼロ化した領域を割り当て、そのアドレスである<code>*T</code>型の値を返します。Go言語風に言い換えると、<code>new(T)</code>が返す値は、新しく割り当てられた型<code>T</code>のゼロ値のポインタです。</p>
<p><code>new()</code>から返されるメモリはゼロ化されています。ゼロ化済みオブジェクトは、さらなる初期化を行わなくても使用できるため、こういったオブジェクトの準備に<code>new()</code>は便利です。すなわち、データ構造体の利用者が<code>new()</code>でそれを作成すると、すぐに使える状態となります。たとえば、<code>bytes.Buffer</code>のドキュメントには、「<code>Buffer</code>のゼロ値は、利用準備が整った空のバッファである。」と記述されています。同様に<code>sync.Mutex</code>には明示的なコンストラクタや<code>Init</code>メソッドは用意されていませんが、その代わりに<code>sync.Mutex</code>のゼロ値は、非ロック状態のミューテックスであることが定められています。</p>
<p>この便利なゼロ値は連鎖的に働きます。下の型宣言をみてください。</p>
<pre>type SyncedBuffer struct {
    lock    sync.Mutex
    buffer  bytes.Buffer
}</pre>
<p>この<code>SyncedBuffer</code>型の値もまた、割り当てや宣言を行うと同時に使用準備が整います。下のコードの変数<code>p</code>と<code>v</code>は、このままで正しく機能します。</p>
<pre>p := new(SyncedBuffer)  // type *SyncedBuffer
var v SyncedBuffer      // type  SyncedBuffer</pre>
<h3 id="composite_literals">コンストラクタと複合リテラル</h3>
<p>下の例は<code>os</code>パッケージからの抜粋です。この例のようにゼロ値では充分でなく、コンストラクタによる初期化が必要となることがあります。</p>
<pre>func NewFile(fd int, name string) *File {
    if fd &lt; 0 {
        return nil
    }
    f := new(File)
    f.fd = fd
    f.name = name
    f.dirinfo = nil
    f.nepipe = 0
    return f
}</pre>
<p>上のコードには冗長な部分が多く見られます。複合リテラルとは、実行する度に新しいインスタンスを生成する式であり、これを使うことで下のコードのように単純化することができます。</p>
<pre>func NewFile(fd int, name string) *File {
    if fd &lt; 0 {
        return nil
    }
    f := File{fd, name, nil, 0}
    return &amp;f
}</pre>
<p>このようにローカル変数のアドレスを返しても問題ありません。関数から戻ったあとも、変数に割り当てたメモリは生き残ります。複合リテラルのアドレスを取得したときは、実行する度に新しいインスタンスが割り当てられる仕様なので、最後の2行を次のようにまとめることができます。</p>
<pre>    return &amp;File{fd, name, nil, 0}</pre>
<p>複合リテラルでは、すべてのフィールドを順番通りに記述しなければなりません。ただし明示的に「フィールド:値」の組み合わせで要素にラベルをつけたときは、イニシャライザは順序通りである必要はなく、また指定しなかった要素には、その型のゼロ値がセットされます。すなわち次のように書き換えられます。</p>
<pre>    return &amp;File{fd: fd, name: name}</pre>
<p>特殊なケースとして、複合リテラルがひとつもフィールドを含まないときは、その型のゼロ値が作られます。すなわち、式<code>new(File)</code>と<code>&amp;File{}</code>は等価です。</p>
<p>また複合リテラルでは、フィールドのラベルをインデックスまたはマップのキーとみなして、配列、スライス、マップを作成することもできます。次の例において、<code>Enone</code>、<code>Eio</code>、<code>Einval</code>がそれぞれ個別の変数でありさえすれば、その値に関わらず初期化は成功します。</p>
<pre>a := [...]string   {Enone: "no error", Eio: "Eio", Einval: "invalid argument"}
s := []string      {Enone: "no error", Eio: "Eio", Einval: "invalid argument"}
m := map[int]string{Enone: "no error", Eio: "Eio", Einval: "invalid argument"}</pre>
<h3 id="allocation_make">make()による割り当て</h3>
<p>割り当てに話を戻します。組み込み関数<code>make(T, </code><em>args</em><code>)</code>は、<code>new(T)</code>とは使用目的が異なります。<code>make</code>で割り当てできるのはスライス、マップ、チャネルだけであり、初期化された、すなわちゼロ値でない<code>T</code>型(<code>*T</code>でない)の値を返します。<code>make</code>と<code>new</code>を使い分ける理由は、これらの3つの型が隠蔽されたデータ構造への参照であり、このデータ構造が使用前に初期化されている必要があるためです。スライスを例にとると、スライスはデータ(配列内)へのポインタ、長さ、キャパシティという３つの情報から構成されており、それらの情報が初期化されるまではスライスの値は<code>nil</code>です。<code>make</code>はスライス、マップ、チャネルの内部データ構造を初期化し、使用可能となるよう値を準備します。下は、<code>make</code>の例です。</p>
<pre>make([]int, 10, 100)</pre>
<p>この例では、100個のintを持つ配列を割り当てたあと、その配列の先頭から10個目までの要素を示す、長さが10でキャパシティ100のスライス構造を作成します。(スライス作成時、キャパシティは省略可能です。詳細はスライスに関するセクションを参照ください。)これに対して、<code>new([]int)</code>は新しくメモリを割り当て、ゼロ化したスライス構造のポインタを返します。つまりこれは<code>nil</code>スライス値へのポインタです。</p>
<p>下は、<code>new()</code>と<code>make()</code>の違いを例示したものです。</p>
<pre>var p *[]int = new([]int)       // スライス構造の割り当て(*p == nil)。あまり使わない。
var v  []int = make([]int, 100) // vは100個のintを持つ配列への参照

// 必要以上に複雑な書き方
var p *[]int = new([]int)
*p = make([]int, 100, 100)

// 一般的な書き方
v := make([]int, 100)</pre>
<p>覚えておいていただきたいことは、<code>make()</code>が適用可能なのはマップ、スライス、チャネルだけであり、返されるのはポインタではないことです。ポインタが必要であれば<code>new()</code>で割り当ててください。</p>
<h3 id="arrays">配列</h3>
<p>配列はメモリ配置を厳密に指定したいときや、ときにはメモリ割り当てを回避したいときに役立ちますが、配列の主な役割は、次セクションの主題であるスライスから参照されることです。そのスライスについて説明する前に基礎知識として、配列について2、3説明しておきます。</p>
<p>Go言語とC言語では配列の動作に大きな違いがあります。Go言語では次のように振舞います。</p>
<ul>
<li> 配列は値です。ある配列を他へ代入するとすべての要素がコピーされます。</li>
<li> すなわち関数に配列を渡すと、関数側ではポインタではなく、その配列のコピーを受け取ります。</li>
<li> 配列のサイズは型の一部です。<code>[10]int</code>と<code>[20]int</code>は異なる型です。</li>
</ul>
<p>値として扱うと有用なこともありますが、高コストでもあるため、C言語のような動作と効率が必要であれば、配列へのポインタを関数に渡すことも可能です。</p>
<pre>func Sum(a *[3]float) (sum float) {
    for _, v := range *a {
        sum += v
    }
    return
}

array := [...]float{7.0, 8.5, 9.1}
x := Sum(&amp;array)  // 注：明示的にアドレス演算子を使用</pre>
<p>しかし、これはGo言語では一般的ではなく、通常はスライスを使用します。</p>
<h3 id="slices">スライス</h3>
<p>スライスは配列をラップして、データ列に対しより普遍的かつ効果的で使い易いインタフェースを提供します。変換行列のような明らかに多次元のデータ構造を扱う場合を除いて、配列を扱うGo言語のプログラムでは、配列そのままではなくスライスが多用されます。</p>
<p>スライスは参照型です。すなわちスライスを別のスライスに代入したときは、双方が同じ配列を参照します。たとえば関数がスライスを引数として取るとき、関数内でスライスの要素に変更を加えると、ポインタ渡しのように関数の呼び元からも変更内容が参照できます。ゆえに<code>Read</code>関数では、引数としてポインタと個数を受け取る代わりに、スライスを受け取ることが可能となります。このときスライスが持つ長さ情報は、読み込むべきデータの上限となります。下は、<code>os</code>パッケージの<code>File</code>型の<code>Read</code>メソッドのシグネチャです。</p>
<pre>func (file *File) Read(buf []byte) (n int, err os.Error)</pre>
<p>このメソッドは読み込んだバイト数と、エラーがあればエラー値を返します。ある大きなバッファ<code>buf</code>から先頭32バイトを読み込むためには、次のようにバッファをスライスしてください。※この「スライス」という言葉は名詞ではなく動詞です。</p>
<pre>    n, err := f.Read(buf[0:32])</pre>
<p>こういったスライスの使い方は一般的かつ効率的です。実際のところ、あまり効率を考慮に入れなければ、下のコードでも同様にバッファの先頭32バイトを読み込めます。</p>
<pre>    var n int
    var err os.Error
    for i := 0; i &lt; 32; i++ {
        nbytes, e := f.Read(buf[i:i+1])  // 1バイト読み込み
        if nbytes == 0 || e != nil {
            err = e
            break
        }
        n += nbytes
    }</pre>
<p>スライスが持つ長さ情報は、その参照先配列の範囲内であれば変更することができます。(試しにスライスを同じスライスに代入し直してみてください。) スライスのキャパシティは組み込み関数の<code>cap</code>で参照できます。キャパシティとはスライスが扱える長さの上限値です。<br/>
下はスライスにデータを追加する関数です。この関数ではデータの長さがキャパシティを超えるときは、スライスは再割り当てされ、結果得られたスライスが関数から返されます。<code>nil</code>スライスが関数に与えられたときには、仕様上<code>nil</code>スライスが<code>len</code>、<code>cap</code>ともに0を返すことを利用しています。</p>
<pre>func Append(slice, data[]byte) []byte {
    l := len(slice)
    if l + len(data) &gt; cap(slice) {  // reallocate
        // 再利用を考慮し、必要なサイズの倍、割り付ける
        newSlice := make([]byte, (l+len(data))*2)
        // Copy data (could use bytes.Copy()).
        for i, c := range slice {
            newSlice[i] = c
        }
        slice = newSlice
    }
    slice = slice[0:l+len(data)]
    for i, c := range data {
        slice[l+i] = c
    }
    return slice
}</pre>
<p><code>Append</code>では<code>slice</code>の要素を変更していますが、スライス自体(ランタイムデータ構造がポインタ、長さ、キャパシティを保持している)は値渡しされているため、処理を終えたあと関数からスライスを返す必要があります。</p>
<h3 id="maps">マップ</h3>
<p>マップは、異なる型の値を結びつける便利で強力な組み込みデータ構造です。マップのキーには、イコール演算子が定められていればどんな型(例えば整数、浮動小数、文字列、ポインタ、動的な型がイコールをサポートするのであればインタフェースさえ)でも使えます。ですが構造体、配列、スライスにはイコールが定義されていないため、マップのキーとして使用することはできません。スライスと同じくマップもまた参照型であるため、マップを関数に渡し、その関数内でマップの内容に変更を加えると、変更内容は呼び出し元からも参照可能です。</p>
<p>複合リテラル構文を使い、キーと値をコロン区切りで指定することでマップを作成できるので、作成と同時に初期化が簡単に行えます。</p>
<pre>var timeZone = map[string] int {
    "UTC":  0*60*60,
    "EST": -5*60*60,
    "CST": -6*60*60,
    "MST": -7*60*60,
    "PST": -8*60*60,
}</pre>
<p>マップへの値の設定と取得は、配列の操作と構文的に似通っていますが、インデックスが整数である必要がない点で異なります。マップ内に存在しないキーを使って、マップから値を取得しようとするとプログラムがクラッシュする要因と成り得るので、これを回避するため下のように複数代入式を使ってください。</p>
<pre>var seconds int
var ok bool
seconds, ok = timeZone[tz]</pre>
<p>これは見たままですが、「カンマok」慣用句と呼ばれています。この例では、<code>tz</code>が存在すれば、<code>seconds</code>に適切な値がセットされ、<code>ok</code>の値は真となります。存在しなければ、<code>seconds</code>にはゼロがセットされ、<code>ok</code>の値は偽となります。下はこれを利用した関数です。</p>
<pre>func offset(tz string) int {
    if seconds, ok := timeZone[tz]; ok {
        return seconds
    }
    log.Stderr("unknown time zone", tz)
    return 0
}</pre>
<p>マップ内に値が存在するか調べたいとき、値自体の取得が不要であればブランク識別子(ただのアンダーライン(_))を使うことができます。ブランク識別子を使うとどんな型の値でも代入または宣言することができ、値を他に影響およぼすことなく破棄することができます。マップ内の存在チェックをするときは、次のように本来は値が返される変数の代わりにブランク識別子を指定してください。</p>
<pre>_, present := timeZone[tz]</pre>
<p>マップから登録を削除するには、代入方向を変えて複数代入式の右側に論理値を指定してください。この論理値の値が偽のとき登録が削除されます。このときマップ内にキーが存在しなくても問題ありません。</p>
<pre>timeZone["PDT"] = 0, false  // 標準時に</pre>
<h3 id="printing">出力</h3>
<p>Go言語におけるフォーマット出力は、C言語の<code>printf</code>群のスタイルと類似していますが、より高機能・多機能です。これら関数は<code>fmt</code>パッケージ内で定義されています。先頭一文字は大文字となっており、<code>fmt.Printf</code>、<code>fmt.Fprintf</code>、<code>fmt.Sprintf</code>などが用意されています。文字列関数(<code>Sprintf</code>など)は、指定したバッファに文字列を格納するのではなく、新しい文字列を返します。</p>
<p>フォーマット文字列の指定は必要ではありません。各<code>Printf</code>、<code>Fprintf</code>、<code>Sprintf</code>にはそれぞれ他にペアとなる関数、例えば<code>Print</code>と<code>Println</code>が用意されています。これらの関数はフォーマット文字列をとらず、代わりに引数ごとにデフォルトフォーマットを生成します。<code>ln</code>版では、引数の間に両引数とも文字列でないときだけ空白を挿入し、出力の後ろに改行を付加します。[訳注：実際試したところ、非<code>ln</code>版のときは引数がともに文字列でないときだけ引数間に空白が挿入されるのに対し、<code>ln</code>版のときは常に空白が挿入されるようです] 下の例では、各行はいずれも同じ内容を出力します。</p>
<pre>fmt.Printf("Hello %d\n", 23)
fmt.Fprint(os.Stdout, "Hello ", 23, "\n")
fmt.Println(fmt.Sprint("Hello ", 23))</pre>
<p>チュートリアルでも解説したように、<code>fmt.Fprint</code>とそれに関連する関数は、一番目の引数に<code>io.Writer</code>インタフェースを実装していればどんなオブジェクトでも指定可能です。 よく使われるのは、お馴染みの変数<code>os.Stdou</code>と<code>os.Stderr</code>です。</p>
<p>ここからC言語との違いが現れます。まず、<code>%d</code>のような数値フォーマットでは、フラグによる符号やサイズの指定は行いません。その代わりに出力ルーチンは、引数の型を参照して値の属性を決定します。</p>
<pre>var x uint64 = 1&lt;&lt;64 - 1
fmt.Printf("%d %x; %d %x\n", x, x, int64(x), int64(x))</pre>
<p>これの出力結果です。</p>
<pre>18446744073709551615 ffffffffffffffff; -1 -1</pre>
<p>例えば整数値を10進表記で出力するようなデフォルトの変換でよければ、どんなケースにも対応可能なフォーマット<code>%v</code>を使うことができます。このとき出力される内容は、<code>Print</code>と<code>Println</code>の出力結果と全く同じです。さらにこのフォーマットは、配列、構造体、マップなどどんな値でも出力することができます。下は、前のセクションで定義したタイムゾーンマップを出力するステートメントです。</p>
<pre>fmt.Printf("%v\n", timeZone)  // fmt.Println(timeZone)としても同じ</pre>
<p>これの出力結果です。</p>
<pre>map[CST:-21600 PST:-28800 EST:-18000 UTC:0 MST:-25200]</pre>
<p>マップの出力では、キーの出力は当然ながら順不同となります。<br/>
構造体を出力するとき、限定フォーマット<code>%+v</code>を使うと構造体の各フィールドに対してフィールド名も出力されます。また、代替フォーマット<code>%#v</code>を使うとどんな値でも完全なGo言語の構文形式で出力されます。</p>
<pre>type T struct {
    a int
    b float
    c string
}
t := &amp;T{ 7, -2.35, "abc\tdef" }
fmt.Printf("%v\n", t)
fmt.Printf("%+v\n", t)
fmt.Printf("%#v\n", t)
fmt.Printf("%#v\n", timeZone)</pre>
<p>これらの出力結果です。(アンパサンドに注意)</p>
<pre>&amp;{7 -2.35 abc   def}
&amp;{a:7 b:-2.35 c:abc     def}
&amp;main.T{a:7, b:-2.35, c:"abc\tdef"}
map[string] int{"CST":-21600, "PST":-28800, "EST":-18000, "UTC":0, "MST":-25200}</pre>
<p>引用符付き文字列の出力も、<code>string</code>または<code>[]byte</code>型の値に対して<code>%q</code>を使えば可能です。(代替フォーマット<code>%#q</code>では、可能であればバッククォートを使います。) また<code>%x</code>を文字列またはバイト配列に対して適用したときは、整数に適用したときと同様に、長い16進数文字列を出力します。このときフォーマットにスペースを入れると(<code>% x</code>)、バイト間にスペースが出力されます。</p>
<p>もう一つの便利なフォーマットは<code>%T</code>です。これは値の型を出力します。</p>
<pre>fmt.Printf("%T\n", timeZone)</pre>
<p>これの出力結果です。</p>
<pre>map[string] int</pre>
<p>自作の型でデフォルトのフォーマット処理を制御したければ、必要なことはその型にメソッド<code>String() string</code>を定義するだけです。下は先ほどの型<code>T</code>に実装してみた例です。</p>
<pre>func (t *T) String() string {
    return fmt.Sprintf("%d/%g/%q", t.a, t.b, t.c)
}
fmt.Printf("%v\n", t)</pre>
<p>これのフォーマット出力結果です。</p>
<pre>7/-2.35/"abc\tdef"</pre>
<p>自作の<code>String()</code>メソッドは<code>Sprintf</code>からも呼び出されます。これは出力ルーチンが完全にリエントラント(再入可能)かつ再帰的に呼び出されるためです。もう少し手を加えて、出力ルーチンが受け取った引数を、同様の別ルーチンにそのまま渡すことも可能です。<code>Printf</code>のシグネチャの最後の引数には…型が使われているため、フォーマット指定以降には、いくつでもパラメータを指定できます。</p>
<pre>func Printf(format string, v ...) (n int, errno os.Error) {</pre>
<p><code>Printf</code>関数内の変数<code>v</code>は、別の出力ルーチンに渡すことも可能です。下は、以前使用した関数<code>log.Stderr</code>の実装です。ここでは、実際にフォーマット処理を行うために、<code>fmt.Sprintln</code>に引数をそのまま渡しています。</p>
<pre>// Stderrは標準出力にログを簡単に出力するヘルパー関数です。Fprint(os.Stderr)と似ています。
func Stderr(v ...) {
    stderr.Output(2, fmt.Sprintln(v))  // Outputはパラメータ (int, string)を取る
}</pre>
<p>ここで説明した範囲は出力機能のほんの一部です。より詳しい説明はパッケージ<code>fmt</code>の<code>godoc</code>ドキュメントを参照ください。</p></div>
    </content>
    <updated>2010-03-02T07:17:20Z</updated>
    <category term="&#x30C9;&#x30AD;&#x30E5;&#x30E1;&#x30F3;&#x30C8;"/>
    <category term="&#x5B9F;&#x8DF5;Go&#x8A00;&#x8A9E;"/>
    <author>
      <name>noboru</name>
    </author>
    <source>
      <id>http://golang.jp</id>
      <link href="http://golang.jp/feed" rel="self" type="application/atom+xml"/>
      <link href="http://golang.jp" rel="alternate" type="text/html"/>
      <subtitle>プログラミング言語Goの情報サイト</subtitle>
      <title>Google's Go Guide</title>
      <updated>2010-03-12T08:00:14Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:27001</id>
    <link href="http://blog.notdot.net/2010/03/Handling-downtime-The-capabilities-API-and-testing" rel="alternate" type="text/html"/>
    <title>Handling downtime: The capabilities API and testing</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>After the <a href="http://groups.google.com/group/google-appengine-downtime-notify/browse_thread/thread/b4ed491a8b9ccce2">unfortunate outage</a> the other day, how to handle downtime with your App Engine app is a bit of a hot topic. So what better time to address proper error handling for situations where App Engine isn't performing at 100%?</p>

<p>There's three major topics to cover here: Handling timeouts from API calls, using the Capabilities API, and testing your app's support for handling failures. We'll go over them in order.</p>

<h3>Handling timeouts</h3>

<p>At the 'stub' level, timeouts and other exceptions are communicated by the stub throwing an <a href="http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/runtime/apiproxy_errors.py">google.appengine.runtime.apiproxy_errors.ApplicationError</a>. ApplicationError instances have an 'application_error' field, which contains an ID, drawn from <a href="http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/runtime/apiproxy_errors.py">google.appengine.runtime.apiproxy_errors</a>, which indicates the cause of the error. As you can see, DEADLINE_EXCEEDED is 4. Other errors of interest are OVER_QUOTA, which will occur if your app runs out of quota for a given API call or capability, and CAPABILITY_DISABLED, which is thrown if the API capability has been explicitly disabled (more on this later).</p>

<p>Each of the various APIs catches ApplicationErrors thrown by their stub, and wraps them in a higher level exception. The datastore, for example, has a function, <a>_ToDatastoreError</a> that maps different error codes to exceptions from <a href="http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/api/datastore_errors.py">datastore_errors</a>, which results in an ApplicationError(4) being transformed into a datastore_errors.Timeout exception. The urlfetch API, similarly, <a href="http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/api/urlfetch.py#316">maps exceptions</a>, with a timeout (along with some other errors) being represented as a DownloadError.</p>

<p>The best way to handle timeouts varies from API to API. The datastore API now automatically retries timed out operations. If it cannot execute the operation even after multiple timeouts, it will return a <a href="http://code.google.com/appengine/docs/python/datastore/exceptions.html">db.Timeout</a> exception (or a db.TransactionFailedError if the exception occurred inside a transaction). For an in-depth description of how to handle datastore timeouts and why they happen, I recommend <a href="http://code.google.com/appengine/articles/handling_datastore_errors.html">this excellent and well written article</a>.</p>

<p>Memcache, in contrast, generally <a href="http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/api/memcache/__init__.py#412">won't return timeout errors on get operations</a>, but will rather fail to return a value. Set operations return error codes rather than throwing exceptions, in conformance with the memcached API it imitates. See <a href="http://code.google.com/appengine/docs/python/memcache/clientclass.html">the memcache docs</a> for details.</p>

<p>Wherever possible, you should handle exceptions on a call-by-call basis, and deal with them appropriately. Sometimes, however, an exception from a given API call simply means you're unable to service the user's request, and have to show them an error page and ask them to try again later. In such situations, it helps to have a catch-all exception handler, which gets invoked for any exceptions that make it to the top level of your app. The webapp framework provides just such a facility in the form of the <a href="http://code.google.com/appengine/docs/python/tools/webapp/requesthandlerclass.html#RequestHandler_handle_exception">handle_exception</a> method, which gets called with the exception if your handler methods (get, post, etc) throw one. <a href="http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/webapp/__init__.py#377">By default</a>, this method calls self.error(500), logs the exception, and then prints the stacktrace to the output if debugging is enabled. Overriding this to present a nicer message to your users is probably a good idea - even better, override the error() method to display appropriate error pages for all the status codes your app can return!</p>

<h3>The Capabilities API</h3>

<p>While it's important to have proper exception handling for API calls, that's not all you can do. With the Capabilities API, you can proactively query App Engine to check if a given API, capability, or specific method is available. Documentation, unfortunately, is rather light at the moment, so consult <a href="http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/api/capabilities/__init__.py">the source</a> for details.</p>

<p>In general, calls to the Capabilities API take a service name - such as 'memcache' or 'datastore_v3' - and optionally either a 'capability', such as 'write', or a specific method, such as 'put'. The API then returns whether or not that entire API, capability, or individual method is available. For example:</p>

<pre class="prettyprint">from google.appengine.api import capabilities

images_enabled = capabilities.CapabilitySet('images').is_enabled()
datastore_write_enabled = capabilities.CapabilitySet('datastore_v3', capabilities=['write']).is_enabled()
memcache_get_enabled = capabilities.CapabilitySet('memcache', methods=['get']).is_enabled()</pre>

<p>We can make use of this to, for example, create some WSGI middleware that automatically returns a friendly error message any time the datastore is entirely disabled (presuming our app is dependent on the datastore, and sets a flag in the WSGI environment if it's read-only:</p>

<pre class="prettyprint">def capability_middleware(application):
  def wsgi_app(environ, start_response):
    if not capabilities.CapabilitySet('datastore_v3').is_enabled():
      print_error_message(environ, start_response)
    else:
      environ['capabilities.read_only'] = capabilities.CapabilitySet('datastore_v3', capabilities=['write']).is_enabled()
      return application(environ, start_response)

  return wsgi_app</pre>

<p>Obviously, far more sophisticated handling of disabled capabilities are possible - for example, you can use the 'read_only' flag the above middleware sets to disable any features of your site that require writing to the datastore, politely informing users that it's not available, rather than resorting to an error page.</p>

<h3>Testing timeouts and capabilities</h3>

<p>Once you've implemented proper error handling, and you're using the capabilities API, the question inevitably arises: How do I test this? We can do this using <a href="http://code.google.com/appengine/articles/hooks.html">hooks</a> - specifically, using a pre-call hook that throws the exception we want to test. Here's a class that makes it simple to test for error returns from APIs:</p>

<pre class="prettyprint">from google.appengine.runtime import apiproxy
from google.appengine.runtime import apiproxy_errors

class APIErrorHook(object):
  def __init__(self):
    self.error_map = {}  # Maps (api, method) tuples to error statuses

  def set_error_code(self, service, method, code):
    self.error_map[(service, method)] = code

  def get_error_code(self, service, method):
    """Returns the error code to return for a service and method, or None."""
    return self.error_map.get((service, method), None)

  def _error_hook(self, service, method, request, response):
    error_code = self.get_error_code(service, method)
    if error_code:
      raise apiproxy_errors.ApplicationError(error_code)

  def install(self, apiproxy, unique_name):
    apiproxy.GetPreCallHooks().Append(unique_name, self._error_hook)</pre>

<p>This should all be fairly straightforward: Once the hook is installed, calling set_error_code with a service and method name will cause all future invocations to raise an ApplicationError with that code. Calling set_error_code with None as the code will make the API call operate normally again. Here's an example of it in use:</p>

<pre class="prettyprint">from google.appengine.api import apiproxy_stub_map

error_hook = APIErrorHook()
error_hook.install(apiproxy_stub_map.apiproxy, 'error_hook')

db.get(a_key)  # Works

error_hook.set_error_code('datastore_v3', 'Get', apiproxy.DEADLINE_EXCEEDED)
db.get(a_key)  # Throws a db.Timeout error

error_hook.set_error_code('datastore_v3', 'Get', None)
db.get(a_key)  # Works again</pre>

<p>That's all there is to it. You can easily use this in your unit tests or for manual testing - just remember to install the API hook when you need it.</p>

<p>For testing the Capabilities API, we need a little more sophistication. The <a href="http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/api/capabilities/capability_stub.py">default implementation</a> of the capability service always returns 'ENABLED' for every call. Normally, modifying this behaviour would require writing our own capability stub and reaching into the SDK to replace the default one with our implementation. Fortunately, however, the capabilities API is simple enough that we can instead register a post-call hook that changes the return value to whatever we want it to be. Here's an extension of the above class that adds the ability to enable and disable APIs:</p>

<pre class="prettyprint">class CapabilityHook(APIErrorHook):
  # Maps (service, method) tuples to the capability it depends on
  _CAPABILITY_MAP = {
    ('datastore_v3', 'Put'): 'write',
    ('datastore_v3', 'Delete'): 'write',
  }

  def __init__(self):
    self.disabled_capabilities = set()  # Set of (service, capability) tuples that are disabled
    super(CapabilityHook, self).__init__()

  def set_capability_disabled(self, service, capability, disabled):
    if disabled:
      self.disabled_capabilities.add((service, capability))
    else:
      self.disabled_capabilities.discard((service, capability))

  def get_error_code(self, service, method):
    if (service, '*') in self.disabled_capabilities:
      return apiproxy.CAPABILITY_DISABLED
    required_capability = CapabilityHook._CAPABILITY_MAP.get((service, method), None)
    if required_capability and (service, required_capability) in self.disabled_capabilities:
      return apiproxy.CAPABILITY_DISABLED
    return super(CapabilityHook, self).get_error_code(service, method)

  def _capability_hook(self, service, method, request, response):
    # Accumulate a mapping of capabilities to enabled-ness
    capabilities = {}
    for capability in request.capability_list():
      if (method, capability) in self.disabled_capabilities:
        capabilities[(method, capability)] = False
      else:
        capabilities[(method, capability)] = True
    for method in request.call_list():
      required_capability = CapabilityHook._CAPABILITY_MAP.get(method, '*')
      if required_capability in self.disabled_capabilities or (service, '*') in self.disabled_capabilities:
        capabilities[(method, capability)] = False
      else:
        capabilities.setdefault((method, capability), True)

    # Add them to the response
    response.clear_config()
    for (service, capability), enabled in capabilities.items():
      config = response.add_config()
      config.set_package(service)
      config.set_capability(capability)
      config.set_status(capabilities.IsEnabledResponse.ENABLED if enabled else capabilities.IsEnabledResponse.DISABLED)

    # Calculate the summary response
    config.set_summary_status(capabilities.IsEnabledResponse.ENABLED if False not in capabilities.values() else capabilities.IsEnabledResponse.DISABLED)

  def install(self, apiproxy, unique_name):
    apiproxy.GetPostCallHooks().Append(unique_name, self._capability_hook, 'capability_service')
    super(CapabilityHook, self).install(apiproxy, unique_name)</pre>

<p>This is substantially more complicated than the previous handler, because it has to implement the intricacies of the capabilities API. The basic operation is fairly straightforward, however. The set_capability_disabled method allows you to disable or enable specific capabilities. To disable or enable an entire service, use set_capability_disabled with a capability name of '*'. CapabilityHook then extends the get_error_code method to add additional checks: It returns CAPABILITY_DISABLED if the entire service is disabled, or if the method being requested is mentioned in its _CAPABILITY_MAP with a capability name, and that capability is disabled.</p>

<p>The class also implements a post-call hook for the capability service; this modifies responses by checking its own internal list of capabilities and assembling a response appropriately. The summary status is set to ENABLED iff all the individual queried capabilities and methods are themselves enabled.</p>

<p>Here's a simple example of it in use:</p>

<pre class="prettyprint">capability_hook = CapabilityHook()
capability_hook.install(apiproxy_stub_map.apiproxy, 'error_hook')

db.put(some_entity)  # Succeeds
db.get(some_key)  # Succeeds
capabilities.CapabilitySet('datastore_v3', capabilities=['write']).is_enabled()  # Returns True

capability_hook.set_capability_disabled('datastore_v3', 'write')
db.put(some_entity)  # Fails, raising datastore_errors.Error
db.get(some_key)  # Still succeeds
capabilities.CapabilitySet('datastore_v3', capabilities=['write']).is_enabled()  # Returns False</pre>

<p>There you go: How to handle API call errors, how to detect disabled capabilities, and how to test both of them. Now you're prepared for the next scheduled maintenance, or the unlikely event of another unplanned outage!</p></div>
    </content>
    <updated>2010-03-01T15:33:24Z</updated>
    <published>2010-03-01T15:32:32Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-03-12T16:51:18Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-644191305643743365</id>
    <link href="http://reneefrench.blogspot.com/feeds/644191305643743365/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=644191305643743365" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/644191305643743365" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/644191305643743365" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/bacon.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://2.bp.blogspot.com/_va9O40qIhaE/S4sMG0vN73I/AAAAAAAACV4/FxL-LCSJ1eQ/s1600-h/duck44.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5443457885982814066" src="http://2.bp.blogspot.com/_va9O40qIhaE/S4sMG0vN73I/AAAAAAAACV4/FxL-LCSJ1eQ/s320/duck44.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 320px; height: 269px;"/></a><br/><div>bacon</div><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-644191305643743365?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-03-01T00:37:16Z</updated>
    <published>2010-03-01T00:36:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="notes"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://netherstone.org/golang/netbsd/blog/?p=38</id>
    <link href="http://netherstone.org/golang/netbsd/blog/?p=38" rel="alternate" type="text/html"/>
    <title>Quick Update: progressing slowly</title>
    <summary>Still working, nothing much more to show.  The syscall package is being beaten into behaving.
I’ve received one offer to beta test; be sure I’ll post here (and to the NetBSD mailing lists) when I get to alpha and beta testing stages.
Cheers,
Giles</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Still working, nothing much more to show.  The syscall package is being beaten into behaving.</p>
<p>I’ve received one offer to beta test; be sure I’ll post here (and to the NetBSD mailing lists) when I get to alpha and beta testing stages.</p>
<p>Cheers,</p>
<p>Giles</p></div>
    </content>
    <updated>2010-02-28T08:33:44Z</updated>
    <category term="Uncategorized"/>
    <category term="Go"/>
    <category term="golang"/>
    <category term="syscall"/>
    <author>
      <name>admin</name>
    </author>
    <source>
      <id>http://netherstone.org/golang/netbsd/blog</id>
      <link href="http://netherstone.org/golang/netbsd/blog/?feed=rss2" rel="self" type="application/atom+xml"/>
      <link href="http://netherstone.org/golang/netbsd/blog" rel="alternate" type="text/html"/>
      <subtitle>Of course it runs on NetBSD!</subtitle>
      <title>Porting Go to NetBSD</title>
      <updated>2010-03-10T03:00:10Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-8854312619478460255</id>
    <link href="http://reneefrench.blogspot.com/feeds/8854312619478460255/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=8854312619478460255" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/8854312619478460255" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/8854312619478460255" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/mizur.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://3.bp.blogspot.com/_va9O40qIhaE/S4miCMQf7zI/AAAAAAAACVw/BOKKUwSRiM0/s1600-h/set3tsm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5443059783187820338" src="http://3.bp.blogspot.com/_va9O40qIhaE/S4miCMQf7zI/AAAAAAAACVw/BOKKUwSRiM0/s320/set3tsm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 230px; height: 320px;"/></a><br/><div>mizur</div><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-8854312619478460255?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-27T22:52:10Z</updated>
    <published>2010-02-27T22:51:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="line drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-5371526077965056347</id>
    <link href="http://reneefrench.blogspot.com/feeds/5371526077965056347/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=5371526077965056347" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/5371526077965056347" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/5371526077965056347" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/95000.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://4.bp.blogspot.com/_va9O40qIhaE/S4mhnqqq8zI/AAAAAAAACVo/rJ8LSJOV9M4/s1600-h/swim.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5443059327494189874" src="http://4.bp.blogspot.com/_va9O40qIhaE/S4mhnqqq8zI/AAAAAAAACVo/rJ8LSJOV9M4/s320/swim.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 268px; height: 320px;"/></a><br/><div>95000</div><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-5371526077965056347?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-27T22:50:56Z</updated>
    <published>2010-02-26T22:48:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="tonal drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://www.airs.com/blog/?p=325</id>
    <link href="http://www.airs.com/blog/archives/325" rel="alternate" type="text/html"/>
    <title>Superbugs</title>
    <summary>Increasing antibiotic resistance in bacteria is a nice demonstration of:

The speed and effectiveness of evolutionary change.
The Law of Unintended Consequences
The danger of hospitals

Antibiotics are in effect poisons that don’t happen to affect humans, typically because they interfere with bacterial cell walls that our cells don’t have.  It doesn’t take long in human terms for [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Increasing antibiotic resistance in bacteria is a nice demonstration of:</p>
<ul>
<li>The speed and effectiveness of evolutionary change.</li>
<li>The Law of Unintended Consequences</li>
<li>The danger of hospitals</li>
</ul>
<p>Antibiotics are in effect poisons that don’t happen to affect humans, typically because they interfere with bacterial cell walls that our cells don’t have.  It doesn’t take long in human terms for bacteria to develop resistance to antibiotics, though presumably it does take quite a while in bacteria terms.  With regard to selection under extreme pressure from antibiotic poisons, bacteria have an advantage over more complex animals: they can evolve faster because they can exchange new genetic material directly rather than only passing it on to their children.  This is isomorphic to cultural evolution in h humans: the way that a good idea can spread quickly through a human population.</p>
<p>The unintended consequences I see are three-fold.  First, when the first antibiotics were used (i.e., penicillin) they were considered to be miracle drugs.  People didn’t realize initially that miracles have a limited lifespan depending on how heavily you use them, and there are many penicillin resistant bacteria these days.  Second, antibiotics were eventually spread through society in the form of soaps and creams.  This turned out to be almost wholly counter-productive, in that it exposed bacteria to low levels of antibiotics, making it easier for them to evolve resistance before they were poisoned.  Third, the industrial food system relies on antibiotics to keep animals alive and more-or-less well even though they live in exceedingly unhealthy conditions (packed in tightly, covered with feces, etc.).  This has also greatly increased bacterial exposure to antibiotics, increasing resistance, thus unwittingly exchanging safer and cheaper food for increased danger in other areas of life.</p>
<p>The benefit of hospitals is that you can put experts and expensive equipment in one place where they can efficiently work to help people.  The danger of hospitals is that you put all the sick people in the same place, which gives infections a steady supply of people who are weakened and less able to fight off infections.  In effect hospitals become sanctuaries for infections.  Two hundred years ago a hospital was not a place for healing; it was a place for dying.  Modern medicine has changed that to an extraordinary degree.  But antibiotic resistant bacteria remind us that is a hospital is a place you should go only when you have no other choice.  Doctors making house calls is inefficient and expensive, but it would almost certainly be healthier for people who are not too sick to be cared for at home.</p></div>
    </content>
    <updated>2010-02-27T18:29:11Z</updated>
    <category term="Random"/>
    <author>
      <name>Ian Lance Taylor</name>
    </author>
    <source>
      <id>http://www.airs.com/blog</id>
      <link href="http://www.airs.com/blog/feed" rel="self" type="application/atom+xml"/>
      <link href="http://www.airs.com/blog" rel="alternate" type="text/html"/>
      <subtitle>Ian Lance Taylor</subtitle>
      <title>Airs - Ian Lance Taylor</title>
      <updated>2010-03-09T08:00:16Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-3303907924347033832.post-2655013291324632820</id>
    <link href="http://feedproxy.google.com/~r/goplexian/~3/WC6BGz4EZSY/setting-up-jack-audio-for-gstreamer.html" rel="alternate" type="text/html"/>
    <title>Setting up Jack Audio for GStreamer, Flash, and VLC</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">First of all I need to say that I won't be mentioning Pulseaudio so if that is what you're here for then you are at the wrong place because I don't use Pulseaudio at all, Pulseaudio can be run ontop of Jack but doing so will increase CPU load (a very tiny amount on modern systems). Someday I may find a reason to run Pulseaudio on top of Jack but right now I don't have one.<br/>
<br/>
I'm going to try to keep this guide as distribution agnostic as I can, I'm sure that all of these packages are available for all of the major Linux distributions so I leave it up to you to get them and install them.<br/>
<br/>
<h2>Jack Audio</h2>I'm using Jack version 0.116.2<br/>
<br/>
Start by installing jack on your computer. :)<br/>
<br/>
The beautiful thing about jack is its super low latency real-time support, but in order to realize its full potential you will likely need to do a bit of tweaking to your system first.<br/>
<br/>
Fortunately there is a perl script called the "<a href="http://code.google.com/p/realtimeconfigquickscan/">Realtime Config Quickscan</a>" for Jack which you can download and run in order to see what has already been setup on your system and what still needs to be fixed, I highly suggest getting and running that script as the first order of business.<br/>
<br/>
When I run the script on my system the output looks like this:<br/>
<br/>
<div class="separator" style="clear: both; text-align: center;"><a href="http://3.bp.blogspot.com/_Nkd2arCyCxQ/S4dALpd3tJI/AAAAAAAAAaE/etqzyvVSU_4/s1600-h/quickscan.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/_Nkd2arCyCxQ/S4dALpd3tJI/AAAAAAAAAaE/etqzyvVSU_4/s320/quickscan.png"/></a></div><br/>
<br/>
A couple of things may stand out when you look at that, first you may notice that I'm not running a real-time kernel, surprise! Actually you don't need to be running a real-time kernel in order to get real-time audio with Jack as long as you are running a reasonably recent version of Linux.<br/>
<br/>
Quite frankly compiling your own kernel can take a lot of time especially if you make a mistake, and time is my most precious resource so I prefer to run the standard issue kernels which come with my distribution and I just always make sure they are as up to date as possible.<br/>
<br/>
So here is a list of the bare minimum needed to get real time audio in Linux.<br/>
<br/>
First make sure you are in the audio group, this can be done from the command line like so:<br/>
<br/>
<blockquote>$ sudo gpasswd -a &lt;USER&gt; audio</blockquote><br/>
<br/>
Change &lt;USER&gt; to your user name.<br/>
<br/>
Next edit the file <b>/etc/security/limits.conf</b><br/>
In that file you should see two lines that look like this:<br/>
<br/>
<div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/_Nkd2arCyCxQ/S4dD5vWgL7I/AAAAAAAAAaM/3R5oS2LdFyU/s1600-h/bad.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/_Nkd2arCyCxQ/S4dD5vWgL7I/AAAAAAAAAaM/3R5oS2LdFyU/s320/bad.png"/></a></div><br/>
Move those two lines to the very end of the file, and right above them add the following information:<br/>
<br/>
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/_Nkd2arCyCxQ/S4dEFyL8snI/AAAAAAAAAaU/EnNr9_0g7W8/s1600-h/good.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/_Nkd2arCyCxQ/S4dEFyL8snI/AAAAAAAAAaU/EnNr9_0g7W8/s320/good.png"/></a></div><br/>
It should look like this when you are done:<br/>
<br/>
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/_Nkd2arCyCxQ/S4dFf_VYjXI/AAAAAAAAAac/KVmqc4kYaNM/s1600-h/final.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/_Nkd2arCyCxQ/S4dFf_VYjXI/AAAAAAAAAac/KVmqc4kYaNM/s320/final.png"/></a></div><br/>
Next, check if you have a shared memory file system mounted on /dev/shm by running this command:<br/>
<blockquote>$ mount | grep shm</blockquote><br/>
If you see output then you're good to go, otherwise add this text to the <b>/etc/fstab</b> file:<br/>
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/_Nkd2arCyCxQ/S4dIfdn69GI/AAAAAAAAAak/w__eCBCBiNQ/s1600-h/shm.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/_Nkd2arCyCxQ/S4dIfdn69GI/AAAAAAAAAak/w__eCBCBiNQ/s320/shm.png"/></a></div><br/>
While you are there messing with your /etc/fstab make sure that all of your major file systems such as /boot, /, and /home, as well as /dev/dvd and /dvd/cdrom and any external hard drives all have "noatime" listed among their options, this can significantly increase file system performance and it will make the Quickscan script happy.<br/>
<br/>
The last thing to do is to set your max_user_watches, open the file <b>/etc/sysctl.conf</b> and add this to the end:<br/>
<br/>
<blockquote>fs.inotify.max_user_watches = 524288</blockquote><br/>
Next restart your computer, yes I know, we all hate to reboot, but sometimes it is necessary and this is one of those times.<br/>
<br/>
After the reboot, as a regular user start jack from the command line:<br/>
<br/>
<blockquote>jackd -R -P89 -s -dalsa -dhw:0 -r48000 -p256 -n3</blockquote><br/>
If all goes well your system now has real time audio capabilities. You will now need to start jack as a regular user (not root) every time you login with the command listed above, I leave it up to you to figure out the best way to do this on your system, personally I just add a little shell script to my users startup applications.<br/>
<br/>
<h2>Connecting GStreamer to Jack</h2>Having realtime capability is only great if your applications actually know about it. So lets connect GStreamer to Jack so that Gnome desktop apps like Rhythmbox, or whatever, have access to your new cool sound system.<br/>
<br/>
I am using GStreamer Core Library version 0.10.26<br/>
<br/>
First of all you will need to install the Jack plugin for GStreamer, this can be found in a package called <b>gstreamer-0.10-bad-plugins</b> (I've also seen it called gstreamer-0.10-plugins-bad).<br/>
<br/>
After installing the plugin make sure that you have both <b>jackaudiosink</b> and <b>jackaudiosrc</b> by running this command:<br/>
<br/>
<blockquote>$ gst-inspect-0.10 | grep jack</blockquote><br/>
If you see output for both jackaudiosink and jackaudiosrc then you are good to go. If you are missing jackaudiosrc then you are running an old version of gstreamer and I strongly suggest that you upgrade it. You can still continue onward with this guide but you will be unable to record audio input from a microphone, so if using a microphone with a GStreamer app is important to you then you are out of luck unless you upgrade.<br/>
<br/>
Next, on the command line, launch the program called <b>gstreamer-properties</b> and change the audio settings so that they look like this:<br/>
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/_Nkd2arCyCxQ/S4dM_fDCuKI/AAAAAAAAAas/h9ncmFifJRg/s1600-h/gstreamer.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/_Nkd2arCyCxQ/S4dM_fDCuKI/AAAAAAAAAas/h9ncmFifJRg/s320/gstreamer.png"/></a></div><br/>
That wasn't so hard, was it.<br/>
<br/>
Rhythmbox and other Gnome audio applications that use GStreamer should work as expected now.<br/>
<br/>
(Some old Gnome audio applications may still not work right, for example gnome-audio-recorder does not work for me, but its not exactly essential so I don't really care. If you need to record audio through your microphone then I suggest using Audacity anyway.)<br/>
<br/>
<h2>Introducing libflashsupport-jack</h2>Sometime in the near future Flash may be put out to pasture by newer and better technologies such as html5 but for now most people need it. <br/>
<br/>
I've never had an easier time hooking Jack to Flash than with libflashsupport-jack by Torben Hohn, actually, I've never hooked Jack to Flash at all until now. <br/>
<br/>
You can download it from <a href="http://repo.or.cz/w/libflashsupport-jack.git">git</a>, or if you are using Archlinux and packer then you <a href="http://aur.archlinux.org/packages.php?ID=26219">probably</a> don't need me to say anymore ;)<br/>
<br/>
<h2>Dear sweet VLC</h2>OK, we all know VLC is great but when it comes to Jack some might have an issue because of VLC's rather silly setting defaults.<br/>
<br/>
I am using VLC version 1.0.5<br/>
<br/>
Open VLC, go to Tools -&gt; Preferences, then click Audio, then change the output type to "JACK audio output". Done? Nope!<br/>
<br/>
Notice that down in the lower left hand corner there is a toggle option button, it is set to <b>Simple</b> by default, change this to <b>All</b> instead.<br/>
<div class="separator" style="clear: both; text-align: center;"><a href="http://2.bp.blogspot.com/_Nkd2arCyCxQ/S4dRX4rZxzI/AAAAAAAAAa0/fb5vvxbwls0/s1600-h/vlc1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/_Nkd2arCyCxQ/S4dRX4rZxzI/AAAAAAAAAa0/fb5vvxbwls0/s320/vlc1.png"/></a></div><br/>
Then in the "Advanced Preferences" window go to Audio -&gt; Output Modules -&gt; JACK and put a check in the check-box which says "Automatically connect to writable clients." It should look like this:<br/>
<br/>
<div style="text-align: center;"><a href="http://2.bp.blogspot.com/_Nkd2arCyCxQ/S4dR70N1UmI/AAAAAAAAAa8/sbgGbIui4eU/s1600-h/vlc2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/_Nkd2arCyCxQ/S4dR70N1UmI/AAAAAAAAAa8/sbgGbIui4eU/s320/vlc2.png"/></a></div><br/>
I have no idea why this isn't enabled by default, or at the very least over in the "Simple" preferences, but anyway thats what you need to do to get VLC to connect automatically to Jack.<br/>
<br/>
I hope you've found this helpful and I hope you have fun using real time audio on Linux!<div class="blogger-post-footer">&lt;script charset="utf-8" expr:src=""http://feeds.feedburner.com/~s/goplexian?i=" + data:post.url" type="text/javascript"&gt;&lt;/script&gt;<img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/3303907924347033832-2655013291324632820?l=www.goplexian.com" width="1"/></div><img height="1" src="http://feeds.feedburner.com/~r/goplexian/~4/WC6BGz4EZSY" width="1"/></div>
    </summary>
    <updated>2010-02-26T06:02:00Z</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="Audio"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Tips"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Linux"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Guide"/><feedburner:origLink xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://www.goplexian.com/2010/02/setting-up-jack-audio-for-gstreamer.html</feedburner:origLink>
    <author>
      <name>Alex Combas</name>
      <email>alex.combas@gmail.com</email>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-3303907924347033832</id>
      <author>
        <name>Alex Combas</name>
        <email>alex.combas@gmail.com</email>
      </author>
      <link href="http://www.goplexian.com/" rel="alternate" type="text/html"/>
      <link href="http://feeds.feedburner.com/goplexian" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <subtitle>open-source, programming, and indie games</subtitle>
      <title>One billion extensible bits</title>
      <updated>2010-02-26T15:00:07Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-4633566926723133810</id>
    <link href="http://reneefrench.blogspot.com/feeds/4633566926723133810/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=4633566926723133810" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/4633566926723133810" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/4633566926723133810" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/s5-ee.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://2.bp.blogspot.com/_va9O40qIhaE/S4dPD4r5cSI/AAAAAAAACVg/0C2MroPcZRk/s1600-h/dogbarsm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5442405602875240738" src="http://2.bp.blogspot.com/_va9O40qIhaE/S4dPD4r5cSI/AAAAAAAACVg/0C2MroPcZRk/s320/dogbarsm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 320px; height: 220px;"/></a>s5 ee<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-4633566926723133810?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-26T04:39:14Z</updated>
    <published>2010-02-26T04:32:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="line drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:12007</id>
    <link href="http://blog.notdot.net/2010/02/Consuming-RSS-feeds-with-PubSubHubbub" rel="alternate" type="text/html"/>
    <title>Consuming RSS feeds with PubSubHubbub</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Frequently, it's necessary or useful to consume an Atom or RSS feed provided
by another application. Doing so, though, is rarely as simple as it seems: To
do so robustly, you have to worry about polling frequency, downtime, badly
formed feeds, multiple formats, timeouts, determining which items are new and other such issues,
all of which distract from your original, seemingly simple goal of retrieving
new updates from an Atom feed. You're not alone, either: Everyone ends up dealing with the same set of
issues, and solving them in more or less the same manner. Wouldn't it be nice if
there was a way to let someone else take care of all this hassle?</p>

<p>As you've no doubt guessed, I'm about to tell you that there is. I'm speaking,
of course, of <a href="http://code.google.com/p/pubsubhubbub/">PubSubHubbub</a>.
I <a href="http://blog.notdot.net/2009/10/Blogging-on-App-Engine-part-8-PubSubHubbub">discussed</a>
publishing to PubSubHubbub as part of the 
<a href="http://blog.notdot.net/2009/10/Writing-a-blog-system-on-App-Engine">Blogging on App Engine series</a>,
but I haven't previously discussed what's required to act as a subscriber. Today,
we'll cover the basics of PubSubHubbub subscriptions, and how you can use them
to outsource all the usual issues consuming feeds.</p>

<p>At this point, you may be wondering how this is useful if the feed you're
consuming doesn't support PubSubHubbub. Fortunately, the PubSubHubbub protocol
provides for the possibility of hubs doing polling on feeds that do not support
PubSubHubbub themselves. The public hub on <a href="http://pubsubhubbub.appspot.com/">http://pubsubhubbub.appspot.com/</a>
doesn't currently have this enabled, but there are plenty of alternatives.
First and foremost, you can <a href="http://code.google.com/p/pubsubhubbub/wiki/DeveloperGettingStartedGuide">run your own hub</a>.
The reference implementation is an App Engine app, so you can deploy it the same
way you do your regular app. You can even deploy the hub as an alternate version
under the same App ID, providing you with a 'private' hub that you can access
the same way you would any other hub.</p>

<p>An easier alternative, however, is to use a hub provider that already supports
polling. One such provider is <a href="http://superfeedr.com/">superfeedr</a>,
who provide services for both publishers and subscribers. They're a commercial
outfit, but they offer a "hackr plan", which is free if you monitor fewer than
1000 feeds - and their <a href="http://superfeedr.com/cost">rates</a> seem very
reasonable. For simplicity, we'll be demonstrating subscriptions using their
service, but the rest of the article applies equally to any other hub.</p>

<p>First, <a href="http://superfeedr.com/signup">sign up</a> to superfeedr. Once
you've signed up and verified your account, you're ready to go!</p>

<p>Subscribing to a feed using hubbub is a three stage process:</p>

<ol>
  <li>Send a subscription request to the hub</li>
  <li>Handle the subscription callback</li>
  <li>Process notifications</li>
</ol>

<p>We'll go over each of these steps, using an example app that allows users to
receive notifications of new posts over XMPP. First, we need to define models
to keep track of subscriptions and individual subscribers:</p>

<pre class="prettyprint">class Subscription(db.Model):
  @property
  def url(self):
    return self.key().name()

  verify_token = db.StringProperty(required=True)  # Random verification token.

class Subscriber(db.Model):
  @property
  def subscription(self):
    return self.parent
  
  @property
  def address(self):
    return self.key().name()
</pre>

<p>We're making heavy use of entity relationships and key names here. To enforce
uniqueness, the key name of a Subscription entity is the URL of its feed, and
Subscriber entities are child entities of Subscriptions, with their key name
being the XMPP address of the subscriber.</p>

<h3>Sending subscription requests</h3>

<p>Now we can handle the first part of subscribing to a feed: Sending the request
to the hub. Doing so is a straightforward matter of sending an HTTP POST request
to the correct URL, as detailed
<a href="http://pubsubhubbub.googlecode.com/svn/trunk/pubsubhubbub-core-0.3.html#anchor5">in
the hubbub spec</a>. We'll do so when a user asks to be subscribed, using an
<a href="http://code.google.com/appengine/articles/using_xmpp.html">XMPP Handler</a>:</p>

<pre class="prettyprint">class XmppHandler(xmpp_handlers.CommandHandler):
  def send_subscription_request(self, subscription):
    subscribe_args = {
        'hub.callback': urlparse.urljoin(self.request.url, '/hubbub'),
        'hub.mode': 'subscribe',
        'hub.topic': subscription.url,
        'hub.verify': 'async',
        'hub.verify_token': subscription.verify_token,
    }
 
    headers = {}
 
    if HUB_CREDENTIALS:
      auth_string = "Basic " + base64.b64encode("%s:%s" % HUB_CREDENTIALS)
      headers['Authorization'] = auth_string
 
    response = urlfetch.fetch(HUB_URL, payload=urllib.urlencode(subscribe_args),
                              method=urlfetch.POST, headers=headers)
 
 
  def subscribe_command(self, message):
    if not message.arg.startswith("http"):
      message.reply("Subscription requests must consist of a URL to subscribe to")
      return
 
    created, subscription, subscriber = db.run_in_transaction(
        add_subscription,
        message.arg,  # URL to subscribe to
        message.sender,  # User who is subscribing
    )
 
    if created:
      self.send_subscription_request(subscription)
    
    message.reply("Subscription created!")</pre>

<p>When a user sends a message starting with '/subscribe', the 'subscribe_command'
method is called. After doing some basic verification, it calls 'add_subscription'
inside a datastore transaction, which returns the subscription and subscriber entities.
This is necessary to make sure we don't subscribe to the same feed multiple times.
Here's the code for add_subscription:</p>

<pre class="prettyprint">def add_subscription(topic, recipient):
  created = False
  subscription = Subscription.get_by_key_name(topic)
  if not subscription:
    created = True
    subscription = Subscription(key_name=topic, verify_token=str(uuid.uuid4()))
  subscriber = Subscriber(key_name=recipient, parent=subscription)
  db.put([subscription, subscriber])
  return created, subscription, subscriber</pre>

<p>If this user is the first to subscribe to this feed, the
send_subscription_request method is called. This constructs a dictionary of
arguments for the subscription request, consisting of the URL to send callbacks
and updated entries to, the mode ('subscribe'), the topic we're subscribing to,
and a couple of verification arguments - 'hub.verify' and 'hub.verify_token'.
The first one specifies that we're happy to handle the verification callback after
the current request has completed, and the second argument provides a secret token
that only we and the hub know of. This is to make it impossible for other people
to subscribe us to a feed without our permission, as we'll see shortly.</p>

<p>After assembling the dictionary of subscription arguments, we deal with
authorization. Public hubs, like <a href="http://pubsubhubbub.appspot.com/">
http://pubsubhubbub.appspot.com/</a> don't require any authentication, but other
providers, such as superfeedr, do. If we provided credentials (a (username, password)
tuple in the HUB_CREDENTIALS) variable), we add those to the request. Finally,
we make the subscription request using urlfetch.</p>

<h3>Handling subscription callbacks</h3>

<p>Part 2 is handling the subscription callback from the hub. The hub does this
to make sure that nobody else forged the subscription request, and to make sure
that we are operating a valid endpoint. This is where the verify_token parameter
from above comes in: When we receive a subscription callback, we should check
that the hub.verify_token argument the hub is supplying matches the one we
stored when we made the request. If it does, we respond to the request by echoing
back the 'hub.challenge' string it sends us, to confirm that we really want to
subscribe. Here's how we handle it in our app:</p>

<pre class="prettyprint">class CallbackHandler(webapp.RequestHandler):
  def get(self):
    if self.request.GET['hub.mode'] == 'unsubscribe':
      self.response.headers['Content-Type'] = 'text/plain'
      self.response.out.write(self.request.GET['hub.challenge'])
      return
      
    if self.request.GET['hub.mode'] != 'subscribe':
      self.error(400)
      return
 
    subscription = Subscription.get_by_key_name(self.request.GET['hub.topic'])
    if not subscription or subscription.verify_token != self.request.GET['hub.verify_token']:
      self.error(400)
      return
 
    self.response.headers['Content-Type'] = 'text/plain'
    self.response.out.write(self.request.GET['hub.challenge'])</pre>

<p>As you can see, this is very straightforward: We check that it's a subscription
request ('hub.mode' is 'subscribe'), then we fetch the subscription and check that
the tokens match. If all is well, we echo back the challenge string in the response,
which is how hubbub verifies that we're okay with the subscription request.</p>

<h3>Processing updates</h3>

<p>Now that the subscription process is out of the way, we can handle the updates
themselves. For this, we'll use the <a href="http://www.feedparser.org/">Universal Feed Parser</a>
library, though since the hub processes and sanitizes the feed, we could just as
easily use a standard XML parser. Since new entries are sent as a POST request
to the same URL as the subscription callback, we add a post() method to our
CallbackHandler:</p>

<pre class="prettyprint">  def post(self):
    """Handles new content notifications."""
    feed = feedparser.parse(self.request.body)
    id = find_self_url(feed.feed.links)
    subscription = Subscription.get_by_key_name(id)
    subscriber_keys = Subscriber.all(keys_only=True).ancestor(subscription).fetch(1000)
    subscriber_addresses = [x.name() for x in subscriber_keys]
    if not subscription:
      logging.warn("Discarding update from unknown feed '%s'", id)
      return
    for entry in feed.entries:
      message = "%s (%s)" % (entry.title, entry.link)
      xmpp.send_message(subscriber_addresses, message)

def find_self_url(links):
  for link in links:
    if link.rel == 'self':
      return link.href
  return None</pre>

<p>Here, we parse the request body with UFP, and extract the feed's 'self' URL using
a convenience method. We then use that 'self' URL to retrieve the Subscription entity,
and for each item in the feed, we notify all the subscribers of the update. Note
that because we store the subscribers' XMPP addresses as key names, we don't need
to fetch the Subscriber entities themselves - just their keys.</p>

<p>That's it - you now never have to worry about polling intervals, sanitization, or unavailable feeds again! 	The full source for the example app in this post is <a href="http://gist.github.com/313753">here</a>, and you can try it out by messaging xmpphubbub@appspot.com. A few caveats before you go, though:</p>

<ul>
  <li>There's no unsubscribe in the example - so be careful what you subscribe to!</li>
  <li>Real code would have more error checking, such as verifying that the response to the subscribe request was a 2xx, that the callback is made (sooner or later).</li>
  <li>Superfeedr doesn't support automatic subscription renewal - so if you want to know for certain that it hasn't forgotten about a subscription, and you haven't heard from it in a bit, you'd better re-subscribe.</li>
  <li><strike>Superfeedr also doesn't support "authenticated content distribution", a mode that uses a shared secret to generate an HMAC signature for updates. In my mind, this is a major omisson - because it means that anyone who knows your callback URL can invent RSS updates at will!</strike> Edit: superfeedr <a href="http://blog.superfeedr.com/API/PubSubHubbub/secure/secure-pubsubhubbub/">does support</a> authenticated content distribution.</li>
</ul>

<p>Those caveats aside, I'm confident that if you compare this solution to implementing your own polling infrastructure, you'll find that it comes out significantly simpler. Plus, as soon as the publishers of your feeds start using Hubbub, you'll get instant updates!</p></div>
    </content>
    <updated>2010-02-25T21:36:23Z</updated>
    <published>2010-02-24T20:46:27Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-03-12T16:51:18Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-8382649207764800820</id>
    <link href="http://reneefrench.blogspot.com/feeds/8382649207764800820/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=8382649207764800820" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/8382649207764800820" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/8382649207764800820" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/458-thursday.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://3.bp.blogspot.com/_va9O40qIhaE/S4YRSd798HI/AAAAAAAACVQ/OLecVCaDoLs/s1600-h/halfhaus.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5442056208695292018" src="http://3.bp.blogspot.com/_va9O40qIhaE/S4YRSd798HI/AAAAAAAACVQ/OLecVCaDoLs/s320/halfhaus.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 219px; height: 320px;"/></a>458 thursday<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-8382649207764800820?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-25T05:58:27Z</updated>
    <published>2010-02-25T05:57:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="notes"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-3303907924347033832.post-9099294894386313586</id>
    <link href="http://feedproxy.google.com/~r/goplexian/~3/x5IhVHR03oo/facebook-will-set-indie-gaming-back-5.html" rel="alternate" type="text/html"/>
    <title>Facebook will set indie gaming back 5 years</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">I read books just about every day, and I'm talking real books mind you, not e-ink, not e-book. I'm talking paper and dust and the musty smell of old print. So if you're one of those people who gave up reading a few years ago and whose fingers spasmodically continue to click long after the hand has left the mouse then you may not exactly understand the reasons for my grumbling, but just a brief word of warning this is probably an "I'm an old man so get off my lawn" type of rant and it is likely to upset you.<br/>
<br/>
Facebook games suck. Few would really be surprised if Farmville turned out to be made by a couple of 17 year olds in their mom's basement. Turns out it wasn't, but it easily could have been. But it made hundreds of millions of dollars, so it *must* be good, right? Wrong. Popularity has no bearing on quality these days. Does anyone remember that kid on youtube swinging the lightsaber? Didn't he get over 20 million views? Was he some kind of genius? Nope, just a silly video that got lucky and went viral a few times.<br/>
<br/>
Facebook games are a lot like that, except instead of just being silly they are sinister, they are designed to be simple and viral, not good.<br/>
<br/>
I want games with substance and style, richly textured and thickly layered, with real character development and breathtaking artwork. --[[ I'm talking in the context of indie games though, I am not suggesting that indie titles can compete pound for pound with AAA studio titles. If you're not sure what I'm talking about maybe have a look at <a href="http://www.braid-game.com/">Braid</a> or <a href="http://machinarium.net/demo/">Machinarium</a>.]]-- Essentially I want games which remind me of good books. Facebook games don't even qualify as comics. I feel sick even comparing them to comics.<br/>
<br/>
Facebook games might get a bit prettier after Googles' NaCL takes off and we see serious hardware acceleration become standard on the web but they wont get any closer to what us old timers consider to be good, they judge good by a different metric.<br/>
<br/>
Sadly though everybody is screaming their brains out about Facebook right now, and the hundreds of millions some of its games made last year, we're looking at a gold rush in the middle of a global recession folks, and you mark my words, where the carcase lays down the eagles will gather, big names are going to start dropping Facebook titles, but instead of making things better this will assuredly only make things worse. It will only lend further credibility to what has become nothing but a glorified marketing machine.<br/>
<br/>
Facebook games are successful for three reasons. Firstly because Facebook's main purpose is to expose internet newbies to marketing from their nearest and dearest friends. Everyone knows that people are many times more likely to try/buy something which is recommended to them from their friends. Facebook is built on that premise. It is simply a thinly veiled mechanism by which people organize themselves willingly into groups which know and trust each other, so that they can then unwittingly mass market applications amongst their closest friends. <br/>
<br/>
The second reason web games are successful is because they are delivered through a  browser, and even though the games suck the sucking is mostly excused because even grandpa knows that browsers are limited. The browser also means these games can be played on just about any computer in the known universe.<br/>
<br/>
And third, they succeed because they are designed to be played in short bursts, people new to the net don't feel intimidated or obligated. They can get in, give it a try for free, and then get out, or so they think. It is like the perfect gateway drug.<br/>
<br/>
Facebook is going to set indie gaming back 5 years, developers must follow the money, and nobody can deny that there is sick cash to be had playing the viral lottery on Facebook. The indie market is literally teetering on the verge of awesome, but it's going to get slammed pretty hard when half the market suddenly flips the channel to Facebook or other similar venues.<div class="blogger-post-footer">&lt;script charset="utf-8" expr:src=""http://feeds.feedburner.com/~s/goplexian?i=" + data:post.url" type="text/javascript"&gt;&lt;/script&gt;<img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/3303907924347033832-9099294894386313586?l=www.goplexian.com" width="1"/></div><img height="1" src="http://feeds.feedburner.com/~r/goplexian/~4/x5IhVHR03oo" width="1"/></div>
    </summary>
    <updated>2010-02-24T12:17:00Z</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="Indie"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Games"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Facebook"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Topics for Discussion"/><feedburner:origLink xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://www.goplexian.com/2010/02/facebook-will-set-indie-gaming-back-5.html</feedburner:origLink>
    <author>
      <name>Alex Combas</name>
      <email>alex.combas@gmail.com</email>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-3303907924347033832</id>
      <author>
        <name>Alex Combas</name>
        <email>alex.combas@gmail.com</email>
      </author>
      <link href="http://www.goplexian.com/" rel="alternate" type="text/html"/>
      <link href="http://feeds.feedburner.com/goplexian" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <subtitle>open-source, programming, and indie games</subtitle>
      <title>One billion extensible bits</title>
      <updated>2010-02-26T15:00:07Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-5538763207903679784</id>
    <link href="http://reneefrench.blogspot.com/feeds/5538763207903679784/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=5538763207903679784" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/5538763207903679784" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/5538763207903679784" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/sold-out-of-labute.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://3.bp.blogspot.com/_va9O40qIhaE/S4UMp_PsMLI/AAAAAAAACVI/1UxnCWozGz0/s1600-h/hdaymovbed39sm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5441769640238526642" src="http://3.bp.blogspot.com/_va9O40qIhaE/S4UMp_PsMLI/AAAAAAAACVI/1UxnCWozGz0/s320/hdaymovbed39sm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 320px; height: 233px;"/></a>sold out of labute<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-5538763207903679784?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-24T11:27:30Z</updated>
    <published>2010-02-23T11:24:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="line drawings"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="story h"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-8082954141980125536.post-3775091129210813871</id>
    <link href="http://research.swtch.com/feeds/3775091129210813871/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=8082954141980125536&amp;postID=3775091129210813871" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default/3775091129210813871" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default/3775091129210813871" rel="self" type="application/atom+xml"/>
    <link href="http://research.swtch.com/2010/02/off-to-races.html" rel="alternate" type="text/html"/>
    <title>Off to the Races</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p class="lp">
Go is defined to be a safe language.
Indices into array or string references must be in bounds;
there is no way to reinterpret the bits of one type
as another, no way to conjure a pointer out of thin air;
and there is no way to release memory, so no
chance of “<a href="http://en.wikipedia.org/wiki/Dangling_pointer">dangling pointer</a>” errors and the
associated memory corruption and instability.
</p>

<p class="pp">In the current Go implementations, though, there are two
ways to break through these safety mechanisms.
The first and more direct way is to use 
<a href="http://golang.org/pkg/unsafe/">package unsafe</a>,
specifically <a href="http://golang.org/pkg/unsafe#Pointer">unsafe.Pointer</a>.
The second, less direct way is to use a data race in a multithreaded program.
</p>

<p class="pp">If you were going to build an environment that ran untrusted
Go code, you'd probably want to change the available packages to restrict
or delete certain routines, like <a href="http://golang.org/pkg/os/#RemoveAll">os.RemoveAll</a>,
and you'd want to disallow access to package unsafe.
Those kinds of restrictions are straightforward.
</p>

<p class="pp">The data races that can be used to break through the
usual memory safety of Go are less straightforward.
This post describes the races and how to rearrange the data
structures involved to avoid them.
Until the Go implementations have been tuned more,
we won't be able to measure whether there is a
significant performance difference between the current
representation and the race-free implementation.
</p>

<h3>Package Unsafe</h3>

<p class="lp">Here's a simple packaging of a type that lets you
edit arbitrary memory locations, built using the standard
<a href="http://golang.org/pkg/unsafe/">package unsafe</a>:
</p>

<pre class="indent">import "unsafe"

type Mem struct {
 addr *uintptr // actually == &amp;m.data!
 data *uintptr
}

// Peek reads and returns the word at address addr.
func (m *Mem) Peek(addr uintptr) uintptr {
 *m.addr = addr
 return *m.data
}

// Poke sets the word at address addr to val.
func (m *Mem) Poke(addr, val uintptr) {
 *m.addr = addr
 *m.data = val
}

func NewMem() *Mem {
 m := new(Mem)
 m.addr = (*uintptr)(unsafe.Pointer(&amp;m.data))
 return m
}
</pre>

<p class="lp">(The Go type <code>uintptr</code> is an unsigned integer
the size of a pointer, like <code>uint32</code> or <code>uint64</code>
depending on the underlying machine architecture.)
</p>

<p class="pp">The key line is near the bottom, the use of 
the special type <code>unsafe.Pointer</code> to convert a
<code>**uintptr</code> into a <code>*uintptr</code>.
Dereferencing that value gives us <code>m.data</code> (actually a <code>*uintptr</code>)
interpreted as a <code>uintptr</code>.
We can assign an arbitrary integer to <code>*m.addr</code>, that changes <code>m.data</code>,
and then we can dereference the integer as <code>*m.data</code>.
In other words, the <code>Mem</code> struct
gives us a way to convert between integers and pointers, just like in C.
There are no races here: this is just something you
can do by importing <code>unsafe</code>.
The <code>Mem</code> wrapper is a bit convoluted—normally you'd just use <code>unsafe</code> directly—but
we're going to drop in a different implementation of <code>NewMem</code>
that doesn't rely on <code>unsafe</code>.
</p>


<h3>A Race</h3>

<p class="lp">The current Go representation of slices and interface values
admits a <a href="http://en.wikipedia.org/wiki/Race_condition">data race</a>:
because they are multiword values, if one goroutine reads the value
while another goroutine writes it, the reader might see half of the old
value and half of the new value.
</p>

<p class="pp">Let's provoke the race using interface values.
In Go, an interface value is <a href="http://research.swtch.com/2009/12/go-data-structures-interfaces.html">represented as two words</a>,
a type and a value of that type.
After these declarations:
</p>

<pre class="indent">var x *uintptr

var i interface{} = &amp;x
var j interface{} = (*uintptr)(nil)
</pre>

<p class="lp">The data structures for <code>i</code> and <code>j</code> look like:
</p>

<center>
<img src="http://4.bp.blogspot.com/_ZnVhQ3NyEx0/S4NfhGfalZI/AAAAAAAAABc/tW8HwS2YeTM/s400/gorace1.png"/>
</center>

<p class="lp">Suppose we kick off a goroutine that alternately assigns <code>i</code> and <code>j</code>
to a new interface value <code>k</code>:

</p><pre class="indent">var k interface{}

func hammer() {
 for {
  k = i
  k = j
 }
}
</pre>

<p class="lp">After each statement executes, <code>k</code> will look like either <code>i</code> or <code>j</code>, but during the assignment, there will be a moment when <code>k</code> is half <code>i</code> and half <code>j</code>, one of these:
</p>

<center>
<img src="http://1.bp.blogspot.com/_ZnVhQ3NyEx0/S4NfhYd6Q0I/AAAAAAAAABk/5yRlfksZmq8/s400/gorace2.png"/>
</center>

<p class="lp">
The top case gives us a <code>**uintptr</code> <code>nil</code>, which
we could obtain more easily via legitimate means,
but the bottom case gives us the value <code>&amp;x</code> (actually
a <code>**uintptr</code>) interpreted as a <code>*uintptr</code>.
If we can catch the interface when it looks like the case on the right,
we'll have rederived the conversion we used above via <code>unsafe</code>.
Based on that insight, we can rewrite <code>NewMem</code> without <code>unsafe</code>:
</p>

<pre class="indent">func NewMem() *Mem {
 fmt.Println("here we go!")

 m := new(Mem)

 var i, j, k interface{}
 i = &amp;m.data
 j = (*uintptr)(nil)

 // Try over and over again until we win the race.
 done := false
 go func(){
  for !done {
   k = i
   k = j
  }
 }()
 for {
  // Is k a non-nil *uintptr?  If so, we got it.
  if p, ok := k.(*uintptr); ok &amp;&amp; p != nil {
   m.addr = p
   done = true
   break
  }
 }
 return m
}
</pre>

<p class="pp">The same kind of race happens in all of
Go's mutable multiword structures: slices, interfaces, and strings.
In the case of slices, the trick is to get a pointer from
one slice and a cap from a different one.
In the case of strings, the trick is to get a pointer from
one string and the len from a different one.
(The string race isn't as interesting, because strings
cannot be written to, so it would only let you read memory, not write it.)
</p>

<h3>The Fix</h3>

<p class="lp">The race is fundamentally caused by
being able to observe partial updates to Go's 
multiword values (slices, interfaces, and strings):
the updates are not atomic.
</p>

<p class="pp">The fix is to make the updates atomic.
In Go, the easiest way to do that is to make the
representation a single pointer that points at an
immutable structure.  When the value needs to be
updated, you allocate a new structure, fill it in
completely, and only then change the pointer
to point at it.  This makes the assignment atomic:
another goroutine reading the pointer at the
same time sees either the new data or the old data,
but not a mix, assuming the compiler is careful to
read the pointer just once and then access
both fields using the same pointer value.</p>

<center>
<img src="http://1.bp.blogspot.com/_ZnVhQ3NyEx0/S4NfhjTBPRI/AAAAAAAAABs/SnNac85wwSg/s400/gorace3.png"/>
</center>

<p class="lp">(The red border indicates immutable data.)</p>

<p class="pp">For slices and strings, it makes sense to keep the
multiword representation but put an immutable
”pointer and cap” stub structure
between the slice and the underlying array.
This keeps the same basic efficiency properties
of slices at the cost of a few extra instructions
on each indexing operation.</p>

<center>
<img src="http://2.bp.blogspot.com/_ZnVhQ3NyEx0/S4NfiL9UgZI/AAAAAAAAAB0/mW2hZr-Ay5k/s400/gorace4.png"/>
</center>

<p class="lp">The idea here is to keep a structure with a 
mutable offset and length to support efficient slicing
but replace the pointer with an immutable base+length pair.
Any access to the underlying data must check the final
offset against the immutable <i>cap</i>.
Copying slice values is still not an atomic operation,
but an invalid <i>len</i> will not keep an out-of-bounds
index from being caught.
</p>

<p class="pp">This representation requires a couple
more assembly instructions, because each index
must be checked against two bounds, first the relative len
and then the absolute cap:
</p>

<center>
<table>
<tbody><tr height="5"><td/></tr>
<tr align="center"><th colspan="5">Compute <code>x[i]</code> in <code>AX</code></th></tr>
<tr><th align="center"><i>Racy</i></th><th/><th align="center"><i>Race-free</i></th></tr>
<tr><td><pre class="smallish">
LEAL x, SI
MOVL i, CX
CMPL CX, 4(SI)
JGE panic




MOVL 0(SI), DI
MOVL (4*CX)(DI), AX
</pre></td><td width="20"/><td><pre class="smallish">
LEAL x, BX
MOVL i, CX
CMPL CX, 4(BX)
JGE panic
ADDL 8(BX), CX
MOVL 0(BX), SI
CMPL CX, 4(SI)
JGE panic
MOVL 0(SI), DI
MOVL (4*CX)(DI), AX
</pre></td><td width="20"/><td><pre class="smallish">
 
 
// i &gt;= len?
 
 
// i+off &gt;= cap?
 
// &amp;x[0] -&gt; SI
// x[i] (or x[i+off]) -&gt; DI
 
</pre></td></tr>
</tbody></table>
</center>

<p class="lp">With suitable analysis, an optimizing compiler
could cache <code>0(BX)</code>, <code>4(BX)</code>, <code>8(BX)</code>,
and <code>4(SI)</code>, so in a loop, it is possible that the 
new representation would run at the same speed
as the original.</p>

<p class="pp">An ambitious implementation might
continue to use the current data structures for
slices, interfaces, and strings stored on the stack,
because data on the stack can only be accessed
by the goroutine running on that stack.
(Local variables whose addresses might escape
to other goroutines are already allocated
on the heap automatically, to avoid dangling pointer bugs
after a function returns.)
</p>

<h3>Garbage Collection</h3>

<p class="lp">This fix is feasible only because Go is
a garbage-collected language: we can treat the
red stub structures as immutable and trust that
the garbage collector will recycle the memory only
when nothing points to them anymore.
It's much harder to build a safe language
without a garbage collector to fall back on.
</p>

<h3>Security Implications</h3>

<p class="lp">It is important to note that these races do not make
the current implementations any less secure than they already are.
The races allow clever programmers to subvert Go's memory safety,
but a less clever programmer can still use 
the aptly-named <a href="http://golang.org/doc/go_spec.html#Package_unsafe">package unsafe</a>.
</p>

<p class="pp">
These races only matter if you are trying to build a Go service
that can safely run arbitrary code supplied by untrusted programmers
(and to the best of my knowledge, there are no such services yet).
In that situation, you'd already need to change the implementations
to disable access to the unsafe package and remove or restrict functions like
os.Remove or net.Dial.
Changing the data representations to be race free is just one more 
change you'd have to make.  Now you know, not just that a change
is needed but also what the change is.
</p>

<p class="pp">The races exist because the data representations 
were chosen for performance: the race-free versions introduce
an extra pointer, which carries with it the cost of extra indirection
and extra allocation.  Once the Go implementations are more mature,
we'll be able to evaluate the precise performance impact of using
the race-free data structures and whether to use them always
or only in situations running untrusted code.
</p><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/8082954141980125536-3775091129210813871?l=research.swtch.com" width="1"/></div></div>
    </content>
    <updated>2010-02-23T17:00:00Z</updated>
    <published>2010-02-23T17:00:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="data structures"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="brute force"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Go"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="security"/>
    <author>
      <name>rsc</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/06357099531993534337</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-8082954141980125536</id>
      <author>
        <name>rsc</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/06357099531993534337</uri>
      </author>
      <link href="http://research.swtch.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://research.swtch.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Computer programming links, collected by
<a href="http://swtch.com/~rsc/">Russ Cox</a>.  Updated sporadically.</div>
      </subtitle>
      <title>research!rsc</title>
      <updated>2010-03-11T20:33:15Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-6989726062940083922.post-5531784633012264008</id>
    <link href="http://robpike.blogspot.com/feeds/5531784633012264008/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=6989726062940083922&amp;postID=5531784633012264008" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default/5531784633012264008" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default/5531784633012264008" rel="self" type="application/atom+xml"/>
    <link href="http://robpike.blogspot.com/2010/02/two-birds.html" rel="alternate" type="text/html"/>
    <title>Two Birds</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://3.bp.blogspot.com/_Fpj1cqLIn_Y/S4OiSWCsUBI/AAAAAAAABsk/MWWEAphHmqI/s1600-h/Two+Birds.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5441371210831908882" src="http://3.bp.blogspot.com/_Fpj1cqLIn_Y/S4OiSWCsUBI/AAAAAAAABsk/MWWEAphHmqI/s400/Two+Birds.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 400px; height: 269px;"/></a><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/6989726062940083922-5531784633012264008?l=robpike.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-23T09:39:26Z</updated>
    <published>2010-02-23T09:39:00Z</published>
    <author>
      <name>rob</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/18259238879445421354</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-6989726062940083922</id>
      <author>
        <name>rob</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/18259238879445421354</uri>
      </author>
      <link href="http://robpike.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://robpike.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <title>rob pike</title>
      <updated>2010-03-08T22:35:14Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-824498351384646817</id>
    <link href="http://reneefrench.blogspot.com/feeds/824498351384646817/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=824498351384646817" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/824498351384646817" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/824498351384646817" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/in-heat-of-night.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://1.bp.blogspot.com/_va9O40qIhaE/S4OfMtxdtqI/AAAAAAAACVA/FlLQUIQ3juE/s1600-h/hdayboatleavingsm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5441367815588001442" src="http://1.bp.blogspot.com/_va9O40qIhaE/S4OfMtxdtqI/AAAAAAAACVA/FlLQUIQ3juE/s320/hdayboatleavingsm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 293px; height: 320px;"/></a>in the heat of the night<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-824498351384646817?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-23T09:27:02Z</updated>
    <published>2010-02-22T09:25:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="story h"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="tonal drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://netherstone.org/golang/netbsd/blog/?p=30</id>
    <link href="http://netherstone.org/golang/netbsd/blog/?p=30" rel="alternate" type="text/html"/>
    <title>Two steps forward, one step back</title>
    <summary>I better understand now how the pkg/syscall/z*.go files are generated.  That’s the good news, part 1.
The good news part 2 is that with a working NetBSD/amd64 host, I have filled in placeholders similar to the 386 files in the pkg/runtime/amd64 directory.
The not so good news is back in pkg/syscall, where I’ve stripped syscalls_netbsd.go back [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I better understand now how the pkg/syscall/z*.go files are generated.  That’s the good news, part 1.</p>
<p>The good news part 2 is that with a working NetBSD/amd64 host, I have filled in placeholders similar to the 386 files in the pkg/runtime/amd64 directory.</p>
<p>The not so good news is back in pkg/syscall, where I’ve stripped syscalls_netbsd.go back to basics and am filling it based on analysis of NetBSD’s syscalls.master file.  Just copying from FreeBSD or Darwin wasn’t going to cut it.</p>
<p>The updated patches have been uploaded in case anyone’s really curious (and it gets me an offsite backup) but they’re still some way off being useful.</p>
<p>–giles</p></div>
    </content>
    <updated>2010-02-23T04:02:47Z</updated>
    <category term="Go"/>
    <category term="NetBSD"/>
    <category term="golang"/>
    <category term="patch"/>
    <category term="patches"/>
    <category term="syscall"/>
    <author>
      <name>admin</name>
    </author>
    <source>
      <id>http://netherstone.org/golang/netbsd/blog</id>
      <link href="http://netherstone.org/golang/netbsd/blog/?feed=rss2" rel="self" type="application/atom+xml"/>
      <link href="http://netherstone.org/golang/netbsd/blog" rel="alternate" type="text/html"/>
      <subtitle>Of course it runs on NetBSD!</subtitle>
      <title>Porting Go to NetBSD</title>
      <updated>2010-03-10T03:00:10Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://netherstone.org/golang/netbsd/blog/?p=17</id>
    <link href="http://netherstone.org/golang/netbsd/blog/?p=17" rel="alternate" type="text/html"/>
    <title>Distraction: Virtualisation Software Wars</title>
    <summary>Short version: Arrghhh!
Long version:
For historical reasons (and some commercial software) my "own" machines run OS X.  (Up until a week ago I had a ten year old x86 machine as well, but I’d used up all my spare parts, and wanted the cupboard space, so it had to go.)
Virtualisation (or “Virtualization”, depending on the [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Short version: Arrghhh!</p>
<p>Long version:</p>
<p>For historical reasons (and some commercial software) my "own" machines run OS X.  (Up until a week ago I had a ten year old x86 machine as well, but I’d used up all my spare parts, and wanted the cupboard space, so it had to go.)</p>
<p>Virtualisation (or “Virtualization”, depending on the version of English you write), you say.  Didn’t I use to be an expert on that?  (By most definitions, yup.  But not on x86/x86_64.)</p>
<p>I have been using Parallels 4.x, and found it usable.  I could (with arm twisting) get it to run NetBSD-4.0/i386 (32 bit, not 64 bit) and there were limitations with its networking support on OS/X.</p>
<p>Parallels keep encouraging me to buy their (now not-so-new) 5.x, and offer a trial version.  So I tried it. (Emphasis on the past tense.)</p>
<ul>
<li>it won’t run NetBSD-5.0/amd64 any way I can figure out (a main target for a go port)</li>
<li>it will run NetBSD-5.0/i386, and is <em>fast</em> (but I’m not so convinced about the stability)</li>
<li>it runs Linux (surprise ☺)</li>
<li>it won’t run FreeBSD-8.0/amd64, which I want for comparison purposes.</li>
<li>its ACPI is … peculiar (And yeah, I know ACPI is overly complex and stupid.  I even know what the acronym stands for.  But we have to live with it these days, "the industry" tells us)</li>
</ul>
<p>And they want money for this.  Maybe I’d prefer to give my money to VMware.</p>
<p>But before I do anything rash, I try VirtulBox again.  It’s updated a few versions since I used it last; it’s sorta-kinda-partly-at-least open source.  Last time I ran it it had problems with NetBSD, ran slow, and caused my laptop to run hot.</p>
<p>This time, installs NetBSD-5.0 (i386 and amd64), with ACPI (gee, revolutionary in 2010, dontchathink?) and they’ve moved to include bridged networking on OS/X, which means I don’t have to run it on my laptop.</p>
<p>Looks like a winner.  Except that it won’t run FreeBSD/amd64 any way I can figure out.  (I am sure I saw it installing and losing access to its “disks”, but all subsequent attempts to boot it make it look like a 32 bit machine trying to boot a 64 bit kernel).  It does run FreeBSD-8.0/i386, at least.  And 32 and 64 bit Linux, of course.</p>
<p>Maybe I want VMware after all.  Something that "just works" would be nice.  Truly nice.  Especially if it keeps working when I stress it, which isn’t necessarily going to be the case with any of them.   (Or OS X, of course.  Don’t mention the transitory network problem that I can’t pin down to hardware, software, or even a single machine yet.)</p>
<p>Rant for the day is now over.  Progress might resume shortly.</p></div>
    </content>
    <updated>2010-02-22T22:29:50Z</updated>
    <category term="Uncategorized"/>
    <category term="ACPI"/>
    <category term="Parallels"/>
    <category term="rant"/>
    <category term="VirtualBox"/>
    <category term="virtualisation"/>
    <category term="virtualization"/>
    <category term="VMware"/>
    <author>
      <name>admin</name>
    </author>
    <source>
      <id>http://netherstone.org/golang/netbsd/blog</id>
      <link href="http://netherstone.org/golang/netbsd/blog/?feed=rss2" rel="self" type="application/atom+xml"/>
      <link href="http://netherstone.org/golang/netbsd/blog" rel="alternate" type="text/html"/>
      <subtitle>Of course it runs on NetBSD!</subtitle>
      <title>Porting Go to NetBSD</title>
      <updated>2010-03-10T03:00:10Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:37001</id>
    <link href="http://blog.notdot.net/2010/02/Implementing-a-non-relational-database-in-Go" rel="alternate" type="text/html"/>
    <title>Implementing a non-relational database in Go</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>In a previous Damn Cool Algorithms post, I discussed <a href="http://blog.notdot.net/2009/12/Damn-Cool-Algorithms-Log-structured-storage">log structured storage</a>, and how it applies to databases. For a long time, I've wanted to implement a database based on log structured storage, and a few other nice mechanics from other database systems:</p>

<ul>
  <li>Tables are key:value mappings, with duplicate keys allowed (Bigtable, BDB)</li>
  <li>Map-based views, also known as materialized views, for indexing (couchdb).</li>
  <li>Reducer support for views (couchdb).</li>
</ul>

<p>Since my <a href="http://blog.notdot.net/tag/go">previous posts about go</a> have been generally well received, and because I want to explore the language a bit more, I'll be implementing all this in <a href="http://golang.org/">Go</a>. The approach I'd like to take is one of gradually building up abstractions. We'll tackle each of the components in its own post:</p>

<ol>
  <li>An interface for writing records to an append-only file or set of files.</li>
  <li>A B-Tree implementation, built on the record interface.</li>
  <li>Map-based / materialized views, based on the B-Tree implementation.</li>
  <li>Reducers for views.</li>
</ol>

<p>Unlike previous series, this one is likely to be fairly fragmented. There's a fair chunk of functionality to be implemented here, so I won't be able to get it out at my usual three posts a week schedule. In the meantime, the usual posts on App Engine and other topics will continue.</p>

<p>In the first post in the series, we'll implement an interface for writing records to an append-only file (or set of files), and reading records back, given their address. This may not sound like the most thrilling component, but it's necessary in order to implement the rest of the system, and we'll learn a lot about Go's IO interface by doing it.</p></div>
    </content>
    <updated>2010-02-22T21:22:29Z</updated>
    <published>2010-02-22T21:22:28Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-03-12T16:51:18Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-4406086193904129581</id>
    <link href="http://reneefrench.blogspot.com/feeds/4406086193904129581/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=4406086193904129581" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/4406086193904129581" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/4406086193904129581" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/set-3.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://3.bp.blogspot.com/_va9O40qIhaE/S4Ijj0VX0wI/AAAAAAAACUw/oVIfdNHzhuw/s1600-h/set3sm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5440950398067659522" src="http://3.bp.blogspot.com/_va9O40qIhaE/S4Ijj0VX0wI/AAAAAAAACUw/oVIfdNHzhuw/s320/set3sm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 260px; height: 320px;"/></a>set 3<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-4406086193904129581?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-22T06:28:41Z</updated>
    <published>2010-02-22T06:26:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="line drawings"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="story l"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://netherstone.org/golang/netbsd/blog/?p=11</id>
    <link href="http://netherstone.org/golang/netbsd/blog/?p=11" rel="alternate" type="text/html"/>
    <title>Current patch list</title>
    <summary>This is the current patch list, in the order I apply them.  (Curently I don’t think the order matters, but in case it does, here’s what I use)):

noparallel

This one’s trivial, and won’t be needed in the final port.  It merely turns off the “-j4” option in the build, which makes reading the build [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>This is the current patch list, in the order I apply them.  (Curently I don’t think the order matters, but in case it does, here’s what I use)):</p>
<dl>
<dt><a href="http://netherstone.org/golang/netbsd/patches/noparallel.diff">noparallel</a><p/>
</dt>
<dd>This one’s trivial, and won’t be needed in the final port.  It merely turns off the “<tt>-j4</tt>” option in the build, which makes reading the build output easier.  (Sure, it might slow down the build too, but I’m working on a virtual machine anyway, so speed’s not of the essence.)<p/>
</dd>
<dt><a href="http://netherstone.org/golang/netbsd/patches/netbsd.diff">netbsd</a><p/>
</dt>
<dd>Minor bits and pieces to include NetBSD as a valid build target.  Nothing interesting here, move along.<p/>
</dd>
<dt><a href="http://netherstone.org/golang/netbsd/patches/libmach.diff">libmach</a><p/>
</dt>
<dd>This <em>will</em> need some work, and honestly I don’t know what it requires yet.  For now, I have just copied the FreeBSD port which has left a whole lot of functions stubbed out.  I presume those functions do something useful, but until I know what they’re used for I don’t know what to implement.  As for now they’re not stopping me working on the rest of the build, the placeholders get to stay.<p/>
</dd>
<dt><a href="http://netherstone.org/golang/netbsd/patches/runtime.diff">runtime</a><p/>
</dt>
<dd>This patch is for all the stuff under <tt>$GOROOT/src/pkg/runtime/</tt>.  As it involves low level kernel access and provides facilities like semaphores and thread support, it’s important.  It is also an area in which NetBSD is almost completely different from OS X (a.k.a. Darwin), Linux, and FreeBSD.  Plus to make things even more complicated, the existing ports have all used low level OS specific features in preference to higher level standardised features such as the pthreads library supplies.  Doubtless there is a reason (or reasons!) for this, but all I have so far is speculation.<p/>
<p>Work here isn’t progressing very fast: I want to think about it some more, and have found simpler and more obvious work to go on with in the next patch.</p>
</dd>
<dt><a href="http://netherstone.org/golang/netbsd/patches/syscall.diff">syscall</a><p/>
</dt>
<dd>This patch is for all the code under <tt>$GOROOT/src/pkg/syscall/</tt>.  It includes things like system call numbers, errno values, and translations between C and Go types.  Conceptually it’s not too difficult; in practice it requires creating some material by hand, and writing scripts to create other source files.  I’d hoped this would be almost idenitcal to the FreeBSD port, but it turns out there are some divergences between FreeBSD so it’s not as simple as cut &amp; paste.<p/>
<p>This patch isn’t done yet, but it’s not far off, and then I think I’ll return to the runtime changes.</p>
</dd>
</dl></div>
    </content>
    <updated>2010-02-22T02:32:57Z</updated>
    <category term="Go"/>
    <category term="NetBSD"/>
    <category term="golang"/>
    <category term="patch"/>
    <author>
      <name>admin</name>
    </author>
    <source>
      <id>http://netherstone.org/golang/netbsd/blog</id>
      <link href="http://netherstone.org/golang/netbsd/blog/?feed=rss2" rel="self" type="application/atom+xml"/>
      <link href="http://netherstone.org/golang/netbsd/blog" rel="alternate" type="text/html"/>
      <subtitle>Of course it runs on NetBSD!</subtitle>
      <title>Porting Go to NetBSD</title>
      <updated>2010-03-10T03:00:10Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://www.airs.com/blog/?p=323</id>
    <link href="http://www.airs.com/blog/archives/323" rel="alternate" type="text/html"/>
    <title>Synthetic Food</title>
    <summary>In the modern industrial food system, a cow is a chemical factory which converts corn into beef or milk.  This is inefficient and unsafe in several different ways.  Cows can not be maintained in sterile environments, so E. coli and other bacteria from their feces can contaminate the meat.  Cows evolved to [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>In the modern industrial food system, a cow is a chemical factory which converts corn into beef or milk.  This is inefficient and unsafe in several different ways.  Cows can not be maintained in sterile environments, so E. coli and other bacteria from their feces can contaminate the meat.  Cows evolved to eat grass, so feeding them corn, while cheaper and more efficient, significantly increases bacteria count.  Moving cows from feedlot to slaughter house, and moving beef from slaughter house to market, is inefficient.</p>
<p>Now that we have industrialized the food chain, there is increasing study of synthetic life.  There is even a <a href="http://partsregistry.org/Main_Page">Registry of Biological Parts</a> intended to make it easier to design your own life forms.  These mostly work as modifications of existing life forms.  There are, for example, people working on making bacteria which can efficiently produce diesel fuel; it apparently works in small quantities but there are still scaling issues.</p>
<p>Different people are working on what seems to be called in vitro meat: flesh which has never been part of an actual animal.  This is generally done by culturing muscle cells.</p>
<p>In view of these efforts, it seems ridiculous to use something as complex and inefficient as a cow to produce beef.  How long will it be until we have fully synthetic meat products?  (This will of course raise a host of interesting health issues, but I think it’s safe to predict that none of them will be addressed until and unless the product is already popular.)</p>
<p>For people concerned about the increasing industrialization of food, synthetic meat will only make matters worse.  However, as a vegetarian, I think the only valid choices are synthetic meat or no meat.  So I would be happy to see increasing work in these fields, and I’m confident that they will become not only less cruel, but cheaper, than dealing with real cows.</p></div>
    </content>
    <updated>2010-02-22T00:53:55Z</updated>
    <category term="Random"/>
    <author>
      <name>Ian Lance Taylor</name>
    </author>
    <source>
      <id>http://www.airs.com/blog</id>
      <link href="http://www.airs.com/blog/feed" rel="self" type="application/atom+xml"/>
      <link href="http://www.airs.com/blog" rel="alternate" type="text/html"/>
      <subtitle>Ian Lance Taylor</subtitle>
      <title>Airs - Ian Lance Taylor</title>
      <updated>2010-03-09T08:00:16Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://netherstone.org/golang/netbsd/blog/?p=1</id>
    <link href="http://netherstone.org/golang/netbsd/blog/?p=1" rel="alternate" type="text/html"/>
    <title>Hello world!</title>
    <summary>This blog is intended to record progress on porting Google’s Go language to NetBSD.  There is an open item #611 in Google’s issue tracker for this.
Initial efforts are going to concentrate on the 386 (a.k.a. i386) and amd64 ports; in theory it should be possible to port to NetBSD arm platfoms as well.
As yet [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>This blog is intended to record progress on porting Google’s <a href="http://golang.org">Go</a> language to <a href="http://www.netbsd.org">NetBSD</a>.  There is an open item <a href="http://code.google.com/p/go/issues/detail?id=611">#611</a> in Google’s issue tracker for this.</p>
<p>Initial efforts are going to concentrate on the 386 (a.k.a. i386) and amd64 ports; in theory it should be possible to port to NetBSD arm platfoms as well.</p>
<p>As yet there’s no mailing list: should there be desire for one,  I’ll create one.  For now, feel free to add comments to the blog, which  I’ll endeavour to keep updated as I update the patches.</p>
<p>All assistance is welcome.  Feel free to dig in.  No questions are  too foolish to ask!</p>
<p>There’s a page of general information here:</p>
<blockquote><p><a href="http://netherstone.org/golang/netbsd/">http://netherstone.org/golang/netbsd/</a></p></blockquote>
<p>The in-progress diffs are maintained here:</p>
<blockquote><p><a href="http://netherstone.org/golang/netbsd/patches/">http://netherstone.org/golang/netbsd/patches/</a><a> </a></p></blockquote>
<p>–giles</p></div>
    </content>
    <updated>2010-02-21T12:07:14Z</updated>
    <category term="Go"/>
    <category term="NetBSD"/>
    <category term="golang"/>
    <author>
      <name>admin</name>
    </author>
    <source>
      <id>http://netherstone.org/golang/netbsd/blog</id>
      <link href="http://netherstone.org/golang/netbsd/blog/?feed=rss2" rel="self" type="application/atom+xml"/>
      <link href="http://netherstone.org/golang/netbsd/blog" rel="alternate" type="text/html"/>
      <subtitle>Of course it runs on NetBSD!</subtitle>
      <title>Porting Go to NetBSD</title>
      <updated>2010-03-10T03:00:10Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-6989726062940083922.post-1511102207236100362</id>
    <link href="http://robpike.blogspot.com/feeds/1511102207236100362/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=6989726062940083922&amp;postID=1511102207236100362" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default/1511102207236100362" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default/1511102207236100362" rel="self" type="application/atom+xml"/>
    <link href="http://robpike.blogspot.com/2010/02/poultry.html" rel="alternate" type="text/html"/>
    <title>Poultry</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://1.bp.blogspot.com/_Fpj1cqLIn_Y/S4CR4zHL5dI/AAAAAAAABsc/LlGtN_vg-ac/s1600-h/Poultry.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5440508754842609106" src="http://1.bp.blogspot.com/_Fpj1cqLIn_Y/S4CR4zHL5dI/AAAAAAAABsc/LlGtN_vg-ac/s400/Poultry.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 400px; height: 357px;"/></a><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/6989726062940083922-1511102207236100362?l=robpike.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-21T01:52:40Z</updated>
    <published>2010-02-21T01:52:00Z</published>
    <author>
      <name>rob</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/18259238879445421354</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-6989726062940083922</id>
      <author>
        <name>rob</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/18259238879445421354</uri>
      </author>
      <link href="http://robpike.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://robpike.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <title>rob pike</title>
      <updated>2010-03-08T22:35:14Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-5403353775600759563</id>
    <link href="http://reneefrench.blogspot.com/feeds/5403353775600759563/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=5403353775600759563" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/5403353775600759563" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/5403353775600759563" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/td-hands.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://4.bp.blogspot.com/_va9O40qIhaE/S4B1Hefg9jI/AAAAAAAACUo/fSxUYQXjM6w/s1600-h/tazhandsm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5440477121168340530" src="http://4.bp.blogspot.com/_va9O40qIhaE/S4B1Hefg9jI/AAAAAAAACUo/fSxUYQXjM6w/s320/tazhandsm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 260px; height: 320px;"/></a><br/><div>td hands</div><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-5403353775600759563?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-20T23:50:20Z</updated>
    <published>2010-02-20T23:49:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="tonal drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-6989726062940083922.post-694272046823436478</id>
    <link href="http://robpike.blogspot.com/feeds/694272046823436478/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=6989726062940083922&amp;postID=694272046823436478" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default/694272046823436478" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default/694272046823436478" rel="self" type="application/atom+xml"/>
    <link href="http://robpike.blogspot.com/2010/02/ned-kelly.html" rel="alternate" type="text/html"/>
    <title>Ned Kelly</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://3.bp.blogspot.com/_Fpj1cqLIn_Y/S3-lCX4MBGI/AAAAAAAABsU/VeDLq9sI2KM/s1600-h/Ned+Kelly.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5440248335074853986" src="http://3.bp.blogspot.com/_Fpj1cqLIn_Y/S3-lCX4MBGI/AAAAAAAABsU/VeDLq9sI2KM/s400/Ned+Kelly.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 268px; height: 400px;"/></a><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/6989726062940083922-694272046823436478?l=robpike.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-20T09:02:27Z</updated>
    <published>2010-02-20T09:01:00Z</published>
    <author>
      <name>rob</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/18259238879445421354</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-6989726062940083922</id>
      <author>
        <name>rob</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/18259238879445421354</uri>
      </author>
      <link href="http://robpike.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://robpike.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <title>rob pike</title>
      <updated>2010-03-08T22:35:14Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-7356196735386868841</id>
    <link href="http://reneefrench.blogspot.com/feeds/7356196735386868841/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=7356196735386868841" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/7356196735386868841" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/7356196735386868841" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/not-josephine.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://4.bp.blogspot.com/_va9O40qIhaE/S35Yyy_QNAI/AAAAAAAACUg/4jya4q9Vokw/s1600-h/tazgoatsm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5439883029613917186" src="http://4.bp.blogspot.com/_va9O40qIhaE/S35Yyy_QNAI/AAAAAAAACUg/4jya4q9Vokw/s320/tazgoatsm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 320px; height: 240px;"/></a><br/><div>not josephine</div><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-7356196735386868841?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-19T09:24:51Z</updated>
    <published>2010-02-19T09:24:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="photographs"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-9123749025050012156</id>
    <link href="http://reneefrench.blogspot.com/feeds/9123749025050012156/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=9123749025050012156" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/9123749025050012156" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/9123749025050012156" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/koi.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://4.bp.blogspot.com/_va9O40qIhaE/S30m5y4htxI/AAAAAAAACUQ/2RZBUGGlrpo/s1600-h/xsm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5439546699286689554" src="http://4.bp.blogspot.com/_va9O40qIhaE/S30m5y4htxI/AAAAAAAACUQ/2RZBUGGlrpo/s320/xsm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 320px; height: 274px;"/></a><br/><div>koi</div><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-9123749025050012156?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-18T11:39:45Z</updated>
    <published>2010-02-18T11:39:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="notes"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="flies"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T15:18:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:33001</id>
    <link href="http://blog.notdot.net/2010/02/Webapps-on-App-Engine-Part-5-Sessions" rel="alternate" type="text/html"/>
    <title>Webapps on App Engine, Part 5: Sessions</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><em>This is part of a series on writing a webapp framework for App Engine Python. For details, see the introductory post <a href="http://blog.notdot.net/2010/01/Writing-your-own-webapp-framework-for-App-Engine">here</a>.</em></p>

<p>Sessions are another component that's regularly required by webapps, but isn't really a core part of a framework. In this post, we'll discuss the session mechanisms available for App Engine and how they work, and settle on a recommendation for our own lightweight framework.</p>

<p>The basic mechanism behind a session library is straightforward: A random session ID is generated for the user, which is embedded in an <a href="http://en.wikipedia.org/wiki/HTTP_cookie">HTTP cookie</a> and sent to the user. Meanwhile, a record is created on the server with the same ID, containing any data the webapp wants to store about this user. When the user makes a subsequent request, the session library decodes the session ID from the cookie header, and loads the corresponding session record from permanent storage.</p>

<p>There are three major advantages of handling sessions this way, rather than naively storing session data directly in the cookie:</p>

<ul>
  <li>We can store data that the client shouldn't be able to modify, such as the user's access flags.</li>
  <li>We can store data the client shouldn't even be able to read, or shouldn't be sent in the clear, such as their credentials.</li>
  <li>We can store more data than can be practically carried in an HTTP cookie.</li>
</ul>

<p>There are, of course, situations in which some of these constraints don't apply. Sometimes none of them apply, such as in the case of preference cookies; sometimes size is not an issue, but we want integrity and/or confidentiality. In these cases, many session libraries provide "cookie only" sessions, which store the data entirely in the cookie, while adding signing and/or encryption to prevent tampering or reading of the cookie data by the user.</p>

<p>Using cookie-only sessions has one major advantage: You remove the necessity to retrieve the user's data from storage on each request. This needs to be balanced with the limited storage on the one hand, and the need to embed a secret key in your code that can be used to sign and verify the cookies.</p>

<p>For non-cookie sessions, the session data needs to be stored somewhere. Many systems use the local filesystem, but this isn't practical in the case of distributed systems like App engine. On App Engine, that leaves us with two main options: Memcache, and the datastore.</p>

<p>Memcache initially seems like quite an attractive option, as it's substantially faster to query and update than the datastore. This comes with a major caveat, though: Since memcache makes no guarantees about how long values will persist, there's absolutely no guarantee that your session will still be around when the user comes back for it.</p>

<p>Losing the occasional user session doesn't seem like to much of a problem at first, but there are several factors that need consideration. If you're using sessions to implement a shopping site, losing a user's session is the absolute last thing you want to do: A user who suddenly loses the contents of their shopping cart is quite likely to simply leave, costing you one or even multiple sales. Even if sales aren't involved, if users regularly get logged out of their accounts, they may grow frustrated with your site and leave. Ad-hoc testing isn't sufficient to establish how much of an issue this is, either: Problems may not come up when you test the system with a reasonable load, but may instead occur when the system's under heavy load.</p>

<p>The other option, of course, is the Datastore. At the cost of a little extra latency, we gain near perfect reliability. With proper design, fetching the session should only require a single datastore get operation, too - no queries, which are much more expensive.</p>

<p>Hybrid approaches are of course also possible: We can store to both memcache and the datastore, and fetch from one, then the other, thus minimizing latency whenever memcache is available.</p>

<h3>Solutions</h3>

<p>Enough theorizing - let's take a look at the ready-made sessions libraries for App Engine. The first one is <a href="http://beaker.groovie.org/">Beaker</a>.</p>

<p>Beaker is a standalone library for session handling, implemented as WSGI middleware. It also includes caching middleware. Beaker supports App Engine datastore sessions, <strike>though an <a href="http://bitbucket.org/bbangert/beaker/issue/36/beaker-sessions-no-longer-work-on-app">open bug</a> means that the library currently needs some modification to work on App Engine</strike> (Edit: Now fixed!).</p>

<p>Using Beaker is a matter of downloading and unpacking it into your app's root directory, then opening beaker/cache.py and deleting or commenting out lines 29 through 51 - the section dealing with pkg_resources, which is unavailable on App Engine - as well as line 10, which imports pkg_resources. To use Beaker, we simply insert it as middleware, like this:</p>

<pre class="prettyprint">router = WSGIRouter()

#...

beaker_opts = {
  'session.type': 'ext:google',
}
application = beaker.SessionMiddleware(router)</pre>

<p>The session.type configuration option tells beaker what session storage to use - in this case, the Google datastore. Beaker also supports memcached - although not App Engine's implementation of it - and <a href="http://beaker.groovie.org/sessions.html#cookie-based">cookie-only sessions</a>, which can be enabled by setting session.type to "cookie", and session.secret to a secret key for hashing and encrypting the cookie.</p>

<p>Another sessions implementation is provided by <a href="http://gaeutilities.appspot.com/">gaeutilities</a>. gaeutilities supports datastore, memcache, and pure-cookie sessions. Using gaeutilities' sessions is even simpler:</p>

<pre class="prettyprint">session = appengine_utilities.sessions.Session()
session["keyname"] = "value" # sets keyname to value
print session["keyname"] # will print value</pre>

<p>As you can see, no middleware is required in this case - gaeutilities takes advantage of App Engine's use of the system environment to retrieve session data. gaeutilities also includes features such as token rotation to make session hijacking more difficult, while Beaker uses only a single session ID.</p>

<p>One quick caveat: Unlike beaker, gaeutilities does not encrypt or sign cookie-only sessions, so they should only be used for data where user tampering is not a concern.</p>

<h3>Conclusion</h3>

<p>We've looked at two good sessions libraries for App Engine. Either one would be a good choice for our framework. Given the current state, however, gaeutilities seems like the better choice: It doesn't require modifications to work, it's built specifically for App Engine, and if you need a lightweight library, you can easily take just the session handling code and not include the rest of the library.</p></div>
    </content>
    <updated>2010-02-18T09:34:15Z</updated>
    <published>2010-02-05T17:47:45Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-03-12T16:51:18Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:24002</id>
    <link href="http://blog.notdot.net/2010/02/Writing-a-twitter-service-on-App-Engine" rel="alternate" type="text/html"/>
    <title>Writing a twitter service on App Engine</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Services that consume or produce Twitter updates are popular apps these days, and there are more than a few on App Engine, too. Twitter provide an <a href="http://apiwiki.twitter.com/">extensive API</a>, which provides most of the features you might want to access.</p>

<p>Broadly, Twitter's API is divided into two distinct parts: The streaming API, and everything else. The streaming API is their recommended way to consume large volumes of updates in real-time; unfortunately, for a couple of reasons, using it on App Engine is not practical at the moment. The rest of their API, however, is well suited to use via App Engine, and covers things such as retrieving users' timelines, mentions, retweets, etc, sending new status updates (and deleting them, and retweeting them), and getting user information.</p>

<h3>Authentication</h3>

<p>Most of Twitter's API calls require authentication. Currently, Twitter support two different <a href="http://apiwiki.twitter.com/Authentication">authentication methods</a>: Basic, and <a href="http://oauth.net/">OAuth</a>. Basic authentication, as the name suggests uses HTTP Basic authentication, which requires prompting the user for their username and password. We won't be using this, since it's deprecated, and asking users for their credentials is a bad idea. The OAuth API makes it possible to call Twitter APIs on behalf of a user without knowing their password, and that's what we'll focus on today.</p>

<p>The key features of OAuth is that every consumer - that's you - needs a 'consumer key' and a 'consumer secret'. As the names imply, the first one is a key that identifies you, while the second is a secret value, known only to you and Twitter. Together, these allow you to prove to Twitter that you are who you say you are. In addition, for each user you authenticate, you'll need to store a user token and a user secret. These operate in the same way as the client token and secret, and allow you to prove to Twitter that you're making legitimate requests on behalf of that client.</p>

<p>In order to get permission to act on behalf of a user, you need to go through an authentication process. This consists of sending the user to a URL on twitter.com, where Twitter asks them if they want to authorize you to use their account. If the user agrees, Twitter redirects the user back to your site, embedding in the URL the details required. After that, you have all the necessary keys and secrets to use the API as that user (until they revoke your access!)</p>

<p>OAuth is a <a href="http://oauth.net/core/1.0a/">relatively straightforward</a> protocol, but it'd be nice if we didn't have to implement it ourselves. Fortunately, Mike Knapp has already done all the hard work for us, in the form of the <a href="http://github.com/Arachnid/AppEngine-OAuth-Library">AppEngine-OAuth</a> library (that link goes to my own fork of it, which has a few improvements that haven't yet made it into the mainline). This library takes care of all the nitty-gritty of OAuth authentication and making OAuth requests, making things Just Work.</p>

<h3>Using AppEngine-OAuth</h3>

<p>The first thing you should do is go to Twitter and <a href="http://twitter.com/oauth_clients">create an OAuth consumer</a>. Take the key and secret you're given, and store it somewhere - as a configuration variable in your code, or in the datastore, wherever suits. Next, download the library from the link above - you only need the file 'oauth.py', and place it in your app's root.</p>

<p>There are three major components you need to integrate: Sending the user to Twitter to be authenticated, handling the redirect back to complete authentication, and making API calls using the credentials. We'll tackle these in order.</p>

<h3>Starting the Authentication process</h3>

<p>Initiating authentication is easy. First, construct an oauth.TwitterClient:</p>

<pre class="prettyprint">consumer_key = "LKlkj83kaio2fjiudjd9...etc"
consumer_secret = "58kdujslkfojkjsjsdk...etc"
callback_url = "http://www.myurl.com/callback/twitter"
 
  client = oauth.TwitterClient(consumer_key, consumer_secret, callback_url)</pre>

<p>Here, callback_url should be the complete URL of the callback handler in your app. Next, you can generate a URL and redirect the user to it as follows:</p>

<pre class="prettyprint">self.redirect(client.get_authorization_url())</pre>

<h3>Completing Authentication</h3>

<p>When the user is done at Twitter, they will be redirected back to the callback URL you provided. Handling this requires constructing another instance of the TwitterClient, as above, and calling get_user_info on it:</p>

<pre class="prettyprint">class CallbackHandler(webapp.RequestHandler):
  def get(self):
    client = oauth.TwitterClient(consumer_key, consumer_secret, callback_url)
    auth_token = self.request.get("oauth_token")
    auth_verifier = self.request.get("oauth_verifier")
    user_info = client.get_user_info(auth_token, auth_verifier=auth_verifier)</pre>

<p>The 'user_info' variable here is a dict containing the relevant information about the authenticated user. Of particular interest is the "token" and "secret" keys, which we need to store to authenticate future requests, and the "username" key, which identifies the user. Services like Twitter also return additional keys - for instance, "name", which is the user's display name, and "picture", a URL to their avatar. If you want to see a real working example of a callback handler, here's <a href="http://github.com/Arachnid/tweetengine/blob/master/src/tweetengine/handlers/add.py#L21">Tweet Engine's one</a>.</p>

<h3>Making Authenticated Requests</h3>

<p>Now that you've authenticated the user and stored their credentials, you can make authenticated requests as them. Again, the OAuth library makes this easy. We once again construct a TwitterClient instance, and call .make_request on it, passing in the URL, the user's OAuth token and secret, as well as any additional parameters:</p>

<pre class="prettyprint">client = oauth.TwitterClient(consumer_key, consumer_secret, callback_url)

additional_params = {
  status: "Testing Twitter OAuth",
}

result = client.make_request(
    "http://twitter.com/statuses/update.json",
    token=client_token,
    secret=client_secret,
    additional_params=additional_params,
    method=urlfetch.POST)</pre>

<p>The 'result' variable, here, is a urlfetch Response object, which you can treat as you would the result of any other urlfetch call. Again, for a real example, you can check out <a href="http://github.com/Arachnid/tweetengine/blob/master/src/tweetengine/model.py#L163">how Tweet Engine does it</a>, though in this case it's slightly complicated by some extra layers of abstraction we haven't covered here.</p>

<h3>Rate Limiting</h3>

<p>One concern a lot of users have about using Twitter via App Engine is rate limiting. Twitter has two different rate limiting systems: per-IP, and per-app/per-user. This comes up a lot with users of the search API via App Engine, because all App Engine apps make external requests via the same pool of IPs. Authenticated requests, such as those we're making, are all rate limited per app and/or user, so we don't have to be worried about the per IP ratelimits.</p>

<p>That's all there is to using Twitter's OAuth API on App Engine. Have a use-case in mind? Let us know in the comments!</p></div>
    </content>
    <updated>2010-02-17T17:59:57Z</updated>
    <published>2010-02-17T17:59:56Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-03-12T16:51:18Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-978382632444850597</id>
    <link href="http://reneefrench.blogspot.com/feeds/978382632444850597/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=978382632444850597" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/978382632444850597" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/978382632444850597" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/toasters.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://4.bp.blogspot.com/_va9O40qIhaE/S3vxS8cvzUI/AAAAAAAACUI/XVxi9EaD9Nc/s1600-h/mrcollsm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5439206282746645826" src="http://4.bp.blogspot.com/_va9O40qIhaE/S3vxS8cvzUI/AAAAAAAACUI/XVxi9EaD9Nc/s320/mrcollsm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 299px; height: 320px;"/></a>toasters<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-978382632444850597?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-17T13:39:08Z</updated>
    <published>2010-02-17T13:38:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="tonal drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-14T04:19:47Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-3303907924347033832.post-2426009421874277380</id>
    <link href="http://feedproxy.google.com/~r/goplexian/~3/3daBT9qAMPI/first-rule-of-lua.html" rel="alternate" type="text/html"/>
    <title>The first rule of Lua.</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">This is a follow up to an article I wrote titled <a href="http://www.goplexian.com/2010/02/why-nobody-talks-about-lua.html">"Why nobody talks about Lua"</a> it's funny how sometimes little questions like that can turn into big discussions, because its not even a week later and that post has had over 10,000 views and generated something over 200 comments through various forums.<br/>
<br/>
So I wanted to <s>capitalize on my success</s> do a <s>brief</s> review today of how the various communities viewed the question and what their answers were, especially the responses from the Lua community itself through the Lua-list.<br/>
<br/>
The highest voted comment on reddit with actual content was from <b>munificent</b> and he wrote:<br/>
<blockquote>1. It's small. You can learn everything there is to know about Lua pretty quickly.<br/>
2. It moves slowly. There isn't a lot of hot new Lua tricks to blog about.<br/>
3. The existing documentation is fantastic.<br/>
4. Because it's embedded in other apps, there isn't a lot of "here's something useful" stuff that applies to all Lua users.<br/>
<br/>
No one talks about screwdrivers either.</blockquote><br/>
Interesting comment, but I dont entirely agree that these are the main reasons we don't hear much about Lua because there are other small, slow moving, excellently documented, embeddable type of applications which are popularly talked about online. For example sqlite satisfy's most of those criteria.<br/>
<br/>
The highest voted response on HN was by <b>Chipsy</b>, who said:<br/>
<br/>
<blockquote>I have trouble finding a use for Lua, even though I like it better as a language than most.<br/>
<br/>
The problem is that it isn't a good "starting place" for an app. Instead you write something in C/C++ and say "oh, I wish I had a dynamic language for this part" and then you add Lua on top. And this is part of why Lua is such a compelling language now - by being extension-focused it's been able to iterate the entire language many times over and make basic semantic changes without worrying about backwards-compatibility.<br/>
<br/>
But if I start writing an app and want something Lua-like....it ends up being easier to start in Python. There are some good projects out there to address this but it's a question of maturity - as of right now Lua still doesn't really satisfy as a "batteries-included" platform.</blockquote><br/>
This is a great description of how Lua is used I think, but I do not agree that this is the main reason why people do not talk about Lua because just like before I can think of other examples which also fit this general description yet get a lot of attention online. <br/>
<br/>
A commenter on this blog, <b>Steven</b>, wrote:<br/>
<br/>
<blockquote>"I think it's in part because Lua first became big in the game industry, which is not known for its openness and is still dominated by the large players. Many game companies guard their IP religiously, and often the developers are under NDAs. You won't see them organize a friendly neighbourhood somethingCamp to share and learn.</blockquote><br/>
This is certainly true, yet I'm sure there are a number of popular bloggers who work for large company's and somehow manage to blog about tech which excites them without disclosing company Intellectual Property, so again I don't see this as being the main reason why Lua discussion isn't more popular online.<br/>
<br/>
After having read  the comments and thought about this matter for a couple days I decided that I would bring this question to the Lua-list and see what the actual Lua community had to say about the matter.<br/>
<br/>
The difficulty though with mailing lists is that they lack the voting mechanism so you have no real way to determine if a given comment is relflective of a single individual or the community as a whole<br/>
<br/>
The first reply I got on the list made me laugh though, <b>dcharno</b> wrote:<br/>
<br/>
<blockquote>"I didn't understand the article. Lots of people use and talk about Lua. It serves a specific niche in application development. The Lua team is happy with the language. What is the issue?"</blockquote><br/>
If you are jaded skeptic like me you might at first think this person is just being oblivious, or doesn't want to show weakness or something else similarly cynical, but it is my opinion now that this general sentiment is shared by a fairly large segment of the Lua community and that when they say things like this they are speaking sincerely.<br/>
<br/>
After thinking about the responses I got on the Lua-list for a while I was lead back to ask a more general question: "<b>Why do people talk about programming?"</b>.<br/>
<b><br/>
</b><br/>
I can think of at least 5 reasons why people talk about programming languages, and I think the answer to the question of "why nobody talks about Lua" can be found when we look at the major reasons why people talk about programming in general.<br/>
<br/>
<b>1.</b> Perceived online popularity will increase adoption percentage for new programming projects (say that fast five times). For those projects struggling for mind share and trying to break into the big leagues lots of online discussion is rightly seen as an essential for growth and success.<br/>
<br/>
Lua though has no confidence issues, it has already been used in more video games than all of the other major scripting languages combined, and nobody needs to see crowds of happy bloggers in order to be convinced of this fact. So Lua developers see little need to proselytize about the language in the same way other projects attempt to do.<br/>
<br/>
<b>2.</b> Talking and writing is a means of reinforcing learning. After delving into something interesting and emerging from the other side victorious it is natural to want to do a bit of a victory dance, and for a certain segment of people this mean writing about it on our blogs.<br/>
<br/>
Lua though is small, simple, easy to learn, with great documentation. This makes those types of victory dances much less frequent.<br/>
<br/>
<b>3.</b> People <s>like</s> love to complain. I'm Canadian, so I find complaining a bit difficult, but I do think it is an entirely valid reason to communicate. If you don't like the way a certain something works then why not discuss it? I think most everyone agree's that the best thing to do is to fix it yourself, but that isn't always possible or practical even in the world of open-source.<br/>
<br/>
I know the Lua community is probably not going to thank me for this, but I think complaining is probably an area where Lua discussion could be dialed up a few notches. Again and again a common complaint made in the comments was that Lua's standard library isn't that great, and that it is one of Lua's major hurdles. Lua doesn't come with batteries included, etc etc.  If you take a look at the list of <a href="http://www.lua.org/manual/5.1/manual.html#5">Lua's standard libraries</a>, and compare that with the <a href="http://golang.org/pkg/">Go's standard libraries</a>, you'll see what people are talking about. This is the major reason why people say that Lua, despite being a great language, isn't so great for stand-alone development.<br/>
<br/>
It has been this way for years though, and the developers aren't likely to fix this any time in the immediate future but hopefully improvements will continue to be addressed.<br/>
<br/>
<b>4.</b> Genuine passion. If you really love something you can't help but talk about it, and as crazy as it sounds there are people out there who actually love programming languages and code. Personally I don't understand how anyone can have emotional feelings about code, but then again it is psychologically well documented that people grow in affinity as they grow in familiarity, the better you know something the closer you feel to it.<br/>
<br/>
But people don't often discuss a screwdriver, they just use it. Mind you though there is a big difference between leaning how to programming and learning how to use a language. It takes a lot longer to learn to program than it does to learn a language. If you haven't gained proficiency in Lua in a couple weeks then you are probably lacking some fundamental programming knowledge, in which case Lua can be a great teacher and something worth writing online about, but you wouldn't really be talking about Lua you'd more be talking about learning to program and just happen to be using Lua.<br/>
<br/>
<b>5.</b> The final reason why people write about programming is because of the internet driven childish hype culture. Reaching for a 'whats hot' tag, looking for their 2 minutes of fame.<br/>
<br/>
In many of the comments on the Lua-list there was a <b>strong</b> resentment to this type of hype culture which is so dominant on the internet today, it almost seemed to border on unwritten internal policy that hype for the sake of hype was completely unacceptable and actually attracts the wrong crowd.<br/>
<br/>
So as funny as it sounds it seems "The first rule of Lua is you do not hype about Lua, Lua doesn't need you to hype it, and Lua doesn't want the sort of people who are attracted by hype."<br/>
<br/>
For what its worth I think that's a good enough answer, funny though that I would get this answer from a community made up largely of game developers, an industry where hype is usually the order of the day. ;)<br/>
<br/>
This little foray into the world of Lua has opened my eyes quite a bit, Lua is certainly an interesting language, and an even more interesting community, and I think that if you're getting your feet wet in programming, or you are a seasoned developer contemplating adding scripting to your project, then Lua has a lot to offer you not least of which is a great and down to earth community. Wait, is this hype?<div class="blogger-post-footer">&lt;script charset="utf-8" expr:src=""http://feeds.feedburner.com/~s/goplexian?i=" + data:post.url" type="text/javascript"&gt;&lt;/script&gt;<img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/3303907924347033832-2426009421874277380?l=www.goplexian.com" width="1"/></div><img height="1" src="http://feeds.feedburner.com/~r/goplexian/~4/3daBT9qAMPI" width="1"/></div>
    </summary>
    <updated>2010-02-16T23:45:00Z</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="Topics for Discussion"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Open Source"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Lua"/><feedburner:origLink xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://www.goplexian.com/2010/02/first-rule-of-lua.html</feedburner:origLink>
    <author>
      <name>Alex Combas</name>
      <email>alex.combas@gmail.com</email>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-3303907924347033832</id>
      <author>
        <name>Alex Combas</name>
        <email>alex.combas@gmail.com</email>
      </author>
      <link href="http://www.goplexian.com/" rel="alternate" type="text/html"/>
      <link href="http://feeds.feedburner.com/goplexian" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <subtitle>open-source, programming, and indie games</subtitle>
      <title>One billion extensible bits</title>
      <updated>2010-02-26T15:00:07Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-294481685846522416</id>
    <link href="http://reneefrench.blogspot.com/feeds/294481685846522416/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=294481685846522416" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/294481685846522416" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/294481685846522416" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/moon2.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://2.bp.blogspot.com/_va9O40qIhaE/S3qm1MIFw7I/AAAAAAAACUA/PfoaFWH3tWU/s1600-h/flypicnic.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5438842932721730482" src="http://2.bp.blogspot.com/_va9O40qIhaE/S3qm1MIFw7I/AAAAAAAACUA/PfoaFWH3tWU/s320/flypicnic.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 320px; height: 266px;"/></a>moon2<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-294481685846522416?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-16T14:12:07Z</updated>
    <published>2010-02-16T14:07:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="notes"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="flies"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-13T00:14:14Z</updated>
    </source>
  </entry>

  <entry xml:lang="en-us">
    <id>http://twitter.com/_rsc/statuses/9167871443</id>
    <link href="http://twitter.com/_rsc/statuses/9167871443" rel="alternate" type="text/html"/>
    <title>_rsc: 2nd worst @jetblue flight ever: 200+ person bag drop line at BOS, 2hr boarding delay, 2hr sitting on plane at gate. (but no night in bangor)</title>
    <summary>_rsc: 2nd worst @jetblue flight ever: 200+ person bag drop line at BOS, 2hr boarding delay, 2hr sitting on plane at gate. (but no night in bangor)</summary>
    <updated>2010-02-16T03:08:12Z</updated>
    <source>
      <id>http://twitter.com/_rsc</id>
      <author>
        <name>RSC</name>
      </author>
      <link href="http://twitter.com/_rsc" rel="alternate" type="text/html"/>
      <link href="http://twitter.com/statuses/user_timeline/22455722.rss" rel="self" type="application/atom+xml"/>
      <subtitle>Twitter updates from Russ Cox / _rsc.</subtitle>
      <title>Twitter / _rsc</title>
      <updated>2010-03-15T06:00:09Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:35003</id>
    <link href="http://blog.notdot.net/2010/02/Bulk-updates-with-cursors" rel="alternate" type="text/html"/>
    <title>Bulk updates with cursors</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Last week, I <a href="http://blog.notdot.net/2010/02/New-features-in-1-3-1-prerelease-Cursors">blogged about cursors</a>, a new feature in version 1.3.1 of the App Engine SDK. Today, I'm going to demonstrate a practical use for them: Bulk datastore updates.</p>

<p>In both the <a href="http://code.google.com/appengine/articles/remote_api.html">Remote API</a> and <a href="http://code.google.com/appengine/articles/deferred.html">deferred</a> articles, I used a (perhaps poorly named) 'mapper' class as an example of ways to use these libraries. In neither case was the class intended to be anything other than a sample use case for the library, but nevertheless, people have used the examples in production. The introduction of cursors provides a prime opportunity to introduce a more robust, yet simpler, version of the bulk updater concept.</p>

<p>First, let's define a few requirements for our bulk updater:</p>

<ul>
  <li>Support for any query for which a cursor can be obtained</li>
  <li>Handles failure of individual updates gracefully</li>
  <li>Can fail the whole update process if enough errors are encountered</li>
  <li>Handles timeout errors, service unavailability, etc, transparently</li>
  <li>Can report completion to admins</li>
</ul>

<p>As in the Remote API and Deferred articles, we'll implement the updater as an abstract class, which individual updater implementations should subclass. Here's the basic interface:</p>

<pre class="prettyprint">import logging
import time
from google.appengine.api import mail
from google.appengine.ext import db
from google.appengine.ext.deferred import defer
from google.appengine.runtime import apiproxy_errors


class BulkUpdater(object):
  """A bulk updater for datastore entities.
  
  Subclasses should implement, at a minimum, get_query and handle_entity.
  """

  # Number of entities to put() at once.
  PUT_BATCH_SIZE = 20
  
  # Number of entities to delete() at once.
  DELETE_BATCH_SIZE = 20
  
  # Maximum time to spend processing before enqueueing the next task in seconds.
  MAX_EXECUTION_TIME = 20.0
  
  # Maximum number of failures to tolerate before aborting. -1 indicates
  # no limit, in which case the list of failed keys will not be retained.
  MAX_FAILURES = 0
  
  def __init__(self):
    self.__to_put = []
    self.__to_delete = []
    self.__failed_keys = []
    self.num_processed = 0
    self.num_tasks = 0
    self.num_put = 0
    self.num_deleted = 0
  
  def get_query(self):
    """Returns the query to iterate over.

    Returns:
      A db.Query or db.GqlQuery object. The returned query must support cursors.
    """
    raise NotImplementedError()

  def handle_entity(self, entity):
    """Performs processing on a single entity.
    
    Args:
      entity: A db.Model instance to update.
    """
    raise NotImplementedError()

  def finish(self, success, failed_keys):
    """Finish processing. Called after all entities have been updated.
    
    Args:
      success: boolean: Indicates if the process completed successfully, or was
        aborted due to too many errors.
      failed_keys: list: A list of db.Key objects that could not be updated.
    """
    pass</pre>

<p>The first thing we do is define some constants that will affect the operation of our updater - the batch sizes for put and delete operations, and the maximum time to execute before enqueueing the next task. This last one is necessary because tests have shown that the approach used in <a href="http://code.google.com/appengine/articles/deferred.html">the deferred article</a>, of catching the first deadline error and enqueueing the next task then, is not sufficiently reliable. We also define a maximum number of update failures to tolerate before aborting the update process.</p>

<p>We need some way for updater instances to propagate their changes back to the datastore. As with previous mappers, we want to batch these operations for efficiency. This time, let's define helper methods that the handle_entity() method can call:</p>

<pre class="prettyprint">  def put(self, entities):
    """Stores updated entities to the datastore.
    
    Updates are batched for efficiency.
    
    Args:
      entities: An entity, or list of entities, to store.
    """
    if isinstance(entities, db.Model):
      entities = [entities]
    self.__to_put.extend(entities)
    
    while len(self.__to_put) &gt; self.PUT_BATCH_SIZE:
      db.put(self.__to_put[-self.PUT_BATCH_SIZE:])
      del self.__to_put[-self.PUT_BATCH_SIZE:]
      self.num_put += self.PUT_BATCH_SIZE

  def delete(self, entities):
    """Deletes entities from the datastore.
    
    Deletes are batched for efficiency.
    
    Args:
      entities: An entity, key, or list of entities or keys, to delete.
    """
    if isinstance(entities, (db.Key, db.Model, basestring)):
      entities = [entities]
    self.__to_delete.extend(entities)
    
    while len(self.__to_delete) &gt; self.DELETE_BATCH_SIZE:
      db.delete(self.__to_delete[-self.DELETE_BATCH_SIZE:])
      del self.__to_delete[-self.DELETE_BATCH_SIZE:]
      self.num_deleted += self.DELETE_BATCH_SIZE</pre>

<p>These methods are fairly straightforward: We add passed in entities or keys to our internal lists for batching purposes, and if there are enough entries, we execute the batch update process for each batch. We use a while loop rather than an if, because a single call to put() or delete() could add more than one batch's worth of entries to put or delete.</p>

<p>Now we can implement the code that does the actual work. We'll start by defining a method that executes a single batch of work:</p>

<pre class="prettyprint">  def __process_entities(self, q):
    """Processes a batch of entities.
    
    Args:
      q: A query to iterate over doing processing.
    Returns:
      True if the update process has finished, False otherwise.
    """
    end_time = time.time() + self.MAX_EXECUTION_TIME
    for entity in q:
      try:
        self.handle_entity(entity)
      except (db.Timeout, apiproxy_errors.CapabilityDisabledError,
              apiproxy_errors.DeadlineExceededError):
        # Give up for now - reschedule for later.
        return False
      except Exception, e:
        # User exception - log and (perhaps) continue.
        logging.exception("Exception occurred while processing entity %r",
                          entity.key())
        if self.MAX_FAILURES &gt;= 0:
          self.__failed_keys.append(entity.key())
          if len(self.__failed_keys) &gt; self.MAX_FAILURES:
            # Update completed (failure)
            return True
      
      self.num_processed += 1
      
      if time.time() &gt; end_time:
        return False
    
    # The loop finished - we're done!
    return True</pre>

<p>The __process_entities method takes a query, already positioned at the start of a batch, and iterates over it. We use iteration rather than the more efficient fetch(), because we don't know how many entities we will be able to process in the allotted time.</p>

<p>Most of this method is taken up with exception handling. Several exceptions are treated specially - db.Timeout, apiproxy_errors.CapabilityDisabledError, and apiproxy_errors.DeadlineExceededError, by immediately terminating the batch. We give up immediately on Timeout errors due to the new changes in 1.3.1 which mean that a Timeout returned to our code almost certainly indicates a need to retry at a later stage. Other errors are assumed to be user errors, and are caught and logged. If there's a finite threshold for the maximum number of user errors, the key of the failing entity is recorded, and we abort if we've reached the limit. Finally, after processing each entity, we check the current system time, to determine if we have reached our self-imposed deadline. The method returns True if processing is done - due to success or failure - and False otherwise.</p>

<p>Now we can define run(), the method that handles the whole process:</p>

<pre class="prettyprint">  def run(self, _start_cursor=None):
    """Begins or continues a batch update process."""
    q = self.get_query()
    if _start_cursor:
      q.with_cursor(_start_cursor)
    
    finished = self.__process_entities(q)
    
    # Store or delete any remaining entities
    if self.__to_put:
      db.put(self.__to_put)
    if self.__to_delete:
      db.delete(self.__to_delete)
    self.num_put += len(self.__to_put)
    self.__to_put = []
    self.num_deleted += len(self.__to_delete)
    self.__to_delete = []
    
    self.num_tasks += 1
    
    if finished:
      logging.info(
          "Processed %d entities in %d tasks, putting %d and deleting %d",
          self.num_processed, self.num_tasks, self.num_put, self.num_deleted)
      self.finish(len(self.__failed_keys) &lt;= self.MAX_FAILURES
                  and self.MAX_FAILURES &gt;= 0,
                  self.__failed_keys)
    else:
      defer(self.run, q.cursor())</pre>

<p>run()'s main job is to create a query with which to call __process_entities(), and to clean up after it by storing and deleting any remaining entities. Finally, it checks if the process has finished; if it has, it calls finish(); otherwise, it enqueues the next task, picking up where this one left off.</p>

<p>Back in the original requirements, we included the requirement that it be possible to report completion to admins. Let's do that with a mixin:</p>

<pre class="prettyprint">class ReportingMixin(object):
  def __init__(self, email_sender=None):
    """Constructor.
    
    Args:
      email_sender: If set, send a completion email to admins, from the provided
        email address.
    """
    super(ReportingMixin, self).__init__()
    self.email_sender = email_sender

  def finish(self, success, failed_keys):
    super(ReportingMixin, self).finish(success, failed_keys)
    if not self.email_sender:
      return

    if success:
      message = "Bulk update job %s completed successfully!\n\n" % self.__class__
      subject = "Bulk update completed"
    else:
      message = "Bulk update job %s failed.\n\n" % self.__class__
      subject = "Bulk update FAILED"
    
    message += ("Processed %d entities in %d tasks, putting %d and deleting %d\n\n"
                % (self.num_processed, self.num_tasks, self.num_put,
                   self.num_deleted))
    
    if failed_keys:
      message += "Processing failed for the following keys:\n"
      for key in failed_keys:
        message += "%r\n" % key
    
    mail.send_mail_to_admins(self.email_sender, subject, message)</pre>

<p>This mixin simply extends the finish() method, and if a sender address is provided, sends an email from it to all the app's admins, giving a brief report of the process's completion or failure.</p>

<p>Finally, we can define a couple of simple classes for commonly used types of update operation:</p>

<pre class="prettyprint">class BulkPut(ReportingMixin, BulkUpdater):
  def __init__(self, query, email_sender=None):
    super(BulkPut, self).__init__(email_sender)
    self.query = query

  def get_query(self):
    return self.query

  def handle_entity(self, entity):
    self.put(entity)


class BulkDelete(ReportingMixin, BulkUpdater):
  def __init__(self, query, email_sender=None):
    super(BulkDelete, self).__init__(email_sender)
    self.query = query

  def get_query(self):
    return self.query

  def handle_entity(self, entity):
    self.delete(entity)</pre>

<p>These two classes are almost identical, except for the operation carried out on each entity. In each case, the constructor takes a Query object, which is stored as an instance attribute and returned by get_query; this works because Query objects are picklable, and run() is guaranteed not to modify the query except by calling .with_cursor() on it.</p>

<p>We can test our updater from the remote_api console, like so:</p>

<pre class="prettyprint">notdot-blog&gt; updater = bulkupdate.BulkPut(models.BlogPost.all())
notdot-blog&gt; updater.MAX_EXECUTION_TIME=1.0
notdot-blog&gt; defer(updater.run)</pre>

<p>Checking the admin console shows the deferred tasks being executed, and checking our email shows a message in our inbox titled "Bulk update completed".</p>

<p>As always, bear in mind the limitations of the deferred library when it comes to import path changes, etcetera.</p>

<p>The complete source of our new bulk updater can be found <a href="http://gist.github.com/304654">here</a>.</p>

<p>Finally, a few suggestions for how you can use this module:</p>

<ul>
  <li>Updating instances of a model whose definition has changed, for indexing purposes, using the BulkPut class we defined above.</li>
  <li>Bulk deleting an entity kind, or a subset of it, using the BulkDelete class we defined above.</li>
  <li>Calculating global statistics by storing them against the BulkUpdater instance across requests. Make sure these remain small - if the pickled size of the entity exceeds 10k, each deferred invocation will have to load it from the datastore and store it again at the end!</li>
  <li>Migrating models to new definitions or kind names.</li>
  <li>Performing more complex 'map' operations, such as inserting or updating one entity based on the contents of another.</li>
  <li>Doing periodic updates of stored counts, etc.</li>
</ul>

<p>Got more ideas? Mention them in the comments! Are you using this class for something novel? Let us know!</p></div>
    </content>
    <updated>2010-02-15T13:37:35Z</updated>
    <published>2010-02-15T13:37:35Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-03-12T16:51:18Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:9105</id>
    <link href="http://blog.notdot.net/2006/2/Backstory" rel="alternate" type="text/html"/>
    <title>Backstory</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">A summary of what's going on in my life, for those that don't already know.
<br/> <br/>In early December, I was contacted by a company called [redacted for paranoia]. It seems the CEO of this company was seated next to a good friend of mine, on a flight in the US. My friend was reading an extremely technical book on Software Engineering, and the CEO of this company, noticed this and struck up a conversation. One thing led to another, and (so I gather) the end result was "I met this great guy on the plane. He's already got a job, but he knows someone who's almost as good!". ;)
<br/> <br/>Two phone interviews later - one with the CEO and one with their head of engineering, and they wanted to get me up to their main office for a round of interviews in person. After some wrangling arranging (unpaid) leave with my current employers, I flew up for a few days. The first full day I spent being interviewed by half a dozen people about different aspects of my Software Engineering experience. The one that stands out in my mind most was the interview with their database guru. This is someone who <b>really</b> knows his stuff. I thought I knew a lot about RDBMSes, but coming out of this interview, I felt like I knew next-to-nothing.
<br/> <br/>Apparrently I wasn't that bad, though, because the same evening, the CEO took me out to a resteraunt/bar where we had dinner, and he made me a job offer. The work seems interesting (and challenging too, which is at least as important), and the offer itself was very good. I told him I'd think on it.
<br/> <br/>The next day - a single precious extra day I'd managed to sneak when asking for leave, I bussed up to Vancouver, where I met a number of UFies I've known for some time but never met in person. Dark and a friend of his, met me at my Hotel, and we went to a resteraunt where I finally met (in person) Illiad, Kickstart, and their respective SOs. We then had one of the best dinners I've ever had, both food and company. Plus, everyone else paid my part of the bill. ;)
<br/> <br/>The day after, I took the bus back, where I was met by the head of engineering, given a copy of the job offer, and transported to the airport.
<br/> <br/>Two months after this whole thing began, I write this sitting in my parents' front room, with most of my posessions (having just read Stephen King's Dark Tower, I had to restrain myself from writing 'gunna') arrayed around me. My flight leaves tomorrow evening for Vancouver Canada, where I will be living and telecommuting until (hopefully!) October, when I'll (hopefully!) get my US work visa and move down to work there. In the mean time, I can commute when I'm needed for meetings or training, and spend the rest of the time telecommuting from Vancouver.
<br/> <br/>Edit: Yes, edited to be much less specific, for paranoia reasons. My apologies.</div>
    </content>
    <updated>2010-02-15T13:27:06Z</updated>
    <published>2006-02-20T00:38:50Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-03-10T14:55:11Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:8162</id>
    <link href="http://blog.notdot.net/2006/3/Stereotypes-in-action" rel="alternate" type="text/html"/>
    <title>Stereotypes in action!</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">On Sunday evening (a little before midnight - the Amtrak train got in really late), I arrived at my accommodations for the next 3 weeks - the Pacific Inn in Bellevue. Checking in, the person at the desk asked me for my passport or driver's license so he could take a copy of it. I gave him my passport, which he took to another room to photocopy.
<br/> <br/>I waited for him to return. And waited. And waited. About 5 minutes after he left, he came back in, without my passport or a copy, and said "You're a software guy, right?".
<br/> <br/>I'm sure you can see what's coming. He was unable to operate the photocopier. He asked me to take a look. I pressed the '+' button to increase the number of copies from 0 to 1, then pressed the copy button. It copied.
<br/> <br/>What amuses me here isn't that he was unable to operate the photocopier - any photocopier that defaults to 0 copies (and returns to that when all its copies are made) is particularaly badly designed, and it's not surprising he had trouble if he hadn't used it before. What amuses me is how incredibly stereotypical it is. Geek arrives in a hotel, and is immediately called on to help fix something that's preventing him from being able to check in.
<br/> <br/>Anyway, the apartments are nice. I have a small loft apartment, with a kitchenette, a lounge area (with a desk and proper office chair - yaay!) and a bathroom, then a short flight of stairs up to an area with my bed. It's small (or should I say 'compact'?), but quite nice. Definitely an improvement over the American Extended Stay I was in last time. Internet is provided via Ethernet cable, which I have hooked up to a newly purchased Airport Express so I can have wireless (two levels of NAT, though - yuck). Access is, unfortunately, rather slow. Also, random ports - 993 for SSL IMAP, 9898 for my IRC proxy - seem to be blocked. It might be the Airport Express, but I doubt it.</div>
    </content>
    <updated>2010-02-15T13:27:06Z</updated>
    <published>2006-03-08T19:40:53Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-03-01T15:33:24Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:8161</id>
    <link href="http://blog.notdot.net/2006/2/Here-I-am" rel="alternate" type="text/html"/>
    <title>Here I am</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Well, here I am in Canada. The trip was, as expected, exhausting, and hard on my legs.
<br/> <br/>The flight out of Christchurch was on one of the old, unrefurbished 747s, which was rather annoying - the in-flight entertainment systems on the refurbished ones are really good at banishing boredom. Instead, mixed with mostly failed attempts to get some sleep, I read <a href="http://www.amazon.com/gp/product/1400030927/sr=8-1/qid=1140594422/ref=pd_bbs_1/103-6211066-3508622?%5Fencoding=UTF8">Jennifer Government</a> cover-to-cover (good book), with enough time left over to watch the few remaining episodes of <a href="http://www.tv.com/qi/show/19917/summary.html?q=qi">QI</a> that I hadn't seen yet.
<br/> <br/>Then I transferred through LAX, where I had to pick up all my baggage to check it in at the transferring baggage desk. Thankfully, a helpful TSA(!) person told me I should take it all upstairs and get it checked in there, because the bike was too large and would have to go up there anyway. After a wait of about 1/2 an hour to get into the lift, my bag, box and bike were accepted almost immediately.
<br/> <br/>The service from Air Canada wasn't nearly as bad as I'd been led to expect - the flight attendants were friendly to a fault, and I have no complaints. Maybe it was an exception.
<br/> <br/>On arriving at Vancouver, there was a long delay before the bags were emitted from the luggage turnstile. My bike box had developed, since LAX, a rather worrying hole in it, with the front wheel hub poking through. On inspection, the front wheel is significantly out of true. :/
<br/> <br/>A long day, anyway. I'm glad I'm not travelling anymore.</div>
    </content>
    <updated>2010-02-15T13:27:06Z</updated>
    <published>2006-02-22T07:43:55Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-03-03T14:49:07Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:8160</id>
    <link href="http://blog.notdot.net/2006/2/An-unexpected-party" rel="alternate" type="text/html"/>
    <title>An unexpected party</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Yesterday evening, my (now ex-) flatmates came around to pick me up for a farewell drink or two at the dux. Returning home, I was somewhat, though not entirely, surprised to find the kitchen dining room filled to bursting with friends and acquaintances. I'd been expecting a family farewell dinner, with maybe some extended family around, this was rather larger.
<br/> <br/>I had a great evening, and caught up with some people I haven't seen in too long. I was given a few going-away gifts, chief amongst them the book 'Are you a geek?', given to me by a collection of friends. I'm pretty sure I know what the answer is already, but from the browse through it I've already had, the book is hilarious. I look forward to filling it out.
<br/> <br/>All in all, I couldn't have asked for a better going-away party.</div>
    </content>
    <updated>2010-02-15T13:27:06Z</updated>
    <published>2006-02-20T00:58:29Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-03-08T14:41:24Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:9109</id>
    <link href="http://blog.notdot.net/2006/4/Somewhere-to-stay" rel="alternate" type="text/html"/>
    <title>Somewhere to stay!</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">As much as I like sleeping in Dark's lounge, eating his breakfast cereal, and working from his dinner table, I have been desperately searching for a furnished apartment I can stay in while I'm here. All at once, on Thursday, my search paid off - with two seperate apartments. I took the slightly more expensive and slightly larger one, paying $100 less than Too Much for it. It's still a studio apartment, but it has a murphy bed, placed such that I can fold it up when I have people around, but I don't _have_ to if I don't. It has a nice little enclosed balcony/conservatory area with a computer workstation. I can work whilst looking out over the city from my dizzyingly high 32nd floor perspective.
<br/> <br/>Photos will be forthcoming once I'm moved in, later today.</div>
    </content>
    <updated>2010-02-15T13:27:05Z</updated>
    <published>2006-04-08T20:45:08Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-17T17:59:57Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:9106</id>
    <link href="http://blog.notdot.net/2006/3/How-Canadian-Immigration-helps-Amtrak-compete-with-airlines-for-user-unfriendliness" rel="alternate" type="text/html"/>
    <title>How Canadian Immigration helps Amtrak compete with airlines for user-unfriendliness.</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Today was the day I was scheduled to go back up to Canada, after 3 weeks down here in Seattle training at the offices of the company I contract for. In an ideal world, I would have headed back to Vancouver, whereupon I would have located a furnished apartment to stay in until the end of June, or, with an application to Canadian immigration, possibly as late as October.
<br/> <br/>Instead, I spent 4 hours getting down there, 3/4 of an hour being interrogated by Canadian Immigration personnell, 6 hours sitting in a stationary train being watched over by a security guard, and another 4 hours back to Seattle.
<br/> <br/>Basically, the Canadian customs officer decided my reasons for wanting to (re)enter Canada weren't wholesome enough. The fact that I was contracting for a Seattle company, and planning on staying in Vancouver with trips down to Seattle at intervals, apparrently indicated to him that:
<br/>1) I was doing this to avoid US visa requirements, which prohibit me from working for the Seattle company as an employee in Seattle, by tele-commuting from the conveniently-nearby Vancouver.
<br/>2) He had no proof that my company was even applying for an H1B VISA, and that they weren't just bullshitting me, or that I wasn't intending to just stay in Canada indefinitely.
<br/> <br/>So, here I am back in Seattle. In a different hotel, since my old one had already cleaned and re-rented my old room.
<br/> <br/>Oh, and someone remind me to tell you all about the least competent security guard I've ever met, when I'm less tired and pissed off.
<br/> <br/>Edited: More paranoia - removed the name of the company I work for. Sorry.</div>
    </content>
    <updated>2010-02-15T13:27:05Z</updated>
    <published>2006-03-26T08:35:53Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-22T21:22:29Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:8165</id>
    <link href="http://blog.notdot.net/2006/4/Photos-of-my-new-apartment" rel="alternate" type="text/html"/>
    <title>Photos of my new apartment</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">A bunch of photos of my new apartment. Please forgive the poor compositing on the two of my work area, I didn't have a tripod, and it wasn't possible to get the whole thing with a single frame (too much dynamic range).
<br/><a href="http://blog.notdot.net/uploads/DSC_1603.JPG"><img alt="" height="73" src="http://blog.notdot.net/uploads/DSC_1603.serendipityThumb.JPG" style="border: 0px; padding-left: 5px; padding-right: 5px;" width="110"/></a><a href="http://blog.notdot.net/uploads/DSC_1608.JPG"><img alt="" height="73" src="http://blog.notdot.net/uploads/DSC_1608.serendipityThumb.JPG" style="border: 0px; padding-left: 5px; padding-right: 5px;" width="110"/></a><a href="http://blog.notdot.net/uploads/DSC_1609.JPG"><img alt="" height="73" src="http://blog.notdot.net/uploads/DSC_1609.serendipityThumb.JPG" style="border: 0px; padding-left: 5px; padding-right: 5px;" width="110"/></a> <br/> <br/><a href="http://blog.notdot.net/uploads/DSC_1638.JPG"><img alt="" height="73" src="http://blog.notdot.net/uploads/DSC_1638.serendipityThumb.JPG" style="border: 0px; padding-left: 5px; padding-right: 5px;" width="110"/></a><a href="http://blog.notdot.net/uploads/DSC_1611.JPG"><img alt="" height="73" src="http://blog.notdot.net/uploads/DSC_1611.serendipityThumb.JPG" style="border: 0px; padding-left: 5px; padding-right: 5px;" width="110"/></a><a href="http://blog.notdot.net/uploads/workspace2_composite.JPG"><img alt="" height="73" src="http://blog.notdot.net/uploads/workspace2_composite.serendipityThumb.JPG" style="border: 0px; padding-left: 5px; padding-right: 5px;" width="110"/></a> <br/> <br/><a href="http://blog.notdot.net/uploads/workspace1_composite.JPG"><img alt="" height="110" src="http://blog.notdot.net/uploads/workspace1_composite.serendipityThumb.JPG" style="border: 0px; padding-left: 5px; padding-right: 5px;" width="73"/></a> <br/> <br/>Edit: Added a picture of how it looks at sunset:
<br/> <br/><a href="http://blog.notdot.net/uploads/DSC_1642.JPG"><img alt="" height="73" src="http://blog.notdot.net/uploads/DSC_1642.serendipityThumb.JPG" style="border: 0px; padding-left: 5px; padding-right: 5px;" width="110"/></a></div>
    </content>
    <updated>2010-02-15T13:27:05Z</updated>
    <published>2006-04-11T04:03:24Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-15T13:37:35Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:8164</id>
    <link href="http://blog.notdot.net/2006/4/Back-in-Canada" rel="alternate" type="text/html"/>
    <title>Back in Canada</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">So, I made it back into Canada. After all the extensive, lawyer-assisted preparations so I would be able to explain myself in sufficient and excrutiating detail to the customs officers, I was simply waved through with nary a glance.
<br/> <br/>Then, as I pull away, suitcase in tow, the officer goes "Hold on a moment". "Uh oh", I think, "now I get the half hour of going over all my documentation 5 times before they're satisfied". I return to the desk, and give him back my passport. The passport scanner is flashing "NZ Passport Alert!!!" on and off. The screen has a single line entry " Personal Marajuana Posession". I have no idea what it's talking about - I presume a name collision. He puts the passport back on the scanner, waits a couple of seconds, takes it off, hands it back, and tells me I can go. I do.</div>
    </content>
    <updated>2010-02-15T13:27:05Z</updated>
    <published>2006-04-04T04:00:00Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-18T09:34:15Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:8163</id>
    <link href="http://blog.notdot.net/2006/3/Things-that-are-strange-about-North-America-part-1" rel="alternate" type="text/html"/>
    <title>Things that are strange about North America, part 1</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">- Coins are 1c (useless bits of copper), 5c, 10c and 25c. Canada sensibly has $1 (a 'Loonie') and $2 (a 'Toonie') coins. The US still has scraps of tattered paper for $1, and nothing for $2.
<br/> <br/>- The 5c coin is bigger than the 10c coin. So is the 1c coin. Yes, the 10c coin is the smallest coin of the lot.
<br/> <br/>- 10 coins are 'dimes', and 5c coins are 'nickels'. The 10c coin doesn't even say what its value in cents is, just 'one dime'.
<br/> <br/>- Pedestrian crossing buttons are sometimes on the side of the pole facing the direction you want to cross, and sometimes 90 degrees from that (with an arrow pointing the direction you should cross for this button). They are never on the opposite side of the pole to the direction you are going so you can press it as you approach.
<br/> <br/>- The only 'barn dance' crossing I have encountered has a recorded voice telling people how to use it.
<br/> <br/>- Cars drive on the right (duh).
<br/> <br/>- Most roads are more than two lanes, even right in the middle of town.
<br/> <br/>- The lanes are really narrow.
<br/> <br/>- Instead of one set of signals, possibly with additional left and right arrow signals, there's often a set of signals over each lane.
<br/> <br/>- Cars can ignore the red light when turning right if there's nothing coming. Smart idea.
<br/> <br/>- Some crossings in Vancouver have a counter under them indicating how much longer you have to cross. Another smart idea.
<br/> <br/>- In the US, your taxi driver will always ask you if you like "this country". This is a trick question. There is only one correct answer.
<br/> <br/>- Tipping.
<br/> <br/>- When you eat in a resteraunt, your bill is brought to you in a little folder. You insert cash and/or credit-cards, and they take it away again.
<br/> <br/>- A manual transmission car is a 'stick shift'.
<br/> <br/>- Everyone thinks you're from Australia.
<br/> <br/>- EFTPOS is called Interac instead.
<br/> <br/>- Late night bookstores, with multiple large shelves of sci-fi and fantasy titles. I'm going to end up spending waaay too much on books.
<br/> <br/>- The books are really cheap, though.
<br/> <br/>- Cars stop for you at corners, even when there's no pedestrian or signalled crossing.
<br/> <br/>- You can buy a reasonable lunch for under $5.
<br/> <br/>- 'Kiwifruit' is called just 'Kiwi'. Saying you're a Kiwi is liable to get some odd looks.
<br/> <br/>- It's winter.
<br/> <br/>- Most power plugs can be inserted upside-down.
<br/> <br/>- Toilets have some sort of weird system where they first drain, then refill, instead of just using a u-bend.</div>
    </content>
    <updated>2010-02-15T13:27:05Z</updated>
    <published>2006-03-08T19:50:19Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-25T21:36:23Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:30001</id>
    <link href="http://blog.notdot.net/2010/01/Webapps-on-App-Engine-part-1-Routing" rel="alternate" type="text/html"/>
    <title>Webapps on App Engine part 1: Routing</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><em>This is part of a series on writing a webapp framework for App Engine Python. For details, see the introductory post <a href="http://blog.notdot.net/2010/01/Writing-your-own-webapp-framework-for-App-Engine">here</a>.</em></p> 

<p>The first part of a framework you encounter when using one is, more often than not, the routing code. With that in mind, it's what we'll be tackling first. There are several approaches to handling request routing, and we'll go on a quick tour of the libraries and approaches before we decide on one and implement it.</p>

<p>The built-in App Engine webapp framework takes an extremely straightforward approach: The incoming request's URL is compared to a list of regular expressions in order, and the first one that matches has the corresponding handler executed. As an enhancement, any captured groups in the regular expression are passed to the request handler as additional arguments. You can see the code that does all this <a href="http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/webapp/__init__.py#493">here</a> - it's extremely straightforward and easy to follow.</p>

<p>The webapp module does one thing that I'm not a huge fan of: It ties the request routing in with handling the requests. The same function that finds the appropriate handler for a request also takes care of parsing the request and calling the appropriate methods on the RequestHandler subclass. As a result, RequestHandler classes are not WSGI applications, and you can't mix non-webapp apps in. With that caveat in mind, let's continue to look at some of the alternate approaches.</p>

<p>Django's approach to URL handling is documented <a href="http://docs.djangoproject.com/en/1.1/topics/http/urls/#topics-http-urls">here</a>. It bears a remarkable resemblance to the webapp module's approach, and for good reason: A lot of App Engine's python library was inspired by Django. One difference worth noting about the way Django handles things is that the second parameter in each tuple is the string name of the module that will handle requests for that URL regex, rather than the class itself. This seems a little awkward, but provides a real benefit: It means we don't need to load every handler module in order to service a request to just one of them. We'll discuss optimisations like this in more detail in a later post.</p>

<p>In the realm of independent libraries, there are several prominent options. The <a href="http://routes.groovie.org/index.html">routes</a> library is a port of the Rails routing system, and uses a rather sophisticated system based on expressions that symbolically represent the sort of URLs you want to match. For example, the string "/error/{action}/{id}" matches any URL that has 3 slash-separated components starting with "/error", and breaks out the last two into separate variables, 'action' and 'id'.</p>

<p>Somewhat counterintuitively, the Routes library doesn't actually route requests to individual WSGI applications or handlers; instead it simply takes care of parsing URL patterns into dictionaries mapping set keys to values found in the URL. In that respect it's very sophisticated, allowing a great deal of flexibility in how you specify your URL parsing, including default values, regular expressions, and other features. It's then the job of another (simpler) piece of WSGI middleware to take the information routes produces and use it to dispatch to the appropriate handler.</p>

<p>Besides being typically easier to understand and more flexible than a naive regular-expression based system, Routes' approach has another advantage: It's possible to perform the reverse transformation, and generate a URL given a dict like that generated by routes. As long as your apps use this to generate URLs when they're needed, this means that you or your users can completely restructure the URL structure of your app without needing to make any changes to the rest of your code.</p>

<p>The <a href="http://werkzeug.pocoo.org/documentation/0.5.1/routing.html">werkzeug</a> framework provides a similar mechanism, enhancing it with 'converter' functions that specify the accepted characters and converting the returned value. <strike>Unlike Routes, however, it doesn't provide the capability to use the mapping in the reverse direction, generating URLs.</strike> Edit: Werkzeug also supports doing reverse mappings, like Routes.</p>

<p>Finally, Webob's "do it yourself framework" <a href="http://pythonpaste.org/webob/do-it-yourself.html#routing">demonstrates</a> a method that is very similar to that defined by Routes, but has the substantial advantage that it's easily converted from the semantic form users enter into an ordinary regular expression. It is on this that we will base our own routing middleware.</p>

<p>First, let's take a look at the template_to_regex function from the webob framework, which we will use without modification:</p>

<pre class="prettyprint"> &gt;&gt;&gt; import re
 &gt;&gt;&gt; var_regex = re.compile(r'''
 ...     \{          # The exact character "{"
 ...     (\w+)       # The variable name (restricted to a-z, 0-9, _)
 ...     (?::([^}]+))? # The optional :regex part
 ...     \}          # The exact character "}"
 ...     ''', re.VERBOSE)
 &gt;&gt;&gt; def template_to_regex(template):
 ...     regex = ''
 ...     last_pos = 0
 ...     for match in var_regex.finditer(template):
 ...         regex += re.escape(template[last_pos:match.start()])
 ...         var_name = match.group(1)
 ...         expr = match.group(2) or '[^/]+'
 ...         expr = '(?P&lt;%s&gt;%s)' % (var_name, expr)
 ...         regex += expr
 ...         last_pos = match.end()
 ...     regex += re.escape(template[last_pos:])
 ...     regex = '^%s$' % regex
 ...     return regex</pre>

<p>The workings of this function are described in detail on the <a href="http://pythonpaste.org/webob/do-it-yourself.html#routing">webob site</a>, but we'll go over the basics here. Our ultimate goal is to take strings that contain expressions of the form "{variable:regex}" and convert them into fully formed regular expressions. For example, a template such as "/{year:\d\d\d\d}/{month:\d\d}/{slug}" should be converted into the regular expression "^/(?P&lt;year&gt;\d\d\d\d)/(?P&lt;month&gt;\d\d)/(?P&lt;slug&gt;[^/]+)$". The parentheses in the regular expression are capturing subexpressions, meaning their contents will be available to us if the expression matches, while the "?P&lt;foo&gt;" part signifies a label for that subexpression, allowing us to access it by name rather than by position.</p>

<p>The main part of the function is a loop over every template expression found in the input string. The output regular expression is built up in the variable named 'regex'. For each match, we first append the text between the previous match (if any) and the current one (after escaping it, so special characters aren't mistakenly interpreted as regular expression modifiers). Then, the variable name and regular expression are extracted from the template expression. If no regular expression was specified, the default expression "[^/]+", meaning one or more non-forward-slash characters, is used. The regular expression for this match is then appended to the regex-so-far, as a named sub-group as we described above. Finally, any remaining text is appended to the string, and the whole regular expression is wrapped in '^' and '$', the regular expression symbols that indicate the start and end of a string.</p>

<p>And yes, if you think using a regular expression to parse bits of regular expression into a new regular expression is all a bit meta, you're not alone.</p>

<p>Now that we've sorted out what format we'll use for specifying routes, we're ready to write the routing code itself. We'll be using a system similar to Routes, whereby you can specify additional default named arguments with your route and handler, but our handlers will be regular WSGI applications, called directly, rather than using the extra layer of indirection provided by Routes. Also, although we have left the door open for being able to do the reverse transform of handlers back to URLs, we won't be doing so in our first iteration.</p>

<pre class="prettyprint">class WSGIRouter(object):
  def __init__(self):
    self.routes = []

  def connect(self, template, handler, **kwargs):
    """Connects URLs matching a template to a handler application.
    
    Args:
      template: A template string, consisting of literal text and template
        expressions of the form {label[: regex]}, where label is the mandatory
        name of the expression, and regex is an optional regular expression.
      handler: A WSGI application to execute when the template is matched.
      **kwargs: Additional keyword arguments to pass along with those parsed
        from the template.
    """
    route_re = re.compile(template_to_regex(template))
    self.routes.append((route_re, handler, kwargs))</pre>

<p>As you can see, the basic code for our router is extremely simple. We define a method, connect(), which takes a template string, a handler, and optional keyword arguments. This method calls template_to_regex to generate a regular expression, then inserts that and the additional argument in the list of routes. The real work happens when our router object is called as a WSGI application:</p>

<pre class="prettyprint">  def __call__(self, environ, start_response):
    for regex, handler, kwargs in self.routes:
      match = regex.match(environ['PATH_INFO'])
      if match:
        environ['router.args'] = dict(kwargs)
        environ['router.args'].update(match.groupdict())
        return handler(environ, start_response)</pre>

<p>The name of the method, __call__, distinguishes this as a special method to python. Normally it's not possible to call an object as you would a function, but if your class defines the __call__ method, this method is executed when someone calls your object. This allows objects of our WSGIRouter class to act as regular WSGI applications.</p>

<p>When our router is called, it iterates over each of the routes that were provided, and for each one attempts to match it against the PATH_INFO CGI variable. If it finds a match, it extends the WSGI environment by adding a variable called 'router.args'. This variable consists of any static arguments that were passed to the connect() method, in addition to the values of all the matched template parameters. The router then calls the selected WSGI app, returning its result to its own caller. It's up to whatever WSGI application is being called to extract the router.args variable from its environment if it needs it, and to act on it accordingly.</p>

<p>Let's define a simple webapp to test all this out:</p>

<pre class="prettyprint">def hello_app(environ, start_response):
  start_response(200, [("Content-Type", "text/plain")])
  return ["Hello, world."]


def echo_app(environ, start_response):
  start_response(200, [("Content-Type", "text/plain")])
  return [repr(environ['router.args'])]


router = WSGIRouter()
router.connect("/hello", hello_app)
router.connect("/echo/{foo}/{bar:[0-9]+}", echo_app, test="test")

def main():
  run_wsgi_app(router)

if __name__ == '__main__':
  main()</pre>

<p>This app defines two handlers, mapped to two different URL patterns. If you go to '/hello', you should see "Hello, world.". If you go to a URL such as "/echo/bleh/123", you should see the complete template dict - in this example, it'll be "{'test': 'test', 'foo': 'bleh', 'bar': '123'}".</p>

<p>That's it for routing! In the next post we'll handle decoding and encoding requests and responses.</p></div>
    </content>
    <updated>2010-02-15T13:02:03Z</updated>
    <published>2010-01-20T14:05:24Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-15T13:02:03Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:29001</id>
    <link href="http://blog.notdot.net/2010/01/Writing-your-own-webapp-framework-for-App-Engine" rel="alternate" type="text/html"/>
    <title>Writing your own webapp framework for App Engine</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Welcome back! I trust you all had a good holiday period? Mine was spent back
in sunny New Zealand, seeing friends and family, visiting <a href="http://www.drexels.co.nz/">favorite restaurants</a>,
enjoying the sunshine, and <a href="http://www.parapro.co.nz/">learning to paraglide</a>.</p>

<p>I would have started blogging again last week, but my first week back was
made both exciting and frantically busy preparing for, then attending the
<a href="http://www.btyoungscientist.ie/">BT Young Scientist Exhibition</a>, where
I gave tutorials on App Engine at the Google booth. But now, back to your regularly
scheduled blogging...</p>

<p>Sometimes it seems like everyone has written their own blogging system, and
everyone has written their own framework for webapps. That's not all these two 
things have in common, though: They're both excellent learning projects. Since 
you've already done <a href="http://blog.notdot.net/2009/10/Writing-a-blog-system-on-App-Engine">the first</a>, why not do the second? This will 
be the first of a series of posts covering how to write your own Python webapp 
framework. The framework, while targeted at App Engine, isn't exclusive to it.</p>

<p>As with the blogging project, it helps to set some goals before we get started. 
Here's our goals for this project:</p>

<ul>
  <li>Lightweight. With cold startup time being a significant concern for many, 
    it's essential to avoid creating a large, monolithic framework which 
    requires importing a lot of extraneous code before it can serve even basic 
    requests. Likewise, we don't want users of our framework to have to add a 
    great deal of overhead to their app.</li>
  <li>Loosely coupled. Like all good frameworks, swapping out components should 
    be easy, and nobody should be forced to use the entire framework if they 
    only want part of it.</li>
  <li>'Best-of-breed' components. As we'll see, there are already many good open 
    source libraries that take care of individual tasks like routing, rendering 
    templates, and session handling. Our framework should reuse these wherever 
    possible.</li>
  <li>Fast. This overlaps with the first two, but it's worth a bullet point of 
    its own. There's a great deal of variability in the performance of some of 
    the libraries available, and we should do our best to pick the fast ones.</li>
</ul>

<p>One caveat, however. My main goal for this series is to introduce you to the 
inside workings of a web framework, and the things it interfaces with, such as 
WSGI and CGI. We're not writing something with the goal of being a serious 
competitor to all those other frameworks out there, so don't expect 
enterprise-level support or an active development beyond the series. If, like 
me, you love to hack around with this sort of thing, feel free to pick it up - 
fork it, use it, improve it! If, however, you're just looking for a ready-made 
framework to use with your next webapp, you're probably better off choosing one 
of the many existing frameworks with App Engine support.</p>

<p>Before we begin, we need to cover the basics of what a framework is, and how 
it works. If you're already familiar with things such as HTTP, CGI, and WSGI, 
feel free to skip over this section. Otherwise, read on!</p>

<h3>HTTP</h3>
<p>At the bottom of the stack is HTTP, which you should already be somewhat 
familiar with. HTTP is fundamentally a request-based protocol: A client makes a 
request, consisting of a URI path, a method, a set of headers, and an optional 
body, and the HTTP server sends back a response, likewise consisting of a set of 
headers and an optional body.</p>

<h3>CGI</h3>
<p>In order to be able to write an application that operates over HTTP, an 
interface of some sort is required, and that interface is CGI. CGI is a 
venerable standard by now, first standardized back in 1993, and it's a little 
archaic by today's standards. Although it (or systems based on it, like WSGI) is 
still used today, many of its design features are more than a little odd for 
today's webapps.</p>

<p>When a webserver receives a request that is to be handled by a CGI script, it 
transforms the request into a set of environment variables. The request method 
(Eg, GET, HEAD, POST, etc) is passed as the REQUEST_METHOD variable, while the
URI path is split up into several components, which are passed separately: 
SCRIPT_NAME, the URI to the CGI script, PATH_INFO, the remainder of the URI path, 
and QUERY_STRING, the contents of the query string. The protocol being used is 
passed in via the 'HTTPS' variable, which is set to 'on' if HTTPS is in use, 
and 'off' otherwise. Other headers are transformed by making them all uppercase, 
and replacing hyphens with underscores - eg, 'Content-Type' becomes 
'CONTENT_TYPE'. Since most webapps now don't actually use CGI scripts, the first 
variable, SCRIPT_NAME, is often left blank, or is set to the path to the 
application as a whole.</p>

<p>CGI was originally designed to formalize the handling of HTTP requests by 
standalone executables. The request would be transformed as we described above, 
then the script in question would be executed with those variables in its OS 
environment. The request body, if any, would be passed in on standard input. The 
CGI script is expected to process the request, and return the headers, followed 
by a newline and the response body, on standard out. This general pattern is 
preserved, with some modifications, on App Engine.</p>

<p>The main difference in App Engine's handling of CGI is a performance 
optimisation: instead of re-executing your Python executable for each request, a
single Python runtime is used for multiple requests. Each request simply
re-imports the main handler script for your app, which results in re-executing
all the code in it, though modules loaded from it are not re-imported. As a further
optimisation, if you provide a function called 'main' in your handler module,
that function is executed on the second and subsequent requests, instead of
re-importing the module.</p>

<h3>WSGI</h3>
<p><a href="http://wsgi.org/wsgi/">WSGI</a> is a Python standard for interactions
between servers and webapps. It utilizes components of the CGI standard,
enhancing them in a manner that makes it easier to use in Python. Although it's
not necessary to use WSGI with App Engine, it is convenient, and most framework
libraries expect it, so that's what we'll be using.</p>

<p>WSGI operates
by calling an 'application' function with a specific signature. The function is
expected to take two arguments, 'environ' and 'start_response', and return an iterable
of strings. The environ argument is a Python dict, containing a standard CGI
environment, along with certain extra values specific to WSGI. The 'start_response'
argument is a function, which itself takes two parameters, 'status' and
'response_headers'.</p>

<p>When called, a WSGI application is expected to do its stuff, then call
start_response with the HTTP status code and a dictionary of HTTP headers to
return to the client. Then, it should return or yield the body of the response
as an iterable sequence of strings. Since App Engine doesn't support streaming
responses, returning or yielding are equivalent, so we'll simply use return,
for simplicity.</p>

<p>The way WSGI works permits very modular design of apps and frameworks. WSGI
middleware is code that takes a WSGI application and 'wraps' it, transparently
adding functionality. An example of WSGI middleware is
<a href="http://beaker.groovie.org/index.html">beaker</a>, a Python library that
provides caching and session handling for WSGI applications.</p>

<p>Here's a simple WSGI application that prints 'hello world':</p>

<pre class="prettyprint">def application(environ, start_response):
  start_response(200, {'Content-Type': 'text/plain'})
  return ['Hello, world!']</pre>

<p>As you can see, this is still a bit low level for your average webapp - hence
our quest to write our own framework. There are several major components to a
webapp framework, and we'll be covering them over the next couple of weeks:</p>

<ol>
  <li><a href="http://blog.notdot.net/2010/01/Webapps-on-App-Engine-part-1-Routing">Routing</a></li>
  <li><a href="http://blog.notdot.net/2010/01/Webapps-on-App-Engine-part-2-Request-Response-handling">Request decoding &amp; Response encoding</a></li>
  <li><a href="http://blog.notdot.net/2010/01/Webapps-on-App-Engine-part-3-Request-handlers">Request handlers</a></li>
  <li><a href="http://blog.notdot.net/2010/02/Webapps-on-App-Engine-part-4-Templating">Templates</a></li>
  <li><a href="http://blog.notdot.net/2010/02/Webapps-on-App-Engine-Part-5-Sessions">Sessions</a></li>
  <li><a href="http://blog.notdot.net/2010/02/Webapps-on-App-Engine-part-6-Lazy-loading">Optimizing performance with load-on-demand</a></li>
</ol>

<p>In each part of the series, we'll discuss the currently available options for
that part of the framework, then decide on a solution that best suits our
specific needs, and implement it. In some cases we'll go with pre-made solutions,
while in others we'll choose to implement it ourselves. In the most part, the
decision of which of these to choose will rest on which teaches us the most about
how it all works.</p>

<p>Look out for the first post, on request routing, on Wednesday!</p></div>
    </content>
    <updated>2010-02-15T13:02:03Z</updated>
    <published>2010-01-18T14:57:16Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-15T13:02:03Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:28001</id>
    <link href="http://blog.notdot.net/2009/12/Merry-Season" rel="alternate" type="text/html"/>
    <title>Merry Season!</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>As you've probably guessed by now, I'm not posting over the holiday period. Expect new content, including an all new series of posts, in the new year, however!</p>

<p>In the meantime, enjoy your time with your families, if that's what you're doing. As for myself and my wife, Hayley, we're back in New Zealand, enjoying some quality time with our families.</p></div>
    </content>
    <updated>2010-02-15T13:02:03Z</updated>
    <published>2009-12-24T19:04:11Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-15T13:02:03Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:34001</id>
    <link href="http://blog.notdot.net/2010/02/New-features-in-1-3-1-prerelease-Cursors" rel="alternate" type="text/html"/>
    <title>New features in 1.3.1 prerelease: Cursors</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Recently, the App Engine team <a href="http://groups.google.com/group/google-appengine/browse_thread/thread/ddef6d9fa4aa0ae2?pli=1">announced</a> that they'd be pre-releasing SDKs for testing and feedback, before they go live in production. With the first prerelease, 1.3.1, a number of new features are included in the SDK. Today we'll discuss cursors - how they work, and what they're useful for.</p>

<p>Cursors are a feature that many people have been waiting for with bated breath. As well as making pagination easier, they also provide a way around the "1000 result limit" that many people feel (in some cases correctly) makes it harder to achieve what they want to do on App Engine.</p>

<p>When it comes to investigating new features, there are two really useful tools: An interactive console - such as that on http://localhost:8080/_ah/admin/, http://shell.appspot.com/ or the remote_api console - and the source code. Many people forget that as an Open Source project, the App Engine SDK code is all available - and easily <a href="http://code.google.com/p/googleappengine/source/browse/">browseable on code.google.com</a>.</p>

<p>Our first stop is google/appengine/ext/db/__init__.py. Of interest here is <a href="http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/db/__init__.py#1600">the cursor() method</a>, which starts on line 1600. As you can see, when called on a query that's already been executed (with .fetch(), .get(), etc), it constructs a datastore_pb.CompiledQuery object, fills in its fields with information from the query, and returns the encoded Protocol Buffer, wrapped in base64 for easy transport. Let's give it a try in our interactive shell:</p>

<pre class="prettyprint">&gt;&gt;&gt; class TestModel(db.Model): pass
&gt;&gt;&gt; db.put([TestModel() for x in range(100)])

&gt;&gt;&gt; q = TestModel.all()
&gt;&gt;&gt; [x.key().id() for x in q.fetch(5)]
[1, 2, 3, 4, 5]

&gt;&gt;&gt; q.cursor()
'CxoRY3Vyc29yPTUmb2Zmc2V0PTUgAAxgAA=='</pre>

<p>About what we expected, given the source. How do we use it, though? The very next method after cursor() is <a href="http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/db/__init__.py#1637">with_cursor()</a>, which, according to the docstring, will "set the start of this query to the given serialized cursor". Perfect! Let's give that a try, then:</p>

<pre class="prettyprint">&gt;&gt;&gt; class TestModel(db.Model): pass

&gt;&gt;&gt; q = TestModel.all()
&gt;&gt;&gt; [x.key().id() for x in q.fetch(3)]
[1, 2, 3]

&gt;&gt;&gt; r = TestModel.all().with_cursor(q.cursor())
&gt;&gt;&gt; [x.key().id() for x in r.fetch(3)]
[4, 5, 6]</pre>

<p>Easy! This will work for any query at all, and makes it possible to pick up where you left off, simply by storing the cursor string, and using it in a subsequent query.</p>

<p>But what's in these mysterious query strings? Well, we already know they're constructed from datastore_pb.CompiledQuery protocol buffers. Let's write a function that'll let us peek inside one:</p>

<pre class="prettyprint">import base64
from google.appengine.datastore import datastore_pb

def cursor_to_ascii(cursor):
  pb = datastore_pb.CompiledQuery(base64.urlsafe_b64decode(cursor))
  return pb.ToASCII()</pre>

<p>Using it on our earlier cursor, we get:</p>

<pre class="prettyprint">PrimaryScan {
  start_key: "cursor=5&amp;offset=5"
  start_inclusive: false
}
keys_only: false</pre>

<p>As you can see, the internals of a cursor store pretty much the same information you'd store if you were doing pagination yourself - only, with the datastore doing it for you, everything is much easier, and likely more efficient to boot. Finally, let's try it on a slightly more complex query, one for TestModel.all().filter("foo =", bar"):</p>

<pre class="prettyprint">PrimaryScan {
  start_key: "shell\000TestModel\000foo\000\232bar\000\200"
  start_inclusive: true
}
keys_only: false</pre>

<p>Apart from the obvious difference, you'll note this seems to be a different format to the first one. That's because the first one was generated by the dev_appserver, while this one was generated on shell.appspot.com. As you can see, they use slightly different notations - but then, that shouldn't matter, since you certainly shouldn't be relying on the internal format of these data structures for anything except informational purposes!</p>

<p>One caveat for early adopters: A near perfect storm of different minor bugs make testing this in interactive consoles - remote_api, shell.appspot.com and the dev_appserver console - more problematic than it should be. And, of course, cursors, like all other prerelease features, are likely to only work on the dev appserver. But then, that's why it's called a prerelease.</p></div>
    </content>
    <updated>2010-02-15T13:02:02Z</updated>
    <published>2010-02-08T16:45:38Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-15T13:02:03Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:32002</id>
    <link href="http://blog.notdot.net/2010/01/Snow-Sprint-wrap-up-and-introducing-Tweet-Engine" rel="alternate" type="text/html"/>
    <title>Snow Sprint wrap-up, and introducing Tweet Engine</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>It's Friday evening, which means the
<a href="http://code.google.com/p/snowsprint2010/">Snow Sprint</a> is wrapping up,
and everyone's presenting their App Engine apps. There's some pretty impressive
work been done in a mere 5 days...</p>

<h3>Tweet Engine</h3>
<p>First up is us! Myself, <a href="http://bluedynamics.com/">Jens Klein</a>, and
<a href="http://valentinewebsystems.com/en/">Sasha Vincic</a> teamed up to write
<a href="http://www.tweetengine.net/">Tweet Engine</a>, a twitter webapp for collaborative tweeting. Many
organisations - both companies and open source groups - have shared twitter
accounts. Using these shared accounts, however, can be a huge pain, especially
if you have multiple accounts to manage. The goal of Tweet Engine is to make
this more manageable.</p>

<p>Anyone can sign up by logging in with their Google account. Once signed up,
you can add any number of Twitter accounts. We use the <a href="http://apiwiki.twitter.com/OAuth-FAQ">
Twitter OAuth</a> library, which allows us to obtain permission from a user without
prompting you for your password.</p>

<p>Once you've added an account, you can give any number of other people permission
to use it. Access is configurable, including full administrator access, just the
ability to send and view tweets, or just the ability to suggest tweets for review
and approval. Once a suggestion is submitted, anyone with sufficient permissions
can approve or decline it. Scheduled tweeting is also supported, for both regular
tweets and those that require approval - simply specify the date and time you
want it published at.</p>

<p>We also support XMPP: Simply add <em>account_name@tweet-engine.appspotchat.com</em>
to your XMPP list, and send tweets to it - they'll be sent immediately. Finally,
thanks to Jens' recent efforts, Tweet Engine is also internationalized, in
English and German (so far)!</p>

<p>Tweet Engine is, of course, OSS - the entire source is available on GitHub,
<a href="http://github.com/arachnid/tweetengine">here</a>. Feel free to fork,
download and deploy as you wish. If you implement something cool, don't forget
to let us know!</p>

<p>Still on the drawing board:</p>

<ul>
  <li>More documentation - about pages, help pages, and so forth.</li>
  <li>Email notifications of tweets waiting to be reviewed.</li>
  <li>A page that summarizes all the accounts you have.</li>
  <li><a href="http://github.com/arachnid/tweetengine/issues">Much much more...</a></li>
</ul>

<p>If you feel inspired, feel free to help out with these, too. Or if you just have
an idea, <a href="http://github.com/arachnid/tweetengine/issues">file a bug</a>.</p>

<h3>gaelogger</h3>
<p>Next up was <a href="http://code.google.com/p/gae-logger">gaelogger</a>, an App
Engine logging application. It has a sophisticated web-based interface, allowing
filtering and viewing of logs, but its main functionality is as a programmatic
logging service. Users can register clients, obtaining a client key, which
allows them to log events to the service. The API uses JSONRPC, and supports both
individual and batch logging, in addition to querying the logs.</p>

<p>Other users can
do live queries in a 'tail -f' fashion, or subscribe to event notifications,
receiving notifications via XMPP or email, setting filter criteria to specify
what they want to be notified of. The notification service makes use of the
Task Queue API in order to be able to send out notifications without being
bottlenecked by the limitations of the request that submitted the event.</p>

<p>XMPP isn't just for output - they also support querying the logger via XMPP,
as well as subscribing, unsubscribing, and submitting events via XMPP.</p>

<p>On the API end of things, there's already a Python logging handler, which
uses threads to asynchronously upload new log events without slowing down the
app that's using it.</p>

<p>There's a lot of similarities to <a href="http://www.gnip.com/">gnip</a> and
<a href="http://code.google.com/p/pubsubhubbub/">PubSubHubbub</a> here. I think
it would be particularly interesting to see them offering atom output and using
PubSubHubbub, especially if they consumed it as well as outputting it - it would
expand this project's scope substantially.</p>

<h3>waph</h3>

<p>Another group wrote a monitoring frontend hosted on App Engine, due to being
unhappy with <a href="http://code.google.com/p/ganeti/">ganeti</a>'s interface.
It's currently at a fairly early stage, supporting creating new graps from the
<a href="http://oss.oetiker.ch/rrdtool/">RRD</a> files provided by ganeti - the 
created graphs then update automatically on the web interface, which certainly
looks impressive. Graphs are rendered in-browser using the
<a href="https://developer.mozilla.org/en/HTML/canvas">canvas API</a>. Unfortunately,
due to the restrictions of where they could fetch ganeti information from,
they didn't end up writing any of the app on App Engine.</p>

<h3>Open Dropbox</h3>

<p><a href="http://code.google.com/p/opendropbox">Open Dropbox</a>
is a clone of Dropbox. Unlike Dropbox, Open Dropbox is decentralised,
It's still a work-in-progress, but here's what's planned: It will be possible to
share and sync folders with hundreds of other users. They build the whole project
around doctests, as they made it easier to think about requirements in a
comprehensible fashion, while specifying the requirements in the form of a test.</p>

<p>Communication between peers is handled by having each peer generate a public
key for themselves, then upload it over HTTPS to App Engine. Other peers can then
request the keys - again over a secure link with the App Engine app. Messages
between peers are secured and verified using the public keys, using
<a href="http://www.keyczar.org/">keyCzar</a>.</p></div>
    </content>
    <updated>2010-02-15T13:02:02Z</updated>
    <published>2010-01-29T21:00:35Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-15T13:02:03Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:32001</id>
    <link href="http://blog.notdot.net/2010/01/ReferenceProperty-prefetching-in-App-Engine" rel="alternate" type="text/html"/>
    <title>ReferenceProperty prefetching in App Engine</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><em>This post is a brief interlude in the <a href="http://blog.notdot.net/2010/01/Writing-your-own-webapp-framework-for-App-Engine">webapps on App Engine</a> series. Fear not, it'll be back!</em></p>

<p>Frequently, we need to do a datastore query for a set of records, then do something with a property referenced by each of those records. For example, supposing we are <a href="http://blog.notdot.net/2009/10/Writing-a-blog-system-on-App-Engine">writing a blogging system</a>, and we want to display a list of posts, along with their authors. We might do something like this:</p>

<pre class="prettyprint">class Author(db.Model):
  name = db.StringProperty(required=True)

class Post(db.Model):
  title = db.TextProperty(required=True)
  body = db.TextProperty(required=True)
  author = db.ReferenceProperty(Author, required=True)


posts = Post.all().order("-timestamp").fetch(20)
for post in posts:
  print post.title
  print post.author.name</pre>

<p>On the surface, this looks fine. If we look closer, however - perhaps by using Guido's excellent <a href="https://sites.google.com/site/appengineappstats/">AppStats</a> tool, we'll notice that each iteration of the loop, we're performing a get request for the referenced author entity. This happens the first time we dereference any ReferenceProperty, even if we've previously dereferenced a separate ReferenceProperty that points to the same entity!</p>

<p>Obviously, this is less than ideal. We're doing a lot of RPCs, and incurring a lot of per-RPC overhead and delay. Further, since we're performing them serially, they take a lot longer than a batch fetch for the equivalent number of entities would take. Is there some way we can improve on this?</p>

<p>It turns out, there is. There's a well known mechanism for retrieving the key for a ReferenceProperty without dereferencing it, by using Property.get_value_for_datastore. For example:</p>

<pre class="prettyprint">key = Post.author.get_value_for_datastore(a_post)</pre>

<p>Given a list of entities, then, we can get the keys they reference, and with those, we can fetch the referenced entities. How do we update the entities in the list with the retrieved references, though? The code for caching referenced entities is deep inside the ReferenceProperty class, and although we could monkey around with it, we really shouldn't - it's likely to break without notice.</p>

<p>There's a way around this impasse, however: We can simply set the ReferenceProperty to the value we retrieved, as if we were modifying it. This will cause the ReferenceProperty to update the value (but no change there), and to cache the entity for later dereferencing. Easy!</p>

<p>Here's the code:</p>

<pre class="prettyprint">def prefetch_refprop(entities, prop):
  ref_keys = [prop.get_value_for_datastore(x) for x in entities]
  ref_entities = dict((x.key(), x) for x in db.get(set(ref_keys)))
  for entity, ref_key in zip(entities, ref_keys):
    prop.__set__(entity, ref_entities[ref_key])
  return entities</pre>

<p>Line 2 extracts the referenced key from each entity that was passed in, storing it in a list named ref_keys. On line 3, we first convert ref_keys to a set, eliminating any duplicates, then we retrieve the referenced entities with a db.get(). Finally, we construct a dict mapping entity keys to retrieved entities with the results. Line 4 iterates through the original entities and the keys they referenced, and line 5 sets the property on each entity to the retrieved value, looking it up in the dict we just constructed. At the end, we return the original list of entities, so we can use our function as a filter, if we wish. Here's how it's used:</p>

<pre class="prettyprint">posts = Post.all().order("-timestamp").fetch(20)
prefetch_refprop(posts, Post.author)
for post in posts:
  print post.title
  print post.author.name</pre>


<p>This is looking really good - but what if we want to dereference multiple ReferenceProperty fields on the same set of entities? We could call prefetch_refprop once for each, but that's reintroducing some of the same inefficiency we wrote all this to combat. Can we do better? Naturally we can:</p>

<pre class="prettyprint">def prefetch_refprops(entities, *props):
    fields = [(entity, prop) for entity in entities for prop in props]
    ref_keys = [prop.get_value_for_datastore(x) for x, prop in fields]
    ref_entities = dict((x.key(), x) for x in db.get(set(ref_keys)))
    for (entity, prop), ref_key in zip(fields, ref_keys):
        prop.__set__(entity, ref_entities[ref_key])
    return entities</pre>

<p>This is similar to the original function, but with a couple of added wrinkles. We've converted the "prop" argument to "*props", allowing us to pass any number of ReferenceProperty instances as additional arguments. On line 2, we create the list "fields", which consists of the cartesian join of entities and properties - that is, every combination of entity and property in the input lists. Line 3 operates much the same as previously, except that both the property and the entity are fetched from the fields list. Line 4 remains completely unchanged, while line 5, the loop, now zips together the fields list and the referenced keys. Line 6 behaves as previously.</p>

<p>Using this new function is exactly the same as using the original one, except that we can now pass multiple ReferenceProperty instances, as in "prefetch_refprops(posts, Post.author, Post.category)" - and they're all fetched with a single datastore get.</p>

<p>One caveat if you intend to use this recipe: With regular dereferencing, two fields that reference the same entity will return different objects, which can be modified independently. With our recipe, though, if the keys are the same, the entities will be the same object - so modifying post1.author could modify post2.author! Bear this in mind if you intend to modify the referenced entities.</p></div>
    </content>
    <updated>2010-02-15T13:02:02Z</updated>
    <published>2010-01-27T21:28:40Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-15T13:02:03Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:31001</id>
    <link href="http://blog.notdot.net/2010/02/Webapps-on-App-Engine-part-4-Templating" rel="alternate" type="text/html"/>
    <title>Webapps on App Engine, part 4: Templating</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><em>This is part of a series on writing a webapp framework for App Engine Python. For details, see the introductory post <a href="http://blog.notdot.net/2010/01/Writing-your-own-webapp-framework-for-App-Engine">here</a>.</em></p>

<p>In the first three posts of this series, we covered all the components of a bare bones webapp framework: <a href="http://blog.notdot.net/2010/01/Webapps-on-App-Engine-part-1-Routing">routing</a>, <a href="http://blog.notdot.net/2010/01/Webapps-on-App-Engine-part-2-Request-Response-handling">request/response encoding</a>, and <a href="http://blog.notdot.net/feeds/atom.xml">request handlers</a>. Most people expect a lot more out of their web framework, however. Individual frameworks take different approaches to this, from the minimalist <a href="http://code.google.com/appengine/docs/python/tools/webapp/">webapp framework</a>, which provides the bare minimum plus some integration with other tools, to the all-inclusive <a href="http://www.djangoproject.com/">django</a>, to the 'best of breed' <a href="http://pylonshq.com/">Pylons</a>, which focuses on including and integrating the best libraries for each task, rather than writing their own.</p>

<p>For our framework, we're going to take an approach somewhere between webapp's and Pylons': While keeping our framework minimal and modular, we'll look at the best options to use for other components - specifically, templating and session handling. In this post, we'll discuss templating.</p>

<p>To anyone new to webapps, templates may seem somewhat unnecessary. We can simply generate the output direct from our code, right? Many CGI scripting languages used this approach, and the results are often messy. Sometimes, which page to be generated isn't clear until after a significant amount of processing has been done, and dealing with errors and other exceptional conditions likewise becomes problematic. Finally, this approach tends to lead to gobs of print statements cluttering up the code, making both the structure of the page and the flow of the code unclear.</p>

<p>Templating systems were designed to eliminate these issues. Instead of generating the page as we process the request, we wait until we're done, construct a dictionary of variables to pass to the template, and select and render the template we need. The templating system then takes care of interpreting the template, substituting in the variables we passed where necessary. Templating doesn't have to be complicated - here's a simple templating system:</p>

<pre class="prettyprint">def render_template(template, values):
  return template % values

# Example
template = """Hello, %(name)s! How are you this %(time_of_day)s?"""
self.response.body = render_template(template, values)</pre>

<p>This 'templating system' simply uses Python's string formatting functionality to generate its result. It quickly becomes apparrent that this isn't sufficient for templating web pages, though - we need more functionality. At a minimum, we need some form of flow control, so we can include sections of a page conditionally, such as login/logout links, and some form of looping construct, so we can include repeated sections, such as results from datastore queries. It helps if our templating system provides some features for template reuse, too, such as including other templates, or extending them.</p>

<p>How powerful should our templates be, though? This is a source of some disagreement. Some templating systems, like Django's, take a very minimalist approach, and contain only the bare minimum of functionality required to render templates. Any form of calculation - even things as simple as basic math and comparisons - should be done in code, with the results passed to the template. Other templating systems, like <a href="http://www.makotemplates.org/">Mako</a>, provide a much more full-featured templating language, and trust you not to abuse it.</p>

<p>Here's what sample templates look like in a few templating languages:</p>

<h3><a href="http://www.djangoproject.com/documentation/0.96/templates/&quot;">Django</a>:</h3>
<pre class="prettyprint">{% extends "base_generic.html" %}

{% block title %}{{ section.title }}{% endblock %}

{% block content %}
&lt;h1&gt;{{ section.title }}&lt;/h1&gt;

{% for story in story_list %}
&lt;h2&gt;
  &lt;a href="{{ story.get_absolute_url }}"&gt;
    {{ story.headline|upper }}
  &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;{{ story.tease|truncatewords:"100" }}&lt;/p&gt;
{% endfor %}
{% endblock %}</pre>

<p>You're probably already familiar with Django's template syntax from previous posts. Because it's included with App Engine, it's often the easy default. As we've already mentioned, it's very restrictive about what you can do: It provides a few primitives, and relies on an extensible library of tags and filters (the bits after the | in {{...}}) to make it useful.</p>

<h3><a href="http://www.makotemplates.org/">Mako</a>:</h3>

<pre class="prettyprint">&lt;%inherit file="base.html"/&gt;
&lt;%
    rows = [[v for v in range(0,10)] for row in range(0,10)]
%&gt;
&lt;table&gt;
    % for row in rows:
        ${makerow(row)}
    % endfor
&lt;/table&gt;
   
&lt;%def name="makerow(row)"&gt;
    &lt;tr&gt;
    % for name in row:
        &lt;td&gt;${name}&lt;/td&gt;\
    % endfor
    &lt;/tr&gt;
&lt;/%def&gt;</pre>

<p>Mako is another popular templating engine, and takes the opposite approach to Django: Templates are created by inserting actual Python code, inside special processing directives of the form &lt;% .. %&gt;. It even goes so far as to permit and encourage defining functions inside templates! Mako works around Python's use of indentation for control flow by defining new keywords such as 'endfor'.</p>

<h3><a href="http://www.cheetahtemplate.org/">Cheetah</a></h3>

<pre class="prettyprint">&lt;html&gt;
  &lt;head&gt;&lt;title&gt;$title&lt;/title&gt;&lt;/head&gt;
  &lt;body&gt;
    &lt;table&gt;
      #for $client in $clients
      &lt;tr&gt;
        &lt;td&gt;$client.surname, $client.firstname&lt;/td&gt;
        &lt;td&gt;&lt;a href="mailto:$client.email"&gt;$client.email&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;
      #end for
    &lt;/table&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre>

<p>Cheetah is another templating system that takes the "we provide the gun, you point it at your foot" approach. It's similar to Mako in many ways, but doesn't require variable substitutions to be embedded in curly braces, and instead of using processing directives, it treats lines starting with a # as Python code. It also uses special directives such as 'end for' for nesting.</p>

<h3><a href="http://jinja.pocoo.org/2/">Jinja2</a></h3>

<pre class="prettyprint">&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"&gt;
&lt;html lang="en"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;head&gt;
    {% block head %}
    &lt;link rel="stylesheet" href="style.css" /&gt;
    &lt;title&gt;{% block title %}{% endblock %} - My Webpage&lt;/title&gt;
    {% endblock %}
&lt;/head&gt;
&lt;body&gt;
    &lt;div id="content"&gt;{% block content %}{% endblock %}&lt;/div&gt;
    &lt;div id="footer"&gt;
        {% block footer %}
        © Copyright 2008 by &lt;a href="http://domain.invalid/"&gt;you&lt;/a&gt;.
        {% endblock %}
    &lt;/div&gt;
&lt;/body&gt;</pre>

<p>Jinja2 claims to have "Django-like syntax (but faster)". Notably, the syntactic elements for loops, control flow, etc, are a lot more Python-like, but they're still limited to what the language supports, and it still relies on specially defined tests, filters, etc.</p>

<h3><a href="http://www.kuwata-lab.com/tenjin/">Tenjin</a></h3>

<pre class="prettyprint">&lt;html&gt;
  &lt;body&gt;
    &lt;h1&gt;${title}&lt;/h1&gt;
    &lt;table&gt;
&lt;?py i = 0 ?&gt;
&lt;?py for item in items: ?&gt;
&lt;?py     i += 1 ?&gt;
&lt;?py     color = i % 2 == 0 and '#FFCCCC' or '#CCCCFF' ?&gt;
      &lt;tr bgcolor="#{color}"&gt;
        &lt;td&gt;#{i}&lt;/td&gt;
        &lt;td&gt;${item}&lt;/td&gt;
      &lt;/tr&gt;
&lt;?py #endfor ?&gt;
    &lt;/table&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre>

<p>Tenjin claims to be the fastest Python templating framework - and it has benchmarks (although not exhaustive ones) to back it up. It takes the general approach, with Python expressions and statements embedded directly into the markup. Notably, indentation of the Python statements maters, producing a somewhat confused mix of markup and Python code.</p>

<h3><a href="http://chameleon.repoze.org/">Chameleon</a></h3>

<pre class="prettyprint">&lt;table border="1"&gt;
  &lt;tr tal:repeat="row range(10)"&gt;
    &lt;td tal:repeat="column range(10)"&gt;
      &lt;span tal:define="x repeat.row.number;
                        y repeat.column.number;
                        z x * y"
            tal:replace="string:$x * $y = $z"&gt;1 * 1 = 1&lt;/span&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;</pre>

<p>Chameleon is based on the <a href="http://chameleon.repoze.org/docs/latest/zpt.html">Zope Page Templates</a> specification, which takes an interesting approach. Chameleon templates are valid XML documents, unlike many templating engines, and it uses namespaces for attributes and tags to define the template behaviour. For example, the "tal:repeat" tag indicates that the tag it's on and all its children should be repeated for each value in the Python iterator passed as an argument. tal:replace replaces an element with the value of the expression, while other expressions permit setting attributes and replacing body content, and a 'meta' namespace handles operations such as including other templates.</p>

<p>Chameleon <a href="http://chameleon.repoze.org/docs/latest/zpt.html#extensions">extends</a> the Zope standard in several ways: expressions can be arbitrary Python expressions, and values can be substituted using a ${...} syntax in addition to the XML syntax, which avoids a lot of boilerplate in some situations. Chameleon templates are compiled to Python code on first use - so you're not doing XML DOM manipulation on every template generation. Chameleon recently got App Engine support when the author refactored out some code that relied on modules not available in App Engine.</p>

<p>I haven't mentioned all Python's templating systems here, by a long shot - this is merely a representative sample. For a more complete list, see <a href="http://wiki.python.org/moin/Templating">this page</a>.</p>

<h3>Our framework</h3>

<p>Examining the different templating engines leads to an interesting observation: Those templating engines that take the Django approach of "only what's necessary" tend to, of necessity, be a lot larger and more involved - and hence have a steeper learning curve - than those that allow you to leverage your Python knowledge in some fashion. For that reason and others, I'm not a big fan of them - I'd rather provide someone with a powerful but lightweight system, and trust them not to shoot themselves in the foot, than use a more complicated system designed to make foot-shooting an impossibility. With that consideration and others in mind, we'll look at what is required to use Chameleon in our framework.</p>

<h3>Using Chameleon</h3>

<p>Installation is straightforward: Download the tarball from <a href="http://pypi.python.org/pypi/Chameleon/1.1.1">the PyPi page</a>, and copy the Chameleon-1.1.1/src/chameleon directory into a directory on the system path (eg, your app's root folder).</p>

<p>To use Chameleon, we first define a template loader:</p>

<pre class="prettyprint">from chameleon.zpt import loader

template_path = os.path.join(os.path.dirname(__file__), "..", "templates")
template_loader = loader.TemplateLoader(template_path, auto_reload=os.environ['SERVER_SOFTWARE'].startswith('Dev'))</pre>

<p>Template loaders serve to cache loaded and compiled templates, which is essential for performance. As such, it makes sense to define our loader once at module level, and use it for all requests. To render a template, we fetch a template from the loader, then call it with keyword arguments corresponding to the parameters we want to pass to the template:</p>

<pre class="prettyprint">def TestHandler(RequestHandler):
  def get(self):
    template = template_loader.load("test.pt")
    self.response.body = template(name="test")</pre>

<p>In terms of integrating templates into our framework, there's not a great deal we can do without locking users of our framework into using our preferred templating system. You can bundle the templating system with the framework, and even make it create a loader when it's first used. The approach you take depends on where you want to be on the flexibility / ease-of-use axis.</p>

<p><em>In the next post, we'll discuss session handling, the options available on App Engine, and how to integrate it into our framework.</em></p></div>
    </content>
    <updated>2010-02-15T13:02:02Z</updated>
    <published>2010-02-01T17:34:04Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-15T13:02:03Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:30003</id>
    <link href="http://blog.notdot.net/2010/01/Webapps-on-App-Engine-part-3-Request-handlers" rel="alternate" type="text/html"/>
    <title>Webapps on App Engine part 3: Request handlers</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><em>This is part of a series on writing a webapp framework for App Engine Python. For details, see the introductory post <a href="http://blog.notdot.net/2010/01/Writing-your-own-webapp-framework-for-App-Engine">here</a>.</em></p>

<p>Now that we've covered the background on <a href="http://blog.notdot.net/feeds/atom.xml">request handling</a>, it's time to tackle request handlers. Request handlers are the core and most obvious part of a web framework. They serve to simplify the writing of your app, and remove some of the boilerplate that you end up with if you write raw WSGI applications. Before we go any further, let's see what basic request handlers look like in a range of frameworks. Then we can discuss the pros and cons of each, and settle on one for ours.</p>

<p><a href="http://docs.djangoproject.com/en/1.1/topics/http/views/#topics-http-views">Django</a>:</p>
<pre class="prettyprint">def current_datetime(request):
    now = datetime.datetime.now()
    html = "&lt;html&gt;&lt;body&gt;It is now %s.&lt;/body&gt;&lt;/html&gt;" % now
    return HttpResponse(html)</pre>

<p>App Engine's <a href="http://code.google.com/appengine/docs/python/gettingstarted/usingwebapp.html">webapp</a> framework:</p>
<pre class="prettyprint">class MainPage(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.out.write('Hello, webapp World!')</pre>

<p><a href="http://werkzeug.pocoo.org/documentation/dev/tutorial.html#part-4-the-view-functions">Werkzeug</a>:</p>
<pre class="prettyprint">@expose('/display/&lt;uid&gt;')
def display(request, uid):
    url = URL.query.get(uid)
    if not url:
        raise NotFound()
    return render_template('display.html', url=url)</pre>

<p><a href="http://www.web2py.com/examples/default/examples">web2py</a>:</p>
<pre class="prettyprint">def hello1():
    return "Hello World"</pre>

<p><a href="http://pylonshq.com/docs/en/0.9.7/gettingstarted/#creating-a-pylons-project">Pylons</a>:</p>
<pre class="prettyprint">class HelloController(BaseController):

    def index(self):
        # Return a rendered template
        #return render('/hello.mako')
        # or, Return a response
        return 'Hello World'</pre>

<p>You've probably noticed that the handlers here fall into two broad categories: Function based handlers, and class based handlers. Frameworks like Django, Werkzeug and web2py take a function-based approach, where each handler is a function. Frequently, such functions are expected to return the response. This matches up fairly closely with the WSGI approach, though frameworks generally add a lot of extra features and syntactic sugar.</p>

<p>Other frameworks, like Pylons and the webapp framework, use class based handlers: each handler is a class, subclassing a base request handler. Requests are handled by instantiating the class, then calling a handler method. In the case of Pylons, multiple different URL patterns may route to the same handler class, resulting in different handler methods being called, while in the case of the webapp framework, the method that gets called is determined entirely by the HTTP method of the request.</p>

<p>For various reasons, we're going to take the class-based approach in our framework. Whilst the function-based approach definitely has its merits, there are several benefits to using a class-based approach in our framework:</p>

<ul>
  <li>Easier to understand. Everyone understands inheritance; not as many people understand the magic behind some of the function-based frameworks.</li>
  <li>Our handler classes can also be valid WSGI apps.</li>
  <li>It's easier for users of our framework to extend the handler's functionality for their own use.</li>
</ul>

<p>As far as request routing and dispatching goes, we're going to take the same approach as the webapp framework: The method we call on our handler object depends entirely on the HTTP method of the request. We'll also take the opportunity to make use of WebOb's more advanced features, as we discussed yesterday.</p>

<p>Let's start with the basic functionality we need for our handler to work at all:</p>

<pre class="prettyprint">import webob
import webob.exc

class RequestHandler(object):
  ALLOWED_METHODS = set(['get', 'post', 'put', 'head', 'delete'])

  def __call__(self, environ, start_response):
    self.request = webob.Request(environ)
    self.response = webob.Response(request=self.request, conditional_response=True)
    try:
      self.handle()
      return self.response(environ, start_response)
    except webob.exc.WSGIHTTPException, ex:
      return ex(environ, start_response)
    except Exception, ex:
      return self.handle_exception(ex)</pre>

<p>First, we define a set of allowed HTTP methods. We'll use those shortly. Then, we define the special method __call__, which as we previously discussed, is executed when something attempts to call instances of our class as functions. We take the standard WSGI application arguments, and immediately construct WebOb request and response objects, making sure to set up the response object so it supports conditional responses.</p>

<p>Then, we call the yet-to-be-defined method handle(), which will take care of dispatching the request to the appropriate user defined method. Apart from making the code cleaner, this also allows subclasses to override how requests are dispatched to methods, if they wish, or to add code that is executed regardless of the HTTP method. If handle() returns successfully, we return the response to the user by treating the WebOb response object as a WSGI application.</p>

<p>If the handle() method throws one of WSGI's status code exceptions, we catch that and call it to generate the WSGI response. If some other exception occurs, we catch that and call the handle_exception method, which is expected to do generic error handling for uncaught exceptions.</p>

<p>The handle() method is fairly straightforward, as it only needs to take care of dispatching requests to the appropriate method. Let's take a look:</p>

<pre class="prettyprint">  def handle(self):
    method_name = self.request.method.lower()
    method = getattr(self, method_name, None)
    kwargs = self.request.environ.get('router.args', {})
    if method_name not in self.ALLOWED_METHODS or not method:
      raise webob.exc.HTTPMethodNotAllowed()
    method(**kwargs)</pre>

<p>First, we fetch and normalize the name of the HTTP method. We also extract the keyword arguments that were extracted by the router code back in the first post of the series. Then, we compare it against the list of allowed methods. If it doesn't match, or the method itself isn't found, we simply raise an HTTPMethodNotAllowed exception, which the exception handling code in __call__ takes care of for us. Finally, we call the method in question, passing the router arguments as keyword arguments.</p>

<p>The default implementation of handle_exception() is also fairly straightforward:</p>

<pre class="prettyprint">  def handle_exception(self, ex):
    logging.exception("Unhandled exception")
    lines = ''.join(traceback.format_exception(*sys.exc_info()))
    return webob.exc.HTTPInternalServerError(detail='%s' % lines)</pre>

<p>All we do here is obtain a nicely formatted version of the exception, log it, and print it out. In a real, production-quality framework, you'd definitely want to make sure that in 'production mode', you don't show stacktraces to the users!</p>

<p>Finally, there's one more enhancement we can make to our basic framework to avoid a gotcha that the webapp framework and some other frameworks suffer from: Lack of support for the HEAD method. In webapp, and in our framework so far, if a browser makes a HEAD request, and the user hasn't explicitly implemented it, an HTTP 405 "Method not allowed" response is returned! This has practical implications - some sites such as <a href="http://digg.com/">digg</a> do HEAD requests to check for the existence of a page, so failing to handle it can make it impossible to submit your site to services like digg.</p>

<p>Fortunately, this is easily worked around: All we have to do is provide a default implementation of head() that executes get(), then erases the content of the response. It's not the most efficient, but it is effective:</p>

<pre class="prettyprint">  def head(self, **kwargs):
    method = getattr(self, 'get', None)
    if not method:
      raise webob.exc.HTTPMethodNotAllowed()
    method(**kwargs)
    self.response.body = ''</pre>

<p>The only complication here is that we can't rely on get() being defined in every handler subclass, so we have to use getattr to retrieve it, and throw a regular 405 error if it doesn't exist. Otherwise, we're simply executing get(), then erasing the body of the response before returning.</p>

<p>Let's use our new framework to write a couple of sample handlers:</p>

<pre class="prettyprint">class HelloHandler(RequestHandler):
  def get(self, name='world'):
    self.response.content_type = 'text/plain'
    self.response.body = 'Hello, %s.' % (name,)

class EchoHandler(RequestHandler):
  def get(self, **kwargs):
    self.response.content_type = 'text/plain'
    self.response.body = repr(kwargs)

router = WSGIRouter()
router.connect("/hello", HelloHandler())
router.connect("/hello/{name}", HelloHandler())
router.connect("/echo/{foo}/{bar:[0-9]+}", EchoHandler(), test="test")</pre>

<p>Things are starting to look a little more familiar, right? No more boilerplate, no raw WSGI environments, just familiar and convenient handler classes, request and response objects.</p>

<p>At this point, we've written everything required of a bare-bones webapp framework. Most people expect more to be bundled with their framework, however, and in the next few posts we'll deal with that, starting with the next post, where we'll discuss templating.</p></div>
    </content>
    <updated>2010-02-15T13:02:02Z</updated>
    <published>2010-01-25T19:15:18Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-15T13:02:03Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:30002</id>
    <link href="http://blog.notdot.net/2010/01/Webapps-on-App-Engine-part-2-Request-Response-handling" rel="alternate" type="text/html"/>
    <title>Webapps on App Engine part 2: Request &amp; Response handling</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><em>This is part of a series on writing a webapp framework for App Engine Python. For details, see the introductory post <a href="http://blog.notdot.net/2010/01/Writing-your-own-webapp-framework-for-App-Engine">here</a>.</em></p>

<p><em>This post is mostly background on request and response encoding/decoding. If you're already fairly familiar with how this works in CGI and in higher level frameworks, you may want to skip this and wait for the next posting, on request handlers.</em></p>

<p>If you've ever written a CGI script, you'll be well aware of how much of a pain interpreting and decoding CGI environment variables and headers can be - so much so that the first action of many is to find or write a library to handle it for you! And if you've ever coded in a CGI-inspired language such as PHP, you're probably familiar with how much of a pain managing the combination of response headers and output content can likewise be.</p>

<p>As a result of this, one of the most basic tools a framework offers is some form of abstraction for request and response data. Typically, this takes care of collecting and parsing HTTP headers, parsing the query string (if any), decoding POSTed form data, and so forth. Better frameworks also take care of common header-related tasks, like interpreting cookies and headers that should affect the nature of the response.</p>

<p>Very nearly every framework defines its own request and response abstraction. <a href="http://docs.djangoproject.com/en/1.1/ref/request-response/#ref-request-response">Django</a> and <a href="http://werkzeug.pocoo.org/documentation/dev/wrappers.html">Werkzeug</a> both define their own, for example, while the authors of the Paste framework recognized this trend towards repetition, and created <a href="http://pythonpaste.org/webob/">WebOb</a>, a standalone library that incorporates just the request and response objects from the Paste framework.</p>

<p>Due to the constraints, different frameworks' takes on request and response objects tend to be very similar - there's often not much to choose between them. For the same reason, it's also the case that writing our own request handling would be tedious, and not particularly enlightening. With that in mind, we'll go ahead and use the WebOb library, for these reasons:</p>

<ul>
  <li>It fulfills all our requirements admirably</li>
  <li>It's available as a separate library</li>
  <li>It's already bundled with the App Engine SDK!</li>
  <li>It has several advanced features we can make use of to improve our framework overall</li>
</ul>

<p>Without further ado, let's take a look at the basic workings of WebOb. Unsurprisingly, there are two major classes we need to concern ourselves with: <a href="http://pythonpaste.org/webob/reference.html#id1">Request</a>, and <a href="http://pythonpaste.org/webob/reference.html#id2">Response</a>. Let's examine them in order.</p>

<p>The Request object is fairly straightforward: To construct one, you must pass in a WSGI environment dictionary. The resulting Request object then exposes everything you would generally expect to have available: Information about the URL and the request method, headers, query and form data, and so forth. It also provides access to the raw body of the request (if any), and interprets cookies for you. Finally, it breaks common headers out into their own properties, including the 'accept' headers and those dealing with conditional requests and caching.</p>

<p>The response object is a little more surprising. In addition to all the usual functionality, such as allowing you to set headers and fill out the response body, the Response object is itself a fully-formed WSGI application. Apart from providing an easy way to actually send the response back to the client, this also provides additional functionality: The Webob response object automatically takes care of handling HTTP conditional requests for you - instantly providing your app with a bunch of features that many interactive apps don't support without much manual involvement, or at all.</p>

<p>Let's see a practical example of how to use the WebOb Request and Response objects in a WSGI application:</p>

<pre class="prettyprint">def application(environ, start_response):
  request = webob.Request(environ)
  response = webob.Response(request=request, conditional_response=True)
  response.content_type = 'text/plain'
  out = response.body_file
  out.write("Hello, %s!" % (request.GET.get('name', 'world'),))
  return response(environ, start_response)</pre>

<p>As you can see, this is starting to look a little saner, and more like what you're used to if you regularly use frameworks. There's still a bit of boilerplate here, but we'll be taking care of that when we discuss request and response handlers in the next post.</p>

<p>One final feature of the WebOb library that we'll be making use of is its set of <a href="http://pythonpaste.org/webob/reference.html#exceptions">status code exceptions</a>. This comprises a comprehensive set of classes for all the HTTP response codes. These classes are WSGI applications, so they can be used as a WSGI application, and they are also valid Python exception classes, so they can be thrown. This is particularly useful because it allows you to 'throw' an error status code in an intuitive fashion - for example:</p>

<pre class="prettyprint">  def some_handler(request):
    if not request.is_authorized:
      raise exc.HTTPForbidden()
    # Otherwise, do stuff...</pre>

<p>You're not limited to using 400 and 500 status codes in this fashion. Somewhat less intuitive, but often useful, is the ability to throw a redirect:</p>

<pre class="prettyprint">  def some_handler(request):
    if not request.logged_in:
      raise exc.HTTPFound(location='/login')
    # Otherwise, user is logged in...</pre>

<p>We'll be making use of these when we start to deal with request handling, in the next post.</p>

<p><b>Update:</b> Added a few paragraphs about WebOb's status code exceptions.</p>

<p>I'm away at the <a href="http://code.google.com/p/snowsprint2010/">Lovely Snow Sprint</a> all next week. Posts in the series will continue as normal, but may be displaced by updates from the sprint if anything particularly fascinating happens. ;)</p></div>
    </content>
    <updated>2010-02-15T13:02:02Z</updated>
    <published>2010-01-22T14:30:45Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-15T13:02:03Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-2350108441289570086</id>
    <link href="http://reneefrench.blogspot.com/feeds/2350108441289570086/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=2350108441289570086" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2350108441289570086" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2350108441289570086" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/mission-pile.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://4.bp.blogspot.com/_va9O40qIhaE/S21eQNgEdbI/AAAAAAAACTw/_aPN4R0EdGA/s1600-h/hdaymovbed15sm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5435103957901145522" src="http://4.bp.blogspot.com/_va9O40qIhaE/S21eQNgEdbI/AAAAAAAACTw/_aPN4R0EdGA/s320/hdaymovbed15sm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 320px; height: 266px;"/></a>mission pile<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-2350108441289570086?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-15T12:18:00Z</updated>
    <published>2010-02-15T12:18:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="line drawings"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="story z"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-11T07:53:56Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-2396317128089383622</id>
    <link href="http://reneefrench.blogspot.com/feeds/2396317128089383622/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=2396317128089383622" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2396317128089383622" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2396317128089383622" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/walsh.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://2.bp.blogspot.com/_va9O40qIhaE/S21dcJrCz6I/AAAAAAAACTo/_pw84Cx3jas/s1600-h/hdaymovbed24sm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5435103063520235426" src="http://2.bp.blogspot.com/_va9O40qIhaE/S21dcJrCz6I/AAAAAAAACTo/_pw84Cx3jas/s320/hdaymovbed24sm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 320px; height: 235px;"/></a>walsh<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-2396317128089383622?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-14T12:15:00Z</updated>
    <published>2010-02-14T12:15:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="line drawings"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="story z"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-10T03:54:15Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-4159071858512982896</id>
    <link href="http://reneefrench.blogspot.com/feeds/4159071858512982896/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=4159071858512982896" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/4159071858512982896" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/4159071858512982896" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/hobart.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://3.bp.blogspot.com/_va9O40qIhaE/S21dNIynQUI/AAAAAAAACTg/uVjtO4K5PR4/s1600-h/hdaymov25sm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5435102805585510722" src="http://3.bp.blogspot.com/_va9O40qIhaE/S21dNIynQUI/AAAAAAAACTg/uVjtO4K5PR4/s320/hdaymov25sm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 200px; height: 320px;"/></a>hobart<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-4159071858512982896?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-13T12:12:00Z</updated>
    <published>2010-02-13T12:12:00Z</published>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-10T03:54:15Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://www.airs.com/blog/?p=321</id>
    <link href="http://www.airs.com/blog/archives/321" rel="alternate" type="text/html"/>
    <title>Thread Sanitizer</title>
    <summary>I recently ran the gold linker under Thread Sanitizer.  It’s a nice plugin for Valgrind which looks for race conditions in multi-threaded programs.  To describe it briefly, it builds Happens-Before relationships based on mutex operations and warns when it notices a write and a read/write to the same memory location without a Happens-Before [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I recently ran the gold linker under <a href="http://code.google.com/p/data-race-test/wiki/ThreadSanitizer">Thread Sanitizer</a>.  It’s a nice plugin for Valgrind which looks for race conditions in multi-threaded programs.  To describe it briefly, it builds Happens-Before relationships based on mutex operations and warns when it notices a write and a read/write to the same memory location without a Happens-Before relationship.  This approach can yield false positives to be sure, but it does a very nice job of identifying real problems.</p>
<p>It was able to identify one real bug in gold, one problem that led to less efficient link time, and several cases where several threads would set a shared memory location to the same value.  The latter cases are not a problem on x86 architectures, though they could be on other processors.  In order to get clean Thread Sanitizer results in the future, I fixed all of the cases so that I could get a clean run of gold, at least with the default settings.</p>
<p>The real bug that it found was a typical multi-threaded bug: the code looked fine, but it had a well-hidden error.  Gold uses a workqueue of tasks to execute, with a pool of worker threads.  Many of the tasks are run using a blocker token.  The blocker token is set to the number of tasks that precede it.  As each task completes, it decrements the blocker count.  When the count goes to zero, the next set of tasks can start.  This is a simple way to parallelize linker operations, in which one set of operations (e.g., process the symbol tables) must be run before the next set (e.g., process the relocations) can begin.  Naturally I paid close attention to the blocker behaviour when a task completed, and there were no problems there.  The problem arose in setting the blocker count when the tasks started.  The code was doing a loop of “increment the blocker count” and then “queue the task.”  What I forgot was that the process of queuing the task actually lets another thread in the pool start working on it immediately.  When the task completed, it decremented the blocker count with a lock.  But if the task completed fast enough, the initial code was still running the loop queuing up new tasks, and thus incrementing the blocker count.  I didn’t think that I needed to lock the increment, since I wasn’t expecting any task to actually complete before I started all of the tasks.  A dumb mistake—just the kind of mistake one makes in multi-threaded programming.</p>
<p>Gold is written in C++.  In Go I would of course have each task communicate its completion on a channel.  The locking would be handled by the runtime, and there would be no chance for me to make the same sort of error.  If you write multi-threaded code, and you can’t use Go, you should definitely check out Thread Sanitizer.</p></div>
    </content>
    <updated>2010-02-13T02:36:51Z</updated>
    <category term="Programming"/>
    <author>
      <name>Ian Lance Taylor</name>
    </author>
    <source>
      <id>http://www.airs.com/blog</id>
      <link href="http://www.airs.com/blog/feed" rel="self" type="application/atom+xml"/>
      <link href="http://www.airs.com/blog" rel="alternate" type="text/html"/>
      <subtitle>Ian Lance Taylor</subtitle>
      <title>Airs - Ian Lance Taylor</title>
      <updated>2010-03-09T08:00:16Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-3303907924347033832.post-9013231031306761767</id>
    <link href="http://feedproxy.google.com/~r/goplexian/~3/AMqYBfn9yBg/cost-of-ubuntus-success.html" rel="alternate" type="text/html"/>
    <title>The cost of Ubuntu's Success</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">My father has a saying that "success is like a meat grinder, lots of different meat goes in, but it all comes out looking and tasting the same". Its a pretty jaded view, but time they say is the greatest teacher and hes almost as old as dirt now so who knows maybe he's got something.<br/>
<br/>
There is no doubt Ubuntu is the most successful Linux desktop on the market today, and while technically they aren't actually on the market I wouldn't be surprised if that was their next step, after all Redhat which is on the market has been doing quite well and is by far the leading Linux distribution when it comes to servers and enterprise.<br/>
<br/>
Yet Ubuntu's success, like all success, has come at a cost and just like a choice cut of meat thrown into the grinder it seems they have mixed themselves with their competitors to a degree that it is becoming more and more difficult to tell them apart.<br/>
<br/>
Some of you who read this might think I'm being a little over the top, but lets look at a few things.<br/>
<br/>
Did you know that <a href="http://www.microsoft.com/opensource/">Microsoft makes and contributes</a> to open source software, and <a href="http://www.opensource.apple.com/">so does Apple</a>? Guess what, Ubuntu now makes a closed source product called Ubuntu-One, and they've even said they are working on a Windows version. Ubuntu still far out weighs their proprietary competitors when it comes to open-source, but it is a lot less true today that it was a few years ago, things are changing and the differences are beginning to blur.<br/>
<br/>
You may have heard that Ubuntu decided to switch their default browser search tool from Google over to Yahoo after Yahoo offered to cut them a check, but what you may not have realized is that Yahoo uses Microsoft Bing as their back-end search tool.<br/>
<br/>
I never thought I'd see the day when a Linux distribution would be serving Microsoft search results by default, even though it is through the thinly veiled disguise of Yahoo.<br/>
<br/>
Does Ubuntu not know that Microsoft is their competitor and would like nothing better than to destroy them?<br/>
<br/>
Does Ubuntu not know that Microsoft search has been shown to favor itself over its competitors?<br/>
<br/>
Did they forget that Google is Linux powered?<br/>
<br/>
Just because advertising for your competitor makes you some money in the short term doesn't make it a smart business move in the long run.<br/>
<br/>
I really wish I knew what was happening over at Canonical, and while these compromises in themselves aren't earth shattering they do raise questions about whats coming next, and it seems that <a href="http://madhatter.ca/?p=241">I'm not</a> the <a href="http://openbytes.wordpress.com/2010/01/29/ubuntu-one-for-windows-microsoft-cash/">only one</a> raising <a href="http://www.theopensourcerer.com/2010/02/09/is-canonical-becoming-the-new-microsoft/">doubts</a> regarding Ubuntu's future, and if as I speculate a public offering may be in their future will they have the strength to remain true to their ideals and obligations to the community at that time given that already they seem to be making compromises.<div class="blogger-post-footer">&lt;script charset="utf-8" expr:src=""http://feeds.feedburner.com/~s/goplexian?i=" + data:post.url" type="text/javascript"&gt;&lt;/script&gt;<img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/3303907924347033832-9013231031306761767?l=www.goplexian.com" width="1"/></div><img height="1" src="http://feeds.feedburner.com/~r/goplexian/~4/AMqYBfn9yBg" width="1"/></div>
    </summary>
    <updated>2010-02-13T00:06:00Z</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="Open Source"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Apple"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Microsoft"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Ubuntu"/><feedburner:origLink xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://www.goplexian.com/2010/02/cost-of-ubuntus-success.html</feedburner:origLink>
    <author>
      <name>Alex Combas</name>
      <email>alex.combas@gmail.com</email>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-3303907924347033832</id>
      <author>
        <name>Alex Combas</name>
        <email>alex.combas@gmail.com</email>
      </author>
      <link href="http://www.goplexian.com/" rel="alternate" type="text/html"/>
      <link href="http://feeds.feedburner.com/goplexian" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <subtitle>open-source, programming, and indie games</subtitle>
      <title>One billion extensible bits</title>
      <updated>2010-02-26T15:00:07Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-3303907924347033832.post-4278265949320008610</id>
    <link href="http://feedproxy.google.com/~r/goplexian/~3/f-P0TmdeRcg/why-nobody-talks-about-lua-one-billion.html" rel="alternate" type="text/html"/>
    <title>Why nobody talks about Lua | One billion extensible bits</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><div><a href="http://tc50tweets.techcrunch.com/story/563407831/why-nobody-talks-about-lua-one-billion-extensible-bits">TechCrunch 50 News</a></div><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/3303907924347033832-4278265949320008610?l=www.goplexian.com" width="1"/></div>
<p><a href="http://feedads.g.doubleclick.net/~a/L6wb964L688CjowGnfxVI5VO4UQ/0/da"><img border="0" ismap="true" src="http://feedads.g.doubleclick.net/~a/L6wb964L688CjowGnfxVI5VO4UQ/0/di"/></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/L6wb964L688CjowGnfxVI5VO4UQ/1/da"><img border="0" ismap="true" src="http://feedads.g.doubleclick.net/~a/L6wb964L688CjowGnfxVI5VO4UQ/1/di"/></a></p><img height="1" src="http://feeds.feedburner.com/~r/goplexian/~4/f-P0TmdeRcg" width="1"/></div>
    </summary>
    <updated>2010-02-12T21:40:00Z</updated><feedburner:origLink xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://www.goplexian.com/2010/02/why-nobody-talks-about-lua-one-billion.html</feedburner:origLink>
    <author>
      <name>Alex Combas</name>
      <email>noreply@blogger.com</email>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-3303907924347033832</id>
      <author>
        <name>Alex Combas</name>
        <email>noreply@blogger.com</email>
      </author>
      <link href="http://www.goplexian.com/" rel="alternate" type="text/html"/>
      <link href="http://feeds.feedburner.com/goplexian" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com" rel="hub" type="text/html"/>
      <subtitle>Random stuff about open-source, programming, and indie games.</subtitle>
      <title>One billion extensible bits</title>
      <updated>2010-02-12T22:00:07Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:36001</id>
    <link href="http://blog.notdot.net/2010/02/No-post-today" rel="alternate" type="text/html"/>
    <title>No post today</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Sorry, but I'm totally mentally exhausted after a long week - including a <a href="http://www.csi.ucd.ie/content/etc">talk at UCD</a> on Wednesday - and I just don't have the energy to write up today's post. Look out for it on Monday, instead.</p></div>
    </content>
    <updated>2010-02-12T16:59:39Z</updated>
    <published>2010-02-12T16:59:39Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-12T16:59:39Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-2062573939698904538</id>
    <link href="http://reneefrench.blogspot.com/feeds/2062573939698904538/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=2062573939698904538" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2062573939698904538" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2062573939698904538" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/charlotte.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://3.bp.blogspot.com/_va9O40qIhaE/S21ceTfGDvI/AAAAAAAACTY/i9G8NxhVa7Q/s1600-h/charlotte.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5435102001002581746" src="http://3.bp.blogspot.com/_va9O40qIhaE/S21ceTfGDvI/AAAAAAAACTY/i9G8NxhVa7Q/s320/charlotte.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 260px; height: 320px;"/></a>charlotte<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-2062573939698904538?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-12T12:06:00Z</updated>
    <published>2010-02-12T12:06:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="notes"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-09T18:16:58Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-3303907924347033832.post-6992682189707952440</id>
    <link href="http://feedproxy.google.com/~r/goplexian/~3/N6TAsuekdC8/flattr-not-just-another-hand-in-your.html" rel="alternate" type="text/html"/>
    <title>Flattr, not just another hand in your pocket</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">A founder of the now infamous "The Pirate Bay" has started a new project which is aimed at changing the way content providers are paid called <a href="http://flattr.com/beta/">flattr</a>. While another hand in my pocket doesn't exactly thrill me, once I got all the details on this project it turns out this is something I would definitely use.<br/>
<br/>
In a nutshell you put money into an account and that money gets distributed evenly on a monthly basis to however many projects or developers you wish to give it to. So you put in $10 a month, and you sign up to contribute to 40 projects, and at the end of the month each of those projects would get a 25 cent slice of the cake.<br/>
<br/>
While nobody is going to get rich off my tiny contribution of 25 cents a month I'm sure there are some popular projects out there which will be flattred by thousands or even 10's of thousands of loyal and thankful customers, which when combined with other means of income from the project such as advertising and services, may actually add up to enough to make a decent living from, and I have a feeling that flattr will end up itself being one of them.<br/>
<br/>
This is definitely good news for open source content providers, I hope the system catches on.<div class="blogger-post-footer">&lt;script charset="utf-8" expr:src=""http://feeds.feedburner.com/~s/goplexian?i=" + data:post.url" type="text/javascript"&gt;&lt;/script&gt;<img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/3303907924347033832-6992682189707952440?l=www.goplexian.com" width="1"/></div><img height="1" src="http://feeds.feedburner.com/~r/goplexian/~4/N6TAsuekdC8" width="1"/></div>
    </summary>
    <updated>2010-02-11T21:37:00Z</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="flattr"/><feedburner:origLink xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://www.goplexian.com/2010/02/flattr-not-just-another-hand-in-your.html</feedburner:origLink>
    <author>
      <name>Alex Combas</name>
      <email>alex.combas@gmail.com</email>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-3303907924347033832</id>
      <author>
        <name>Alex Combas</name>
        <email>alex.combas@gmail.com</email>
      </author>
      <link href="http://www.goplexian.com/" rel="alternate" type="text/html"/>
      <link href="http://feeds.feedburner.com/goplexian" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <subtitle>open-source, programming, and indie games</subtitle>
      <title>One billion extensible bits</title>
      <updated>2010-02-26T15:00:07Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-3303907924347033832.post-6724449614732993328</id>
    <link href="http://feedproxy.google.com/~r/goplexian/~3/LzcmyUmf5GU/why-nobody-talks-about-lua.html" rel="alternate" type="text/html"/>
    <title>Why nobody talks about Lua</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Like many web savvy folk, I've known about Lua for a long time, I'm sure you've heard of it as well.<br/>
<br/>
But is it just me, or does it seem like Lua never generates any buzz in the media? In the major tech news aggregators (at least the ones that I typically check) its always Javascript this, or Ruby that, or Python everything.<br/>
<br/>
Yet when you look at what Lua's actually done and been used for in the industry it certainly seems disproportionate to the eerie silence it seems to experience in the blogosphere. Just for example I'm going to drop a few names now of commercial products which use Lua: Eyeon Digital Fusion, Adobe Photoshop Lightroom, Sim City 4, World of Warcraft, Warhammer Online, Escape from Monkey Island, Psychonauts, and this is just a handful, if you want to see a couple of exhaustive lists then I'm sure Google and Wikipedia can help you.<br/>
<br/>
Anyway I'm not trying to raise a stink, I just think its an interesting question to ask because Lua is a real world language being used  by serious mainstream projects yet you hardly hear a blip about it, and I have no idea why.<br/>
<br/>
I can think of only one thing which has happened in the Lua world fairly recently which was caught and discussed on the web and that was Google giving a Lua developer an $8k donation to work on the amd64 port of the Lua-jit.<br/>
<br/>
I just happened to hear this morning of a new Lua project <a href="https://code.google.com/p/aima-lua/">AiMa-Lua</a> which will be implementing the code from "Aritificial Inteligence, a Modern Approach" by Stuart Russell and Peter Norvig as an example of good Lua coding for practice. I always like these types of projects, and I look forward to seeing the result.<br/>
<br/>
&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=learnin01-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=0136042597&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="align: left; height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;In my opinion a better book couldn't have been chosen, it is essentially "the" book when it comes to this subject. I own a 1st edition copy and it weighs in at over 800 pages.<br/>
<br/>
While it is expensive its one of the few books I'd say are <a href="http://aima.cs.berkeley.edu/adoptions.html">actually worth owning</a> simply for having such a reputable monster sitting on your shelf.<br/>
<br/>
You can pick up your own copy of the behemothic <a href="http://www.amazon.com/gp/product/0136042597?ie=UTF8&amp;tag=learnin01-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0136042597">Artificial Intelligence: A Modern Approach (3rd Edition)</a><img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=learnin01-20&amp;l=as2&amp;o=1&amp;a=0136042597" style="border: none !important; margin: 0px !important;" width="1"/> from Amazon.<br/>
<br/>
<br/>
<br/>
<br/>
<h1><br/>
</h1><div class="blogger-post-footer">&lt;script charset="utf-8" expr:src=""http://feeds.feedburner.com/~s/goplexian?i=" + data:post.url" type="text/javascript"&gt;&lt;/script&gt;<img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/3303907924347033832-6724449614732993328?l=www.goplexian.com" width="1"/></div><img height="1" src="http://feeds.feedburner.com/~r/goplexian/~4/LzcmyUmf5GU" width="1"/></div>
    </summary>
    <updated>2010-02-11T21:20:00Z</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="Lua"/><feedburner:origLink xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://www.goplexian.com/2010/02/why-nobody-talks-about-lua.html</feedburner:origLink>
    <author>
      <name>Alex Combas</name>
      <email>alex.combas@gmail.com</email>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-3303907924347033832</id>
      <author>
        <name>Alex Combas</name>
        <email>alex.combas@gmail.com</email>
      </author>
      <link href="http://www.goplexian.com/" rel="alternate" type="text/html"/>
      <link href="http://feeds.feedburner.com/goplexian" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <subtitle>open-source, programming, and indie games</subtitle>
      <title>One billion extensible bits</title>
      <updated>2010-02-26T15:00:07Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-6010385767212376379</id>
    <link href="http://reneefrench.blogspot.com/feeds/6010385767212376379/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=6010385767212376379" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/6010385767212376379" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/6010385767212376379" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/launceston.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://3.bp.blogspot.com/_va9O40qIhaE/S21alpgNKFI/AAAAAAAACTQ/EDZJsPCgnos/s1600-h/tmusselsm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5435099928148650066" src="http://3.bp.blogspot.com/_va9O40qIhaE/S21alpgNKFI/AAAAAAAACTQ/EDZJsPCgnos/s320/tmusselsm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 320px; height: 262px;"/></a><br/><div>launceston</div><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-6010385767212376379?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-11T11:59:00Z</updated>
    <published>2010-02-11T11:59:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="tonal drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-08T04:00:37Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://rogpeppe.wordpress.com/?p=37</id>
    <link href="http://rogpeppe.wordpress.com/2010/02/10/unlimited-buffering-with-low-overhead/" rel="alternate" type="text/html"/>
    <title>Unlimited Buffering with Low Overhead</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">In Go, channels have a fixed length buffer. Sometimes it is useful to add a buffer of unlimited length to a channel (here is an example). The first question is what the interface should look like. I can think of three immediate possibilities (assume T is an arbitrary type – if Go had generics, this [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=rogpeppe.wordpress.com&amp;blog=10759696&amp;post=37&amp;subd=rogpeppe&amp;ref=&amp;feed=1"/></div>
    </summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><br/><p>In Go, channels have a fixed length buffer. Sometimes it is useful to add a buffer of unlimited length to a channel (<a href="http://blog.onideas.ws/eratosthenes.go#comment-32915986">here</a> is an example). The first question is what the interface should look like. I can think of three immediate possibilities (assume T is an arbitrary type – if Go had generics, this would be a generic function): </p>
<p>Given a channel, make sure that no writes to that channel will<br/>
block, and return a channel from which the buffered values can be read:</p>
<pre>func Buffer(in &lt;-chan T) &lt;-chan T
</pre>
<p>Given a channel, return a channel that will buffer writes<br/>
to that channel:</p>
<pre>func Buffer(out chan&lt;- T) chan &lt;-T
</pre>
<p>Given two channels, connect them via a buffering process:</p>
<pre>func Buffer(in &lt;-chan T, out chan&lt;- T)
</pre>
<p>Of these possibilities, on balance I think I prefer the second, as no operations will be performed on the original channel except when a value is written on the returned channel.</p>
<p>I’d be interested in hearing arguments for or against the other possibilities.</p>
<p>Here is one simple, and relatively slow implementation. It uses the doubly-linked list implementation from the Go library. I timed it at 2076ns per item transferred on my machine. Note the code that runs before the select statement each time through the loop, which works out whether we want to be sending a value, and when it is time to finish. This relies on the fact that in a Go select statement, operations on nil channels are ignored. </p>
<pre>import "container/list"
func BufferList(out chan&lt;- T) chan&lt;- T {
	in := make(chan T, 100)
	go func() {
		var buf = list.New()
		for {
			outc := out
			var v T
			n := buf.Len()
			if n == 0 {
				// buffer empty: don't try to send on output
				if in == nil {
					close(out)
					return
				}
				outc = nil
			}else{
				v = buf.Front().Value.(T)
			}
			select {
			case e := &lt;-in:
				if closed(in) {
					in = nil
				} else {
					buf.PushBack(e)
				}
			case outc &lt;- v:
				buf.Remove(buf.Front())
			}
		}
	}()
	return in
}
</pre>
<p> The above implementation allocates a new linked list item for every value transferred. Here’s an alternative implementation that uses an array as a circular buffer, amortising allocations over time by doubling the size of the buffer when it overflows, and shrinking it when there is too much space. Although the basic structure is similar, the code is more complex, and the time saving is modest – I timed it at 1729ns per item transferred, an improvement of 17%.  Removing the code to shrink the buffer does not make it significantly faster. </p>
<pre>func BufferRingOrig(out chan&lt;- T) chan&lt;- T {
	in := make(chan T, 100)
	go func() {
		var zero T
		var buf = make([]T, 10)
		var i = 0 // location of first value in buffer.
		var n = 0 // number of items in buffer.
		for {
			outc := out
			switch {
			case n == 0:
				// buffer empty: don't try to send on output
				if in == nil {
					close(out)
					return
				}
				outc = nil

			case n == len(buf):
				// buffer full: expand it
				b := make([]T, n*2)
				copy(b, buf[i:])
				copy(b[n-i:], buf[0:i])
				i = 0
				buf = b

			case len(buf) &gt; 128 &amp;&amp; n*3 &lt; len(buf):
				// buffer too big, shrink it
				b := make([]T, len(buf) / 2)
				j := i + n
				if j &gt; len(buf) {
					// wrap around
					k := j - len(buf)
					j = len(buf)
					copy(b, buf[i:j])
					copy(b[j - i:], buf[0:k])
				}else{
					// contiguous
					copy(b, buf[i:j])
				}
				i = 0
				buf = b
			}
			select {
			case e := &lt;-in:
				if closed(in) {
					in = nil
				} else {
					j := i + n
					if j &gt;= len(buf) {
						j -= len(buf)
					}
					buf[j] = e
					n++
				}
			case outc &lt;- buf[i]:
				buf[i] = zero
				if i++; i == len(buf) {
					i = 0
				}
				n--
			}
		}
	}()
	return in
}
</pre>
<p>I wondered if the unnecessary tests before the select statement were making any significant difference to the time taken. Although it makes it easy to preserve the invariants, there is no need to test whether the buffer is empty when a value has just been placed in it, for example.</p>
<p>Here is a version that only does the tests when necessary. Interestingly, this change actually made the code run marginally <i>slower</i> (1704ns per item)</p>
<pre>func BufferRing(out chan&lt;- T) chan&lt;- T {
	in := make(chan T, 100)
	go func() {
		var zero T
		var buf = make([]T, 10)
		var i = 0 // location of first value in buffer.
		var n = 0 // number of items in buffer.
		var outc chan&lt;- T
		for {
			select {
			case e := &lt;-in:
				if closed(in) {
					in = nil
					if n == 0 {
						close(out)
						return
					}
				} else {
					j := i + n
					if j &gt;= len(buf) {
						j -= len(buf)
					}
					buf[j] = e
					n++
					if n == len(buf) {
						// buffer full: expand it
						b := make([]T, n*2)
						copy(b, buf[i:])
						copy(b[n-i:], buf[0:i])
						i = 0
						buf = b
					}
					outc = out
				}
			case outc &lt;- buf[i]:
				buf[i] = zero
				if i++; i == len(buf) {
					i = 0
				}
				n--
				if n == 0 {
					// buffer empty: don't try to send on output
					if in == nil {
						close(out)
						return
					}
					outc = nil
				}
				if len(buf) &gt; 128 &amp;&amp; n*3 &lt; len(buf) {
					// buffer too big, shrink it
					b := make([]T, len(buf) / 2)
					j := i + n
					if j &gt; len(buf) {
						// wrap around
						k := j - len(buf)
						j = len(buf)
						copy(b, buf[i:j])
						copy(b[j - i:], buf[0:k])
					}else{
						// contiguous
						copy(b, buf[i:j])
					}
					i = 0
					buf = b
				}
			}
		}
	}()
	return in
}
</pre>
<p>Although the speed improvement from the above piece of code was disappointing, the change paves the way for a change that really does make a difference. A select statement in Go is significantly more costly than a regular channel operation. In the code below, we loop receiving or sending values as long as we can do so without blocking. Here’s a version of the list-based code that does this. I measured it at 752ns per item, an improvement of 63% over the original, or 2.7x faster.</p>
<pre>func BufferListCont(out chan&lt;- T) chan&lt;- T {
	in := make(chan T, 100)
	go func() {
		var buf = list.New()
		var outc chan&lt;- T
		var v T
		for {
			select {
			case e := &lt;-in:
				if buf.Len() == 0 &amp;&amp; !closed(in) {
					outc = out
					v = e
				}
				for {
					if closed(in) {
						in = nil
						if buf.Len() == 0 {
							close(out)
							return
						}
						break
					}
					buf.PushBack(e)
					var ok bool
					if e, ok = &lt;-in; !ok {
						break
					}
				}

			case outc &lt;- v:
				for {
					buf.Remove(buf.Front())
					if buf.Len() == 0 {
						// buffer empty: don't try to send on output
						if in == nil {
							close(out)
							return
						}
						outc = nil
						break
					}
					v = buf.Front().Value.(T)
					if ok := outc &lt;- v; !ok {
						break
					}
				}
			}
		}
	}()
	return in
}
</pre>
<p>One objection to the above code is that in theory if there was a fast enough producer on another processor, the buffer process could spend forever feeding values into the buffer, without ever trying to write them out. Although I believe that in practice the risk is negligible, it’s easy to guard against anyway, by only adding a fixed maximum number of values before returning to the select statement.</p>
<p>Here’s my final implementation, using the looping technique and with the guard added in.</p>
<p>I timed it at 427ns per item transferred, an improvement of 79% over the original version, or almost 5x faster. Using a buffered channel directly is only 2.4x faster than this.</p>
<pre>func BufferRingContCheck(out chan&lt;- T) chan&lt;- T {
	in := make(chan T, 100)
	go func() {
		var zero T
		var buf = make([]T, 10)
		var i = 0 // location of first value in buffer.
		var n = 0 // number of items in buffer.
		var outc chan&lt;- T
		for {
			select {
			case e := &lt;-in:
				for added := 0; added &lt; 1000; added++ {
					if closed(in) {
						in = nil
						if n == 0 {
							close(out)
							return
						}
						break
					}
					j := i + n
					if j &gt;= len(buf) {
						j -= len(buf)
					}
					buf[j] = e
					n++
					outc = out		// enable output
					if n == len(buf) {
						// buffer full: expand it
						b := make([]T, n*2)
						copy(b, buf[i:])
						copy(b[n-i:], buf[0:i])
						i = 0
						buf = b
					}
					var ok bool
					if e, ok = &lt;-in; !ok {
						break
					}
				}
			case outc &lt;- buf[i]:
				for {
					buf[i] = zero
					if i++; i == len(buf) {
						i = 0
					}
					n--
					if n == 0 {
						// buffer empty: don't try to send on output
						if in == nil {
							close(out)
							return
						}
						outc = nil
						break
					}
					if len(buf) &gt; 128 &amp;&amp; n*3 &lt; len(buf) {
						// buffer too big, shrink it
						b := make([]T, len(buf) / 2)
						j := i + n
						if j &gt; len(buf) {
							// wrap around
							k := j - len(buf)
							j = len(buf)
							copy(b, buf[i:j])
							copy(b[j - i:], buf[0:k])
						}else{
							// contiguous
							copy(b, buf[i:j])
						}
						i = 0
						buf = b
					}
					if ok := outc &lt;- buf[i]; !ok {
						break
					}
				}
			}
		}
	}()
	return in
}
</pre>
<p>Obviously the final code is significantly bigger and more complex than the original. Which implementation should we choose? Lacking generics, this code cannot usefully be put into a library, as most channels are not of type <tt>chan interface{}</tt>.</p>
<p>Given this, in most instances, perhaps the first version is to be preferred, as it’s smaller to cut and paste, and easier to understand. In cases where performance is crucial, the final version can easily be substituted.</p>
<p>Perhaps there’s another faster technique that I haven’t found yet. I’d be interested to hear any ideas on the matter.</p>
<p>The code with all the tests and benchmarks can be found <a href="http://www.morgyhill.talktalk.net/buffer_test.go">here</a>.</p>
  <a href="http://feeds.wordpress.com/1.0/gocomments/rogpeppe.wordpress.com/37/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/rogpeppe.wordpress.com/37/"/></a> <a href="http://feeds.wordpress.com/1.0/godelicious/rogpeppe.wordpress.com/37/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/rogpeppe.wordpress.com/37/"/></a> <a href="http://feeds.wordpress.com/1.0/gostumble/rogpeppe.wordpress.com/37/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/rogpeppe.wordpress.com/37/"/></a> <a href="http://feeds.wordpress.com/1.0/godigg/rogpeppe.wordpress.com/37/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/rogpeppe.wordpress.com/37/"/></a> <a href="http://feeds.wordpress.com/1.0/goreddit/rogpeppe.wordpress.com/37/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/rogpeppe.wordpress.com/37/"/></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=rogpeppe.wordpress.com&amp;blog=10759696&amp;post=37&amp;subd=rogpeppe&amp;ref=&amp;feed=1"/></div>
    </content>
    <updated>2010-02-10T17:06:22Z</updated>
    <category term="computers"/>
    <category term="golang"/>
    <author>
      <name>rogpeppe</name>
    </author>
    <source>
      <id>http://rogpeppe.wordpress.com</id>
      <logo>http://www.gravatar.com/blavatar/b31ca77090118540d0465ede69a57976?s=96&amp;d=http://s.wordpress.com/i/buttonw-com.png</logo>
      <link href="http://rogpeppe.wordpress.com/feed/" rel="self" type="application/atom+xml"/>
      <link href="http://rogpeppe.wordpress.com" rel="alternate" type="text/html"/>
      <link href="http://rogpeppe.wordpress.com/osd.xml" rel="search" type="application/opensearchdescription+xml"/>
      <subtitle>Just another WordPress.com weblog</subtitle>
      <title>Savoury Morsels</title>
      <updated>2010-02-10T18:00:03Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blog.notdot.net,2009:post:35001</id>
    <link href="http://blog.notdot.net/2010/02/Webapps-on-App-Engine-part-6-Lazy-loading" rel="alternate" type="text/html"/>
    <title>Webapps on App Engine, part 6: Lazy loading</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><em>This is part of a series on writing a webapp framework for App Engine Python. For details, see the introductory post <a href="http://blog.notdot.net/2010/01/Writing-your-own-webapp-framework-for-App-Engine">here</a>.</em></p>

<p>A major concern for many people developing for App Engine, particularly those building low-to-medium traffic sites, is instance load time. When App Engine serves the first request to a new instance of your app, it must import the request handler module you specified, which in turn imports all the other modules required to serve the request. In large apps, this can add up to quite a lot of additional overhead for loading requests, and substantially impact the experience for end users.</p>

<p>There are a number of things you can do to reduce loading times, including using <a href="http://blog.notdot.net/2010/01/Writing-your-own-webapp-framework-for-App-Engine">lighter weight frameworks</a> instead of <a href="http://www.djangoproject.com/">all inclusive</a> ones, and breaking seldom used components up into separate handlers - an approach taken by <a href="http://github.com/arachnid/bloggart/">bloggart</a> for the admin interface. One source of inefficiency stands out as a prime candidate for optimisation, though: unnecessary imports.</p>

<p>Many frameworks, including the built in webapp framework, require you to provide a list of handler classes that should be instantiated to serve requests, in a 'url map'. When a request comes in, the framework simply instantiates the relevant class and calls it to handle the request. However, doing this requires you to import all your handler classes so you can construct the url map, and this likely results in transitively importing your entire webapp, even though only a small proportion of it may be required to handle the request at hand.</p>

<p>You may have noticed that our framework, so far, doesn't appear to do any better on this front - and you'd be right. That's about to change, however. One thing we've kept a constant throughout writing the framework is making as many components as possible independent, often by making them WSGI applications in their own right. The router is a WSGI application, and so are handler classes, and so is the WebOb response object. Today, we'll make use of that feature to add support for lazy loading in a manner that's completely independent of our framework - and would work on any other WSGI-based framework, too.</p>

<p>The interface to our lazy loader will be straightforward: Instantiate a class with the fully qualified name of a module containing a WSGI application (such as a handler for our framework), and it will act as a WSGI application that imports the handler module on first access, and calls it in turn. To do this, we need to be able to import a module whose name is defined at runtime - and for that we use the Python <a href="http://docs.python.org/library/functions.html">builtin</a> __import__.</p>

<p>__import__'s operation is fairly straightforward: Simply call it with the name of the module to be imported as the first argument, and it returns a module instance containing that module. As additional information, we pass it our local and global variables using two more arguments, to allow it to resolve relative imports. In short, this:</p>

<pre class="prettyprint">from mypackage import mymodule</pre>

<p>Is equivalent to this:</p>

<pre class="prettyprint">mymodule = __import__('mypackage.mymodule', globals(), locals())</pre>

<p>We also need to know how to retrieve a name from a module dynamically. This is even simpler: Every object in python (more or less) is backed by a dict, which can be accessed with its '__dict__' attribute. Retrieving a name from a module is thus achieved like so:</p>

<pre class="prettyprint">myclass = mymodule.__dict__['myclass']</pre>

<p>With that in mind, writing our lazy importer is simple:</p>

<pre class="prettyprint">class WSGILazyLoader(object):
  def __init__(self, fullname):
    self.modulename, self.objname = fullname.rpartition('.')
    self.obj = None

  def __call__(self, environ, start_response):
    if not self.obj:
      module = __import__(self.modulename, globals(), locals())
      self.obj = module.__dict__[self.objname]
    return self.obj(environ, start_response)</pre>

<p>To use it, we simply define our handler (and create an instance of it) in one module:</p>

<pre class="prettyprint">import framework

class HomeHandler(framework.RequestHandler):
  def get(self):
    self.response.body = "Hello, world!"

home_handler = HomeHandler()</pre>

<p>And reference it using the lazy loader in another:</p>

<pre class="prettyprint">import framework
from google.appengine.ext.webapp.util import run_wsgi_app

application = framework.WSGIRouter()
application.connect('/', framework.WSGILazyLoader('home.home_handler'))

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()</pre>

<p>You can enhance the lazy loader, of course. Possibilities include having it take the name of a class instead of an instance, and have it automatically instantiate the handler class for each new request, thus duplicating the instance-per-request mechanism of webapp and other frameworks.</p></div>
    </content>
    <updated>2010-02-10T15:58:59Z</updated>
    <published>2010-02-10T15:58:59Z</published>
    <author>
      <name>Nick Johnson</name>
      <uri>http://blog.notdot.net/</uri>
    </author>
    <source>
      <id>tag:blog.notdot.net,2009:atom.xml</id>
      <link href="http://blog.notdot.net/" rel="alternate" type="text/html"/>
      <link href="http://blog.notdot.net/feeds/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <rights>Copyright (c) 2009</rights>
      <subtitle>because repeating myself sucks</subtitle>
      <title>Nick's Blog</title>
      <updated>2010-02-12T16:59:39Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-7114172681493277172</id>
    <link href="http://reneefrench.blogspot.com/feeds/7114172681493277172/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=7114172681493277172" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/7114172681493277172" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/7114172681493277172" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/hey-boo.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://4.bp.blogspot.com/_va9O40qIhaE/S21ZFRHbo5I/AAAAAAAACTI/SIr9KERmdbg/s1600-h/hdaymovbed22sm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5435098272334848914" src="http://4.bp.blogspot.com/_va9O40qIhaE/S21ZFRHbo5I/AAAAAAAACTI/SIr9KERmdbg/s320/hdaymovbed22sm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 320px; height: 223px;"/></a><br/><div>hey boo</div><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-7114172681493277172?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-10T11:50:00Z</updated>
    <published>2010-02-10T11:50:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="line drawings"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="story z"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-06T06:34:29Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://swtools.wordpress.com/?p=184</id>
    <link href="http://swtools.wordpress.com/2010/02/10/update-go-scanner-to-accept-non-ascii-operators/" rel="alternate" type="text/html"/>
    <title>Update Go scanner to accept non-ASCII operators</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Read the discussion of this change on the golang-nuts mailing list.  See this notice in UTF-8 format.
For each line, the scanner accepts, in place of the first operator, any of the remaining operators, and outputs a token whose string (set in $GOROOT/src/go/token/token.go) is the first operator.
 ! ¬
 != ≠
 &amp; ∧
 &amp;&amp; ⋀
 &amp;= ∧=
 [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=swtools.wordpress.com&amp;blog=201050&amp;post=184&amp;subd=swtools&amp;ref=&amp;feed=1"/></div>
    </summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Read the <a href="http://groups.google.com/group/golang-nuts/browse_thread/thread/502a754f5541a61">discussion</a> of this change on the golang-nuts mailing list.  See <a href="http://dl.dropbox.com/u/502901/myscanner.1">this notice</a> in UTF-8 format.</p>
<p>For each line, the scanner accepts, in place of the first operator, any of the remaining operators, and outputs a token whose string (set in $GOROOT/src/go/token/token.go) is the first operator.</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>!<span style="white-space: pre;"> </span>¬</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>!=<span style="white-space: pre;"> </span>≠</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>&amp;<span style="white-space: pre;"> </span>∧</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>&amp;&amp;<span style="white-space: pre;"> </span>⋀</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>&amp;=<span style="white-space: pre;"> </span>∧=</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>&amp;^<span style="white-space: pre;"> </span>∧¬</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>&amp;^=<span style="white-space: pre;"> </span>∧¬=</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>…<span style="white-space: pre;"> </span>…</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>:=<span style="white-space: pre;"> </span>≔</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>&lt;-<span style="white-space: pre;"> </span>←</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>&lt;&lt;<span style="white-space: pre;"> </span>≪</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>&lt;&lt;=<span style="white-space: pre;"> </span>≪=</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>&lt;=<span style="white-space: pre;"> </span>≤</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>==<span style="white-space: pre;"> </span>=?<span style="white-space: pre;"> </span>≟</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>&gt;=<span style="white-space: pre;"> </span>≥</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>&gt;&gt;<span style="white-space: pre;"> </span>≫</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>&gt;&gt;=<span style="white-space: pre;"> </span>≫=</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>^<span style="white-space: pre;"> </span>⊻</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>^=<span style="white-space: pre;"> </span>⊻=</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>|<span style="white-space: pre;"> </span>∨</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>|=<span style="white-space: pre;"> </span>∨=</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>|| ⋁</p>
<p>To install, copy $GOROOT/src/pkg/go/scanner/scanner.go to another file.</p>
<p>Replace scanner.go with <a href="http://dl.dropbox.com/u/502901/scanner.go">scanner.go</a></p>
<p>Run $GOROOT/src/all.bash and check for 0 unexpected errors.</p>
<p>Changes to scanner.go update gofmt, which accepts UTF-8 operators and outputs their ASCII equivalents.  This mkfile production rule uses gofmt as a preprocessor to create a sharable and compilable file.</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> </span>%.go: %.ℊℴ</p>
<p style="padding-left: 60px;"><span style="white-space: pre;"> </span>cat $stem.ℊℴ | gofmt &gt; $stem.go</p>
<p>See these files for an example of each new operator form in the context of a simple Go program.</p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> <a href="http://dl.dropbox.com/u/502901/myscanner.%E2%84%8A%E2%84%B4">myscanner.ℊℴ</a></span></p>
<p style="padding-left: 30px;"><span style="white-space: pre;"> <a href="http://dl.dropbox.com/u/502901/chan.%E2%84%8A%E2%84%B4">chan.ℊℴ</a></span></p>
<p>Please <a href="mailto:Jason.Catena@gmail.com">mail me</a> privately if something doesn’t work with this code, to avoid noise on the golang-nuts list, since we’re no longer discussing officially-released code.</p>
<br/>  <a href="http://feeds.wordpress.com/1.0/gocomments/swtools.wordpress.com/184/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/swtools.wordpress.com/184/"/></a> <a href="http://feeds.wordpress.com/1.0/godelicious/swtools.wordpress.com/184/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/swtools.wordpress.com/184/"/></a> <a href="http://feeds.wordpress.com/1.0/gostumble/swtools.wordpress.com/184/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/swtools.wordpress.com/184/"/></a> <a href="http://feeds.wordpress.com/1.0/godigg/swtools.wordpress.com/184/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/swtools.wordpress.com/184/"/></a> <a href="http://feeds.wordpress.com/1.0/goreddit/swtools.wordpress.com/184/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/swtools.wordpress.com/184/"/></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=swtools.wordpress.com&amp;blog=201050&amp;post=184&amp;subd=swtools&amp;ref=&amp;feed=1"/></div>
    </content>
    <updated>2010-02-10T06:16:26Z</updated>
    <category term="Uncategorized"/>
    <author>
      <name>catena</name>
    </author>
    <source>
      <id>http://swtools.wordpress.com</id>
      <logo>http://www.gravatar.com/blavatar/1b0e7838e53455cdcc9f41b08c0f496d?s=96&amp;d=http://s2.wp.com/i/buttonw-com.png</logo>
      <link href="http://swtools.wordpress.com/feed/" rel="self" type="application/atom+xml"/>
      <link href="http://swtools.wordpress.com" rel="alternate" type="text/html"/>
      <link href="http://swtools.wordpress.com/osd.xml" rel="search" type="application/opensearchdescription+xml"/>
      <link href="http://swtools.wordpress.com/?pushpress=hub" rel="hub" type="text/html"/>
      <subtitle>Do one thing well, and work together.</subtitle>
      <title>Software Tools</title>
      <updated>2010-03-05T21:00:03Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://www.airs.com/blog/?p=319</id>
    <link href="http://www.airs.com/blog/archives/319" rel="alternate" type="text/html"/>
    <title>Biophilia</title>
    <summary>E.O. Wilson’s notion of biophilia, which is slightly different from closely related to the newer idea of evolutionary psychology, posits that humans can not be healthy without some access to the natural world.  The argument basically amounts to saying that we have evolved in a world which is not completely under human control, and [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>E.O. Wilson’s notion of biophilia, which is slightly different from closely related to the newer idea of evolutionary psychology, posits that humans can not be healthy without some access to the natural world.  The argument basically amounts to saying that we have evolved in a world which is not completely under human control, and we are not happy unless we are, at least to some extent, in such a world today.</p>
<p>I think the basic argument is likely true for most people.  There was an interesting experiment which seemed to show that people next to a window onto an outside nature scene were under less stress than people next to a television screen showing the same image (I can’t find a link, but Journal of Evolutionary Psychology by PH Kahn).  I think that many of us look for something to exist outside ourselves, and nature can play that role.</p>
<p>Some people use that as an argument for preserving the environment: we should preserve the environment to keep ourselves healthy (this is in some ways a variant on the idea that we should save the rainforest because we can find new pharmaceutical drugs there).  Unfortunately, while I’m definitely in favor of preserving the environment, I think this argument fails.  I think that technology can provide us the health benefits of access to the natural world, by hiding the sources of the technology.  I think that a sophisticated robot dog can provide all the psychological benefits of a real dog, and more.  With a good design we can get the unpredictability, the sense of a different mind and a different world operating.  I think those are the things we need.  I don’t think they have to actually come from nature.</p></div>
    </content>
    <updated>2010-02-09T14:29:36Z</updated>
    <category term="Philosophy"/>
    <author>
      <name>Ian Lance Taylor</name>
    </author>
    <source>
      <id>http://www.airs.com/blog</id>
      <link href="http://www.airs.com/blog/feed" rel="self" type="application/atom+xml"/>
      <link href="http://www.airs.com/blog" rel="alternate" type="text/html"/>
      <subtitle>Ian Lance Taylor</subtitle>
      <title>Airs - Ian Lance Taylor</title>
      <updated>2010-03-09T08:00:16Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-2629813730017430194</id>
    <link href="http://reneefrench.blogspot.com/feeds/2629813730017430194/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=2629813730017430194" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2629813730017430194" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/2629813730017430194" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/gap.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://3.bp.blogspot.com/_va9O40qIhaE/S21YW-msAEI/AAAAAAAACTA/TR0g60kHeR4/s1600-h/hdaycreatsm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5435097477091688514" src="http://3.bp.blogspot.com/_va9O40qIhaE/S21YW-msAEI/AAAAAAAACTA/TR0g60kHeR4/s320/hdaycreatsm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 310px; height: 320px;"/></a>gap<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-2629813730017430194?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-09T11:53:00Z</updated>
    <published>2010-02-09T11:53:00Z</published>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-05T14:57:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://www.airs.com/blog/?p=317</id>
    <link href="http://www.airs.com/blog/archives/317" rel="alternate" type="text/html"/>
    <title>iPad</title>
    <summary>It’s taken me a while to understand the point of the iPad.  I can type on a keyboard faster than I can press keys on a screen, so the iPad would not be useful for me as a computer.  And it wouldn’t fit in my pocket, so I wouldn’t carry around the way [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>It’s taken me a while to understand the point of the iPad.  I can type on a keyboard faster than I can press keys on a screen, so the iPad would not be useful for me as a computer.  And it wouldn’t fit in my pocket, so I wouldn’t carry around the way I carry my phone.</p>
<p>I think I get it now, though.  The point of the iPad is to read books, watch videos, and play games.  For that, it is looks quite convenient.  I can carry it easily from room to room, I can prop it up while I’m eating, I can hold it up while I’m in bed (I assume it’s not too heavy for that).  That is, the iPad is not a computer and it’s not a phone: it’s a media consumption device.  It’s only real competition at the moment are the various e-book readers, which tend to be limited to just reading books.  The first version of the iPad apparently won’t have a camera, and I don’t know whether it has a microphone, but I’m sure that future versions will have both, and that they will be a good way to do video chat.</p>
<p>With that understanding, the complaints I’ve seen about Apple’s tight control over the app store are kind of irrelevant.  I don’t want to run arbitrary programs on my books, and I won’t want to run them on an iPad either.  When I want to run programs, I’ll use a computer.  The app store will be mainly an alternative way to publish information–authors will be able to sell directly to you, rather than going through a publisher.</p>
<p>More troubling are the complaints about Apple’s tight controls over content distribution.  If other companies emulate Apple and Amazon, then we are taking another big step toward tight control over copyrighted content and the elimination of some fair use rights.  When my only copy of a book is on my Kindle or my iPad, I can’t easily lend it to my friend.  When publishers stop making physical books, libraries will become far less useful.</p>
<p>I’ve written before about how copyright will vanish.  The iPad points to a way to bring it back: to build copyright controls into the architecture of how people read books.  This is the kind of thing Lessig talked about in Code and Other Laws of Cyberspace.  Building tight copyright control into a general purpose computer is really really hard.  Building it into a closed system like the iPad is much simpler.  I’m sure that enterprising people will crack the iPad’s controls, but it remains an open question whether they can crack the controls while still letting the iPad continue to access the various stores that will provide content.</p>
<p>Whether these are reasonable concerns depends entirely on how well the iPad does.  I have no plans to buy one myself—I wouldn’t buy one even if I didn’t have these concerns.  That is quite different from the iPhone, which I did buy a couple of months after it came out, though I’ve switched to a different phone since.  I can’t predict how well the iPad will do; if it is very successful, then we’ll really have to worry about copyright issues in the future.</p></div>
    </content>
    <updated>2010-02-08T06:53:29Z</updated>
    <category term="Random"/>
    <author>
      <name>Ian Lance Taylor</name>
    </author>
    <source>
      <id>http://www.airs.com/blog</id>
      <link href="http://www.airs.com/blog/feed" rel="self" type="application/atom+xml"/>
      <link href="http://www.airs.com/blog" rel="alternate" type="text/html"/>
      <subtitle>Ian Lance Taylor</subtitle>
      <title>Airs - Ian Lance Taylor</title>
      <updated>2010-03-09T08:00:16Z</updated>
    </source>
  </entry>

  <entry xml:lang="ja">
    <id>http://golang.jp/?p=1210</id>
    <link href="http://golang.jp/2010/02/1210" rel="alternate" type="text/html"/>
    <title>実践Go言語(part6)</title>
    <summary>実践Go言語(Effective Go)の翻訳、6回目です。
前回までの訳は実践Go言語[日本語訳]にまとめてあります。

関数
複数の戻り値
Go言語の目新しい特徴のひとつは、関数およびメソッドが複数の値を返せることで [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><a href="http://golang.org/doc/effective_go.html" target="_blank">実践Go言語(Effective Go)</a>の翻訳、6回目です。<br/>
前回までの訳は<a href="http://golang.jp/effective_go">実践Go言語[日本語訳]</a>にまとめてあります。</p>
<hr/>
<h2 id="functions">関数</h2>
<h3 id="multiple-returns">複数の戻り値</h3>
<p>Go言語の目新しい特徴のひとつは、関数およびメソッドが複数の値を返せることです。これは、C言語のプログラムで扱いにくかった、受信エラー(<code>EOF</code>を表す<code>-1</code>など)や引数の値の変更などを改善します。</p>
<p>C言語で書き込みエラーが起きたときは、マイナス値を返すことにより通知され、共用の変数にエラーコードが格納されます。Go言語では<code>Write</code>は書き込みデータ数とエラーを別々に返すことができます。つまり次のような情報を得ることができます。「何バイトか書き込めましたが、デバイスが一杯になったので一部書き込めませんでした。」</p>
<p><code>os</code>パッケージの<code>*File.Write</code>のシグネチャは次のように定義されています。</p>
<pre>func (file *File) Write(b []byte) (n int, err Error)</pre>
<p>シグネチャが示すとおりに、このメソッドは書き込んだバイト数を返すとともに、<code>n</code> <code>!=</code> <code>len(b)</code>のとき非nilの<code>Error</code>を返します。これは一般的な書き方です。その他の例は、エラーハンドリングに関するセクションを参照ください。</p>
<p>同様のアプローチにより、戻り値に参照パラメータを模してポインタを返す必要がなくなります。次の関数は、バイト配列の指定位置から数値を取り出し、その値と次の位置を返す単純な関数です。</p>
<pre>func nextInt(b []byte, i int) (int, int) {
    for ; i &lt; len(b) &amp;&amp; !isDigit(b[i]); i++ {
    }
    x := 0
    for ; i &lt; len(b) &amp;&amp; isDigit(b[i]); i++ {
        x = x*10 + int(b[i])-'0'
    }
    return x, i
}</pre>
<p>この関数は次のようにして、入力配列から数値を取り出すために利用できます。</p>
<pre>    for i := 0; i &lt; len(a); {
        x, i = nextInt(a, i)
        fmt.Println(x)
    }</pre>
<h3 id="named-results">名前付き結果パラメータ</h3>
<p>Go言語の、戻り／結果「パラメータ」には、名前をつけることができ、引数パラメータのように通常の変数として扱うことができます。名前が付けられていると、関数が呼び出されたときにその型のゼロ値で初期化されます。引数を持たない<code>return</code>ステートメントを実行したときは、その時点で結果パラメータに格納されている値が、戻り値として使われます。</p>
<p>名前は必ずしも必要ではありませんが、名前をつけることでコードをより簡潔にすることができます。これは資料としても役立ちます。前出の<code>nextInt</code>関数の結果パラメータに名前を付けると、返された<code>int</code>値がそれぞれ何を示しているか明確になります。</p>
<pre>func nextInt(b []byte, pos int) (value, nextPos int) {</pre>
<p>名前付きの結果パラメータは、初期化が行われた上で、パラメータなしのreturnと結びつけられるので、明確になるだけでなくシンプルになります。下は、この仕組みをうまく使った<code>io.ReadFull</code>の例です。</p>
<pre>func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
    for len(buf) &gt; 0 &amp;&amp; err == nil {
        var nr int
        nr, err = r.Read(buf)
        n += nr
        buf = buf[nr:len(buf)]
    }
    return
}</pre></div>
    </content>
    <updated>2010-02-08T06:36:31Z</updated>
    <category term="&#x30C9;&#x30AD;&#x30E5;&#x30E1;&#x30F3;&#x30C8;"/>
    <category term="&#x5B9F;&#x8DF5;Go&#x8A00;&#x8A9E;"/>
    <author>
      <name>noboru</name>
    </author>
    <source>
      <id>http://golang.jp</id>
      <link href="http://golang.jp/feed" rel="self" type="application/atom+xml"/>
      <link href="http://golang.jp" rel="alternate" type="text/html"/>
      <subtitle>プログラミング言語Goの情報サイト</subtitle>
      <title>Google's Go Guide</title>
      <updated>2010-03-12T08:00:14Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-4929950041227209263</id>
    <link href="http://reneefrench.blogspot.com/feeds/4929950041227209263/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=4929950041227209263" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/4929950041227209263" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/4929950041227209263" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/sausage-skin-king.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://1.bp.blogspot.com/_va9O40qIhaE/S21XO2Ki0UI/AAAAAAAACS4/5Zw1s2O-fBQ/s1600-h/hdaymov31sm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5435096237875581250" src="http://1.bp.blogspot.com/_va9O40qIhaE/S21XO2Ki0UI/AAAAAAAACS4/5Zw1s2O-fBQ/s320/hdaymov31sm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 207px; height: 320px;"/></a>sausage skin king<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-4929950041227209263?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-07T11:48:00Z</updated>
    <published>2010-02-07T11:48:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="line drawings"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="story z"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-05T08:58:49Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-4684223483086743509</id>
    <link href="http://reneefrench.blogspot.com/feeds/4684223483086743509/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=4684223483086743509" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/4684223483086743509" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/4684223483086743509" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/blog-post.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://2.bp.blogspot.com/_va9O40qIhaE/S24BXUoYKUI/AAAAAAAACT4/bkpgDDdvHXU/s1600-h/hdaymovbed30sm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5435283300469451074" src="http://2.bp.blogspot.com/_va9O40qIhaE/S24BXUoYKUI/AAAAAAAACT4/bkpgDDdvHXU/s320/hdaymovbed30sm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 320px; height: 229px;"/></a><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-4684223483086743509?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-06T23:55:15Z</updated>
    <published>2010-02-06T23:54:00Z</published>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-04T08:16:47Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-7369486875687078481</id>
    <link href="http://reneefrench.blogspot.com/feeds/7369486875687078481/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=7369486875687078481" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/7369486875687078481" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/7369486875687078481" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/it-wasnt-invented-yet.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://1.bp.blogspot.com/_va9O40qIhaE/S2utUC0_wPI/AAAAAAAACSQ/txKigfM7fLY/s1600-h/hdaydogwatersm.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5434627935220777202" src="http://1.bp.blogspot.com/_va9O40qIhaE/S2utUC0_wPI/AAAAAAAACSQ/txKigfM7fLY/s320/hdaydogwatersm.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 246px; height: 320px;"/></a>it wasn't invented yet<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/5192082-7369486875687078481?l=reneefrench.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-06T17:31:00Z</updated>
    <published>2010-02-06T17:31:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="story z"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="tonal drawings"/>
    <author>
      <name>renee</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/04038449165206577034</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-5192082</id>
      <author>
        <name>renee</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/04038449165206577034</uri>
      </author>
      <link href="http://reneefrench.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://reneefrench.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/5192082/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>click to make them bigger</subtitle>
      <title>renee french</title>
      <updated>2010-03-03T02:19:31Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-6989726062940083922.post-2317888286763766146</id>
    <link href="http://robpike.blogspot.com/feeds/2317888286763766146/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=6989726062940083922&amp;postID=2317888286763766146" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default/2317888286763766146" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default/2317888286763766146" rel="self" type="application/atom+xml"/>
    <link href="http://robpike.blogspot.com/2010/02/clouds-jan-30-2010.html" rel="alternate" type="text/html"/>
    <title>Clouds Jan 30, 2010</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://2.bp.blogspot.com/_Fpj1cqLIn_Y/S2vqHpPS_WI/AAAAAAAABsA/Rmn4o1xDR6M/s1600-h/Cloud-2010-01-30.jpg"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5434694792402632034" src="http://2.bp.blogspot.com/_Fpj1cqLIn_Y/S2vqHpPS_WI/AAAAAAAABsA/Rmn4o1xDR6M/s400/Cloud-2010-01-30.jpg" style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; cursor: hand; width: 400px; height: 269px;"/></a><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/6989726062940083922-2317888286763766146?l=robpike.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-05T09:51:45Z</updated>
    <published>2010-02-05T09:50:00Z</published>
    <author>
      <name>rob</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/18259238879445421354</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-6989726062940083922</id>
      <author>
        <name>rob</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/18259238879445421354</uri>
      </author>
      <link href="http://robpike.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://robpike.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/6989726062940083922/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <title>rob pike</title>
      <updated>2010-03-08T22:35:14Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-8082954141980125536.post-7431555927693868235</id>
    <link href="http://research.swtch.com/feeds/7431555927693868235/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=8082954141980125536&amp;postID=7431555927693868235" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default/7431555927693868235" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default/7431555927693868235" rel="self" type="application/atom+xml"/>
    <link href="http://research.swtch.com/2010/02/names.html" rel="alternate" type="text/html"/>
    <title>Names</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p class="lp">Every programmer has a variable naming philosophy.
This is mine:
</p>

<blockquote>
<p class="pp">
<i>A name's length should not exceed its information content.</i>
For a local variable, the name <code>i</code> conveys
as much information as <code>index</code> or <code>idx</code> and is quicker to read.
Similarly, <code>i</code> and <code>j</code> are a better pair of names for
index variables than <code>i1</code> and <code>i2</code> (or, worse, <code>index1</code> and <code>index2</code>),
because they are easier to tell apart when skimming
the program.
Global names must convey relatively more information,
because they appear in a larger variety of contexts.
Even so, a short, precise name can say more than a long-winded one:
compare 
<a href="http://www.google.com/codesearch?q=acquire"><code>acquire</code></a>
and <a href="http://www.google.com/codesearch?q=take_?ownership"><code>take_ownership</code></a>.
Make every name <a href="http://www.bartleby.com/141/strunk5.html#13">tell.</a>
</p>
</blockquote>

<p class="lp">The information content metric gives a quantitative
argument against long-winded names: they're simply inefficient.
I internalized this metric years ago but only realized this phrasing of it
recently,
perhaps because I have been looking at
<a href="http://www.google.com/codesearch?q=getParametersAsNamedValuePairArray">too</a> <a href="http://www.google.com/codesearch?q=org\.apache\.commons\.httpclient\.MultiThreadedHttpConnectionManager">much</a> <a href="http://www.google.com/codesearch?q=com\.google\.common\.base\.FinalizablePhantomReference">Java</a> <a href="http://www.google.com/codesearch?q=&quot;public+static+void+main&quot;">code</a>.
</p><div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/8082954141980125536-7431555927693868235?l=research.swtch.com" width="1"/></div></div>
    </content>
    <updated>2010-02-04T17:00:01Z</updated>
    <published>2010-02-04T17:00:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="notation"/>
    <author>
      <name>rsc</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/12988172038803189837</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-8082954141980125536</id>
      <author>
        <name>rsc</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/06357099531993534337</uri>
      </author>
      <link href="http://research.swtch.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://research.swtch.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/8082954141980125536/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Computer programming links, collected by
<a href="http://swtch.com/~rsc/">Russ Cox</a>.  Updated sporadically.</div>
      </subtitle>
      <title>research!rsc</title>
      <updated>2010-03-11T20:33:15Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-5192082.post-7109128012154254608</id>
    <link href="http://reneefrench.blogspot.com/feeds/7109128012154254608/comments/default" rel="replies" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment.g?blogID=5192082&amp;postID=7109128012154254608" rel="replies" type="text/html"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/7109128012154254608" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/5192082/posts/default/7109128012154254608" rel="self" type="application/atom+xml"/>
    <link href="http://reneefrench.blogspot.com/2010/02/bulb.html" rel="alternate" type="text/html"/>
    <title/>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://4.bp.blogspot.com/_va9O40qIhaE/S2luAEhMZXI/AAAAAAAACSA/rjnwxN8MOew/s1600-h/hdaymovbed9sm.jpg"><img alt=""