Selenium IDE: Gosub Control 使い方

定型操作のlogin

gosubを使わない例

# login user
open ${BASE_URL}/login
type name=username ${USER_USERNAME}
type name=password ${USER_PASSWORD}
clickAndWait id=btnLogin
# action and verify
...
# lougout
clickAndWait link="logout"
#
# login admin
open ${BASE_URL}/login
type name=username ${ADMIN_USERNAME}
type name=password ${ADMIN_PASSWORD}
clickAndWait id=btnLogin
# action and verify
...
# logout
clickAndWait link="logout"

gosubを使って、login user、login admin、logoutをサブルーチン化した例

gosub login_user
# action and verify
...
#
gosub logout
#
gosub login_admin
# action and verify
...
gosub logout
#
#----------------------------------------
# sub login_user
#----------------------------------------
sub login_user
open ${BASE_URL}/login
type name=username ${USER_USERNAME}
type name=password ${USER_PASSWORD}
clickAndWait id=btnLogin
endsub
#----------------------------------------
# sub login_admin
#----------------------------------------
sub login_admin
open ${BASE_URL}/login
type name=username ${ADMIN_USERNAME}
type name=password ${ADMIN_PASSWORD}
clickAndWait id=btnLogin
endsub
#----------------------------------------
# sub logout
#----------------------------------------
sub logout
clickAndWait link="logout"
endsub
#

Selenium IDE: Gosub Control

Selenium IDE: Gosub Controlをリリースしました。
Selenium IDEにBASIC言語ライクなgosub、sub、endsub、returnコマンドを追加します。

https://github.com/ninton/selenium-ide-gosubcontrol
https://addons.mozilla.org/ja/firefox/addon/selenium-ide-gosub-control/

・定型作業をサブルーチン化して、testcaseを読みやすくしましょう。

・定型作業ではなくても、コメントを詳しく記述するよりは、サブルーチン化のほうが効果的な場合があります。

・testcaseをまたいだサブルーチン呼び出しはできません。
同じ内容だとしてもtestcaseごとにサブルーチンを記述する必要があります。

・sub ~ endsub のネストはできません。

・サブルーチン内から別のサブルーチンへgosubできます。

・参考
gotoIfやwhile/endWhileを追加するプラグイン Selenium IDE: Flow Control
https://addons.mozilla.org/ja/firefox/addon/flow-control/
https://github.com/davehunt/selenium-ide-flowcontrol

サンプル1
gosubから呼ばれた場合、subとendsubの間を実行します。
次のサンプルは、x_add_1 を3回読んでいるので、Xの値は3になります。
endsubの後ろのverifyExpressionでは、Xの値は4ではなく、3のままです。

store 0 X
# x_add_1 x 3
gosub x_add_1
gosub x_add_1
gosub x_add_1
# verify( x == 3 )
verifyExpression ${X} 3
#
sub x_add_1
storeEval parseInt(${X})+1 X
echo ${X}
endsub
#
verifyExpression ${X} 3

サンプル3
gosubから呼ばれたのではなく、単にsubに到着した場合、endsubまでスキップします。
次のサンプルでは、x_add_1を呼んでいないので、Xの値は0のままです。

store 0 X
# verify( x == 0 )
verifyExpression ${X} 0
#
sub x_add_1
storeEval parseInt(${X})+1 X
echo ${X}
endsub
#
verifyExpression ${X} 0

Selenium IDE ユーザー拡張スクリプトでstore変数を参照する

Selenium IDE で、store変数USERNAMEに “taro” を保存する。
コマンド: store
対象: taro
値: USERNAME

store変数USERNAMEをinputタグ(id=”username”)に入力する。
コマンド: type
対象: id=username
値: ${USERNAME}

ユーザ拡張スクリプト(jsファイル)で独自コマンドを定義する。
http://oss.infoscience.co.jp/seleniumhq/docs/08_user_extensions.html

ユーザ拡張スクリプト(jsファイル)の設定箇所
Selenium IDE>オプション>設定>Selenium Core 拡張スクリプト(user-extensions.js)

