自分の作った箇所のテストケース作成、実施はまだ良いんだけど、他の人の作った機能のテスト、しかも機能追加後のほとんどのテストをもう一回流すテストでえんえんと大量のエビデンス(テスト成功の証拠となるスクリーンショットやDBダンプ)をとりつづけるテストはほんと苦痛でしかない。おかげでモチベーション上がらず無駄に時間を過ごしてしまい非効率この上ないことになってしまった。
テストはもちろん重要なんだけども、再テストの単調作業のダルさはどうにかならんのか。
まぁこうやって再テストをただの単調作業としか認識していない時点でどれくらい重要だと思っているか甚だ疑問ではあるわけで、どうせだからテストについてちょっと勉強してみよう、と思った。
また直近で勉強すること増やすのかよって感じだけど、少しずつでもテストのやり方とかについて勉強しないとヤバい。新人研修の演習で一番テストに工数かけなかったの自分だしね。
テストでモチベーション上がらないのも問題だけど、ここんとことの仕事中の問題は(前からもそうだけど)、目的をはき違えて、または目的に目を背けて、手段に拘っていること。「他の人が忙しいから自分でなんとかしないと」と思い込んで人に聞くことを回避しようとしたり、「こんな仕様わかんねーよ」って仕様をほじくり返して愚痴る材料を見つけようとしたり。そんなことに時間を使ってしまう。
目的からやるべき事を考えればもうちょっとまともな手段をしなおせるはずなのに、それさえしないのは、「それに気づいておきながら目を背けている」んだと思う。
自分のやるべき事を正しく認識するんだ。絵でもいっしょやね。
gnome2.8以降、キーボードショートカットから直接Emacsスタイルのキーバインドを指定しなくなって、次の二通りの方法でEmacs風にできる。まぁwebにゴロゴロ転がってるネタ。
一つ目は、~/.gtkrc-2.0に「gtk-key-theme-name = "Emacs"」を書くこと。二つ目は、gconf-editorで「desktop → gnome → interface」で、該当変数の設定ができる。
どうもこの設定はうまく行っているっぽい、gimageviewやgnome-terminal、firefoxではemacsのキーバインドとなっている。しかし、geditやanjuta、nautilusでは相変わらずUNIXキーバインドだ。
今まで、geditやanjutaで設定したはずのキーバインドにならないのは設定がまずいからだと思っていたけど、そうじゃなくて、geditやanjuta側でキーバインドの設定を勝手にしてるんじゃなかろうかと思えてきた。と思っていたら、Sylpheedでメニューの雛形のせいでGTKの設定が無効になっていたという話があったので、調べてみる価値はありそうな予感がしてきた。
E'sはいつになったら話が進むのかと思っていたけど、やっと展開の進みがはっきりわかるようになってきた。後書きで今まで丸ペン一本で漫画を描いてきたという話があって、この巻からGペンも使うようにしたとのこと。
デジコミの本は2002年に出版された本。すこし古いおかげでフォトレタッチソフトであるPhotoShopを使った漫画の効果処理の仕方が細かく描かれている。ソフトの使いかたというよりも、その効果の意味や、デジタルでやる利点の解説に重点をおいて書かれている。最近出版されている本ってたいがい漫画作成用ソフトのマニュアルか、どういうフィルタを使えばいいのかだけしか書かれていないとかばっかりで他のソフトでの流用のしようがなかったので、こういう本が欲しかった。
あ、あと、30日でできる! OS自作入門も買ってくるつもりだったけど、予想したよりでかくて邪魔になりそうだったので、引っ越してから買うことに。
3/10に引越しをするので、3/9の午後からサーバが止まります。そのため、この日記も見えなくなります。復帰予定は3/21です。
ネット自体には3/11から繋がるんですが、契約したSo-netは、接続開始から10日経たないと固定IPサービスの申請ができないということだったので、早くても3/21からとなります、ぐんにょり。まぁ、こういうイレギュラーもしょうがない、プロバイダを変えてみたかったのは自分だし。
その間に最低でもOSを更新したいなぁ。
サーバ停止中はmixiの方でこっちと似たような更新をしていきます。
二週間の我慢ということで、昼間ネットができない環境で頑張って仕事しています。仕事は先方で色々用意していただいているので問題はないんですが、昼間ネット巡回ができないんで日々のニュースや記事が全く読めていません。まぁ引越しの作業がまだ続いているせいもありますが。
今まで、昼間注目した記事を消化できないんで悩んでいたのに、今度はそもそも見つけにいけなくて悩んでいます。このまま当分ここで仕事というのならAirH゛も契約するんですが、そういうわけでも無いんでそのまんま。
よそ事ばっかりしてて仕事に集中できないのは問題ですが、全く他のことができないのは辛い。要はバランスか、復帰したらメリハリつけて仕事していきたいなぁ。
自転車で柏まで行ってみた、途中道間違ったので1時間ぐらいかかった。本屋も小さくてしょんぼり。
V・B・ローズは相変わらず美しい世界タレ流し。紫サンとあげはのらぶらぶーも垂れ流されるのかと思いきや気持ちの接点がフラフラ、決定的な部分以外がどんどん埋められていっているにもかかわらず、すごいバランスだ。
ミニマム☆マニア、タイトルだけで買ったわけではないけども。小学館の少女漫画って総じてオタ臭い絵柄ばっかりな気がするんですがどうよ。話は良いとは言わないが、悪い訳でもなくちゃんと読めるレベルなのに、細かい描写が適当で展開の雑さが目立って、悪い意味で低学年向けだからこれくらいいいだろーっていうとこがちゃおとなかよし系の漫画には多くて残念でならない。それでも買うのは結局、絵柄とシチュエーションが好みだからなわけだけど。
昨日同窓会で飲んだんで昨日はさっさと寝、8時に起きるも二度寝、しかも変な夢を見て寝た気がしない。昼すぎに部屋の管理会社の人がくる予定だったので片付けの続き。
二階の洋間がサーバと本棚を置く場所にしたけども、全然片付いていない。とりあえず棚を組み上げて(そっからかよ)。PCを置いて、スペース確保。明後日か来週ぐらいにサーバをこっちに置く予定。
2時過ぎに管理会社の人がくる。これは先週、部屋の不具合について連絡したのでその確認だった。補修できるところはしてもらったけど、台所周りはどうにもならんかったので、また来週大工を呼ぶとのこと。
っていうか水周りが結構適当だったことに驚いた。これじゃ下水の臭気もれるぜ。まぁなんとかするか。引っ越してから、ホームセンターとドラッグストアを行ったり来たりしながら掃除したり、モノ入れ換えたり、殺虫(鼠)剤やら置いたりと行ったことばっかりやってます。来週末には机が来るんでそれでもぅ引越し作業は完結するはず。
あぁカーテンかって無いとこどうしようかなぁ、角部屋なんで窓が6箇所あるんで全部にカーテン付けるのは金かかっていやん、困りはしないからとりあえず半分は雨戸しめたまま。
先週の話だけども、Gigabitのスイッチを買うついでに無線LANの環境を作るためにアクセスポイントと無線LANカードを購入。これで1階のルータから2階の和室にケーブルを這わせる必要がなくなって気持ち良い。最初、WEPとかWPAがよくわからなくて繋がったり繋がらなかったりを繰り返していたが、なんとか繋がるようになった。PSPもネットワークに参加できるようになったので、色々遊んでみたいところ。
買ったのは俺コンハウス、最初愛三電機でアライドテレシスのGigabitハブと一緒に買おうと思っていたけど、愛三が日曜やってなかったので、俺コンへ。しかし店員のにーちゃんのアドバイスが微妙で、最後適当に話を流してレジへ。とはいえこっちの説明も悪かった。いかんいかん。
前回の2P目の和訳からえらい間が空きましたが、How to write a GIMP plug-in 3Pの和訳です。訳出の意図、注意は1P目同様です。
コードについてはプロトタイプ宣言だけは載せていますので、コード全体は原文を適宜参照してください。
この和訳文書はcreative commons : 帰属 - 非営利 - 同一条件許諾 2.5でライセンスされてます。
原著者: Dave Neary(bolsh@NOSPAM.gimp.org)
第二章で、私はピクセル単位か行単位での画像データ(image data)の操作を説明した。今回は、さらに進めて、今までに作ったプラグインの性能を改善させられるタイル単位でのデータ処理を行う。また、より大きな半径を配慮したアルゴリズムへの改良を行い、パラメータを変更させることができるようなグラフィカルインターフェイスの構築も行う。
前に作った単純なアルゴリズムを確認してみよう。このアルゴリズムは、ピクセル単位で、各レイヤーに(2r+1)x(2r+1) - x,yの形式、rは半径 - の近傍を設定し、その近傍の平均でレイヤーの各ピクセルを置き換えるモノであった。
例の画像で画像の境界で注意を払わなければいけないのはいささか複雑ではある。しかしこのアルゴリズムによるブラー処理は一般的にそれほど悪くはない。
とはいえ、今まで書いてきたアルゴリズムは3x3近傍ピクセルを対象とした処理であった。この章では、対象とする範囲を一般化し、パラメータとして近傍の範囲を取得するようにする。
まずはタイルについて。
タイルとはサイズ64x64ピクセルの画像データブロックです。通常タイルはプラグインに対して一つ一つ要求に応じて、共有メモリから送られます。もちろん、この処理は大量の資源を必要とし避けるべきである。
普通、特定のキャッシュを必要とすることはない、どのタイルも必要とされたとき送られ、他のタイルが呼ばれれば、開放される。それでもなお、以下の関数を使うことによって、一定間隔で回ってくるround tripを避けてプラグインにタイルキャッシュを保持させることができる。
gimp_tile_cache_ntiles (gulong ntiles);
part2の例では、gimp_pixel_rgn_get_row()とgimp_pixel_rgn_set_row()を呼び出したが、キャッシュを使うことはしなかった。
タイル列一列のタイルの数は、タイルの幅でレイヤーの幅を割った数に1足した数となるだろう。そのため、レイヤーの幅が65の場合、我々は二つのタイルをキャッシュすることになる。通常シャドウタイルも処理するので、プラグインの扱うキャッシュのサイズは倍にしている。
gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
キャッシュによって遅かったプラグインは早くなった。300x300の画像上では、最新のブラー処理は3秒かかった。しかし、2000x1500の画像上では遅くなり、142秒かかった。
上記のコードを追加することで、処理速度は向上し、11秒で終了した。我々はまだタイルの変わり目での変化に要する時間を失っている。2行分のタイルキャッシュを取得する変わりに4行分取得するようにしたら、10秒まで減らすことができた。ある点を堺に処理時間の増加を減らすことができたが、より多くのキャッシュを必要とするようになり、またさらなるハードディスクへのアクセスを発生させることになった。
半径パラメータを考慮するために、アルゴリズムを修正しよう。半径が3の場合、ピクセル近傍は7x7とし、半径1の場合は3x3とする。これを実現するために、以前のアルゴリズムを次のように修正する。
このアルゴリズムは一つ前のよりも複雑である、なぜなら平均の計算時間がO(r^2)のアルゴリズムだからである。
このように動作するよう修正されたソースコードを以下に示す。ほとんどの処理は、process_row()関数内で行われる。init_mem()関数とshuffle()関数はブラー処理のソースコードをきれいで小さく保つ。
static void blur (GimpDrawable *drawable); ... static void blur (GimpDrawable *drawable) { ... } static void init_mem (guchar ***row, guchar **outrow, gint num_bytes) { ... } static void process_row (guchar **row, guchar *outrow, gint x1, gint y1, gint width, gint height, gint channels, gint i) { ... } static void shuffle (GimpPixelRgn *rgn_in, guchar **row, gint x1, gint y1, gint width, gint height, gint ypos) { ... }
ユーザが半径を修正しようとするために、もしくは対話的で無いスクリプトにパラメータとして値を渡す場合、run()関数へ戻る必要があり、それは単純なスクリプトでできる。
まず我々は、オプションを保存し返すことができる構造体を作成する。たいてい、これは一つだけパラメータをもつプラグインの為に使われる。
typedef struct { gint radius; } MyBlurVals; // /* Set up default values for options */ static MyBlurVals bvals = { 3 /* radius */ };
次に、execution modes(実行モード)を考慮するためにrun()関数を修正する。interactive mode(対話モード)や、一つ前のフィルタを繰り返すモードにおいて、われわれはgimp_get_data()関数で利用された値を取得しようとした。この関数は一番最初に入力パラメータとして一意なデータ識別子を提供してくれる。たいてい、プロシージャ名を使う。
最終的には、対話モードで、オプションを修正するためのグラフィカルインターフェイスを構築するための数行を追加した。
static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { ... }
私は、GTK+プログラミングの詳細は詳しくない、GTK+プログラミングについては他の素晴らしいサイトを参照してくれ。まず最初に試したのは非常に単純なものだ。GIMPのウィジェットユーティリティを使い、ヘッダーを持つウィンドウをGimpDialogで作成し、数値を制御する(GtkAdjustmentと関連付けられた)GtkSpinButtonも作り、そしてGtkFrameでラベルを作成した。
以下のパートでは、このような作業がどれだけ簡単にできるかを示すために、パラメターの効果をリアルタイムに示すプレビューダイアログを追加する。
最終的に、Gladeのツリー表示パネルで以下のように表示される程度になった。
GIMP2.2で、GNOMEヒューマンインターフェイスガイドラインに沿って、首尾一貫した振る舞いを行うように考慮された、パラメータを伴うウィジェットが存在する。GimpPreviewは2.2から現れた、とりあえずそれを使わない版を作ってみる。
static gboolean blur_dialog (GimpDrawable *drawable) { ... }
GimpPreviewを追加するのは本当に簡単だ。最初に、gimp_drawable_preview_new()関数を使ったGtkWidgetを作成する。その時、無効化シグナル(訳者注)をこの関数に設定し、プレビューが更新される度にblur()関数を呼ぶようにする。また、MyBlurValsにプレビューが有効かどうかを覚えておくための第二引数を追加する。
簡易的なプレビューの更新方法とは、プレビューパラメータをblur()関数内に追加することです。そして、プレビュー引数がNULLでないなら、限定的にGimpPreviewを行う。そして、run()関数からblur()関数を呼ぶ場合、プレビューパラメータはNULLに設定する。
限定的なGimpPreviewを行う為に、gimp_preview_get_position()とgimp_preview_get_size()を利用する。これで表示されている箇所だけにぼかし処理をかけることができる。
最適な方法に到達するには、コードのいくらかを調整しないといけない。例えば、プレビュー生成時はプログレスバーの更新は必要ないし、GimpPixelRgn初期化時、タイルキャッシュがコアに送り返さないようにさせる。
最終的に、gimp_drawable_preview_draw_region()によって更新されたプレビューを表示させる。プラグインの効果をリアルタイムに表示するダイアログボックスを得られる。さらには、GIMPコアのおかげで既にこのプラグインは選択領域も考慮できているからだ。
static void blur (GimpDrawable *drawable, GimpPreview *preview) { ... } static gboolean blur_dialog (GimpDrawable *drawable) { ... }
タイルキャッシュ処理、UI、プレビュー処理についてはそれぞれのコードを見てくれ。
この記事では、我々はいくつかのGIMPプラグインの側面を基本的な概念を見てきた。単純なアルゴリズムによる画像データの処理を行ってきた、そしてパフォーマンス問題をどのようにして避けるべきなのかという道を示した。最終的に我々はアルゴリズムを一般化し、パラメータを追加し、GIMPウィジェットを良いユーザインターフェイスにするために使った。
この記事を書いている間中、私を助けてくれた妻AnneとDavid Odinへ感謝する。
体裁がぐっちゃぐちゃなんで、どうにかしたい。っていうかやっぱり、翻訳支援ツールとか使ってみるべきだった。後、語尾もですます調にするべきだったなぁ。
さて、次はどうするべか。ってせっかく訳したんやし何かPlug-inを作ってみんとなぁ、調べたことが無駄になる...。
gimp_drawable_preview_new()では、invalidated signalというシグナルが定義されていて、最初何の意味かさっぱりわからなかった。
「無効化されたシグナル」とか直訳して、”シグナルを無効化する関数があるんかなぁ”とか思ったけども、どうやら違うらしい。っていうかそれじゃあ意味が通らないし。
invalidateはGUIプログラミングでupdateやrepaintと同じ再描画に関する信号としてよく使われる名前のようで、「描画した効果がなくなった」ことを示すシグナルだということでした。windowsでのゲームプログラミングの記事でその名前が確認できました。
というわけで、上記の文章でinvalidated signalが表れた箇所は、再描画の必要がある際、invalidated signalが発行されるとblur()関数を呼ぶようにしている。
土曜日に机、棚よりも一足早くやってきました、アーロンチェア。一番安い、スタンダードですが、大方問題無し。アームレストの高さ調節がスタンダードではできないので、腕の行き場所に悩みました。しかし、思いっきりリクライニングさせてキーボードに手を伸ばすとそもそもアームレスとが机の下に隠れる上、腕が机に完全に乗っかってしまったので問題解決。
前傾姿勢ではないので座っている間、足に全然力がかかりません。おかげで、立ち上がるとき体を重く感じます(何
現状まぁそんなもんなんだろうなぁって感じはするけど、「一般的にOSS翻訳は軽視されており」ってのはどうなんだろ。debianやFedoraでは翻訳に関するMLがあったりするし、GNOME、KDE等にしても翻訳が軽く見られているなんて思えないんだけどなぁ。まぁ思えないってだけで中がほんとはどうなのか見たことないからなんともいえんが。
この発表をされてる樋口さんってSunで翻訳スタイルガイドを策定された人かな。ここんとこオープンソースな翻訳支援ツールもいくつかあるんで、これから試してみたい。
いつまでも質の低い和訳を垂れ流す訳にもいかんしのぅ。
なんだか、nozomさんとcarbuncle君が盛り上がってたから自分も書いてみました、pythonで。
#! env python def fib_cps(n, k): if n == 1 or n == 2: return k(1) else: return fib_cps(n - 1, (lambda v1: fib_cps(n - 2, (lambda v2: k(v1 + v2))))) if __name__ == '__main__': for val in range(1, 10): print 'Fibonacci(', val, ') = ', fib_cps(val, lambda x : x)
書きかたはnozomさんとこのJavascriptの例をそのまんまpython上で書いただけです。なんかもっといやらしい書きかたできんかなぁ(ぇ。主張できるものが無い。
上げ方ミスってindex.rdfが汚れたかも、RSSリーダで読んでる人ゴメン。コードに空行が無いのはpythonだからじゃないっす。
あと、Sofutware Design 4月号と電撃萌王。Software Designはひなた先生の為だけってのが大きいかも。Web関連の記事が軒並一瞥して終わり以上の価値が無いってのは悲しいなぁ。電撃萌王は七尾奈留の表紙に捕まった、と最初思ったけど意外によさげな内容だった。
かりん8巻の通常版が4/1発売と聞いて憤りを感じずにはいられない。どうせ買われない限定版をなんでそんなに先行させる必要があったんだ、とつい考えてしまう。
機長が語るヒューマンエラーの真実は、関係する仕事をしているからというわけでは無いけど、興味深い。ただ、普通に読むにはもうちょっと一般論を深く論じて欲しいんじゃないかなぁと思った。
いぬかみっは絵柄が好みだった、漫画も絵柄は良かった。
ARIAは電車の中でニヤニヤする展開でどうしようかと(ぇ。二期がほんと楽しみだ。
やっと時間が取れたのでTurbogearsでblogを作るのを再開。とはいってもCSSとHTMLをこねくりまわしている時間が大半なわけですが。
最初、preview versionは使う気が無くて、release versionのモジュールのupdateをかけようと思ってez_setup.pyを動かしたらダウンロードサイト内のURLが間違っててインストールができなかった。
というわけで、ついでなのでpreview versionを使ってみることにした。諸々の変更点に気をつけつつ、作業作業。
Google AdSenseがウザいんですよ。っていうかクリックしたこと一度もないし、サイトと全然関係ない広告ばっかりで役にたたないし、等々で前々から目障りだなぁと思ってました。
どうにかできんもんかなぁと思って、この前nozomさんの書いたJavascriptで継続渡しを読んでそのままpythonへ写したとき、以前あったJavaScriptアレルギーがめっきり少なくなってたので(今でもありますが)、Greasemonkeyに挑戦してみることにした。
どのサイトでも効くかどうかは調べてないけど、とりあえずこんな感じ。
// ==UserScript== // @name Google Adsense Remover // @description removing remove google Adsense. // ==/UserScript== (function () { var ad_name = "google_ads_frame"; var iframes = document.getElementsByTagName("iframe"); var googleAd; for (var i = 0; i < iframes.length; i++) { googleAd = iframes[i]; if (googleAd.getAttribute("name") == ad_name) { googleAd.parentNode.removeChild(googleAd); } } })();
これ書く上で、始めてfirefoxのDOMインスペクタ使ったんですが、便利ですね!(今更
さ、次はamazonへのリンクURLからアマゾンアソシエイツのIDを削るのを書くぞー。
やってることは単なるURLの成形。あと、ASIN以降にredirect〜とか書かれている場合の対応をしないといけないけど、面倒になってきたんでそれはそのうち。
ちなみにURLのamazonアソシエイツID以降を削りたいのは、リンクが商品詳細へのリンクになっておらず、アソシエイツユーザのレコメンド一覧のページへのリンクになっているのが嫌だから。
// ==UserScript== // @name Amazon Associate ID Remover // @description removing Amazon Associate ID. // ==/UserScript== (function () { var delim = "/"; var attrName = "href"; var amazon = "www.amazon.co.jp"; var ASIN = "ASIN"; var links = document.getElementsByTagName("a"); var url; var fixedUrl; for (var i = 0; i < links.length; i++) { element = links[i]; if (element.hasAttribute(attrName)) { url = element.getAttribute(attrName); if (url.indexOf(amazon) != -1) { tokens = url.split(delim); fixedUrl = "http://" + amazon; for (var j = 3; j < tokens.length; j++) { if (tokens[j] == ASIN) { fixedUrl = fixedUrl + delim + ASIN + delim + tokens[j+1]; break; } else { fixedUrl = fixedUrl + delim + tokens[j]; } } element.setAttribute(attrName, fixedUrl); } } } })();
DOMインスペクタとWeb Developerが無いと開発がままならないです、ままならないっていうか不可能。あと、javascript-mode.el必須。
まぁJavascriptといっても必要な知識はほとんどはDOMかなぁ。