tag:blogger.com,1999:blog-21368101260152306722024-02-19T18:08:10.810+09:00亀鶴茄子亀鶴と茄子のblogです亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.comBlogger239125tag:blogger.com,1999:blog-2136810126015230672.post-59024350027069583902016-12-31T16:29:00.001+09:002016-12-31T16:29:36.663+09:002016年最初で最期の投稿気づけば一年何も書いていなかった。<br />
<br />
この一年も人に道をよく聞かれたけど、一時期ほどの頻度ではなくなった気がする。<br />
<br />
twitterを見返すとアウトプットを増やしたいのと、電子工作なことをやりたいと書いていて、見事にその通りに活動してきたように思う。<br />
<br />
正月あたりはRaspberry Piに接続された白黒液晶をGoで動かすために、i2cの簡単な使い方や、Goでのクロスコンパイルの仕方について調べていた。このあたりの成果は6月に開催されたPayPal Tech MeetupのDemo Nightの際に存分に生かされている。<br />
また直接的ではないものの、Raspberry PiのGPIO制御に慣れたことは、11月のArt Hack Dayにおいて非常に役に立った。 <br />
Demo NightにしろArt Hack Dayにしろ、会社の外で、特に評価がつくイベントに参加することは、緊張感を強いられるけど、地力をブーストしていくにはうってつけと思う。適度な危険に身を晒さないと成長実感を得るのは難しい。<br />
<br />
夏には小規模ながらGoの勉強会を主催したりして、今更感はあるもののGoの布教活動もした。とはいうものの、Goを教えるという点では社外より社内の方が頻繁にあり、先生役が求められている気がしないでもない。<br />
<br />
一方で、今年は応用というか実装面での学習、成長にパワーが割かれすぎて、もう少し基礎的な知識や、新しい言語を覚える時間が削られてしまった気もする。<br />
夏ぐらいにCommon Lispに挑戦しようとしていたのだけど、Common Lisp自体はともかく、Emacsの半強制(一応elvisは入れたのだけど)に閉口してしまい、結局起動自体が億劫になってしまった。<br />
他にもOCamlやRustを時々触ってはいたのだけど、イベント発表用の制作に追われて、結局まともには出来なかった。 <br />
プログラミング言語に限らず、自然言語についても、英語というか英会話を要求されるケースが仕事だけでなくプライベートでも何故か増えてきていて、そろそろ本格的に開始しないと日常生活でストレスがたまるようになってきている(弊社は英語公用語とかではない)。<br />
一応、英会話学習サービスをやってはいたのだけど、やはり制作が佳境に入るとそれどころではなくなってしまった。 <br />
<br />
ということで、来年はもう少し基礎的な学習と英会話に力を入れていきたいなと思っている。<br />
このブログももう少し活用するか。もしくはmediumあたりに引っ越すか。<br />
bloggerはいつになったら公式でMarkdownをサポートするのだろう。亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-65318281194504965402015-12-27T10:20:00.001+09:002015-12-28T05:33:00.315+09:00LLDBでGoのデバッグをする その2 test編<p>その1では<code>go build</code>したLLDBでデバッグしてみましたが、その2では<code>go test</code>でのdebugの仕方です。</p>
<p>今回のデバッグ対象として以下のようなプログラム(main.go)とそのテスト(main_test.go)を書きました。</p>
<pre class="prettyprint"><code class="language-go hljs "><span class="hljs-keyword">package</span> main
<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>
<span class="hljs-keyword">func</span> RectArea(w, h <span class="hljs-typename">int</span>) <span class="hljs-typename">int</span> {
<span class="hljs-keyword">return</span> w * h
}</code></pre>
<pre class="prettyprint"><code class="language-go hljs "><span class="hljs-keyword">package</span> main
<span class="hljs-keyword">import</span> <span class="hljs-string">"testing"</span>
<span class="hljs-keyword">func</span> TestRectArea(t *testing.T) {
s := RectArea<span class="hljs-number">(6</span>,<span class="hljs-number"> 8</span>)
<span class="hljs-keyword">if</span> s !=<span class="hljs-number"> 48</span> {
t.Error(<span class="hljs-string">"error"</span>)
}
}</code></pre>
<h2 id="testをビルドする">testをビルドする</h2>
<p><code>go test</code> には <code>-c</code> というオプションがあり、これを使うとtestのバイナリをビルドできます。これと <code>-gcflags</code> を組み合わせてデバッグ可能なtestバイナリを作ります。</p>
<pre class="prettyprint"><code class="language-bash hljs "><span class="hljs-comment"># -o は出力結果のファイル名を指定するオプション</span>
$ go test -c -gcflags <span class="hljs-string">'-N -l'</span> -o test
<span class="hljs-comment"># 実行するとgo testと同じ結果が得られる</span>
$ ./test
PASS</code></pre>
<h2 id="デバッグする">デバッグする</h2>
<p>後は、前回同様lldbに、このtestバイナリを渡すだけです。</p>
<pre class="prettyprint"><code class="language-bash hljs ">$ lldb test
(lldb) target create <span class="hljs-string">"test"</span>
Current executable <span class="hljs-keyword">set</span> to <span class="hljs-string">'test'</span> (x86_64).
(lldb)</code></pre>
<p>せっかくなのでプログラム本体とテスト両方にブレイクポイントを置いてみます。</p>
<pre class="prettyprint"><code class="language-bash hljs ">(lldb) target create <span class="hljs-string">"test"</span>
Current executable <span class="hljs-keyword">set</span> to <span class="hljs-string">'test'</span> (x86_64).
(lldb) b main.go:<span class="hljs-number">4</span>
Breakpoint <span class="hljs-number">1</span>: where = test`_/Users/kmtr/misc/c.RectArea + <span class="hljs-number">9</span> at main.go:<span class="hljs-number">6</span>, address = <span class="hljs-number">0</span>x000000000007dc09
(lldb) b main_test.go:<span class="hljs-number">7</span>
Breakpoint <span class="hljs-number">2</span>: where = test`_/Users/kmtr/misc/c.TestRectArea + <span class="hljs-number">58</span> at main_test.go:<span class="hljs-number">7</span>, address = <span class="hljs-number">0</span>x000000000007dc5a
(lldb)</code></pre>
<p>後は <code>run</code> するだけです。 <br>
main.go側で止まったところで、変数を確認。</p>
<pre class="prettyprint"><code class="language-bash hljs "> <span class="hljs-number">3</span> func RectArea(w, h int) int {
<span class="hljs-number">4</span> <span class="hljs-keyword">return</span> w * h
<span class="hljs-number">5</span> }
(lldb) fr v
(long) w = <span class="hljs-number">6</span>
(long) h = <span class="hljs-number">8</span>
(long) ~r2 = <span class="hljs-number">0</span>
(lldb)</code></pre>
<p><code>c</code> で継続して、次はmain_test.goで止まるので、こちらでも変数を確認。 <br>
そして <code>c</code> で終了させます。</p>
<pre class="prettyprint"><code class="language-bash hljs "> <span class="hljs-number">4</span>
<span class="hljs-number">5</span> func TestRectArea(t *testing.T) {
<span class="hljs-number">6</span> s := RectArea(<span class="hljs-number">6</span>, <span class="hljs-number">8</span>)
-> <span class="hljs-number">7</span> <span class="hljs-keyword">if</span> s != <span class="hljs-number">48</span> {
<span class="hljs-number">8</span> t.Error(<span class="hljs-string">"error"</span>)
<span class="hljs-number">9</span> }
<span class="hljs-number">10</span> }
(lldb) fr v
(long) s = <span class="hljs-number">48</span>
(testing.T *) t = <span class="hljs-number">0</span>x000000c82009c000
(lldb) c
Process <span class="hljs-number">25022</span> resuming
PASS
Process <span class="hljs-number">25022</span> exited with status = <span class="hljs-number">0</span> (<span class="hljs-number">0</span>x00000000)
(lldb) </code></pre>
<h2 id="まとめ">まとめ</h2>
<p><code>-c</code> オプションでtestバイナリを作るのがポイントで、後は前回と同じですね。</p>
<p>また続くかもしれない。</p>亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-44200477964722204622015-12-26T06:25:00.001+09:002015-12-28T05:32:46.399+09:00LLDBでGoのデバッグをする その1<h2 id="環境">環境</h2>
<p>環境は以下の通りです。</p>
<ul>
<li>OS X El Capitan 10.11.2</li>
<li>lldb-340.4.119</li>
<li>go version go1.5 darwin/amd64</li>
</ul>
<p>LLDBはxcodeについてきたものです。</p>
<h2 id="やってみる">やってみる</h2>
<p>デバッグ対象のコードは、やっつけですがこんな感じです。ファイル名はmain.goとしました。</p>
<pre class="prettyprint"><code class="language-go hljs "><span class="hljs-keyword">package</span> main
<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>
<span class="hljs-keyword">func</span> main() {
a :=<span class="hljs-number"> 10</span>
fmt.Printf(<span class="hljs-string">"Add1(10) == %d\n"</span>, Add1(a))
}
<span class="hljs-comment">// Add1 ...</span>
<span class="hljs-keyword">func</span> Add1(i <span class="hljs-typename">int</span>) <span class="hljs-typename">int</span> {
<span class="hljs-keyword">return</span> i +<span class="hljs-number"> 1</span>
}</code></pre>
<p>LLDBでデバッグするために、<code>-gcflags '-N -l'</code> というオプションをつけてビルドします。</p>
<pre class="prettyprint"><code class="language-bash hljs ">$ go build -gcflags <span class="hljs-string">'-N -l'</span> main.go
$ ls
main main.go</code></pre>
<p>lldbコマンドに作成されたファイルを渡してみます。</p>
<pre class="prettyprint"><code class="language-bash hljs ">$ lldb main
(lldb) target create <span class="hljs-string">"main"</span>
Current executable <span class="hljs-keyword">set</span> to <span class="hljs-string">'main'</span> (x86_64).
(lldb) </code></pre>
<p>ここから先はlldbの操作になります。とりあえず <code>q</code> と打つとlldbから抜けられることだけは覚えてください。</p>
<p>デバッグを開始するには <code>run</code> または <code>r</code> と打ちます。</p>
<pre class="prettyprint"><code class="language-bash hljs ">(lldb) run
Process <span class="hljs-number">22044</span> launched: <span class="hljs-string">'/Users/kmtr/misc/c/main'</span> (x86_64)
Add1(<span class="hljs-number">10</span>) == <span class="hljs-number">11</span>
Process <span class="hljs-number">22044</span> exited with status = <span class="hljs-number">0</span> (<span class="hljs-number">0</span>x00000000)
(lldb) </code></pre>
<p>無事実行されました。 <br>
これではデバッグにならないので、ブレイクポイントを打ちます。 <br>
試しに6行目と12行目に打ってみます。ブレイクポイントを打つ方法はいくつかありますが、行番号指定の場合 <code>b ソースファイル名:行番号</code> が楽です。</p>
<pre class="prettyprint"><code class=" hljs avrasm">(lldb) b main<span class="hljs-preprocessor">.go</span>:<span class="hljs-number">6</span>
Breakpoint <span class="hljs-number">1</span>: where = main`main<span class="hljs-preprocessor">.main</span> + <span class="hljs-number">31</span> at main<span class="hljs-preprocessor">.go</span>:<span class="hljs-number">6</span>, address = <span class="hljs-number">0x000000000000205f</span>
(lldb) b main<span class="hljs-preprocessor">.go</span>:<span class="hljs-number">12</span>
Breakpoint <span class="hljs-number">2</span>: where = main`main<span class="hljs-preprocessor">.Add</span>1 + <span class="hljs-number">9</span> at main<span class="hljs-preprocessor">.go</span>:<span class="hljs-number">12</span>, address = <span class="hljs-number">0x0000000000002199</span>
(lldb) </code></pre>
<p><code>br list</code> もしくは <code>b</code> と打つと、現在のブレイクポイントの一覧が表示されます。 <br>
<code>br delete ブレイクポイント番号</code> で対象のブレイクポイントを削除できます。 <br>
2番のブレイクポイントを消した後、再度ブレイクポイントを一覧表示して削除されることを確認してみてください。</p>
<p>ブレイクポイントを打った状態で再び <code>run</code> すると、こんな感じに止まります。</p>
<pre class="prettyprint"><code class="language-bash hljs "> <span class="hljs-number">3</span> import <span class="hljs-string">"fmt"</span>
<span class="hljs-number">4</span>
<span class="hljs-number">5</span> func <span class="hljs-function"><span class="hljs-title">main</span></span>() {
-> <span class="hljs-number">6</span> a := <span class="hljs-number">10</span>
<span class="hljs-number">7</span> fmt.Printf(<span class="hljs-string">"Add1(10) == %d\n"</span>, Add1(a))
<span class="hljs-number">8</span> }
<span class="hljs-number">9</span>
(lldb) </code></pre>
<p>ステップオーバーは <code>n</code> です。打ってみるとカーソルが7行目に移ると思います。<code>fr v 変数名</code> で変数の中身を表示できるので打ってみます。</p>
<pre class="prettyprint"><code class="language-bash hljs ">(lldb) fr v a
(long) a = <span class="hljs-number">10</span>
(lldb) </code></pre>
<p>なぜかlongですが、とりあえずの確認には十分です。 <br>
現在のブレイクポイント周辺のソースを再表示する場合は <code>f</code> と打ちます。</p>
<p>ソースレベルでのステップインは <code>s</code> です。7行目で実行すると次のようにAdd1関数の中に入ると思います。</p>
<pre class="prettyprint"><code class="language-bash hljs "> <span class="hljs-number">9</span>
<span class="hljs-number">10</span> // Add1 ...
<span class="hljs-number">11</span> func Add1(i int) int {
-> <span class="hljs-number">12</span> <span class="hljs-keyword">return</span> i + <span class="hljs-number">1</span>
<span class="hljs-number">13</span> }
(lldb) </code></pre>
<p><code>fr v</code> と変数名を指定せずに打つと、現在のフレームの変数が全て表示されます。</p>
<pre class="prettyprint"><code class="language-bash hljs ">(lldb) fr v
(long) i = <span class="hljs-number">10</span>
(long) ~r1 = <span class="hljs-number">0</span>
(lldb) </code></pre>
<p>(<code>~r1</code> てなんだろう、、、)</p>
<p><code>c</code> と打つと、次のブレイクポイント、もしくは終了するまで停止せずに実行されます。</p>
<pre class="prettyprint"><code class="language-bash hljs ">(lldb) c
Process <span class="hljs-number">22103</span> resuming
Add1(<span class="hljs-number">10</span>) == <span class="hljs-number">11</span>
Process <span class="hljs-number">22103</span> exited with status = <span class="hljs-number">0</span> (<span class="hljs-number">0</span>x00000000)
(lldb) </code></pre>
<p>LLDBの使い方は、<a href="http://lldb.llvm.org/index.html">The LLDB Debugger</a> のgdbとの比較がわかりやすいです。 <br>
watchが効かないという話も見かけましたが、少なくとも私の環境では問題ありませんでした。</p>
<h2 id="感想">感想</h2>
<p>少ししか使っていないので、どこまでちゃんと動くのか、GDBとの差がどれだけあるかわからないけど、LLDBでもデバッグはできそうです。</p>
<p>続くかもしれない。</p>亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-38944021670771977982015-05-13T22:41:00.001+09:002015-05-14T08:04:09.594+09:00Goで書かれたHTTP2対応サーバーCADDYを試す<p>CADDYというHTTP2対応サーバーを見つけたので簡単に使ってみる。</p>
<p><a href="https://caddyserver.com/">https://caddyserver.com/</a></p>
<p>Goで書かれていて、インストールは各プラットホーム毎のバイナリを適当に配置するだけなので、インストールが楽。</p>
<h2 id="起動する">起動する</h2>
<p>とりあえずPATHが通っているところに置いて叩いてみる。</p>
<pre class="prettyprint"><code class="language-sh hljs ruby"><span class="hljs-variable">$ </span>caddy
<span class="hljs-number">0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">2015</span></code></pre>
<p>デフォルトポートが2015なのだけど、来年になったら2016になるのだろうか。</p>
<p>curlで叩いてヘッダを見てみる。</p>
<pre class="prettyprint"><code class="language-sh hljs lasso">$ curl <span class="hljs-attribute">-I</span> localhost:<span class="hljs-number">2015</span>
HTTP/<span class="hljs-number">1.1</span> <span class="hljs-number">404</span> <span class="hljs-literal">Not</span> Found
Server: Caddy
<span class="hljs-built_in">Date</span>: Tue, <span class="hljs-number">12</span> May <span class="hljs-number">2015</span> <span class="hljs-number">13</span>:<span class="hljs-number">52</span>:<span class="hljs-number">04</span> GMT
Content<span class="hljs-attribute">-Length</span>: <span class="hljs-number">13</span>
Content<span class="hljs-attribute">-Type</span>: text/plain; charset<span class="hljs-subst">=</span>utf<span class="hljs-subst">-</span><span class="hljs-number">8</span></code></pre>
<p>404だけど、とりあえず動いている。HTTP2はHTTPSじゃないと動かないので、HTTP/1.1なのが残念。 <br>
(CADDYのサイトはCADDYでホストされていて、HTTP2が使われていることをブラウザで確認しています)</p>
<h2 id="設定を変える">設定を変える</h2>
<p>CADDYの設定ファイルは<code>-conf</code>オプションで任意のファイルを指定出来るけど、デフォルトではコマンドを叩いたディレクトリにあるCaddyfileを見るらしい。 <br>
1行目には必ずlistenするアドレスを書けということなので、ポートをデフォルトから変更したものを記述してみる。</p>
<pre class="prettyprint"><code class=" hljs ruby"><span class="hljs-variable">$ </span>echo <span class="hljs-string">"localhost:2016"</span> > <span class="hljs-constant">Caddyfile</span>
<span class="hljs-variable">$ </span>caddy
<span class="hljs-symbol">localhost:</span><span class="hljs-number">2016</span></code></pre>
<p>無事ポート2016で起動した。 <br>
ちなみに1行目と言うのは、設定値としての1行目で、コメントは普通にかける。コメントはapacheと同様、<code>#</code>から始まる文字列。</p>
<h2 id="静的ファイル配信">静的ファイル配信</h2>
<p>このままでは404を返すだけのサーバーなので、とりあえず静的ファイルを返すようにしてみる。 <br>
まずはドキュメントルートとなるディレクトリを作り、適当なHTMLファイルを置く。</p>
<pre class="prettyprint"><code class="language-sh hljs ruby"><span class="hljs-variable">$ </span>mkdir public_html
<span class="hljs-variable">$ </span>echo <span class="hljs-string">"Hello, world"</span> > public_html/index.html</code></pre>
<p>次にCaddyfileをこんな感じに編集する。 <br>
<code>root</code>はドキュメントルートを指定するディレクティブ。カッコでくくらずに、そのまま次の行に書いてもよいのだけど、書いた方が分かりやすいと思う。</p>
<pre class="prettyprint"><code class=" hljs vala"><span class="hljs-preprocessor"># example</span>
localhost:<span class="hljs-number">2016</span> {
root ./public_html/
}</code></pre>
<p>再起動して、curlしてみる。</p>
<pre class="prettyprint"><code class="language-sh hljs ruby"><span class="hljs-variable">$ </span>curl <span class="hljs-symbol">localhost:</span><span class="hljs-number">2016</span>
<span class="hljs-constant">Hello</span>, world</code></pre>
<p>無事、静的ファイルを配信出来た。</p>
<h2 id="markdown配信">markdown配信</h2>
<p>リダイレクトやプロキシといった機能の他に、CADDY特有の機能がいくつかある。その一つのmarkdown配信機能を使ってみる。</p>
<p>設定はmarkdownディレクティブの後ろに、適用するPATHを記述する。このPATHはリクエストのパスであると同時にmarkdownファイルを置くディレクトリの事も示すらしい。 <br>
つまりmarkdownファイルは、public_html/blogではなくblogというディレクトリに置く必要がある。</p>
<pre class="prettyprint"><code class=" hljs vala"><span class="hljs-preprocessor"># example</span>
localhost:<span class="hljs-number">2016</span> {
root ./public_html/
markdown /blog
}</code></pre>
<p>次に記事を作る。</p>
<pre class="prettyprint"><code class="language-bash hljs ">$ mkdir blog
$ <span class="hljs-built_in">echo</span> <span class="hljs-string">"# Hello, markdown"</span> > blog/hello.md </code></pre>
<p>curlで確認。</p>
<pre class="prettyprint"><code class="language-sh hljs xml">$ curl localhost:2016/blog/hello.md
<span class="hljs-doctype"><!DOCTYPE html></span>
<span class="hljs-tag"><<span class="hljs-title">html</span>></span>
<span class="hljs-tag"><<span class="hljs-title">head</span>></span>
<span class="hljs-tag"><<span class="hljs-title">title</span>></span># Hello, markdown<span class="hljs-tag"></<span class="hljs-title">title</span>></span>
<span class="hljs-tag"><<span class="hljs-title">meta</span> <span class="hljs-attribute">charset</span>=<span class="hljs-value">"utf-8"</span>></span>
<span class="hljs-tag"></<span class="hljs-title">head</span>></span>
<span class="hljs-tag"><<span class="hljs-title">body</span>></span>
<span class="hljs-tag"><<span class="hljs-title">h1</span>></span>Hello, markdown<span class="hljs-tag"></<span class="hljs-title">h1</span>></span>
<span class="hljs-tag"></<span class="hljs-title">body</span>></span>
<span class="hljs-tag"></<span class="hljs-title">html</span>></span></code></pre>
<p>ソースを確認したところ、markdownの処理には <a href="https://github.com/russross/blackfriday">https://github.com/russross/blackfriday</a> を使っていた。</p>
<h2 id="性能">性能</h2>
<p>性能について、FAQには正確に答えるのは難しいとしながら、概ね速いと書いてある。 <br>
Apacheよりは速くて、nginxよりちょっと遅いぐらいという事なので、実用上十分な速さと思っておけば良さそう。 <br>
CADDYのコンセプトは設定が簡単なWebサーバなので、それでよいのだと思う。</p>
<h2 id="感想">感想</h2>
<p>全部の機能を試したわけではないけど、1バイナリで完結して、設定が簡単に出来て、それなりに速いという使い勝手の良いサーバーという印象。 <br>
ちょっとしたサーバーが欲しいのだけど、Apacheやnginxだと大げさ過ぎるとか、設定が面倒という時に重宝しそう。</p>
<p>あとはfcgiを使ったプロジェクトのルートディレクトリにCaddyfileを置いといて、git cloneしてcaddyと叩いたら開発環境として立ち上がるみたいな使い方とか。</p>
<p>小回りが効くので、応用範囲が広そう。</p>亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-6081514092795106972015-04-29T09:10:00.001+09:002015-04-29T11:05:55.373+09:00Goのtesting/quickを簡単に触ってみる<p>Goのpackageを眺めていたら、いまさらtesting/quickというものを見つけたので試してみる。 <br>
quickの説明をみると、</p>
<blockquote>
<p>help with black box testing</p>
</blockquote>
<p>と書いてあるし、Checkという関数があったりするので、QuickCheckのためのパッケージのはず。</p>
<h2 id="普通のtest">普通のtest</h2>
<p>まずはquickを使わないテスト。 <br>
2つのintで割り算をする関数のテスト。</p>
<pre class="prettyprint"><code class="language-go hljs "><span class="hljs-keyword">package</span> main
<span class="hljs-keyword">import</span> <span class="hljs-string">"testing"</span>
<span class="hljs-keyword">func</span> div(n, m <span class="hljs-typename">int</span>) <span class="hljs-typename">int</span> {
<span class="hljs-keyword">return</span> n / m
}
<span class="hljs-keyword">func</span> TestDiv(t *testing.T) {
<span class="hljs-keyword">if</span> div<span class="hljs-number">(4</span>,<span class="hljs-number"> 2</span>) !=<span class="hljs-number"> 2</span> {
t.Error(<span class="hljs-string">"error!"</span>)
}
<span class="hljs-keyword">if</span> div<span class="hljs-number">(3</span>,<span class="hljs-number"> 2</span>) !=<span class="hljs-number"> 1</span> {
t.Error(<span class="hljs-string">"error!"</span>)
}
}</code></pre>
<p>明らかにテストケースが不足してる。 <br>
とりあえず第二引数に0を入れたら、確実にエラーになるはずだけど、このケースでは考慮されていない。</p>
<h2 id="quick導入">quick導入</h2>
<p>というわけでquickを導入。</p>
<pre class="prettyprint"><code class="language-go hljs "><span class="hljs-keyword">package</span> main
<span class="hljs-keyword">import</span> (
<span class="hljs-string">"fmt"</span>
<span class="hljs-string">"testing"</span>
<span class="hljs-string">"testing/quick"</span>
)
<span class="hljs-comment">// テスト回数計測のためのカウンター</span>
<span class="hljs-keyword">var</span> count <span class="hljs-typename">int</span> =<span class="hljs-number"> 0</span>
<span class="hljs-keyword">func</span> div(n, m <span class="hljs-typename">int</span>) <span class="hljs-typename">int</span> {
count++
<span class="hljs-keyword">return</span> n / m
}
<span class="hljs-keyword">func</span> TestDiv(t *testing.T) {
f := <span class="hljs-keyword">func</span>(x, y <span class="hljs-typename">int</span>) <span class="hljs-typename">bool</span> {
<span class="hljs-keyword">return</span> div(x, y) == (x / y)
}
<span class="hljs-keyword">if</span> err := quick.Check(f, <span class="hljs-constant">nil</span>); err != <span class="hljs-constant">nil</span> {
t.Error(err.Error())
}
fmt.Printf(<span class="hljs-string">"テスト回数:%d\n"</span>, count)
}</code></pre>
<p>これで<code>go test</code>してみる。</p>
<pre class="prettyprint"><code class="language-sh hljs ruby"><span class="hljs-variable">$ </span>go test
テスト回数<span class="hljs-symbol">:</span><span class="hljs-number">100</span>
<span class="hljs-constant">PASS</span>
ok quick_example <span class="hljs-number">0</span>.<span class="hljs-number">005</span>s</code></pre>
<p>通ってしまった。 <br>
quickというかQuickTestは要はとにかくいろいろ試してみるテストなので、100回程度では通ってしまうのも仕方ない。 <br>
今回の場合、第二引数に0が入るのは 「1/intの取りうる値」 なので、試行回数が全然足りない。</p>
<h2 id="試行回数を変える">試行回数を変える</h2>
<p>ということで試行回数を増やしてみる。 <br>
試行回数の設定をするには、quick.Configのインスタンスを作って、 <br>
MaxCountに試行回数を設定する。</p>
<pre class="prettyprint"><code class="language-go hljs "><span class="hljs-keyword">package</span> main
<span class="hljs-keyword">import</span> (
<span class="hljs-string">"fmt"</span>
<span class="hljs-string">"testing"</span>
<span class="hljs-string">"testing/quick"</span>
)
<span class="hljs-keyword">var</span> count <span class="hljs-typename">int</span> =<span class="hljs-number"> 0</span>
<span class="hljs-keyword">func</span> div(n, m <span class="hljs-typename">int</span>) <span class="hljs-typename">int</span> {
count++
<span class="hljs-keyword">return</span> n / m
}
<span class="hljs-keyword">func</span> TestDiv(t *testing.T) {
f := <span class="hljs-keyword">func</span>(x, y <span class="hljs-typename">int</span>) <span class="hljs-typename">bool</span> {
<span class="hljs-keyword">return</span> div(x, y) == (x / y)
}
config := &quick.Config{
MaxCount:<span class="hljs-number"> 10000</span>,
}
<span class="hljs-keyword">if</span> err := quick.Check(f, config); err != <span class="hljs-constant">nil</span> {
t.Error(err.Error())
}
fmt.Printf(<span class="hljs-string">"テスト回数:%d\n"</span>, count)
}</code></pre>
<p>そして<code>go test</code>する。</p>
<pre class="prettyprint"><code class="language-sh hljs ruby"><span class="hljs-variable">$ </span>go test
テスト回数<span class="hljs-symbol">:</span><span class="hljs-number">10000</span>
<span class="hljs-constant">PASS</span>
ok quick_example <span class="hljs-number">0</span>.<span class="hljs-number">015</span>s</code></pre>
<p>通ってしまった。 <br>
<code>math.MaxInt64</code>を突っ込めば確実に失敗するのだろうけど、 <br>
それは最早ブラックボックステストではない。 <br>
(ちなみにMaxInt64でやってみたら、手元のマシンでは3分経っても終わらなかった) </p>
<h2 id="テスト値を制御する">テスト値を制御する</h2>
<p>とはいえ、0ぐらい入れて欲しい。 <br>
ブラックボックステストと言っても、本当に無作為に値を突っ込むのではなく、とりあえず0から100と、0から-100で動いてもらえば最低限の仕様は満たすという事はままある。 <br>
そのように、自分でランダム性を制御するにはconfig.Valuesに値を生成する関数を設定する。</p>
<p>値を生成する関数は<code>func(args []reflect.Value, rand *rand.Rand)</code>というシグネチャを持つ。 <br>
<code>args</code>には、quick.Check関数の第一引数に渡す関数の引数の数のサイズを持つスライスが渡されてくる。</p>
<p>今回のケースで、0から100の範囲の値を無作為に選ばせるのであれば、こんな感じの関数をconfig.Valuesに渡せば良い。</p>
<pre class="prettyprint"><code class=" hljs avrasm">func(args []reflect<span class="hljs-preprocessor">.Value</span>, rand *rand<span class="hljs-preprocessor">.Rand</span>) {
args[<span class="hljs-number">0</span>] = reflect<span class="hljs-preprocessor">.ValueOf</span>(rand<span class="hljs-preprocessor">.Intn</span>(<span class="hljs-number">100</span>))
args[<span class="hljs-number">1</span>] = reflect<span class="hljs-preprocessor">.ValueOf</span>(rand<span class="hljs-preprocessor">.Intn</span>(<span class="hljs-number">100</span>))
}</code></pre>
<p>これで10000回くらい回せば、流石にargs[1]に0が入るはず。</p>
<p>第二引数のrandは見ての通りRandインスタンスが渡ってくる。このRandインスタンスはconfig.Randで設定しないとデフォルトのものが使われるのだけど、go 1.4.2ではデフォルトのrandはseedが0固定されているので、変えないと毎回同じ結果になる(デフォルトのseed=0は意図したものなのか?)。</p>
<p>上記を踏まえるとこんな感じのソースになる。</p>
<pre class="prettyprint"><code class="language-go hljs "><span class="hljs-keyword">package</span> main
<span class="hljs-keyword">import</span> (
<span class="hljs-string">"math/rand"</span>
<span class="hljs-string">"reflect"</span>
<span class="hljs-string">"testing"</span>
<span class="hljs-string">"testing/quick"</span>
<span class="hljs-string">"time"</span>
)
<span class="hljs-keyword">var</span> count <span class="hljs-typename">int</span> =<span class="hljs-number"> 0</span>
<span class="hljs-keyword">func</span> div(n, m <span class="hljs-typename">int</span>) <span class="hljs-typename">int</span> {
count++
<span class="hljs-keyword">return</span> n / m
}
<span class="hljs-keyword">func</span> TestDiv(t *testing.T) {
f := <span class="hljs-keyword">func</span>(x, y <span class="hljs-typename">int</span>) <span class="hljs-typename">bool</span> {
<span class="hljs-keyword">return</span> div(x, y) == (x / y)
}
config := &quick.Config{
MaxCount:<span class="hljs-number"> 10000</span>,
Rand: rand.New(rand.NewSource(time.Now().UTC().UnixNano())),
Values: <span class="hljs-keyword">func</span>(args []reflect.Value, rand *rand.Rand) {
args<span class="hljs-number">[0</span>] = reflect.ValueOf(rand.Intn<span class="hljs-number">(100</span>))
args<span class="hljs-number">[1</span>] = reflect.ValueOf(rand.Intn<span class="hljs-number">(100</span>))
},
}
<span class="hljs-keyword">if</span> err := quick.Check(f, config); err != <span class="hljs-constant">nil</span> {
t.Error(err.Error())
}
fmt.Printf(<span class="hljs-string">"テスト回数:%d\n"</span>, count)
}</code></pre>
<p>これで<code>go test</code>すると、まず確実にこんなかんじで0除算エラーが発生する。めでたしめでたし。</p>
<blockquote>
<p>— FAIL: TestDiv (0.00s) <br>
panic: runtime error: integer divide by zero [recovered] <br>
panic: runtime error: integer divide by zero</p>
</blockquote>
<h2 id="まとめ">まとめ</h2>
<p>今回はquickを使うというのが目的なので、こんな感じのテストコードになったけど、実際には普通のテスト(=ホワイトボックステスト)と組み合わせて使うはず。 <br>
ブラックボックステストはホワイトボックスを置き換えるものではないし。 <br>
といっても、特に難しく考えず、とりあえず値を大量に作ってくれる装置として使うだけでも恩恵があるかと。今回のように完全な無作為ではなく、そこそこの無作為にしてグレーボックスとして使ったりとか。</p>
<p>quick固有の問題として、デフォルトのRandがseed=0で初期化されているという点だけは要注意ですね。</p>亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-89286297389779773502015-02-17T01:53:00.001+09:002015-04-29T10:56:47.387+09:00Firefox OS WoTハッカソンに参加してきた<p>2/14-15に行われたFirefox OS WoTハッカソンに参加してきました。</p>
<p>申し込んだ時点で70名の募集のところ既にいっぱいで、補欠でしたが数日でキャンセルが何人か出て、繰り上がりで参加出来ることになりました。 <br>
終わった今、改めて見てみたら50位ぐらいまで繰り上がっていたので、こういうのは諦めたら駄目ですね。</p>
<h2 id="アイディア出し">アイディア出し</h2>
<p>初日は企画コンセプトやWoTの概要説明から始まり、アイディア出し&チーム決め。 <br>
最終的には、以下にまとめられているものを作ったわけですが、 <br>
<a href="http://fabble.cc/dobogo/pitagoraxsugoroku">http://fabble.cc/dobogo/pitagoraxsugoroku</a> <br>
いきなり「要件定義」に書いているような立派な案が出たわけではなく、お菓子を食べつつ、光らせたいとか、NFCを使いたいという、使いたいものベースで、だらだらとホワイトボードに書き付けていました。 <br>
途中でゲーム的なものや動きのあるものが作りたいという流れになり、すごろくというアイディアと、ピラゴラ装置というアイディアが発生。それらを組み合わせた「いろんな仕掛けのあるすごろく」になっていきました。 <br>
当初、そのすごろくはFx0を持った人間が歩き回るという話になっていましたが、どこかのタイミングでロボット(この時点ではふぉくすけの存在は無く、車に乗せたFx0)に移動させるというアイディアが出てきて「すごろく」と「ロボット」の二本立てとなりました。 <br>
最終的に、今回はインパクト重視で「ロボット」に注力し、すごろくは余力があったらという方針になりました。 <br>
ふぉくすけが採用された経緯が記憶からすっぽり抜けていますが、他のチームの方から、ふぉくすけのヌイグルミをお借りして、ふぉくすけロボという具体的なゴールが昼食前には完成しました。</p>
<h2 id="設計と実装">設計と実装</h2>
<p>ロボットの方針が出たあたりで、ざっくりとどういうモジュールが必要かと、それぞれの間のやり取りの図を書き、それを元に役割分担をしました。私はhttpd.jsを使って、Fx0内で動くサーバーの実装を担当しました。 <br>
ふぉくすけロボは、足と尻尾はmbedで制御されているのですが、その指示はFx0からHTTPで、mbed側のサーバに飛ばしています。私が作ったのは、リモコン側からのリクエストをそのままmbedに飛ばす、一種のリバースプロキシというわけです。 <br>
とりあえずリモコン担当の方、mbed担当の方と、ざっくり必要そうなAPIを相談し実装。 <br>
mbedが制御しない、表情制御については、並行で作られている表情プログラムを呼び出す事になるので、一旦呼び出し口だけを用意しておきました。</p>
<p>実装そのものは大したことが無いのですが、テストが大変でした。ひとまずFx0にインストールしてみて動かしてみたのですが、デバッガにソースが出てこない。console.logも出てこない(確か)。 <br>
仕方がないので、FirefoxのWebIDEからシミュレータを起動して、そこでテストしようとするも、バージョン2.1以降(unstable)でないとやはりソースが出てこない。 <br>
やっとデバッガにソースが出たと喜んだものの、コールバック内のブレイクポイントは機能しないという状況でした。Flame(fxos ver3.0?)をお借りして試してみたところ、シミュレータと同様の状態だったため、console.logでプリントデバッグで進めました。</p>
<p>また、初日はネットワーク環境が不安定で、テスト用の無線LANになかなか繋げられず、mbed側サーバーとの疎通が安定して出来るようになったのは2日目になってからでした。 <br>
今回のハッカソンはWoTがテーマになっていますが、実際のWoTの現場でも、安定したネットワークの確保は課題になると思います。</p>
<p>もう一つ大変だったのは、現状のhttpd.jsのパスHandler機能、要するに静的ファイル配信の機能がFx0でしか動作しないことでした。リモコンは静的なHTML+JSで書かれているので、これをロボット側のFx0から配信しようとしたのですが、シミュレータやFlameでは動作せず、しばらくたってFx0で試して、初めて機能する事を確認しました。</p>
<p>そんな新しい端末やOSらしいトラブルに見舞われながらも、何とかかんとか、ふぉくすけロボを完成させることができました。</p>
<h2 id="デモ">デモ</h2>
<p>完成したふぉくすけロボですが、mbed側は、mbed + 無線LANモジュール + モーター*3という構成のため、非常に電気を使うようです。さらに、それを乾電池だけで動かしているため、下手に動かすとデモが出来ない恐れがありました。 <br>
それでも、デモの数分間、ふぉくすけロボは頑張ってくれて、おかげさまでARM賞もいただけました。</p>
<h2 id="firefox-osに対する感想">Firefox OSに対する感想</h2>
<p>Firefox OSは使う分には、特に問題無いレベルにあると思います。少なくともFx0やFlameは、スマートフォンとして普段使うのに必要十分な動作をしていました。 <br>
開発環境も、若干使いづらいところはあるものの、今後改善していくだろうし、何よりWeb技術でアプリが作れるという特性は、潜在的な開発者数が、AndroidやiOS以上に存在しているという事を示しています。httpd.jsは普通のアプリにはまず使われないと思われるので、今回ほどの苦労はしないはずです。</p>
<p>また今回はFirefoxOSの端末としてFx0を使うことが、ある種の縛りとしてあったのですが、他のチームの発表を見ると、Fx0ではなくOpen Web Boardを主にしたものもいくつかあり、スマートフォン以外の応用可能性が、Firefoxには十分あるように思います。</p>
<h2 id="ふぉくすけロボの発展">ふぉくすけロボの発展</h2>
<p>ふぉくすけロボはその動きをリモコンに頼っていたわけですが、リモコンからは単にHTTPでリクエストを飛ばしているだけです。つまりロボのFx0にHTTPに投げられる存在であれば、何であれふぉくすけロボを操作出来るわけです。 <br>
今回作れなかったすごろく側ですが、センサーとHTTPクライアントを埋めた壁、床を作ることで、すごろくがふぉくすけを動かす仕組みなんかが作れると、わけがわからなくて良いと思います。</p>
<p>それと懇親会の最後で、ふぉくすけが出た状態のFx0をお面のようにしたのですが、カメラAPIと組み合わせて、任意の顔をお面にするアプリが作れるなあと考えていました。 <br>
問題はFx0もFlameも持っていないことなわけですが。 <br>
今後機会があれば作りたいです。</p>亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-30275847059608434682015-01-23T00:04:00.003+09:002015-02-17T01:54:43.991+09:00天丼屋さんを教える今回教えたのは天丼屋さんの場所。
平日でもお昼には行列が出来るくらい有名で、一度行ったことがあるけど確かにおいしかった。
駅から少し離れているのが難点で、今回道を聞かれたおじいさんも、駅から歩いてきて、なかなか辿り着けずに不安だった様子。
道沿いにあるので、見逃すことは無いはず。亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-25560804112724535022015-01-22T23:54:00.001+09:002015-01-23T00:00:08.163+09:00CarthageでGPUImageをSwiftから使う<h1 id="carthageでgpuimageをswiftから使う">CarthageでGPUImageをSwiftから使う</h1>
<p>XCodeで何かを作ろうとした場合、標準のframework以外のフレームワークを導入したくなります。 <br>
Objective-Cな時代にはCocoaPodsを使うのが定石だったようですが、Swift時代にはどうしたらよいのか、調べていたところCarthage(カルタゴ)というものが存在している事を知りました。</p>
<p><a href="https://github.com/Carthage/Carthage">https://github.com/Carthage/Carthage</a></p>
<p>備忘録代わりに、Carthageを使ってGPUImageを使ったアプリケーションを作成してみます。Carthageの使い方の説明を主とするため、アプリケーション自体は、GPUImageのSimpleSwiftVideoFilterExampleをそのまま用います。</p>
<p><a href="https://github.com/BradLarson/GPUImage/tree/master/examples/iOS/SimpleSwiftVideoFilterExample">https://github.com/BradLarson/GPUImage/tree/master/examples/iOS/SimpleSwiftVideoFilterExample</a></p>
<h2 id="0-前提">0. 前提</h2>
<p>この記事はYosemite 10.10.1、XCode 6.1.1の環境で確認しています。 <br>
Carthageは0.4.0を使いました。 <br>
実機確認する場合、実機とiOS Developer Programへの登録が必要となります。</p>
<h2 id="1-carthageのインストール">1. Carthageのインストール</h2>
<p>CarthageのREADME.mdを読めば分かりますが、pkgファイル、Homebrew、makeの3通りの方法でインストール出来ます。 <br>
私はHomebrewで<code>brew install carthage</code>しました。 <br>
2015-01-19時点で、Homebrew経由でインストールされるのは0.4.0でした。 <br>
pkg版は0.5.2まで上がっており、いろいろ機能が追加されているようですが、今回の場合は0.4.0の機能でも問題ありません。</p>
<h2 id="2-xcodeプロジェクトを作る">2. XCodeプロジェクトを作る</h2>
<p>ベースとなるXCodeプロジェクトを作ります。 <br>
XCodeを開き、”File -> New -> Project…”を選択し、”iOS -> SingleView Application”を選んで、Nextを押します。 <br>
次の画面でLanguageにSwiftを、DevicesにiPhoneを選びます。 <br>
他の項目は適当に入力してください。 <br>
Nextを押すと、プロジェクトの保存場所を選択すると、新しいプロジェクトが作られ、XCodeに表示されます。</p>
<h2 id="3-cartfileの作成">3. Cartfileの作成</h2>
<p>Cartfileを作成します。Cartfileは利用したいframeworkを記述したファイルです。npmのpackage.json、mvnのpomです。</p>
<p>作成したプロジェクトのディレクトリの*.xcodeprojと同じ階層に、Cartfileという名前のテキストファイルを作成し、以下のように記述します。</p>
<pre class="prettyprint"><code class=" hljs bash">git <span class="hljs-string">"https://github.com/BradLarson/GPUImage.git"</span> == <span class="hljs-number">0.1</span>.<span class="hljs-number">6</span></code></pre>
<p><code>==</code>の部分には他にも<code>~></code>と<code>>=</code>が使えます。バージョンはsemverで解決されるそうです。 <br>
対象となるリポジトリがgithubの場合、以下のような指定も出来ます。</p>
<pre class="prettyprint"><code class=" hljs bash">github <span class="hljs-string">"BradLarson/GPUImage"</span> == <span class="hljs-number">0.1</span>.<span class="hljs-number">6</span></code></pre>
<h2 id="4-外部フレームワークのビルド">4. 外部フレームワークのビルド</h2>
<p>ターミナルで、プロジェクトのディレクトリに移動します。 <br>
その位置で<code>carthage update</code>を実行すると、対象のgitリポジトリからソースコードがプロジェクトディレクトリ下の”Carthage/Checkouts/”以下にコピーされます。 <br>
その後、ビルドが実行され、生成物がプロジェクトディレクトリ下の”Carthage/Build”以下に出力されます。</p>
<h2 id="5-外部フレームワークをプロジェクトに追加">5. 外部フレームワークをプロジェクトに追加</h2>
<p>XCodeのプロジェクトのTARGETSのGeneralタブにある、”Linked frameworks and Libraries”に、”Carthage/Build/iOS/GPUImage.framework”をドラッグアンドドロップします。</p>
<p>次にBuild Phasesタブの左上にある”+”を押し、”New Run Script Phase”を選びます。 <br>
Shell欄の下の”Type a Script or …”と書いてある欄に、<code>/usr/local/bin/carthage copy-frameworks</code>と入力し、”Input Files”に<code>$(SRCROOT)/Carthage/Build/iOS/GPUImage.framework</code>と入力します。</p>
<p>ここまででCarthageを使って、frameworkを導入するという作業は終わりました。後はコードを書いていくだけです。</p>
<h2 id="6-コードを書く">6. コードを書く</h2>
<p>ここからはCarthageとは関係なく、GPUImageViewの使い方になります。 <br>
最初にMain.storyboardを開き、ViewのCustom ClassをGPUImageViewに変更します。</p>
<p>次にViewController.swiftの内容を、SimpleSwiftVideoFilterExampleのそれと同じにします。</p>
<p><a href="https://raw.githubusercontent.com/BradLarson/GPUImage/master/examples/iOS/SimpleSwiftVideoFilterExample/SimpleSwiftVideoFilterExample/ViewController.swift">https://raw.githubusercontent.com/BradLarson/GPUImage/master/examples/iOS/SimpleSwiftVideoFilterExample/SimpleSwiftVideoFilterExample/ViewController.swift</a></p>
<h2 id="7-実行する">7. 実行する</h2>
<p>iPhoneに転送して実行してみましょう。</p>
<h2 id="8-感想">8. 感想</h2>
<p>他言語における依存性解決ツールに比べると、やっていることは単純ですが、XCodeというGUIが大前提のツールと共存させようとすると、これが正解な気がします。 <br>
CocoaPodsとは違い、ソースのダウンロードとビルド以上の事は一切行わないところも、個人的には好感が持てます。 <br>
Bridging Headerもいらないので、これからは積極的に使っていき、かつ自分でライブラリを書くときも、*.frameworkを吐くように作ろうと思います。</p>
<iframe src="http://rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=kameturu-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=ss_til&asins=4800710707" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>
亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-22708132334212332332014-12-24T00:13:00.001+09:002014-12-24T00:13:50.581+09:00bingから画像をダウンロードしてMacの壁紙に設定するツールをGoで書いた<p><a href="http://www.bing.com/">bing</a>から画像をダウンロードしてMacの壁紙に設定するbinggoというツールをGoで書きました。</p>
<p><a href="https://github.com/kmtr/binggo">https://github.com/kmtr/binggo</a></p>
<p><code>go get github.com/kmtr/binggo</code>でインストール出来ます。</p>
<h2 id="-">なぜ書いたのか</h2>
<p>私はbingのトップページの画像が大好きで、Windowsの壁紙は<a href="http://www.bing.com/explore/desktop">Bingデスクトップ</a>を使って、毎日bingの画像が設定されるようにしています。
ですが、残念ながらBingデスクトップのMac版は存在していません。
無いのであれば作るしかないということで、書いてみました。
ちなみに同じことを考える人はそれなりにいるようで、Pythonやbash、Automatorによる同様のツールがすでに存在しています。
ただインストールが面倒であったり、私の環境での動作が不安定だったりと不満があったので、自分で書いてみました。</p>
<h2 id="-go-">なぜGoなのか</h2>
<p>Goが好きだからというのが最大の理由です。</p>
<p>前々からGoには少し触っていたのですが、Go Conference 2014 autumnに参加して自分の中のGo熱が高まり、何か書きたいけど丁度良いネタが無いかと考えていたところ、bingに「今日の画像をダウンロード」という機能が追加され、Goで書いてみようと思いつきました。
ただ機能が単純なのでchannelどころかgoroutineすら使わなかった(使うまでもなかった)のが少し残念でした。</p>
<h2 id="-">おまけ</h2>
<p>bingの過去画像が欲しい場合は、<a href="http://www.bing.com/gallery/">Bing Homepage Gallery</a>が便利です。</p>亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-1043908427817499002014-07-12T16:49:00.000+09:002014-07-12T16:49:34.102+09:00gulp-coffeekupを作りましたCoffeeKupというcoffee-scriptのソースコードがそのままテンプレートになるテンプレートライブラリがあります。<br />
どういう意味かは、公式サイトのデモを見ればなんとなく分かるかとおもいます。<br />
<br />
<a href="http://coffeekup.org/">coffeekup.org</a><br />
<br />
テンプレート言語としてはなんとなくjadeっぽいので、coffee-scriptを知らない人でも使うのは難しくないはずです。テキストをいちいちクォートしているあたりにcoffee-scriptそのものを使っている感が見て取れるかと思います。<br />
<br />
さて、これを静的HTMLの生成に使おうとしたのですが、CLIなコマンドは提供されているもののうまく動作せず、gulp経由でやってみようかと思ったら、今時にしては珍しくgulpプラグインがありませんでした(検索力不足かも)。<br />
想像ですが、サーバサイドでレンダリングするために利用する事がメインで、静的HTML出力はあまり力を入れていないのかな?<br />
ということでgulpプラグインを書いてみました。<br />
<br />
<a href="https://github.com/kmtr/gulp-coffeekup">https://github.com/kmtr/gulp-coffeekup</a><br />
<br />
手元ではとりあえず、動作を確認しています。<br />
<br />
(テンプレート言語がcoffee-scriptそのものである利点って何か実はよく分かっていない)亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-13883725811433557792014-06-10T07:00:00.003+09:002014-06-10T07:00:53.185+09:00丁目番地を聞かれたのでiPhoneで道案内今年は道案内の回数が多い気がする。
今回は家の近所で、丁目番地指定で道を聞かれた。
分かるわけが無いので、すぐにiPhoneを使用。
目的地はもう少し歩いたところだったのでそれを伝える。
年配の二人連れだったけど、無事辿り着けただろうか。亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-23225690867573105592014-03-05T07:50:00.003+09:002014-03-05T07:50:51.950+09:00都庁への入り方都庁、北庁舎外の中央公園側をふらふらしていたら、外国人カップルに英語で話しかけれられる。
都庁の中に入りたいが入り口が見つからないらしい。
あのあたり、ガラス張りで中に入れそうな雰囲気はあるのだけど、入るにはぐるっと回る必要がある。
聞く方はなんとかなるが、話せないのでついてくるようにジェスチャーして誘導。
若干適当な扱いだったかもしれないけど「アリガト」と言われたのでよしとしよう。
「Follow me.」 ぐらいは言えば良かったかな。亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-82570430098550324982014-02-25T23:13:00.001+09:002014-02-25T23:13:43.667+09:002014年初道案内今年初めての道案内の相手は外国人の方。
ビジネスビルの場所を聞かれたけれど、六本木ヒルズとかヒカリエみたいに商業施設がついているならともかく、ビジネスビルとなると即答出来ず。
今回もiPhoneを使って案内。
ほぼ夜だったけど、何かカンファレンスでもあったのかな?パーティーな服装ではなかった。亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-9633273933711921532013-10-17T07:22:00.000+09:002013-10-17T07:22:00.863+09:00小規模企業によるFOSS開発のモデルケースになりうるかもしれない事例最近は企業によるFOSS活動も活発になっています。<br />
そんな中で、今注目している一連の流れ。
<br />
<br />
<br />
そもそもの発端。20人/月のほとんどはサーバではなくアプリ側に使われているのだろうか。<br />
<a href="http://techwave.jp/archives/spika_launching.html">世界初 メッセンジャーアプリ「Spika」を完全オープンソースで公開、フロントからバックエンドまで提供</a>
<br />
<br />
<br />
問題点の指摘。最大の問題点である問題が指摘されているDBの部分は2013/10/16時点のコミットで完全に消去されているみたい。<br />
<a href="http://mask-legacy.tumblr.com/post/63466133306/phper-spika">レガシーズ公式ブログ PHPerはSpikaのどこを見たのか?</a>
<br />
<br />
<br />
そして有志?によって直す会が開かれるらしい。<br />
<a href="http://connpass.com/event/3698/">spika hackathon Spika-Server のコードを15年ぐらい若返らせます</a><br />
<br />
行数は少なめでやる事は決まっているので、設計上の問題が無ければ割と簡単なはずだけど、モダンになった後のコードで、元の企業の人たちがカスタマイズやコンサルティングができるようになるのかが気になるところ。
<br />
<br />
一番最初の記事中で、WordPressのような存在になりたいと言っているけど、WordPressもこんな問題を抱えている。せめてPSRの議論と投票には参加して欲しい。<br />
<a href="http://mask-legacy.tumblr.com/post/62315583278/in-wordpress-phpcon2013-wctokyo">レガシーズ公式ブログ 活動報告 「レガシーコード in WordPress」</a>亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-52942142531405629912013-08-04T10:27:00.005+09:002013-08-04T10:27:59.737+09:00夏の日に道を教える今回は新宿で若い男女の観光客。<br />
以前、外国人の方に聞かれたのと同じホテルの場所を聞かれる。有名なホテルなのかな?<br />
今回は歩道沿いにある地図でご案内。<br />
<br />
道を聞かれたのは日本人だけど、最近外国人観光客が多い印象。それもどうみてもお金の無さそうな大学生っぽい人たちとか、割と普通な家族。<br />
円安の効果?亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-58299183513034287222013-06-05T23:20:00.000+09:002013-06-05T23:21:12.859+09:00exportsされていないjavascriptやCoffeeScriptのメソッドをテストする。半分以上、自分向けメモ。
<br />
<br />
exportsされていないjavascriptのメソッドをテストするにはどうするか。<br />
理屈としては、以下の記事2つを読めばOK。要はjsを別コンテクストにロードして、その時にプライベートなメソッドを引き上げるわけですね。<br />
<br />
<a href="http://howtonode.org/testing-private-state-and-mocking-deps">Testing Private State and Mocking Dependencies</a><br />
<a href="http://nazomikan.hateblo.jp/entry/2013/04/10/032410">Nodeでプライベートな(exportsされてない)メソッドのテスト</a><br />
<br />
不思議なのは、どちらの記事でも、<a href="https://github.com/vojtajina/node-mocks">node-mocks</a>に触れられていない事(一番目の記事のコメントで触れられているだけ)。<br />
これは一番目の記事のvojtajinaさんが作ったライブラリで、ざっくり言えば、解説されている内容が実装されているテスト用のライブラリ。<br />
これを使えば、いちいち上記解説記事のコードを書かなくて済むわけですね。めでたしめでたし。<br />
<br />
と思ったのですが、このライブラリ、JSは読み込めるのだけど、CoffeeScriptを直接読み込むことが出来ません(README.mdのサンプルテストコードはCoffeeScriptで書かれているのに)。<br />
もちろん、JSにコンパイルすればよいのだけど、面倒なわけです。<br />
<br />
というわけで、CoffeeScriptをロード出来るようにしてみました。<br />
<br />
<a href="https://github.com/kmtr/node-mocks/tree/coffeescript">https://github.com/kmtr/node-mocks/tree/coffeescript</a><br />
<br />
npmでインストールするなら、以下を実行。<br />
<pre><code class="shell">
</code></pre>
<pre><code class="shell">npm install https://github.com/kmtr/node-mocks/tarball/coffeescript --save-dev</code></pre>
<br />
可能な限りCoffeeScriptから出ずに、開発したい私みたいな人におすすめです。<br />
<br />
一応、pull requestを送ってみたけどどうだろうか。<br />
オリジナルと比べてcoffee-scriptへの依存が増えてしまったし。亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-2839645104411723452013-05-04T22:56:00.004+09:002013-05-04T22:56:57.997+09:00雨の日に道を教える今回は夜に家の近所。
雨が降る中、傘もささず(酔って?)ふらふらしているお爺さんから、橋の方に行きたいと聞かれる。
歩けない距離ではないけど、大丈夫だったろうか。亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-56620492296435444732012-12-27T20:50:00.003+09:002012-12-27T20:52:48.727+09:00DBFluteをCDIで使ってみる(適当レベル)Javaでは当たり前になったDI。SpringやSeasar2、Guiceが有名ですが、JavaEEにもCDIというDIシステムがあります。今年出たばかりとかではなく、2009年に出ています。標準規格なのにあまり注目されていない、というかSpringやSeasar2は知っていても、CDIは知らないというケースもままあるという。<br />
でもJavaEEの一部という事は、JavaEE対応のアプリケーションサーバなら追加のjar無しで使えるわけで、依存するjarを減らせるわけです。<br />
<br />
一方、これまた当たり前になったORMはhibernateの方向性が主流になりつつあるも、やはりSQLで書きたいケースも多く、というかRDBに問い合わせるならSQLを使うのが結局楽だったりするわけです。とはいえSQLを生で書くというのもあり得ないですよね。結果はオブジェクトとして受け取りたいし。という要求の元、DBFluteやDomaやMyBatisと言った、SQLと親和性のあるORMも根強い人気があります。<br />
私も基本的にはSQL大好きなので、これらのORMを使いたいわけです。<br />
<br />
DIは標準規格のCDIを、ORMは手のひら返してJPA系ではないものを使うわがままをなんとか実現したい。で、幸いにもDBFlute、Doma、MyBatisのどれもCDIで使えるらしい。という事でDBFluteでCDIを試してみました。DBFluteを選んだ理由は最近1.0になったからというだけ。<br />
ちなみにCDIも初体験。<br />
とりあえず深く考えずに、GlassFish 3.1.2 + DBFlute 1.0 + Derbyでやってみる事に。<br />
<br />
DBFluteのドキュメントを見つつ、以下のようにセッティング。<br />
<pre style="border: thin solid;"><code>
mvn dbflute:download
mvn dbflute:create-client
#DDLを書いたり、dfpropを編集したり
mvn dbflute:replace-schema
mvn dbflute:jdbc
mvn dbflute:generate
</code></pre>
<br />
これでDBFlute側の準備は完了。WEB-INFの下にbeans.xmlという名前のファイルを置いて、CDIを有効にする。これで設定はすべて完了したはず。という事でGlassFIshに乗せてみると、こんなエラーが発生。
<br />
<pre style="max-height: 10em; overflow: auto;border: thin solid;"><code>
デプロイメント中にエラーが発生しました: Exception while loading the app : Exception List with 5 exceptions:
Exception 0 :
org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies for type [EmployeeBhv] with qualifiers [@Default] at injection point [[field] @Inject com.example.servlet.EmployeeServlet.employeeBhv]. Possible dependencies [[Managed Bean [class com.example.dbflutecdi.db.exbhv.EmployeeBhv] with qualifiers [@Any @Default], com.example.dbflutecdi.db.allcommon.DBFluteModule$DBFluteBean@422f8df7]]
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:314)
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:280)
at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:143)
at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:163)
at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:382)
at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:367)
at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:380)
at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:199)
at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:128)
at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:313)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:461)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:240)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:389)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:348)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:363)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1085)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1200(CommandRunnerImpl.java:95)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1291)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1259)
at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:461)
at com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:212)
at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:179)
at com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:117)
at com.sun.enterprise.v3.services.impl.ContainerMapper$Hk2DispatcherCallable.call(ContainerMapper.java:354)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:722)
Exception 0 :
org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [DataSource] with qualifiers [@Default] at injection point [[parameter 1] of [method] @Inject public com.example.dbflutecdi.db.allcommon.ImplementedInvokerAssistant.setDataSource(DataSource)]
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:311)
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:280)
at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:143)
at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:163)
at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:382)
at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:367)
at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:380)
at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:199)
at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:128)
at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:313)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:461)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:240)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:389)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:348)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:363)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1085)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1200(CommandRunnerImpl.java:95)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1291)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1259)
at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:461)
at com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:212)
at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:179)
at com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:117)
at com.sun.enterprise.v3.services.impl.ContainerMapper$Hk2DispatcherCallable.call(ContainerMapper.java:354)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:722)
Exception 0 :
org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies for type [CommonColumnAutoSetupper] with qualifiers [@Default] at injection point [[parameter 1] of [method] @Inject public com.example.dbflutecdi.db.bsbhv.BsEmployeeBhv.setCommonColumnAutoSetupper(CommonColumnAutoSetupper)]. Possible dependencies [[Managed Bean [class com.example.dbflutecdi.db.allcommon.ImplementedCommonColumnAutoSetupper] with qualifiers [@Any @Default], com.example.dbflutecdi.db.allcommon.DBFluteModule$DBFluteBean@14423bc8]]
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:314)
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:280)
at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:143)
at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:163)
at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:382)
at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:367)
at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:380)
at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:199)
at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:128)
at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:313)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:461)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:240)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:389)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:348)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:363)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1085)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1200(CommandRunnerImpl.java:95)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1291)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1259)
at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:461)
at com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:212)
at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:179)
at com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:117)
at com.sun.enterprise.v3.services.impl.ContainerMapper$Hk2DispatcherCallable.call(ContainerMapper.java:354)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:722)
Exception 0 :
org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [DataSource] with qualifiers [@Default] at injection point [[parameter 1] of [method] @Inject public com.example.dbflutecdi.db.allcommon.ImplementedInvokerAssistant.setDataSource(DataSource)]
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:311)
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:280)
at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:143)
at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:384)
at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:367)
at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:380)
at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:199)
at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:128)
at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:313)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:461)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:240)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:389)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:348)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:363)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1085)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1200(CommandRunnerImpl.java:95)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1291)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1259)
at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:461)
at com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:212)
at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:179)
at com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:117)
at com.sun.enterprise.v3.services.impl.ContainerMapper$Hk2DispatcherCallable.call(ContainerMapper.java:354)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:722)
Exception 0 :
org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies for type [CommonColumnAutoSetupper] with qualifiers [@Default] at injection point [[parameter 1] of [method] @Inject public com.example.dbflutecdi.db.bsbhv.BsEmployeeBhv.setCommonColumnAutoSetupper(CommonColumnAutoSetupper)]. Possible dependencies [[Managed Bean [class com.example.dbflutecdi.db.allcommon.ImplementedCommonColumnAutoSetupper] with qualifiers [@Any @Default], com.example.dbflutecdi.db.allcommon.DBFluteModule$DBFluteBean@14423bc8]]
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:314)
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:280)
at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:143)
at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:384)
at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:367)
at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:380)
at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:199)
at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:128)
at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:313)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:461)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:240)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:389)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:348)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:363)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1085)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1200(CommandRunnerImpl.java:95)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1291)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1259)
at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:461)
at com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:212)
at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:179)
at com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:117)
at com.sun.enterprise.v3.services.impl.ContainerMapper$Hk2DispatcherCallable.call(ContainerMapper.java:354)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:722)
</code></pre>
weldというのはGlassFishが使っているCDIの実装。CDIのリファレンス実装でもある。<br />
どうやらweldが何をInjectionしたら良いのか分からなくてエラーになっている様子。<br />
残念ながら、DBFlute 1.0.0でCDIをそのまま使う事は出来ないようです。<br />
<br />
ここで諦めても良かったのですが、悔しいので解決策を探る事にしました。<br />
まずAmbiguous dependenciesという例外に対応する事に。<br />
エラーログを読む限り、それぞれのクラスのインスタンスとDBFluteModuleクラスのsetupDfComponentsメソッドで生成されているインスタンスが競合している様子。<br />
<br />
おそらく解決策は2つあり、DBFluteModuleのsetupDfComponentsの一部をコメントアウトするか、QualifierアノテーションというInjection対象を指定するためのアノテーションを作って、Injectionして欲しい方に付与する必要がある。<br />
とりあえずDBFluteModuleがなにしているのか調べるのが面倒なので、DBFluteGenerateというQualifierアノテーションを作ってInjection対象になってほしいクラスにつけてみたところ成功。<br />
<span style="white-space: pre-wrap;">DBFluteGenerateのソースはこんな感じ。</span><br />
<pre><code></code></pre>
<br />
//import 省略<br />
<br />
<pre style="white-space: pre-wrap; word-wrap: break-word;">@Qualifier
@Retention(RUNTIME)
@Target({FIELD, METHOD, PARAMETER, TYPE})
public @interface DBFluteGenerate {
}</pre>
<br />
<br />
<br />
エラーログにはもう一つUnsatisfied dependenciesというものがあり、これはdatasourceのインジェクションのところで起きています。たぶんインジェクション対象が見つからないという事なのだと思うのだけど、どうすればいいのかさっぱり分からない。仕方ないのでsetDatasourceについていた@Injectを外して、_datasourceフィールドに@ResourceでDatasouceの名前を直接指定。<br />
よくないやり方とは思うのだけど、これでデプロイし直すと動作するようになりました。<br />
<br />
ここまでの対応+実際に動く例としてのソースコードを<a href="https://bitbucket.org/kameturu/dbflute-cdi-sample">bitbucket</a>に上げてみました。もっとエレガントな解決策があれば誰か教えてください。<br />
なおDBFluteのgenerateタスクはソースコードの上書きをするので、根本的に対応するにはDBFlute側のテンプレートなどを変える必要があります。<br />
<br />
ただJavaEE7の足音が聞こえてきているので、これ以上追求する元気が失われつつもあり。亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-18276165956863795152012-08-22T06:33:00.000+09:002012-08-22T06:33:00.486+09:00初めて道案内にiPhoneを使う最早、道案内の記録になりつつこのブログ。<div>
<br /><div>
今回は、新宿で外国人(おそらく韓国の方)にホテルの場所を英語で聞かれたので、手にしていたiPhoneで素早く地図を出して方角を伝えました。</div>
<div>
タイトル通り、今回初めてiPhoneで道案内をしました。</div>
<div>
いつも道案内した後に、iPhoneがあるのに!と思っていたので、今回は大きな進歩。</div>
<div>
<br /></div>
<div>
とはいえ、ホテルまではそれなりに歩く距離だったので、無事辿り着いていればよいけど。</div>
</div>
亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-20396470185770407592012-04-22T22:08:00.000+09:002012-04-22T22:09:10.589+09:00たのまれごと2012 春と日記的な<br />
いろいろ忙しくて全然更新していない。TwitterとGoogle+はやたら使っているので、長い文章を書く元気と時間が無いとも言える。<br />
去年の12月から3ヶ月ほどプログラミングHaskellの練習問題を解いたりして楽しんでいたので、それを書けば良いのだけど、パラダイムチェンジしたいという曖昧なリクエストを持っていた人に本をあげてしまったので、それも書けない。買えばいいだけではあるけど。<br />
<br />
とはいえ、関数型言語熱は引いていなくて、Erlangとかを経由しつつ、一応お仕事ではJavaが多いので、それをScalaで置き換えられないか、少なくともHaskellよりは導入が楽だろうと、Scalaを調べつつ、引越しもしなきゃだったりでバタバタしている今日この頃。<br />
Scalaスケーラブルプログラミング第2版てのを読めば良いのだろうけど電子書籍版が無いのよね。収納の都合上、これ以上物理本は増やしたくないのだけど。<br />
章毎に分解して、読んだ端から捨てるという読み方を実践してみるか。勿体無いけど、その方がちゃんと覚える気もする。<br />
読書記録はここに書けば良いし。<br />
<br />
<br />
さて、最近の頼まれ事は、新宿で親子連れにあるスタジオの場所を聞かれたので応えたのと、外国人の女性(おそらく旅行者)に新宿中央公園の場所を聞かれた。<br />
iPhoneを持っているので、それを出せばきちんと場所を伝えられるのだけど、そういう場面になるとそれを忘れてしまう。<br />
<br />
頼まれ頻度は最近落ちてきたかな?<br />亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-46673027131971480502011-09-14T22:58:00.000+09:002011-09-14T22:58:57.630+09:00devquiz 2011 Go!の解答devquizのGo!の問題で提出した解答。<br />
問題文は以下の通り。<br />
<blockquote>Go 言語で、PNG 画像を入力として受け取り、その画像が何色使っているかを返す関数<br />
<br />
func CountColor(png io.Reader) int<br />
を実装してください。PNG 画像は io.Reader 型で与えられます。<br />
なお、入力の画像は R G B の各色の値が 0 から 255 までの 256 段階のいずれかであり、不透明(アルファチャンネルの値が常に 255)であることが保証されています。<br />
</blockquote><br />
答えとして送ったもの(ただし変数名は多少整理した)。素直にスキャンしているだけです。<br />
<pre><code class="go">package main
import (
"fmt"
"io"
"strings"
"image"
"image/png"
)
func CountColor(r io.Reader) int {
colormap := map[uint32]int{}
image, _ := png.Decode(r)
bounds := image.Bounds()
w, h := bounds.Max.X, bounds.Max.Y
var colorNum uint32 = 0
for i := 0; i < w; i++ {
for j := 0; j < h; j++ {
colorNum = colorCheck(image.At(i, j))
colormap[colorNum] = colormap[colorNum] + 1
}
}
return len(colormap)
}
func colorCheck(color image.Color) uint32 {
r, g, b, _ := color.RGBA()
var num uint32
num = uint32(uint8(r))
num = num << 8
num = num + uint32(uint8(g))
num = num << 8
num = num + uint32(uint8(b))
return num
}
/* これらの関数は提出時に自動挿入されます。 */
func main() {
png := GetPngBinary()
cnt := CountColor(png)
fmt.Println(cnt)
}
func GetPngBinary() io.Reader {
// img_strの中身は提出するたびに変化します。
// 省略
}
</code></pre><br />
以下は、後から考えたgoroutine使用版。<br />
<pre><code class="go">
package main
import (
"fmt"
"io"
"strings"
"image"
"image/png"
)
func CountColor(r io.Reader) int {
colormap := map[uint32]int{}
img, _ := png.Decode(r)
bounds := img.Bounds()
w, h := bounds.Max.X, bounds.Max.Y
result := make(chan uint32)
go colorCheck(img, w, h, result)
for i := 0; i < w*h; i++ {
colormap[<-result]++
}
return len(colormap)
}
func colorCheck(img image.Image, w, h int, result chan uint32) {
var num uint32
for x := 0; x < w; x++ {
for y := 0; y < h; y++ {
r, g, b, _ := img.At(x, y).RGBA()
num = uint32(uint8(r))
num = num << 8
num = num + uint32(uint8(g))
num = num << 8
num = num + uint32(uint8(b))
result <- num
}
}
}
/* これらの関数は提出時に自動挿入されます。 */
func main() {
png := GetPngBinary()
cnt := CountColor(png)
fmt.Println(cnt)
}
func GetPngBinary() io.Reader {
// img_strの中身は提出するたびに変化します。
// 省略
}
</code></pre>goっぽさという点ではgoroutine版のが良いのだろうけど、いきなりこれを書くのは今の私には無理でした。<br />
<br />
改めて見ると、後者ではImageをスキャンしている部分(colorCheck)と、色数を数える部分(CountColor)が分離出来ているので、すっきりしているかも。亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-84098563707870111642011-08-27T23:11:00.000+09:002011-08-27T23:11:49.989+09:00「小さな哲学者たち」という映画を見てきた<a href="http://tetsugaku-movie.com/index.html">小さな哲学者たち</a>というドキュメンタリー映画を見てきた。<br />
これは、フランスはパリ近郊のZEP(教育優先地区)の幼稚園で行われた、3歳から5歳の子供に向けてなされた哲学の授業の様子を追いかけたドキュメンタリーで、原題は「Ce n'est qu'un début」。日本語だと「これは始まりに過ぎない」という意味になるみたい。<br />
(ガンダムF91のラストの字幕のようだけど、全く関係ない)<br />
<br />
哲学の授業といっても、哲学史ではなく、愛とは何か、死とは何かといった内容を、子供たち同士が意見を言い合い、互いの言葉に耳を傾け、時に反論し、時に賛成する。そういう態度を身につけさせるものらしい。話し合いだけでなく、それをフォローするように、テーマに沿った絵を描いたりもするらしい。<br />
<br />
その一番最初の授業では「大人と子供の違い」について先生が質問することで始めるのだけど、しばらくすると子供たちは黙りこんでしまう。それだけでなく、まったく関係ない話を先生に語ろうとしたり、隣の子とおしゃべりしたりと、授業の体を為さないまま終わってしまう。<br />
ZEPとされる地域は「恵まれない」とされる家庭が多く、また移民(二世も含む)の家族が多い土地で、教育レベルが高くないところだそうだけど、3歳児の教育レベルなんて、どこだろうとこんなものだろう。3歳の頃の自分にこの質問をしても「大きいのが大人で、小さいのが子供」以上のことは言えないと思う。先生は「大人がやっても良くて、子供がやってはいけないこと」は何か?とか、大人目線で見ればうまい質問をして、子供が考えるのを助けるのだけど、それでもやっぱり難しいらしい。<br />
<br />
それでも何回か授業を繰り返すうちに、自分や家族の実体験を元に具体例を提示した上で、「だから○○と思う」という議論の下地のような物を子供たち自身が獲得していく。子供の体験した事なので、提示される例は「チョコレートを出しっぱなしにしたから溶けちゃった」とか「お父さんとお母さんが喧嘩したけど、最後は謝っていた」みたいにささいだけど、ものすごく具体的。<br />
それと小さくても流石フランス人というべきか、女の子が好きな男の子と一緒にいる絵を描いていて、それを見たその男の子が「君とはもう別れたんだからそんな絵を描くな」と言ったりとか、子供たちの恋愛絡みの光景が多く映されている。知らないだけで日本の子もそんな感じかも知れないけど。<br />
<br />
印象的だったのは、ある女の子が障害を持った父親の事を「お父さんは自分で歩けないけど、自分で動ける」「自分とは違うけど同じ」と矛盾した言い回しで語っているシーン。他の子たちは、この矛盾を追求するのだけど、女の子はそれにきちんと応答しようと試み、最終的に「障害があるとしても、そのままのお父さんが好きである」事を表明する。矛盾の追求に対する回答にはなっていないのだけど、おそらくその子にとっては、矛盾の解消以上に重要なことに辿り着いたのだと思う。<br />
<br />
もう一つ印象に残ったのは、子供たちの多くが「自由」というものは一人で出歩く事であるという意見に同意していたこと。さらに大人が子供を「自由」に歩かせないのは、子供を守るためであることをきちんと認識していること。自分たちが「自由」で無い理由は、大人たちが守ってくれているからという事を理解しながらも、柵を乗り越えて怒られた子供の話や、旅行に行った子が滞在先の家から一人で海まで歩いたことを自慢気に話すのを、わくわくした顔で聞き入っているのが「移動の自由」の原点を表しているようで、微笑ましくも頼もしい。<br />
<br />
また、子供たちは哲学の授業から「愛」や「死」といったテーマを持ち帰り、家庭内でも思考が連続していく。両親とも一緒にテーマについて語り、両親もそれに応答していく。幼稚園だけでなく家庭も含めて思考する態度が訓練されていく様子が分かる。<br />
<br />
哲学というと抽象的で、虚学の総本山という印象があるけれど、この映画で、様々なバックグラウンドを持つ子供たちが、暴力ではなく言葉と思考によって、相手を説得する態度を学んでいく様子を見ると具体的で実践的なツールとして哲学を使うことが出来るのだと言うことがよく分かる。<br />
移民が多いという背景により「単純な一つの道徳」が暴力に成りうる土地、国において、まずなされるべき対話(これすら暴力かもしれないが、少なくともマシな暴力だ)を構築する上で、哲学の授業が有効に機能している。<br />
<br />
私が見た回では、上映後トークショーがあって、移民が少ない日本ではこのような授業の要請はまだ少ないと語られていたけど、例えば北海道と沖縄の子が遠隔で対話するような哲学の授業というのは潜在的に要求されているのではないかと思う。亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-49459887861259263502011-08-27T21:53:00.000+09:002011-08-27T21:53:56.435+09:00道を聞かれた 新宿西新宿のあたりで、初老の女性に十二庵?という場所が無いか聞かれた。<br />
聞いたことが無かったので、知りませんと回答。<br />
他の人にも聞いていたようだけど、他の人も心当たりが無さそう。<br />
<br />
後から調べるとニューオータニのあたりに、そういう名前のお店があるらしい。<br />
確かに、あのあたりのお店に行きそうな上品なお金持ち風の格好だったけど、無事辿りつけただろうか。亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-90874921386489589572011-05-28T23:27:00.001+09:002011-05-28T23:27:41.518+09:00正規表現 幅ゼロ先読みでよく間違えるのでメモ正規表現で、いつも混乱するゼロ幅先読みについてメモ。<br />
整理せず思考過程をそのまま記述する。<br />
<br />
まず確認として、ゼロ幅とか気にしない正規表現。<br />
具体例が合ったほうが分かりよいので、以下の仕様で考える。<br />
<br />
1) aとzだけが使われる<br />
2) 文字列の長さは3以上、10以下<br />
<br />
これにマッチする正規表現は<code>^[az]{3,10}$</code>である。ここまでは問題ない。<br />
次に以下の仕様を追加する。<br />
<br />
3)zは連続して3つ以上ならんではならない<br />
<br />
連続した3つ以上のzとマッチする正規表現は、<code>z{3,}</code>なので、これを幅ゼロ否定先読みしてやればよい。<br />
そして、こう間違える<code>(?!z{3,})^[az]{3,10}$</code>。(※)<br />
この書き方では、zzzaは確かにマッチしないが、aaazzzaaaにはマッチしてしまう。<br />
<br />
なぜなら、正規表現のカーソルはマッチした文字列の後ろに移動してしまうから。<br />
aaazzzaaaの場合、文字列の先頭(最初のaの直前)で3連続以上のzを探した後、aaazzzaaaにマッチして、カーソルは文字列の最後に移動してしまう。<br />
<br />
正しい正規表現はこうなる<code>(?![az]*z{3,})^[az]{3,10}$</code>。<br />
否定先読みの中身だけ取り出すと<code>[az]*z{3,}</code>。つまりaかzが先頭に0個以上あって、その後でzが3つ以上並んでいるかどうかを調べている。<br />
<br />
なんで、※のような間違いに至るかについて、自己分析してみる。<br />
人間が文字列を検索するときは基本的に頭から順番に一文字ずつ、対象の文字列と合っているかどうかを調べていく。<br />
対して、正規表現は与えられた個々の正規表現単位で合っているかどうかを調べていく。<br />
aaazzzaaaを^[az]{3,10}$と表す場合、aaazzzaaaで一つの「文字」であり、aaaやzzzという「文字」は存在していない。<br />
この違いを忘れて、人間の検索戦略をそのまま正規表現での検索に当てはめてしまうところに、間違いの原因がある。<br />
<br />
ところで、人間であっても実際には正規表現と似たような調べ方を行っている。<br />
例えば「時」という漢字は「日」「寺」に分けられるが、人間が「時」という文字を検索するとき(書体の影響もあるとはいえ)、「日寺」という文字の並びとはマッチさせない。<br />
とはいえ、あえて「時」と「日寺」をマッチさせるような遊びも楽しいのだけど。亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0tag:blogger.com,1999:blog-2136810126015230672.post-42269078276100933522011-03-11T11:37:00.004+09:002011-03-11T11:43:37.657+09:00かわいいPS1TwitterでTerminalともっと仲良くなりたいという人と話していて、プロンプトをかわいくすれば仲良くなれるかも、と思ってやってみた。<br /><br />bashrcで<code class="code">PS1="\w\n(・ᴗ・)?"</code>と設定。<br /><a href="http://www.flickr.com/photos/28342034@N04/5515996333/" title="kawaii PS1 by kameturu, on Flickr"><img src="http://farm6.static.flickr.com/5054/5515996333_958a90e0a4.jpg" width="500" height="316" alt="kawaii PS1" /></a>亀鶴http://www.blogger.com/profile/00663453431403053017noreply@blogger.com0