Amazon

2011年11月30日水曜日

Google App Engineの新料金体系まとめ

Google App EngineがPreviewステージを卒業して正式サービスを開始したのを受けて新料金体系を発表したのは5月。適用は9/1とのことだったが、利用者からの猛反発を受けて以下に変更

幾つか新料金体系の変更を加えた
・新料金の適用を9/1から11/1へ延期
・無料Front Instance Hours 24 -> 28
・12/1のPython 2.7サポートまではFront Instance Hoursを課金を半額にする

さて、ここで自分がハマっていたことのメモ。
無料枠は依然残るものの、課金設定をしていると無料枠に収まっていても毎月$9(毎週$2.1)請求される。ただし、この毎週$2.1は最低利用料という扱いのため、例えばこの一週間で$1.3分を使用したとしても請求されるのは$2.1。つまり本請求は$2.1を超えたものから行われていく。

何も考えずにスケール対策のために課金設定にしていたので見事に毎週請求が来てました(ToT) 

課金設定を解除するにはBilling Setting -> Disable Billingにすること。
また、知らないうちに設定していたようだけど、9/1-10/31の間に課金設定にしてあれば、そのアプリケーションに対して$50分がもらえた様子。確かに自分のアプリケーションのいくつかも、Billing Historyの中でBalanseが($50)になっていた。ちなみに、請求されるとステータスはCharge Cancelとなるようです。

にしてもこの値上げは痛いなぁ。。。

さて、値上げ対策としてアプリケーションのチューニングが必要になるようだけど、
簡単な方法は
・Application SettingsでMax Idle Instancesを1、Min Pending Latencyを15Sにすること
・Datastoreへの問い合わせを極力減らして、Memcacheを使用

くらいのようです。

参考:Google App Engineの新料金体系対策

2011年11月27日日曜日

Aptana(Pydev)環境をWindowsからMacへ移動

MacBook Air(MacOS X Lion)を購入したので、
WindowsからMacへAptanaの環境を移行する方法をメモしておきます。

  1. Mac用のAptana Studioをダウンロード&インストール  
  2. Python 用 Google App Engine SDK 1.6のダウンロード&インストール
  3. WindowsからAptana Studio workspaceからプロジェクトフォルダをコピー
  4. Macの/Document/Aptana Studio 3 Workspaceの下に2.をコピー
  5. 各プロジェクト内の.pydevprojectファイルを編集
    * もしFinderで表示されていない場合はターミナルで以下のコマンドを打つと隠しファイルも表示されるようになる。
    % defaults write com.apple.finder AppleShowAllFiles TRUE
    逆に隠しファイルを隠す場合は
    % defaults write com.apple.finder AppleShowAllFiles FALSE

    .pydevprojectのファイルを編集

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <?eclipse-pydev version="1.0"?>

    <pydev_project>
    <pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
    <pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
    <pydev_variables_property name="org.python.pydev.PROJECT_VARIABLE_SUBSTITUTION">
    <key>GOOGLE_APP_ENGINE</key>
    <value>C:\Program Files\Google\google_appengine</value>
    </pydev_variables_property>
    <pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
    <path>/harnivorous/src</path>
    </pydev_pathproperty>
    <pydev_pathproperty name="org.python.pydev.PROJECT_EXTERNAL_SOURCE_PATH">
    <path>${GOOGLE_APP_ENGINE}</path>
    <path>${GOOGLE_APP_ENGINE}/lib/django</path>
    <path>${GOOGLE_APP_ENGINE}/lib/webob</path>
    <path>${GOOGLE_APP_ENGINE}/lib/yaml/lib</path>
    <path>C:\Python27\Lib\site-packages\nose-1.1.2-py2.7.egg</path>
    </pydev_pathproperty>
    </pydev_project>



    a) C:\Program Files\Google\google_appengine ->

    /Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine
    b) ${GOOGLE_APP_ENGINE}/lib/django -> ${GOOGLE_APP_ENGINE}/lib/django_1_2
    c) <path>C:\Python27\Lib\site-packages\nose-1.1.2-py2.7.egg</path> -> 削除
    d) <path>${GOOGLE_APP_ENGINE}/lib/simplejson</path> を追加
     
     
  6. Aptanaを起動してFile -> Import -> Existing Folder as New ProjectとしてProject TypeはデフォルトのWebのチェックをはずす
  7. GAEへのデプロイ(アップロード)起動オプションの作成。Run -> Run ConfigurationsでPyDev Google App RunをダブルクリックしてProjectは起動オプションを作りたいプロジェクト名を入れる。Browseを押しても出てこない場合は直接名前を入力。以下を設定したらApplyで保存
    -Main Tab-
    Project: THE_PROJECT_NAME
    Main Module: ${GOOGLE_APP_ENGINE}/appcfg.py
    -Arguments Tab-
    Program arguments: --email=GAE_ID --no_cookies update "${workspace_loc:THE_PROJECT_NAME/src}"
    Working directory: Defaultで${project_loc:_selected project name}

  8. GAEへのデプロイではなく、ローカルホストでの実行の場合は、上記の起動ウィザードのうち以下を変更。
    Main Module: ${GOOGLE_APP_ENGINE}/dev_appserver.py
    Program arguments: "{workspace_loc:THE_PROJECT_NAME/src}"

