Archive for 8月, 2009

以下のような書き方はFlexならではなのかなーということで記述。
XML内の記述方法だけを見れば、いろいろ見るけど、それを同じソース内で利用するのあまり知らないので、
なるほどと思う方もいるかもしれない。(私は思った。)

フォームなどの画面から入力されたデータを1つの変数にまとめるのに、XMLを利用できる。

<mx:Model id="user">
  <user>
  	<name>{f_name.text}</name>
  	<age>{f_age.text}</age>
  	<pref>{f_pref.text}</pref>
  </user>
</mx:Model>

<mx:TextInput id="f_name" />

のようにXML中に{f_name.text}のように変数をバインディングしておき、
それをXMLのオブジェクト1つとして扱う。

1つのまとめておけば、Validatorなども作りやすくなるだろうし、
また、このようにXMLでワンクッション置いていると、入力方法の変更もしやすくなるだろう。

やっぱり、ActionScriptの非同期処理はいろいろと面倒で、なんかいい方法はないかなーといろいろと考えているが、
なんかのサブクラスを作って、それで処理をするってのはどうもお手軽ではない。。。
(これはこれで本格的にやらなくてはいけないときにはいいのですが、やっぱりちょっとしたことをするのにサブクラスは気がひけますから・・・)

それで、
1)Bの処理はAが終わったら処理をする。
2)Cの処理はAが終わったら処理をする。
ここまでは、とくに非同期処理があっても面倒ではないのです。
ところが、
3)Dの処理はBとCの処理が終わったら処理をする。
ってのがあると、、、、んんん・・・・って考えてしまいます。

そこで、こんなことができるようにとクラスを作成してみました。
ポリシーは、
・書き方が簡単であること
・サブクラスなど複雑な構造にならないこと
ってな感じで、

書き方はこんな感じです。
[AS]
var flow:JobFlow = new JobFlow();
foo.addEventListener(eventName,execA);

// 処理Bは処理Aが終わってから・・・
// 第1引数が、処理したいFunction, 第2以降は依存
flow.addDependsListener(execB,execA);
flow.addDependsListener(execC,execA);
flow.addDependsListener(execD,execB,execC);

// この関数がexecAを呼び出すと仮定している・・
foo.execute();

private function execA(e:Event):void{
// 自分のメソッド内の最後で自分のメソッドが終わったことを通知する
flow.doneDepend(execA);
}
private function execB():void{
// たとえば、処理Bがさらに非同期処理の結果を待つ場合
foo.addEventListener(eventName,handleExecB);
}
private funciton handleExecB(e:Event):void{
//  このように実際に終わったときに依存が終了したことを伝える
foo.doneDepend(execB);
}

private function execC():void{
flow.doneDepend(execC);
}
private function execD():void{
flow.doneDepend(execD);
}
[/AS]

とこのようにすれば新たなクラスを作らなくて済むし、ちょっとした部分で非同期処理のスパゲティを回避できるのではないだろうか?
ここで、依存は関数にしたがとくに何であっても問題ない。
(関数にしたのは、コードヘルパが補完してくれるので間違いが起こりにくいので、それがいいと思っています。)

ただし、イベントの結果の中身で判断しなくてはないらない場合には、そのために関数を作るのも変ですし、
[AS]
flow.addDependsListener(execD,”FLAG_A”,”FLAG_B”);
[/AS]
のように記述もでき、
[AS]
flow.doneDepend(“FLAG_A”);
[/AS]
のように書くこともできます。

ちなみに、今まで処理が途中までやったけど、一度何もなかったことにしたい・・・という場合は
[AS]
flow.reset();
[/AS]
としてください。

ただし、依存関係を消すということはできません。(この場合にはインスタンスを作りなおしてね)

ソースはこちらから

たとえば、こんなXMLがある。

<office :document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:ooo="http://openoffice.org/2004/office" office:version="1.2">
  </office><office :meta>
    <meta :creation-date>2009-08-11T09:32:05</meta>
    <dc :date>2009-08-11T09:35:06.48</dc>
    <meta :editing-duration>PT00H03M08S</meta>
    <meta :editing-cycles>2</meta>
    <meta :generator>OpenOffice.org/3.0$Win32 OpenOffice.org_project/300m9$Build-9358</meta>
    <dc :description>これはOpenOfficeのドキュメントです。</dc>
    <meta :keyword>OpenOffice</meta>
    <meta :keyword>XML</meta>
    <meta :keyword>操作</meta>
    <dc :subject>サブジェクト</dc>
    <dc :title>これはタイトル</dc>
    <meta :document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="13" meta:word-count="665" meta:character-count="1725"/>
    <meta :user-defined meta:name="Info 1"/>
    <meta :user-defined meta:name="Info 2"/>
    <meta :user-defined meta:name="Info 3"/>
    <meta :user-defined meta:name="Info 4"/>
  </office>

