DiaryException このページをアンテナに追加 RSSフィード Twitter

2010-11-27(土)

[][]WebSocketとDeviceMotion Eventで遊ぶ

iPod touch(第2世代と第4世代)のiOSを4.2.1にアップデートした。Safari on iPhone & iPad 4.2: Accelerometer, WebSockets & better HTML5 support | Breaking the Mobile Webによれば、SafariHTML5対応が強化されたらしい。

試しに遊んでみる。

WebSocketとDeviceMotion Eventの組み合わせに着目して、複数のボールiPod touchのモーションによって動き、そのボールの位置がWebSocketを通してWebページを閲覧している全てのデバイスに通知/共有される、というシナリオを考えた。

図にすると以下のような感じ。1つのデバイスが1つのボールを制御し、WebSocketを通じて共有されるデータは「どのボールがどの位置にあるか」という単純なデータとする。

f:id:LaclefYoshi:20101127124936p:image

完成したものがこちら。

まず、1つのiPod touchGoogle Chromeで同じWebページを開き、iPod touchボールを動かした。WebSocketを通して、Google Chromeにもボールの動きが反映されている。

D

次に、2つのiPod touchGoogle Chromeで同じWebページを開き、それぞれのiPod touchで別々のボールを動かした。左のiPod touchが赤ボールで、右が青ボール。WebSocketを通して、2つのiPod touchGoogle Chromeボールの動きが共有されている。

D

積んだ本の上にデジカメを置いて両手でiPod touch操作する様子を撮るのは、結構大変だった (もうちょっと上手く撮りたかった)。

WebページはHTML5で以下のように書いた。ボールはもちろんcanvasで書いている (ただの塗り潰した円だけど)。WebSocketサーバが動いていない時の挙動など、エラー処理は省いてある。

Webページが通信するためのWebSocketサーバにはTornado (ver.1.1)を用いた。

Webページに直書きしてあるが、IPアドレスとして192.168.254.23を持つMacbookWebサーバとWebSocketサーバを動かし、デバイスは"http://192.168.254.23/balls.html"を参照しWebページを開くと、"ws://192.168.254.23:8888/balls"で参照されるWebSocketサーバコネクションを張る。WebSocketサーバコネクション(Webページを開いているデバイス)を管理して、ある端末から送信されたデータを他の端末に転送する。

WebSocketはCometと比べて、ずっと簡単だった。

ところで、同じバージョンiOSでも、出来ることと出来ないことがあってちょっと戸惑っている。Safariなら第4世代だとDeviceOrientation Eventが取れて、第2世代だと取れないとか。まあ古いものはどう頑張っても段々と時代遅れになるということらしい。

2010-11-20(土)

[][]GrowlメッセージNotifo転送するGrowlプラグイン

Apple Push Notification ServiceiPod touchで使っていると、何でもこれに集約したくなる。

最近Twitterの公式アプリPush Notificationに対応したし、Push Notificationに特化した(自分メッセージを構築出来る)アプリには、im.kayac.comNotifoBoxcarProwlなどがある。

BoxcarとProwlには、自分MacGrowlメッセージ(Growlが外部のアプリケーションからイベントを受けて表示するメッセージ)を、Push NotificationとしてiPod touch/iPhone(勿論、BoxcarかProwlアプリインストール済み)に転送/表示する機能がある。Prowlはそれを売りにしている。この機能は両者ともGrowlプラグインとして実装されている。自分Macにこのプラグインを入れて、Macが動いている間、イベントを検出してメッセージ転送する仕組みのようだ。

Boxcarはアプリインタフェースイマイチで重い。Prowlは有料。どちらも使いたくない。

そこで、Growl Display Plugin Sampleを元に、Growlプラグインを作った。


このプラグインは、自分MacGrowlメッセージNotifo転送し、NotifoアプリインストールされたiPhone/iPod touchメッセージを表示する。ほとんど同じコードim.kayac.com版も作れるが、まだ手を付けていない。

インストールには、ダウンロードしたzipファイル解凍、あるいはビルドして得られた、"Notifo.growlView"をダブルクリックする。