2011年11月26日土曜日

PythonでJavaScriptのencodeURIと同じことをやるには?

JavaScriptで言うところのencodeURIと同じことをPythonでやるにはurllib.quote()メソッドを使う。

第一引数に変換したい文字列を、第二引数に変換したい文字コードを設定すること。
# -*- coding: utf-8; -*-

import urllib

print urllib.quote('いろはにほへと')
print urllib.quote(u'いろはにほへと'.encode('euc-jp'))
print urllib.quote(u'いろはにほへと'.encode('shift_jis'))
print urllib.quote(u'いろはにほへと'.encode('iso-2022-jp'))
print urllib.quote(u'いろはにほへと')
print urllib.unquote('%E3%81%84%E3%82%8D%E3%81%AF%E3%81%AB%E3%81%BB%E3%81%B8%E3%81%A8')


但し上記の方法だと、GETリクエストのURIは作りにくいので、urllib.urlencode()というメソッドがある。これはクエリにしたいものをリスト形式で記述して、urlencode()の引数に与えてあげる。(辞書形式の場合は順番は保持されない)


# -*- coding: utf-8; -*-

import urllib

urlprefix = 'http://www.google.co.jp/search?'
keyword = u'Python URIエンコード'
lang = 'ja'
encoding = 'utf-8'
query = [
    ('q', keyword.encode(encoding)),
    ('hl', lang),
    ('lr', 'lang_' + lang),
    ('ie', encoding),
    ('oe', encoding),
]

print urlprefix + urllib.urlencode(query)
 
 
参考元はこちら 
 

2011年11月21日月曜日

HTMLとJavaScriptでWebアプリケーションを作る際に注意すること

○ window.confirm()のタイトルは変更不可
window.alert, window.confirmなどでポップアップのダイアログを表示する際、ブラウザによって表示のされ方が異なる。IEやChromeの場合、タイトルバーが表示されてタイトルが表示されるがSafariの場合、タイトルの内容が本文に表示されてしまう。Firefoxはタイトルなし。
しかも、このダイアログのタイトルは変更不可能。
もし自由なダイアログを作成したいならjQuery Alertがオススメ

- IE








- Firefox









- Chrome






- Safari










