« 2010年10月 | メイン | 2010年12月 »

2010年11月17日

ジンガジャパンの壁
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちはhohtaです。オフィスが新しくなってからはや1ヶ月、移動したばかりの時はひろびろーとした感じでしたが採用活動が順調らしく、人口密度が上がってきました。

さて、提題の件ですが今回は技術的な話からちょっと離れて弊社にある壁を紹介したいと思います。一口に壁と言っても言語の壁、文化の壁、人生の壁、ぬりかべなど概念的なものから建物の壁面といった物理的なものまで様々ですが、この記事で扱うのは物理的な壁、新オフィスに作られているクライミング(ボルダリング)用の壁を紹介します。

どんな壁?

クライミング1

こんな壁です。全長7m、高さ2.2mで手前が垂壁(90度)、奥が110度と角度がついています。建物の構造上高さが少し物足りないですが、そこは課題をトラバース(横移動)メインにしてカバーです。ちなみに、マットは埋込式ではなくボルダリング用のクラッシュパッドを登るときに敷いて使っています。埋込式と違ってスペースが無駄になりません。

業者さんに初期の段階で設定していただいた課題は長物30手、足自由4課題、足限定1課題です。専用の靴を履かなくても楽しめるように足は大きめのものが多くなっています。課題は今も生産中ですが、僕しか作る人がいないので作ってくれる人募集です。

実際は登ってないんじゃ?

クライミング2

意外とみんな登っているみたいです。大会議室と呼ばれているエリア(オフィススペースから繋がっていて明確な仕切りは無いです)の壁の一部がこうしたクライミングウォールになっているので、人の目が気になる人は仕事が終わってから登っているみたいですし、人によっては専用のクライミングシューズに履き替えて昼から登ってます。

どうやって作ったの?

真面目に企画書を作って提出しました。以前から冗談ベースで同僚と話題にすることはあったのですが、折角オフィス移転というタイミングにも恵まれたので冗談で終わらせずにきちんと話をしてみました。

もしあなたが社内にクライミングウォールを作りたいと思っているなら、理解ある経営陣にその声を届けるために企画書を書いて提出するといいかもしれません。

Google Japanの壁部が遊びにきました

クライミング3

噂を聞きつけてGoogleJapan壁部の方々が登りに来ました。GoogleJapanのオフィスにも壁があるそうですが、ポータブル(といっても持ち運ぶ人はそういないだろうけど)のタイプなのであまり楽しめないという話です。

皆さん色々な課題にチャレンジして凄く楽しんでいただいた様子でした。また遊びに来て下さい。

という感じで弊社の壁の紹介は以上です。オフィスが移転して広くなったらロープ使って登れる場所が欲しいなー、とかもっと傾斜がきつい壁が欲しいなーとか、野望は尽きないので頑張って仕事しようと思います。

Zynga Japanでは特に最近、積極的にエンジニアを採用しています。
採用ページをご覧になり興味のある方、ぜひご応募ください。

2010年11月16日

ASIHTTPRequestを入れてみた
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

ご無沙汰しています。Brandonです。
今回は私がジンガジャパンでやってる実務とまったく関係がないObjective Cのライブラリ「ASIHTTPRequest」を紹介したいと思います。

前の記事の続きをやってたら、たまたま「ASIHTTPRequest」に出くわして、これはなかなかよさそうなのでみんなさんにご紹介しようと思いました。
(もし既に知っていたらどうもすみません。前の記事からまったくiPhone関係の物を触ってなかったこともあって、情報が遅いのは承知しています。)

AppleのiOS SDKに入っているNSMutableURLRequestでHTTPリクエストを送るやりかただと、以下のようなコードになります。
(下記は前の記事の一部の内容になります)

/**
 * リクエスト(requestObj)に認証情報をつける関数
 */
- (void) addAuthToWebRequest:(NSMutableURLRequest*)requestObj username:(NSString*)username password:(NSString*)password{

    NSString *authString = [[[NSString stringWithFormat:@"%@:%@", username, password] dataUsingEncoding:NSUTF8StringEncoding] base64Encoding];

    authString = [NSString stringWithFormat: @"Basic %@", authString];

    [requestObj setValue:authString forHTTPHeaderField:@"Authorization"];
}