設定は、全てGrowlのPreferencesパネルで行う。このプラグインは「表示オプション」タブで「Notifo」として表示される。ここで、NotifoのUsernameとAPI Keyを入れる。ラベルは、iPod touchメッセージ転送したとき接頭辞として使うオプション(日本語OK)。

f:id:LaclefYoshi:20101120134322p:image

全てのGrowlメッセージiPod touch転送して見たいとは思わないので、このプラグインを用いるアプリケーション、あるいはアプリケーションの中の特定のイベントについて、このプラグインを表示に用いる設定をする。「アプリケーション」タブで任意のアプリケーションの設定が出る。更に「通知」タブでイベント毎に表示を設定することが出来る。

f:id:LaclefYoshi:20101120134321p:image

後は、いつも通りアプリケーションを使っていれば、いつもGrowlメッセージとしてMacデスクトップに表示されていたものが、Notifoを通してiPod touchに表示される。

f:id:LaclefYoshi:20101120134324j:image f:id:LaclefYoshi:20101120134323j:image

BoxcarやProwlは、Push Notificationと共にデスクトップにもGrowlメッセージを表示するオプションがあるようだが、まだGrowlの中身を熟知していないため、方法が分からなかった。また、優先度によってメッセージを表示するかを設定するオプションがあるようだが、これは必要性を感じなかったので省いた。

2010-11-13(土)

[][]Mac環境Ubuntu環境におけるデスクトップ通知

デスクトップ通知とは、デスクトップで全てのアプリケーションより上のレイヤバルーンあるいはポップアップの形式でメッセージを表示するものを指す。

結果の出力に時間のかかるプログラムを端末で動かしている場合など、プログラムを動かしている端末から目を離したい場合が時々ある。しかし、プログラムエラーにより落ちたり、あるいは正常に終了した場合に、端末から目を離していてはすぐに対応することが出来ない。

そこで、プログラムからデスクトップ通知を用いることで、全てのアプリケーションより上のレイヤに任意のメッセージを表示することが出来るので、プログラムの挙動に対しすぐに対応することが出来る。

Mac環境デスクトップ通知: Growl

Macデスクトップ通知と言えばGrowlがある。

AppleScriptによるGrowlによるデスクトップ通知を出すプログラムは以下のようになる。

tell application "GrowlHelperApp"
	register as application "GrowlTest" all notifications {"Error", "Info"} default notifications {"Info"} icon of application "Script Editor.app"
	-- アプリケーションのアイコン指定の他、画像ファイルの指定も可
	notify with name "Info" title "This is a Title" description "This is a Description" application name "GrowlTest"
end tell

f:id:LaclefYoshi:20101113173221p:image

Growl SDKパッケージを開き、Bindings/Pythonディレクトリに、Pythonで用いるためのGrowlライブラリがあるのでインストールするとPythonプログラムからGrowlによるデスクトップ通知を出すことが出来る。

import Growl
g = Growl.GrowlNotifier(applicationName='GrowlTest',
                        notifications=['Info', 'Error'])
g.register()

imagePath = "/Applications/R.app/Contents/Resources/RLogo.png"
iconfile = Growl.Image.imageFromPath(imagePath)
g.notify(noteType='Info',
         title='GrowlTest',
         description='This is a Description.',
         icon=iconfile,
         sticky=False)

f:id:LaclefYoshi:20101113173222p:image

Growlネットワークを通してリモートマシンデスクトップ通知を送ることが出来る(404 Not Found)。このプロトコルを用いたアプリケーションには、Growlパッケージに含まれているgrowlnotifyがある(growlnotifyはネットワーク経由でないデスクトップ通知も可能)。

$ growlnotify -m "This is a Message" -u -H "localhost"

f:id:LaclefYoshi:20101113175234p:image

ネットワーク経由の通知の場合アイコンの設定は出来ない。

growlnotifyで-n(--name)オプションを設定しない場合デフォルト名前:growlnotifyが用いられるためデスクトップ通知が表示される。独自の名前ネットワーク経由の通知で設定する場合、予め、Growlの設定から「リモートアプリケーション登録を許可」し、パスワードを設定する必要がある。そして、growlnotifyでその独自の名前を用いる場合には、パスワードを-P(--password)オプションを設定する。リモートアプリケーション登録を許可しない場合、独自の名前を用いた通知は無視される。

