2013年12月6日金曜日

AS3.0 で [Embed]で埋め込んだ動画(FLVなど)の再生と終了を検知する方法

データ(ByteArray)からの動画再生

Flash10からデータ(ByteArray)を直接実行する機能がNetStreamクラスに追加されている。
NetStream.play()にnullを渡すことで、データ生成モードとなり、appendBytes()というメソッドを使ってデータ(ByteArray)から再生できる。
Flash10からの機能なのでFlash9向けのAPIリファレンスを見ると載っていないので注意。

動画の終了検知

データ生成モードの場合、通常の再生と異なり色々とイベントが発生しないようである。
通常はVideoクラスのEvent.COMPLETEイベントで終了を検知できるようだが、データ生成モードの場合はできない。

動画の終了を検知するには、NetStreamクラスのNetStatusEvent.NET_STATUSイベントを使用する。
NetStatusEventのinfoプロパティのcodeに 'NetStream.Buffer.Empty' が入っていたらappendBytes()で追加したデータをすべて使い切ったということなので、終了を検知できる。

netStream.addEventListener( NetStatusEvent.NET_STATUS, handler );

function handler(e:NetStatusEvent):void {

    if ( e.info.code == 'NetStream.Buffer.Empty' ) {
        // 動画終了時処理
    }
}

参考サイト

ビデオ再生方法
http://stackoverflow.com/questions/10579142/how-to-embed-flv-in-flash-and-play-it-with-as3

終了を検知してループ再生する方法
http://stackoverflow.com/questions/11891852/how-to-loop-video-using-netstream-in-data-generation-mode

2013年12月4日水曜日

[AS3]BreakOpportunity.ANYでTLF Markupの明示的な改行(
)が効かなくなる。

いつも直感的な動作をしてくれないAdobeのフレームワーク。
またひとつやらかしてくれました。

問題発生

コンテナに沿って一文字ずつ文字を表示したかったため、TextFlowをBreakOppotunity.ANYに設定していたのですが、TextConverter.importToFlow()で読み込んだTLF Markupの<br/>が効かないという事象が発生しました。
BreakOppotunity.AUTOに戻すと効きます。BreakOppotunity.AUTOにしておかないとたとえ<br/>タグ(内部的には改行コード)であろうと改行してくれないようです。

なお、発生した環境は MacOSX Flex4.6/Air3.1

解決策

TextConverter.importToFlow()は<br/>を見つけると<span>\u2028</span>という形式に変換するようです。直前までのspanを一度区切って、一個専用のspan要素を作ります。
そこで、importToFlow()が返したTextFlowの子要素を再帰的に辿り、<br/>から変換されたspan要素のbreakOppotunityだけをBreakOppotunity.AUTOに書き換えることで問題を解決することができました。

private function fixLineBreak(elem:FlowGroupElement):void {
 var num:int = elem.numChildren;
 for ( var i:int = 0; i < num; i++ ) {
  var child:FlowElement = elem.getChildAt(i);
  if ( child is SpanElement ) {
   var span:SpanElement = SpanElement(child);
   if ( span.text == "\u2028" ) {
    span.breakOpportunity = BreakOpportunity.AUTO;
   }
  }
  if ( child is FlowGroupElement ) {
   fixLineBreak(FlowGroupElement(child));
  }
 }
}


2013年12月2日月曜日

Flexでゲーム開発するならuse-gpu=trueを設定しないといけない

色々事情があってAdobe Air/Flex環境でゲームを作っていたところ、描画にCPUリソースを使いまくることに気づいた。埋め込みSWFなんかをそこそこの大きさで描画するとすぐに50%くらいCPUを消費してしまう。
どうもコンパイラオプションにuse-gpu=trueを設定しないと描画がすべてCPUで行われてしまうらしい。
Air/FlexでStarlingも使わずにゲーム開発なんてなかなかしないだろうからか、そういった情報が全然なかったのでだいぶ悩んだ。

Flexの設定ファイルに記述するrenderModeについては多く情報が存在する。
しかしrenderModeにgpuを設定するだけでは無駄で、コンパイラオプションを設定しない限りGPUが使われることはない。

GPUを使う場合は色々制約があり、下記に記載がある。
http://help.adobe.com/ja_JP/air/build/WSfffb011ac560372f-5d0f4f25128cc9cd0cb-7ffd.html

その他、あまり理解していないがuse-direct-blitというオプションもGPU描画に関連しているらしいのでtrueにしておくと高速化されるかもしれない。

コンパイラオプションの一覧(英語)
http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7a92.html


2013年11月10日日曜日

wineでSuzuka0.8.1を動かす