ユーザ拡張スクリプトの例

Selenium.prototype.doEchoUsername = function() {
	// 独自コマンド echoUsername
	// store変数USERNAME をログに表示する

	// Selenium IDEのログに表示する
	this.doEcho( storedVars.USERNAME );

};

cakephp plugin CryptoDbをgithubで公開しました

github / ninton / cakephp.CryptoDb

特徴
1) 平文と暗号キーがMySQL binlogに残りません。

2) ivを毎回生成します。そのため同じ平文、同じキーで暗号化しても同じ結果になりません。
(暗号データにivを含んでいます)

----------------------------------------
MySQL field type	CryptoDb support
----------------------------------------
text			recommended
varchar(255)		plaintext length <= 32

----------------------------------------
設定手順
----------------------------------------
YourModel.messageを暗号化してDB保存したい場合

1) edit App/Config/bootstrap.php

CakePlugin::loadAll(array(
  'CryptoDb' => array('bootstrap' => true),
));

2) create plugins/CryptDb/Config/bootstrap.php

Configure::write( 'CryptoDb.cryptoKey', 'Your Cryptography Key' );

plugins/CryptDb/Config/bootstrap.sample.phpも参照してください。

*注意*
サービスを開始したら、暗号キーを変更してはいけません。
古いキーで暗号化したフィールドは、新しいキーで復号できません。

3) edit App/Model/YourModel.php

App::uses()、extends Crypto、$cryptoFieldsの3点を編集してください。

App::uses('Crypto', 'CryptDb.Crypto');
class YourModel extends Crypto {
    public $cryptoFields = array(
        'message'
    );

4) call save() and find()

暗号/復号処理を記述する必要はありません。

// save()に平文を渡してください。
$data['YourModel']['message'] = 'This is my secrets';
$YourModel->save( $data );

// find()を呼ぶと、平文が返ってきます。
$data = $YourModel->find('first');
echo $data['YourModel']['message'];
--> 'This is my secrets'

phpMyAdmin (or mysql command) で直接データベースを見ると、暗号化されています。
--> 'a:4:{s:4:"algo";s:12:"rijndael-256";s:4:"mode";s:3:"cbc";s:2:"iv";s:44:"56...'

----------------------------------------
CakeTest fixture
----------------------------------------
CakeTestのfixtureには、暗号化したデータを記述してください。
記述したとおりにINSERTされます。

----------------------------------------
暗号化せずに、saveする方法
----------------------------------------
save()ではなく、saveAll()を使います。

$params['callbacks'] = false;
$this->saveAll($data, $params);

----------------------------------------
復号せずに、findする方法
----------------------------------------

// way-1.
$this->virtualFields['hoge_raw'] = 'hoge';
$data = $this->find('all', $params);
		
// way-2. 
unset($this->cryptoFields['hoge']);
$data = $this->find('all', $params);

jquery.jpostal.js ver2.1をリリース

郵便番号から住所入力するjQueryプラグインです。
郵便データは 2014-06-30版です。

⇒郵便番号から住所入力のサンプルフォーム

公開サイト
https://github.com/ninton/jquery.jpostal.js

https://code.google.com/p/jpostal/

既存フォームにjquery.jpostal.jsを設定する作業のご依頼、弊社サーバの郵便データファイルのご利用申し込みをお待ちしています。
料金について

※githubまたはgooglecodeからダウンロードして、ご自分のサイトにご自分で設定する場合は無料でご利用できます。

ディールシャッフルをランダム順に配ってみると

去年からジン・ラミーというカードゲームで遊ぶようになった。そしてシャッフルに興味を持ち、ヒンズーシャッフルより良いシャッフル手法について検討した。

1. シャッフルの手法

カット

 1組の山を2つに分けて、上下を入れ替える。シャッフル後に1回カットする、という使い方をする。1組の山をリング状と考えると、カードの並びは変化しないため、カットだけを繰り返してもシャッフルとしては不十分である。

ヒンズーシャッフル

 日本で一般的なシャッフル手法。ときどき手さばきを失敗してカードを撒き散らしてしまう。充分にシャッフルするために延々とヒンズーシャッフルすることがあるが、本当にシャッフルできているか、シミュレーションで確認したい。