PythonGrowlライブラリでもネットワーク経由のデスクトップ通知を行うことが出来る。

import Growl

ui = {'ApplicationName': 'growlnotify',
      'NotificationDescription': 'This is a Description',
      'AllNotifications': ['Command-Line Growl Notification'],
      'DefaultNotifications': [0],
      'NotificationName': 'Command-Line Growl Notification',
      'NotificationTitle': 'This is a Title'}

n = Growl.netgrowl("localhost", None)
# リモートアプリケーション登録を許可している場合、あるいは登録済みのリモートアプリケーション名を用いる場合、パスワードを入れる

# n.PostRegistration(ui)  # リモートアプリケーション登録をする
n.PostNotification(ui)

f:id:LaclefYoshi:20101113173223p:image

ネットワーク経由の通知はUDPパケットを送るだけなので、Growlライブラリを用いる必要はない。Growlライブラリ内のGrowl.pyからnetgrowlクラス辺りをプログラムコピペしても使える。

Ubuntu環境デスクトップ通知: xmessageとNotifyOSD

Ubuntuに限らず、X11環境インストールされている環境では、xmessageコマンドを用いることが出来る。

$ xmessage -button '' -timeout 2 "This is a short Message"

f:id:LaclefYoshi:20101113184225p:image

Ubuntuでのデスクトップ通知は、標準でNotifyOSDという機能が搭載されている。libnotify-binパッケージインストールすると、notify-sendというコマンドが使える。

$ notify-send -i /usr/share/icons/application-default-icon.png "This is a Summary" "This is a Body"

f:id:LaclefYoshi:20101113185003p:image

python-pynotifyパッケージインストールすると、PythonプログラムからNotifyOSDによるデスクトップ通知を出すことが出来る。

import pynotify
pynotify.init("My Application")
n = pynotify.Notification("This is a Title",
                          "This is a Description",
                          "/usr/share/icons/application-default-icon.png")
n.show()

f:id:LaclefYoshi:20101113173224p:image

NotifyOSDではネットワーク経由のデスクトップ通知は出来ないようだ。

2010-11-10(水)

[][]RockMeltを使ってみた

先輩からno titleダウンロード権を貰い、早速インストールした。

ベースChromiumなので見た目はまんまGoogle Chrome。違うのは、左にFacebookで知り合い登録をしているアカウントアイコンが並び、右にRSSTwitterFacebookストリームポップアップで表示するアイコンが並んでいる。それぞれの領域をエッジと呼ぶ。

f:id:LaclefYoshi:20101110212328p:image

f:id:LaclefYoshi:20101110212326p:image

デベロッパーツールは、Google Chromeの様に独立窓で出るのではなく、Firebugの様に現在表示しているタブ内の下部に表示される。

アドレスバー右に「Shareボタンがあり、何かWebページを表示しているときにクリックするとそのURLFacebookTwitterで共有(投稿)するためのポップアップが出る。どうせなら、アドレスバーtweetを書き込んで投稿というのも可能なら良かったのに、と思った。

Shareボタンの右にFirefoxの様に検索ボックスがある。Google Chromeの様にアドレスバー検索語を入力して検索することもできるが、検索ボックス検索すると、タブを使わずに検索ボックス下部ににゅうっと出るポップアップ検索結果を簡易表示する。

f:id:LaclefYoshi:20101110212329p:image

もちろん、Google Chrome拡張機能を使うことが出来る。拡張機能アイコンはFeedsエッジに表示される。そして、Feedsエッジに表示されることにより、Google Chromeではウィンドウが非アクティブになるとポップアップが閉じられるが、RockMeltではウィンドウが非アクティブになってもポップアップが閉じない、再生中局名バッジ表示が出ない、など挙動の差異が現れている。

f:id:LaclefYoshi:20101110215523p:image

f:id:LaclefYoshi:20101110215659p:image