最新版のSuzukaでは下記の記事の内容にプラスして作業が必要だった。
wineでsuzukaが動いたので報告

環境

・Mac OSX10.7
・wine1.6
・winetrick @20130707

発生していたエラー

err:ole:CoGetClassObject class {603c7e80-87c2-11d1-8be3-0000f8754da1} not registered

解決方法

mscomct2.ocx というのが足りなかったのが原因のようで下記からDLした。

(1) OCXをダウンロード
http://www.nodevice.jp/dll/MSCOMCT2_OCX/item12150.html

(2) 保存
落としたocxを ~/.wine/drive_c/windows/system32/mscomct2.ocx に保存。

(3) レジストリに登録
$wine RegSvr32 mscomct2.ocx

これでひとまずSuzukaが起動しました。

2013年10月8日火曜日

ヤフオク、Yahoo!ショッピングの無料化に関するまとめ

Yahoo!ショッピング

・ストア出店料(初期費用)を無料化
・売上ロイヤルティを無料化
・年内に個人の出店を可能に

ヤフオク

・出品手数料を無料化
・ストアの月額料金を無料化
・ストアの出品数上限を撤廃
・5000円以上の入札をYahoo!プレミアム会員以外にも解放
・5000円以上の入札は本人確認済みのユーザーでないと入札できなくする設定も可能

今後のビジネスモデル

今後は出店料や手数料ではなく、広告により収益をあげる予定とのこと。

楽天との比較

・楽天オークションの落札時手数料は6.3%であるのに対して、ヤフオクは5.25%なので、ヤフオクの方が安い
・楽天市場は出店料(月額)やロイヤルティがある。Yahoo!ショッピングは両方無料。

出品者にかかる金銭的負担に関して、楽天と比べるとYahoo!が圧倒的に有利な形に変わったといえる。
楽天の動き次第ではあるが、このままなら急速に楽天からYahooに出品者が移行する可能性が高いのではないだろうか。

2013年10月7日月曜日

Encrypted Media Extensions(HTML5におけるDRMの扱い)についてのメモ

W3CがHTML5におけるメディア著作権の管理(DRM)機構を承認したという記事があったので、なんととなくその仕様であるEncrypted Media Extensionsについて調べたのでメモ。

W3Cのドラフト
http://www.w3.org/TR/encrypted-media/

・クライアント(ブラウザ)はwebサーバーとのみ通信を行う
・webサーバー(つまりアプリケーション)はライセンス管理サーバーと通信を行う。クライアントはメディアの復号に必要なキーをwebサーバーを経由して取得する。
・暗号化の形式は規定しない。(つまりブラウザによってサポートする形式が異なることになる)
・Simple Decryptionという平文キーによる暗号化はマストでサポートするけれど、デバッグ用途などを想定しているもののようで、実システムで使うべきものじゃない。
・JavaScriptのAPIを通じてコンテンツ復号モジュール(CDM)へアクセスできる

海外ではこのDRMの承認や仕組みに関して批判が多い。
https://www.eff.org/deeplinks/2013/10/lowering-your-standards

PHP初級者におすすめ。PHP The Right Way がすばらしい

PHP The Right Wayという今時のPHP開発についてのチュートリアルサイトを見つけたのだが、これが素晴らしい。

http://ja.phptherightway.com/

サイトに書いてあるとおり、PHPはどんどん進化していて古い情報が多い。初級者(初心者ではない)やモダンなPHP開発をあまり知らない中級者が間違えずにステップアップするためのチュートリアルとしてこの記事は本当に有用だ。
コーディングやテスト、ツール周りを一通り説明してくれている。

ざっくり要約というか超訳。

・最近いっぱい進化したから最新版(PHP5.5)を使いましょう。
・コーディング規約はPSR-0,PSR-1,PSR-2など標準的な規約があるので使うといいよ。
・最近のPHPはオブジェクト指向や関数プログラミング、メタプログラミングができます。
・よく使うデータ構造などはStandard PHP Library(SPL)としてまとめられてます。
・依存関係の管理にはcomposerとpearが便利です。composerはプロジェクト単位、pearはシステム単位の依存関係の管理に使います。
・DB接続にはPDOを使おう。DBレイヤーを抽象化するライブラリとしてAura-SQLやDoctorine2 DBALなどがあるよ。
・例外を使ってエラーを補足しやすくしよう。
・ユニットテストしよう。PHPUnit、SimpleUnitなど便利なライブラリがいっぱいあります。
・ビルドやデプロイを自動化しよう。php版Antであるphingやchef(ruby製)などで自動化できます。
・継続的インテグレーションをしよう。TravisCIやJenkins、PHP-CIなどのツールが便利。
・バイトコードキャッシュしよう。OPcache(PHP5.5に組み込まれている)やAPCでPHPバイトコードをキャッシュして高速化できる。
・オブジェクトキャッシュしよう。単一サーバーでキャッシュするならAPCu、複数のサーバーでキャッシュを共有するならmemcachedなどを検討しましょう。



