心魅 - cocoromi -

半角スペース時々全角

Skypeがapple scriptから叩けるAPIを公開していた

全然知らなかったけど、いつの間にかMacにもAPIが来てた。 これで好きなだけSkypeのボットが作れるぞ。

基本的にはSkypeに対してAppleScriptのsend command でコマンドを送ることでAPIを利用出来る

send command "SKYPE_API_COMMAND ARGUMENTS" script name "YOUR_SCRIPT_NAME"

ドキュメント

まずはドキュメント

CocoaやCarbonなんかも対応している

メッセージを送ってみる

以下の手順でSkypeに対してメッセージを送信できる。

  1. SEARCH CHATSやSEARCH RECENTCHATSを使って、chat_idを取得する
  2. CHATMESSAGEコマンドを投げる

チャットウィンドウにメッセージを送るにはCHATMESSAGEを使うがこれに渡す引数chat_idの取得方法は複数あって、今のところSEARCH RECENTCHATSしか成功してない。(勉強中)

RECENTCHATSが成功すると以下のようなリストが文字列で返ってくる。このCSVな要素の1つ1つがchat_idとなる

CHATS #chat_owner/$hash, #chat_owner/$hash, #chat_owner/$hash, ......

この結果が見えたらあとは楽勝で、以下のようなAppleScriptでメッセージを送信できる。

tell application "Skype"
    send command "CHATMESSAGE #chat_owner/$hash MESSAGE_YOU_WANT_TO_SEND" script name "YOUR SCRIPT NAME"
end tell

初回はスクリプトからのSkypeへのアクセスを許可するかどうかのダイアログがSkype側で表示されるので、権限を与える必要がある。

まとめ

MacでSkypeAPIって簡単につかえたんだ!

Document Object Model Events

ブラウザJSでアプリケーションのロジックをつくろうとしていて、どうもObserver Patternになりそうなので、カスタムイベントを扱う方法を調べている。


取り合えずW3Cのドキュメントから。Level3はDraft。
http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/
http://www.w3.org/TR/2011/WD-DOM-Level-3-Events-20110531/


参考にしたのはこちら。
javascriptのカスタムイベントを作ろう!
http://d.hatena.ne.jp/shim0mura/20111224/1324735206


やりたい事

  1. EventTargetオブジェクトのdispatchEventしたいから、EventTargetを作りたい
  2. Eventオブジェクトを拡張したい
  3. 拡張したEventオブジェクトをイベントハンドラで処理したい

3はclickなんかのハンドリングと変わらないので気にしない。

EventTargetを操作するには

イベントが拡張できたとしても発火出来なかったら何も意味ない!
なのでまずは発火つまりdispatchを行えるのかを調べた。


これに関してはEventTargetがインターフェースとして定義されているのだが、
Interface EventTarget (introduced in DOM Level 2)で書かれているようにHTMLのノードとして実装されている模様。

The EventTarget interface is implemented by all Nodes in an implementation which supports the DOM Event Model.

DOM Event Modelをサポートしている実装(訳者注ブラウザのこと)では全てのノードがEventTargetインターフェースを実装します。


ちなみに、定義はこんな感じ。

// Introduced in DOM Level 2:
interface EventTarget {
  void               addEventListener(in DOMString type, 
                                      in EventListener listener, 
                                      in boolean useCapture);
  void               removeEventListener(in DOMString type, 
                                         in EventListener listener, 
                                         in boolean useCapture);
  boolean            dispatchEvent(in Event evt)
                                        raises(EventException);
};


アプリケーションロジックとしてのイベントを扱いたいので、これを使うのはスマートでは無い。
使うんだけど。



Eventオブジェクトを拡張する

Level2だと微妙だったのだが、Level3だとCustomEventというインターフェースが定義されている。

The CustomEvent interface is the recommended interface for application-specific event types. Unlike the Event interface, it allows applications to provide contextual information about the event type. Application-specific event types should use a prefix string on the event type name to avoid clashes with future general-purpose event types.


