2012年12月23日日曜日

Typescriptでライフゲーム

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

jsdo.itで動くのがこれ。ソースは下


あんまりぽくない気もするけど書きやすかった感がある。
/**
* ライフゲームの世界。ボード
*/
class World{
 interval: number = 10;
 canvas: HTMLCanvasElement;
 ctx: CanvasRenderingContext2D;
 cells: Cell[][];
 constructor(public width:number, public height:number){
  this.canvas = document.createElement("canvas");
  this.canvas.width=width*Cell.cellSize;
  this.canvas.height=height*Cell.cellSize;
  this.ctx = this.canvas.getContext("2d");
  document.body.appendChild(this.canvas);
  this.cells = new Array(width);
  for(var i = 0; i < width; i++){
   this.cells[i] = new Array(height);
   for(var j = 0; j < height; j++){
    var mo = Math.floor( Math.random()*10)%2;
    this.cells[i][j] = new Cell(mo==0);
   }
  }
 }
 timeGoseBy(){
  for(var i = 0; i < this.width; i++){
   for(var j = 0; j < this.height; j++){
    this.cells[i][j].draw(this.ctx, i, j);
   }
  }
  for(var i = 0; i < this.width; i++){
   for(var j = 0; j < this.height; j++){
    this.cells[i][j].nextGeneration(i, j, this);
   }
  }
  this.start();
 } 
 start(){
  var self = this;
  setTimeout(function(){self.timeGoseBy();}, 50);
 }
}
/**
* 細胞
*/
class Cell{
 static cellSize: number = 4;
 public now: bool = false;
 public next: bool = false;
 constructor (next: bool){
  this.next = next;
  this.now = next;
 };
 leftUp(x:number, y:number, world:World){
  if(x-1 < 0){
   x = world.width;
  }
  if(y-1 < 0){
   y = world.height;
  }
  return world.cells[x-1][y-1].now ? 1 : 0;
 }
 left(x:number, y:number, world:World){
  if(x-1 < 0){
   x = world.width;
  }
  return world.cells[x-1][y].now ? 1 : 0;
 }
 leftDown(x:number, y:number, world:World){
  if(x-1 < 0){
   x = world.width;
  }
  if(y+1 >= world.height){
   y = -1;
  }
  return world.cells[x-1][y+1].now ? 1 : 0;
 }
 rightUp(x:number, y:number, world:World){
  if(x+1 >= world.width){
   x = -1;
  }
  if(y-1 < 0){
   y = world.height;
  }
  return world.cells[x+1][y-1].now ? 1 : 0;
 }
 right(x:number, y:number, world:World){
  if(x+1 >= world.width){
   x = -1;
  }
  return world.cells[x+1][y].now ? 1 : 0;
 }
 rightDown(x:number, y:number, world:World){
  if(x+1 >= world.width){
   x = -1;
  }
  if(y+1 >= world.height){
   y = -1;
  }
  return world.cells[x+1][y+1].now ? 1 : 0;
 }
 up(x:number, y:number, world:World){
  if(y-1 < 0){
   y = world.height;
  }
  return world.cells[x][y-1].now ? 1 : 0;
 }
 down(x:number, y:number, world:World){
  if(y+1 >= world.height){
   y = -1;
  }
  return world.cells[x][y+1].now ? 1 : 0;
 }
 nextGeneration(x:number, y:number, world:World){
  var aroundLivingCount = 0;
  aroundLivingCount += this.rightUp(x, y, world);
  aroundLivingCount += this.right(x, y, world);
  aroundLivingCount += this.rightDown(x, y, world);
  aroundLivingCount += this.leftUp(x, y, world);
  aroundLivingCount += this.left(x, y, world);
  aroundLivingCount += this.leftDown(x, y, world);
  aroundLivingCount += this.up(x, y, world);
  aroundLivingCount += this.down(x, y, world);
  switch(aroundLivingCount){
   case 0:
   case 1:
   case 4:
   case 5:
   case 6:
   case 7:
   case 8:
    this.next = false;
    break;
   case 2:
    break;
   case 3:
    this.next = true;
    break;
  }
 }
 draw(ctx: CanvasRenderingContext2D, x: number, y: number){
  this.now = this.next;
  if(this.next){
   ctx.fillStyle = "#000000";
  }
  else{
   ctx.fillStyle = "#ffffff";
  }
  ctx.fillRect(x*Cell.cellSize, y*Cell.cellSize, Cell.cellSize, Cell.cellSize);
 }

}
window.onload=function(){
 var w = new World(100, 100);
 w.timeGoseBy();
}