2013年9月21日土曜日

コマンドラインからHTMLサニタイズする

ソースコードをブログに貼付ける際に、簡単なサンプルコードをコマンドラインからHTMLサニタイズしたくなりました。そこで、方法を調べたところ、perlやphpをコマンドラインから呼ぶ方法や、recodeコマンドを使う方法が見つかりました。(正確には逆のことをする方法を見つけたので、サニタイズするコマンドに書き換えてみました)

方法1.PHPによるシェルコマンドの作成


cat $1 | php -r 'while(($line=fgets(STDIN)) !== FALSE) echo htmlspecialchars($line);'

php5.4を前提にしたコードになっていたので、少し修正しました。5.4の場合はHTML5などに対応したオプションフラグが容易されているため、php5.4環境が前提ならばhtmlspecialcharsにフラグを追加するとよいかもしれません。

方法2.Perlによるシェルコマンドの作成


cat $1 | perl -MHTML::Entities -le 'while(<>) {print encode_entities($_);}'

なお、このコマンドを動作させるには、自分の環境(MacOSX)では root権限で下記を実行してライブラリを追加する必要がありました。

cpan install HTML::Entities

方法3.GNU recodeコマンドを使う

あまり聞き慣れないコマンドですが、代表的なLinuxディストリビューションのaptやyumパッケージには含まれているようです。様々なテキストコードの変換が可能なので、勉強しておくと結構役立つかもしれません。

recodeのインストール

recodeはroot権限にて下記を実行してインストールできます。

yum install recode
or
apt-get install recode

reocodeによるHTMLサニタイズ例

cat ファイル名 | recode utf8..html

utf8のところは文字エンコーディングによって変える必要があります。

JavaのMapに同じキーの要素を含めるには

JavaのMapに同じキーに対して複数の要素を含めたくなる場合があります。
しかし、Javaの標準ライブラリに含まれるMapの実装にはHashMapやTreeMapがありますが、これらは重複したキーの要素を単純に登録することはできません。

対策1.HashMapなどの要素をコレクション型(ArrayListなど)にする

もっとも単純な解決策は要素をコレクション型にすることです。

iimport java.util.*;

public class Test {
  public static void main(String[] args) {
    Map<String,List<Integer>> map = new HashMap<String,List<Integer>>();
    // 登録
    List<Integer> list = new ArrayList<Integer>();
    list.add(11);
    list.add(12);
    map.put("group1", list);

    // 参照
    for ( Integer i : map.get("group1") ) {
      System.out.println(i);
    }
  }
}

対策2.guava-librariesのようなサードパーティライブラリを使用する

重複キーをうまく取り扱うことができるサードパーティ製の信頼できるライブラリが公開されています。

Guavaプロジェクトのページ
https://code.google.com/p/guava-libraries/

重複キーを扱えるMap実装(ArrayListMultiMap)
http://guava-libraries.googlecode.com/svn/tags/release03/javadoc/com/google/common/collect/ArrayListMultimap.html

下記のサンプルコードを見ると登録がとても簡潔にできるようになっているのが分かるかと思います。

import java.util.*;
import com.google.common.collect.*;

public class Test2 {
  public static void main(String[] args) {
    Multimap<String,Integer> map = ArrayListMultimap.create();
    // 登録
    map.put("group1", 11);
    map.put("group1", 12);

    // 参照
    for ( Integer i : map.get("group1") ) {
      System.out.println(i);
    }
  }
}

2013年9月20日金曜日

Bloggerでクッキーを使用して初回表示の判定を行う

JavaScript(JS)とクッキーを使用して、Bloggerで初回表示の判定をして表示分けをしてみました。

JSのライブラリとして jquery と jquery-cookie を使用しています。BloggerでJSのライブラリを使うためには、どこかのサイトにJSのライブラリを配置する必要がありますが、この2つを配置したCDNサービスが見つかったので、CDNサービスから呼び出すことにしました。

Bloggerの[テンプレート]-[HTMLの編集] からテンプレートを修正し、<head>にJSを記述。初回表示エリアに表示内容を記述します。

