2008年12月23日火曜日

OpenGL: Visual C++ 2008 Express EditionでGLUTを使う

このブログ記事をはてなブックマークに追加

WindowsにVisual C++ 2008 Express Editionをダウンロード・インストールする。このバージョンではPlatform SDKは同梱されている。

GLUT for Win32からglut-3.7.6-bin.zipをダウンロードする。ファイルを展開し以下に示すフォルダにコピーする。

glut.h → C:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\gl glut32.lib → C:\Program Files\Microsoft SDKs\Windows\v6.0A\Lib glut32.dll → C:\WINDOWS\System

これで準備完了。因みにglaux.libは存在せず、リンクする必要はなくなっている。

使用例

C++: OpenGLで正十二面体を回転させるで示したソースを dodecahedron.cpp として保存し、以下のコマンドをコマンドプロンプト上で実行する。Visual Studio 2008へのパス(C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools)は通しておくこと。

vsvars32 cl dodecahedron.cpp /O2 /FIwindows.h dodecahedron

これで回転している正十二面体が表示されるはずだ。

続きを読む...

2008年12月18日木曜日

ActionScript 3.0のコードをコンパイルしてそのまま公開できてしまうwonderfl

このブログ記事をはてなブックマークに追加

ウェブ上でActionScript 3.0のコードを書いてサーバ上でコンパイルでき、しかもそれをそのままFlashとして公開できてしまうというサイト、wonderflが面白い。早速、適当な短いコードをコンパイル・公開してみた。簡単だ。



文字を打ち込むと鏡文字になるFlash。最初にクリックしないとアクティブにならないかも。

ところでGoogle Chromeだと正常にコンパイルができなかったな。仕方がないのでFirefoxを使った。うーむ。

続きを読む...

2008年12月16日火曜日

PS3: WipEout HDの楽しみ方

このブログ記事をはてなブックマークに追加

最近、WipEout HDの圧倒的なスピードと映像に酔い痴れている。画像はレースの一シーン。この映像が1080p/60fpsで目にも留まらぬ速さで動きまくる。とりあえず数日プレイしてすべてのレースキャンペーンで1位(イージーが多いけど)を取れたのでWipEoutを楽しむ方法について書いてみる。

自分はPSのワイプアウトXLからのファン(Wiperと呼ばれる)なのだけど、ワイプアウトは本当に楽しいと思う。自分の操るクラフト(自分の運転するマシンのこと。空中に浮いているのでクルマとは言わない)が最速クラスで綺麗に走れたときには脳汁が出っ放しになる。だが何故か日本ではあまり流行らない。一部の熱狂的なファンはいるのだが一般受けしないようだ。前作のWipEout Pulse(PSP)は日本語化さえされない始末。欧州ではキラーソフトの一つにも数えられているのになぁ。自分が考えるに流行らない理由はきっとワイプアウトの楽しみ方を知らない人が多いからではないだろうか。そこで自分なりのワイプアウトの楽しみ方を述べることにする。

ワイプアウトは最初から最速で走ることはできない。これはいきなり最速クラスでレースをしても速過ぎてとてもじゃないがゲームにならないからだ。遅いクラスで慣らしていって最後に最速クラスでレースを行うようになっている。ただし、Zoneモードは別だ。これはだんだんとスピードが速くなるモードで壊れるまで走ることができる。ただし、いきなりZoneをプレイしても最速になるまでに壊れてしまうだろう。

で、初めてワイプアウトをプレイすると、最初のところで挫折してしまう人が多いようなのだ。クラフトを思うように操作できない人もいれば、思ったよりも速くないし爽快感がないと感じる人もいるようだ。

操作が難しいという人は、慣れるまでしばらくプレイして欲しい。慣れてくると低速クラスなら苦もなく操れるようになると思う。ワンポイントアドバイスとしては、カーブは外側から内側に入るようにして、気持ち早めに曲がったほうがいいかもしれない。それとエアブレーキを利用すること。あとは曲がりすぎないことかな。人によっては後方視点よりコックピット視点にした方が操りやすいかもしれない。自分はコックピット視点の方が操りやすかった。

思ったよりも速くないと感じた人は、序盤はどれも遅いクラスなのでしばらく我慢して速いクラスをプレイできるようになるまでは走ってみよう。違った世界が見えるはずだ。また、もし後方視点であればコックピット視点も試して欲しい。コックピット視点だと体感速度が倍は違うと思う。因みに自分はデフォルトの後方視点だとスピード感に乏しく、操作もしづらかったので、シリーズを通してずっとコックピット視点だ。それにバレルロール(クラフトを回転させて高速移動)はコックピット視点じゃないと物足りない。

少しでもWipEoutをプレイする人が増えるといいなぁ。WipEout HDにはオンラインレースもあるのだけど、多くのホストが欧州で時々アメリカって感じになっていて日本のホストはあまり見かけない。まあ、レースする分にはどこの国の人たちでも困らないのだけど、日本人が少ないとなんとなく寂しい。因みにWipEout HDはダウンロード販売専用で価格は1,800円だ。自分ならたとえ1万円だとしてもPS3本体ごと買ってしまうレベルなのに。なんてリーズナブルなんだ。

続きを読む...

2008年12月12日金曜日

Fortranコンパイラの速度比較

このブログ記事をはてなブックマークに追加

10年以上も前の話だけど、Fortran90はFORTRAN77に比べて遅くてダメダメ、GNU Fortranは遅くてダメダメって云われていた。今でもFortranを使っている身としてはちょっと気になったので簡単なベンチマークテストを実施。Xeon 3.2GHz/メモリ2GB の環境で、姫野ベンチ(サイズS)を使って測定した。因みにコンパイラのオプションはGNUコンパイラが -O3 、Intelコンパイラが -O3 -tpp7 -xW -Vaxlib とした。

以下、測定結果。

Fortran90 - ifort 9.0
MFLOPS: 1190.497 time(s): 59.9921000000000 Score based on Pentium III 600MHz : 14.37104

FORTRAN77 - ifort 9.0
MFLOPS: 1539.517 time(s): 64.18000 Score based on Pentium III 600MHz : 18.58422

Fortran90 - gfortran 4.0.2
MFLOPS: 603.2382 time(s): 60.6580000000000 Score based on Pentium III 600MHz : 7.281968

FORTRAN77 - g77 3.4.5
MFLOPS: 1426.6582 time(s): 57.7142258 Score based on Pentium III 600MHz : 17.2218533

Fortran benchmarks

コンパイラのバージョンがちょっと古いけど、やっぱりFortran90に比べFORTRAN77の方が速いな。GNUコンパイラについてはg77が思ったよりも悪くない。確かバージョン3で大幅に性能が改善されたんだっけな。うろ覚えだけど。

続きを読む...

2008年12月9日火曜日

インデントの大切さ

このブログ記事をはてなブックマークに追加

大学の実習で学生にプログラミングを教えているのだが、C言語などでプログラムを書かせるとほとんどの人がインデント(字下げ)をでたらめに入れる。これは何故だろう。

教えている学生は2年生なのだが、1年生で既に講義で習っているはずなのに。自分ならインデントを揃えないと読みづらくてやっていられなくなるが、インデントをでたらめに書く人はそれを苦労とは思わないのだろうか。インデントの意味を教えてもキツネにつままれたような顔して、それが重要であると考えてくれないようなのだ。それならばと放っておくと括弧が足りなくてコンパイルエラー、条件文のスコープが分からなくなって四苦八苦、関数を終わらせずに次の関数を書き始める等々、奇妙奇天烈なコードを書いてくれる。で、最後には分からなくなったので教えて欲しいと言ってきて、インデントがでたらめなコードを自分が読む羽目になるのだ。

プログラムを書くなら、文法などよりもまずインデントの重要性を知る必要があると思う。…と考えるとやっぱりPythonはプログラミングを習い始めるのに良い言語のように思うなぁ。

続きを読む...

2008年12月4日木曜日

Python 3.0がリリースされた

このブログ記事をはてなブックマークに追加

Python 3.0の正式版が公開されたみたい。そろそろ本腰入れて使ってみるかなぁ。

参考サイト: もっと知りたいPython3000

続きを読む...

2008年12月3日水曜日

Python: NumPyで相関係数を求める

このブログ記事をはてなブックマークに追加

覚書。numpy.corrcoefを使う。

from numpy import corrcoef print corrcoef([1, 2, 3, 4, 5], [1, 2, 2, 5, 5])

出力結果:

[[ 1. 0.92966968] [ 0.92966968 1. ]]

入力データのそれぞれの組み合わせに対する相関係数が行列として出力される。2データの相関係数は右上か左下の値となる。

続きを読む...

2008年12月2日火曜日

Goolge Livelyの終焉

このブログ記事をはてなブックマークに追加

少し前のニュースだけどGoogleのLivelyが12月いっぱいで終了するそうだ。少しばかりオブジェクトのプログラミングでもしようかと思ったが、結局は手を付けず仕舞いだった。

まずは、3Dオブジェクトを作ろうとした場合、Mayaなどの本格的な3Dモデリングソフトが必要なことがネックとなっていた。SketchUpあたりで作れたのなら良かったのだけど。その辺のことは疎いので、それだと技術的な問題があったのかもしれないが。簡単なガジェットならばGoogleデスクトップガジェットで作成できるようだったが、これもまったく宣伝していなかったので知っていた人もほとんどいないのではないだろうか。

また、発表後にほとんどソフトウェアなどのアップデートはなかった。大体Google Chromeで使えない時点で問題外である。せめて定期的にオブジェクトを追加するなりしていればまだ良かったのだが。オブジェクトすら増えないとなれば最初に部屋を作った以降はなにもすることはなくなってしまう。

多くの人はこれを以って仮想空間はまったく流行らないと考えるかもしれない。しかし、どんなサービスにでも云える事だが、定期的に利用者の期待するサービスを提供しなければダメなのだ。逆に言えば、良いサービスを継続して出していればもう少し流行っただろうと思う。

続きを読む...

2008年12月1日月曜日

11月を振り返って

このブログ記事をはてなブックマークに追加

11月はほとんどブログを更新しなかったな。11月最後のリトルビッグプラネットの記事も以前に書いていたものをアップロードしていなかっただけだし。一番の原因は風邪で体調を崩したことかなぁ。この時期はいつも体調が悪い気がする。仕事の掛け持ちやらで疲れているところに、周りに風邪引きが増えてそれを貰ってしまうという悪循環。一度体調を崩すと気力が削られて様々な「やる気」が萎えてしまうのだ。

体調が悪かったり、仕事がちょっと忙しかったのもあるけど、ブログの更新が滞った別の理由としては面白いゲームが出ていたってのもあるな。ブログ更新の優先度はそれほど高くない、というか一番低い位置にあるので他にやることができてしまうととたんに更新が滞ってしまう。プログラミング関連だと趣味や仕事とも共有できて、ブログネタにもなるんだけど、ゲームだとねぇ。まあ需要があればプレイ日記を書いてもいいのだけど。個人的には他の人のゲームプレイ日記を読むのは好きだし。

因みに11月中に、PS3ではリトルビッグプラネットとWipEout HD、PSPではパタポン2と勇者のくせになまいきだor2をプレイした。この四つのうち主にプレイしたのはリトルビッグプラネットとパタポン2で、どっちもかなり面白いよ。残りの二つも面白いのだけどプレイする時間がなかっただけ。PlayStation Homeの大規模βテストにも当選したけど時間がなくて一回起動しただけだな。

12月は時間と体調の管理に気をつけたい。

続きを読む...

2008年11月30日日曜日

PS3: リトルビッグプラネットをパーフェクトクリア

このブログ記事をはてなブックマークに追加

