TopCoder - SRM 144 DIV 2: 250

TopCoder勉強を開催。今回は8人が参加してくれた。と言っても俺も初心者だから、まずは登録(これが意外と面倒)からプラクティスルームにたどり着くまで。あとプラクティスでSRM 144 DIV 2:250を解いた。俺はJavaで。皆さん「おもしろい!」と言っていただいてなにより!TopCoderもっと流行って良いと思うw一番最初の問題なんだけど、秒数を数値型でインプットし、文字列型で"H:M:S"に変換してアウトプットする。うむ・・・今の問題と比較するとむちゃ簡単。。。 ソースコードビューアで見る。

public class Time {
  public String whatTime (int seconds) {
    int h = seconds/(60*60);
    int m = (seconds/60)%60;
    int s = seconds%60;
    return Integer.toString(h) 
      + ":" 
      + Integer.toString(m) 
      + ":" 
      + Integer.toString(s);
  }
}

TopCoder - SRM 423 DIV 2: 250

500のコンパイルまでいけた。しかし250で撃沈…。バグを発見されてしまいました。今回の250のソースをソースコードビューアで公開(後悔…)。うーん何が間違ってたんだろう。今回は難しかったし、間違いがわからん(笑)

public class TheSimpleGame {
  public int count(int n, int[] x, int[] y) {
    int counter = 0;
    if (n<1||n>100){
      return counter;
    }
    int i = 0;
    int j = 0;
    for (i=0;i<x.length&&i<50;i++) {
      if (n==x[i]) return i;
      for (j=0;j<y.length&&j<50;j++) {
        if (n==y[j]) return i + 1;
      }
    }
    return i + 1;
  }
}

TopCoder勉強会 - vol.1

最近日本でもはやり始めたTopCoderの勉強会資料を作成した。まずは登録から練習までの流れ。日本語訳が少なく、登録もわかりにくいので、画面付きで解説してます。明日18時ぐらいから、このドキュメントから解説して、練習問題を解きます。Googleアカウントでログイン後、アクセスしていただけるとチャットが見えるかと思います。ライトフリーで公開するので、ご自由にお使いください。元データがほしい場合も、応じます。トラックバックとかコメントでお知らせいただけるとワクワクします。ドキュメントリンク

Zipimortを使ってApp EngineでDjango1.0を利用する

"Using Django 1.0 on App Engine with Zipimport"の日本語訳。訳がおかしいところはコメントください。

はじめに

App EngineのアプリケーションでPython Webアプリケーションフレームワークを使うことは、アプリケーションフレームワークで使っているコードを取り込むぐらい簡単です。しかし、アプリケーションがアップロードできるファイルには制限があり、いくつかのフレームワークで制限を超えてしまう場合や、アプリケーションコードを書く余裕がない場合があります。この場合、App Engine リリース 1.1.3からサポートされているPythonの"zipimport" で解決することができます。

この記事では、Google App Engineに"zipimport"を使ってDjango 1.0を使用するための解説をします。

Zipimortの導入

アプリケーションにモジュールをインポートする際、Pythonはいくつかのディレクトリーの中からそのモジュールのコードを探します。PythonコードからPythonチェックするディレクトリーのリストを変えるにはsys.pathを使用します。App Engineがインクルドするパスは、App Engine APIとアプリケーションのルートディレクトリーです。

sys.pathのアイテムでZipフォーマットのアーカイブを指定することで、Pythonはそのアーカイブをディレクトリーとして扱います。アーカイブは1つ以上のモジュールを含む.pyソースコードを含みます。この機能はzipimportという標準ライブラリーのモジュールでサポートされており、このモジュールはデフォルトのインポートプロセスの1つであるため、このモジュールを使うために直接このモジュールをインポートする必要はありません。zipimportに関する詳しい情報に関しては、zipimportドキュメントを参照してください。

App Engineでモジュールアーカイブを使う方法:

  • バンドルしたいモジュールのZipフォーマットのアーカイブを作る
  • アプリケーションディレクトリーにアーカイブを入れる
  • 必要な場合はハンドルしたスクリプトをsys.pathに追加する

以下のようなファイルが入っている、django.zipというアーカイブの場合:

django/forms/__init__.pydjango/forms/fields.pydjango/forms/forms.pydjango/forms/formsets.pydjango/forms/models.py...

ハンドルしたスクリプトは以下のようにしてアーカイブからインポートします:

import syssys.path.insert(0, 'django.zip')import django.forms.fields

注意:このzipimportの解説例では、App EngineでDjango 1.0をロードするためには十分ではありません。より詳細な例は以下のとおりです。

zipimportとApp Engine

App Engineでは標準実装のzipimport機能ではなくカスタムバージョンを使用します。通常の動作: sys.pathにZipアーカイブを追加し、通常通りインポートします。

これはカスタム実装であるため、いくつかのドキュメントに記載されていない機能正式書類のない機能は動作しません。たとえば、App Engineはアーカイブから.pyはロードできますが、標準バージョンのように.pycファイルはロードできません。SDKでは標準版が使われているので、zipimportの正式書類のない機能を使用する場合は、App Engineで必ずテストしてください。

現在、App Engineのキャッシュロジックには、リクエストの度にsys.pathがリセットされるというバグが含まれているため、インポートした後にキャッシュしてください。ハンドラスクリプトが最初にロードされた時に、アプリケーションがすべてのモジュールをインポートしていることが確実でない場合、ハンドラーのmain()ルーチンはsys.pathの回復が必要です。

import sysdjango_path = 'django.zip'sys.path.insert(0, django_path)def main():  if django_path not in sys.path:    sys.path.insert(0, django_path)
Django 1.0のアーカイブ

App Engineは2008年夏にローンチし、スタートが簡単になるように環境の一部としてDjangoアプリケーションフレームワークを含んでいます。当時Djangoの最新リリースが0.96であったので、それがPythonランタイム環境のバージョン"1"となっています。それ以降、Djangoプロジェクトはバージョン1.0をリリースしました。互換性の問題で、App EngineはPythonランタイム環境にこのバージョンのDjangoにアップデートできません。1.0をApp Engineのランタイム環境のバージョン"1"で利用するためには、アプリケーションのディレクトリーに1.0をインクルードしなければなりません。

Django 1.0ディストリビューションには、1,582ファイルが含まれています。App Engineのアプリケーションのファイル数は1,000個に制限されているため、直接このディストリビューションをインクルードすることはできません。もちろん、ディストリビューション内の全てのファイルが必要というわけではありません。ファイル数を減らすために、ドキュメントファイル、未使用のロケール、データベースのインターフェース、その他App Engine上で動作しない(例えばAdminアプリケーション)コンポーネントをディストリビューションから除くことができます。zipimportを使うと、たった1つのファイルでDjango 1.0をアプリケーションで使うことができます。しかし、Django 1.0の1つのZipアーカイブファイルは3 MB以上ありますが、各アプリケーションのファイルは1MBをを超えることはできません。最も簡単な解決策は、未使用のロケールとコンポーネント以外でDjangoのアーカイブを作成することです。

Django 1.0をダウンロードし、以下を含んだZipアーカイブを再作成:

  1. DjangoウェブサイトからDjango 1.0ディストリビューションをダウンロードしてください。OSの適切なツールを使ってこのアーカイブを解凍してください(.tar.gzを解凍できるツール)。LinuxもしくはMac OS Xのコマンドラインでの例:
    tar -xzvf Django-1.0.tar.gz
  2. .../conf/.../contrib/のサブディレクトリーを除く(bin/test/を除くことも可能)、django/ディレクトリー内のすべてのファイルを含むZipアーカイブを作成する。Zipファイル内のパスはtest/で始まっている必要があります。
    cd Django-1.0zip -r django.zip django/__init__.py django/bin django/core \                  django/db django/dispatch django/forms \                  django/http django/middleware django/shortcuts \                  django/template django/templatetags \                  django/test django/utils django/views
  3. confパッケージには多くのローカライズファイルが含まれています。全てのファイルをアーカイブに追加すると、アーカイブのサイズが1MBの限界を超えてしまいます。しかし、いくつかのファイルは追加できる余裕があり、多くのDjangoパッケージがconfのうちいくつかが必要です。localeフォルダを除くすべてのconfファイルをアーカイブに追加してください。もし、必要なロケールファイルを追加する場合は、必ずファイルサイズが1MB未満であることを確認してください。

    以下のコマンドで、conf/locale以外のすべてのconfをアーカイブに追加できます。

    zip -r django.zip django/conf -x 'django/conf/locale/*'
  4. 同様に、.../contrib/内の必要なものだけを追加してください。contrib内の最大のコンポーネントはDjango Adminアプリケーションですが、これはApp Engineでは動作しないため、adminadmindocsディレクトリは削除してください。例えば、formtoolsを追加します。
    zip -r django.zip django/contrib/__init__.py \                  django/contrib/formtools
  5. アプリケーションディレクトリにアーカイブファイルを入れてください。
    mv django.zip your-app-dir/