/**
 * リクエストを送信する
 */
- (void)sendRequest:(NSString*)address username:(NSString*)username password:(NSString*)password {

    //リクエストの初期設定
    NSString *urlString = [NSString stringWithFormat:address];
    NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
    [request setURL:[NSURL URLWithString:urlString]];
    [request setHTTPMethod:@"POST"];

    //上記のaddAuthToWebRequestで認証情報をリクエストに追加します
    [self addAuthToWebRequest:request username:username password:password];

    NSLog(@"connection attempted");

    [NSURLConnection connectionWithRequest:request delegate:self];
}

//getSites APIリクエスト
-(void)getSites:(NSString*)username password:(NSString*)password {
    [self sendRequest:@"https://posterous.com/api/getsites"username:username password:password];
}

//最初にレスポンスが来たとき一度だけだけ実行されます
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    //receivedDataを初期化してデータ受信の準備をする
    receivedData = [[NSMutableData alloc]init];
    [receivedData setLength:0];
    NSLog(@"Set received data length to 0");

    //レスポンスのヘッダー情報をNSLogでコンソールに出力して確認する
    if ([response respondsToSelector:@selector(allHeaderFields)]) {
        NSLog(@"response header");
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
        NSDictionary *dictionary = [httpResponse allHeaderFields];
        NSLog(@"%@", [dictionary description]);
    }
}

//受信したデータをreceivedDataに保存する
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [receivedData appendData:data];
}

//レスポンスが終了したときに実行されます
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
    NSError *error;
    NSLog(@"succeeded! received %d bytes of data", [receivedData length]);
    GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:receivedData options:0 error:&error];
    if (doc != nil) {
        /*
         ...
         レスポンス解析
         ...
         */
    }

    [doc release];
    [receivedData release];
}

ASIHTTPRequestなら、下記のコードのようにより簡単・分かりやすいようにかける。

-(void)getSites:(NSString*)username password:(NSString*)password {
     NSURL *url = [NSURL URLWithString:@"https://posterous.com/api/getsites"];
     ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
     [request setUsername:username];
     [request setPassword:password];
     [self grabURLInBackground:request];
}

- (IBAction)grabURLInBackground:(id)sender
{
     [sender setDelegate:self];
     [sender startAsynchronous];
}

- (void)requestFinished:(ASIHTTPRequest *)request
{
     // テキストデータを取得する場合はこちらを使用する
     NSString *responseString = [request responseString];
    
     // バイナリデータを取得する場合はこちらを使用する
     NSData *responseData = [request responseData];
         
     [responseString release];
     [receivedData release];
}

- (void)requestFailed:(ASIHTTPRequest *)request
{
     NSError *error = [request error];
     //エラー処理
}

ご覧のとおり、コードがかなり短くなり、分かりやすくなります。

パラメータ付けたリクエストを送信するのもより簡単にできちゃいます。

ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request addPostValue:@"Ben" forKey:@"names"];
[request addPostValue:@"George" forKey:@"names"];
[request addFile:@"/Users/ben/Desktop/ben.jpg" forKey:@"photos"];
[request addData:imageData withFileName:@"george.jpg" andContentType:@"image/jpeg" forKey:@"photos"];

他にもqueueなど、色々な機能があります。
英語になりますが、ホームページで使い方の例など色々書かれています。


セットアップする方法をこちらに詳しく書いてあります(英語ですが画像付きなので分かりやすいです)。


日本語記事を検索してみたら他の記事も色々出てきました。


もしまだ使っていない方がいっらっしゃれば、ぜひ使ってみてください!

2010年11月14日

PHPでwin32serviceを使ってみる
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは。yuzoです。
今回はPHPをwindowsのサービスとして動作させるwin32serviceを試してみました。

準備した環境

  • Windows 7 Professional(32bit)
  • PHP 5.3.3
  • win32service 0.1.0-dev

インストール

PHPは「VC9 x86 Non Thread Safe」を利用しました。
http://windows.php.net/download/
どこに配置してもいいと思うのですが、
便宜上

