FoxmarksがXmarksになるらしい

以前ちょっとしたきっかけFirefox用ブラウザ間ブックマーク同期プラグインFoxmarksの日本語翻訳者になったのですが、そのFoxmarksが名前をXmarksと変えたようです。
なんでも、Google ChromeIEなどに対応するので、Foxmarksだとブランディング上よくないから、とか。
それで、今Xmarks3.0.1用の翻訳依頼が来ています。大体のリソースは変わらないですが、発表があったように「推薦エンジン」機能が付いたようです。(さっき、推奨エンジンって訳しちゃったな。。推薦のほうがいいかも。もしくは「サイトおすすめエンジン」?)

あんまりわかってなかったですが、推薦エンジンってすごいのかも。もうちょっとまとめて書いてみます。
ちなみに、FoxmarksユーザはそのままではXmarksにはならなくて、明示的にインストールする必要があるみたいです。

iKnow!がsmart.fmになりました

ちょっと前の話ですが、APIを使ってアプリを作ったりしていたiKnow!が、smart.fmという名前に変更になりました。
最初は、少し名前に違和感があったのですが、しばらくすると慣れるものですね。
アプリのしりとりゲームも、今までどおり使えるようです。(こちらの名前はまだ「iKnow! しりとり」ですが・・そのうち変更するかも)

わざわざサービス名を変更した理由は、iKnow!は語学学習のためのサイトだったけど、smart.fmは語学に限らず、いろいろな学習ができるサイトに変わったから、だそうです。実際、道路標識や星座の学習ができるようになっているようです。今までの言葉だけの選択肢だけじゃなく、絵で選べるようになったようですね。
(サイト更新当初はトラブルもあったようですが、現在は安定しているようです。)

まだあまり使えていませんが、学習できることが広がったのは面白いと思います。

iKnow!しりとりバージョンアップ v1.3

iKnow! APIをつかったしりとり遊び、「iKnow! しりとり」をバージョンアップしました。今回は、issochiさんのコメントに、「ゲームオーバーになったときにその最後の問題のヒントが出るといい」というアイデアを実装しました。
これで、ゲームオーバーになっても少しは再チャレンジする気になるのでは?と期待しています。

ぜひ、遊んでみてください!

第二回 iKnow! Developers Conferenceに参加してきました

最近のこのブログのネタである、iKnow! APIを使ったアプリ作成ですが、KICK OFFコンテストの結果発表があるということで、Developers Conferenceに参加してきました。

事前の申し込み時に、「LTに参加したい方は申し出を」とあったので、私が作ったアプリ「iKnow! しりとり」を売り込むべく、LTも参加してきました!
このコンテストでは開発者用のWikiがあるのですが、そこにはみんな作ったものをあまり載せてなかったので、どんな作品が出てくるか楽しみだったのですが、案の定面白いものがいくつもありました。

今回多かったのは、iPhoneアプリとしてiKnow!アイテムで勉強できる、というものです。たしかに、いつでも持ってるiPhoneiKnow!のアイテムを勉強できたら、便利ですよね。ちょうど、単語帳のようなイメージで使うアプリ(デザインもよくて操作性も抜群!)などが紹介されてました。

また、一番面白くて技術的にもすごいなぁと思ったのは、いそっちさんのiKnow! Handwritingというアプリです。これは、iKnow!の本家クイズアプリのUIに似せた中で、iKnow!にある日本語コースを選んで、その日本語をマウスやDS(!)を使って、入力するというものです。ただ入力するだけではなく、「Zinnia」という筆記認識エンジンを組み込んで、実際に似た候補を表示するという、よくMSIMEパッドがやっているようなことを独自でやってました。このZinniaについては、ちょっと自分でも何かやってみたい、と思いました。アプリ全体としても、DSとの連携、Zinnia、flexとJNIなど、技術的にどうなっているのかのぞきたくなりますね。

また、iKnow!開発元のセレゴジャパンのエンジニアの方たち(別の集まり(NinJava)で結構よく知った人たちばかりなのですが)の話も、iKnow!の学習とセマンティックウェブの話を絡めたものなど、高度で面白かったです。あと、APIにも新しい機能が追加されるということで、それを使えばしりとりゲームをもっと進歩させることができそうです!

さて、今日iKnow!の本家ブログを見たら、コンテストの結果が載っていました。