左/右のエッジは非表示にすることも出来る。

f:id:LaclefYoshi:20101110212327p:image

Google ChromeGrowlを使わず全てDesktop Notificationsで通知を行うと決めた*1ので、Growlが使われることはないだろうが、RockMeltはFeedsのアップデート通知のみでGrowlを使うことが出来る。

f:id:LaclefYoshi:20101110212325p:image

しばらく(と書いて実は6時間ほどだが)使ってみて、TwitterにFeedsエッジでログイン出来なくなったり、Friendsエッジのtweet/status投稿ポップアップが出なくなったりするトラブルがあった(再起動したら直った)が、全体としてはGoogle Chromeと同じようにさくさく動く。Google Chromeブックマークなどをインポート出来るので、環境を移行する手間も小さい。

常に知り合いのStatusが見えているという状態はIMっぽくてソーシャル可視化として正しいと感じている。知り合いのアイコンクリックすると他人から知り合いへのメッセージが見えたり(なんとなく、知り合いから他人へのメッセージが見えるのが普通だと思っていたのでちょっと驚いた)、すぐチャットが出来たりして、コミュニケーションのためのインタフェースとしてよく考えられている。

ただ、tweet/status投稿でも、Feedsを見るにしても、ポップアップを出すためにエッジにマウスを移動して1クリックする必要があるというのが、少々面倒に感じる。Feedsがアップデートされるとアップデート数(未読数)をアイコンバッジ表示してくれるが、それだけ。この辺は、もう少しプッシュ的なインタフェースを導入して、洗練して欲しい。ソーシャルというのは、そんなに読むことを押し付けるようなインタフェースでなくても、見逃し/聞き逃しを許容するような形も、ありなんじゃないだろうか。どうしてもちゃんと読みたいものがあるなどの場合は、フィルタリング等でコンテンツの流れをユーザ管理出来るようにすれば良い。

まあまだプレビュー段階だから、これからどうなるかは分からないけれど。

元祖ソーシャルブラウザことFlockも3.0から(今ダウンロード出来るのは2.6.1)はChromiumベースになるというし*2、一時は盛り上がったXULベースアプリ界隈が落ち着いている。Flock場合ベース移行に伴ってOpenID for Flockみたいな良いFlock拡張機能が(一時的かもしれないが)使えなくなるのが痛いかな。

2010-11-06(土)

[][]Paver/SphinxOMakeドキュメント生成/公開を自動化する

前提と目標

ドキュメントはreStructuredText(reST)で書き、htmlドキュメントに変換される(ドキュメント生成)。生成されたhtmlドキュメントリモートサーバにscpで転送され、公開される(ドキュメント公開)。

ドキュメントを書くことのみに集中し、ドキュメント生成と公開は自動化したい。

用いるツール

ドキュメント生成/公開手順

まず、プロジェクトHOGEディレクトリを作る。

f:id:LaclefYoshi:20101106184110p:image

次に、Sphinxドキュメントディレクトリを作る。セットアップ支援があるので利用する。

$ pwd
HOGE
$ sphinx-quickstart  # セットアップ支援 / 色々聞かれるので適当に答える
# ドキュメントルートディレクトリ名: docs
# ドキュメントソースディレクトリ名: source
# ドキュメントビルドディレクトリ名: build

Paverを使って、ドキュメントを生成するために、pavement.pyを作る。