C:\PHP\5.3.3

にインストールしたことにします。
もちろんPATHもとおします。

win32serviceについては、別途こちらからダウンロードが必要です。
http://downloads.php.net/pierre/
今回は「php_win32service-svn20091206-5.3-nts-vc9-x86.zip」を利用しました。
先ほどPHPをインストールした配下、

C:\PHP\5.3.3\ext

にdllをコピーしましょう。

php.iniを配置する

windows7の場合だとphp.iniの格納場所は "C:\Windows" らしいので、
php.exeと一緒にzipに入っていたphp.ini-development(もしくはphp.ini-production)
を "C:\Windows\php.ini" にコピーします。
windows7なんて使わない方は

php --ini

で各自格納場所を調べて下さい。

php.iniを編集する

配置したphp.iniにextension_dirとwin32serviceのextensionを定義します。

extension_dir = "C\PHP\5.3.3\ext"
extension=php_win32service.dll

ついでにtimezoneのWarningがウザイので 、

date.timezone = Asia/Tokyo

を定義しておきましょう。
これで環境は整いました。以下のコマンドで確認してみましょう。

php --re win32service

win32serviceのextension情報が出力されていれば成功です。

サービススクリプトを書く

subversionのサンプルソースを参考に以下のようなソースを準備しました。

C:\PHP\scripts\win32service.php

<?php
/**
 * win32service.php
 * usage:
 * サービス登録 / php win32service.php install
 * サービス解除 / php win32service.php uninstall
 **/
if ($argv[1] == 'install') {
    // win32serviceを登録する
    $x = win32_create_service(array(
        'service'       => 'PHPwin32service',
        'display'       => 'PHP win32service sample', // サービスの「名前」に表示される
        'description'   => 'Zynga is not Janga!',
        'params'      => __FILE__ . ' run',
    ));
    debug_zval_dump($x);
    exit;
} elseif ($argv[1] == 'uninstall') {
    // win32serviceを解除する
    $x = win32_delete_service('PHPwin32service');
    debug_zval_dump($x);
    exit;
} else if ($argv[1] != 'run') {
    die("Woops you are TENGA!!");
}

// SCMへcheckin
$x = win32_start_service_ctrl_dispatcher('PHPwin32service');
// サービス状態の更新
win32_set_service_status(WIN32_SERVICE_RUNNING);

// service loop
while (WIN32_SERVICE_CONTROL_STOP != win32_get_last_control_message()) {
    // ここにservice処理かく
    file_put_contents("C:\PHP\dummy".time().".txt","hoge");
    // ご利用は計画的に
    usleep(2000000);
}
動作確認のため、 "C:\PHP\dummy_{xxxx}.txt" に永遠とファイルを作成し続ける処理を書きました。

サービス登録/実行

それではさっそくサービス実行してみましょう。
以下のコマンドでサービス登録します。

php C:\PHP\scripts\win32service.php install
bool(true) refcount(2)

これでサービスが登録されているはずです。
サービスコンソールで「PHP win32service sample」が存在するか確認してみましょう。

win32service.gif
サービスを開始すると指定した場所 "C:\PHP\" 以下にポコポコとファイルが作られます。
このままファイルを生成し続けるのも困り者なので急いでサービスを停止しましょう。

サービスを解除する

動作確認を終えたので、さっさとサービスを解除します。

php C:\PHP\scripts\win32service.php uninstall


ジンガジャパンでは特に最近、積極的にスタッフを採用しています。
採用ページをご覧になり興味のある方、ぜひご応募ください!!

普段はwindowsを利用する機会がほとんどないのですが、
どうしても利用しなければならなくなった時に試してみるのもいいかもしれませんね。

それでは、またいつかお会いしましょう。

2010年11月12日