○ document.getElementById().innerHTMLの落とし穴
DOM操作などでdocument.getElementById()を多用するかと思うけど、このタグに囲まれている値を取る時に注意が必要。.innerHTMLメソッドで要素内のデータを取得すると、HTML形式で値が取得されてしまうため、例えば、以下のようなtextareaのHTML要素に対してタグで囲まれた文字列"ここは<textarea>タグの領域です。" を取得しようとして、document.getElementById("textarea1").innerHTMLとすると、"ここは&lt;textarea&gt;タグの領域です。"となる。もしHTMLの特殊文字をそのまま取得したいならば、document.getElementById("textarea1")..textContentとする。


     <textarea id="textarea1">ここは<textarea>タグの領域です。</textarea>
○ formタグ内のinputタグの挙動について
<input onclick="javascript:hoge()">に対して、
<form action="ACTION_URL" method="GET">
で囲まれている場合、このinputタグがtype="submit"が指定されていなくてもACTION_URLに対してGETリクエストを送ってしまうようだ。

コードの再利用している場合は注意が必要。ちゃんと意味のあるタグだけつけるように。

2011年10月23日日曜日

スマートフォン向けWebアプリ開発に有用なリンク

iOSやAndroidなどのスマートフォン用のネイティブアプリを開発するにはObjective-CやJavaによる開発を行わなければならないが、
せめて見た目だけでもそれっぽく見せたいなら
jQuery Mobileが使えそう。

jQuery Mobileのドキュメント
iOSやAndroidのネイティブっぽいUIを作るためのjQueryのプラグイン

ナビゲーションバーに使えるアイコン(無償、有償)
http://glyphish.com/


jQuery Mobileを使用するには
http://jquerymobile.com/download/
から落としてくるか

<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0rc2/jquery.mobile-1.0rc2.min.css" />
<script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
<script src="http://code.jquery.com/mobile/1.0rc2/jquery.mobile-1.0rc2.min.js"></script>
 
で直接呼び出す。 
 
Page-Themeを変更したければ
http://blog.livedoor.jp/aki_mana/archives/3458912.html 
 
【参考】 
jQuery mobile でスマートフォン用のフッターを作成 
jQueryのテンプレート 

JavaScriptでiOSアプリもAndroidアプリも開発
初心者でも2週間でiPhoneアプリが作れちゃうTitanium Mobileがすごい件 
Titanium MobileでiPhoneアプリを開発、リリースしました
PhoneGap

Titanium Mobileで作る! iPhone/Androidアプリ
 

2011年10月10日月曜日

開発mixiアプリ3本 (9月分)

先月公開したmixiアプリ3本ご紹介

4つの質問に答えるだけで、あなたの今日の出逢える度を診断!!
その日の恋愛アドバイス&ラッキーアイテム付きで婚活のお供にも最高なアプリです。
毎日のお出掛け前にチェックしてね。

このアプリで遊ぶ


2. 彼氏・彼女の肉食度診断 (PC版、スマフォ板、ケータイ版)
気になるあの人の肉食度・隠れ肉食度を30秒チェック!
約5000人のアンケートデータを基にした診断で、今彼・今カノ、元カレ・元カノ、気になるあの人の肉食度をさりげなくチェックしちゃいましょう!
肉食度のレベルに応じた恋愛アドバイスつき☆

このアプリで遊ぶ



3.  彼氏・彼女の草食度診断 (PC版、スマフォ板、ケータイ版)
気になるあの人の草食度を30秒チェック!
今彼・今カノ元カレ・元カノ、気になるあの人の草食度を5000人のデータを基にした診断でさりげなくチェックしちゃいましょう!
草食度のレベルに応じた恋愛アドバイスつき☆

このアプリで遊ぶ

Djangoテンプレートの埋め込みタグ

Django埋め込みタグリファレンスより

よく使いそうなものをピックアップ

now