モジュールアーカイブを使う

チップス:Django App Engine Helperの最新版(バージョン "r64" 以降)は、Django 1.0のZipimportをサポートしています。アーカイブ名がdjango.zipにし、アプリケーションのルートディレクトリに配置してください。manage.pyで生成されたすべての新規プロジェクトが自動的にそれを利用します。既存のプロジェクトをアップグレードする場合、まず新しいプロジェクトを生成し、既存プロジェクトからプロジェクトのmain.pyをアップデートしてください。詳細はUsing the Google App Engine Helper for Djangoを参照してください。

あなたがHelperなしでDjangoを使用するか、またはあなたが別のモジュールアーカイブを用いる場合にだけ、以下の解説が適用されます。

モジュールアーカイブを使用する場合、.zipファイルをPythonモジュールのロードパスに配置する必要があります。これを実現する最も簡単な方法は、各ハンドラースクリプトの先端でパスをロードし、main()ルーチンでにおける各操作者の主な()ルーチンでハンドルします。アーカイブ内のモジュールを使用する他のすべてのファイルは変更なしで動作します。App EngineはすべてのPythonアプリケーションにDjango 0.96をプリロードするため、Django 1.0を使うためには、djangoパッケージがプリロードされたバージョンではなく1.0を利用することを確実にするために多くのステップを必要とします。Running Django on App Engineに記述されてるように、Django 1.0をインポートする前に、sys.modulesからDjango 0.96を削除しなければなりません。

以下のコードのテクニックを利用することで、django.zipアーカイブからDjango 1.0を起動できます:

import sys# Uninstall Django 0.96.for k in [k for k in sys.modules if k.startswith('django')]:  del sys.modules[k]# Add Django 1.0 archive to the path.django_path = 'django.zip'sys.path.insert(0, django_path)# Django imports and other code go here...import django.core.handlers.wsgidef main():  # Re-add Django 1.0 archive to the path, if needed.  if django_path not in sys.path:    sys.path.insert(0, django_path)  # Run Django via WSGI.  application = django.core.handlers.wsgi.WSGIHandler()  util.run_wsgi_app(application)if __name__ == '__main__':  main()

適切なapp.yaml、settings.py、およびurls.pyファイルにより、このハンドラーはDjangoの"It worked!"ページを表示します。App EngineでDjangoを使用するための詳細については、Running Django on App Engineを参照してください。

単一パッケージに複数のアーカイブファイルを使用する

Django 1.0のすべては単一のアーカイブファイルに収めることができないので、これを複数のアーカイブファイルに分割し、sys.pathに配置することができます。Pythonを別の場所にナビゲートするために、いくつかのブートストラップコードを記述します。

Pythonはモジュールをインポートする際に、sys.pathに記述された各場所をチェックします。もしロケーションが最初のパッケージにない場合は、Pythonは次のsys.pathエントリーをチェックし、最初のパッケージを発見するまでロケーションをチェックし続けます。

Pythonがモジュールパスから最初のパッケージを発見した際、それを最終的に指定されたロケーションと仮定し、他のロケーションは探しに行きません。もしPythonがパッケージ内からモジュールを発見できなかった場合、インポートエラーが発生し、停止します。Pythonはパッケージ内でモジュールを発見した場合、sys.pathのエントリーをチェックしません。

最初のアーカイブ