これは、OpenOfficeで作ったドキュメントファイル(odt)ファイルのから取り出したmeta.xmlだ。

通常、名前空間がなければ
[AS]
var metas:XMLList = _xml.title;
[/AS]
のようにすればよい。
しかし、名前空間があるXMLの場合には、この名前空間を指定しなければいけない。

では、<dc:title />のように名前空間がある要素の取得は以下のようにする。

[AS]
var _dcNS:Namespace = _xml.namespace(“dc”);
trace(_xml.dcNS::title); // これで「これはタイトル」の文字列が出力される
[/AS]
初めの例でいえば、_xml.title の title が _dcNS::title のようにNamespaceの変数名 + “::” + 要素名 にすればいいのだ。
これが、もっと深い子になると、非常に読みづらくなる。
(※:_xmlは上の内容のXMLオブジェクトです。)

16進数をソースコード上に直接記述するには、
[AS]
var code:int = 0xff;
[/AS]
のように0xと付ければよい。

では、8進数はといえば、実はActionScript3 では直接記述する方法はないようです。
ただし、
[AS]
var num:int = 0766;
[/AS]
のように記述してもこれは、8進数ではなく、10進数の766です。
したがって、8進数を入力したい場合には

[AS]
var num1:int = parseInt(“0766″,8);
// もしくは
var num2:int = parseInt(“766″,8);
[/AS]
のように記述する必要があるというわけです。
頭に”0″をつけるのは好き好きで可能です。

また、16進数でparseIntを使うと
[AS]
var num1:int = parseInt(“1f6″,16);
var num2:int = parseInt(“0x1f6″,16);
[/AS]
で問題ない。

ただし、
[AS]
var i:int = parseInt(“790″,8);
[/AS]
のように、8進数ではありえない数字[9]があってもエラーにはならなく、
この結果は「7」となってしまうようです。

同様に、n進数はparseInt(number,n)の基数nを変えればいいということです。

では、次に与えられた数字を16進数や、8進数ではどのようになるのだろうか?ということを求めるにはどうしたらいいだろうか?

これは、非常に簡単だ。
[AS]
var num:int = 504;
trace(num.toString(16)); // 16進数 — 1f8
trace(num.toString(8)); // 8進数 — 770
trace(num.toString(2)); // 2進数 — 111111000
[/AS]
となる。

このような関数は知らなくても、簡単に作れてしまうために調べる手間より作ってしまえと思ってしまうことがあるが、
やっぱり他の人が見ることがあることを考えると標準を使うほうがよいだろう。

散々今まで作ってきたAIRでのZIP解凍&圧縮ライブラリですが、
ソースとドキュメントを公開しました。

こちらからどうぞ

ライセンスはLGPLとなっています。

これでZIP関連はまあ、ひと段落ついたので今度はメール関連を作っていきます。

以前、ByteArray.uncompress()でいろいろな解凍に失敗するということを書きましたが、

間違っていました。

完全なるzipの構造データの読み間違いでした。

何を間違ったかといえば、zipファイルの構造は

  • local file header (ヘッダ部分)
  • data ( データ本体)
    –  ファイル分だけ繰り返し -
  • central directory
    -  ファイル分だけ繰り返し -
  • end of central directory record

のような感じになっています。

ここで、central directoryのデータと、local file headerのデータ構造はほぼ一緒で、また、データもほぼ一緒です。

したがって、私が作ったzipライブラリはこのcentral directory を後ろから探してファイルの情報を見ています。

たまーに拡張部分のデータが異なるのです。
しかし、ほぼ一緒ではなく“完全に同じ”としてしまったために、拡張部分のデータがデータ本体に含まれてしまい、
解凍ができなかったというわけです。

試しに、deflate64(version made by = 2.1) のデータもzip64のデータ(version made by 4.5)もきちんと解凍できました。
多分、解凍に必要なバージョン( version needed to extract ) <= 2.0 なら大丈夫なのかなという感じです。