指定したフォーマット文字列にしたがって現在の日時を表示します。
フォーマット文字列中で普通の文字列を使いたければ、バックスラッシュでエスケー プできます。下の例では、"f" が時刻を表すフォーマット指定子として解釈されな いようにエスケープしています。 "o" はフォーマット指定子ではないのでエスケー プしていません:
It is {% now "jS F Y H:i" %}
It is the {% now "jS o\f F" %}
フォーマット文字 説明 出力例
a 'a.m.' または 'p.m.' (Associated Press に合わせるため、'.' が入っている点 が PHP と違います)。 'a.m.'
A 'AM' または 'PM' です。 'AM'
b 3 文字の小文字で表した月名です。 'jan'
B 実装されていません。  
d 月の中の日。 2 桁のゼロ詰めです。 '01' から '31'
D 週の中の日。 3 文字のテキスト形式です。 'Fri'
f 12 時間表記の時と分。ただし、ゼロ分の 場合には表示しません。独自の拡張です。 '1', '1:30'
F 月名を長いテキスト形式で表したものです。 'January'
g 12 時間表記の時。ゼロ詰めはしません。 '1' から '12'
G 24 時間表記の時。ゼロ詰めはしません。 '0' から '23'
h 12 時間表記の時です。 '01' から '12'
H 24 時間表記の時です。 '00' から '23'
i 分です。 '00' から '59'
I 実装されていません。  
j 月の中の日。ゼロ詰めしません。 '1' から '31'
l 週の中の曜日。長いテキスト形式です。 'Friday'
L 閏年かどうかを表すブール値です。 True または False
m 月です。2 桁でゼロ詰めしたものです。 '01' から '12'
M 月です。3 文字のテキスト形式です。 'Jan'
n 月です。ゼロ詰めしません。 '1' から '12'
N Associated Press スタイルの月の省略表記 です。独自の拡張です。 'Jan.', 'Feb.', 'March', 'May'
O グリニッジ標準時からの時差です。 '+0200'
P 時刻です。12 時間表記の時、分、 そして 'a.m.'/'p.m.' です。分がゼロの 場合には省略され、必要に応じて 'midnight' または 'noon' になります。 独自の拡張です。 '1 a.m.', '1:30 p.m.', 'midnight', 'noon', '12:30 p.m.'
r RFC 2822に従ったフォーマットの日時です。 'Thu, 21 Dec 2000 16:01:07 +0200'
s 秒です。 2 桁のゼロ詰めです。 '00' から '59'
S 月の中の日につける 2 文字の序数接尾辞 です。 'st', 'nd', 'rd' or 'th'
t 月の日数です。 28 から 31
T 計算機のタイムゾーン設定です。 'EST', 'MDT'
U 実装されていません。  
w 週の中の曜日です。ゼロ詰めしません。 '0' (Sunday) to '6' (Saturday)
W ISO-8601 に従った年の中の週番号です。 週は月曜日から始まります。 1, 53
y 2 桁の年です。 '99'
Y 4 桁の年です。 '1999'
z 年の中の日 0 から 365
Z タイムゾーンオフセットを秒であらわした ものです。UTC よりも西側のタイムゾーン値 は全て負の値になり、東側の値は常に正に なります。 -43200 から 43200

include

テンプレートをロードして、現在のコンテキストを使ってレンダリングします。あ るテンプレートに別のテンプレートを取り込む ("include") 方法の一つです。
テンプレート名はハードコードされた (引用符で囲った) 文字列でもよく、引用符 は一重でも二重でもかまいません。
以下の例では、 "foo/bar.html" という名前のテンプレートを取り込みます:
{% include "foo/bar.html" %}
次の例では、 変数 template_name に入っている名前のテンプレートを取り込 みます:
{% include template_name %}
取り込まれたテンプレートは、取り込んだ側で使われているコンテキストの下でレ ンダリングされます。下の例では "Hello, John" を出力します:
  • コンテキスト: 変数 person"john" に設定
  • テンプレート:
    {% include "name_snippet.html" %}
  • name_snippet.html テンプレート:
    Hello, {{ person }}
{% ssi %} も参照してください。

cycle

Django 1.0 で変更されました: タグを処理するごとに、指定した文字列や変数を循環して返します。
ループの中では、ループごとに指定した文字列や変数を循環して返します:
{% for o in some_list %}
    <tr class="{% cycle 'row1' 'row2' rowvar %}">
        ...
    </tr>
{% endfor %}
ループの外側では、最初に一意な名前を与えておき、以後はその名前を使います。 例えば:
<tr class="{% cycle 'row1' 'row2' rowvar as rowcolors %}">...</tr>
<tr class="{% cycle rowcolors %}">...</tr>
<tr class="{% cycle rowcolors %}">...</tr>
任意の個数の値を使えます。値はスペースで区切ります。値をクオート (') または二重クオート (") で囲むと、文字列リテラルとして扱います。 クオートされていない値はコンテキスト変数への参照とみなされます。
値をカンマで区切った形式もつかえます:
{% cycle row1,row2,row3 %}
ただし、この構文では、値は全てリテラルテキストとして扱われます。 カンマを使った構文は以前のバージョンとの互換性のために残されています。 新たなプロジェクトでは使わないようにしてください。

for

アレイの各要素に渡ってループします。例えば、アスリート (athlete) のリストを athlete_list で渡して表示するには:
<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% endfor %}
</ul>
{% for obj in list reversed %} のようにすると、リストに対して逆順のルー プを実行できます。
Django 1.0 で新たに登場しました.
リストのリストにわたってループ処理を行う場合、各サブリストをアンパックして、 個別に名前を割り当てられます。例えば、座標 (x, y) のリストが入った points というコンテキスト変数があり、各座標を出力したい場合には以下のよ うにします:
{% for x, y in points %}
    座標 {{ x }},{{ y }} が登録されています。
{% endfor %}
この方法は、辞書の各要素にアクセスしたい場合にも便利です。例えば、コンテキ スト変数 data に辞書が入っている場合。以下のようにすれば辞書内のキーと 値を表示できます:
{% for key, value in data.items %}
    {{ key }}: {{ value }}
{% endfor %}
for ループは、ループの各回ごとに使える変数を設定します:
変数名 説明
forloop.counter 現在のループ回数番号 (1 から数えたもの)
forloop.counter0 現在のループ回数番号 (0 から数えたもの)
forloop.revcounter 末尾から数えたループ回数番号 (1 から数えたもの)
forloop.revcounter0 末尾から数えたループ回数番号 (0 から数えたもの)
forloop.first 最初のループであれば True になります
forloop.last 最後のループであれば True になります
forloop.parentloop 入れ子のループの場合、一つ上のループを表します 




 

2011年10月9日日曜日

Twitterのようなアプリを作る時に役立つ情報


○Twitterみたいに文字数を動的にカウントしてくれるjQueryのplugin
http://cssglobe.com/post/7161/jquery-plugin-simplest-twitterlike-dynamic-character-count-for-textareas

○jQueryの直接呼び出し
- Google Libraries APIを使用することでサーバーに置いておかなくてすむ
http://code.google.com/intl/ja/apis/libraries/devguide.html#jquery

