2012年11月30日金曜日

iPhone5の地図

噂には聞いていたが、iPhone5はかなりおかしい。Siriに「東京の地図」というと地図が開くが歌舞伎町に連れて行かれる・・・

2012年10月22日月曜日

AQUOS PHONE SH-13Cカメラが変な感じ

先日サンフランシスコ周辺へ行ったとき、docomoのAQUOS PHONE SH-13C を持っていき標準のカメラアプリで写真を撮った。最近、久しぶりに写真の整理をしてiPadに転送したのだが、おかしなことにiPadの撮影地の世界地図で見るとその写真が中国の山東半島の付近や沖合に表示されてしまう。
 
iOSは最近地図がおかしいと話題になっているだけに、ここまでおかしくなったのかと最初は疑ってしまったが、おかしいのは写真のほうでExif情報に入っている座標が正しく無いようであった。
 
日本でとったものは正しい場所に出ているため、どうしてこれらの写真だけおかしいのか不思議であったが、アメリカ西海岸と中国の座標を比べてあることに気付く。たとえばサンフランシスコのユニオンスクエアの緯度・経度は37.78792,-122.407438である。西経なので経度は一般に負の値にする。
 
ここで、経度の符号を入れ替えて37.78792,122.407438にすると、山東半島付近を指すことがわかる。
 
 
どうも、SH-13Cの標準カメラが東経西経を正しく扱えていないような気がしてしまう。北米方面に行く機会があればもう一度検証できるが、その機会もなかなかないので真実は謎。
 

2012年2月8日水曜日

Java Class.isAssignableFromメソッド

Javaクラスの継承関係を調べるClass.isAssignableFromメソッドの使い方をいつも忘れるのでメモ

ClassA,ClassBがあって、ClassBがClassAを継承している(ClassB extends ClassA)のときは以下のようになる。

class ClassB extends ClassA { ... }

ClassA.class.isAssignableFrom(ClassB.class) = true
ClassB.class.isAssignableFrom(ClassA.class) = false


instanceofとよく似ているが、instanceofはあるインスタンスがあるクラスを継承したものかを調べるのに対して、isAssignableFromメソッドはクラス同士で継承関係を調べるときに使う。

以下コードの(2)のように書くとinstanceofと同等の使い方となる。
まあinstanceofの場合はbがnullだった場合もnullチェックせずに使えるので便利だろう。

ClassB b = new ClassB();

// (1) これはtrueになる
if (b instanceof ClassA) { ... }

// (2) これもtrueになる
if (ClassA.class.isAssignableFrom(b.getClass())) { ... }


普通のプログラムだとisAssignableFromメソッドはあまり使わないが、クラスのメタ情報を使って動くようなプログラムを書くときは個人的にはよく使います。

2012年1月24日火曜日

SiriProxy

Siriをハックして独自機能が追加できるSiriProxyというのを人に教えてもらった。

どういう仕組みなのか興味がわいたのであちこちのサイトから断片的な情報を集めてきてまとめると、どうやらSiriクライアントからの音声入力文字列をAppleのSiriサーバーに渡さずに横取りするためのサーバーのようである。以下はその想像図である。(図はクリックで拡大します)


プラグインをいろいろつけることで自分だけの独自機能をSiriクライアントを通じてキックすることができるようだ。プラグインはRubyで書くようである。
わかりやすいサンプルとしてはiTuneを制御するためのプラグインのソースが公開されていた。中を見てみると音声認識されて受け取った文字列を正規表現でマッチしてそれに応じた応答を生成しているようですな。本物のSiriも似たようなことをやっているのだろう。

このプラグインの先にAnswers Anywhereをくっつけても面白いかなと思った。Appleから早く公開SDKが出るといいのに…

2012年1月20日金曜日

SQL Anywhere CSVファイルをテーブルにロードする

CSVファイルからデータベースにデータをインポートするというのは管理者にとっては必ず経験する作業だと思う。SQL AnywhereでLOAD TABLE文を使ってCSVファイルをロードするための方法をいくつか書いてみたいと思う。

基本のやりかた


CSVファイルとテーブルの列数が一致する場合の一番基本のやり方。

次のようなテーブルがあって、

