2015年11月17日火曜日

TensorFlowを勉強中

先日Googleが公開した機械学習ライブラリであるテンソルフローについて毎日こっそり勉強中です。
まだざっとしか見れていないのですが、機械学習を行う時に問題となる、どのように一台のPCから複数のPCで分散処理をさせるかとか、どのように学習結果を視覚化するかとか、PCで学習させたデータをどのようにスマートフォンで使うかなど、他の機械学習のライブラリで問題となる点を全部解決しているように思えます。

すごすぎる。

2015年11月12日木曜日

JavaScriptで他のファイルをincludeする2


前回、JavaScriptで他のファイルをincludeする方法について簡単に書きました。
しかし、前回の方法では複数のファイルにinclude関数が宣言されていた、以下のように同じファイル名がある場合に多重にファイルをincludeしてしまいあまり実用的ではありません。

include("test.js");
include("test.js");

そこで、今回は前回の関数をすこし修正し、これらの問題を解決した完成版のinclude関数を作ります。



main.js
------------------------------------
if(typeof(include)=="undefined"){include_list={};include=function(src){
    var xhr=null;if(include_list[src])return;include_list[src]=1;
    if (window.XMLHttpRequest)xhr=new XMLHttpRequest();
    else if(window.ActiveXObject)try {
        xhr=new ActiveXObject("Msxml2.XMLHTTP");
    }catch(e){xhr=new ActiveXObject("Microsoft.XMLHTTP");}
    xhr.open("GET",src,false);xhr.send("");(0,eval)(xhr.responseText);
}}
//↑include関数を使うすべてのjsファイルの先頭に入れる

include("test.js");
println("test.js include OK");
------------------------------------


test.js
------------------------------------
if(typeof(include)=="undefined"){include_list={};include=function(src){
    var xhr=null;if(include_list[src])return;include_list[src]=1;
    if (window.XMLHttpRequest)xhr=new XMLHttpRequest();
    else if(window.ActiveXObject)try {
        xhr=new ActiveXObject("Msxml2.XMLHTTP");
    }catch(e){xhr=new ActiveXObject("Microsoft.XMLHTTP");}
    xhr.open("GET",src,false);xhr.send("");(0,eval)(xhr.responseText);
}}
//↑include関数を使うすべてのjsファイルの先頭に入れる

include("jquery-1.11.3.js");

println=function(src)
{
 alert(src);
}