from paver.easy import *
from paver.setuputils import setup
import paver.doctools
options(
    setup(
# ...
        sphinx = Bunch(
            docroot = "docs",
            builddir = "build",
            sourcedir = "source"),
# ...

f:id:LaclefYoshi:20101106191510p:image

docs/source/index.rstを適当にいじったり、同じディレクトリに別ファイル.rstを作ったりしてドキュメントを書く。詳しくは、Sphinx説明書を参照すること。

ドキュメントソースを書いたら、htmlドキュメントを生成する。

$ pwd
HOGE
$ paver html
# docs/source/以下のrstファイルを元に、docs/build/html/以下にhtmlドキュメントが生成される

生成されたhtmlドキュメントリモートサーバで公開するタスクを、pavement.pyに以下のように書いて定義する。

@task
@needs('paver.doctools.html')
def publish():
    src = "docs/build/html/*"
    dst = "saeki@example.org:./public_html/hoge"
    sh("scp -r %s %s" % (src, dst))
$ paver publish
# docs/build/html/以下のhtmlドキュメントを(無ければ paver htmlで生成して)、リモートサーバにscpで転送する

ドキュメント生成/公開の自動

docs/source/以下のファイルをいじる度に、端末(もしくはemacsシェル)でpaver publishを実行するのは面倒。

そこで、OMakeファイル監視/自動ビルド機能を活用する。

$ pwd
HOGE
$ omake --install  # 全てのサブディレクトリにOMakefileを配置するなら--install-all

f:id:LaclefYoshi:20101106191511p:image

OMakefileを編集する。

.PHONY: publish

publish: $(glob docs/source/*)
    paver publish
$ pwd
HOGE
$ omake -P --verbose publish
# ターゲットはpublish
# ファイル監視/自動ビルドのため待機(終了するにはC-c)

これで、docs/source/以下のファイル編集される度に、自動的にビルドコマンド:paver publishが実行される、つまりhtmlドキュメントの生成とリモートサーバへのドキュメントファイル転送が行われる。

まとめ

これまで

emacs上でreSTドキュメントを書く -> 端末(emacsシェル)に移動しpaver publish -> emacsに戻りドキュメント編集する -> 端末に移動しpaver publish -> ...

これから

emacs上でreSTドキュメントを書く -> emacs上ででドキュメント編集する -> ...
(裏では、ドキュメント編集される度にOMakeがpaver publishしている)

2010-11-03(水)

[]OpenGL五芒星を描く

Haskell PlatformにはOpenGLGLUTライブラリが入っているので、余計な手間不要ですぐ使える。

no titleにあるチュートリアルを読めば、使い方はすぐ分かる。

f:id:LaclefYoshi:20101103150200p:image

とりあえず、関数型言語らしさがどうとか気にせず、素直に書いた。

import Graphics.Rendering.OpenGL
import Graphics.UI.GLUT

main = do
  (progname, _) <- getArgsAndInitialize
  createWindow "Star"
  displayCallback $= display
  mainLoop

display = do
  clear [ColorBuffer]
  renderPrimitive LineStrip $ do
                color $ (Color3 (1.0::GLfloat) 1.0 1.0)
                vertex $ (Vertex3 ((cos (pi * 90 / 180))::GLfloat)
                                  (sin (pi * 90 / 180))
                                  0)
                vertex $ (Vertex3 ((cos (pi * (90 + 2 * 72) / 180))::GLfloat)
                                  (sin (pi * (90 + 2 * 72) / 180))
                                  0)
                vertex $ (Vertex3 ((cos (pi * (90 + 4 * 72) / 180))::GLfloat)
                                  (sin (pi * (90 + 4 * 72) / 180))
                                  0)
                vertex $ (Vertex3 ((cos (pi * (90 + 72) / 180))::GLfloat)
                                  (sin (pi * (90 + 72) / 180))
                                  0)
                vertex $ (Vertex3 ((cos (pi * (90 + 3 * 72) / 180))::GLfloat)
                                  (sin (pi * (90 + 3 * 72) / 180))
                                  0)
                vertex $ (Vertex3 ((cos (pi * 90 / 180))::GLfloat)
                                  (sin (pi * 90 / 180))
                                  0)
  flush

僕が最初に書いたプログラムBASICで、本に書かれたコードをそのまま入力して、FM-7の画面の上に線と円で描いた絵が表示された。

最近流行りのプログラミング言語は、どれも初学者がいきなり絵を描くには向いてなくて、Hello, Worldとか、せいぜいASCII文字を並べて端末上に三角形を描かせる程度しか最初は出来ない。

プログラミング教育で何を教えるか、というところでこの辺の良し悪しは違ってくるけれど、やっぱりLOGOとかプログラミンとかで、綺麗な絵を描いたり絵を動かしたりすることは楽しい

2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2013 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2014 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2015 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2016 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2017 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |