2015年5月31日日曜日

[Raspberry Pi]Raspberry Pi を買いました


Raspberry Pi を買いました。

OSはRASPBIANをインストールしました。

【必要なもの】
・Raspberry Pi本体(Raspberry Pi 2 Model B)
・USB-ACアダプター(セットで買ったのでよくわからないのですが何でもよいわけではないようです)
・microSDカード(8GB以上でSDHCクラス10またはUHSがいいらしいです)
・HDMIケーブル(Raspberry側はタイプAです)
・ディスプレイ
・LANケーブル
・マウス(USB)
・キーボード(USB)
ディスプレイにHDMIがなかったので、HDMI → DVI変換コネクタ → ディスプレイとつないています。

セットアップはmicroSDカードにNOOBS(1.4.1 / 2015-05-11)というのをコピーしてから、それ経由でRASPBIANをインストールしました。
RASPBIANというのは最低限必要なソフトだけが入っているLinuxみたいな感じでしょうか。あとから自分でいろいろ追加していきます。

方法はここに詳しく書いてあります。

初めてRASPBIANを起動すると「raspi-config」というのが表示されます。
書籍を参考に下記の設定をしました。
あとから「raspi-config」を起動するにはLXTerminalで$ sudo raspi-config です。
I1 Change Locale: ja_JP.UTF-8
I2 Change Timezone: Asia -> Tokyo
I3 Change Keyboard: Generic 101-key PC -> Other -> Japanese -> Japanese -> The default ... -> No compose key -> Yes

最後にFinish
Passwordもここで変えておいたほうがいいかもしれません。
デフォルトはraspberryです。

raspberry pi login: pi
Password: raspberry

$ startx



GUIが起動します!

この時点でもいろいろ入っています。

LXTerminalでバージョンを確かめてみました。
$ git --version
git version 1.7.10.4

$ ruby -v
ruby 1.9.3p194 (2012-04-20 revision 35410) [arm-linux-eabihf]

pythonとか他のソフトウェアも入っていました。

[android]AdapterView.OnItemClickListener#onItemClickのpositionについて


listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
  @Override
  public void onItemClick(AdapterView parent, View view, int position, long id) {
    // positionでitemを取得する★
  }
});

「// positionでitemを取得する★」のところで、ArrayAdapterの生成のときに渡したListインスタンスからList#getでItemを取得するようなコードを書いていました。よく。。。

ある日これではだめなことがわかりました。
listView.addHeaderView(header, null, false);
上にくっつきすぎている気がして、ヘッダーを追加したんです。
すると、+1された位置のものが返されるようになって、Listインスタンスから取得しているものだから最後尾のアイテムを触るとArrayIndexOutOfBoundsExceptionが発生するようになりました……

http://stackoverflow.com/questions/11106397/listview-addheaderview-causes-position-to-increase-by-one
に答えがありました。
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
        Klass item = (Klass)(parent.getItemAtPosition(position));
        // Klassは任意のクラス
}
});

こちらとか2011年10月4日から上のようになっています。
先人のサンプルをよく研究することが大事だとおもいました。

[android]Android M PreviewをNexus9にインストールする

[環境]
・Nexus9
・Mac OS X 10.10.3
・adb、fastbootはAndroid SDK Managerで最新を取得済
・adb、fastbootへのPathが通っている(echo $PATHすると、sdk内のplatform-toolsへのpathが表示されるみたいな)



[手順]
最悪Nexus9が壊れるので慎重に。

1. System Imageをダウンロードしてどこかに解凍しておく
  ・http://developer.android.com/preview/download.htmlからvolantis-MPZ44Q-preview-d15ad483.tgzをダウンロードする
  ・ダウンロードがおわったら$md5 volantis-MPZ44Q-preview-d15ad483.tgzとか$open sha1 volantis-MPZ44Q-preview-d15ad483.tgzで値が一致することを確認しておく
  ・$ tar zxvf volantis-MPZ44Q-preview-d15ad483.tgz
  ・フォルダ名に日本語が入らないようにしておいたほうがよいかもしれません(関係ないかもしれません)

2. データのバックアップをとる
  私はやっていませんが、出荷状態みたいにまっさらになるので必要な場合はバックアップをとる

3. Nexus9をfastboot modeにする
 ・設定->タブレット情報でビルド番号を連打 すると設定に「開発者向けオプション」というのが追加される
 ・設定->開発者向けオプションで「OEMロック解除」と「USBデバッグ」をONにする
 ・MacとNexus9をUSBで接続し、ターミナルで$ adb reboot bootloader
 ・すると、見たこともない画面が表示されるのでここで怖気づかない
 ・続けて$ fastboot oem unlock

4. 1で解凍したもののなかにflash-all.shがあるのでそれをテキストエディタ等で開き、sleep 5のところをsleep 20くらいにかきかえておく
 ・インストール(書き込み)の途中で一度再起動するフェーズがあるのですが、そこの待ち時間のようでして場合によってはsleep 5のままで大丈夫なのだとおもうのですが、私のところでは何度やっても失敗をしましてここを延ばすことにしました
 ・ちなみにそのときのエラーは下記のような感じでして、usb_write failedとか言われました。まだ再起動するまえに次のフェーズを実行しようとして失敗していたのではないかとおもわれます。こんなのがでると正直壊してしまったのじゃないかとドキドキしていました。
ERROR: could not clear input pipe; result e00002ed, ignoring...
ERROR: could not clear output pipe; result e00002ed, ignoring....
ERROR: usb_write failed with status e00002ed
ERROR: usb_write failed with status e000404f
sending 'cache' (6248 KB)...
ERROR: usb_write failed with status e000404f
FAILED (command write failed (No such file or directory))

5. $ which fastboot 等でfastbootにPATHが通っていることを確認

6. $ ./flash-all.sh を実行
・この.shのなかでfastbootを使います
・10分か20分待つとこんがりいい感じ焼き上がります
・自動的に再起動します

7. 再起動すると初期設定をするように促されます。気のせいかもしれませんがWi-Fiの設定はスキップできませんでした。oem lockを再びかけたいのでスキップできるところはスキップしました。

8. oem lockをする。fastboot modeにして、$ fastboot oem lock

9. fastboot mode画面にたしかRESTARTのメニューがあるので音量キーでカーソルをあわせて電源ボタンをおしたとおもいます(すみません、詳細忘れました)

10. 再起動するので今度はGoogleアカウント設定等をする

・OTAで自動的に次のpreview releaseへアップグレードされるらしいです
・ただしfinal system image(正式リリースのこと?)は配信されないので、手動でアップグレードしてねとのことでした。

Android Mになることで個人的に気になったことです。
http://developer.android.com/preview/features/runtime-permissions.html

Permissionの取り扱い方がだいぶかわるようです。以前はインストール時に全部許可を求めるような感じでしたが、Mからは必要となったときに許可を求めるような感じにしないといけないようです。
なぜこのパーミッションが必要なのかをユーザに説明することがベストプラクティス、ユーザが拒否した場合には代替手段を提供するのがベストプラクティスらしいです。たとえばカメラ撮影のパーミッションをユーザーに拒否されたら、MediaStore.ACTION_IMAGE_CAPTUREを暗黙的IntentでstartActivityForResult()して、他の許可されているアプリに撮ってもらいなさいということらしいです。
全部のパーミッションがこういう扱いになるのではないようでして、PROTECTION_NORMALのものは従来通りインストール時に許可してもらうことになるそうです。PROTECTION_NORMALの例はalarm clockとinternetが挙げられていました。

boolean Context.checkSelfPermission(String) # 許可があるかどうか
Activity#requestPermissions(String[], int) # 許可を求めるAPI
Activity.onRequestPermissionsResult(int, String[], int[]) # 許可を求めるAPIのコールバックrequestPermissionsの第2引数とonRequestPermissionsResultの第1引数が関連している

2015年4月11日土曜日

[android]画像認識API(docomo developer support様ご提供)をvolleyを使ってリクエストする

読書日記にdocomo developer support様ご提供の画像認識APIを使って、カメラで撮った書籍画像から本の情報を取得するようにしました。
いやあ、こんなにすばらしいものを提供していただいて、本当にありがたいです。
画像認識用のSDKがありましたが、遅ればせながら最近導入したvolleyで実装することにしました。
volleyの基本的な使い方はTransmitting Network Data Using Volley等が詳しいです。

final byte[] imageBytes = ……
final String url = "https://api.apigw.smt.docomo.ne.jp/imageRecognition/v1/recognize?" +
                "APIKEY=YOUR_API_KEY" +
                "&recog=book" +
                "&numOfCandidates=1";

JsonObjectRequest jsObjRequest = new JsonObjectRequest
                (Request.Method.POST, url, null, new Response.Listener() {
                    @Override
                    public void onResponse(JSONObject jsonObject) {
                        Log.d("TAG", jsonObject.toString());
                        success(jsonObject);
                    }
                }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Log.d("TAG", error.toString());
                        failed();
                    }
                }) {

            @Override
            protected Map getParams() {
                Map params = new HashMap<>();
                params.put("Content-Type", "application/octet-stream");
                return params;
            }

            @Override
            public byte[] getBody() {
                return imageBytes;
            }

        };

// あとはjsObjRequestをcom.android.volley.RequestQueueインスタンスにadd()すると通信が始まります。

通信結果はJSONで得られるので、JsonObjectRequestを使いました。
ポイントはPOSTであることと、JsonObjectRequestのgetParamsをOverrideしてContent-Typeの設定をすることと、getBodyをOverrideしてbyte[]つまりここでは画像データを返すようにすることです。
上記はnew JsonObjectRequestしたときにOverrideしていますが、JsonObjectRequestを継承して新たにクラスを作ったほうがよいのかもしれません。
通信結果はonResponse(JSONObject)でコールバックされます。
上記のsuccess()、failed()は私が作った適当なメソッドです。
byte[] imageBytesについては下記で補足します。

その他です。
・カメラ画像の取得はImage capture intentを参考にminimal codingしました。下記のようなintentを作ってActivity#startActivityForResult()する感じです。結果はもちろん、onActivityResultで得られます。
・getOutputMediaFileUri()はここに説明があります
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name