まあ、この辺もdeflate圧縮 ( LZ77 + Haffman法)をひっくり返して勉強してみて、自分が間違っているのだなーという感触を得たので、
たまにコアな部分の勉強も悪くないものです。

というわけで、AIR版圧縮・解凍アプリ(Anzipper)もバージョン 0.85でこれらのバグが治っています。

ちなみにZIPの構造について勉強させてもらった資料は

  1. http://www.pkware.com/documents/casestudies/APPNOTE.TXT
  2. http://www.wankuma.com/seminar/20080823osaka22/Default.aspx
    http://www.wankuma.com/seminar/20080823osaka22/4.pdf

を参考にさせていただきました。

せっかく、作ったのでAdobe AIR Gallery に登録してみました。

こちらから見れます。

半年前には、Flash( まあ、正確にはAIRというのかもしれませんが・・・)で、
このようなツールが作れるような環境だとは思っておらず、アニメーションツールという枠組みから抜け出せていませんでした。

まだまだ、課題はありますが・・・

さらに何点か機能追加とバグを修正しました。

機能追加

  1. 解凍モードでファイルの情報を見えるようにしました。
  2. 解凍モードで、解凍をサポートできないファイルにアイコンを表示するようにしました。
    - 赤いアイコンは、バージョンによる解凍がサポートできない。
    - かぎ付きはパスワード付きファイル(暗号化ファイル)のためにサポートできない。
  3. 解凍モードですべてを解凍したときに解凍できなかったファイルはログに表示するようにしました。
    (見えにくいですがすいません。)

です。

image4_w270

左上の[Info]ボタンで表示できます。

image5

パスワードがかかっているとかぎマークが表示されます。

バグは、おもに解凍関連で解凍が失敗するとダイアログが消えない場合が多々ありました。

詳しくはこちらからからどうぞ。

さて、今までZipの圧縮・解凍ツールを作っていた。
もともと、世の中のツールのように高機能なZipの圧縮・解凍がしたいわけではなく
最近のZipパッケージ形式のファイル(MS-OfficeのOpenXML等)の中身を見て、
中身を変更しようかなと思ったのだが、ちょっとすんなりとはできなそうです。

しかし、結構世の中に普及しているZipファイルというのは多様なのだと学びました。

まず、Zipファイル自体のフォーマット(つまりファイルを格納するための情報の持ち方)にも、
ZipとZip64というものがあり、Zip64は大きなファイル形式も格納できるフォーマットです。

また、圧縮方法もZipの仕様としてはいろいろな圧縮ルールが入れられるのですが、事実上 deflateのみ。
ただし、deflateにも通常のdeflateとdeflate64という、これまた大きなファイルでも圧縮できる方式があるのです。

そして、ByteArray.uncompress()で確実に解凍できるのは、
Zip形式のdeflateのみなのです。

まず、macの標準ツールでZip圧縮すると、圧縮方式がdeflate64という形式になり解凍できない。
また、MS-OfficeのOpenXMLのファイルはZip64という形式のZipファイルで、これが部分的に解凍できない。
なぜか、
docProps/app.xml
docProps/core.xml
が解凍できないのです。

今のところOpenOfficeで作成したファイルは大丈夫そうです。

んー、こうなると道は2つ。
1)自前で解凍するロジックを作る
解凍が十分早くできるのか心配・・・
解凍するための資料を見ようと本を探すと、絶版ばかりで高騰中・・・・、んー大学中にハフマンなんちゃら、ちゃんと勉強しとけばよかったかな。
でも、当時はそれが何を意味するのかまったくわからなかったし。
2)ActionScriptで解凍しない
100%ローカルでできなくなるかな・・・・

になりました。
ながーい時間をかけて1)で行こうかなと思っていますが、とりあえずこのあたりは保留にしておきます。

友人に「AIRってどうなの?」「いま一つはやらないね」と言われる。

原因はいくつか考えられる。
ちなみに、ここで「WEBアプリ」と記述するが、これはブラウザ上で動くアプリ(サイトともいう)

まずは、WEBアプリの代替としての可能性。

  • 1)AIRで作られていても、WEBアプリでもあまり関係がない場合には、WEBアプリのほうが有利。
  • 2)ブラウザ上でHTMLベースでしか知らないエンジニアにクライアントサイドでのプログラムはハードルが高い。
  • 3)非同期処理対応

