Androidの/systemに書きこむ

Androidの/systemは、通常roでマウントされており、書きこむことができない。
が、ファイルシステムをマウントし直すことで書きこむことができるようになる。

情報元はAndroid Tricks Mount a filesystem read-write

まず/systemがどのデバイスか確認しよう。
adb shellして端末にログイン、suでrootになる。# cat /proc/mounts と入力し、/systemがどのデバイスか確認する。

/dev/hoge/fuga /system ext4 ro,relatime,data=ordered 0 0

となっている場合、/dev/hoge/fugaがデバイスだ。

次に、/systemをremountする。

 # mount -o rw,remount -t yaffs2 /dev/hoge/fuga /system 

これで/systemも書き込めるようになる。

mmmでビルドしたapkをインストールしようとするとINSTALL_FAILED_DEXOPTと怒られる問題

mmmでとあるモジュールをビルドする。次のような感じで。
mmm -j10 packages/hoge/fuga

apkとodexが作成され、apkをインストールしようとしてもINSTALL_FAILED_DEXOPTと怒られる。
apkとodexの両方を/data/appにコピーするとOKという情報もあったけど、とりあえず次のようにビルドするとOKだった。
$ cd packages/hoge/fuga
$ mm WITH_DEXPREOPT=false

mmmやmmが無いという時は、source (Androidソース)/build/envsetup.shをすればOK

Macでグローバルフック

Macで別のアプリをフォーカスしててもキー入力をフックして何か処理したいときがある。
ということでMacでグローバルフックを使う方法。

情報元はこちら。
[Mac] Event Monitor 〜 Cocoaにおけるホットキー実装に使えるか?

とっても簡単で、次のような感じ。
applicationDidFinishLaunchingで

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    [NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask
                                           handler:^(NSEvent* event) {
                                               NSLog(@"GlobalMonitor: %@", event);
                                           }];
    
    [NSEvent addLocalMonitorForEventsMatchingMask:NSKeyDownMask
                                          handler:^(NSEvent* event) {
                                              NSLog(@"LocalMonitor: %@", event);
                                              return event;
                                          }];
}

ただ、フォーカスが当たっていなくてもキー入力を取得できるGlovalMonitorは次の設定をする必要がある。
環境設定から、アクセシビリティを開き、「補助装置にアクセスできるようにする」にチェックを入れる。
ただし、これにチェックを入れるとすべてのキー入力をプログラムから取得できるようになるため、セキュリティのリスクが高まる可能性がある。

Rails3でbootstrapをカスタマイズしようとした際にvariable @baseLineHeight is undefinedって怒られちゃう問題

Rails3でbootstrapを使う場合、twitter-bootstrap-railsのGemを使うととても簡単にbootstrapを導入することができる。

で、こうやって入れたbootstrapはどこにあるかというと、ホーム以下の.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/twitter-bootstrap-rails-2.0.8とかにあったりする。
ホーム以下にあるので、lessファイルをいじくり回したいときはとても不便である。プロジェクトディレクトリ以下にコピーしたいのが人情というものだ。

で、何も考えずにlessファイルたちを、railsプロジェクトのapp/assets/stylesheets以下にコピーしちゃうと次のエラーが出る。

variable @baseLineHeight is undefined
  (in HOGE/app/assets/stylesheets/bootstrap/accordion.less)

「@baseLineHeightは定義してるのに何で!?」と思ったら、どうやらstylesheetsの下に入れておくと、依存性のあるファイルでも単体でコンパイルしようとして怒られている(予感がする)

lessファイルを入れているディレクトリを、app/assets/stylesheetsではなくapp/assets以下にコピーし、bootstrap_and_overrides.css.lessのimportを次のように親ディレクトリを見に行くようにしてあげると解決した。

@import "../bootstrap/bootstrap";
body { padding-top: 60px; }

@import "../bootstrap/responsive";

Rubyでクイックソートを実装してみる

今時の言語は標準で配列をソートする機能がライブラリなどで提供されている。
が、プログラマたるものソートするコードぐらい何も見ずに書けなければならない。

俺も今までは「バブルソート最高 ^q^」と言っていたのだけれどクイックソートぐらい書けないと、「お前はO(n^2)レベルのプログラマだ」と罵倒されてしまう。