ウォッシュシャッフル

 カードをテーブルに広げ、手でかき混ぜる。最後にカードを揃えることが手間であり、時間もかかる。

ファローシャッフル

 1組の山を2つに分けて端同士を押し付けて、互い違いにかみ合わせる。慣れると1枚づつ互い違いにかみ合わせることは難しくなく、この場合のランダム性は山の分け方だけである。

ディールシャッフル

 1組の山から1枚づつ順にいくつかの山に配る。配り終えたら、1組の山にまとめる。隣り合ったカードが離れることが長所である。時間がかかる。並び方にランダム性はない。

2. 理想的なシャッフル

 テーブルに52枚のカードを並べる場所を用意する。PC152をランダムに表示しながら、1組の山から順に表示された場所へ置く。52枚を置き終えたら、1組の山にまとめる。ところが52枚を並べるために広いテーブルが必要である。

3. ランダム順に置くディールシャッフル

 ディールシャッフルは時間はかかるが、カードの操作は易しく練習する必要はない。そこでディールシャッフルで山に配るとき、ランダムな順番で山に配ったらどうだろうか。以下「ランダムディール」と呼ぶことにする。

4. シミュレーションプログラムについて

 カード番号0,1,2,3のカード4枚の並び替えで説明する。カードの並びを配列で表現する。配列の添え字がカード位置、配列の内容がカード番号である。

シャッフル前:カード配列 = [ 0, 1, 2 ,3 ]

シャッフル後:カード配列 = [ 1, 3 ,0, 2 ]

 集計用の配列を2次元で、横軸をカード番号、縦軸をカード位置で表現し、内容を出現回数とする。試行1回ごとに集計し、集計配列1[カード番号][カード位置] +1 する。

カード位置

カード番号

0

1

1

3

2

0

3

2

カード番号

0

1

2

3

カード位置

0

0

1

0

0

1

0

0

0

1

2

1

0

0

0

3

0

0

1

0

 次に、シャッフル前の隣合ったカードの位置の変化を調べた。試行1回ごとに、集計配列2[カード番号][距離] +1 する。

A

B

C

D

E

カード番号

カード位置

A–1

カード番号

Cのシャッフル後の

カード位置

距離

B-D

0

2

3

1

1

1

0

0

2

-2

2

3

1

0

2

3

1

2

3

-1

Aカード番号

0

1

2

3

E距離

0

0

0

0

0

1, -3

1

0

0

0

2, -2

0

1

1

0

3, -1

0

0

0

1

 同様の要領で、シャッフル前の一つ飛びのカード、2つ飛びのカードとのシャッフル後の距離を集計配列3、集計配列4に保存した。

5. 集計結果の可視化

 文献1でシャッフルのシミュレーション結果をグレイスケール画像で表現している。これを集計配列14を画像14に画像化した。

6. シミュレーション結果

 310は各シャッフル手法を10000回シミュレーションしたものである。

 左から画像14とする。画像14とも、均一になっていることが望ましい。

 ヒンズーシャッフルは、切る枚数を420の一様分布とし、山がなくなるまで切ったら、1回と数える。ヒンズーシャッフル(3)は、これを3回繰り返し、試行1回とした。

shuffle_sim

1

シャッフル前のソートされた初期状態
画像
1は、左上から右下へ直線である。
画像
2は、全カードで距離=1
画像
3は、全カードで距離=2
画像
4は、全カードで距離=3となっている。

2

位置10でカットした状態
画像
24とも初期状態と同じであり、並び順に変化がないことがわかる。

3

ランダム:疑似乱数で並び替えた
すべての画像が均一となっている。

4

ランダムディール(5)
画像
1の右上角と左上角が黒く、先頭の数枚は末尾へ、末尾の数枚は先頭へ移動しやすいことがわかる。山の数と同じ縞模様がある。
画像
2は上部に白い部分があり、距離=51に集中がある。隣同士のカードは、同じ山に配れば隣のまま、違う山に配れば1山分の枚数(5山では約10)離れる。つまり隣同士だったカードは、29枚離れる可能性が非常に小さいためである。