しばらく前にリトルビッグプラネットのすべてのステージをノーミス(ライフパーフェクト)でクリアした(ゴールドトロフィー「プレイ」取得)。後半のステージが結構大変だったな。最難関といわれているスノーランドのファクトリーは確かに難しかったけど、慣れたら思ったより苦労はしなかった。それよりも何故かダンシングパレスのほうが苦労した。眠かったせいもあるかもしれないけど普段しないようなミス連発。あそこのステージは乗り物系のからくりが多くて突っ走ってクリアができない(つまり時間がかかる)のもきつかった原因。でもそのステージの内容自体は好きだけど。

ライフパーフェクトに比べて全アイテム集め(シルバートロフィー「アイテムフリーク」取得)は楽だったかな。オンラインでみんなとワイワイやっていれば集まるってのも楽だった理由。フレンドと2人でやっているときにフローズンツンドラのx4(4人プレイ専用)をやったのだけど、こちらが一人でコントローラ3個使ってクリアした。手が攣りそうだったよ…。

アイテムもすべて集めたので最近はクリエイトに手を出してみたのだが、これも楽しいな。慣れるまで大変だけど自分で仕掛けを考えて作るってのは予想以上に面白い。現在の作品が完成したら公開してみよう。なんだかステージの構想を練ったり、実際にパーツを組み立てて作成する感じが、プログラミングを彷彿とさせるな。

とにかくリトルビッグプラネットは楽しい。横スクロールのアクションゲームにリアルな物理演算と画像処理、作成ツール、オンラインプレイ等々、既存のパーツの寄せ集めでできているのだけど、プレイする感覚はこれまでにない新しいものだった。こんな素晴らしいゲームが出てくるのを見ると、まだまだテレビゲームも捨てたものじゃないなと思う。

続きを読む...

2008年10月31日金曜日

ActionScript 3.0でハロウィン

このブログ記事をはてなブックマークに追加

お菓子をくれなきゃ、いたずらするぞ! Trick or Treat!

ということで、ハロウィン。ActionScript 3.0を使って10分ほどで作成。カボチャをクリックすると色が変わる。

以下に、ソースコードを示す。

Halloween.as

// Halloween.as // by nox, 2008.10.31 package { import flash.display.*; import flash.text.*; import flash.events.*; import flash.utils.Timer; public class Halloween extends Sprite { // dafont.com http://www.dafont.com/ [Embed(systemFont="Halloween Borders", fontName="HalloweenFont", mimeType="application/x-font" )] private static const HalloweenFont:Class; private var txtHalloween:TextField = new TextField(); private var HalloweenStageWidth:int, HalloweenStageHeight:int; private var timer:Timer; private function ClickHandler(event:Event):void { var format:TextFormat = txtHalloween.getTextFormat(); format.color = Math.random() * 0xFFFFFF; txtHalloween.setTextFormat(format); } private function OnTick(event:TimerEvent):void { txtHalloween.x += (Math.random() - 0.5) * 2; txtHalloween.y += (Math.random() - 0.5) * 2; } private function Init():void { var format:TextFormat = new TextFormat(); with (format) { color = 0xCC0000; size = 144; align = TextFormatAlign.CENTER; font = "HalloweenFont"; } with (txtHalloween) { autoSize = TextFieldAutoSize.CENTER; selectable = false; x = HalloweenStageWidth / 2; embedFonts = true; defaultTextFormat = format; text = "e"; y = (HalloweenStageHeight - textHeight) / 2; } addChild(txtHalloween); txtHalloween.addEventListener(MouseEvent.CLICK, ClickHandler); timer = new Timer(10); timer.addEventListener(TimerEvent.TIMER, OnTick); timer.start(); } public function Halloween() { HalloweenStageWidth = stage.stageWidth; HalloweenStageHeight = stage.stageHeight; Init(); } } }

Halloween-config.xml

<flex-config> <output>Halloween.swf</output> <default-size> <width>150</width> <height>150</height> </default-size> <default-frame-rate>60</default-frame-rate> <default-background-color>0xFFFFFF</default-background-color> <use-network>false</use-network> </flex-config>

続きを読む...

2008年10月29日水曜日

ActionScript 3.0で少し早いクリスマス気分を味わう

このブログ記事をはてなブックマークに追加

クリスマスあたりを目処に簡単なゲームをActionScript 3.0で作ろうかと思って、その雛型を作ってみた。雛型なんでホントに形だけだけど。それでも赤と緑の色合いとクリスマスソングで気分だけはクリスマスっぽくなるなぁ。それにしても未だにActionScript 3.0の使い方がこんなんで良いのか疑問に思う。なんだか無駄の多いコードのような気がする。

以下のFlashコンテンツをマウスクリックなどでアクティブにして適当なキーを押すと始まる。MP3だけで2.5MBあるので少し重いかも。尚、音が鳴るので注意すること。因みに飛んでいる天使をクリックすると…。


BGMにtaitai studioフリーMp3素材集からHappy Christmas Partyを利用させてもらった。また、効果音は効果音gから。フォントについてはdafont.comからクリスマス関連のフォントを使用した。

以下、ソースコード。

ActionXmas.as

// ActionXmas.as // by nox, 2008.10.29 package { import flash.display.*; import flash.text.*; import flash.events.*; import flash.media.Sound; import flash.media.SoundChannel; import flash.utils.Timer; public class ActionXmas extends Sprite { // taitai studio http://www.taitaistudio.com/ // taitai studio フリーMp3素材集 http://www.taitaistudio.com/mp3/ [Embed(source="xmas.mp3")] private static const SoundXmas:Class; // 効果音g http://sfxg.bufsiz.jp/index.html [Embed(source="slap01.mp3")] private static const SoundSlap:Class; // dafont.com http://www.dafont.com/ [Embed(systemFont="KR Christmas Dings 2004 Four", fontName="StFont", mimeType="application/x-font" )] private static const StFont:Class; [Embed(systemFont="Kingthings Christmas ", fontName="XmasFont", mimeType="application/x-font" )] private static const XmasFont:Class; [Embed(systemFont="Faux Snow BRK", fontName="SnowFont", mimeType="application/x-font" )] private static const SnowFont:Class; private static const version:String = "0.01"; private var bgm:Sound = new SoundXmas() as Sound; private var ss:Sound = new SoundSlap() as Sound; private var channel:SoundChannel; private var txtTitle:TextField = new TextField(); private var txtSt:TextField = new TextField(); private var txtFadeSt:TextField = new TextField(); private var txtXmas:Array = new Array(); private var txtXmasList:Array; private var txtXmasLength:int; private var txtXmasWidth:Number; private var txtXmasMargin:Number; private var txtSnow:Array = new Array(); private var txtSnowList:Array; private var speedSnow:Array = new Array(); private var numTxtSnow:int = 30; private var txtSnowMargin:Number = 300; private var timer:Timer; private var delta_y_st:Number = 0.5; private var XmasStageWidth:int, XmasStageHeight:int; private function ClickHandler(event:Event):void { ss.play(); // fade flying angel FadeSt(); } private function OnTick(event:TimerEvent):void { var i:int; // flying angel if (txtSt.y > XmasStageHeight / 10 + 10) delta_y_st = -0.5; else if (txtSt.y < XmasStageHeight / 10 - 10) delta_y_st = 0.5; txtSt.y += delta_y_st; TickFadeSt(); // walking background characters for (i = 0; i < txtXmasLength; i++) { txtXmas[i].x += 1; if (txtXmas[i].x > txtXmasWidth - txtXmasMargin) txtXmas[i].x -= txtXmasWidth; } // fall snow for (i = 0; i < numTxtSnow; i++) { txtSnow[i].y += 1 * speedSnow[i]; txtSnow[i].x += (Math.random() - 0.5) * 2 + 1; if (txtSnow[i].x > XmasStageWidth + txtSnowMargin) txtSnow[i].x -= XmasStageWidth + txtSnowMargin * 2; if (txtSnow[i].y > XmasStageHeight) NewSnow(i); } } private function FadeSt():void { with (txtFadeSt) { defaultTextFormat = txtSt.defaultTextFormat; autoSize = TextFieldAutoSize.CENTER; selectable = false; text = txtSt.text; x = txtSt.x; y = txtSt.y; embedFonts = true; alpha = 1.0; } addChild(txtFadeSt); removeChild(txtSt); } private function TickFadeSt():void { txtFadeSt.alpha *= 0.95; txtFadeSt.x = txtSt.x; txtFadeSt.y = txtSt.y; } private function OnPlaybackComplete(event:Event):void { txtSt.removeEventListener(MouseEvent.CLICK, ClickHandler); timer.stop(); // ending var format_red:TextFormat = new TextFormat(); var format_small:TextFormat = new TextFormat(); format_red.color = 0xCC0000; format_small.size = 48; with (txtTitle) { text = "Fin\nHit Any Key!"; autoSize = TextFieldAutoSize.LEFT; x = XmasStageWidth / 10; y = XmasStageHeight / 5; for each (var n:int in [0, 4, 8, 12]) setTextFormat(format_red, n); setTextFormat(format_small, 4, 16); } addChild(txtTitle); stage.addEventListener(KeyboardEvent.KEY_UP, StartGame); } private function SetFlyingAngel():void { var format:TextFormat = new TextFormat(); var format_red:TextFormat = new TextFormat(); with (format) { color = 0x00CC00; size = 72; align = TextFormatAlign.CENTER; font = "StFont"; } format_red.color = 0xCC0000; with (txtSt) { defaultTextFormat = format; autoSize = TextFieldAutoSize.LEFT; selectable = false; x = XmasStageWidth * 3 / 5; y = XmasStageHeight / 10; embedFonts = true; text = "t"; } addChild(txtSt); } private function SetBackgroundCharacters():void { var format:TextFormat = new TextFormat(); var format_red:TextFormat = new TextFormat(); with (format) { color = 0x00CC00; size = 72; align = TextFormatAlign.CENTER; font = "StFont"; } format_red.color = 0xCC0000; with (txtXmas[0]) { embedFonts = true; defaultTextFormat = format; text = txtXmasList.toString(); } // length of background charactors txtXmasWidth = txtXmas[0].textWidth; txtXmasMargin = (txtXmasWidth - XmasStageWidth) / 2; for (var i:int = 0; i < txtXmasLength; i++) { with (txtXmas[i]) { autoSize = TextFieldAutoSize.CENTER; selectable = false; embedFonts = true; defaultTextFormat = format; text = txtXmasList[i]; x = i > 0 ? txtXmas[i-1].x + txtXmas[i-1].textWidth : -txtXmasMargin; y = XmasStageHeight * 2 / 3; } addChild(txtXmas[i]); } // red in background charactors txtXmas[0].setTextFormat(format_red); } private function SetSnow():void { var format:TextFormat = new TextFormat(); var format_size:TextFormat = new TextFormat(); with (format) { color = 0xFFFFFF; align = TextFormatAlign.LEFT; font = "SnowFont"; } for (var i:int = 0; i < numTxtSnow; i++) { format_size.size = 24 + Math.random() * 48; speedSnow[i] = 0.5 + Math.random() * 0.5; with (txtSnow[i]) { selectable = false; embedFonts = true; defaultTextFormat = format; text = txtSnowList[int(Math.random() * txtSnowList.length)]; x = Math.random() * (XmasStageWidth + txtSnowMargin * 2) - txtSnowMargin; y = -100; setTextFormat(format_size); alpha = 0.3 + Math.random() * 0.7; } addChild(txtSnow[i]); } } private function NewSnow(n:int):void { var format:TextFormat = new TextFormat(); var format_size:TextFormat = new TextFormat(); with (format) { color = 0xFFFFFF; align = TextFormatAlign.LEFT; font = "SnowFont"; } format_size.size = 24 + Math.random() * 48; speedSnow[n] = 0.5 + Math.random() * 0.5; with (txtSnow[n]) { selectable = false; embedFonts = true; defaultTextFormat = format; text = txtSnowList[int(Math.random() * txtSnowList.length)]; x = Math.random() * (XmasStageWidth + txtSnowMargin * 2) - txtSnowMargin; y = -100; setTextFormat(format_size); alpha = 0.3 + Math.random() * 0.7; } } private function StartGame(event:Event):void { removeChild(txtTitle); stage.removeEventListener(KeyboardEvent.KEY_UP, StartGame); txtSt.addEventListener(MouseEvent.CLICK, ClickHandler); channel = bgm.play(); channel.addEventListener(Event.SOUND_COMPLETE, OnPlaybackComplete); // show flying angel SetFlyingAngel(); // show background characters SetBackgroundCharacters(); // show snow SetSnow(); timer.start(); } private function InitGame():void { var format:TextFormat = new TextFormat(); var format_red:TextFormat = new TextFormat(); var format_small:TextFormat = new TextFormat(); var i:int; // opening (upper letters are red, others are green) with (format) { color = 0x00CC00; size = 72; align = TextFormatAlign.CENTER; font = "XmasFont"; } format_red.color = 0xCC0000; format_small.size = 48; with (txtTitle) { autoSize = TextFieldAutoSize.CENTER; selectable = false; x = XmasStageWidth / 2; y = XmasStageHeight / 3; embedFonts = true; defaultTextFormat = format; text = "ActionXmas\nHit Any Key!"; } for each (var n:int in [0, 6, 11, 15, 19]) txtTitle.setTextFormat(format_red, n); txtTitle.setTextFormat(format_small, 11, 23); addChild(txtTitle); txtXmasList = ["s", "k", "e", "h", "j", "r", "g", "x", "n", "i"]; txtXmasLength = txtXmasList.length; for (i = 0; i < txtXmasLength; i++) txtXmas[i] = new TextField(); txtSnowList = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]; timer = new Timer(10); timer.addEventListener(TimerEvent.TIMER, OnTick); for (i = 0; i < numTxtSnow; i++) txtSnow[i] = new TextField(); } public function ActionXmas() { XmasStageWidth = stage.stageWidth; XmasStageHeight = stage.stageHeight; InitGame(); stage.addEventListener(KeyboardEvent.KEY_UP, StartGame); } } }