1)は、そもそもの必要性の問題だ。
ブランド戦略として、違いを出すためクライアント化するような場合があっても、
機能として必要か?と言われれば疑問がある場合がある。
しかも、ほとんどの人にとってデータの取得元はネットだ。
したがって、オンラインを前提とするならば、AIRである必要性はここではあまりなくなってくる。
さらにGoogle GEARなどローカルのストレージまで持ち始めている。これではますますその必要性が薄くなる。

2)これはJavaScriptでもAjaxなどのライブラリを記述する人はほとんどいない。
したがって、WEBアプリだろうと、AIRであろうとどちらでもライブラリがなければ作れないのだ。
その意味では、両方ともそろっていると思われる。
では、なぜ2で言ったようにハードルが高いのかといえば、AIRでやるからにはAIRの特徴、
つまりクライアントアプリとしての特徴が必要になってしまう。ここでハードルを越えられない可能性が高い。

3)非同期処理というのは、WEBアプリではあまりなじみがない。もちろん最近のAjaxなどを使えば非同期処理があるが、
それでもすべてライブラリでやっているのでその中身や対応すらしないということもあるだろう。
それに、非同期処理という概念がまったくなくてもWEBアプリは作れる。

次にクライアントアプリを作っていた人がRIAアプリを作りたい場合

  • 1)処理が遅い(ネイティブに近い処理をしようとするとやはり遅い)
  • 2)制限が多い(自分のIPアドレスがとれないとか・・・)
  • 3)非同期処理対応

1)は、UIに関してではない。ファイル操作や、ソケットなどを見るとやはり遅さを感じる。
計測したわけではないので正確ではないかもしれないがそう感じる。

2)これはしょうがない。これをなくしてしまえばただのクライアントアプリだ。
Cでも、Javaでも使えばAIRでできることはほとんどすべてできる。ただ大変なだけだ。
でも、発想が途切れてしまうことはある。あー、あとこれだけできれば・・・・という感じだ。

3)さて、非同期処理はWEBアプリにもあるが、これは私個人になってしまうかもしれないが、
スレッドなどを使って自分でその必要性があるならば非同期処理を使える。
したがって、自分でその処理がどのようにふるまうのか定義できるのが普通の中で、
これができないといわれると困る。
非同期処理の中から非同期処理が発生してしまうとちょっと厄介だ。
これは簡単にできることが大変になってしまうので、ちょっと嫌悪感が出てしまう。

さて、ここまで見れば、やはりAIRは必要ないじゃないか?ということになってしまう。
結局、コウモリのような存在かもしれない。(鳥でもなく、動物でもない)

では、AIRという位置づけは意味があるのか?
と考えたときにプラスの面を見てみる。

それは、AIRだから画期的というよりも、今ある問題の1つの解決策という見方をしたほうがいいかもしれない。
では今ある問題とは・・・

1)多様なブラウザへの対応困難
ブラウザがOS化しようとしている。HTMLというレベルでは問題なかったが、今後ますます独自性がでることだろう。
そうなると、アプリを作るとなるといろいろなブラウザに対応する必要があるかもしれない。
AIRであれば簡単だ。AIR対応です。で終了だ。
ただ、ここでの問題は本質的にはAIRでも解決していない。IEでも対応してよ。ってなったらとか?
IE8限定。とか言ってしまえば問題は解決できるじゃないか?
でも、それは技術的問題。本質は、人間側の問題。
「ブラウザ上で動きます」→「他のブラウザは大丈夫」→「セキュリティとかでバージョンが上がるけど、それも大丈夫」
って話になるが、「AIRはクライアントのOS上で動きます。」は、そんな質問が他から出てくることもない。
OSの依存を解決するということで流行ったのがJavaとするならば、
ブラウザの依存を解決するのがAIRだと思えばわかりやすいかもしれない。

2)高機能のブラウザしかない状態は今後もあり続けることができるのか?
GoogleのChrome、Firefoxをはじめ現在ブラウザは高機能だ。IEも十二分に高機能だ。
昔はJavaScriptは禁止といわれた時代もあったが今では、当たり前だ。
さて、これほど高機能になってきたのはサイトがアプリの要素をもち始めたからだ。
しかも、無料だ。これは一見いいようにも見えるが、なぜ無料かといえば、広告があるからだ。
しかも、その広告を出す技術は高機能になり、行動追跡などをおこないそれらの情報は外に流れている。