自力でUNIX TIMEを計算してみよう
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

 Flashエンジニアのくせに今日もFlashの話題を振らないnaoです。こんにちは。
 クビにならないよう努力はしています。

 今回のお題。何の役に立つのかと問われれば、漢らしく「何の役にもたたん」と答えましょう。しかし、ひょっとしたらいつか、使う日も来るかもしれない。こうして諸葛孔明の様に何事にも用意周到に備える私の部屋はモノで溢れかえっております。みろ、部屋がゴミのようだ。だってさー、PowerBook Duo(270cカラー液晶だぜ)とか、そのうちプレミアつきそうじゃん?いつか本当に必要な時が来たら、その時には声高らかに朗々と「こんな事もあろうかと」と宣言をするのである。

 というわけで今回は、まるで昔使った思い出の品のように、近年すっかり過去の遺物へと変貌し始めているUNIX TIMEです。UNIX TIMEといえば昔Perlのcgiで掲示板スクリプトを作るときなんかにはよく使われましたが、最近ではそこらの無料レンタルサービスでもDBが普通に使えるので、きょう日常用するのはtimestamp型ですよね。人間にも分かりやすいし、なにより遠い未来でも利用できる。それに対してUNIX TIMEは、2038年(2038年問題でググろう)までしか使えません。
 ではなぜ今更UNIX TIMEなのか。それはやっぱり、いつか使うかもしれないじゃん?という個人的なこだわりです。まぁ、使おうと思えばいくらでも使う場面はありますけどね。あえて使う理由も無いんですが。

 UNIX TIMEとは、1970年1月1日0時0分0秒(これをUNIX EPOCHという)より始まるタイムスタンプで、1秒経過すると値が1増えるという非常に扱いやすい性質を持ちます。そのため、例えば1970年1月1日0時1分0秒なら、UNIX TIMEは60というとうに、非常にシンプルです。この性質を利用すれば、例えば現在の時刻が判明すれば、UNIX EPOCHからの秒数を計算して、現在のUNIX TIMEを得ることが出来るのである。今回は、それを計算してみようというわけです。
 勘の良い人はそろそろ気がついたかもしれませんが、実は今回のラボブログ、目的はUNIX TIMEを計算することですが、本質的にはグレゴリオ暦を計算する計算式の話になります。暦が計算できて、UNIX EPOCHからの日数の差分が得られたら、あとはそれを秒数に変換すれば、UNIX TIMEになるのです。

グレゴリオ暦とは
グレゴリオ暦(グレゴリオれき)とは、1582年にローマ教皇グレゴリオ13世がユリウス暦を改良して制定した暦である。現行の太陽暦として世界各国で用いられている。単に新暦(英語:New Style、略称:N.S.、NS)と呼ばれる場合もある。現在使われている西暦はグレゴリオ暦である。
以上、wikipedia グレゴリオ暦より引用。

早い話が、今現在使われている暦の事である。500年近く前に作られたアルゴリズムなんですって。すごいよね。
それでは、さっそくUNIX TIMEの基準となる紀元元年1月1日からUNIX EPOCHまでの経過日数の計算をしてゆきましょう。

閏年の判定の仕方
閏年の判定は、条件式で書くとこんな感じになります。

year % 4 == 0 && year % 100 != 0 || year % 400 == 0

1)西暦を4で割って余りが0(4の倍数)の年は閏年
2)だけど100で割って余りが0(100の倍数)の年は除外して
3)なおかつ400で割った場合に余りが0(400の倍数)の年はやっぱ例外的に閏年

ということですね。

 これだけ理解しておけば、何かしらのプログラミング言語であれば、forとか構造体を使って暦の紀元元年1月1日からの経過日数を計算できますが、そこは公衆の面前に晒されるラボブログの記事。もう一歩突っ込んで、公式を使ってイッパツで計算しましょう。まぁ、誰にも見せないコードの中身だったら、面倒だから何も考えずforとかで回しちゃいますけどね。

グレゴリオ暦換算紀元0年1月1日からの経過日数の数え方
ここに「Fairfieldの公式(フェァフィールドのこうしき)」という非常に素晴らしい公式があります。こんなに素晴らしいのに、何故かマイナー。google先生にお伺いしても、あんまり情報がありませんが、今回はコレを使います。

Fairfieldの公式による経過日数の算出
365*(y-1)+[y/4]-[y/100]+[y/400]+31+28+1+[306*(m+1)/10]-122+(d-1)

さぁ、ややこしいモノが出てまいりました。まずは、順を追って見ていきましょう。