ActionXmas-config.xml

<flex-config> <output>ActionXmas.swf</output> <default-size> <width>350</width> <height>350</height> </default-size> <default-frame-rate>60</default-frame-rate> <default-background-color>0x000000</default-background-color> <use-network>false</use-network> <compiler> <fonts> <languages> <language-range> <lang>englishRange</lang> <range>U+0020-U+007E</range> </language-range> <language-range> <lang>otherRange</lang> <range>U+00??</range> </language-range> </languages> </fonts> </compiler> </flex-config>

続きを読む...

2008年10月22日水曜日

Processingで分子動力学計算

このブログ記事をはてなブックマークに追加

Processing面白いなぁ。以前はhttp://proce55ing.orgが公式サイトだったことから、Proce55ingとしても知られている。Java仕様のビジュアルデザイン用プログラミング言語なのだが、とても簡単に扱うことができる。プログラミングでアートする感じ。

そこで今回はなんちゃって分子動力学計算プログラムを作ってみた。もちろん原子をリアルタイムに計算しながら表示させている。ただし、コードを短くするために分子ではなく疑似原子単体同士の相互作用にしている。そのため計算している相互作用はvdW力とクーロン力のみだ。また特に工夫をしているわけでもなく全原子同士のすべての相互作用をそのまま計算している。分子動力学計算の詳細についてはPEACHによる生体分子の分子動力学シミュレーション(1)原理と方法あたりを参考にすると良いと思う。

実際のプログラムを以下に示す。num_atomsで原子数を指定しており、初期配置を比較的密集させてその状態で力を計算させている。また、左上にエネルギーを表示している。初期の高エネルギー状態から低エネルギー状態に安定化するのが見て取れる。その他の詳しいことは実際にソースコードを読めば分かると思う。短いしね。

This browser does not have a Java Plug-in.
Get the latest Java Plug-in here.



以下、ソースコード。

simple_md.pde

/** * Simple molecular dynamics by nox, 2008.10.21. * * Perform molecular dynamics for pseudo-atoms without internal * interactions, such as bonds, angles, dihedrals. Only vdW and * Coulomb interactions. */ final int num_atoms = 20; Atom[] atoms = new Atom[num_atoms]; void setup() { size(360, 360, P3D); noStroke(); // initialize positions of atoms int cnt = 0; int num_side = ceil(pow(num_atoms, 1.0 / 3.0)); for (int i = 0; i < num_side && cnt < num_atoms; i++) for (int j = 0; j < num_side && cnt < num_atoms; j++) for (int k = 0; k < num_side && cnt < num_atoms; k++) atoms[cnt++] = new Atom((i - num_side / 2) * 20, (j - num_side / 2) * 20, (k - num_side / 2) * 20); PFont font = createFont("Times New Roman", 32); textFont(font); } float calcDistance(int atom1, int atom2) { float distance, sum = 0.0; for (int i = 0; i < 3; i++) { distance = atoms[atom1].crd[i] - atoms[atom2].crd[i]; sum += distance * distance; } return sqrt(sum); } float calcDistanceXYZ(int atom1, int atom2, int xyz) { return atoms[atom1].crd[xyz] - atoms[atom2].crd[xyz]; } float calcEnergy(Atom[] atoms, int num_atoms) { float sum = 0.0; for (int i = 0; i < num_atoms; i++) sum += atoms[i].energy(); return sum / 2.0; } void draw() { background(0); lights(); float[] r = new float[num_atoms]; float[][] r_xyz = new float[num_atoms][3]; for (int i = 0; i < num_atoms; i++) { for (int j = 0; j < num_atoms; j++) { r[j] = calcDistance(i, j); for (int k = 0; k < 3; k++) r_xyz[j][k] = calcDistanceXYZ(i, j, k); } atoms[i].calculate(r, r_xyz, num_atoms); } for (int i = 0; i < num_atoms; i++) atoms[i].move(); text("Energy: " + calcEnergy(atoms, num_atoms), 10, 40); }

simple_atom.pde

class Atom { float[] crd, f, max_range; float ene; Atom() { this(0, 0, 0); } Atom(float x, float y, float z) { this.crd = new float[3]; this.f = new float[3]; this.crd[0] = x; this.crd[1] = y; this.crd[2] = z; for (int i = 0; i < 3; i++) this.f[i] = 0.0; this.max_range = new float[3]; this.max_range[0] = width / 2; this.max_range[1] = height / 2; this.max_range[2] = 200; } // Calculate energies and forces // Total energy = vdW + Coulomb // vdW // U = eps * [(Rij / r[i])^12 - 2 * (Rij / r[i]^6)] // F = -12 * eps / Rij * [(Rij / r[i])^13 - (Rij / r[i])^7] * r_xyz / r[i] // Coulomb // U = SUM_i>j qiqj / r[i] // F = SUM_j qiqj / r[i]^3 * r_xyz void calculate(float[] r, float[][] r_xyz, int num_atoms) { float[] delta_f = new float[3]; final float eps = 10.0; final float Rij = 10.0; final float q = 10.0; // qi*qj this.ene = 0.0; for (int i = 0; i < num_atoms; i++) { if (r[i] == 0.0) continue; final float R12 = pow(Rij / r[i], 12); final float R6 = pow(Rij / r[i], 6); this.ene += eps * (R12 - 2.0 * R6); this.ene += q / r[i]; for (int j = 0; j < 3; j++) { delta_f[j] += -(12 * eps / Rij) * (R12 * Rij / r[i] - R6 * Rij / r[i]) * r_xyz[i][j] / r[i]; delta_f[j] += q / pow(r[i], 3) * r_xyz[i][j]; } } for (int i = 0; i < 3; i++) this.f[i] += delta_f[i]; } float energy() { return this.ene; } void move() { pushMatrix(); for (int i = 0; i < 3; i++) { this.crd[i] += this.f[i]; if (this.crd[i] > max_range[i] || this.crd[i] < -max_range[i]) this.f[i] *= -1; } translate(max_range[0] + this.crd[0], max_range[1] + this.crd[1], -max_range[2] + this.crd[2]); sphere(20); popMatrix(); } }

続きを読む...

2008年10月19日日曜日

2D物理演算ソフトウェアPhunを楽しむ

このブログ記事をはてなブックマークに追加

2D物理演算ソフトウェアのPhunは楽しい。Phunと云う名前自体が、Physics(物理)+Fun(楽しむ)の造語であり、名が体を見事に表している。

物理演算と聞くとなにやら難しそうだが、このPhunは少しも難しくない。もちろん壮大な設計図のもと、緻密で複雑な機械を作ろうとすれば大変だろうが、とりあえず四角や丸の置物、バネや水を出してみたりといったことはマウス操作でちょちょいのちょいだ。3歳の子供だってできるのだから誰にだってできるだろう。



まずはここに掲載されているPhunの動画を見て欲しい。ちょっとばかり楽しい気分になれる。因みに自分はリトルビッグプラネットのβテストが終わってしまったので、発売日までそれに代わる類似ソフトを探していたところPhunを知った。もしPhunを少しでも楽しめたのならリトルビッグプラネットに嵌ることは間違いないと思う。

続きを読む...

2008年10月14日火曜日

ブルーレイディスクで録画データをバックアップ

このブログ記事をはてなブックマークに追加

自宅の居間に設置しているPCはほぼ録画専用になっていてHDD容量は500GBだ。しかし、この容量でも録画目的だと全然足りない。仕方がないので、MPEG-4に変換して保存したり、DVDにバックアップしてたりしたのだが、バックアップの手間が非常にかかるので、先日、ブルーレイディスク(BD)ドライブを購入した。

MPEG-4への変換は、Pythonスクリプトとmencoderを使って、タイトルから自動的にフォルダを割り振って変換するようにしてあるので、ある程度自動化できていたのだが、DVDへのバックアップについては、1枚4.8GBの容量では何度もドライブから出し入れしなくてはならず非常に厄介だった。BDだと一層で25GB、二層(DL)で50GBと、DVDに比べ容量が格段に大きいのでバックアップがとても楽になった。最近はBD-Rの値も下がり、一枚350円を切る値段になっていて、これなら許容できる。

と云うわけで、我が家では着々とBD化が進んでいる。そう言えば最近は市販のDVDはまったく購入しなくなってしまった。BDの画質を見た後だととてもDVDを購入する気にはなれないなぁ…。

続きを読む...

2008年10月8日水曜日

C言語で複数のアルゴリズムを使って円周率を求める

このブログ記事をはてなブックマークに追加

以前、大学でプログラミング実習を教えたときの課題だった、複数のアルゴリズムで円周率を求めるプログラムが出てきたのでここに書いておく。実行時間も測定している。これはCで書いたけど、使用言語はFortranでも可だったはず。

出力結果:

Machin's formula: 3.14159265358979 Time: 0.437000s (1000000 times) Gauss-Legendre : 3.14159265358979 Time: 0.219000s (1000000 times) Count points : 3.14552000000000 Time: 0.265000s (10 times) Monte Carlo : 3.14394000000000 Time: 0.594000s (10 times) Circumference : 3.14159265358979 Time: 3.047000s (1000000 times) Integral : 3.14159265393433 Time: 0.375000s (10 times)

Machin's formula, Gauss-Legendre, Circumferenceは100万回計算、Count points, Monte Carlo, Integralは10回計算して時間を測定している。それにしても、算術幾何平均を使ったガウス-ルジャンドルのアルゴリズムは速いなぁ。

以下、ソースコード。

/*======================================================= ratio of the circumference of a circle to its diameter =======================================================*/ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> /*------------------------------------------------------- Machin's formula: PI/4 = 4*arctan(1/5) - arctan(1/239) --------------------------------------------------------*/ double pi_machin(int dummy) { int k; double p, temp, last; p = 0.0; /* 4*arctan(1/5) */ k = 1; temp = 16.0 / 5.0; /* arctan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... */ do { last = p; p += temp / k; temp /= -5.0 * 5.0; k += 2; } while (p != last); /* arctan(1/239) */ k = 1; temp = 4.0 / 239.0; do { last = p; p -= temp / k; temp /= -239.0 * 239.0; k += 2; } while (p != last); return p; } /*------------------------------------------------------- Gauss-Legendre algorithm a[1] = 1, b[1]= 1/sqrt(2) arithmetic means: a[n+1] = (a[n] + b[n]) / 2 geometric means: b[n+1] = sqrt(a[n] * b[n]) PI[n] = 2*a[n+1]^2 / (1-SUM^n_k=0{2^k*(a[k]^2-b[k]^2)}) = 2*a[n+1]^2 / (1-SUM^n_k=0{2^k*(a[k]-a[k-1])^2}) PI[n->inf] -> PI --------------------------------------------------------*/ double pi_gauss_legendre(int dummy) { int i; double a, b, s, temp, last; a = 1.0; b = 1.0 / sqrt(2.0); s = 1.0; temp = 4; do { last = a; a = (a + b) / 2.0; /* arithmetic means */ b = sqrt(last * b); /* geometric means */ s -= temp * (a - last) * (a - last); temp *= 2.0; } while (a != last); return (a + b) * (a + b) / s; } /*------------------------------------------------------- Using count points in circle num: length of side -------------------------------------------------------*/ double pi_points(int num) { int i, j, hit; double x, y, p; hit = 0; for (i = 0; i < num; i++) { for (j = 0; j < num; j++) { x = (double)i / num; y = (double)j / num; if (x * x + y * y < 1.0) hit++; } } p = (double)hit / (num * num); return p * 4.0; } /*------------------------------------------------------- Using Monte Carlo method num: number of random points -------------------------------------------------------*/ double pi_monte(int num) { int i, hit; double x, y, p; hit = 0; for (i = 0; i < num; i++) { x = (double)rand() / RAND_MAX; y = (double)rand() / RAND_MAX; if (x * x + y * y < 1.0) hit++; } p = (double)hit / num; return p * 4.0; } /*------------------------------------------------------- 2*PI <- length of side * N div: number of division on a side of hexagon -------------------------------------------------------*/ double pi_circumference(int div) { /* 2*PI = sin(theta) * 360.0 / theta */ int i; double a, b, multi; a = 1.0; multi = 1.0; for (i = 0; i < div; i++) { b = 1.0 - sqrt(1.0 - a * a / 4.0); a = sqrt(b * b + a * a / 4.0); multi *= 2.0; } return a * 6.0 * multi / 2.0; } /*------------------------------------------------------- x^2 + y^2 = 1, y = sqrt(1 - x^2) PI/4 = INT{y}dx div: number of division on integrals -------------------------------------------------------*/ double pi_integral(int div) { int i; double p, delta, y, a; y = 0.0; for (i = 0; i < div; i++) { a = (i + 0.5) / div; y += sqrt(1.0 - a * a); } return y / div * 4.0; } /*------------------------------------------------------- Measurement of time func: function of calculation of pi arg: argument of function num: number of repeats msg: message of output -------------------------------------------------------*/ void run(double (*func)(int), int arg, int num, char *msg) { clock_t start, finish; int i; start = clock(); for (i = 0; i < num - 1; i++) (*func)(arg); printf("%-16s: %16.14f\n", msg, (*func)(arg)); finish = clock(); printf("Time: %14.6fs (%d times)\n",(double)(finish - start) / CLOCKS_PER_SEC, num); printf("\n"); } int main() { srand((unsigned int)time(NULL)); run(pi_machin, 0, 1000000, "Machin's formula"); run(pi_gauss_legendre, 0, 1000000, "Gauss-Legendre"); run(pi_points, 1000, 10, "Count points"); run(pi_monte, 1000000, 10, "Monte Carlo"); run(pi_circumference, 50, 1000000, "Circumference"); run(pi_integral, 1000000, 10, "Integral"); return 0; }

続きを読む...

2008年10月7日火曜日

PS3:「リトルビッグプラネット」信じられない面白さ

このブログ記事をはてなブックマークに追加

1年以上前に「LittleBigPlanet」というエントリを書いた。そしてとうとうリトルビッグプラネット日本語版が10月30日に発売する。それに先駆けて、βテスターの募集があったのだが、運よく日本地域枠の2万人に入ったようでβテストに参加することができた。因みに、米国、欧州でそれぞれ2万人の枠があり、全部で6万人のβテスターがいることになる。

早速、PSN経由で1GB弱のファイルをダウンロード、インストールし、プレイしてみたのだが、予想以上に楽しい。本当に楽しい。誰にでもすぐにできる簡単操作、自由にコーディネートできる愛くるしいリビッツ人形、世界中の人とのオンラインプレイ、想像力を刺激するステージのクリエイトなど。これほど予想を上回るできのソフトはアンチャーテッド以来かなぁ。アンチャーテッドとはジャンルがぜんぜん違うけど。

百聞は一見にしかずということで、まずはトレイラー動画を観ていただきたい。



どうですか? 面白そうですか? 実は自分はそれほど面白そうだと思わなかった。もし、この時点で凄く楽しそうと感じたなら、即、購入で間違いない。

動画ではそれほど面白そうだとは思わなかったけど、確かに実写のようなプレイ画面や驚くほどリアルな物理演算処理は凄いと思ったので、βテストに応募してプレイしてみたのだが、このとき初めて自分の考えが誤っている事に気が付いた。これはプレイしないとその凄さが分からない。百見は一プレイにしかず、である。正直、このゲームの楽しさ、面白さは文章では伝わらないと思うので、これ以上の説明はしない。しかし、週末のプレイを楽しみにしていたところ、子供たちに見つかって占領されてしまい、自分はあまりプレイできなかったことからも、その楽しさが伝わるはずだ。

やっとPS3の性能をちゃんと使った、次世代機らしい、素晴らしいゲームソフトが出てきた。老若男女を問わずに遊べるので是非多くの人にプレイして欲しい。

続きを読む...

2008年9月24日水曜日

Evernoteを使わないと人生損する

このブログ記事をはてなブックマークに追加

Evernoteを使っていないと人生を損していると思う。もちろん独断と偏見だけど。それにしても、もっと早くからこのようなサービスがあることを知っていればなぁ、と思ってしまう。それほどまでに個人的には画期的なアプリケーションであり、サービスであったのだ。

少し前にあるウェブサイトでEvernoteのことを知り、すぐにインストールした。しかし、イマイチその便利さが分からずしばらく放置していた。まず、どのように使えばいいか分からない。画像やPDFファイルなどを貼り付けることができるノートのようなものと云うことは分かったのだが、どこが便利なのか。普通にノートを取れば済む事ではないかと思ってしまったのだ。

それで、Evernoteはしばらく使っていなかった。ところで、自分は仕事用のノートを持っており、ミーティングやセミナー、仕事の進捗、ちょっとしたメモをこれに書いていた。ある日、以前行った仕事の手順を知るためにそのノートを見返してみたのだが、すぐに該当する箇所を見つけることができなかった。この時間の浪費はひどく損だ。特に仕事関係のメモは高い頻度で見返すことが多く、仕事の効率にも響く。そこで、Evernoteを思い出した。Evernoteならタグでグループ分けもでき、ソートや検索もお手の物だ。これは使わない手はないと、ここで初めて気が付いた。

それからしばらく使ってみたのだが、これがとても良い。まず、入力したメモやデータがオンラインストレージと同期されるので、どのPCからも同じノートを読むことができる。もちろん、オンラインでデータを扱うことに対しセキュリティが気になるようならローカルデータとして扱うこともできる。この場合、入力したPCでしか閲覧できないが。

また、普段PCを使って仕事しているので、仕事の進捗など一々ノートを取り出して開いてペンで書き込むという行為はそれだけで効率が落ちるのだ。EvernoteであればPCから離れることもない。さらに、仕事のデータ、例えば数値計算のグラフなどを画像のまま貼り付けることができるのも凄く便利だ。

自分は仕事柄、論文を読むことが多く、ほとんどの場合PDFで保存されているのだが、その管理が今までは非常に大変であった。ファイル名やフォルダでの分類に気を使って管理していたのだが、これだと手間が掛かり、ファイル数が多いとあまり機能しなくなる。EvernoteだとPDFファイルをドラッグ&ドロップするだけだし、読んだ内容をちょこっとメモするだけで情報の価値も格段に上がる。検索も一発だ。今までの苦労が嘘のようである。

ノートブックは目的別に複数作成できるので、仕事用のノート、個人用備忘録のノート、それにこのブログ記事用のノートも作った。ブログで書きたいことを思いついたとき、タイトルもしくは短い要旨だけをノートに書いておく。そして、後で時間ができたときにちゃんと書き直してブログにアップするわけだ。もちろん、メモだけ取ってやっぱり書かない記事もあるが、メモをしてからしばらく時間を置くことで本当に書きたい記事かどうかを見極めることもでき一石二鳥だ。

これで自分がEvernoteを使わないと損すると思う理由を理解してもらえただろうか。とりあえず簡単な使い方を知りたいのなら、シゴトハッカーズ:Evernoteの基本的な使い方【チュートリアル編】あたりが参考になる。因みに対応機種にはWindows, Mac, iPhone, Windows Mobileがあり、ソフトウェア自体は無料だ。さらにブラウザ上からも操作することができる。ただし、使うには無料のアカウント登録をする必要がある。オンラインストレージは月に40MBまでは無料であり、有料のプレミアム会員になると月に500MBまで使える。プレミアム会員の料金は月5ドルもしくは年45ドルのどちらかを選ぶことができる。

続きを読む...

2008年9月19日金曜日

UMPC購入で最終的に選んだのはWILLCOM D4

このブログ記事をはてなブックマークに追加

しばらく前からUMPC(Ultra Moblie PC)に興味を持っていたのだが、いろいろと調べた上で最終的に購入したのはWILLCOM D4だった。今のところ、かなり満足している。

購入動機

現在、仕事では多数のUnix系マシンとWindows XPを搭載したメインノートPC、自宅では多目的用途のWindows XP搭載のメインデスクトップPC、Windows Vista搭載のTV録画用途キューブPCを使っている。メインノートPCはちょっと古いがLet's Note CF-W4を使っており、毎日、職場・自宅間を持ち歩いている。重量は約1.2kgである。

で、通勤時に1.2kgを持ち歩くのが重く感じられてきたのでサブノートが欲しくなったのだ。そこで、メインノートPCの代わりになる性能を持ち、コンパクトで軽いサブノートを物色してみた。

選定

まずここで大事なのは、重量、大きさ、性能だ。特に持ち歩きを楽にしたいので重量が最も優先される項目である。次に性能だろう。普段メインノートPCで行っていることは一通りこなしたい。大きさについては軽ければ軽いほど小さくなると思ったのでそれほど気にしなかった。もちろん、価格については安いほど良い。

そこで、最近出ているUMPCを一通り調べてみた。いわゆるネットブック(Netbook)と呼ばれる低価格なノートPCでは重さに問題がある。大体1kgほどあるのだ。現在使用しているLet's Noteが1.2kgであることを考えると、1kg前後ではあまり重量としてのメリットがない。それならば、0.9kgのLet's Note Rシリーズのほうが(価格以外は)良いだろう。今回は重量を大幅に減らして運搬を楽にすることが目的の一つとなっているので、現在の半分ほどの重さにはしたい。そこで、1.2kgの半分で600g程度を目安とした。これを踏まえてUMPCを調べてみるとWILLCOM D4とLOOX U/B50しか残っていないことが分かった。と云うわけでこの二つの中から選ぶことにした。

WILLCOM D4とLOOX U/B50ではそれほど性能に差はないようだが、若干LOOX U/B50のほうが良さそう。しかし、D4であればPHS通信が最初から使えるのでどこでも簡単にネットに繋ぐことができる。また、価格のほうでもD4のほうが安い。特にW-VALUE割引により実質価格が6万円以下になる。また、購入の指針には入れなかったが見た目は個人的にはD4のほうが良い。この点は性能には影響しないが個人的な満足感には影響する。

というわけで最終的に選んだのはWILLCOM D4だった。因みにこの時点で実際に実機には触れている。やはり実機に触れることは大事だと思う。

WILLCOM D4の評判

しかし、実際に使った人でないとスペック以外の目に見えない部分については分からない。そこでネット上でWILLCOM D4の評判を調べてみた。かなり気に入っている人もいる一方、購入して最悪だったという人もいる。まず、欠点として挙げられているのが、無線LANの感度の悪さだ。すぐ近くに無線ポートがあっても途中ぶちぶち切れるのだとか。ほかに、電池の持ちが悪い、Windows XPではなくVistaである、筐体のSHARPのロゴを押すだけでスリープが復帰してしまう、全般的に不安定、などなど。いろいろ挙がっている。

このように欠点もかなりあるようだが、結局、この軽さには何物にも代えがたく、WILLCOM D4の購入に踏み切ることにした。

WILLCOM D4を使用した感想

この小ささで普通のPCと同じことができることは驚きである。Windows Vistaが動いているので当たり前なのだが、それでも普通にメールやウェブはもちろんのこと、PythonやVisual C++までも使えるのは嬉しい。VPN ClientでIPSecを通して職場のネットワークを使えるのも便利だ。

また、懸念していた無線LANの感度の悪さはほとんど感じなかった。確かにアンテナは3-4本だったりするが、職場、自宅、実家などで試したところ一度も通信が途切れなかった。メインノートPCのLet's Noteのほうがよっぽど感度が悪い(これは多分自分がはずれを引いたからだと思うが、有線LANもあるし修理に出すほど困っているわけではないのでそのまま使っている)。

電池の持ちはそれほど長いわけではないが、Ver. Lを購入したので大容量バッテリーが付いてきたし、不自由はしてない。公称では4.5時間とあるが実質3.5時間ぐらいか。SHARPのロゴを押すことでスリープ復帰とのことだが、基本的に持ち運び時はキーロックをするので勝手に起動することはない。ただし、不安定さは若干あるかもしれない。一度、シャットダウン時にブルースクリーンになったことがある。ただ、頻繁にあるわけではないのでそれほど問題視はしていない。

上記のように、使用した感想は概ね満足できるものだった。

より使いやすく

始めからWindows Vistaに入っているアプリケーションだけでは仕事としても趣味としても使えないので、いくつかの設定とアプリケーションをインストールすることにした。

まず、ディスク容量だが、40GBのHDDを備えていて、10GBほどはリカバリ領域に使われており、残りの30GBのうち10GBはシステムで使っている。実質ユーザが使える領域は20GB弱ほどだ。そこで、外部記憶装置としてmicroSDHC 8GB(Class 6)をつけることにした。ダウンロードしたファイルや仕事用の一時ファイルはすべてここに置く。microSDはClass 4以上は対応していないとのことだったが、転送速度が上がらないだけで実際は使えるようだ。次に、ネットワークの設定だ。無線LANは最初切れているのでFn+Capsで使えるようにする。当初、これに気が付かないで少し戸惑った。あとはプリンタ設定だが、自宅のローカルプリンタ、職場のネットワークプリンタどちらも問題なしだった。

次いで、アプリケーションのインストールを行った。インストールしたソフトウェアは以下の通りだ。

Microsoft Office
Officeの付いていないVer. Lだったので。デスクトップPC用にOfficeを購入していたのでそれをインストールした。因みに一つのOfficeアプリケーションをメインのPCとサブのノートPCにインストールすることはライセンス上で認められている行為だ。

Kasparsky
これは以前購入した3ユーザライセンスのものが余っていたので。

Visual C++
やっぱりC++で遊びたい。

xyzzy
普段はWZ EDITORをEmacsキーバインドで利用しているが、Emacsならxyzzyでもいいかと思って。因みに自宅のビデオ録画用PCでも利用している。

ActivePython
Pythonは基本。最近は何をやるにしてもPythonだ。

IPython
Pythonとセットで。コマンドラインでちょっとした操作をしたいときに便利。電卓にもなるし。

FileVisor6
ファイル操作・管理ユーティリティ。ファイルエクスプローラを便利にしたもの。シェアウェアだがもうこれがないとWindowsが使えない体になってしまっている。普段はFileVisor5を利用しているが、VistaだということでFileVisor6を購入した。

Cisco VPN Client
職場のネットワークに繋げるため。因みにワンタイムパスワードを使っている。

PuTTY
ターミナル。これがないと仕事ができない。

Google Chrome
IEのモッサリ加減にはうんざりなので。Google Chromeはやはり速い。D4になかなか合うと思う。

Evernote
メモ帳兼スクラップブック。備忘録や研究ノートとして使っている。超便利。使い始めて日は浅いのだが、既にこれがないと生活できない体に…。

PowerShell
コマンドプロンプトはへこすぎるし、Windowsでいろいろやりたいなら必須かと。

Adobe Acrobat Reader
最初から入っているバージョン8をアンインストールして、バージョン9を入れた。

Adobe Flash
ウェブ使うならこれも必須。

Mozilla Thunderbird
いつもお世話になっているメールソフト。

デ辞蔵
アカデミックパックを購入したので無料で付いてきた。リーダース英和+プラスなどが入っており便利だが、起動が重いかなぁ。

OfficeとVisual C++が結構容量を食っているが、それでも残り容量は10GB以上ある。スペック的に動作はそこそこといったところだが、どこにでも持ち運べ一通りの作業ができるというのが素晴らしい。因みに、メインのノートPCは普段は職場に置いておき、必要ならリモートデスクトップを利用することにした。持ち運びの荷物が軽くなり大変満足できる結果となった。

最後に

軽いWILLCOM D4は持ち運びをメインとしたサブノートとして秀逸。外ではPHSで通信、自宅や職場では無線LAN。メインPCで行うような仕事をD4で行うことができるが、基本性能やディスプレイ表示能力、ユーザーインターフェイスからすると効率が落ちるかも。適材適所で。

続きを読む...

2008年9月16日火曜日

Googleデスクトップガジェットを5分で作る

このブログ記事をはてなブックマークに追加

Googleデスクトップガジェット(Google Desktop Gadgets)を作るのは簡単だ。ここではHello, world!と表示させ、表示された文字をクリックするとJavaScriptによりダイアログが出てくるガジェットを作成する。さらに、国際化を施して、英語環境では"Hello, world!"、日本語環境では「こんにちは、世界!」と表示させることにする。

これで、ガジェットの作成、JavaScriptの記述、国際化、それぞれの基本を押さえることができる。またこれはJavaScriptを使ったミニアプリケーションでもあり、JavaScript学習者にとっては手軽に扱えるアプリケーション作成ツールにもなるだろう。

まずは準備

当たり前のことだが、最初にGoogleデスクトップをインストールしておく。

次に、GoogleデスクトップガジェットSDKをダウンロードし、適当なディレクトリに展開する。以前は日本語版があったようだが、現在は英語版しかないようだ。しかし使い方が簡単なので、それでもまったく問題ない。

早速、ガジェットを作ってみる

展開したディレクトリの api/tools/designer_en.exe を実行し、Google Desktop Gadget Designerを起動する。メニューの File から New Gadget... を選択する。

プロジェクト名として適当な名前をつける(ここでは HelloWorld とした)。

プロジェクトを作るとテンプレートとして四角い領域が表示されるので、Gadget Designerの"Label"アイコンを選択し、その領域の中央をクリックしラベルを付ける。付けたラベルをクリックすると右上のペインにラベルのプロパティが表示されるので、プロパティ内のinnerNameの値を &HELLO_WORLD; とする。

左のビューペインでen/フォルダを開くとstrings.xmlが表示されるので、それをダブルクリックする。そうするとstrings.xmlの中身が表示されるので、<strings></strings>内の適当な場所に、

<HELLO_WORLD>Hello, world!</HELLO_WORLD>

と書き込む。

先ほど作成したラベル(&HELLO_WORLD;と表示されているはず)をダブルクリックするとmain.jsにlabel1_onClick()という関数が作成されるので、その中に

view.alert(HELLO_WORLD);

と書き込む。これによりラベルをクリックすると"Hello, world!"というダイアログが表示されるようになる。

メニューの Gadget にある Build Package でHelloWorld.ggが作成できる。これをダブルクリックすればGoogleデスクトップにガジェットが追加される。ガジェット内のHello, world!をクリックするとダイアログが出る。

日本語で表示する

今回作ったガジェットはすべて英語だった。英語圏のユーザはこれでいいが、日本だったら日本語で表示させたい。Googleデスクトップガジェットでは国際化するのは簡単だ。

まず、api/tools/NewProject/jaフォルダを、先ほど作成したガジェットのフォルダにコピーする。そうしたら en/strings.xml を編集したのと同じように ja/strings.xml を開いて、

<HELLO_WORLD>こんにちは、世界!</HELLO_WORLD>

と書き込む。

あとは、Build Packageでggファイルを再作成するだけである。日本語環境であれば、"Hello, world!"の代わりに「こんにちは、世界!」と表示される。更に詳細を知りたかったり、ガジェットを作りこみたい場合は、 Googleデスクトップ サイドバーガジェット入門を参照のこと。また、api/samples/gadgets以下のサンプルプログラムもガジェットを作成する上で非常に役に立つだろう。

今回のチュートリアルは、LivelyのオブジェクトがGoogleデスクトップガジェットSDKで作られているとのことで、使い方をざっと調べたついでに作ってみた。因みにLivelyでガジェットを作成するための許可をもらうにはLively gadget developer requestで登録すればいいらしい。

続きを読む...

2008年9月14日日曜日

PS3:「アンチャーテッド エル・ドラドの秘宝」でプラチナトロフィー

このブログ記事をはてなブックマークに追加

PS3のアンチャーテッド エル・ドラドの秘宝がトロフィーに対応したとのことで、早速やり直してみた。自分の場合、一度クリアしたゲームはほとんどの場合、二度目のプレイはしない。そして、最初からやり直しとなるとげんなりしてしまう。しかし、このアンチャーテッドは違った。再度のプレイだというのにまったくダレもせずに、面白くてのめりこんでしまう。まるで映画の中を駆け回っている気分にさせる。プレイすればするほど上手に立ち回れるようになるのが実感できる。また、キャラクターの日本語吹き替えが特に秀逸でこれを聞くだけでもプレイする価値はある。

と云うわけで、少しも飽きず、退屈もせずにプラチナトロフィーまで取ってしまった。トロフィーを知らない人のために補足しておくが、トロフィーはゲームのやり込みに対する勲章のようなもので、達成項目の難易度に従って、ブロンズ、シルバー、ゴールド、そしてプラチナが与えられる。アンチャーテッドの場合、36個のブロンズ、8個のシルバー、3個のゴールド、そしてそれらすべてのトロフィーを集めて初めて1個のプラチナがもらえるのである。言うなればプラチナトロフィーとはアンチャーテッドを骨までしゃぶりつくしたという証拠でもある。

アンチャーテッドはアクションアドベンチャーなので自分のように暇があまり取れない人にも向いている。今回のプラチナトロフィーもちまちまとプレイしながら約2週間で取得できた。大作RPGとかだとこうは行かないだろう。アンチャーテッドは続編がリリースされることも決まっており、今から本当に楽しみだ。

続きを読む...

2008年9月6日土曜日

Google Chromeの起動オプション一覧

このブログ記事をはてなブックマークに追加

Google Chromeの起動オプション(コマンドラインオプション)の一覧。ソースコードのbase/base_switches.cc, chrome/common/chrome_switches.ccから。すべてを確認したわけではないので使用は自己責任で。

例えば、ユーザデータファイルを保存するディレクトリを"C:\users\chrome"にしてJavaScriptをオフにする場合は、Google Chromeのショートカットのリンク先を以下のようにして起動する。

"C:\Documents and Settings\ユーザ名\Local Settings\Application Data\Google\Chrome\Application\chrome.exe" --user-data-dir=C:\users\chrome --disable-javascript

--debug-on-start If the program includes chrome/common/debug_on_start.h, the process will start the JIT system-registered debugger on itself and will wait for 60 seconds for the debugger to attach to itself. Then a break point will be hit.
--wait-for-debugger Will wait for 60 seconds for a debugger to come to attach to the process.
--noerrdialogs Suppresses all error dialogs when present.
--disable-breakpad Disables the crash reporting.
--full-memory-crash-report Generates full memory crash dump.
--type The value of this switch determines whether the process is started as a renderer or plugin host. If it's empty, it's the browser.
--enable-dcheck Enable DCHECKs in release mode.
--disable-hang-monitor Suppresses hang monitor dialogs in renderer processes.
--disable-metrics Completely disables UMA metrics system.
--disable-metrics-reporting Disables only the sending of metrics reports. In contrast to kDisableMetrics, this executes all the code that a normal client would use for reporting, except the report is dropped rather than sent to the server.
This is useful for finding issues in the metrics code during UI and performance tests.
--assert-test Causes the browser process to throw an assertion on startup.
--renderer-assert-test Causes the renderer process to throw an assertion on launch.
--crash-test Causes the browser process to crash on startup.
--renderer-crash-test Causes the renderer process to crash on launch.
--renderer-startup-dialog Causes the renderer process to display a dialog on launch.
--plugin-startup-dialog Causes the plugin process to display a dialog on launch.
--testshell-startup-dialog Causes the test shell process to display a dialog on launch.
--plugin-launcher Specifies a command that should be used to launch the plugin process. Useful for running the plugin process through purify or quantify.
Ex: --plugin-launcher="path\to\purify /Run=yes"
--channel The value of this switch tells the child process which IPC channel the browser expects to use to communicate with it.
--testing-channel The value of this switch tells the app to listen for and broadcast testing-related messages on IPC channel with the given ID.
--homepage The value of this switch specifies which page will be displayed in newly-opened tabs. We need this for testing purposes so that the UI tests don't depend on what comes up for http://google.com.
--start-renderers-manually When this switch is present, the browser will throw up a dialog box asking the user to start a renderer process independently rather than launching the renderer itself. (This is useful for debugging.)
--renderer Causes the process to run as renderer instead of as browser.
--renderer-path Path to the exe to run for the renderer subprocess
--plugin Causes the process to run as plugin host
--single-process Runs the renderer and plugins in the same process as the browser
--process-per-tab Runs each set of script-connected tabs (i.e., a BrowsingInstance) in its own renderer process. We default to using a renderer process for each site instance (i.e., group of pages from the same registered domain with script connections to each other).
--process-per-site Runs a single process for each site (i.e., group of pages from the same registered domain) the user visits. We default to using a renderer process for each site instance (i.e., group of pages from the same registered domain with script connections to each other).
--in-process-plugins Runs plugins inside the renderer process
--no-sandbox Runs the renderer outside the sandbox.
--safe-plugins Runs the plugin processes inside the sandbox.
--trusted-plugins Excludes these plugins from the plugin sandbox.
This is a comma separated list of plugin dlls name and activex clsid.
--test-sandbox Runs the security test for the sandbox.
--user-data-dir Specifies the user data directory, which is where the browser will look for all of its state.
--app Specifies that the associated value should be launched in "application" mode.
--upload-file Specifies the file that should be uploaded to the provided application. This switch is expected to be used with --app option.
--dom-automation Specifies if the dom_automation_controller_ needs to be bound in the renderer. This binding happens on per-frame basis and hence can potentially be a performance bottleneck. One should only enable it when automating dom based tests.
--plugin-path Tells the plugin process the path of the plugin to load
--js-flags Specifies the flags passed to JS engine
--geoid The GeoID we should use. This is normally obtained from the operating system during first run and cached in the preferences afterwards. This is a numeric value; see http://msdn.microsoft.com/en-us/library/ms776390.aspx .
--lang The language file that we want to try to open. Of the form language[-country] where language is the 2 letter code from ISO-639.
--debug-children Will add kDebugOnStart to every child processes. If a value is passed, it will be used as a filter to determine if the child process should have the kDebugOnStart flag passed on or not.
--wait-for-debugger-children Will add kWaitForDebugger to every child processes. If a value is passed, it will be used as a filter to determine if the child process should have the kWaitForDebugger flag passed on or not.
--log-filter-prefix Will filter log messages to show only the messages that are prefixed with the specified value
--enable-logging Force logging to be enabled. Logging is disabled by default in release builds.
--disable-logging Force logging to be disabled. Logging is enabled by default in debug builds.
--log-level Sets the minimum log level. Valid values are from 0 to 3: INFO = 0, WARNING = 1, LOG_ERROR = 2, LOG_FATAL = 3.
--dump-histograms-on-exit Dump any accumualted histograms to the log when browser terminates (requires logging to be enabled to really do anything). Used by developers and test scripts.
--remote-shell-port enable remote debug / automation shell on the specified port
--uninstall Runs un-installation steps that were done by chrome first-run.
--omnibox-popup-count Number of entries to show in the omnibox popup.
--automation-channel The value of this switch tells the app to listen for and broadcast automation-related messages on IPC channel with the given ID.
--restore-last-session Indicates the last session should be restored on startup. This overrides the preferences value and is primarily intended for testing.
--record-mode
--playback-mode
Chrome supports a playback and record mode. Record mode saves *everything* to the cache. Playback mode reads data exclusively from the cache. This allows us to record a session into the cache and then replay it at will.
--no-events Don't record/playback events when using record & playback.
--hide-icons
--show-icons
Make Windows happy by allowing it to show "Enable access to this program" checkbox in Add/Remove Programs->Set Program Access and Defaults. This only shows an error box because the only way to hide Chrome is by uninstalling it.
--make-default-browser Make Chrome default browser
--proxy-server Use a specified proxy server, overrides system settings. This switch only affects HTTP and HTTPS requests.
--dns-log-details
--dns-prefetch-disable
Chrome will support prefetching of DNS information. Until this becomes the default, we'll provide a command line switch.
--debug-print Enables support to debug printing subsystem.
--allow-all-activex Allow initialization of all activex controls. This is only to help website developers test their controls to see if they are compatible in Chrome.
Note there's a duplicate value in activex_shared.cc (to avoid dependency on chrome module). Please change both locations at the same time.
--disable-dev-tools Browser flag to disable the web inspector for all renderers. const wchar_t kAlwaysEnableDevTools[]
--always-enable-dev-tools Enable web inspector for all windows, even if they're part of the browser. Allows us to use our dev tools to debug browser windows itself.
--tab-count-to-load-on-session-restore Used to set the value of SessionRestore::num_tabs_to_load_. See session_restore.h for details.
--memory-profile Enable dynamic loading of the Memory Profiler DLL, which will trace all memory allocations during the run.
--memory-model Configure Chrome's memory model.
Does chrome really need multiple memory models? No. But we get a lot of concerns from individuals about how the changes work on *their* system, and we need to be able to experiment with a few choices.
--enable-file-cookies By default, cookies are not allowed on file://. They are needed in for testing, for example page cycler and layout tests. See bug 1157243.
--start-maximized Start the browser maximized, regardless of any previous settings.
TODO(pjohnson): Remove this once bug 1137420 is fixed. We are using this as a workaround for not being able to use moveTo and resizeTo on a top-level window.
--enable-watchdog Spawn threads to watch for excessive delays in specified message loops. User should set breakpoints on Alarm() to examine problematic thread.
Usage: -enable-watchdog=[ui][io]
Order of the listed sub-arguments does not matter.
--first-run Display the First Run experience when the browser is started, regardless of whether or not it's actually the first run.
--message-loop-histogrammer Enable histograming of tasks served by MessageLoop. See about:histograms/Loop for results, which show frequency of messages on each thread, including APC count, object signalling count, etc.
--import Perform importing from another browser. The value associated with this setting encodes the target browser and what items to import.
--silent-dump-on-dcheck Change the DCHECKS to dump memory and continue instead of crashing. This is valid only in Release mode when --enable-dcheck is specified.
--disable-prompt-on-repost Normally when the user attempts to navigate to a page that was the result of a post we prompt to make sure they want to. This switch may be used to disable that check. This switch is used during automated testing.
--disable-popup-blocking Disable pop-up blocking.
--disable-javascript Don't execute JavaScript (browser JS like the new tab page still runs).
--disable-java Prevent Java from running.
--disable-plugins Prevent plugins from running.
--disable-images Prevent images from loading.
--use-lf-heap Use the low fragmentation heap for the CRT.
--gears-in-renderer Switch to load Gears in the renderer process.
--new-http Enable new HTTP stack.
--javascript-debugger-path
--enable-p13n
Allow loading of the javascript debugger UI from the filesystem.
--gears-plugin-path Debug only switch to specify which gears plugin dll to load.

続きを読む...

2008年9月4日木曜日

JavaScriptとウェブブラウザ、そしてGoogle Chrome

このブログ記事をはてなブックマークに追加

Googleからウェブブラウザ「Google Chrome」がリリースされた。まだベータ版だが、高速な起動は特筆に値する。作業効率を著しく下げる起動の遅いPC、OS、アプリケーションには個人的に我慢がならないので、それだけでGoogle Chromeを採用する価値がある。しかしながら、このブラウザの本質は独自開発の高速なJavaScriptエンジン"V8"にある。

しばらく前からIE7の動作の遅さや不安定さが目立つようになってきており、そろそろ他のもっと軽快なブラウザに乗り換えようかと考えていた。動作の遅さの原因ははっきりしている。JavaScriptを多用しているページをタブで複数開いているからである。一昔前、GoogleによりAjaxが世間に知られるようになる以前のこと、JavaScriptはオフにしておくべき項目のトップであった。しかし、Ajaxに代表されるJavaScriptを使ったページの便利さが知られることで、JavaScriptの使用は必須になってしまった。今更、GoogleリーダーやGoogleマップを使うなといわれても困るのだ。

しかし、JavaScriptの有用性が知られれば知られるほど、JavaScriptを多用したページは増え、よりリッチになって行き、ついにはウェブブラウザの許容範囲を超えてしまう。ここ最近では、明らかにJavaScriptの要求に付いていってないのが分かるようになっていた。

このまま行けば、ブラウザ環境はいずれ破綻する、しないとしてもユーザビリティの著しく劣った環境になると思っていた。必要とされているのは、JavaScriptが軽快に動作するシンプルで高速なウェブブラウザなのだ。

そんな中、タイミングよくGoogle Chromeが出てきた。個人的にはあまりGoogleばかりに依存したくはないのだが、自分の琴線に触れるようなサービスが出てくるので仕方がない。まだリリースされたばかりのベータ版で機能不足や不安定さが残っているが、素質は十分だ。

Google Chromeを使うにあたってのメモ:

Google Chromeの固定幅フォントのサイズ(13pt)が何故かプロポーショナルフォントのサイズ(16pt)よりも小さく設定されている。そのためサイトによっては固定幅フォントが他のブラウザに比べて小さくなり見にくくなることがある(ここのブログのソースコードのように)。これについてはすべて同じサイズに変更した。また、ダウンロード先のフォルダを変更し、パスワードは保存しないようにした。

続きを読む...

2008年9月1日月曜日

Python: RPyで階層的クラスタリング

このブログ記事をはてなブックマークに追加

Python+RPy+SciPyで階層的クラスタリングを行う。下記のtest.dat(30個の5次元データ)に対して閾値0.5として計算する。

clustering.py test.dat 0.5

標準出力:

Data file: test.dat Element file: element.out Output file: data.out Cluster file: cluster.out EPS file: cluster.eps Threshold: 0.500000 (distance) 30 x 30 = 900 Cluster 1 : 5 Cluster 2 : 8 Cluster 3 : 1 Cluster 4 : 1 Cluster 5 : 12 Cluster 6 : 2 Cluster 7 : 1 Total : 30 Number of clusters: 7

test.dat: 30個の5次元データ。

-2.39257 0.39147 0.21229 -0.84501 -0.02255 -2.13082 0.44121 0.12561 -0.91345 -0.12832 -2.23498 0.26590 -0.35356 -0.03484 -0.17437 -2.27747 0.29900 -0.05188 -0.63788 -0.13000 -2.11555 0.39492 0.11465 -0.86242 -0.34207 -2.31947 0.26036 0.47846 -0.71782 0.07270 -2.32941 0.38637 0.44304 -0.75346 -0.04302 -2.30690 0.59296 0.22947 -0.82801 -0.09882 -2.29088 0.53157 0.03204 -0.75087 -0.05802 -2.36682 0.34835 0.23964 -0.72942 -0.09720 -2.11368 0.52013 0.27528 -0.81122 -0.20050 -2.27156 0.21167 0.57165 -0.66193 -0.03302 -2.15076 0.42352 0.39504 -0.76157 -0.12652 -2.21785 0.36763 0.32698 -0.77082 -0.14381 -2.27547 0.37300 0.27672 -0.84605 -0.11913 -2.21365 0.37827 0.12720 -0.72738 -0.16452 -2.22145 0.53808 0.36045 -0.75871 -0.13850 -2.12462 0.43006 0.16845 -0.87023 -0.09789 -2.20644 0.53991 0.19739 -0.82177 -0.29343 -2.10046 0.77307 0.21435 -0.86245 -0.15118 -2.37488 0.50979 0.17556 -0.78224 -0.14136 -2.31240 0.48578 0.20484 -0.85149 -0.12238 -2.19001 0.33037 0.09407 -0.91014 -0.09473 -2.31135 0.29111 0.38171 -0.73491 -0.03447 -2.23133 0.35395 0.29436 -0.48961 -0.06276 -2.19413 0.36376 0.21777 -0.18686 -0.20020 -2.06165 0.38107 0.43080 -0.76940 -0.38291 -2.34113 0.44097 0.42368 -0.73850 0.02570 -2.41489 0.40263 0.32783 -0.80521 0.03404 -2.34918 0.48361 0.16130 -0.87229 -0.09810

cluster.eps: image file



element.out: height and merge data

0.0653862929061 [-22 -30] 0.0692241388534 [ -2 -18] 0.0918671214309 [ -7 -28] 0.107376254824 [-21 1] 0.110198113414 [-14 -15] 0.136962358698 [ -1 -29] 0.139532210618 [-13 -17] 0.142665365804 [-8 4] 0.146113402192 [-23 2] 0.148827203159 [ -6 -24] 0.154304262741 [-11 -19] 0.184603648393 [-10 5] 0.196790849635 [ 3 10] 0.205812622791 [-16 12] 0.224987104075 [-9 8] 0.253271677848 [-5 11] 0.285769571333 [ 7 14] 0.297698839601 [-12 13] 0.319598069143 [ 9 16] 0.34335611295 [-25 -26] 0.356127683001 [ 6 17] 0.386487913265 [15 19] 0.466665096402 [-4 22] 0.500220834332 [18 21] 0.514176928693 [-20 -27] 0.614681702347 [23 25] 0.710561224034 [20 24] 0.796960005207 [26 27] 1.13283489335 [-3 28]

data.out: averages and member of groups

-2.314584 0.318096 0.459708 -0.721324 -0.002422 12 7 28 6 24 -2.281683 0.402869 0.283269 -0.780521 -0.097274 1 29 13 17 16 10 14 15 -2.100460 0.773070 0.214350 -0.862450 -0.151180 20 -2.061650 0.381070 0.430800 -0.769400 -0.382910 27 -2.232736 0.463276 0.143898 -0.826001 -0.150468 4 9 8 21 22 30 23 2 18 5 11 19 -2.212730 0.358855 0.256065 -0.338235 -0.131480 25 26 -2.234980 0.265900 -0.353560 -0.034840 -0.174370 3

cluster.out: order and member of groups

001: 12 7 28 6 24 002: 1 29 13 17 16 10 14 15 003: 20 004: 27 005: 4 9 8 21 22 30 23 2 18 5 11 19 006: 25 26 007: 3

clustering.py

#!/usr/bin/env python import sys, os from rpy import * from scipy import * def create_data(data, is_square_root=False): """Create distance data. Arguments: data: position data is_square_root: whether to apply square root or not Return values: in_data: distance data ndim: number of dimensions """ in_data = [] num = len(data) ndim = len(data[0]) for i in range(num): for j in range(num): if i < j: dist = 0.0 for k in range(ndim): dist += (data[i][k] - data[j][k])**2 if is_square_root: dist = sqrt(dist) in_data.append(dist) elif i > j: in_data.append(in_data[j*num+i]) elif i == j: in_data.append(0.0) return in_data, ndim def clustering(in_data, data, ele_file, cluster_method="complete", eps_file=None): """Clustering. Arguments: in_data: distance data data: position data ele_file: element filename (height/merge data) cluster_method: clustering method [complete] eps_file: EPS filename [None] """ efile = file(ele_file, "w") if len(in_data) == 2: efile.write("%5.3f [-1 -2]\n" % in_data[1]) efile.close() return mat = in_data[:] print "%d x %d = %d" % (len(data), len(data), len(mat)) mat = with_mode(NO_CONVERSION, r.matrix)(mat, nrow=len(data)) d = with_mode(NO_CONVERSION, r.as_dist)(mat) hc = r.hclust(d, method=cluster_method) for h, m in zip(r["$"](hc, "height"), r["$"](hc, "merge")): efile.write("%s %s\n" % (h, m)) efile.close() if eps_file: r.postscript(eps_file, title=eps_file) r.plclust(hc, hang=-0.1, ann=r.FALSE) r.dev_off() def expand_group(m, n): """Expand group list.""" group = [] for x in m[n-1]: if x < 0: group.append(-x) else: group.extend(expand_group(m, x)) return group def arrange_cluster(ele_file, data, ndim, threshold, out_file): """Arrange clustering data. Arguments: ele_file: element filename (height/merge data) data: position data ndim: number of dimensions threshold: threshold of clustering out_file: output data filename Return value: groups: pair list of hierarchical clustering """ if len(data) == 2: print "Cluster 1 : 1" print "Total : 1" return [] elif len(data) < 2: print "No cluster" print "Total : 0" return [] efile = file(ele_file) ofile = file(out_file, "w") h = [] m = [] for l in efile: e = l.replace("[", "").replace("]", "").replace(",", " ").strip().rstrip("\n").split() h.append(float(e[0])) m.append([int(e[1]), int(e[2])]) tt = [[i, x] for i, (x, d) in enumerate(zip(m, h)) if d > threshold] t = [] for d in tt: for x in d[1]: if x < tt[0][0]+1: t.append(x) groups = [] all = [] for x in t: g = [] if x < 0: g = [-x] else: g = expand_group(m, x) groups.append(g) if not groups: groups = [range(1, len(h) + 2)] for i, g in enumerate(groups): print "Cluster %-3d: %d" % (i+1, len(g)) g_data = [data[j-1] for j in g] for d in range(ndim): ofile.write("%f " % average(mat(g_data).T[d])) for j in g: ofile.write("%d " % j) ofile.write("\n") efile.close() ofile.close() s = 0 for x in groups: s += len(x) print "Total : %d" % s return groups def write_cluster(groups, cluster_out): """Write clustering result.""" clust_file = file(cluster_out, "w") print "Number of clusters: %d" % len(groups) count = 1 for c in groups: clust_file.write("%03d:" % count) for d in c: clust_file.write(" %d" % d) clust_file.write("\n") count += 1 clust_file.close() def main(args): if len(args) < 2: print >>sys.stderr, "Usage: %s data_file [threshold=5.0]>" % os.path.basename(args[0]) sys.exit(1) elif len(args) == 2: th = 5.0 elif len(args) > 2: th = float(args[2]) DATA_FILE = args[1] ELEMENT_FILE = "element.out" OUT_FILE = "data.out" CLUSTER_FILE = "cluster.out" EPS_FILE = "cluster.eps" IS_SQUARE_ROOT = True print "Data file: %s" % DATA_FILE print "Element file: %s" % ELEMENT_FILE print "Output file: %s" % OUT_FILE print "Cluster file: %s" % CLUSTER_FILE print "EPS file: %s" % EPS_FILE if IS_SQUARE_ROOT: print "Threshold: %f (distance)" % th else: th = th**2 print "Threshold: %f (distance**2)" % th # position data data = [[float(d) for d in l.split()] for l in file(DATA_FILE)] if len(data) > 1: # distance data in_data, ndim = create_data(data, is_square_root=IS_SQUARE_ROOT) # clustering by position and distance data and output element file clustering(in_data, data, ELEMENT_FILE, eps_file=EPS_FILE) else: print >>sys.stderr, "Error: no data." sys.exit(1) # arrange clustering data by element file and threshold, and output group data groups = arrange_cluster(ELEMENT_FILE, data, ndim, th, OUT_FILE) # output ordered clustering data by using group data write_cluster(groups, CLUSTER_FILE) if __name__ == "__main__": main(sys.argv)

仕事で使おうと思って一応書いたけど、コード量が多くてなんだかスッキリしないなぁ。Linuxでは問題なかったけど、WindowsではEPSファイルでエラーが出るし。使用環境、RとRPyの相性の問題もあるようだ。Rは2.1.1、RPyは0.4.3でちょっと古いかもしれない。最近はrpy2が出ているようだけどどうなんだろう? 使ってみるかな。

続きを読む...

2008年8月30日土曜日

Python: はてなブックマークのコメント一覧非表示機能について

このブログ記事をはてなブックマークに追加

はてなブックマークのコメント一覧を非表示にする機能が追加された。しかし、新着ブックマークからはコメントが読めてしまう。

例えば、はてなブックマークのコメント一覧非表示機能テストのページはコメントを非表示に設定しているが、その新着ブックマークのページを開くとコメントが表示されていることが分かる。さらに、下記のPythonスクリプトを

hatena_get_comments.py http://d.hatena.ne.jp/fk_2000/20080829/p1

のように実行させると、すべてのコメントとそのユーザ名を表示することができる。

これをGoogle App EngineでWebサービスとすることは簡単だろう。Webサービスの公開はモラルに欠けるようにも思うのでやめておくが、本当にコメントを読めなくするつもりなら今回の非表示機能は中途半端と云わざるを得ない。

因みに、個人的にはコメントを非表示にすることについては賛成とも反対とも考えておらず、あまり関心がない。しかし、はてなブックマークの存在意義にも関わってくるような機能についてはもう少し議論・熟考したほうが良いようにも思える。

hatena_get_comments.py

#!/usr/bin/env python # -*- coding: utf-8 -*- import sys, os, urllib, urllib2, xmlrpclib from HTMLParser import HTMLParser class HatenaHTMLParser(HTMLParser): is_user = False is_comment = False comments = [] current_user = "" current_comment = [] def handle_starttag(self, tag, attrs): if tag == "dd" and ("class", "bookmarker") in attrs: self.is_user = True elif tag == "span" and ("class", "comment") in attrs: self.is_comment = True def handle_endtag(self, tag): if self.is_user and tag == "dd": self.is_user = False if self.is_comment and tag == "span": self.is_comment = False self.comments.append((self.current_user, "".join(self.current_comment))) self.current_comment = [] def handle_data(self, data): if self.is_user: self.current_user = unicode(data) if self.is_comment: self.current_comment.append(unicode(data)) def get_comments(self): return self.comments def main(args): if len(args) < 2: print >>sys.stderr, u"Usage: %s ブックマークされているURL" % os.path.basename(args[0]) sys.exit(1) cnt = xmlrpclib.ServerProxy("http://b.hatena.ne.jp/xmlrpc").bookmark.getCount(args[1])[args[1]] url = "http://b.hatena.ne.jp/bookmarklist?url=%s" % urllib.quote_plus(args[1]) parser = HatenaHTMLParser() for i in range(0, cnt, 25): data = urllib2.urlopen(url + "&of=%d" % i).read() parser.feed(data) for user, comment in parser.get_comments(): print user, comment.encode("mbcs") if __name__ == "__main__": main(sys.argv)

続きを読む...

2008年8月29日金曜日

Python: はてなブックマークのAPIを使ってみた

このブログ記事をはてなブックマークに追加

最近、はてなブックマークを使い始めたこともあり、はてなブックマークのAPIについて調べてみた。ざっと確認をした後、Pythonではてなブックマーク件数取得APIはてなブックマークエントリー情報取得APIを使ってみた。

はてなブックマーク件数取得APIはブックマークされた件数とAmazonの商品がコレクションされた件数をXML-RPCで取得することができる。一方、ブックマークエントリー情報取得APIでは、はてなブックマークのエントリーの情報をJSON形式で取得することができる。サンプルコードを以下に示す。

#!/usr/bin/env python # -*- coding: utf-8 -*- import urllib2 import xmlrpclib import simplejson url = "http://www.hatena.ne.jp/" asin = "4774124966" # はてなブックマークエントリー情報取得API. data = urllib2.urlopen("http://b.hatena.ne.jp/entry/json/%s" % url).read() info = simplejson.loads(data.strip("(").rstrip(")")) if info: title = info["title"] cnt = int(info["count"]) bookmarks = info["bookmarks"] cnt_user = len(bookmarks) cnt_comment = 0 for b in bookmarks: if b["comment"]: cnt_comment += 1 print b["comment"].strip() if cnt_comment > 0: print print u"タイトル: %s" % title print u"URL: %s" % url print u"ブックマークしているユーザ数: %d +%d" % (cnt_user, cnt - cnt_user) print u"コメント数: %d" % cnt_comment rate_comment = float(cnt_comment) / cnt_user * 100 if cnt_user > 0 else 0.0 print u"コメント率: %.2f%%" % rate_comment print # はてなブックマーク件数取得API. s = xmlrpclib.ServerProxy("http://b.hatena.ne.jp/xmlrpc") print u"%sの被ブックマーク数: %d" % (url, s.bookmark.getCount(url)[url]) print u"サイトの被ブックマーク数: %d" % s.bookmark.getTotalCount(url) print u"Amazon商品(%s)の被コレクション数: %d" % (asin, s.bookmark.getAsinCount(asin)[asin])

因みに、JSONを利用するにあたってはsimplejsonモジュールを用いた。

プログラムを実行すると以下のような出力を得る。

お世話になっております。 ぶくま 初ブクマ はてなTOP hoge *default hatena はてなトップ (中略) タイトル: はてな URL: http://www.hatena.ne.jp/ ブックマークしているユーザ数: 1187 +547 コメント数: 218 コメント率: 18.37% http://www.hatena.ne.jp/の被ブックマーク数: 1734 サイトの被ブックマーク数: 54550 Amazon商品(4774124966)の被コレクション数: 127

まず、はてなブックマークエントリー情報取得APIによりすべてのコメントを表示させ、続けて、タイトル、URL、ユーザ数、コメント数、そして、ユーザ数に対するコメント数の割合を示すコメント率を出力。次いで、はてなブックマーク件数取得APIを用いて、指定URLのブックマーク数、サイト全体のブックマーク数、コレクション数の表示を行っている。

続きを読む...

2008年8月24日日曜日

Google: 333333333333335-333333333333334=0?

このブログ記事をはてなブックマークに追加

巷ではGoogleで399999999999999-399999999999998を計算させると0を返すと話題になっているが、ちょうど333333333333335-333333333333334の計算から0を返すようだ。ちなみにこの倍となる数値で計算させると666666666666669-666666666666667=0のように差が2で0を返すようになる。たぶん近いうちに修正されるんじゃないかな。

続きを読む...

2008年8月23日土曜日

Google App Engine: Gearsで位置情報を取得してストリートビューで表示させる

このブログ記事をはてなブックマークに追加

Gearsジオロケーション専用のAPI(Geolocation API)がリリースされたのでGoogle App Engineで実装してみた。まず、Geolocation APIで位置情報を取得し、Google MapsおよびGoogle Street Viewにより表示するWebアプリだ。因みに、アプリを実行させるには予めGearsをインストールしておく必要がある。

Geo View

コードは基本的にはStreet Strollを使っており、初期位置情報をGeolocation APIのgetCurrentPositionメソッドにより取得している。下記に示すコードが主な変更部分になる。

Gearsのコアであるgears_init.jsの読み込み。

<script type="text/javascript" src="http://code.google.com/apis/gears/gears_init.js"></script>

初期化関数initialize()の前にinitialize_geo()を噛ませ、変数lat, lngにそれぞれ緯度・経度が入るようにしている。

function updatePosition(position) { lat = position.latitude; lng = position.longitude; initialize(); } function initialize_geo() { if (window.google && google.gears) { var geo = google.gears.factory.create("beta.geolocation"); geo.getCurrentPosition(updatePosition, function(positionError) { alert(positionError.message); }); } else { if (confirm("位置情報を取得するためにはGearsが必要です。インストールしますか?")) { window.location = "http://gears.google.com/"; } else { // 秋葉原. lat = 35.698584; lng = 139.774216; initialize(); } } }

PCからだとIPアドレスから位置情報を取得するとのことで精度についてはあまり期待できないかもしれないが、携帯電話からだとそれなりに使えるのだろうか。しかし、IE Moblie+Gearsが必要なのがネックかなぁ。

続きを読む...

2008年8月21日木曜日

Google App Engine: mixi OpenIDで認証する

このブログ記事をはてなブックマークに追加

mixiがOpenIDに対応したということで早速Google App Engineで実装してみた。以前のエントリで紹介したがGoogle App Engineのサンプル集OpenID ConsumerというWebアプリがあるので、そのソースコードを利用させてもらった。

しかし、実際に使ってみればわかるのだがこのコードにはいくつかのバグ(とGoogle App Engineの制限)があってちゃんと動かない。下記のリンク先は正常に動くように修正したものだ。

mixi OpenID テスト

以下にバグの箇所とその修正コードを示す。

consumer.py

344-345行目の以下のコードを

self.response.set_status(302) self.response.headers['Location'] = redirect_url

以下のように修正する。

self.response.out.write("<html><head><meta http-equiv=\"refresh\" content=\"0;url=%s\"></head><body></body></html>" % (redirect_url,))

これはGoogle App Engineの制限を回避するためで、一度HTMLを表示し同時にリダイレクトを行っている。

fetcher.py

以下の57行目からのコードで、青で示したコードの後ろにある赤で示したコードを青のコードの前に移動させる。

if body: method = urlfetch.POST if 'Content-Type' not in headers: headers['Content-Type'] = 'application/x-www-form-urlencoded' else: method = urlfetch.GET if not headers: headers = {}

また、外部モジュールのPython OpenID Library (openid)ElementTree (elementtree)は最新のものに変更しても問題なく動く。

ローカルでテストする際はPython OpenID Libraryに付属するexamples/server.pyを利用するのが便利だ。dev_appserver.pyを起動させた後、以下のようにOpenIDサーバを起動させる。これによりテスト用のOpenIDをローカルで作成できる。

./examples/server.py -s localhost

http://localhost:8000/ をブラウザで開くとログイン画面が出るので適当な名前を入れる(たとえばtest)。これでhttp://localhost:8000/id/test がOpenIDのURLとなる。その後、http://localhost:8080/ を開き、OpenIDの入力フィールドでこのIDを使うことができる。もちろんローカルのOpenIDではなくmixi OpenIDや他のOpenIDを使うこともできる。

もしWindowsを使っていてElementTree関連のエラーが出た場合、正しくpyexpatモジュールが読み込まれていない可能性がある。その場合、PythonディレクトリにあるDLLsディレクトリからpyexpat.pydを持ってくると直るかもしれない。

その他については簡単な日本語訳やmixi OpenIDのログインボタンの表示などでそれほど難しくはない。マイミクシィ認証やコミュニティ認証もClaimed Identifierを変更するだけなのでそんなに手間ではないはず。しかし今回、Google App Engineの制限やコードのバグで思ったよりも手間取ってしまった。それでも、ちゃんと動いてしまいさえすればいろいろと応用できそうだ。

追記:

ログイン履歴についてはセキュリティを考慮して最初の1文字以外は伏字とし、リンクしないように変更した。

追記2:

ログイン後にコメントを残せるように変更した。

続きを読む...

2008年8月18日月曜日

Googleの暗号化ツールKeyczarをPythonで使う

このブログ記事をはてなブックマークに追加

Keyczarから持ってきたKeyczar Python (0.5b)を適当なディレクトリに展開し、srcファイル内のkeyczarをPythonディレクトリのsite-packatesにコピーする。次に、PyCryptosimplejsonASN.1 tools for Python から必要なモジュールをダウンロードしインストールする。

KeyczarToolのPythonの実装として、keyczart.pyが提供されているのでこれを利用する。ただし、これにはバグがあり、そのままだとAddKeyを実行できない。詳細は以下に報告されている。

Issue 21: Incorrect AddKey() Call from keyczart.py main()

対処方法としては、svnで最新版を持ってくるか、以下のようにソースを修正する。

keyczart.pyの113行目の

def AddKey(loc, status, crypter=None, size=None):



def AddKey(loc, status, size=None, crypter=None):

に変更する。

実際に平文を暗号文にし、さらにそれを平文に戻してみる。その前に鍵を作る必要があるので、keyczart.pyで作成する。--locationには鍵を作成したいディレクトリを指定すること。

keyczart.py create --location=C:\users\keyczar\keyset --purpose=crypt
keyczart.py addkey --location=C:\users\keyczar\keyset --status=PRIMARY

ここで気を付けなくてはならないのは --status=PRIMARY で指定する文字を大文字にする必要があることだ。マニュアルやコマンドの使い方では小文字になっているが、小文字で指定すると鍵の情報が正しく書き込まれない。たぶんバグだろう。

で、ここまで準備ができれば後は以下のように使用できる。

#!/usr/bin/env python from keyczar import keyczar crypter = keyczar.Crypter.Read(r"C:\users\keyczar\keyset") ciphertext = crypter.Encrypt("Test message!") print ciphertext plaintext = crypter.Decrypt(ciphertext) print plaintext

出力:

AeEDTVSdw1Q-im3koR1BbfgTVVbAWUhX-_4hY23S0cTtKOtdFsTmKi-U9eM6-5Z9MlkOGUhwX54T Test message!

続きを読む...