最初のアーカイブを複数のアーカイブに分割したパッケージをインポートすることにより、その複数の場所にあるパッケージを探索できるようPythonに伝えます。パッケージ(モジュール)オブジェクトの__path__メンバー

は、パッケージコンテンツのロケーションのリストです。例えば、djangoパッケージがdjango1.zip、django2.zipという2つのアーカイブに分割した場合、以下のコードにより両方のアーカイブを見るようPythonに伝えることができます。

sys.path.insert(0, 'django1.zip')
import django
django.__path__.append('django2.zip/django')

これによりdjango1.zipからdjangoをインポートするために、django/__init__.pyをこのアーカイブに含めてください。

2つめのアーカイブの__path__を設定すると、双方のアーカイブからdjangoのモジュールをインポートします。

追記

App Engineでzipimportを使用するために追加で注意すること:

  • モジュールアーカイブを使用すると、最初にアーカイブインポートする時に付加的なCPUを消費します。同様のインスタンスへのリクエストに関してはメモリーにキャッシュされており、またアーカイブは解凍された状態でキャッシュされコンパイルされているので、同様のインスタンスのインポートについては、デコンパイル、コンパイルに必要なCPU時間は短縮されます。
  • App Engineのzipimportは、プリコンパイルされた.pycではなく、.pyソースファイルのみです。
  • ハンドラースクリプトがパスにモジュールアーカイブを追加要求するので、モジュールアーカイブにハンドラースクリプト自体を保存することはできません。モジュールアーカイブにはあらゆるパイソンコードを保存できます。

Blogger 3カラム テンプレート

Blogger Template (Rounders - 3Cols)
サイドバーが長すぎたので、テンプレートを3カラムに変更しました。利用した画像をPicasaに。ソースコードはこちらにおいてます。使いたい方は適当に使ってください。ヘッダーとフッターの画像はPicasaにアップロードしたものを使っているのですが、Picasaの速度が遅いのか表示されない・・・。どなたか良い画像アップローダご存知でしたら教えてくださいwww

Python温泉@熱海

Python温泉@熱海
Voluntasさんが主催するPython温泉に行ってきました。コアな方が集まっていてだいぶ刺激受けました。ちょっと風邪気味で途中熱っぽかったので、部屋にこもってしこしこコード書いてました。温泉は気持ち良かったです。それと、なんとアクセンステクノロジーさんから抽選会(じゃんけん)でPythonのマスコットを頂きました!いつもはじゃんけん弱いのに、もっすご良いとこでじゃんけんに勝てました。我が家のマスコットコレクションが増えて大満足www今回のPython温泉でのテーマは、

  • GAEでZipped Django1.0を使う
  • GAE+Djangoで画像のアップローダを作る

です。目標はなんとかクリアでき。ちょっとずつアプリが出来上がってきました。もう少しで公開したいと思ってます。Python温泉むちゃ勉強になります。さっそく来年も参加申し込みしときました。

XHTML勉強会 - vol.2


第2会のXHTML勉強会を開催しました。今回は簡単なWebディレクションと、アクセシビリティについてのリーディングと今までのリーディングをふまえた、XHTMLのコーディング練習をしました。今回は、WAIは置いといて、コンテンツの配置に重点をおいたコーディングです(コーディング例)。一番伝えたい情報を先に、意味のあるマークアップを!次回は各自のマークアップを元にディスカッションする予定。

Google App EngineがJavaをサポート

このブログで紹介されていますが、Google Developper Day 2008でGoogleがGAEにJavaをサポートさせたようですね。GAE4JとかJ4GAEとかGoogle Groups内でも賑わっています。同時に、Androidがオープンソースになったそうです。色々と目まぐるしいですが、俺はしばらくPython on GAEに夢中だと思います。

TopCoder - SRM 422 DIV 2: 250

83.39点orz。まず英語を読むのに20分もかかった。ソースコードビュアーで見る。今回のミスはStringのlengthに()をつけてなかった。もうアフォですね。