5

ランダムディール(10)
5
山と比較すると、より均一になった。
画像
1の距離=51の集中は残っている。

6

ヒンズーシャッフル(3)
画像
1には左上から右下への縞模様がある。
画像
2を見ると、初期状態の画像2とほぼ同じであり、距離=1に集中している。隣り合ったカードの位置は変化しにくいことがわかる。

7

ヒンズーシャッフル(10)

8

ヒンズーシャッフル(20)
画像
1はほぼ均一である。標準偏差は19とランダムディール(10)より小さく、ランダムの13に近い。
画像
2は、距離=1の集中が残っている。

9

カット+ランダムディール(10)+カット
画像
1はほぼ均一であり、標準偏差もランダムとほぼ同じである。
画像
2の上部の白い部分、距離=51の集中は残っている。

10

カット+ヒンズーシャッフル(20)+カット
画像
1はほぼ均一になった。
画像
2の距離=1の集中は残っている。

 次に、隣合ったカードがシャッフル後も隣り合ったままの確率を調べた。画像2で距離=1や距離=51の集中が濃いほど確率は高い。

確率=Σ(集計配列2[カード番号][1]+集計配列2[カード番号][51]) / 52 / 試行回数

シャッフル手法

隣合ったカードが
隣り合ったままの確率

ランダム

0.0392

ランダムディール(5)

0.1998

ランダムディール(10)

0.1018

ヒンズーシャッフル(3)

0.7768

ヒンズーシャッフル(10)

0.4600

ヒンズーシャッフル(20)

0.2276

7. まとめ

 ヒンズーシャッフルは、隣合ったカードが隣のままの確率が高いことがわかった。ヒンズーシャッフル(3)78%、ヒンズーシャッフル(10)46%、ヒンズーシャッフル(20)でも23%もある。延々とシャッフルしても隣合ったカードをよく混ぜるのは難しいことがわかった。

 ランダムディールの隣だったカードの移動先には特徴があり、隣同士のままか、山1つ以上離れるかである。ディールシャッフルの配り方を考えれば当然であるが、画像2を見るまで思いつかなかった。逆順にはなるが隣のままの確率は、ランダムディール(5)20%、ランダムディール(10)10%である。

 標準偏差はヒンズーシャッフル(20)が良く、隣合ったカードではランダムディール(10)のほうが良かった。

 実際に手でシャッフルするとどちらも約1分とほぼ同じである。私の場合は、ヒンズーシャッフル(20)のほうが失敗してカードを撒き散らしやすいので、ランダムディールを主に使っている。つまりゲーム前にノートPCを見ながらカードを配ってシャッフルし(末尾のリンク参照)、あらためてゲームのためにカードを配っている。

参考文献

  1. 野瀬彰大、深川大路:TCGにおけるシャッフル手法に関する計算機実験を用いた考察, 情報処理学会研究報告, Vol.2011-GI-25 No4 (2011).

リンク
FlickPass>シャッフルナビ
ソースコード( cakePHP plugin) https://github.com/ninton/ShuffleSim

FlickPass:パスワード生成

FlickPassにパスワード生成ページを追加しました。
FlickPass

パスワード16文字を生成したい場合は、[パスワード(8文字)]を2回クリックしてください。

パスワード12文字を生成したい場合は、[パスワード(8文字)]を2回クリックして、4文字削除してください。

リーダブルコードcakePHP版?find()の引数並びにarray()を記述しない

cakePHPの公式サイトには次のようなサンプルコードがある。引数並びにarray()を記述している。

$allPublishedAuthors = $this->Article->find('list', array(
	'fields' => array('User.id', 'User.name'),
	'conditions' => array('Article.status !=' => 'pending'),
	'recursive' => 0
));

この書き方のメリットは、下記の書き方と比較するとわかりやすい。array()を$paramsなどの変数に代入していないので前後の変数との関連を考えなくてもいいこと(下記 A,C)、この1まとまりの処理の途中に無関係なコードを記述できないこと(下記B)だと思う。

