モバイルルータ covia CMR-310
昨年あたりから、月々980円で使える、Willcomに注目していたんだけど、モバイルルータ系のサポートが、どこでもWifiくらいしかないんで、EMobileに行くしかないかなという結論に。で、NetWalkerとの抱き合わせが、当初4000円だったんで、まぁ、これなら、その後1円に下がっても悔しくはないかと、秋葉に行ったら、まだ本発売前だってのに、ソフマップで1円になっていて、ラッキーっていうか、やっぱり売れてないんですかね。確かに、かなりマニアックな方に振ったマシンだし。
で、モバイルルータとしては、CMR-310を購入。最後まで、CMR-250と迷ったんだけど、USBメモリを使ってNASにできるという点が気にいって、CMR-310の方に。でも、やっぱりちょっと重いかもね。CMR-250に、NAS機能が付いていたらなぁ。
で、外部電源には、SANYO KBC-L2Sを購入。このサイズで、5000mAhだもんな。すごい時代になったもんだ(これ、エネループって名前だけど、中身はリチウムイオン電池)。CMR-310には、EMobileの、D22HWと、超小型USBメモリ 8GBを差して、かばんに忍ばせて、ライフライン(?)を確保。電源onから、リンク確立までの時間にバラツキがあって、なんか何度も失敗してから、ようやくつながることも。速い時は1分もしないでつながる。
これでNetWalkerや、PC系は、そのまま無線LANで使える。HT-03Aも、APNdroidで、3G回線offにして無線LANだけで使ってる。ドコモさんごめんね。テザリングの料金下げてくれたら、また乗り替えてもいいよ。
猫さいふを、NetWalkerに移植。
ダウンロードはこちら
といっても、もともとawtで書いてあったから、ほぼ、そのままで動くんだけどね。フォントサイズを変更できるようにしたり、debパッケージを作ったりという作業のみ。最初は、Java Web Startを使ってみたんだけど、OpenJDKに付いている、netxというJava Web Startは、update要素で、backgroundが付けられないんで、起動に13秒くらいかかるようになってしまって、断念。全モジュールを、debパッケージに入れました。なんとか起動は7秒くらいで可能に。個人的にはギリギリ許容かな(Java自体の起動時間がほとんどなんで、チューニングの余地はほとんどない)。
バージョン2で、ソースを、Java 6準拠に書き替え。Zaurus用のバージョン1は、今後はメンテナンスのみで機能は凍結しました。さすがにJDK 1.1 + ライブラリサブセットで書くのは疲れるんで。
Android用も動いているんだけど、まだちょっと安定してないので、様子見。GAE上で動くようにもしたかったり。i18n化や、金額に小数点を指定できるようにたりとかもしたいので。
ソースとか見たい方は、Hudsonから、ワークスペースごとどうぞ。
車買い替え
11年乗ったファミリアSワゴンも、ようやく買い替え。今度はインプレッサにした。毎度10年くらいの周期で買い替えているのだけど、その度に技術の進歩に驚かされる。
ようやくナビも付いた。Bluetoothでケータイとペアリングしておくと、ケータイのミュージックプレーヤの音楽を鳴らしたり、ハンズフリーで、通話できたりするのですな。で、電話帳もBluetoothでナビに送れる(でも1件ずつしか送れなくて閉口。まぁ、これはケータイ側の問題か)。ただ、パナのナビだったんで、せっかくのSDカードは、SD-Audio縛りで宝の持ち腐れ。ただ、CD-Rにmp3入れたのは、ちゃんと再生できている。iPodもつなげられるらしく、助手席にUSBケーブルが来ている。なんか、このへんのちぐはぐさ、間抜けさ加減は、なんとかならんのかね。SDカードだけ、ギチギチな著作権保護をかけることに、なんの意味があるんだ? 一応SD JukeBoxは持ってるけど、Windowsでしか動かないし、やたらと遅いので、昔、ケータイに音楽を転送するのに、一度使ったきりで消してしまった。もうインストールする気にならない。
なんかキーは持ってるだけでよくて、エンジンかけるのも、押しボタンになってたり。う〜ん、別にボタンじゃなくてもいいけどなぁ、と思ったけど、イモビライザを兼ねているわけか。車内は静かで車体の安定感も良くて、なかなか良い感じ。
で、ETCカードは降りる時、抜かないと怒られる。確かに盗難に合うと、使われ放題だろうし。でも無料化の話もあるしね。せっかく付けたけど、使わなくて済むなら、それにこしたことはない。
なんか混雑しているところは、有料のままにしようとかいう話もあるようだけど、反対じゃないのかなぁ。もともと償還の考えなんだから、混雑しているところは、料金もすぐに集まるんだから、さっさと償還して無償化する。そして更にバイパスなり拡幅工事なりやって、また償還で返していけばいいんだよ。むしろ利用頻度が低いところは、償還期間を延長して、料金を取り続ければ良い。そうしないで、交通量の多いところの収益を、そうじゃないところに横流しなんてことをするから、どうみても採算のとれないような工事が、平気で行われて、変な利権の温床になっちまったわけだし。
NetWalkerのOpenJDKで漢字が文字化け
例によって、GUIアプリで、漢字が文字化けするなと思ったら、良く見ると、ものすごく幅の狭いフォントになっているだけで、中身は正常だった。
で、調べてみると、fontconfig.propertiesに日本語のサーチシーケンスが無くて、fallbackに落ちて、中国語用のフォントが表示されているのが原因のようだ。
/usr/lib/jvm/java-6-openjdk/jre/lib/fontconfig.properties のバックアップを取ってから、以下の行を、sequence.fallback=の前あたりに挿入してやって、解決。
sequence.allfonts.UTF-8.ja.JP=japanese-vlgothic,japanese-kochi,japanese-sazanami
NetWalkerに、Emacs23
Debianのarmel用パッケージを入れたら、動いた。
ここにあるemacs23-gtkを起点に、依存パッケージを入れていけば良い。まぁ、そのうちUbuntuのリポジトリにも落ちてくるだろうが。
NetWalker買った。
なんか、最初は、open-jdkも入らなくて困っていたら、どうやら、レポジトリの設定が間違っているようだ。
「休日奮闘記」にあった情報に従って設定し直したら、ちゃんとインストールされた。
1000件のデータを、1000回qsortするというテストを作って速度を計ってみた。
CoreDuo 3GHz: 90ms
NetWalker: 6900ms
うは、遅いっすなぁ。予想では、10-20倍くらいかと思ったんだけど。javaの起動オプション見たら、-cacaoという見たことのないオプションがあって、それを付けてみたところ、530msほどになった。おぉ、これなら、随分と速いね。
なんか、通信すると、あっという間に電池が無くなる感じ。2時間くらいじゃないかな、これだと。10時間持つとか、どんな使い方なんだ? まぁ、リナザウもバリバリ通信すると、30分ほどだったら、それに比べるとまともにはなったけど。しかしこのクラスのPDAで、フルのJavaSEが動く時代になったのだなぁ。
と思ったら、電池メータが「中」になってからも、結構もつようだ。
P.S. ここによると、以下の2行以外は入れてはいけないらしい。この設定で、OpenJDKが入るのかどうかは、分からないけど。
deb http://jp.archive.ubuntu.com/ports/ jaunty main restricted universe multiverse deb-src http://jp.archive.ubuntu.com/ubuntu/ jaunty main restricted universe multiverse
Androidから、Google App Engineにログインする。
ちょっと、GAEにAndroidから接続する方法を探ってみた。目的は、Googleアカウントにログインすること。まずは、GAEの登録。ケータイのIDが必要ってことらしい。HT-03Aで登録しようとしたら、docomoのIDを聞かれる。何それ? なんか自分で申請しないといけないらしい。申請したら、あとで郵送で来るってんで、待ちきれないんで、Softbankのケータイでさくっと登録。
でまぁ、巷にあふれてるサイトを見ながら、EclipseにGAEのプラグイン入れて、テストサイトを作成。GAEでは、簡単にGoogleアカウントへのログイン機能が組み込める。コードは、こんな感じ。
@SuppressWarnings("serial")
public class TestServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String thisURL = req.getRequestURI();
resp.setContentType("text/html");
UserService userService = UserServiceFactory.getUserService();
PrintWriter pw = resp.getWriter();
if (req.getUserPrincipal() == null) {
pw.println("<a href=\"" + userService.createLoginURL(thisURL) + "\">Login</a>");
}
else {
User user = userService.getCurrentUser();
pw.println("<a href=\"" + userService.createLogoutURL(thisURL) + "\">Logout</a><br/>");
pw.println("name = " + req.getUserPrincipal().getName() + "<br/>");
pw.println("isAdmin = " + userService.isUserAdmin() + "<br/>");
pw.println("domain = " + user.getAuthDomain() + "<br/>");
pw.println("email = " + user.getEmail() + "<br/>");
pw.println("nickname = " + user.getNickname() + "<br/>");
}
}
}
これをdeployして、アクセスすると、loginってリンクが表示されて、