・撮影された画像はfileUri(android.net.Uriのインスタンス)に格納されているので、
File file = new File(fileUri.getPath());
FileInputStream inputStream = new FileInputStream(file);
byte[] imageBytes = ByteStreams.toByteArray(inputStream);
とでもすれば、byte[]が得られます。
com.google.common.io.ByteStreamsをつかっています。android studioへのguavaの追加方法はDependenciesあたりでしょうか。

2015年4月10日金曜日

[Ruby][Java]reduce(inject)を使ってみる

#ruby 2.0.0p643 (2015-02-25 revision 49749) [x86_64-darwin13.4.0]
1から100までの足し算は、テンポラリーの変数を使ってこんなふうにかける。
sum = 0
(1..100).each {|n| sum += n}
puts "sum = #{sum}"

Enumerable#reduceを使うと、こんなふうにかける。
sum = (1..100).reduce(0) {|memo, n| memo + n}
puts "sum = #{sum}"

1回目のループでは、memoにはreduce(0)で指定した0が入る。nには1が入っている。
memo + nの結果は次のループではmemoに格納される。
つまり2回目のループではmemo=1, n=2で、3回目にはmemo=3, n=3、4回目にはmemo=6, n=4…… といった具合。
reduceのかわりにinjectでもよい。

単純な足し算だけじゃつまらないので、下記のようなUserというクラスがあったとして、
class User
  attr_accessor :name, :age
  def initialize(options={})
    @name = options[:name]
    @age = options[:age]
  end
end

Userインスタンスの配列の中から21歳以上のUserのnameだけを取り出したい場合には下記のようにすればよい。

users = [User.new(name: 'john', age: 20), User.new(name: 'hanako', age: 21),User.new(name: 'taro', age: 22)]
names = users.reduce([]) {|memo, u| u.age >= 21 ? memo << u.name : memo}
p names
# => ["hanako", "taro"]


JavaではJava8でinjectが使える。
 class User {

  private final String name;
  private final int age;

  private User(final String nameArg, final int ageArg) {
    name = nameArg;
    age = ageArg;
  }

  static User newInstance(String name, int age) {
    return new User(name, age);
  }

  String getName() {
    return name;
  }

  int getAge() {
    return age;
  }
}

List list = new ArrayList<>();
list.add(User.newInstance("john", 20));
list.add(User.newInstance("hanako", 21));
list.add(User.newInstance("taro", 22));
List result = list.stream().reduce(new ArrayList(),
            new BiFunction, User, List>() {
              @Override
              public List apply(List t, User u) {
                if (u.getAge() >= 21) {
                  t.add(u.getName());
                }
                return t;
              }
            },
            new BinaryOperator>() {
              @Override
              public List apply(List t, List u) {
                t.addAll(u);
                return t;
              }
            }
    );

長い……
クラス定義やlistを作っているところはしようがないとしても、reduceのところが長い……
ラムダ式を使うと
result = list.stream().reduce(new ArrayList(), (memo, user) -> {
      if (user.getAge() >= 21) {
        memo.add(user.getName());
      }
      return memo;
    }, (t, u) -> {
      t.addAll(u);
      return t;
    });

第3引数の存在がなぞ。
この例だと{}の中をthrow new NotImplementedException();と書いても動作する。
要素数が多くなったりすると活躍するのかなあ?

けれど、結局
result = new ArrayList<>();
for (User u : list) {
  if (u.getAge() >= 21) {
    result.add(u.getName());
  }
}
のほうがわかりやすい?

2015年4月1日水曜日

[android][Ruby]strings.xmlを一覧化する

すでにこことかここにありますが、Rubyの練習でnokogiriを使わずに書いてみました。

2015年3月28日土曜日

[mruby]Hello, mrubyはじめました


あまり内容はありませんが、メモです。
  • PC
    • ubuntu 14.04 LTS 64bit
  • 必要なもの
    • Cコンパイラ(gcc推奨)
    • Bison
    • Ruby
    • git
    • mrubyソースコード
  • Cコンパイラ(gcc推奨)
    • 入っていました。私のPCの場合、端末(ターミナル)で> gc <tab>とかやるとgccがでてきました。
  • Bison
    • これまた入っていました。> sudo apt-get install bison でインストールできるらしいです。
  • Ruby
  • git
  • mrubyソースコードとビルド
    • > cd
    • > git clone https://github.com/mruby/mruby.git
    • > cd mruby
    • > make #bin/mrbc、bin/mruby、bin/mirbとかが作られます。
    • ここは任意ですがシンボリックリンクを作成しておくと便利です。
    • > cd /usr/local/bin
    • > sudo ln -s ~/mruby/bin/mruby mruby
    • > sudo ln -s ~/mruby/bin/mrbc mrbc
    • > sudo ln -s ~/mruby/bin/mirb mirb
    • > cd
    • > mruby --version
  • puts "Hello, mruby"とでもかいたhello_mruby.rbファイルを作ります。
  • > mruby hello_mruby.rb # できました!
  • Macでもだいたい同じような感じでいけるはずです。