CREATE TABLE employee (
emp_id integer NOT NULL,
emp_name varchar(20) NOT NULL,
emp_comment long varchar,
PRIMARY KEY (emp_id)
)


次のようなCSVファイルempdata.csvがあるとする。
ファイルの文字コードはエクセルから出力した場合と同じMS932であるとする。
"1","山田","がんばります"
"2","田中","はじめまして"
"3","池田","まあまあです"


この場合、テーブルとCSVファイルの列の数が一致しているので以下のようなSQL文でロードができる。

LOAD TABLE "employee" ("emp_id","emp_name","emp_comment")
FROM 'C:\Temp\empdata.csv'
FORMAT 'TEXT'
QUOTES ON
ORDER OFF
ESCAPES ON
CHECK CONSTRAINTS OFF
COMPUTES OFF
STRIP OFF DELIMITED BY ','
ENCODING 'Windows-31J'


FROMにはCSVファイル名を絶対パスで指定する。コマンドラインからdbisqlで実行するのであればカレントディレクトリからの相対パスで指定することもできる。
列の順番はLOAD TABLE文の列名を入れ替えることで好きな順序にできる。

デフォルト値をつける


データの各行にユニークIDを自動採番したいような場合や各行の作成時間を付与したい場合は、列にDEFAULT句を設定しておくとデータに含まれていなくても自動で値が割り振られる。

たとえば自動採番したIDをemp_idに入れ、作成時間をcreatedに入れるため次のようなテーブルを定義する。

CREATE TABLE employee (
emp_id integer NOT NULL DEFAULT autoincrement UNIQUE,
emp_name varchar(20) NOT NULL,
emp_comment long varchar,
created datetime NOT NULL DEFAULT current timestamp,
PRIMARY KEY (emp_id)
)


データにはemp_nameemp_commentのみが入っているとする。
"山田","がんばります"
"田中","はじめまして"
"池田","まあまあです"


この場合は以下のようなSQL文でロードができる。

LOAD TABLE "employee" ("emp_name","emp_comment")
FROM 'C:\Temp\empdata.csv'
FORMAT 'TEXT'
QUOTES ON
ORDER OFF
ESCAPES ON
CHECK CONSTRAINTS OFF
COMPUTES OFF
STRIP OFF DELIMITED BY ','
ENCODING 'Windows-31J'
DEFAULTS ON


DEFAULTS ONをつけるところがポイント。これをつけないとDEFAULT句を持つ列にも値を明示的に入れないといけない。

2012年1月16日月曜日

Microsoft Translator APIで翻訳

(注)2012初旬~ 登録方法やAPI利用方法が変わっています。

⇒新しい方法はこちらの改訂版をご覧ください

指摘してくださった匿名さん、どうもありがとうございます。



Webサービスで翻訳ができるAPIは無いだろうかと探したところ、Google翻訳とBing翻訳がそれぞれAPIを提供しているとのこと。

Google翻訳のほうはGoogle Translate APIというらしい。しかし去年で無償サービスは終了し今は有償しかないとのこと。なんということだ。

Bing翻訳のほうはMictosoft Translator APIというサービスで個人で試すレベルであれば無償のようだ。

値段は翻訳するテキストの量に応じ月あたり以下のような感じである。(記事執筆時点)
無償で試せるのは月あたり2000txまで。1tx=1000 charactersと書いてあるので1txは1000文字換算のようです。


  • ¥12,559/month (16000 tx/month)
  • ¥6,280/month (8000 tx/month)
  • ¥4,710/month (6000 tx/month)
  • ¥3,140/month (4000 tx/month)
  • ¥0 (2000 tx/month)


これの登録方法がよくわからずいろいろ調べてやっとできたので以下にメモ。
ただし、執筆時点の情報なので後日またやり方が変わっているかもしれないので注意してください。

このAPIはWindows Azure Marketplaceというところで登録するようです。ここではWindows Live IDが必要なので持っていない人はあらかじめ作っておくとよいでしょう。→Windows Live ID新規登録