2012年12月20日木曜日

Bing Translator APIを使ったSublime Text 2の翻訳プラグインが無かったので作った話

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

http://www.flickr.com/photos/89031137@N00/5612615769/


Sublime Text 2 Advent Calendar 2012の12/20(木)担当の@sys1yagiです。最近Sublime Text 2に入門しました。

はじめに


Sublime Text 2をちらーっと触って、へーいいんじゃね、と思ってしばらく放置して
また触って、プラグイン入れて、あーいいじゃん、と思ってしばらく放置して
C言語とか触る事になって「SublimeClang」とか「CTags」とか入れてたら前回エントリっつーかAndroid Advent Calendarネタの「aaptを修正してres配下でディレクトリ階層を構築できるようにして、AOSPにrepo uploadした話」でSublime Text 2が活躍しちゃってすっかり離れられなくなった次第というわけで。
そしてプラグインがpythonで書けるという事で。
pythonは何故か無条件で好きなので、せっかくだしプラグイン書いて見ようかと思ってまず書いてみたのが
Sublime Text 2のステータスバー上で素数を数えるだけの画期的なプラグインを作りました。」です。
まぁそれではちょっと味気ないのでもうちょっと使えそうなの作ろうかと思って、まず

Google翻訳APIかTwitterAPIやな!

と思ってたら
Sublime-Text-2-GoogleTranslate-Plugin
とか
Sublime-Tweet
とか
TweetLine(Sublime Text 2 Advent Calendar 9日目 ST2からTwitterに投稿するプラグイン作った@fukayatsuさん作)
とか

既にあるやんけ!

という事で、絶望していたら

無償の Bing Translation APIを使用する(20110407)
Microsoftの翻訳APIはすごいと聞いたので使ってみた。Rubyで。

とか見つけて

よっしゃBing Translator APIで!


という次第。

どんなプラグイン?


Sublime Text 2上で選択したテキストをBing Translator APIで翻訳して、結果を別ファイルに表示するやつ。
これが

こう


詳細は下部でくやしく。

完成!


はい完成!
SublimeBingTranslator
ソースはそんなに長くないけど全部載せると長いので幾つか使ったAPIとかtips的なのをちょい並べます。

日本語に対応する


翻訳プラグインなので英語→日本語に翻訳したりします。
翻訳結果を表示する為にsublimte text 2が提供しているAPIに日本語の文字列を渡すと以下の様なエラーが出てしまします。
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe3 in position 0: ordinal not in range(128)
はいはい〜っと
# -*- coding:utf-8 -*-
を追加。
が、ダメ。

最終的にはこれをimport文の後に追加しました。
reload(sys)
sys.setdefaultencoding("utf-8")
これでSublime Text 2の各種APIに日本語が渡せます。

※その代わりにコンソールにprint文やエラーが表示されないので注意
※反映させるにはSublime Text 2を再起動する必要があります。はずす時も。

スレッドを使う


スレッドは普通に使えます。
import threading

settings.thread = threading.Thread(target=self, args=(command, edit, source_text, _from, to,))
settings.thread.setDaemon(True)
settings.thread.start()
targetにメソッド。argsに引数を渡してstartするとスレッドで実行できます。
ここではselfを渡しています。
selfというかオブジェクトを渡した場合は暗黙的に
__call__()メソッドが実行されます。
今回は
__call__(self, command, edit, source_text, _from, to)
というメソッドを実装しました。

スレッドからSublime Text 2 APIを呼び出す