1位のアプリは、普通にデザインかっこよすぎですね。。これは勝てない。。

さらに、メディアにもいろいろ紹介されたようです。

あと、カンファレンス後の飲み会でお話できたご夫妻、ありがとうございました。お話できて楽しかったです。しりとりも遊んでいただいてありがとうございます!>megawattさん、drmarさん

さらに、しりとりの話をブログに載せていただいた方もいます。少ししかお話できませんでしたが、ありがとうございました!>sakaikさん

iKnow!APIキックオフコンテスト用アプリ「iKnow! しりとり」公開しました

先月末からiKnow!のプログラミングコンテスト用アプリを作っていて、先月は経過をブログにアップしていたのですが、作るほうに忙しくなってブログの更新ができませんでした。でも、アプリは1/15の締め切りまでにちゃんと完成していて、現在iKnow!サービス運営もとのCeregoのほうで審査中です。

で、その公開中のアプリです!
http://iknow.mail-s.net/

その名のとおり、iKnow!のデータベースを使って、しりとり遊びができます。しりとりのルールとしては一般的ですが、英単語を入力してその日本語の意味でしりとりをします。
たとえば、最初の単語(これは自動的に決められます)が「apple(りんご)」であれば、「ご、こ」で始まる英単語を入力します。たとえば、「gorilla(ゴリラ)」であれば、正解です。「ん」で終わる単語はだめで、3回間違うとゲームオーバーです。詳しい遊び方はこちらに書いていますので、ぜひ遊んでみてください!
ちなみに、"Last and First"とは、英語で「しりとり」の意味らしい。。

あと、1/15の締め切りぎりぎりまで、細かい改良やデバッグをしていたので、完成度としてはまだまだで、それ以降も細かい改良(たとえばゲーム中は画面が切り替わらないようにAJAXで操作できる、とか)をしていますが、審査中なのでそれも反映できていません。審査が終わったら、どんどん改良していこうと思っています。なので、ご意見、ご感想とかあればこのブログまたはプロフィールにあるメールアドレスにぜひお願いします!

現時点で、これから改良していきたいことリストです。

  • iKnow!のoauthに対応し、iKnow!ユーザと紐づけたい(oauthは、ID/passなどをAPIを利用したサイトに入力しなくてもいい、マッシュアップ時代に合った認証方法です。google:oauth)
  • ゲームのAJAX化(開発中:ほぼできてる)
  • 正解、不正解のとき音が鳴るように
  • 音声を聞くためのリンク(iKnow!のアイテムページにあるようなもの)
  • oauthに対応したら、初期の単語を現在勉強中のリストなどから引いてこれるようにする
  • タグとか何らかのカテゴリー情報が取れたら、そのカテゴリー縛りのしりとりができるようにする
  • 対戦型しりとりとか(将棋とか囲碁はネットの対戦システムがありますよね。あんな感じで・・)
  • もろもろデバッグ

iKnow gemをXMLフォーマットに対応させる

NovさんのiKnow gemgithubでフォークしてきて、JRubyで動かせるようにはしたんですが、今回iKnowのアプリコンテストで作ろうと思ってたアプリに必要な要素である"transliteration"(音訳、とかの意味)が、iKnow gemが使っているJSONフォーマットで入っていないことがわかりました。
いまさらxmlパーサをベタに書いてアプリ作るのも面倒なので、iKnow gemにXMLフォーマットが使えるようにできないか、やってみました。

調べてみると、どうもiknow gemのJSON処理の肝は lib/iknow/rest_client/base.rb にあるようです。ここを何とかすればXML対応できそうです。

  def self.handle_json_response(json_response)
    hash = JSON.parse(json_response)
    # エラー処理
    hash
  end

JSONライブラリが出力するhashという変数に入っている内容をXMLをパースして出せればOKでしょうか?
ということで、hashの中身を見てみます。