public class MultiNumber {
  public String check(int number) {
    if (number<10) {
      return "NO";
    }
    String s = Integer.toString(number);
    for (int i=0; i<s.length()-1; i++) {
      int n1 = 1;
      for (int j=0; j<=i; j++) {
        n1 *= Integer.valueOf(String.valueOf(s.charAt(j)));
      }
      int n2 = 1;
      for (int j=i+1; j<s.length(); j++) {
        n2 *= Integer.valueOf(String.valueOf(s.charAt(j)));
      }
      System.out.println ("n1: "+n1+", n2: "+n2);
      if (n1==n2){
        return "YES";
      }
    }
    return "NO";
  }
}

TopCoder - SRM 421 DIV 2: 250

public class GymTraining {
  public int trainingTime(int needToTrain, int minPulse, int maxPulse, int trainChange, int restChange) {
    if (minPulse < 50 || minPulse > 200) {
      return -1;
    }
    if (maxPulse < minPulse || maxPulse > 200) {
      return -1;
    }
    if (needToTrain < 1 || needToTrain > 200) {
      return -1;
    }
    if (needToTrain < 1 || needToTrain > 200) {
      return -1;
    }
    if (trainChange < 1 || trainChange > 200) {
      return -1;
    }
    if (restChange < 1 || restChange > 200) {
      return -1;
    }
    int time;
    int trained = 0;
    int pulse = minPulse;
    if(maxPulse < minPulse + trainChange) {
      return -1;
    }
    for(time=0; trained < needToTrain; time++) {
      if(maxPulse >= pulse + trainChange) {
         pulse += trainChange;
         trained++;
       } else {
         pulse -= restChange;
       }
       if(pulse < minPulse) pulse = minPulse;
     }
     return time;
  }
}

ソースコードビュアーで見る

250点問題の練習をしてみた。180点しかとれなかった。超凡ミス。メソッドをpublicにしてなかったのと、セミコロンをつけ忘れてたとこがあったorz。コンパイルエラー2回。あと、他の人のコードを見たら、糞短いwww。英語力も足りない。問題を理解するのに時間がかかりすぎ。いろいろと課題が山積み。

XHTML勉強会

XHTMLの勉強会をしました。ページに対する意味付けを学ぶために、W3CからXHTML1.0の規約をリーディングしました。キーワードは、意味のあるマークアップと、メタ情報による意味付けです。私もまだまだ勉強しないといけないですね(笑)

ソーシャルアプリ

愛用している自分をソーシャルにするためのアプリケーション。OSはWindows XP, Vista, OpenSUSEの3台を使っている。

ブラウザ
Web屋なので、一応すべてのブラウザはインストールされている。だけど、デイリーユースはやっぱりFirefox。アドオン入れまくりです。※アドオンはまた次の機会に紹介したい。Google Chromeはアドオンとテーマ等ができてから考える。
メール
ブラウザの影響からThunderbirdLightningと併せて、カレンダークライアントとしても使っている。メールはGmail、カレンダーはGoogle Calendar、ToDoはRememberTheMilkにホストしている。
IM
アカウントを10個以上持っているので、SkypeDigsbyを利用している。Skypeは主に会議用。Digsbyはコミュニケーション(プライベート)用。
写真
写真は、ストレージにPicasa、ソーシャルコミュニケーション用にFlickrを使っている。PCにはそれぞれ、PicasaクライアントFlickrクライアントを利用している。それと、PicasaからFlickrへのアップロードが多いため、Picasa2FlickrボタンをPicasaに追加している。
音楽
これは間違いなくiTunes。iPod使っているし、PodCast聞きたいし、音楽サーバも立てたい。自分が何を聞いているのかを共有できたり、これは便利。
ノート
複数台で共有したいので、Evernoteを使っている。Evernoteクライアントで、ブラウザ、メールをバシバシメモしている。

BOFと最中限のアルゴリズム

昨日、a2cさんが主催しているBOFに参加させていただいた。それぞれ思い通りに開発しつつ、わからないところはみんなで解決的なのり。是非また参加させていただきたい。

BOFの中で、西尾さんが、最中限という3人でやるゲームを教えてくれた。ルールは本家サイトを参照していただくとして、これをコンピュータ大戦するためのアルゴリズムを考えたい。

ゲーム理論で考えた場合、ミニマックス法でやる場合はすべての条件を網羅しないといけない。この場合の計算コストは以下のようになる。

  • カードは全部で52枚ある
  • 自分は17枚のカードを持っている