365*(y-1)


まずここは簡単。計算したい日の前年までの年数*1年の日数ですね。

+[y/4]-[y/100]+[y/400]

次にこちら。ここは、閏年の処理ですね。[ ]の記号はガウス記号ってヤツで、int()と同じ小数点以下切り捨てですですが、これは高校とか大学で習うのかどうか知らないので、一応説明しておきました。自分中卒なので。 ここまでで、計算したい日の前年までの日数が出ます。

+31+28+1+[306*(m+1)/10]-122+(d-1)

で、問題はこちら。ここが公式の決定的な肝であり、難関でもあります。 ざっくりと説明すると、この公式では1年間を3月〜14月として計算することで、2月の最終日を1年間の最後の日として扱うことが出来ます。 まず「+31+28+1」この部分が1月と2月(公式中の扱いとしては前年の13月と14月)の日数。 次に「[306*(m+1)/10]」ここが、3月〜12月(公式中では1月〜10月)の日数。 最後に「-122+(d-1)」で、13月と14月の補正と、計算したい日の当月の日数になります。

ざっくりとした説明になりましたが、こんなものは数字大好きな人が理解していればいいことなので、私のような凡人は、さらにこの式を発展させて、以下のような式を使います。

365 * y + [y/4] - [y/100] + [y/400] + [306 * (m+1) / 10] + d - 428

「428」って何よ、とか言わないでください。元の式を計算すると、まぁなんとなくこんな感じになります。13月と14月の分と、1年の始まりが3月からになるようにしていた分を全部予め計算しておくと出る数字です。
数学が大の苦手の私的には、こっちがありがたい。

それでは、早速基準となるUNIX EPOCHである1970年1月1日0時0分0秒までの経過日数を計算しましょう。

365 * 1970 + [1970/4)]- [1970/100] + [1970/400] + [306 * (1 + 1) / 10] - 428 + 1 = 719161
 これで、UNIX EPOCHは、グレゴリオ暦換算紀元元年1月1日から719161日経過している、という事がわかりました。  次は、この719161を起点として、そこから何日経過しているかを計算します。
_EPOC_TIME = 719161;
// Fairfieldの公式で算出した719161日からの経過秒数の算出
diff = ((365 * year + int(year / 4) - int(year / 100) + int(year / 400) + int(306 * (month + 1) / 10) - 428 + day) -  _EPOC_TIME) * 24 *60 * 60;

せっかくなのでFlash Lite 1.1のActionScriptで書いてみました。
これに、時刻を足してあげれば、UNIX TIMEの完成です。

_EPOC_TIME = 719161;
UNIX_TIME = ((365 * year + int(year / 4) - int(year / 100) + int(year / 400) + int(306 * (month + 1) / 10) - 428 + day) -  _EPOC_TIME) * 86400 + (hour * 3600) + (minute * 60) + second;

ほら1行でできた。エンジニアっぽいっ!

 今回はグレゴリオ暦の計算を用いてUNIX TIMEを導き出したわけですが、これを応用すれば、いろいろな事が計算できます。例えば、グレゴリオ暦換算の紀元元年1月1日は月曜日なので、Fairfieldの公式による経過日数を7で割った余りで曜日が判定できます。余り0なら日曜日。6なら土曜日。ちなみに、この割り算の"余り"を求める事をモジュロ演算と言います。演算子の"mod"や"%"のヤツ。サマーウォーズで見たよね?こいつのおかげで、ケンジは得意げになりナツキ先輩はメロメロなわけである。みんな覚えておこう。いつか「こんな事もあろうかと」という日が来るかもしれない。

 余談ですが、宇宙戦艦ヤマトの工場長兼技師長である真田志郎氏といえば「こんな事もあろうかと」で有名ですが、wikipediaによると劇中にそんなセリフは無いそうです。

えー、がっかりー。


About 2010年11月

2010年11月にブログ「ウノウラボ by Zynga Japan」に投稿されたすべてのエントリーです。過去のものから新しいものへ順番に並んでいます。

前のアーカイブは2010年10月です。

次のアーカイブは2010年12月です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

Zynga Japan