スレッドで処理した後、何らかの結果をSublime Text 2側に返したくなります。
普通にAPIをコールすると怒られるのでsublime.set_timeoutを使ってメインスレッドで実行してもらう様に登録します。
sublime.set_timeout(lambda:self.show_result(edit, source_text, translated), 100)
第一引数にメソッド、第二引数にdelayをミリ秒で指定します。
今回はlambda式で結果表示用メソッドを呼び出しています。

新しいファイルを開き結果を表示する


pluginでというかSublime Text 2で使える結果表示の方法は以下しか選択肢がないっぽいです。

  • クイックパネルに出す
  • ステータスバーに出す
  • ブラウザ等外部アプリケーションを開く
  • 新しいファイルを作成する
  • コード補正の奴で出す
  • アウトプットパネルに出す

  • なんだかなぁと思いつつ、今回はあたらしいfileを開いて結果をinsertする事にしました。
    ファイル操作する場合はTextCommandを使う必要があるっぽいです。
    TextCommandは実行時にEditオブジェクトを渡してくれます。
    これを使ってファイル操作を行います。

    view.insert(edit, 0, result)
    

    viewは新しく作ったファイルのViewオブジェクト。insertメソッドにEditオブジェクトとオフセットと追加する文字列を渡しています。
    先頭に追加する場合はオフセットを常に0にしとけばいいので楽です。

    インストールの仕方


    インストールはpackage_control_channelに登録したので簡単です。
    Sublime Package Controlがインストールされているものとします。

    インストールする


    Cmd+Shift+PでCommand Paletteを開き、"install"を入力


    インストールするプラグインを絞り込む為に"Bing Trasnlator"と入れると出てきます。


    ※インストール後Sublime Text 2の再起動が必要です

    使い方


    Readme読めと言いたい所ですが、簡単なので。

    翻訳設定


    [Preference]-[Package Settings]-[SublimeBingTranslator]-[Settings - Default]
    で翻訳設定をいじれます。
    デフォルトは以下です。
    {
     //Translator Language Codes
     //http://msdn.microsoft.com/en-us/library/hh456380.aspx
        "from" : "en",
        "to" : "ja"
    }
    

    適宜from, toを書き換えて下さい。
    言語コードは以下にあります。
    http://msdn.microsoft.com/en-us/library/hh456380.aspx

    from-to 翻訳する


    cmd + shift + m
    

    選択したテキストを翻訳します。
    from=en
    to=ja
    の場合以下の様になります。

    これが

    こう


    新しいファイルを開き、翻訳前と翻訳後を表示します。
    普通のファイルなので保存してもいいし編集も出来ます。
    このファイルIDを保持しているのでプロセスが生きている間は翻訳結果がこのファイルに追記されていきます。
    なんか翻訳結果が怪しいけど気にしない!

    to-from 翻訳する


    cmd + shift + alt + m
    

    これでto-fromで翻訳出来ます。


    こう


    おわりに


    Sublime Text 2おもろいでー
    あと「Advent Calendarとかまだ自分には早いわー」とか思ってる場合じゃない!
    脊髄反射で飛び込んでこそ面白い体験が待っているのだ。
    とか何とか思った。疲れるけど。

    2012年12月15日土曜日

    aaptを修正してres配下でディレクトリ階層を構築できるようにして、AOSPにrepo uploadした話

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

    photo by statuelibrtynps

    Android Advent Calendar 2012 12/15(土)担当の@sys1yagiです。

    どうしてもAOSPにコントリビュートしたいと日々悶々としていましたがどうコントリビュったらいいのか思いつかず今まで放置してきました。やはり最初に「コントリビュートしたい」があるともうコントリビュるのが目的になってしまってダメですね。なので現状自分が開発の中で感じた不便を改善するという方向性で考えてみました。

    はじめに


    resの下が全部フラットなのがすげーめんどいじゃないですか。例えば、layoutとか特定画面で数個使ったりする場合もあるし、そもそも機能単位で分けたいじゃないすか。例えばアプリ内課金の画面フローがあったとしたらそれに関連するレイアウトをディレクトリに切って管理したいじゃないですか。一人でやっててもあのlayout配下に増え続けるファイルを管理するのは大変だってのに、複数人で開発やるってなるともうてんやわんやですね。

    これは僕はAndroidを触り始めた1.5辺りの頃からずっと感じていました。なんでフラットやねん、と。でiPhoneアプリケーションの開発をやる事になってXCodeを触り始めてますます強く感じるようになりました。XCodeではプロジェクト内のリソースを論理的にグループ化できたんですよ!Androidェ・・・

    res配下はビルド時に解析され、res配下の内容を元にR.javaが生成されます。R.javaに生成されたR.layout.mainとかはintの定数なんで、別にもともとファイルが置かれているパスとかどーでもいいはずです。更にバイナリ化されたresファイルはR.javaのIDとマッピングされているはずなので実XMLファイルがどこにあったかなど問題にならんはずなんですよ!



    1.こうしたい


    こうしたい!まとめたいよ!


    現状だとres/layout/settings配下は無視されてR.layoutにsettings_mainは出てこないんですねー

    2.改善するには?


    だれがR.javaをgenerateしているんだろうか!?aaptだよ!
    aaptのソースは以下のパスにいます
    /frameworks/base/tools/aapt

    このaaptがresディレクトリ以下をスキャンする処理を修正すればいいのではないか。


    3.改善する


    改善の要件として「修正によって既存のAndroidアプリケーションのコードに影響を及ぼさない」という事を考えると、res/layout/storeというディレクトリがあったとして、R.javaがR.layout.store.mainという風に書き方が変わってしまうのは避けたいですね。するとres/layout配下はXCodeにおけるグループの様に扱うとよさそうです。

    つまりディレクトリで分かれているけどres/layout配下のファイル名はユニークである必要があるという事。生成されるR.javaもres/layout配下のディレクトリ名は無視し、res/layout/store/main.xmlというものがあったらR.layout.mainを生成します。他のres/drawableなども同じです。


    修正したファイル


    修正したファイルはこれ
    #android-4.2_r1
    /frameworks/base/tools/aapt/Resource.cpp
    
    385行目のcollect_files関数でXMLパースの対象となるファイルの準備をやっています。
    //元のコード
    static void collect_files(const sp<AaptDir>& dir,
            KeyedVector<String8, sp<ResourceTypeSet> >* resources)
    {
        const DefaultKeyedVector<String8, sp<AaptGroup> >& groups = dir->getFiles();
        int N = groups.size();
        for (int i=0; i<N; i++) {
            String8 leafName = groups.keyAt(i);
            const sp<AaptGroup>& group = groups.valueAt(i);
            const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& files
                    = group->getFiles();
    
            if (files.size() == 0) {
                continue;
            }
    ...
    

    ここにlayout配下のサブディレクトリも対象に含める様に再帰処理を追加しました。

    //追加後
    static void collect_files(const sp<AaptDir>& dir,
            KeyedVector<String8, sp<ResourceTypeSet> >* resources)
    {
        //begin
        const DefaultKeyedVector<String8, sp<AaptDir> >& subDirs = dir->getDirs();
        int n = subDirs.size();
        for(int i = 0; i < n; i++){
            const sp<AaptDir>& subDir = subDirs.valueAt(i);
            collect_files(subDir, resources);
        }
        //end
        const DefaultKeyedVector<String8, sp<AaptGroup> >& groups = dir->getFiles();
        int N = groups.size();
        for (int i=0; i<N; i++) {
            String8 leafName = groups.keyAt(i);
            const sp<AaptGroup>& group = groups.valueAt(i);
            const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& files
                    = group->getFiles();
    
            if (files.size() == 0) {
                continue;
            }
    ...
    
    collect_files()が呼ばれる前段でresディレクトリ内を走査してAaptDirなどのツリーを作成しています。
    この段階ではサブディレクトリ内のファイルなどもツリーが作成されていました。
    ところがcollect_files()内ではサブディレクトリの情報は利用せずスルーしていたんですねー。
    幸いにもXMLパースの対象にサブディレクトリを含めるだけで「修正によって既存のAndroidアプリケーションのコードに影響を及ぼさない」という要件は満たせました。

    ※上記コードは一回repo upload後rejectを食らってます。真の修正コードは一番下の方のパッチへのリンクから見ることが出来ます

    4.ビルドして使う


    repo syncしたディレクトリのルートで、以下のコマンドを叩けばaaptだけビルド出来ます。
    make aapt
    
    ビルドが済むと以下の場所にaaptの実行ファイルが吐かれます。
    /out/host/darwin-x86/bin/aapt
    
    darwin-x86はMacでの出力先なのでWindowsやLinuxでは別のパスになるはずですが大体同じです。
    出来上がったaaptをAndroid SDK内のaaptと入れ替えればオッケーです。
    android-sdk-mac_x86/platform-tools/aapt
    あるいは
    adt-bundle-mac/sdk/platform-tools/aapt
    

    こんなプロジェクトをビルドしてみます
    出来た!

    5.修正パッチを送る


    まずはAOSPに入門!
    Android Open Source Project
    この辺のドキュメントって日本語化されてないのかなー。
    実際コントリビュートする人達はある程度英語読めるだろうから無いという事なんだろうか?!

    AOSPに修正パッチを送るにはrepo uploadをする必要があります。というかrepo syncして持って来てたらあとは簡単らしい。ここにパッチを投げる手順が・・・!
    Submitting Patches
    http://source.android.com/source/submit-patches.html

    送ったった・・・!手順に沿えば結構簡単だった。

    aapt : Support sub directory resources


    6.レビューを待つ


    どうなるか全裸待機していたら・・・
    あっーー!


    ち、ちくしょおおおおお!!



    という事で見直し。
    エラーログを見ると
    /framework/base/packages/SystemUI/res/values-sw600dp-land/dimens.xml
    で死んでいるらしい。
    どれどれ


    なんじゃこりゃああああああ!!
    res/values-sw600dp-land
    の下にvalues-sw600dp-landがあるやん。
    でdimens.xmlが入っている。衝突してエラーになったらしい。
    なんでこんな所にこんなディレクトリ切ってんの。なんでそれが採用されてマージされてんねん。

    7.エラーを直す


    "Duplicate file"とメッセージ出ているので、重複を検出してエラーにしている所があるようです。
    そこを探し出して修正。重複があった場合エラー吐いて死んでましたが、warningにする様にしました。
    makeも無事通り、再度repo upload!

    aapt : Support sub directory resources and ignore duplicated files.

    8.レビューを待つ2


    パッチを投げて悶々とする日々。実に10日が過ぎようとしていました。
    パッチが通るにはコードレビューと検証が必要です。コードレビューってパッチがキューに積まれてGoogleの中の人が順次やってるんやろなーとイメージしていたんですがどうも違う様子です。どうも自分でレビュアーを追加するか、誰かがふらりとレビューしてくれる必要があるようです。

    「あ、あかん、放置や・・・」と思ったのでadtの開発についてやりとりをしているadt-devというMLにメールを送らないとなーと思っていた、矢先

    Deckardからメールがキテタ━━━━(゚∀゚)━━━━!!。



    そしてVerifiedにチェックマークついてたーーーー!


    いずれマージされるような気がする・・・!

    9.試したい人


    aapt : Support sub directory resources and ignore duplicated files.
    このパッチを適用してmake aaptし、作成されたaaptを既存のaaptと置き換えればいけます。
    MacでしかやってないけどLinuxはすぐできるでしょう。
    aaptは普通のネイティブプログラムなんでWindowsではあれかなーCygwinでやるのかなーしらねーよ!

    10.終わりに


    修正はたったの数行でしたが、そこにたどり着くまでに相当ソースを読みました。
    ソース読んでログ仕込んでmakeして動かしてまたソース読んでログ仕込んで・・・の繰り返し。
    何度か心が折れかけましたが執拗くmakeを繰り返しておりましたら遂に修正すべき箇所を発見。
    そこからは早かったです。

    「AOSPにコントリビュートしてわいも世界デビューやでぇ!」
    と思ってましたが結構あっけなかったです。
    日々AOSP Gerrit Serverにぶん投げられるパッチの一つに過ぎんな、と。

    せっかくコントリビュったので継続的にちょくちょくrepo uploadしようかなと思います。

    意外と簡単にrepo uploadれるので皆やりなよ!

    でも別に儲からないけどね。

    誰か焼き肉奢って下さい。


    完.



    ※2012/12/17(月) 追記!

    続き


    @vvakameからこんな指摘が!





    ぎ、ぎにゃ〜〜〜!!

    でもありがとおおおお!!

    あが…ん
    adt-devにやはりメールか。

    続き2


    という事でおれたちのたたかいはまだはじまったばかりだぜ。
    多分別エントリになる。



    2012年12月5日水曜日

    Sublime Text 2のステータスバー上で素数を数えるだけの画期的なプラグインを作りました。

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

    http://www.flickr.com/photos/whitepebble/1381373166/

    Sublime Text 2が面白いのでプラグインを作ろうと思い立ち、
    API ReferenceとかHow to Create a Sublime Text 2 Pluginとかをチラ見しつつ作成しました。
    凄いです。こんな画期的なプラグインが1日もかからず作れました。

    プラグインの概要


    タイトルにある通り、今回作成した「PrimeCounter」はステータスバーで素数を数えるだけです。
    世界中で使われているSublime Text 2ですのでメッセージはもちろん英語。

    "Let's calm down and count the prime..."
    (素数を数えて落ち着こう・・・)

    このメッセージの後に素数が表示されます!

    このプラグインは以下の様な様々なシーンでご活用頂けます。
  • バグで手が止まった時に
  • 原稿が一文字も進まない時に
  • うっかり素数を忘れてしまった時に
  • 石を叩く音によるモールス信号で自分の正体がバレそうな時に
  • 簡単なSublime Text 2プラグインを勉強したい時に


  • 仕組み


    Sublimte Text 2ではプラグイン開発のベースとなるクラスとして
    EventListener
    ApplicationCommand
    WindowCommand
    TextCommand
    を提供しています。
    今回はWindowCommandを使いました。機能的には別にWindowCommandじゃなくても良かった気がします。

    ファイル構成はこうです


    これをSublimte Text 2のパッケージ置き場に適当にディレクトリ作って放り込めば動くんですから凄いですね。

    キーバインド


    素数のカウントを開始する為のキーバインドを定義しました。
    キーバインドは以下のファイルにjson形式で記述する事で実現出来ます。
    各プラットフォーム毎に分かれてます
    Default (Linux).sublime-keymap
    Default (OSX).sublime-keymap
    Default (Windows).sublime-keymap

    中身はこんな感じです
    [
     { "keys": ["ctrl+shift+p"], "command": "prime" }
    ]
    

    ctrl+shift+pで素数のカウントをスタート・ストップ出来ます。

    実装


    実装は以下の通り。素数計算は適当です。
    重要なのはrunメソッドとdescriptionメソッド。これはWindowCommandクラスのメソッドをオーバーライドしています。
    sublime.status_messageメソッドでステータスバーに文字列を表示させています。
    sublime.set_timeoutメソッドはjavascriptのsetTimeoutと同じで、指定した関数を指定ミリ秒後に実行します。lambda式で生成したメソッドでincrementメソッドを呼び出してます。これによって1秒毎に素数を数え上げていっています。
    今回は利用していないですがスレッドも使えるし、もちろん通信も出来るのでなんでもありですね。
    ファイルアクセス系は試してませんが、どこでもアクセス出来るとなるとセキュリティ怖いですね。
    そもそもEventListenerで色々取れるし、というか開いている文書の情報には全アクセス出来る気がするので色々お漏らし出来そうな悪寒はありますね。怖い怖い。

    # -*- coding: utf-8 -*-
    import sublime, sublime_plugin
    import thread
    
    #Prime Counter
    isStart=False
    class PrimeCommand(sublime_plugin.WindowCommand):
     prime = 1
     def run(self):
      global isStart
      if isStart:
       isStart = False;
       self.prime = 1
      else:
       isStart = True
       self.increment()
     def description(self, args):
      return "prime counter."
     def increment(self):
      if isStart == True:
       self.prime = self.next_prime(self.prime)
       sublime.status_message("Let's calm down and count the prime..."+str(self.prime))
       sublime.set_timeout(lambda:self.increment(), 1000)
     def next_prime(self, now):
      p = now
      while True:
       is_prime = True
       p = p+1
       div_max = p/2
       if div_max < 2:
        return p
       for i in range(2, div_max+1):
        if p%i == 0:
         is_prime = False
         break
       if is_prime==True:
        return p
    


    インストールの仕方


    PrimeCounterはgithubで公開しています。Sublime Text 2にインストールするにはまずリポジトリを追加します。(Sublime Package Controlがインストールされている事とします)

    command+shift+pでCommand Paletteを開き、"add repository"と入れると出てきます。


    画面下部にリポジトリ追加のエディットが出てくるので
    https://github.com/sys1yagi/PrimeCounter
    を入力してEnter


    その後またCommand Paletteを開き、次は"install"を入力


    インストールするプラグインを絞り込む為に"PrimeCounter"と入れると出てきます。


    Enterを押せばPrimeCounterがインストールされます。

    実行!


    ctrl+shift+pで実行!
    素数がカウントされていきます・・・!


    終わりに


    素数計算部分がしょぼいのでpull request待ってます。
    あとこれ並列計算に何か使えないかなーとか。おもた

    2012年12月1日土曜日

    EclipseでNDK(ndk-build)を使う為の設定を自動生成するスクリプト for Mac

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    Setting up Automatic NDK Builds in Eclipse
    を参考に、EclipseでNDKを利用する設定を行なってみたわけですが

    毎回手動でBuildersを追加するのめんどくねー!?


    と思ったので自動化しました。

    スクリプト


    作ったのが以下のスクリプト
    xpathが入っていれば普通に動くはず



    環境


    adt-bundle-mac
    android-ndk-r8c

    使い方


    ANDROID_NDK_ROOTにパスを通す


    ndk導入時にANDROID_NDK_ROOTにパスを通しているとは思いますが念のため。
    ついでにPATHにも通しておくとよりよい

    ANDROID_NDK_ROOTの位置にndk-gen-externalToolBuildersを置く


    ANDROID_NDK_ROOTにはndk-buildが居るはず。
    同じ所に上のgistのコードを置く。
    ファイル名は適当でいいけどここでは"ndk-gen-externalToolBuilders"
    chmod +xで実行権限の付与を忘れずに



    EclipseでAndroid Projectを作る


    ndk-gen-externalToolBuildersはEclipseのプロジェクトファイルである.projectの内容に依存するのでまずEclipseプロジェクトを作ります。
    NDKなので試しにsampleプロジェクトをimportしてみます。





    .projectが出来ます





    プロジェクトのディレクトリでndk-gen-externalToolBuildersを実行する


    で、ターミナルからプロジェクトの所に行って、ndk-gen-externalToolBuildersを実行
    その後Eclipse側のプロジェクトをRefreshしての設定からBuildersを見ると・・・

    (゚д゚)ウマー




    キタ━━━━(゚∀゚)━━━━!!
    ndk-buildが追加されています。
    後は普通にビルドして実行すると・・・



    動いた・・・!


    仕組み


    めんどくさいので適当に。
    Eclipseのプロジェクトファイルである.projectにBuildersを追加してます。
    Buildersの定義ファイルを.externalToolBuilders/ndk-build.launchに吐いてます。
    ndk-build.launchを生成するのに.project内の情報が必要なのでxpath使ってます。
    以上