単純に計算すると、最初のターンで(17×3)×(16×3)×(15×3)× ・・・ (1×3)通りの条件を網羅しないといけない。500垓(該=10の20乗)回の計算。うーん無理だろ。

実際のゲームもこんなに計算しているわけじゃない。っていうかできない。再帰的なスレッドを入れ子して作るんだけど、これはアーランは得意そう。でも現実的には全パターンを網羅する必要なんてまったくない。ということで、アルファ・ベータ法等で、ゲーム木の深さを制限したい。それには条件が色々と必要になる。昨日初めて遊んだだけなので不確かだけど、以下のような条件では探索は不必要となる(と思うw)。

  • 1回目のラウンドは、0か一番少ない得点を狙いたい
  • 2回目のラウンド以降、自分が一番高得点の場合、相手に自分以上の得点を取らせたい
  • 2回目のラウンド以降、自分が最中限の場合、この状態をキープしたい
  • 2回目のラウンド以降、自分が一番低得点の場合、最中限の人を超えて最大得点以下の点を取りたい
  • ラウンド内の各ターンでは、ラウンドで最大の成果を出せるように得点を取りたい
  • 1番強いカードと1番弱いカードは絶対に取りたい時、取りたくない時に有効
  • 点数を取りたくない場合、ターンで最大を目指すか、最少を目指す
  • 点数を取りたい場合、最中を目指す

うーん。どれぐらい減るのかは書いてみないと分からないな。。。まだまだです。各自が作ったアルゴリズムを実装したら対戦して、誰のアルゴリズムが強いかを競い合ったりしたいw

Subversion削除用バッチファイル

Subversionを使ってると、.svnっていうフォルダが生成されちゃいますね。.svnファイルを一括で削除するバッチファイルを置いておく。ソースファイルを納品する時とかに、一気に.svnを削除して納品する時に使ってる。[filename].bat(バッチファイル)っていう名前で保存して、削除したいフォルダの最上位において実行すると、下位フォルダを含むすべての.svnファイルを削除してくれます。

echo off for /r %%i in ( .svn ) do ( if exist "%%i" ( rmdir /s /q "%%i"))

CEATEC JAPAN 2008

CEATEC JAPAN 2008
今日は幕張メッセで開催されているCEATEC JAPAN 2008に行ってまいりました(公式サイト)。ご一緒に連れて行ってくださったのは、Django本の執筆者のおひとりでもある、Voluntasさん。勝手ながら、もっすごリスペクトしています。10分ほど遅刻しちゃってごめんなさい・・・。皆さんもGoogle乗換なんかを信じちゃだめです。東京駅でJR線から京葉線に乗り換えるのに4分は無いです!東京に来てもうすぐ1年ですが、未だに慣れない。。。それはおいといて、CEATECの感想ですが、まとめると「お姉さんが綺麗」、「メッセ広すぎ」、「ブラックベリー・・・」って感じです。写真公開していますが、半分はお姉さんの写真です。くだらない写真でごめんなさいw村田セイコちゃんは思った以上にちっこくて可愛いですね。

Lucky Life Mountain Live

送信者 LuckyLifeMountain_Live
昨日は久しぶりに嫁さんとライブに行ってきました。いつもよくしてもらってる、"Ubuman"こと生方ノリタカさん(公式サイト)。テルミンという珍しい楽器と、エフェクトにMac Bookを使ってライブされてます。今回、Lucky Life Mountainという、テルミン、尺八、コントラバスと、固定された音律を持たない三種類の楽器が織りなす、未体験の音楽世界トリオ(公式サイトより引用)を結成し、その1stアルバムの発売を記念し、全国津々浦々でライブされてるようです(ライブスケジュール)。テルミンの不思議な音色と、尺八の差音が絶妙なバランスで、不思議な世界に引き込まれていくような感じ。行ってあげてくださいw

ちなみにMySpaceでは、生方さんが製作されている音楽が視聴できますので、是非(MySpace)。

それと、ライブは東渋谷の鈴ん小屋(りんごや)というところでした。料理が全部有機野菜なので、相当美味しかったです(公式サイト)!