[{"responses"=>[{"type"=>"meaning", "text"=>"\343\203\255\343\203\201\343\202\247\343\202\271\343\202\277\343\203\274(\350\213\261\345\233\275\357\274\211", "language"=>"ja"}], "id"=>514298, "cue"=>{"text"=>"Rochester", "language"=>"en", "sound"=>"http://media1.iknow.co.jp/contents/halpern/en_male/E0087719.mp3", "part_of_speech"=>"Proper Noun"}},

これに対応するXMLは、

<vocabulary xsi:schemaLocation="http://api.iknow.co.jp/specifications/vocabulary/1.0 http://api.iknow.co.jp/specifications/vocabulary/1.0" version="1.0">
  <items>
    <item href="http://www.iknow.co.jp/item/514298" language="en" id="514298">
      <cue part_of_speech="Proper Noun" language="en">
        <text>Rochester</text>
        <sound>http://media1.iknow.co.jp/contents/halpern/en_male/E0087719.mp3</sound>
        <transliterations/>
      </cue>
      <responses>
        <response type="meaning" language="ja">
          <text>ロチェスター(英国)</text>
        </response>
      </responses>
    <dc:creator>kyoya</dc:creator>
  </item>

おおもとがArrayで、その中の1itemがHashになっていて、各属性やtext要素が出てきている、という感じですね。。ここからかなり試行錯誤したのですが、以下のことがわかりました。(JSON詳しくないので、かなり基本的なこと言ってるかもしれません。。)

  1. items->itemのように、複数を束ねるものはArrayとする
  2. 束ねられた単数(itemとか)の属性(attribute)は、そのHashの1要素となる
  3. 子要素がそれ以上ないものは、そのタグ名でHashの1要素となる

厳密ではないかもしれませんが、このようなルールに従ってパースしてみて、さらにかなりの回数試行錯誤してみた結果のコードはこのようになりました。パースにはrexmlを使っています。

  def handle_response(xml_response)
    doc = REXML::Document.new(xml_response)
    hash = []
    doc.root.elements.each do |e| # TODO need to fetch first significant element
      hash = extract_xml_to_hash(e)
    end
    hash
  end

  def extract_xml_to_hash(parent)
    if has_children_same_element_name? parent
      arr = []
      parent.elements.each do |c|
        arr << extract_xml_to_hash(c)
      end
      return arr
    else
      hash = {}
      hash[parent.name] = parent.text unless parent.elements.size > 0
      parent.elements.each do |c|
        hash[c.name] = c.elements.size > 0 ? extract_xml_to_hash(c) : c.text
      end
      parent.attributes.each do |name, value|
        hash[name] = value
      end
      return hash
    end
  end
   
  def has_children_same_element_name?(parent)
    parent.name.reverse.slice(0, 1) == 's' # last letter
  end

エントリのhandle_response(xml_response)メソッドでは、とりあえずトップ要素(のさらに1階層下)を再帰用メソッドに突っ込んでいます。(ここはもう少しスマートにできるはず)
再帰用メソッドextract_xml_to_hashは、まず、子要素に同じ名前の単数形(ここは横着で自分の名前の最後がsで終わっている、とかの適当実装ですが、とりあえずこれでOKのようです)があるかどうかで、あれば配列に子要素の再帰結果を突っ込むということをしています。
次に、自分が子要素を持たなければ、そのtext要素をhashに突っ込みます。(じつはこれがtransliterationの部分)
また、属性がセットしてあれば、それもhashの要素として入れます。

あとは、JSONXMLのフォーマット切り替えですが、これはconfigクラスで指定して切り替えられるようにしました。:format属性を用意して、デフォルトはJSONですが、これをxmlとするとXMLで取ってくる(つまり上記の実装を使う)ようになるので、たとえばIknow::Item.transliterationsに値が入るようになります。
ちなみに、年明けにはJSONにもこの要素は入るようになる、という話です。(iknow-devメーリングリストで)

XML対応したiKnow! gemはgithubに登録してあります。

http://github.com/fujibee/iknow/tree/master

にあるので、興味がある方は見てください。

githubでフォークしたコードをローカルに取得&githubにコミット

前回、git開発環境をUbuntu上で整え、github上でNOVさんのiKnow! gemのコードをフォークするところまでやりましたが、次にローカルでこのフォークしたソースコードをいじって遊びたいと思います。githubの自分のアカウントにコードをアップするところまでを今回の目標とします。

githubからソースコードを取得

まず、githubからローカルへの取得は以下のように簡単にできます。

$ git clone git://github.com/fujibee/iknow.git
Initialized empty Git repository in /home/fujibee/work/tmp/iknow/.git/
remote: Counting objects: 499, done.
remote: Compressing objects: 100% (443/443), done.
remote: Total 499 (delta 253), reused 111 (delta 31)
Receiving objects: 100% (499/499), 146.27 KiB | 62 KiB/s, done.
Resolving deltas: 100% (253/253), done.
$ ls -F iknow/
ChangeLog  README  Rakefile  examples/  iknow.gemspec  lib/  test/

設定とか

それで、取得したコードに対して修正を加え、コミットするわけですが、そのまえに設定に気をつける必要があるようです。

あ、私のようなgit初心者の方は、まず最初に

$ git config --global user.name "Keita Yamaguchi"
$ git config --global user.email keita.yamaguchi@gmail...

のように名前とメールアドレスを設定しておいて下さい。これを忘れるとマシン名とかがコミットログに残って恥ずかしい感じになります。

とっても優しい github の使い方 - ¬¬日常日記

私もgit初心者なので、その通りにします。

$ git config --global user.name "fujibee"
$ git config --global user.email "fujibee@gmail..."

ほかの設定値についてはここらへんが参考になります。

http://d.hatena.ne.jp/uneasy/20081225/1230212101

ローカルへコミット

gitはまだ詳しくないのでやってみた結果の動作を見てですが、まずローカルリポジトリ(ローカルコピーとは違う)にコミットして、そのあとリモートリポジトリ(githubとか)にpushして公開する、という方法のようです。

ローカルリポジトリへのコミットは、Subversionのように簡単にできます。が、事前にコミット対象を明示的に指定しておかないといけないようです。

$ git add iknow.gemspec Rakefile
$ git commit

commitコマンドの後は、viなどでコミットログを書き込みます。

githubに初めてのpushへの道のり

さらに、ローカルリポジトリからgithubへのpushには、認証としてgithubへの公開鍵の登録が必要になるようです。
この辺を参考に、進めてみます。

Connecting to GitHub with SSH - GitHub Help

まず、ローカルでssh keyを作成して、それを、githubに登録します。

$ cd ~/.ssh
-bash: cd: /home/fujibee/.ssh: No such file or directory

とりあえずないですね。上記ページにしたがって、作成します。

$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/fujibee/.ssh/id_rsa):
Created directory '/home/fujibee/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/fujibee/.ssh/id_rsa.
Your public key has been saved in /home/fujibee/.ssh/id_rsa.pub.
The key fingerprint is:
7a:51:2a:7a:dd:79:06:be:58:dd:94:0d:54:9d:38:6d fujibee@ubuntu810server
The key's randomart image is:
+--[ RSA 2048]----+
|              +.+|
|             + E.|
|          .   +  |
|         o     + |
|      . S .   o .|
|     . + + + o   |
|    . o o = + .  |
|     . . o +     |
|        . .      |
+-----------------+