To create an instance of the CustomEvent interface, use the DocumentEvent.createEvent("CustomEvent") method call.

アプリケーションで定義される種類のイベントはCustomEventを使って実装するといいでしょう。
Eventインターフェースとは違い、アプリケーションがイベントについての情報を提供することができます。
アプリケーションで定義されるイベントの名前にはプリフィクスをつけましょう。一般的なイベント名の場合、将来的な名前の衝突を避けることが出来ます。


インスタンスの生成にはDocumentEvent.createEvent("CustomEvent")を呼び出します。


ってなわけで、createEventの引数に"CustomEvent"を渡せば、アプリケーションレベルのイベントを定義することができそうである。



実装してみた

  • document.createEvent("CustomEvent")
    • 引数間違えるとエラー出るよ( ex: Error: NOT_SUPPORTED_ERR: DOM Exception 9 )
  • evt.initCustomEvent コンストラクタが提供されてないので、メソッドで初期化します
    • 引数は( イベント種 , バブルアップするか , キャンセル出来るか )
  • document.createElement前述の通り、EventTargetはDOMのエレメントとしてしか提供されていないので、適当な要素をつくる

https://github.com/umezo/umezone/blob/master/javascript/samples/event/index.html

まとめ

ブラウザJSでも組み込みのイベントの仕組みを使ってObserverパターンを実装できそう。
その為にdocument.createEventやinitCustomEventを使う。
document経由でイベントの操作するのがちょっと、おかしい気がするけどしょうが無い。

Transition,Animation関連のイベント

CSS3からはアニメーションが出来るようになりました。
そうなると重要なのはタイミングを測ることで、W3Cではその為のイベントも定義されています。

イベントの種類

  • Transition
    • transitionend
  • Animation
    • animationstart
    • animationend
    • animationiteration


CSS Transitions
CSS Animations

メモ

webkitだと webkitTransitionEndになる。

1つのゲストOS(Debian)にNATとBridgeのNICを同時に設定する

ホストに複数NICがあるケースは結構解説がされてたけど、ゲストでNATとBridgeを同時に使う方法はなかった。

ハマりポイント

VMWare FusionのVMに複数NICを設定するのは基本的にGUIから+ボタンでサクサク追加出来るはずだが、
設定後VMをリブートしても設定が反映されていなかった。


以下のように設定しても2種類のIPを持てなかった

解決

どうもGUIから設定してもOS(Debian)の設定に反映されていないようで。
/etc/network/interfacesをみても、たしかにNIC1つ分の設定しか無い。

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug eth0
iface eth0 inet dhcp

なのでここにもう1つ分のNICの設定を書き込みifupしてやったら上手く行った。

/etc/network/interfacesに↓ついか
iface eth1 inet dhcp

$ sudo ifup eth1

まとめ

GUIしか使えないと、ときどきものすごい困る。

簡易Javascriptテンプレートエンジン

ループと条件分岐をバッサリすてたら、意外とまともなのがかけた気がするから、眠い勢いで紹介してみる。

http://github.com/umezo/umezone/blob/master/javascript/template.js

特徴

  • 変数展開しかサポートしてない
  • JSにコンパイルしている
  • JSにコンパイルしてるのにエスケープが全く考慮されてない
  • テンプレートはJSが実行されるページの要素の中に書く
  • っていうかコメントの中に書く
  • Chromeの拡張とかでかなり便利
  • 多分オブジェクトのプロパティとか関数呼び出しは動く気がする・・・。

使い方

テンプレートはtemplate.jsを読み込んでいるページのHTML中にコメントで埋め込みます。

<div id="block">
<!--
<div id="{{$id}}">
   <header>{{$title}}</header>
  <p>{{$content}}</p>
</div>
-->
</div>


区切り文字はコレです。

{{$~}}


