2012/03/03

JavaScriptのモジュールファイル群の読み込み管理をどうしよう。

ある程度考えがまとまってから、アウトプットに起こすべしと考えていたけど、
そんなことしたら何もかけないのでとりあえず書いてみる方向に転換してみる。

ディレクトリ構成
  • test.html テスト用画面
  • test.js テスト用画面の初期化スクリプト
  • module.js モジュール管理
  • completion.js 管理されるモジュール

概要
  • 指定したURLのjsを読み込む
  • 読み込んだURLを記憶して同URLのjsの読み込みを抑制する
課題
  • URLベースの指定なので相対でURL文字列自体がことなると意味なし
  • 読み込みミスった場合のハンドリングがない
  • アンロードはどうしたらいいの?
  • 名前空間衝突への考慮

URLベースの指定について
以下の選択肢で妄想。
1. モジュールごとに識別名を割り振り、それで管理。どこかでモジュール名を集中管理することになるのでやりたくない。

2. URL指定させずに、ファイル名指定させる。ファイルの存在位置は、表示htmlのURLからの相対か、特定のディレクトリ群で決め打ちする。


test.html
<html>
<head>
</head>
<body>
<input type="text" id="loginId">
<input type="button" id="completing" value="completing">
<div id="scriptDeclaration">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="module.js"></script>
<script src="test.js"></script>
</div>
</body>
</html>


module.js
var console = console || {};
console.log = console.log || function(data){alert(data);};


function ModuleLoader(){
 console.log('construtor worked.');
 this.loadedModules = [];
}

ModuleLoader.prototype.require = function(url) {
    var that = this;
    console.log(url + ' is loading...');
    if($.inArray(url, this.loadedModules) == -1){
        $.getScript(url, function(data, status){
            if(status === 'success'){
         that.loadedModules.push(url);
     } else {
                console.log(status);
            }
 });
    } else {
        console.log(url + ' is already loaded.');
    }
}

var mymodule = mymodule || new ModuleLoader();

test.js
var mymodule = mymodule || {};
mymodule.require('./completed.js');
mymodule.require('./completed.js');
mymodule.require('./completed.js');
$(function(){
    $('#completing').click(function(){
 $('#loginId').val(mymodule.compl.getCompletedScript());
    });
});

test.js
function Completion(){
    console.log('Completion loaded')
}
Completion.prototype.getCompletedScript = function(){
    return 'completed';
}

var mymodule = mymodule || {};
mymodule.compl = new Completion();

2012/01/22

hashchangeイベントをjQueryUIのtabより発生させて、DOMを非同期に切り替える