と言う事で自分で書いてみた。

アルゴリズムはWikipediaを参照。

アルゴリズムの概要としては次のような感じ。
1. 配列の中から適当な値を一つ選択する。これをピボットと呼ぶ。でも本当に適当に選ぶと詰むから注意!選び方は後述
2. 配列の左からピボット以上の値を探索
3. 配列の右からピボット未満の値を探索
4. 2と3で選んだ数で、2で選んだ数が3の数より左にあればその二つの値を交換し、2に戻る。
5. 左右それぞれ移動していき、交差する部分で配列を分割して、2に戻る。
6. 配列を分割して要素が1個だけになればその部分は完了。

ピボットは、配列の一番左とその一つ右の要素を比べて大きい方を選択する。もし値が同じなら、さらにその一つ右を見る。配列すべてが同じ値ならば、その部分のソートは完了している。
ピボットの選択はちょっとハマった。ピボット選択時に配列がすべて同じ値だった場合、ソート処理に進むと無限ループになる。
ピボット選択アルゴリズムはこちらのページを参照。と言うかWikipediaよりこっちのページの方がわかりやすいかも。
最初に書いたコードはもうちょっと長ったらしかったんだけど、こっちのページを参考にし、より簡潔に書き直した。

と言う事で書いたコード。

#ピボット選択
def get_pivoit(array, start_index, end_index)
  i = start_index + 1
  while end_index != i && array[i-1] == array[i]
    i += 1
  end
  return -1 if array[i-1] == array[i]
  return  i if array[i-1] < array&#91;i&#93;
  return i-1
end

def quicksort(array, start_index, end_index)
  p_index = get_pivoit(array, start_index, end_index)
  return if p_index == -1
  p_value = array&#91;p_index&#93;

  left_index = start_index
  right_index = end_index
  next_p_index = nil # 分割する位置 このindexが分割した二つ目の配列の開始位置となる

  while left_index <= right_index 
    while left_index <= right_index && p_value > array[left_index]
      left_index += 1
      next_p_index = right_index if right_index < left_index
    end
    while right_index >= left_index && p_value <= array&#91;right_index&#93;
      right_index -= 1
      next_p_index = right_index + 1 if right_index < left_index
    end
    if left_index < right_index
      tmp = array&#91;left_index&#93;
      array&#91;left_index&#93;  = array&#91;right_index&#93;
      array&#91;right_index&#93; = tmp
    end
  end
  quicksort(array,start_index, next_p_index - 1) if ((next_p_index -1) - start_index) > 0
  quicksort(array,next_p_index, end_index) if (end_index - next_p_index) > 0
end

動作確認は次のコードで行った。

def check
  100000.times do |i|
    array = Array.new(100)
    100.times do |j|
      array[j] = rand(10000) - 5000
    end
    quicksort(array,0,(array.length - 1))

    old = -999999
    array.each_index do |i|
      if old > array[i]
        p array
        p "error!"
        exit
      end
      old = array[i]
    end
    puts "ok"
  end
end

check()

なお、このコードはあくまでも学習用のため、課題や業務のためにコピペしちゃダメよ。

HTML5のMedia Capture APIを使う

HTML5には、Media Capture APIと言うものがあり、HTMLからカメラのキャプチャや音声の録音ができるらしい。
と言う事でちょっと試してみた。

現状ではPC向けブラウザでは対応しておらず、Android3.0以降で対応しているとのこと。
Mac版のChrome 21では、普通のファイル選択フォームとしか動作しなかった。
Android4.1のGalaxy Nexusで動作確認をした。

とりあえずHTMLは次のような感じ。

<html>
  <body>
    カメラ<br />
    <input type="file" accept="image/*" capture="camera" id="capture"><br />
    <br />
    マイク<br />
    <input type="file" accept="audio/*" capture="camera" id="capture2"><br />
  </body>
</html>

Android4.1で表示させると次のようになる。

カメラのボタンを選択すると、カメラが起動し、写真を撮影してからOKを示すチェックボタンを押すとファイルが設定され、HTMLから写真が撮影されたことがわかる。
撮影したファイルをJavaScriptからアクセスしたり加工したり表示したりするのは未調査。
ネットを見る限りJavaScriptから扱える様子。