jQuery().ready(function()
{
 println("jQuery OK");
}

------------------------------------


こんな感じです。
これでどんな順番にファイルをincludeしても正しく動きます。
ちなみにこの方法はjQueryも動的にincludeできます。
これであこがのJavaScriptファイルを分割してみんなで作業できる。



2015年11月11日水曜日

JavaScriptで他のファイルをincludeする

昨日に続きいろいろな言語のめんどくさい部分をどうにかするシリーズ。

JavaScripの中から別ファイルのJavaScriptを読み込みたいときがよくあります。
複数人で作業するときや、スマホ対応するときに読み込むJavaScriptファイルを動的に変えたり。
いつもHTMLの中に読み込むJavaScriptファイルを固定的に書くのはとてもめんどくさい。
JavaScripファイルを分割して読み込みたい要求はたくさんあります。

しかしWebで調べてもみたのですが、JavaScriptを動的にincludeする方法はChromeで動かなかったり、どれもいまいち。

ということで、JavaScriptファイルを動的に読み込むinclude関数を作ってみました。


読み込む側(main.js)
--------------------------------------

include=function(src){
    var xhr=null;
    if (window.XMLHttpRequest)xhr=new XMLHttpRequest();
    else if(window.ActiveXObject)try {
        xhr=new ActiveXObject("Msxml2.XMLHTTP");
    }catch(e){xhr=new ActiveXObject("Microsoft.XMLHTTP");}
    xhr.open("GET",src,false);xhr.send("");eval(xhr.responseText);
}

include("test.js");
println("Hello!");

--------------------------------------





読み込まれる側(test.js)
--------------------------------------
println=function(src){
alert(src);
}
--------------------------------------

上記場合の注意点として、関数や変数はvarをつけないで「hoghoge=」として宣言しないといけないです。include()関数は内部でeval()関数を使用しているのですが、Chromeとかではeval()関数内で宣言したvar変数や関数がローカル変数として扱われてしまうからです。varをつけないで宣言するとグローバル変数として扱われ、元のJavaScriptファイルから呼び出せます。

でもこれだとincludeされる関数を作るのがめんどくさい・・・。
しかも外部のライブラリ使えないジャン。

じゃあどうするのか。
ここからが本日最大のポイント。
「eval」のところを「(0,eval)」にすればよさそうな気がする。

自分で書いていて思うんですが、
はぁ僕何言っての?
いっている意味まったくもってわからない。

 (function(){ return eval;}(0))('hoge');


上記の式が等価なのですが、詳しくは以下のサイトに書いてあります。
http://qiita.com/SFPGMR/items/7a09507eead5b5db8d17

簡単にまとめると、JavaScriptのeval関数の仕様では、関数を直接呼び出すと関数内で宣言された変数のスコープが呼び出し元の関数となるのですが、関数を変数経由で間接的に呼び出すと変数のスコープがグローバルになるのです。
そして、eval関数を簡単に間接的に呼び出す方法が、(0,eval)('hoge')なのです。

ということでeval部分を修正してみました。


読み込む側(main.js)
--------------------------------------
function include(src){
    var xhr=null;
    if (window.XMLHttpRequest)xhr=new XMLHttpRequest();
    else if(window.ActiveXObject)try {
        xhr=new ActiveXObject("Msxml2.XMLHTTP");
    }catch(e){xhr=new ActiveXObject("Microsoft.XMLHTTP");}
    xhr.open("GET",src,false);xhr.send("");(0,eval)(xhr.responseText);
}

include("test.js");
println("Hello2!");
--------------------------------------



読み込まれる側(test.js)
--------------------------------------
function println(src){
alert(src);
}
--------------------------------------


やったーinclude関数ができた。
ちゃんとincludeが終わるまで関数をぬけないので、includeが終わった直後からincludeした関数使えるし、includeしたファイルの中からさらにincudeできるし、完璧。

セキュリティーの関係上、他のサーバのファイルはincludeできないのはAJAXと同じです。

eval関数のこの仕様はEcmaScript5から適用されて、それ以前の仕様では変数はローカルスコープになるようです。
したがって、読み込まれる方の関数の形式は後者の方法はInternetExploler8では動かないらしいので、InternetExploler8に対応したい場合は前者の方法で、InternetExploler9以降やスマホのみでよい場合はこの方法が使えます。
読み込む方のinclude関数は後者の方法にしておけばどれでも大丈夫です。
InternetExploler8のシェア2%くらいしかないので、ほとんど無視できますが。

JavaScriptほんとうに奥が深いです。

2015年11月10日火曜日

JavaのRuntime.exec(String cmd)をスペース対応する

ITFFFとかいうサービスを使ってみようと思い、ブログに投稿するとFacebookにも自動で投稿するように設定してみました。
なので久しぶりに技術ブログを更新。


JavaのRuntime.exec(String cmd)メソッドはとっても便利なのですが、cmd文字列の中のファイル名やコマンドオプション文字列にスペースが入っている場合に動作がおかしくなります。



cmd="ls *.bat";

たとえば、上記のパラメーターでRuntime.exec()を呼び出すときちんと動きます。

cmd="sh -c \"ls *.bat\"";

しかし、上記のパラメーターのようにコマンド文字列に'"'でくくった部分がある場合、Runtime.exec()を呼び出すとエラーになてしまい、きちんと動きません。
C言語とか他の言語では動くのに。

ネットの一部の掲示板ではshコマンドのパスが悪いとかいろいろ書かれていますが、どれも原因がいまいち。しかもWindowsではきちんと動くのですが、MacやLinuxでは動かないのです。
そこで、動かない原因を解析しました。


JAVAの仕様書を見ると、Runtime.exec(String cmd)はStringTokenizerを使ってRuntime.exec(String[] cmd)に分解されると書かれています。
StringTokenizerは上記の文字列を以下のように分解するようです。

String[] cmd={"sh","-c","\"ls","*.bat\""};

StringTokenizerはスペースがくるとそこで文字列を強制分割してしまうので、'"'でくくった部分を正しく解釈してくれないようです。

似たようなメソッドで文字列の配列を渡すRuntime.exec(String[] cmd)メソッドならばスペースがあっても大丈夫なのですが、Runtime.exec(String cmd)メソッドはスペース対応してないので、仕様書を見る限り、正しく動作しないようです。

Runtime.exec()メソッドにStringの配列で渡せばよいのですが、関数の戻り値とかをRuntime.exec()メソッドに渡す場合、配列だといろいろめんどくさいしなぁ。
他の言語ではだいたいどれもできるのに、Javaだけできないなんて。うーん。困った。


そこで今日一日よーく考えて、StringTokenizerの代わりとなる、execTokenizerメソッドを作ってみました。

これがあれば、こんな感じでスペースやリダイレクトがある文字列でも正しく動きます。

Runtime.exec(execTokenizer("sh -c \"ls *.bat\""))

急いで書いたのでexecTokenizer()がまだ汚い。
原理は確認できたのであとでソースをきれいにしよう。



----------------
public static String[] execTokenizer(String cmd)
{
 int j,i,l,c,lc=' ',ct=0;
 String[] ret=null;
 int hazime=0,owari=0;

 if(cmd==null)return null;

 try{

 //count umber
 l=cmd.length();
 for(i=0;i<l;lc=c,i++){
  c=cmd.charAt(i);
  if(c=='\"'){
   for(j=i+1;j<l;lc=c,i++,j++){
    c=cmd.charAt(j);
    if(c=='\"'){
     ct++;
     break;
    }
   }
  }
  if(c==' ' && lc!=' '){
   ct++;
  }
 }
 if(lc!=' ' && lc!='\"'){
  ct++;
 }
 if(ct==0){
  return ret;
 }
 ret=new String[ct];
 ct=0;
 //
 l=cmd.length();
 for(i=0;i<l;lc=c,i++){
  c=cmd.charAt(i);

  if(c!=' ' && lc==' '){
   hazime=i;
  }

  if(c=='\"'){
   hazime=i+1;
   for(j=i+1;j<l;lc=c,i++,j++){
    c=cmd.charAt(j);
    if(c=='\"'){
     owari=j;
     ret[ct]=cmd.substring(hazime,owari);
     ct++;
     break;
    }
   }
  }
  if(c==' ' && lc!=' '){
   owari=i;
   ret[ct]=cmd.substring(hazime,owari);
   ct++;
  }
 }
 if(lc!=' ' && lc!='\"'){
  owari=i;
  ret[ct]=cmd.substring(hazime,owari);
  ct++;
 }

 }catch(Exception e){};

 return ret;
}