1.<head>部分にJSをロードするタグと追加のスクリプトを記述します。

      <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
      <script src="//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.3.1/jquery.cookie.min.js"></script>
      <script>
        //<![CDATA[
         $(function(){
          var dom_class= 'div.non_repeater_display_area';
          var key = 'refer_count';
          var expire = 30; // day

          var cnt = $.cookie(key);
          console.log(cnt);
          if ( cnt == null ) {
            cnt = 0;
          } else {
            cnt = parseInt(cnt);
          }
          $.cookie(key, cnt + 1, { expires: expire } );

          if ( cnt == 0 ) {
            $(dom_class).each(function(){ $(this).css('display', 'block'); });
          }
        });
        //]]>
      </script>

2.次に、<body>の初回表示を行いたい場所に下記のようにブロックを追加して完了です。
      <div class="non_repeater_display_area" style="display: none;">
        初回表示の内容をここに記述
      </div>

2013年9月4日水曜日

polymerを使ったWebコンポーネントの作成

polymerとWeb Componentsについて

W3CでWeb Componentsという仕様群が作成されている最中です。これには、外部HTMLの読み込み、テンプレートバインディング、カスタムタグなどの機能が含まれており、Web標準の仕様だけで容易にWebコンポーネントの作成を行えるようになります。
現在、Web Componentsはほとんどブラウザに実装されていませんが、JavaScriptによりWeb Componentsの機能を実装したpolymerを使うことで、既存のブラウザでWeb Componentsを動作させることができます。

コンポーネント化のサンプル(BMI計算フォーム)

サンプルはBMIを計算するフォームをコンポーネント化しています。
フォームのUIと動作はメインのHTML(index.html)とは切り離された外部HTML(gadgets/bmicalc.hml)に記述されています。メインのHTMLからは新たに定義されたカスタムタグをひとつ記述するだけでコンポーネントを表示できます。

サンプルの実行結果

File: index.html

1.scriptタグでpolymer.min.js をロードします。
<script src="polymer.min.js"></script>
polymer.min.js.map も polymer.min.js と同じパスに置かないと動作しません。

2.HTML Importsを使ってコンポーネントを定義したHTMLを読み込みます。

<link rel="import" href="gadgets/bmicalc.html" >

3.コンポーネントを表示するカスタムタグを記述します。

<devneko-bmicalc></devneko-bmicalc>

<!DOCTYPE html>
<html>
  <head>
    <script src="polymer.min.js"></script>
    <link rel="import" href="gadgets/bmicalc.html" >
  </head>
  <body>
    <h2>polytest</h2>
    <devneko-bmicalc></devneko-bmicalc>
  </body>
</html>

File: gadgets/bmicalc.html

コンポーネントを定義します。

1.カスタムタグの名称をpolymer-elementのname属性に指定します。
<polymer-element name="devneko-bmicalc">
カスタムタグ名はハイフンで区切られている必要があります。

2.template要素内にコンポーネントのUIを記述します。

3.scriptでPolymer関数を使いカスタムタグを登録します。

Polymer('devneko-bmicalc',{

Polymer関数の第二引数にはカスタムタグのインスタンスに紐づけるパラメータを指定します。
関数を設定することもでき、呼び出す場合は on-* (サンプルでは on-click) という属性を使ってハンドラー関数を指定します。

<polymer-element name="devneko-bmicalc">
  <template>
    <div class="bmicalc">
      <h1 class="bmicalc-title">BMI計算</h1>
      <div class="bmicalc-form">
        身長: <input type="text" name="height" value="{{height}}"/>cm<br/>
        体重: <input type="text" name="weight" value="{{weight}}"/>kg<br/>
        <p style="text-align:center;margin:0;padding:0;">
          <button on-click="calculate">計算</button>
        </p>
        BMI: <span style="font-size: large;">{{result}}</span>
      </div>
    </div>
  </template>
  <script>
    Polymer('devneko-bmicalc',{
        weight: '',
        height: '',
        result: '',
        calculate: function() {
          var h = this.height / 100.0;
          var res = this.weight / (h * h);
          this.result = Math.floor(res*100)/100;
        }
      });
  </script>
  <link rel="stylesheet" href="bmicalc.css">
</polymer-element>

File: gadgets/bmicalc.css

コンポーネントの見た目を定義します。
CSSの名前空間が呼び出し元と分離されているわけではないので、呼び出し元や他のコンポーネントと被らないようにクラス名などを指定する必要があります。

.bmicalc{
  border: 2px solid lightgreen;
  border-radius: 5px;
  padding: 0em;
  display: inline-block;
}
.bmicalc-title{
  padding: 4px;
  margin: 0px;
  font-size: large;
  color: white;
  background-color: lightgreen;
}
.bmicalc-form {
  padding: 0.5em;
}
.bmicalc-form button {
  color: blue;
  font-size: large;
}