jQuery
    name: jquery
    latest version: 1.6.4 (view older versions)
    load request: google.load("jquery", "1.6.4");
    extras: uncompressed:true (as in google.load("jquery", "1.6.4", {uncompressed:true});
    path: https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js
    path(u): https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.js
    site: http://jquery.com/
    note: 1.2.5 and 1.2.4 are not hosted due to their short and unstable lives in the wild...

jQuery UI
    name: jqueryui
    latest version: 1.8.16 (view older versions)
    load request: google.load("jqueryui", "1.8.16");
    extras: uncompressed:true (as in google.load("jqueryui", "1.8.16", {uncompressed:true});
    path: https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js
    path(u): https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.js
    site: http://jquery.com/
    note: This library depends on jquery. You must also load jquery before loading this module. Version 1.8.3 is not hosted due to its short life, and the alias 1.8.3 actually loads 1.8.4.


使い方は二種類
1. 「Google AJAX Search API」からGoogle APIキーを貰って来る。WebサイトのURLを登録する必要がある。

各ライブラリの呼び出しにはgoogle.load()を使用してライブラリおよびその目的のバージョンの番号を付ける。例えば貰ったAPIキーが「ABCDEFG」だとして、後は下記のような感じでJavaScriptを記述する。
<script type="text/javascript" src="http://www.google.com/jsapi?key=ABCDEFG"></script>  
<script type="text/javascript">  
    google.load("prototype""1.6.0.3");  
    google.load("jquery""1.3.1");  
    google.load("jqueryui""1.5.3");  
    google.load("scriptaculous""1.8.2");  
    google.load("mootools""1.2.1");  
    google.load("dojo""1.2.3");  
    google.load("swfobject""2.1");  
    google.load("yui""2.6.0");  
</script> 

マイナーバージョン(1.x.yのx,y)を省略すると最新のバージョンを自動取得してくれる。



2. Google Libraries APIのpathから直接呼び出す。

<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/blitzer/jquery-ui.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"></script>
<script type="text/javascript"  src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.12/jquery-ui.min.js"></script>


のような感じ

2011年9月26日月曜日

プロキシサーバーSquidをWindowsでセットアップ

プロキシサーバーとして利用できるフリーのSquidのWindows版インストール手順のメモ
参考元はこちら
  1. squidのページよりSquid 2.7 for Windowsをダウンロード
  2. 解凍してC:\squidとなるようにフォルダを配置
  3. C:\squid\etc\mine.conf.default, squid.conf.defaultをそれぞれコピーしてmine.conf, squid.confに名前変更
  4. squid.confの"acl localhost src 127.0.0.1/255.255.255.255"の行の後に次の行を追加"acl lan src 192.168.0.0/255.255.255.0"
  5. "http_access allow manager localhost"の次の行、"http_access deny manager"の前の行に"http_access allow lan"を追加(lanは上記で追加した名前)
  6. visible_hostnameにプロキシサーバーのホスト名を追加(例proxy.hogehoge.co.jp)
  7. コマンドプロンプトでC:\squid\sbinに移動
  8. % squid -z でスワップ用のディレクトリを作成
  9. % squid -i でsquidをWindowsのサービスとして追加
  10. コントロールパネル->管理ツール->サービスでSquidのサービスを開始する 
     
    ちなみに10でサービスの起動に失敗する場合は、6のサーバーにアクセスできない場合(DNSが解決できない場合を含む)に起こる




2011年9月24日土曜日

ケータイで使用できる絵文字の素材

DoCoMo, au, Softbankの絵文字一覧は
http://www.kent-web.com/bbs/epad.html

http://trialgoods.com/emoji/?career=sb&page=all
などで参照できる。けど、著作権的にアウトらしいので、他のものを探していたらTypePadが絵文字をフリーで公開しているらしく、携帯向けコンテンツを作成するときは有用そう。

TypePadの絵文字アイコン画像と、携帯コンテンツ表示モジュールをフリー(自由)ライセンスで公開

http://start.typepad.jp/typecast/

あとは絵文字使用時にライセンスを明記すればOK

2011年9月17日土曜日

mixiアプリのuseragent


mixiアプリを開発していると、色々ハマる。
きっとPC版、モバイル版、スマフォ版とバラバラに作ってるせいだろうけど。

そんなわけで今日ハマったのはmixi側から送られてくるUserAgentの情報
PC版は外部リクエストAPIを使用するとHTTP_USER_AGENTがユーザーのブラウザ情報ではなく "
mixi-platform/1.1"となる。これじゃあブラウザによって処理を変えることができないじゃんよ。。。
スマフォ版、モバイル版はOpenSocialのgadgets.io.makeRequest()メソッドを使わないので外部にリクエストできるので、useragentはユーザーのブラウザ情報が表示される。
さて、どう対処すべきか。。。

2011年9月16日金曜日

ケータイ、Androidの文字コードの袋小路


mixiモバイル、touch、PC版アプリを同時に作ろうとしていて文字コードの袋小路にハマる。
たぶんこれはmixiモバイルに限らないのでメモしておこう。

モバイル系は
au, docomo, softbankはShift-JISに対応。但し、
CSSを使う場合はiモード対応XHTMLにする必要がある。
XML宣言とi-mode用のDOCTYPE宣言が必要。

docomo, softbankはutf-8でも問題ないが
auはau browser6.2はutf-8に対応していない。7.2は対応している。
3G端末に限って言うと、UTF-8が使える条件は次のようになっている。
参照元はこちら
機種 XHTML HTML XHTML
(SSL)
HTML
(SSL)
docomo 3G
au ブラウザver7.2
au ブラウザver6.2 × × ×
SoftBank 3G
○:文字化けしない △:一部の条件下で文字化け ×:文字化けする

次にtouch版
iPhoneの場合、Shift-JISでもUTF-8でも問題ない。
Androidの場合、2.1においてはShift-JISだと問題がある。

参照元はこちら
文字エンコーディング Content-Typeヘッダ xml宣言の有無 結果
Shift_JIS text/html
application/xhtml+xml ×
UTF-8 text/html
application/xhtml+xml
EUC-JP text/html
application/xhtml+xml ×

つまりShift-JISだとAndroid  2.1で非対応となり、UTF-8だとau携帯が非対応(文字化け)となってしまう。
Shift-JISにして、Android 2.1の時だけContent-Typeヘッダーをtext/htmlに変換するのが一番手がかからないかなぁ。。。

Android 2.1でのShift-JISページの取り扱い

mixi touchアプリを作っていたときのこと。
Android 2.1のシュミレーターでテストしてたら
「Unsupported encoding Shift_JIS」のエラーが出ました。
2.2, 2.3では起こらないのになんでやねん?

そこで 調べていたらまさしくビンゴなブログを書いている方がいらっしゃいました。

Andorid2.1のブラウザはShift_JISをサポートしないのか?


Content-Typeヘッダの出力をtext/htmlにしたらどうか?XML宣言を書かなければ?、文字エンコーディングがUTF-8、EUC-JPなら?とパターンをそれぞれ用意し、表示した結果を以下の表にまとめてみました。
文字エンコーディング Content-Typeヘッダ xml宣言の有無 結果
Shift_JIS text/html
application/xhtml+xml ×
UTF-8 text/html
application/xhtml+xml
EUC-JP text/html
application/xhtml+xml ×




いや、そういうバグはやめてくれ。。。

2011年9月6日火曜日

Pythonによるモバイル開発の文字コード2

前回に引き続き、Pythonの文字コードで引っかかったお話。
今回はPythonというよりも、Opensocial APIのgadgets.io.endoceValues()メソッドのお話。

Opensocialのアプリを作成している際
HTML側のメタタグで
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=Shift_JIS" />
と指定した上で
<input type="button" onclick="postSubmit()"/>
と書く。

この時、JavaScriptの
function postSubmit(){
...
var value1="";
var value2="";
params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.POST;
params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.SIGNED;
var post_data{
'key1':value1,
'key2':value2,
} 
params[gadgets.io.RequestParameters.POST_DATA] = gadgets.io.encodeValues(post_data);
と書いてPOSTリクエストをすると、
gadgets.io.endoceValues()が有効になり、
POSTされる文字コードは,入力オブジェクトを URL エンコードしたデータ文字列に変換される。
POST のデフォルト エンコードは application/x-www-form-urlencoded でありShift-JISではない。
 
よって、Python側で受けるとき
self.request.charset="Shift-JIS"
をセットしてしまうと返って文字化けを引き起こしてしまう。
ということで、JavaScriptからPOSTされた場合には、self.request.charset="Shift-JIS"
は呼ばないようにif文を書いてあげる。
userAgent=detectAgent(self.request.user_agent)
if userAgent != 'pc':
 
ここでdetectAgentメソッドは独自メソッドで、self.request.user_agent(HTTP_USER_AGENT)に入っている文字列からpcかsmartphoneかmobileかを判定する。
def detectAgent(userAgent):
    if userAgent.startswith('DoCoMo'):
        return 'mobile'  
    elif userAgent.startswith('KDDI-'):
        return 'mobile'
    elif userAgent.startswith('SoftBank'):
        return 'mobile'
    elif userAgent.startswith('Vodafone'):
        return 'mobile'
    elif userAgent.startswith('Mozilla/5.0 (iPhone'):
        return 'smartphone'
    elif userAgent.startswith('Mozilla/5.0 (Linux'):
        return 'smartphone'
    else:
        return 'pc' 
あまりスマートな書き方じゃないけど、とりあえず暫定版ということで。

2011年9月3日土曜日

Pythonによるモバイル開発の文字コード1


携帯Webサイトを作る際、文字コードがShift-JISにするのが一般的。
このWebサイトからフォームで日本語を POSTする場合、
Python側で受取る時に注意が必要。
通常PythonではUTF-8で受取るため、文字化けを起こす。

そこで、self.request.get('xxx)とする前に
self.request.charset('Shift-JIS')で文字コードを指定する。
こんな感じ

def post(self):
        self.request.charset="Shift-JIS"
        self.request.get('hoge')

Pythonでテスト駆動開発2 -Aptanaからnoseの実行-

前回noseを使って、Pythonでテストを実行する方法について書いた
今回はAptana(Eclipse)からPythonのテストフレームワークのnoseを使用する方法をまとめます。

テストするクラスとテストコードは前回のtest1.py, test2.py

test1.py, test2.pyでは使用していないけど、
テストコードで以下の一文があると、まずライブラリが見つからないとAptana(Eclipse)から怒られる。
from nose.tools import ok_, eq_

ということで解決策
1. プロジェクトを右クリックしてプロパティ
2. PyDev - PYTHONPATHにnoseのライブラリフォルダを追加
 (C:\Python27\Lib\site-packages\nose-1.1.2-py2.7.egg)

テストの実行は
test2.pyの最後に
if __name__ == '__main__':
    import nose
    nose.main()
の記述を入れると、pythonの実行ファイルと認識されて、Eclipseの実行設定ファイルで読み込めるようになる。

ちなみに実行設定ファイルは以下の通り。




で、上記を実行すると
Failure: ImportError (No module named testdata) ... ERROR
Failure: ImportError (No module named sancho.unittest) ... ERROR
Failure: ImportError (No module named sancho.unittest) ... ERROR
Failure: ImportError (No module named sancho.unittest) ... ERROR
Failure: ImportError (No module named sancho.unittest) ... ERROR
Failure: ImportError (No module named sancho.unittest) ... ERROR
Failure: ImportError (No module named sancho.unittest) ... ERROR
Failure: ImportError (cannot import name AES) ... ERROR
Failure: ImportError (No module named testdata) ... ERROR
という結果になる。

このプロジェクト内のテスト(class Testxxx)を全部実行するため、 本来テストしたいもの以外も実行されてしまっている。

ということで、必要なテストだけを実行する場合は--tests=NAMEオプションを付けて実行する。
通常はnose.main()にargs=["-v","--name=tests2.py"] を渡して
test.py
if __name__ == '__main__':
    import nose
    nose.main(args=["-v","--name=tests2.py"] )
とするのが一般的のようだけど、何故か引数が有効にならない。
Aptana(Eclipse)を使用する場合はmainへの引数は実行設定ファイルで設定するようです。



で実行するとverboseモードになって(test.xxx ... okみたいな)テスト結果が表示される。

test2.TestDollar.Multiplicaton_test ... ok

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK


○注意点
class名はTestxxxとTestで始めること
メソッド名はyyy_testとすること

Amazon3