できました。最後のrandomartってのは何なのかな?2次元的なfingerprintのようなものでしょうか?面白そうですが、ここでは深入りしないようにします。

$ cat ~/.ssh/id_rsa.pub

で出てくる、公開鍵をgithubに登録します。登録先は、ログイン後、アカウントページにあります。

では、さっそくgithubにpushしてみましょう。

$ git push
fatal: protocol error: expected sha/ref, got '
*********'

You can't push to git://github.com/user/repo.git
Use git@github.com:user/repo.git

*********'

ふむ、URLの表現がまずいようです。エラーメッセージに従い、git@のほうでやってみます。

$ git push git@github.com:fujibee/iknow.git
The authenticity of host 'github.com (65.74.177.129)' can't be established.
RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
Are you sure you want to continue connecting (yes/no)? yes

初回なのでキー追加OKかどうか聞かれました。

Warning: Permanently added 'github.com,65.74.177.129' (RSA) to the list of known hosts.
Enter passphrase for key '/home/fujibee/.ssh/id_rsa':

で、秘密鍵のパスワード入力です。

Counting objects: 7, done.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 395 bytes, done.
Total 4 (delta 3), reused 0 (delta 0)
To git@github.com:fujibee/iknow.git
   5157e51..eb2e66d  master -> master

無事、pushできました。

実際、githubリポジトリにも反映されています!


余談

実はコミットしたのは今日(12/28)なのですが、github上のコミット日時が12/25になっています。なぜかというと、ローカルのマシンの時計がすごく遅れていて12/25になっていたからです。。これで気づきました。VMWare上のサーバは(それもノート上でスリープとかサスペンドとかやっている場合特に)時計が狂いやすいので、気をつけましょう。。