マイクのほうは、選択するとどのアプリで録音または録音された音声ファイルをアップロードするかを選択するウインドウが表示され、録音する。
録音時は録音アプリが起動するので、FlashのようにHTMLの画面内で録音する事はできなさそうだ。

Windowsで使っていたATOKプレミアムの電子辞典をMac版のATOKでも使う

Windowsでは、ATOKプレミアムを使っており、明鏡国語辞典・ジーニアス英和/和英辞典が付属していた。
Macではベーシック版を購入したので、電子辞典は付属していないが、プレミアムの電子辞典ファイルをインポートすることができる。

方法は公式サイトのFAQにある。

一行で言うと、ATOKの環境設定を開き、電子辞典検索画面で電子辞書ファイル(DRTファイル)をドラッグアンドドロップする。

GENIUSJE.DRTとMEIKYOJJ.DRTを日本語辞典へ、GENIUSEJ.DRTを英語辞典にD&DすればOK!

Rails3でNoMethodError: undefined method ‘accept’ for nil:NilClassが発生するとき

Rails3でmysqlを使うと、文字コードの問題が出た。DBから取得した文字列がASCII-8BITになってしまうという問題だ。
解決するには、Gemfileにgem “mysql2″とし、database.ymlの接続設定にadapter: mysql2を追加すればOKとのこと。

が、それをすると今度はモデルの検索時にNoMethodError: undefined method ‘accept’ for nil:NilClassが発生してしまう。

解決策は次のページにあった。
Rails 3: Model.all => NoMethodError: undefined method ‘accept’ for nil:NilClass

まずデータベースを破棄して・・・

$ rake db:drop RAILS_ENV=production

データベースを作成し直せばOK!

$ rake db:setup RAILS_ENV=production

また、mysql2のgemをインストールしようとすると、*** extconf.rb failed ***のエラーが出る場合がある。
Ubuntuの場合はlibmysql-ruby libmysqlclient-devをインストールすればOK

sudo apt-get install libmysql-ruby libmysqlclient-dev

Rails3で同一モデルに対する多対多参照を作る

Rails3で、モデルの多対多参照を実現するにはhas_manyの:throughオプションで簡単に実現することができる。
が、同一モデルで多対多をやろうとすると、ちょっと工夫が必要だ。同じモデルへの外部参照キーが二つできるので、それぞれ別名をつけてやる必要があるからだ。
参考にしたのは次のページ。
Rails self-referential has_many through with custom naming of join table

ここでは、ユーザが他のユーザと友達登録することを想定する。UserモデルがFriendモデルを通して多対多の関連を持つ。
ポイントはFriendクラスへのhas_many参照を作り、そのmas_many参照をthroughしてその先のUserクラスのインスタンスを取得する部分かな?
has_manyのsourceがfromとtoが逆なのは、その関連の先のユーザを取りたいからだ。
fromで検索した関連で、その相手であるto_userを参照すると。

ユーザクラス

class User < ActiveRecord::Base
  attr_accessible 略

  has_many :from_friend_relations, :foreign_key => "from_user_id", :class_name => "Friend"
  has_many :to_friend_relations, :foreign_key => "to_user_id", :class_name => "Friend"

  has_many :from_friends, :through => :from_friend_relations, :source => :to_user
  has_many :to_friends, :through => :to_friend_relations, :source => :from_user
end

関連用クラス to_user_idとfrom_user_idを持つ。

class Friend < ActiveRecord::Base
  attr_accessible :from_user_id, :to_user_id

  belongs_to :from_user, :class_name => "User"
  belongs_to :to_user, :class_name => "User"
end

友達登録に方向は関係ないので、user.friendsの一発で取れれば良いんだけど、fromとtoで別々になっちゃう。
一発で取りたい場合はSQL書かないとダメぽ。

Mac(Lion)でgem install mysqlしても素直に入ってくれない時

素直に入ってくれないと悲しいよね。
ググって解決策見つけてもうまくいかないことも多いし。

と言う事で私の環境では次のコマンドで入りました。
mysqlはhomebrewで5.5.20を入れたので、libやincludeのパスは各環境のに合わせること。

上の例はhomebrewでmysql入れているので、mysqlをまだインスコして無い場合はbrew install mysqlしてね。