JS側ではテンプレートが入ってる要素のIdを渡すとそのままメソッドになります。
idがhogeならtemplate.hoge();

var template = getTemplate(["block"]);

var html = template.block({
   id : 1 ,
   title : "今日のおかず" ,
   content : "骨っこ"
});

テンプレートが入ってる要素はお好みでdisplay:hiddenしたりしてください。

予期してないけど動きそうなもの

<div id="cal"><!--
{{$sum(1,2)}}
--></div>

>||javascript|
var t = getTemplate( [ "cal" ] );
var html = t.cal({
sum : function( a , b ){ return a + b; }
});

|

まとめ

条件分岐はなくていいから、ループとフィルタが欲しい
タイムスタンプをいれるとYYYY/MM/DDで表示したりとか小数点切り捨てたりとか。

VMからホストOSのMacのgrowlにnotifyを送る

以前こんなエントリー 処理時間が一定以上かかったらGrowlで通知するzshrc - 心魅 〜 cocoromi 〜を書きましたが、現在の職業柄、コマンドの実行はVMで行っています。
なので、以前の仕組みではうまくいきません。

そこで、今度はGrowlのGrowlTalk over UDPプロトコルを使って遠隔からgrowlに通知を送ります。


目次

  1. 受信側(Mac)の設定
  2. 前フリ
  3. 送信側の準備
  4. 確認

1. 受信側(Mac)の設定

Growlに外部からの通知を許可する設定をします。

System PreferenceからGrowl>Networkタブへ遷移し、以下の項目を設定します

  • Listen for incoming notifications
  • Allow remote application registration
    • Optionalな気がしますが、検証してません。

コレで設定を行ったGrowlは前述のGToUで通知を受け取ることが出来るようになります。

2. 前フリ

次はVM側の設定をするわけですが、GToUで会話するためになんとかせにゃなりません。
慣れてる人は自分で作ったほうがいいかもしれませんが、ここは既存のライブラリでサクっと済ませてしまいましょう。

すでにいくつか出回っているのでリストしておきます。php以外は使ったことありません。

3. VM側の準備

以下は上記netgrowl.phpを使った場合の説明をします。

  • 1. netgrowl.phpを適当な場所に置く
    • 色々考えた結果 $HOME/binに置きました
  • 2. netgrowl.phpを少しラップする
    • 送信先やアプリケーション名およびパスワードなんかをハードコーディングしてしまったものでラップします。
    • これも$HOME/binに置きます。
    • ソースはこんな感じ
    • 適当にアレンジしてください
  • 3. 止めにzshrcを編集します。
local COMMAND=""
local COMMAND_TIME=""
precmd() { 
    if [ "$COMMAND_TIME" -ne "0" ] ; then 
        local d=`date +%s`
        d=`expr $d - $COMMAND_TIME`
        if [ "$d" -ge "2" ] ; then
            COMMAND="$COMMAND "
            php $HOME/bin/growl.shell.php "${${(s: :)COMMAND}[1]}" "$COMMAND" 
        fi  
    fi  
    COMMAND=""
    COMMAND_TIME="0"
}
preexec () {
    COMMAND="${1}"
    COMMAND_TIME=`date +%s`
}

4. 確認

準備ができたら sleep 3とかやってローカルのGrowlが反応するか確かめましょう。
うまくいくとGrowlの設定画面にアプリケーションとしてリストされます。

Configureからアプリケーション毎に個別に表示や、音を鳴らすなどの設定ができるので、ネット経由の通知だけ見た目を変えたりすることもできます。


まとめ

なんかSSHのポートフォワードを使って無理やり遠隔のホストから送ったりしてる人もいるみたいですが、なにかとコマンドの終了がわかると便利ですよ。
Growlをつかって外部ホストのイベントを手元の端末でキャッチ!
時間は大切に。


コレを使って他人のmacに通知を送って遊ぶの楽しそう。おきろーとか はらへったーとか こっそりおくれますね!