Mictosoft Translator APIのページから「Microsoft Translator API にサインアップしましょう」のリンクをクリックすると(または直接Windows Azure MarketplaceのMicrosoft Translatorの登録ページに行きます。

右のほうに値段の書いたメニューがあるので Subscription*(2000 tx/month) \0.00 を選んで PURCHASE(またはSIGNUP)ボタンを押します。手順によって出てくるページ順が若干異なると思いますが、Registrationというページで名前やメールアドレスを入れるよう要求されるので入力して画面の指示通りすすめます。その後もagreeにチェックボックスを入れてボタンを押すページがいくつか続き、最終的にThank Youと表示されるページまでくればAPIへのサインアップ完了です。

ただし、この時点ではAPIはまだ利用できません。APIを利用するにはAppIDというのが必要になります。

どうやってAppIDを取得するのかが非常にわかりにくかったのですが、Bing開発者のアプリケーション登録ページに行って新しいアプリを作成することでIDが発行されます。

Windows Live IDでサインアップした状態でこの登録ページに行きADDボタンを押してアプリケーションを登録します。必須情報が多く迷いますが以下のような感じでよいのではないでしょうか。


Application name
適当 (testなど)
Description
適当 (my test appなど)
Company name
適当 (test corpなど)
Country/region
Japan
Email Address
Windows Live IDと同じメールアドレス


登録すると、アプリが一覧に表示されApplication IDが画面に表示されます。このIDをコピーしてAppIDとして使います。

APIの使い方ですが以下のようなURLを投げるとXMLが返ってくるREST APIになっています。

http://api.microsofttranslator.com/V2/Http.svc/Translate?appid={AppID}&from={翻訳元言語}&to={翻訳先言語}&text={翻訳するテキスト}


翻訳元/翻訳先言語はjaenなどの言語コード。テキストには翻訳したい文字列を設定します。日本語などの場合はUTF-8でエンコードします。結果はXMLで戻ってくるので翻訳済みテキストはタグの中から切り出す必要があります。

ためしに日本語の「こんにちは」を英語にしてみると…

http://api.microsofttranslator.com/V2/Http.svc/Translate?appid={AppID}&from=ja&to=en&text=こんにちは


翻訳されました!

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Good afternoon</string>


結果は "good afternoon"

"hello" じゃないのか…

2012年1月11日水曜日

Java JDBCのエラー ローにありません

SQL Anywhere 12 にJavaからiAnywhere JDBC ドライバ(ianywhere.ml.jdbcodbc.jdbc3.IDriver)で接続しSELECT文を実行、結果を読むところで「ローにありません」というエラーが出た。


Caused by: java.sql.SQLException: ローにありません。
at ianywhere.ml.jdbcodbc.jdbc3.IIResultSet.getInt(Native Method)
at ianywhere.ml.jdbcodbc.jdbc3.IResultSet.getInt(IResultSet.java:464)
... 2 more


まったく意味がわからないメッセージなので、どうしたものかと思い該当部分のコードを見る。


ResultSet rs = statement.executeQuery();
int n = rs.getInt(1); // ← ここでSQLException
rs.close();


結果を一行しか返さないSQL文だったのですっかり油断していた。

原因はResultSet.next()が抜けていただけでした。

正しくは…


ResultSet rs = statement.executeQuery();
int n;
if (rs.next()) {
n = rs.getInt(1);
}
rs.close();


これに気づく間、SQLを変えてみたり試行錯誤してました。
適切なエラーメッセージはとても大事です。

2012年1月10日火曜日

Palmware 「書道」を再公開してみた

昔、開発したPalmで書道を楽しむフリーのPalmware「書道」。5年ほど前の引っ越しのときから自宅サーバーを落としたままであるため長らく入手できない状態が続いていた。

Palmは過去の遺物なのでもう需要は無いだろうと放置していたのだが、どこかのアーカイブから探しあてインストールし使ってくれている人が、ごくたまであるが最近もいるようである。

そんな声にこたえておかねばと思い、URLが昔と変わってますがprcファイルのダウンロード先をくまソフトにつくりました。

同じ場所にくまと戯れるPalmware「くま」も置いておきましたので、久々にPalmの電源を入れた方は、ぜひ楽しんでいってください。
くまソフトへいく

どれもPalmOS 3.x向けなので、新しいPalmの人だとうまく動かないという声もあるようですが… そこはご勘弁ください。

(注)"Palmware"とはアプリのことです