Hatena::Groupsubtech

#生存戦略 、それは

-> 07 { 03 / 22 }

明日の資料

00:01 | はてなブックマーク - 明日の資料 - #生存戦略 、それは

とりあえずできた。テキストだけだけど。

もっとグラフィカルな表現をしたい。PowerPoint? KeyNote? いやたぶんそういうツールだけじゃなく、もっと、こう。角谷さんや上津さんのプレゼンには心が引きつけられる。首っ丈になれる。あんなプレゼンがいつかはしたい。二人に共通するところは何だろう。子供。映画。サブカルJava

AS3 で FlashProxy

23:03 | はてなブックマーク - AS3 で FlashProxy - #生存戦略 、それは

んー。いろいろと制約が多すぎて使いやすいのは無理ぽ。

Flashインスタンスを取得しても、呼びたいメソッドが組み込みじゃないことが多すぎる。flash player api は呼ぶのが面倒。たとえばブラジーの例では Sound のインスタンスを作ってロードして play、というのができるけど AS3 だと Sound のインスタンスを作っても、URLをロードするのに今度は URLLoader のインスタンスが必要となる。マッピングめんどい。。

また ExternalInterface 使った FlashProxy の有効活用例として、crypto のライブラリが corelib として提供されているのでそれを JS からプロキシって使うと割と便利じゃ、と思ったのだけどこれも微妙。

http://weblogs.thekeunster.com/?p=10

で書かれてるのだけど、組み込みの flash player api 以外のクラスを import 文で読み込んで、getDefinitionByName で Class オブジェクトを取得したとしても、それを利用できない。これは理由としては

http://subtech.g.hatena.ne.jp/secondlife/20070322/1174557284

で書いているけど、

クラスを読み込んだだけでアプリケーション内で使用していない場合、そのクラスは結果の SWF ファイルのバイトコードには含められません。

つまり getDefinitionByName では実行時にクラスが判別するため、コンパイル時にはアプリケーション内で利用してないと判別され、swf に組み込めない。これはコンパイルオプションかなんかで回避できるのかなー。無理矢理回避する方法として、

var _undefineVar:MD5;

