2013年4月15日月曜日

Google App Engineの検索APIをPythonから利用するサンプルを書きました

Google App EngineでPythonを使って検索API(Full Text Search, FTS)を使用するサンプルを書きました。
https://github.com/narusemotoki/gae-search-sample

ここで実際に動作しているものを試すことができます。
http://gae-search-sample.appspot.com/

WikiPediaのPython, Java, Goの書き出し部分に対して検索を行い、検索ワードがヒットした言語名を返します。
AppEngineの検索APIは、おそらく形態素解析を行なっています。
そのため、「ヘビ」で検索してもPythonがヒットしません。「ニシキヘビ」ならヒットします。

また、開発サーバでの実行結果と、AppEngineでの実行結果は異なります。
AppEngineにデプロイしてからでないと、まともに検索できません。
サンプルを作ってみた段階でのことなので、SDKの更新により改善されている可能性もあります。

2013年3月15日金曜日

スマートフォンなどでJavaScriptのクリックイベントが遅れるのを解消する(AngularJS)

nd-click="hoge($event)"としても、hogeの中で$eventを取得できません。

AngularJS1.1系にngMobileがあります。これが有効になるとスマートフォンでのクリックの遅延がなくなり、スワイプの利用も可能になります。
次期リリース版(1.2系)に含まれると思います。1.0系にバックポートするか1.1系を使うか、1.2系を待つのが良いと思います。
https://github.com/angular/angular.js/tree/master/src/ngMobile


スマートフォンやタブレットではJavaScriptのクリックイベントが少し遅れてくるようになっています。
普段なら自分でtouchstartイベントなどを拾って解決するところだと思いますが、AngularJSはng-clickというAngularJSの機能を使うので、その方法がそのままでは使えなさそうです。AngularJSライク?に解決したのでブログに残します。

タッチイベントが来たらクリックイベントを起こしています。
Gistにも書きました。

CoffeeScriptです。
app = angular.module('AngularStudy', []).directive 'ndClick', => ($scope, $element, $attrs) =>
  isTap = isTapped = false
  $element.bind 'click', => $scope.$apply $attrs['ndClick'] unless isTapped
  $element.bind 'touchstart', => isTap = true
  $element.bind 'touchmove', => isTap = false
  $element.bind 'touchend', => if isTap
    isTapped = true
    $scope.$apply $attrs['ndClick'], $element

一応CoffeeScriptをコンパイルしたJavaScriptも書いておきます。
var app,
  _this = this;

app = angular.module('AngularStudy', []).directive('ndClick', function() {
  return function($scope, $element, $attrs) {
    var isTap, isTapped;
    isTap = isTapped = false;
    $element.bind('click', function() {
      if (!isTapped) {
        return $scope.$apply($attrs['ndClick']);
      }
    });
    $element.bind('touchstart', function() {
      return isTap = true;
    });
    $element.bind('touchmove', function() {
      return isTap = false;
    });
    return $element.bind('touchend', function() {
      if (isTap) {
        isTapped = true;
        return $scope.$apply($attrs['ndClick'], $element);
      }
    });
  };
});

使い方は今までng-clickを書いていたところをnd-clickにするだけです。
<button nd-click="hoge()">ボタン</button>

パソコンとスマートフォンの差を吸収しているので、パソコンでもスマートフォンでもnd-clickだけでカバーできます。

nd-clickはnon delay clickです。

2013年3月9日土曜日

Gistを検索するスクリプトを書きました

GitHubでは、特定のユーザのGistを検索することができないようなので、それを行うスクリプトを書きました。
ソースコードはGistにあります。

仕組みとしては、指定したユーザのGistをすべて取得し、descriptionの中にキーワードがあるか調べて、あればそれを出力しています。
そのため、APIを大量に消費する上、動作も非常に時間がかかる大変残念な状態です。

2013年3月6日水曜日

AndroidとOpenJDKのRandom.javaの実装を比較しました