ブラウザが高機能になったためにいろいろなことができてしまう時代になった。
さらに悪意があればもっともっといろいろなことができる。

そのために、いろいろと企業ではできないようにすることも必要になってしまう。
今、クライアントOS上ではできないように、できないようにと動き始めている。
ブラウザがOS化してしまえば、次はブラウザの番になるだろう。

こう考えれば、単なるメディアでなく機能を提供しようとすると、
インターネットは使いたい。でも、ブラウザ上のルールに縛られるとできない。
じゃ、やっぱり別環境だよね。
というのは不思議ではない考えだ。

作られたアプリが数年動くのであれば、今後どのようになっていくかわからないブラウザアプリはその点で危険だ。
その点、1社のコントロールのもとにあるAIRはその点では安心できる。
私が経験したもので、お客にあるものを導入する際につらいのが「ルールですから」の一言で取りやめになるケース。
たとえば、「JavaScriptは不許可」なんてルールがあったらWEBアプリは動かない。
そのアプリのときだけ「JavaScriptはON」なんて例外は許されないのだ。

まあ、AIRの場合にはそのアプリを導入できるというルールを突破しなけれならないが、
他との依存度が低いので、説得させるのにおかしなルールが入り込んでくるリスクは低いだろう。

3)クライアントアプリのデザインは大変
これは技術的な話になってしまうが、クライアントアプリを作る時にそのデザインは大変だ。
デザインというのは、見栄え(色づかい、ボタンの形)などもそうだが、レイアウトも大変なのだ。
VBアプリで、画面を小さくしても中のレイアウトは変わらずただ見えなくなるだけとかがあるが、
これはHTMLで標準としてできていることもクライアントアプリで実現するには難しいことがある。
しかし、これではあまりにしょぼいではないか?
また、HTMLである程度はデザインと機能の分担が分かれたのは、CSSという簡単なルールがあるおかげだ。
(それでも”ある程度”というレベルだ)
AIRという技術はデザイナよりのプラットフォーム(Flash)から出てきたということは、
デザイナがその制約がわかりやすいということだ。技術者なんて、それに合わせて覚えればいいのだ。
デザイナの気分を理解し、説得させるよりは技術をおぼえるほうが手軽だとは個人的に思う。

まあ、こう見ればASPなどで機能を提供している会社はもっとAIRで機能を提供してもいいのだはないだろうか?
と思う。でもまだブラウザ版も必要になってしまうのが現状だろうから、
それでもAIRしか提供しない思い切りのよさを示せるか、とか、そこまで開発が回らないなどの問題があるだろう。

後はクライアントアプリとしての特徴を出しつつ、WEBの便利さを継承できるか?
というサービスを考えられるか?

ということになるだろう。

したがって、AIRを普及させるためには、まずクライアント型RIA(Rich Internet Application)が必要だという考えが浸透することが一番大切だということになる。
それはもしかしたら、Ajaxが浸透したようにキラーアプリケーションで浸透するかもしれないし、
上で書いた用にセキュリティなどの要因かもしれないが、それはまだまったくわからない。

追加)

あとは、「エンタメ」という領域でいえば、「Flash」でできることをAIRでやる必要性があるのは、
ブラウザの画面をいっぱいにする程のコンテンツでもないが、使っている人の身近においてほしいという場合だろう。
単純にファンの作成などといった場合には、ちょっとした気配りができるツールができるとうれしい。
でも、やはりブラウザをいっぱいするほどの力はない。

こうなると、その環境は十分に普及しているか?ということが大変重要になってくる。
AIRはそういった時に十分なのか?それは提供者の規模にもよるのでわからないが、まだ広まっているとは言えないだろう。
(デスクトップガジェットというもの自体が広まってるとは言えない気がする。)

したがって、この分野でいえば強力なプロバイダが使うか使わないか?という決断になるわけだが、
決断するにはその理由が必要なわけで、そのために、AIRがAIRであることの意味として普及するためには
上のようなことが広まる必要性があると思う。
その結果として、強力なプロバイダが採用ということになるのであろう。

ソフトウェア&ライブラリ



ライブラリ
airxmail(en)
AIR版メール送受信ライブラリ
airxzip
AIR版ZIP圧縮・解凍ライブラリ
カレンダー
2009年8月
« 7月   9月 »
 12
3456789
10111213141516
17181920212223
24252627282930
31  

カスタム検索
RSS
Add to Google
にほんブログ村 IT技術ブログへ