ファイル構成

  • js
    • south-street (jQueryUIのテーマファイル群)
    • index.js
    • exvalidation.js (exValidation プラグイン http://5509.me/log/exvalidation)
    • jquery.ba-hashchange.min.js (http://benalman.com/projects/jquery-hashchange-plugin/)
  • css
  • exValidation.css
  • first.html
  • first.js
  • fourth.html
  • index.html
  • second.html
  • third.html

機能

index.html上にdiv.contentsFrame要素を定義し、jQuery UIのタブ押下に応じて
内部のdiv.contentsを動的に切り替える。

コンテンツの切り替え処理はContentsManagerクラスが担う。ContentsManagerはDOMの摩り替えを行うが、hashchange自体は意識していない。hashchangeにかかる処理はhashchangeイベント内のみで処理をする。

div.contentsの中身は、リンク先のファイルからjQuery.loadで取得する。
遷移に際してはhashchangeイベントを用いて、history.back, forwardに対応する。

ファイルの取得成功時には、リンク先ファイル上の同名jsファイルを読み込む。


考慮不十分事項

エラーハンドリングがない

jsの名前空間がどうなっているのか分からない。

exValidationのエラーチップ初期化が#formError決めうち。

headにscriptをappendすることの危険性がよく分かってない。

URIはUItabがデフォルトでつけるハッシュURIのまま。

GETのためのクエリは考慮できていない。


処理の流れ

  1. 初期ページindex.jsでの初期化処理
  2. hashchangeイベントをトラップするためにjquery.hashchangeプラグインを導入し、初期化処理をする。
  3. UI Tabが生成するハッシュリンクを無視し、html上で指定したhref属性へのリクエストを発生させる。かつUI Tabの遷移先をhash化するようUI Tabのselectイベントを設定する。
  4. 上記によりUI Tabのリンク押下により '#' + href属性のhashchangeイベントを発火させる。
  5. hashchangeイベントの発火に呼応して処理されるコールバックに対して、ハッシュ化されたuriからハッシュを削除し、元々hrefに指定されていたリクエストからdiv.contensElementの内容を非同期ロードする
  6. 上記ロード完了に伴い、既存contentsの削除と新規contentsのappendを行う。ノリでfadeout/fadeinしているがそこはどうでもいい。
  7. ロード成功時に、リクエストしたurlをhtmlと仮定し、同パス上の同ファイル名のjsを読み込む。このときのscriptタグに特定の非同期読み込みされたスクリプトである旨を示すクラス名を付与する。
    (#/hoge/first.htmlへのリクエスト発生時にhoge/index.jsを読み込むscript#contentsScriptタグをheadにappendする。)
    jQuery.getScript(jsUri);する方がハンドリングがかけたりしてまだマシ。(追記: 2012/01/23)
  8. 上記処理によりjQueryのreadyイベントが発火する。(first.jsであればinputに対するexValidationの初期化が行われる。)
  9. 前回読み込んだscriptタグを削除する。(sciprt#contentsScriptをremoveする)
  10. 以上の処理によりfirst.htmlに単独で読み込んだ場合と同等の初期化が完了したコンテンツが表示され(ているといいな)
index.html
<div id="contentNavigation">
    <ol>
      <li><a href="#">HOME</a></li>
      <li><a href="index.html">Index</a></li>
      <li><a href="first.html">First</a></li>
      <li><a href="second.html">Second</a></li>
      <li><a href="third.html">Third</a></li>
      <li><a href="fourth.html">Fourth</a></li>
    </ol>
    <div id="contentsFrame" style="height:500px;">
      <div class="contents">
 <div class="contentsElement">
   <p>this is a index.html</p>
   <p>http://fdays.blogspot.com/2011/01/jquery-ui-tabs.html</p>
   <p>now</p>
 </div>
      </div>
    </div>
  </div>

first.html
<div id="contentsFrame">
      <div class="contents">
 <div class="contentsElement">
   <form id='loginForm'>
   <p id='first'>this is a first.html</p>
   <div>
   <label for='name'>Name:</label>
   <input id='name' type='text'></input>
   </div>
   <div>
   <label for='password'>Pass:</label>
   <input id='password' type='password'></input>
   </div>
   <input id='regist' type='submit' value='Regist' class='button'></input>
   </form>
   <div id='registedName'></div>
 </div>
      </div>
    </div>

first.js
$(function(){
 // 検証処理追加
 $('Form#loginForm').exValidation({
  rules:
  {
      name:'chkrequired',
      password:'chkrequired chkmin5'
  },
  errTipCloseLabel:'x',
  errInsertPos: 'body',
  customSubmit:function(){
      var registedName = $('#name').val();
      var registedPassword = $('#password').val();
      var appendedHtml = '
' + registedName + ':' + registedPassword + '
'; $('#registedName').append(appendedHtml); } }); });

index.js
// ContentsManagerClass
var ContentsManager = function(){
    this.contentsFrameId = 'contentsFrame';
    this.contentsClassName = 'contents';
    this.contentsElementClassName = 'contentsElement';
    this.contentsScriptClassName = 'contentsScript';
};
ContentsManager.prototype.preLoadInitialize = function(){
    // exValidation初期化処理
    $('.formError').remove();
};
ContentsManager.prototype.contentsReplace = function(uri){
    var contentsManager = this;
    if(uri){
 var contentsTemplateHtml = '
'; $('#' + contentsManager.contentsFrameId).append(contentsTemplateHtml); var newContents = $('.' + contentsManager.contentsClassName + ':last-child'); newContents.load(uri + ' .' + contentsManager.contentsElementClassName ,function(){ var oldContents = $('.' + contentsManager.contentsClassName + ':first-child'); oldContents.animate({opacity:0.0},500,function(){ contentsManager.preLoadInitialize(); contentsManager.unloadScript(); oldContents.remove(); contentsManager.loadScript(uri); newContents.animate({opacity:1.0},500); }); }); } }; ContentsManager.prototype.loadScript = function(htmlUri){ var jsUri = htmlUri.replace(/html$/g, 'js'); var className = htmlUri.replace(/\//g, '_'); //var scriptHtml = ''; //$('head').append(scriptHtml); jQuery.getScript(jsUri); }; ContentsManager.prototype.unloadScript = function(){ $('.' + this.contentsScriptClassName).remove(); }; var contentsManager = new ContentsManager(); //---------------------------------------------- $(function(){ $('#contentNavigation').tabs({ select: function(event, ui) { var url = "#/" + $.data(ui.tab, "load.tabs"); if (url) { location.href = url; return false; } return true; } }); $(window).hashchange(function() { var uriWithoutHash = location.hash.replace('#', ''); contentsManager.contentsReplace(uriWithoutHash); }); $(window).hashchange(); });

2012/01/09

XS35GT V2にCentOS6.2をUSBインストールしてメディアサーバにする(2)


2.5. DLNAサーバをインストールする

a. mediatombを含むリポジトリ、
RPM foregeを yumの対象に追加
http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.i686.rpm
をダウンロードしておく
# rpm --import http://apt.sw.be/RPM-GPG-KEY.dag.txt
# rpm -i rpmforge-release-0.5.2-2.el6.rf.i686
# yum install mediatomb

b. meidatom設定ファイルよりネットワーク経由アクセスを許可
# vim /etc/sysconfig/mediatomb
MT_INTERFACE="ra0"
// ifconfigあたりで使用するネットワークを選ぶ

c. 一旦起動し、初期設定ファイルを生成させる。
# /etc/init.d/mediatomb start
# /etc/init.d/mediatomb stop
# vim /etc/mediatomb/config.xml

d. mediatombの動作設定を行う。
// sqlite3ではなくmysqlを使う
      <sqlite3 enabled="no">
        …
      </sqlite3>
      <mysql enabled="yes">
…
      </mysql>
// PS3からの接続に対応
    <protocolInfo extend="yes"/><!-- For PS3 support change to "yes" -->
    <commoystem-charset>UTF-8</filesystem-charset>
    <metadata-charset>CP932</metadata-charset> 
  
// 対応メディアをいろいろ追加
    <mappings>
      <extension-mimetype ignore-unknown="no">
        <map from="jpg" to="image/jpeg"/>
        <map from="jpeg" to="image/jpeg"/>
        <map from="gif" to="image/gif"/>
        <map from="png" to="image/png"/>
        <map from="m4v" to="video/mp4"/>
        <map from="mp4" to="video/mp4"/>
        <map from="mpg" to="video/mpeg"/>
        <map from="mpeg" to="video/mpeg"/>

        <!-- Uncomment the line below for PS3 divx support -->
        <map from="avi" to="video/divx"/> 

e. FWを通過するようにする(iptables)
# iptables -A INPUT -p udp --dport 1900 -j ACCEPT
# iptables -A INPUT -p tcp --dport 50500 -j ACCEPT
# service iptables save
# service iptables restart

とりあえずこれで、iPadからの動作を確認。
iPad側のDLNAクライアントにはAirPlayを使っています。
今のところ動作は良好。

これで、やかましい&音量消費のでかいPCを常時起動する必要はなく、
かつ自宅にあるすべての端末でメディアにアクセス可能になった。

その必要があるかと言われれば、まぁ微妙なところではあるが。

2012/01/07

XS35GT V2にCentOS6.2をUSBインストールしてメディアサーバにする(1)

XS35GT V2(http://www.shuttle-japan.jp/barebone/slim/xs35gt-v2)を衝動買いしてしまったので。
起動してみると非常に静かなので、
やかましいデスクトップは休みに気合入れた作業をするときだけにして、
XS35を常時起動の普段使いにしようかと。

小型静音って、ステキやん。

デスクトップもSSD化したところなんだけど、それはそれ。


0. 環境
作業マシン: Windows7(64bit) SP1

1. 構成
ハードウェア
・XS35GT V2(http://www.shuttle-japan.jp/old/old-barebone/xs35)
 - SSD 64GB
 - SO-DIMM 4GB
・WLI-UC-GNHP(無線子機)
ソフトウェア
・CentOS 6.2 (CentOS-6.2-i386-bin-DVD1.iso)
その他使用したもの
・USBフラッシュメモリ (インストールメディアとして使用)
・Syslinux 4.04 (http://www.kernel.org/pub/linux/utils/boot/syslinux/)


2. 手順概要
 2.1. USBメモリのFAT32フォーマット
 2.2. USBメモリのインストールメディア化
 2.3. CentOSインストール
 2.4. USB無線子機の認識

/**** 本ポストは↑まで ***/
/**** ↓は残りの予定 ***/
 2.5. DLNAサーバインストール

3. 使用状況
 3.1. iPhoneからの使用
 3.2. iPadからの使用
 3.3. PS3からの使用

//--------------------------------------------------------------//

2. 手順概要
2.1. USBメモリのFAT32化
syslinux導入のため、USBをFAT32でフォーマット。















 2.2. USBメモリのインストールメディア化

a. CentOS-6.2-i386-bin-DVD1.isoをそのままUSBメモリのルートディレクトリにコピー。


b. CentOS-6.2-i386-bin-DVD1.iso内のisolinuxディレクトリ直下のすべてのファイルを、
USBメモリのルートディレクトリにコピー。
上記ディレクトリ内の"isolinux.cfg"を"syslinux.cfg"にリネーム。

c. 続けてisolinuxを除くすべてのディレクトリ・ファイルをコピー。


d. syslinuxアーカイブ内のwin64ディレクトリに移動し、
 syslinux -maf j:
を実行。(※ USBメモリは j:ドライブとして認識されています)


















 2.3. CentOSインストール
BIOSからUSBからブートするよう設定。
あとはいつもどおりのCentOSインストーラなので
流れでお願いします。

# CentOS5系で記述されている他記事では
デフォルトのgrubローダインストーラ先がUSBメモリ上となることでの
混乱について触れられています。
今回試行したCentOS6.2でも明示的にローダの位置としてSSDを指定しています。

 2.4. USB無線子機の認識
当方は裸のD25HWしかないのでこれをwifiモードで起動し、
Linuxからwifi接続する。

# e-mobile端末をUSB直差しで使うモジュール化何かが入っているようだがうまく機能させられなかった。
D25HWをUSBで直差しすると、
"モバイルエリアネットワーク"として認識される。
さらに"ネットワーク接続"ウィザードから"e-mobile"を選択することで、
APSなどが設定された接続情報ができあがるが、
試みに接続してもすぐ遮断される。何か設定値が違うのか。


a. ドライバダウンロード

http://www.ralinktech.com/en/04_support/support.php?sn=501
よりドライバ(RT8070 /RT3070 /RT3370 /RT5370 /RT5372 USB)をDL

解凍し
# vim os/linux/config.mk
の2値を変更

HAS_WPA_SUPPLICANT=y
HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=y

# vim common/rtusb_dev_id.c
の下記1行を追加
#ifdef RT3070
{USB_DEVICE(0x0411,0x0158)}, //追加行
引数は下記コマンドで確認しておくとなおよし
# lsusb

あとはいつものメイキングでお願いします。
# make
# make install
# insmod rt5370sta.ko
これで無線LANとしてアダプタとして認識される。

ref.
CentOS - USBデバイスからインストール!- mk-mode BLOG
http://www.mk-mode.com/wordpress/2010/01/11002001/
Ubuntu で Buffalo の WLI-UC-GNHP を使う - 試したことのメモ
http://ossan78.blog9.fc2.com/blog-entry-43.html

2011/12/24

UMTP L1, L2勉強用書籍

僕UMLが読める&かける人だよベンダー認定資格
http://www.umtp-japan.org/

L1,については基本的に、各図の読み方、記号の意味などの基礎知識で対応できる問題が多い。
なので、下記の本くらいの知識を押さえておけば問題ない。

[改訂版] UMLモデリング技能認定試験<入門レベル(L1)>問題集 -UML2.0対応
http://www.amazon.co.jp/dp/4774132454

それでも不安になるという私のような小物諸氏には、
問題数が魅力の下記黒本。

[黒本]
徹底攻略UMLモデリング技能認定試験問題集―L1(T1/T2)対応
http://www.amazon.co.jp/dp/4844324829

徹底攻略UMLモデリング技能認定試験問題集 L2対応 (ITプロ/ITエンジニアのための徹底攻略)
http://www.amazon.co.jp/dp/4844326627

ただし、問題が洗練されていないところに難がある。
問題文が説明不足で、回答を一つに絞り込むことが難しいことがある。
難易度も、私見では高めに設定されている。

問題をこなして自分の知識を確かめて、
穏やかな気持ちで本番を迎えるためのもの、とのある種の割り切りで活用するのがいいのではないか

mx.Controls.AdvancedDataGridのヘッダソートフィールドを非表示にする

sortExpertMode="true"する。
もちろんプロパティ名の通り、ソートフィールドの表示制御が元来の目的のプロパティではない。

sortExpertMode プロパティを true に設定すると、最初の列を選択した後に Control キーを使用して複数の列を選択し、ソートを実行できます。

ref. ActionScript3.0 リファレンスガイド

http://help.adobe.com/ja_JP/FlashPlatform/reference/actionscript/3/mx/controls/AdvancedDataGridBaseEx.html#sortExpertMode

表示:

 <mx:AdvancedDataGrid id="data" designViewDataType="tree" dataProvider="{contents}">
 <mx:columns>
 <mx:AdvancedDataGridColumn headerText="ID" dataField="id" draggable="true"/>
 <mx:AdvancedDataGridColumn headerText="Name" dataField="name"/>
 <mx:AdvancedDataGridColumn headerText="City" dataField="city" labelFunction="labelCityFunction"/>
 </mx:columns>
 </mx:AdvancedDataGrid>
非表示:

 <mx:AdvancedDataGrid id="data" designViewDataType="tree" dataProvider="{contents}"
  sortExpertMode="true">
 <mx:columns>
 <mx:AdvancedDataGridColumn headerText="ID" dataField="id" draggable="true"/>
 <mx:AdvancedDataGridColumn headerText="Name" dataField="name"/>
 <mx:AdvancedDataGridColumn headerText="City" dataField="city" labelFunction="labelCityFunction"/>
 </mx:columns>
 </mx:AdvancedDataGrid>

BlazeDSおぼえがき RemoteObjectのBoolean型のアクセサ命名

1. SwfとJavaのRemote Objectの型変換におけるBooleanの特徴。
オフィシャルな情報はこちら。
http://help.adobe.com/ja_JP/Flex/4.0/AccessingData/WS2db454920e96a9e51e63e3d11c0bf69084-7fda.html

↑によると、AS3のBooleanとJavaのjava.lang.Booleanは普通に疎通できるが、
アクセサメソッドの命名について、他の型と若干の開きがある。

StringとIntegerでの命名対応は下記の通り。
//-----------------------------
Java:
private String param;
public String getParam() ;
public void setParam(String param);

AS:
public param:String
-------------------------------//

BooleanでJava側のアクセサをis形式で書いた場合。
AS側ではisをのぞいたメンバ名をターゲットにバインドしようとしてくる。
//-----------------------------
Java:
private Boolean isFoo;
public Boolean isFoo();
public void setFoo(Boolean foo);

AS:
public foo:Boolean;
------------------------------//

BooleanでJava側のアクセサをゲッターセッターで無理矢理
書けばisFooにバインドしにいってくれる。
アクセサ名で判断してんの?
//-----------------------------
Java:
private Boolean isFoo;   (←冷静に考えてbooleanに対してこの変数命名がおかしかった 2011/5/11追記 )
public Boolean getIsFoo();
public void setIsFoo(Boolean foo);

AS:
public isfoo:Boolean;
------------------------------//

ちなみに、HibernateではいてくれるEntityで、
セッターに戻り値があったりすると認識してくれません。
//--------------------------

public String setFoo(String foo);
----------------------------//

上記理由等でRemote Objectの型変換に失敗した場合は、
デバッグ用のFlashを使っていればログにエラー出力が出ます。