//A. これ以前に$paramsに代入しているだろうか?
$params = array(
	'fields' => array('User.id', 'User.name'),
	'conditions' => array('Article.status !=' => 'pending'),
	'recursive' => 0
);
//B. ここに無関係なコードを記述できてしまう。
$allPublishedAuthors = $this->Article->User->find('all', $params);
//C. これ以降に$paramsを参照しているところがあるだろうか?

しかし実務では次のデメリットのほうが大きいと思う。

1つ目は、引数並びが長すぎて読む気力が萎えてしまうこと。find()の閉じ括弧までが長すぎて、頭の中のスタックのプッシュ量が多い感じがする。

2つ目はデバッグしにくいこと。printデバッグしたくても、引数並びのarray()のままではvar_dump()できない。eclipse+xDebugでトレースする場合も、引数並びのarray()を表示することはできない。ソースファイルがあれば関数へステップインすると表示できるが、組み込み関数の場合はステップインもできない。

次のようにしたほうが読みやすくデバッグもしやすいと思う。

$params = array(
	'fields' => array('User.id', 'User.name'),
	'conditions' => array('Article.status !=' => 'pending'),
	'recursive' => 0
);
$allPublishedAuthors = $this->Article->find('list', $params);

さらに、array要素を1行1要素にすると、gitで直前のリビジョンとdiffしたとき変更箇所がわかりやすい。

$params = array(
	'fields' => array(
		'User.id',
		'User.name',
 	),
 	'conditions' => array(
 		'Article.status !=' => 'pending',
 	),
 	'recursive' => 0,
);
$allPublishedAuthors = $this->Article->find('list', $params);

アクション内で$this->XXX->find()を何回も呼んでいて行数が多いと感じたら、それぞれのfind()呼び出しをモデルのメソッドにするといいと思う。モデルのメソッドにすれば1行で呼び出すことができ、前後の変数との関連はないし、一連の処理の途中に無関係なコードの記述もできない。

$allPublishedAuthors = $this->Article->find_list_ArticleStatusIsPending();

なお、viewの$this->input()の2つ目の引数は、ロジックとは関係がないhtmlタグやcssなどが多く、引数並びにarray()を記述したほうが読みやすいと思う。

関連:リーダブルコード 8章 巨大な式を分割する

gitのブランチの名前の付け方

かつてSubversionを使っていたときは、ほとんどブランチを使ったことがない。慣例にしたがってtrunk、branches、tagsを用意するものの、trunkだけを使っていた。ブランチとタグの違いを理解していなかった。ブランチ操作を難しいものと思い込んでいたし、「変更履歴」と「以前の状態と比較できる」だけで満足していた。

gitを使うようになってからブランチ/マージを試してみたら、あっけないほど簡単だった。日常的にmasterブランチと開発ブランチを使うようになった。

するとブランチの名前の付け方を考えるようになった。最初はmasterとwork。次の段階では、チケット番号をつけてwork_1234 や ticket_1234で作業するようになった。この程度のざっくりとした運用で問題はないのだが、標準的なブランチ名の付け方や運用方法があるなら、知りたいと思っていた。

素晴らしい記事を発見した。ブランチは5個あるが、各ブランチの目的と運用方法が明確で迷うことはないと思う。

O-Showさんの日本語訳
http://keijinsonyaban.blogspot.jp/2010/10/successful-git-branching-model.html

Vincent Driessenさんの原文”A successful Git branching model
http://nvie.com/posts/a-successful-git-branching-model/

中央リポジトリ(例 github)

・master 現在の製品バージョン。
・develop 次回リリースの開発用。

開発者リポジトリ

・feature- 新規機能の開発用。developから分岐し、developへマージする。
・release-
 次回リリースの準備用。developから分岐し、developとmasterへマージする。
・hotfix-* 現在の製品バージョンのバグフィックス用。masterから分岐し、developとmasterへマージする。

※このブランチモデルをベースにしたgit-flow というプラグインもある。

gitブランチの名前の付け方2