public function example():void {
  var className:String = 'com.adobe.crypto.MD5';
  this.target = new (Class(getDefinitionByName(className)));
...

みたいに undefined でいいので記述しておくとかいう回避策が必要でアホっぽい。

というわけで、汎用的に使う FlashProxy でいい実装が思い浮かばないのでした。ただ flash player 組み込みAPIの static なメソッド呼ぶ用途では使うことがあるかも、と思ったので corelib の crypto を組み込んだ as/js ソースを公開してみる。使う人は居なさそうだけど、、、。

これを使うと

new FlashProxy3('com.adobe.crypto.MD5', {
    onComplete: function() {
      console.log('MD5:' + this.hash('example'));
    }
});

new FlashProxy3('com.adobe.crypto.SHA1', {
    onComplete: function() {
      console.log('SHA1:' + this.hash('example'));
      console.log('SHA1 base64:' + this.hashToBase64('example'));
    }
});

new FlashProxy3('com.adobe.crypto.WSSEUsernameToken', {
    onComplete: function() {
      console.log('WSSEUsernameToken:' + this.getUsernameToken('user', 'pass', 'foo', new Date()));
    }
});

で、

MD5:1a79a4d60de6718e8e5b326e338ae533
SHA1:c3499c2729730a7f807efb8676a92dcb6f8a3f8f
SHA1 base64:w0mcJylzCn+AfvuGdqkty2+KP48=
WSSEUsernameToken:UsernameToken Username="user", PasswordDigest="CbEokEddO4P7dw3uy4Wp0OiuIDM=", Nonce="Zm9v", Created="2007-03-22T22:57:31Z"

みたいな結果を取得できる。

以下ソース

FlashProxy3.as

package {
    import flash.external.ExternalInterface;
    import flash.display.Sprite;
    import flash.display.LoaderInfo;
    import flash.utils.getDefinitionByName;
    import flash.utils.describeType;
    import Class;

    import com.adobe.crypto.*;

    public class FlashProxy3 extends Sprite {
        private var target:Class;

        public function FlashProxy3() {
            // corelib crypto.* classes
            com.adobe.crypto.MD5;
            com.adobe.crypto.SHA1;
            com.adobe.crypto.WSSEUsernameToken;

            this.target = Class(getDefinitionByName(params.className));

            ExternalInterface.addCallback("methods", methods);
            ExternalInterface.addCallback("dispatch", dispatch);
            ExternalInterface.addCallback("addListener", addListener);
            ExternalInterface.call("FlashProxy3.loadComplete", params.id);
        }

        private function methods():Array {
            var t:XML = describeType(this.target);
            var methods:Array = [];
            for each (var m:XML in t.method) {
                if (m.@declaredBy == t.@name) {
                    methods.push(String(m.@name));
                }
            }
            return methods;
        }

        private function dispatch(prop:String, args:Array):Object {
            var obj:Object = this.target[prop];
            if (obj is Function) {
                return obj.apply(this.target, args);
            }
            return obj;
        }

        private function addListener(event:String):void {
            this.target.addEventListener(event, function(... args):void {
                ExternalInterface.call("FlashProxy3.onTrigger", params.id, event, args);
            });
        }

        private function get params():Object {
            return this.root.loaderInfo.parameters;
        }
    }
}

flash_proxy3.js

function FlashProxy3(className, options){
    if (options) {
        if (options.onComplete) {
            this.onComplete = options.onComplete;
        }
    }
    var swfLocation = FlashProxy3.options.swfLocation;

    var uid = FlashProxy3.getUid();
    FlashProxy3.instances[uid] = this;

    var tag = [];
    tag.push('<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="0" height="0"');
    tag.push(' id="' + uid+ '"');
    tag.push(' align="middle">');
    tag.push('<param name="movie" value="'+swfLocation+'" />');
    tag.push('<param name="quality" value="high" />');
    tag.push('<param name="bgcolor" value="#ffffff" />');
    tag.push('<param name="FlashVars" value="id=' + uid + '&className=' + className + '"/>');
    tag.push('<param name="allowScriptAccess" value="always"/>');
    tag.push('<embed src="'+swfLocation+'" FlashVars="id=' + uid + '&className=' + className + '"');
    tag.push(' allowScriptAccess="always" quality="high" bgcolor="#ffffff" width="0" height="0"');
    tag.push(' name="' + uid + '" align="middle" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />');
    tag.push('</object>');

    var div = document.createElement("div");
    document.body.appendChild(div);
    div.innerHTML = tag.join("");

    this.flash = document.all ? window[uid] : document[uid];

}

FlashProxy3.getUid = function() {
    var now = new Date();
    var uid = "id_" + now.getTime() + now.getMilliseconds();
    if (FlashProxy3.instances[uid]) {
        return FlashProxy3.getUid();
    }
    return uid;
}

FlashProxy3.instances = {};
FlashProxy3.options = {};
FlashProxy3.options.swfLocation = "FlashProxy3.swf";

FlashProxy3.prototype.dispatch = function(prop, args){
    return this.flash.dispatch(prop, args);
}

FlashProxy3.loadComplete = function(uid) {
    var flash_proxy = FlashProxy3.instances[uid];
    var flash = flash_proxy.flash;

    var methods = flash_proxy['flash'].methods();
    for(var i = 0; i < methods.length; i++ ){
      flash_proxy[methods[i]] = (function(prop){
          return function(){
              return flash.dispatch(prop, Array.prototype.slice.call(arguments))
          }
      })(methods[i]);
    }

    if (flash_proxy.onComplete)
        flash_proxy.onComplete.apply(flash_proxy);
}

FlashProxy3.prototype.addListener = function(event, func){
    this[event] = func;
    this.flash.addListener(event);
}

FlashProxy3.onTrigger = function(uid, event){
    FlashProxy.instances[uid][event](Array.prototype.slice.call(arguments, 2));
}

brazil 産の FlashProxy

21:15 | はてなブックマーク - brazil 産の FlashProxy - #生存戦略 、それは

なるほどねぇ。js/flashイベントの相互追加あたりうまくかんがえてるなー。でもこれだと FlashProxy のインスタンス作った後即座にメソッド呼び出しすると swf がロードされて無くてそれでも ExternalInterface のメソッド呼んでエラーになることが無いかな?

import package.*

18:54 | はてなブックマーク -  import package.* - #生存戦略 、それは

おー。別に flash.display.* や flash.utils.* はワイルドカードで読み込んでも良い気がしてきた(めんどくさいし)。コンパイル時に時間が多少増えるのと、意図しないクラスを使ってもエラーにならない、名前がバッティングする以外にデメリットってどんなのがあるのかしら。

また、ワイルドカード文字 (*) を使用してパッケージ全体を読み込むこともできます。たとえば、次のステートメントを使用すると、MyPackage.Util パッケージ全体が読み込まれます。

import MyPackage.Util.*;

読み込まれるファイルおよびパッケージソースパス上で検索れ、最終的な SWF ファイルで使用されるもののみが組み込まれます。

単に完全修飾クラス名を指定するだけでは十分ではありません。完全修飾クラス名は、異なるパッケージに含まれる同じ名前のクラスを区別する場合のみ使用します。

クラスを読み込んだだけでアプリケーション内で使用していない場合、そのクラスは結果の SWF ファイルのバイトコードには含められません。結果として、ワイルドカードを使用してパッケージ全体を読み込んだ場合でも、必要以上に大きな SWF ファイルは作成されません。

flex2_createextendcomponents.pdf

18:05 | はてなブックマーク - flex2_createextendcomponents.pdf - #生存戦略 、それは

スルーしていたけどこれも読まないとまずそーだなぁ。メタデータの扱いとか載ってる。つーか AS3 の言語自体はわりと簡単だけど、mxmlc の .as のジェネレートの挙動とか namespace での制御とか、追っていくと BK すごそう。

&#13;

17:44 | はてなブックマーク - &#13; - #生存戦略 、それは

改行覚えにくい。慣れの問題カー

のどが

12:03 | はてなブックマーク - のどが - #生存戦略 、それは

ひさしぶりに一時間ぐらい喋ったらのどが><

とほつうきん

09:56 | はてなブックマーク - とほつうきん - #生存戦略 、それは

朝徒歩だと仕事する前から疲れたきぶん><

kumajetkumajet2007/03/22 11:34きっとそのあるいた分おなかの肉が削げるよ!

secondlifesecondlife2007/03/22 11:50昨日夜中にラーメン食べた!死にたい><

brazilbrazil2007/03/22 22:48うーん、こ。
FlashProxy、今使ってるやつと、違うのかもなぁ。
公開しなおすか...、日付つきのエントリなのも、微妙な気持ちのあらわれなのよねぇ。
そもそもやね、Flash側でevalがきちんとできれば、それを外部にさらせば、それで全部終わりだと思うんだけどなぁ。
AS3とか、Flexとか、evalは強いのでしょうか?

secondlifesecondlife2007/03/22 22:58eval は存在しなくなった!よ!
次のエントリーをよんで!ね!

secondlifesecondlife2007/03/22 23:01あ、あと uid もかぶるので修正しt

brazilbrazil2007/03/22 23:18あー、uid、そんなこともありました、バカだから時間かなんかでやっちゃってるんだよね。
そのクラスが使えるかわからないから、evalが使えないってこと?
全部組み込んだスーパーなswf一個作って、ぐりんぐりん使ったりできないんだ?
なんだよ、なんだよ、そもそもevalがないのか!?

secondlifesecondlife2007/03/22 23:23そもそも eval が無いんだよ!!!
あとなんやかんやで型を要求しまくってくるので、
JS の型だと動かないまくり。ラッピングが必要まくり。
Flash 側のデリゲータをもっとかっちょよく書くことができたらうまく行きそうな気もするけどけどけどけどどけー。

brazilbrazil2007/03/23 00:24忙しいとこ、どうもありがとう。

kakutanikakutani2007/03/23 01:34Javaかよ!

secondlifesecondlife2007/03/23 01:44大きな共通点!!!

posemaniacsposemaniacs2007/10/16 16:23AS1やAS2は組み込み関数天国なので、AS3からさらにProxyしてやるといいかも(笑!!

トラックバック - http://subtech.g.hatena.ne.jp/secondlife/20070322