それをクリックすると、おなじみのログイン画面となる。

ログインすると、自動的に自分のページに移動して、以下のようになる。この移動先は、コード中で、thisURLに保存しておいた場所だ。

さて、GAE側はよし。次は、Androidのアプリケーション内から、このサイトにloginしたい。色々といじった感じでは、こんな風にすれば良さそうだ。まずログイン。
DefaultHttpClient httpClient = new DefaultHttpClient();
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("Email", "xxx@gmail.com"));
nvps.add(new BasicNameValuePair("Passwd", "yyyy"));
nvps.add(new BasicNameValuePair("service", "ah"));
nvps.add(new BasicNameValuePair("source", "unoruimo"));
nvps.add(new BasicNameValuePair("accountType", "HOSTED_OR_GOOGLE"));
//Login at Google.com
HttpPost httpost = new HttpPost("https://www.google.com/accounts/ClientLogin");
httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
HttpResponse response = httpClient.execute(httpost);
Log.i(TAG, "Login Response: " + response.getStatusLine());
NameValuePairのListを作ってログイン情報を渡す。serviceには、"ah"これが、Googleのappspotのことらしい。sourceは、自分のアプリケーション名。URL http://unoruimo.appspot.com/test のappspotの前の部分。次にレスポンスの中から、auth=というのを見つける。
String authKey = null;
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = null;
while ((line = br.readLine()) != null) {
String[] s = line.split("=");
if (s.length == 2 && s[0].equalsIgnoreCase("auth")) {
authKey = s[1];
break;
}
}
}
finally {
if (br != null) try {br.close();} catch (IOException e) {
Log.e(TAG, "Cannot close stream.", e);
}
}
Log.i(TAG, "AUTH = " + authKey);
これがトークンで、以後は、このトークンを渡してやれば、サービスを使用できるようだ。http://unoruimo.appspot.com/testをGETしたければ、以下のようにする。
HttpGet httpget = new HttpGet("http://unoruimo.appspot.com/_ah/login?auth=" + authKey + "&continue=" + "/test");
response = httpClient.execute(httpget);
InputStream is = response.getEntity().getContent();
BufferedReader isr = null;
try {
isr = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = isr.readLine()) != null) {
Log.i(TAG, "RESPONSE: " + line);
}
}
finally {
if (isr != null) isr.close();
}
Log.i(TAG, "Appspot.com Login Response: " + response.getStatusLine());
/_ah/loginに対し、auth=で、トークンを、continue=でアクセスしたいリソースを指定する。これでうまくいったけど、資料によると、CAPCHAを要求されることもあるらしい。
で、このユーザとパスワードというのが微妙。Googleアカウントのユーザ、パスワードを、得体の知れないアプリケーションに入力するのは、抵抗あるよねぇ。本当はAndroid側に、認証サービスがあって、アプリケーション側からは、アプリケーション名を指定して、そのAPIを呼ぶと、そっちで認証してトークンを返して欲しいところだけど、どうも、今のところは、そういうサービスは無い模様。でも仮に、標準の認証サービスがあったとしても、それを真似した画面を悪意のあるアプリケーションが表示しているかもしれないし、どうするのがいいのかね。
クラスパスに関する誤解
クラスパスについて、誤解していたことがいくつかあったのでメモ。
jarファイル内のMANIFEST.MFに書くClass-Path指定は、java -cpで指定する場合にも効く。
自分が、なぜ効かないと思っていたのかは不明だけど、アプリケーションサーバ下とか、java -jarで実行する時にしか、効かないものだと思っていた。もちろんそんなことは無い。
--- A.java ---
public class A {
}
--- a.jar ---
-rw-r--r-- 102 5-Sep-2009 11:06:32 META-INF/MANIFEST.MF
-rw-r--r-- 228 5-Sep-2009 11:06:32 A.class
--- META-INF/MANIFEST.MF ---
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: 11.0-b15 (Sun Microsystems Inc.)
--- B.java ---
public class B extends A {
public static void main(String[] args) {
}
}
--- b.jar ---
-rw-r--r-- 102 5-Sep-2009 11:13:56 META-INF/MANIFEST.MF
-rw-r--r-- 331 5-Sep-2009 11:13:46 B.class
--- META-INF/MANIFEST.MF ---
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: 11.0-b15 (Sun Microsystems Inc.)
Class-Path: a.jar
a.jarと、b.jarを同じディレクトリに置いて、
java -cp b.jar B
で、何のエラーも出力されない。
jarファイル内のMANIFEST.MFに書くClass-Path指定は、芋づる式に末端まで伝搬する。
ちょっとうまい表現が見つからないけど、例を見た方が簡単だ。上記に加えて、c.jarを作る。
--- C.java ---
public class C extends B {
public static void main(String[] args) {
}
}
--- c.jar ---
-rw-r--r-- 121 5-Sep-2009 11:17:32 META-INF/MANIFEST.MF
-rw-r--r-- 331 5-Sep-2009 11:17:34 C.class
--- META-INF/MANIFEST.MF ---
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: 11.0-b15 (Sun Microsystems Inc.)
Class-Path: b.jar
Cの実行には、BとAが必要だ。だから、普通なら、
Class-Path: a.jar b.jar
だろう。でも必要ないのだ。b.jarだけで良い。なぜなら、b.jar側のMANIFEST.MFに、
Class-Path: a.jar
と書いてあるから。
java -cp c.jar Cで、実行できる。これが「芋づる式」と表現した挙動だ。依存ライブラリが幾つもあるライブラリがある場合、クラスパスだけを書いた、空のJARファイルを何個か用意して、使い分けるなんてものも、ありかもね。
Ubuntu 9.10 Alpha5
IMが、scimからibusというのに変わるということなので、ちょっと試してみた。
インストーラが途中でハングするので、alternate版を使用。でも、インストール完了後の再起動で画面まっくら。GeForce 9500とは相性悪いのかな。とりあえずディスプレイの接続を1つに減らしてみたら、あっさり立ち上がった。
ibusそのものは、まだ辞書とか入ってないのか、漢字変換ができない状態。で、前にやったJavaのアプリケーションのテスト。なんだこりゃ、全然だめ。バグも引き継がれているようだ。
ベートーベン ピアノソナタ第27番 第二楽章
ベートーベン ピアノソナタ第27番 第二楽章
Beethoven Piano Sonata No27 movement 2
流れるような旋律の、とても美しい曲。