JavaのRandomに同じseedを渡せば、どんな環境でも同じ値が得られるのか?という疑問から、AndroidとOpenJDKの実装を比較することにしました。

java.utilのRandom.javaです。
乱数を得るメソッドはいくつもありますが、これらは最終的にnext(int)を呼びます。
なので、このnext(int)について比較します。

これがAndroid4.2のnext(int)です。
private static final long multiplier = 0x5deece66dL;
 
protected synchronized int next(int bits) {
    seed = (seed * multiplier + 0xbL) & ((1L << 48) - 1);
    return (int) (seed >>> (48 - bits));
}

これがOpenJDK6のnext(int)です。
private final static long multiplier = 0x5DEECE66DL;
private final static long addend = 0xBL;
private final static long mask = (1L << 48) - 1;
 
protected int next(int bits) {
    long oldseed, nextseed;
    AtomicLong seed = this.seed;
    do {
        oldseed = seed.get();
        nextseed = (oldseed * multiplier + addend) & mask;
    } while (!seed.compareAndSet(oldseed, nextseed));
    return (int)(nextseed >>> (48 - bits));
}

肝となる処理はどちらも同じですが、OpenJDKの方が一部の値を定数として保持している分綺麗だと思います。
違いはOpenJDKがAtmicLong#compareAndSet(long, long)でdo whileを回していることです。
AtmicLong#compareAndSet(long, long)はこちらの情報によると「この変数をこの新しい値に更新すること。ただし、このメソッドが最後に参照した後で他のスレッドによって値が変更された場合は、更新処理を失敗すること」とあります。
つまり、複数のスレッドから操作した場合にAndroidとOpenJDKで別の結果を得ることになるかもしれません。

2013年2月16日土曜日

Django1.4をAppEngineで使うための空プロジェクトを作りました

Django 1.4を使用したアプリケーションをすぐにGoogle App Engine向けに開発開始できるように、空プロジェクトをGitHubに置きました。
AppEngine Django Blank


ライセンスはMITライセンスです。Google App Engineなど、サーバ側で利用する分にはライセンス表記の必要もありません。
自由に使ってください。

app.yamlの application: appengine-django-blank この「appengine-django-blank」をGoogle App Engineに登録したアプリケーション名に変更するだけで、デプロイすればGoogle App Engineで動作するようになります。

ローカルで動かす場合は、app.yamlのあるディレクトリで
$ dev_appserver.py .
を実行してください。dev_appserverはGoogle App EngineのSDKに含まれています。
http://localhost:8888/{message}にアクセスすると、Hello Worldと共にmessageが表示されます。
messageの部分は任意の文字列に変更してください。

2012年12月23日日曜日

PythonでTwitter API 1.1を使用する

PythonでTwitterのAPIを利用するとき、これまではtweepyを使っていました。
しかしtweepyはまだTwitter API 1.1に対応していないようなので、今回はすでに対応しているtwythonを使用します。
今回のOSはCentOS 6.3です。

2012年12月17日月曜日

OrmLiteを使う時のProgurdの設定

AndroidでSQLiteを使うときはだいたいOrmLiteを使っています.
ProguardとOrmLiteを併用すると,OrmLiteから使用するメソッドをProguardが消してしまったりリネームしてしまったりするので,proguard-project.txtで適切に設定する必要があります.
-keepattributes *Annotation*
-keep class com.j256.**
-keepclassmembers class com.j256.** { *; }
-keep enum com.j256.**
-keepclassmembers enum com.j256.** { *; }
-keep interface com.j256.**
-keepclassmembers interface com.j256.** { *; }
-keep public class パッケージ.model.** {
public <init>();
}
-keep public class * extends com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper {
public <init>(android.content.Context);
}
僕はこのように書いています.

project.propertiesにproguard.config=${sdk.dir}/tools/proguard/proguard-android-optimize.txt:proguard-project.txtを書くのを忘れずに.