2010年12月17日金曜日

下にスクロールしたら更新ができるアレ

iPhoneアプリで下にググーっとスクロールすると更新が出来るUIありますよね。


これこれ。Twitterの公式アプリにも実装されています。

このUIあんまり好きじゃなかったんですけど、GoogleのアプリでもこのUIが採用されたっぽいし、
標準UIになっていくのかなぁー 実装してみるかなぁー とググっていたのですが...

キーワードが分からない!

なんとかたどり着いたキーワードは

pull to refresh

でした。

Pull かー。なるほどなー。
swipe down とかかな?と思って入れてたのですが、確かに Pull ですね、なんだか凄く納得。

MailアプリをこのUIにする 「Pull To Refresh for Mail」というアプリがあるらしい。
https://github.com/leah/PullToRefresh ここにサンプルコードがあるみたいなので、これを参考に作ってみますー。
• • •

2010年12月13日月曜日

パスワード管理ソフトCIPHERリニューアルしました


以前作成していた、パスワード管理ソフト CIPHER を移行しました。

ダウンロードできるサイトはこちらになります。 aqubi products / cipher
リニューアルしたので、以前のアプリを入れてた場合には一度アンインストールしてから入れて下さい。
DBファイルを同じにすればデータは引き継ぎできます。
ソースの管理もassemblaからbacklogに変えていますので、ソースの参照ができなくなりました。

ちなみに、このソフトの特徴は

マルチプラットフォーム


AdobeAIRで作成されていますので、Windows,Mac,Linuxで使用が可能です。

保存データの持ち運びが可能


保存されたデータは暗号化DBファイル(SQLite)として保存されます。
パスワードはOSに保存され、DBとは別管理になりますので、DBファイルだけ漏れても中身を開くことは出来ません。そのため、複数のPCより同じデータを共有したい場合、USBメモリや、Dropboxなどで同期した共有フォルダにDBファイルを置くことも可能です(最終的には自己責任でおねがいします)

です。
メモが書ける所も大きな領域で用意しているので、パスワードに限らず、漏れたくないメモを入れておくのもよいかも?

よければお使いくださいー

#あとは、ASlimTimerも同じように移行する予定です。
• • •

2010年12月6日月曜日

iPhoneアプリ開発-邪魔にならないメッセージウィンドウ

loadingのぐるぐるイメージを標準で表示できることを最近知って衝撃を受けているaqubiです。こんばんは。

YES/NOダイアログを表示するほどでもないけど、メッセージを通知したい...ということで、
下や上から、にょきにょきっ と表示されるUIViewを作成してみました。



下の方にある [network not connection]って表示されている所です。
下からにょきにょきっと出てきて、数秒後にするするっと下に下がって消えていきます。

イメージのように角丸にしたくて検索していたのですが、よく引っかかる

view.layer.cornerRadius = 5;

という方法が最新のSDKではできないんですかねぇ?
結局ごりごり書いてます。

UIViewのアニメーションは beginAnimations, commitAnimations + 最初と最後の値を指定 すれば、途中の状態は勝手に補完してくれるんすね。エライ。

MessageBoard.h



//
// MessageBoard.h
// CrossBacklog
//
// Created by aqubi on 10/12/05.
// Copyright 2010 aqubi. All rights reserved.
//
typedef enum {
MessageBoardTop,
MessageBoardBottom
} MessageBoardPosition;

@interface MessageBoard : UIView {
UILabel *label;
UIView *parentView;
MessageBoardPosition position;
}

@property (nonatomic, retain) UILabel *label;
@property (nonatomic, assign) MessageBoardPosition position;

+ (MessageBoard *)showMessageBoard:(UIView *)view message:(NSString *) message;
- (void)fillRoundedRect:(CGRect)rect inContext:(CGContextRef)context;
@end


MessageBoard.m



//
// MessageBoard.m
// CrossBacklog
//
// Created by aqubi on 10/12/05.
// Copyright 2010 aqubi. All rights reserved.
//

#import "MessageBoard.h"

@implementation MessageBoard
@synthesize label;
@synthesize position;

int height = 26;
float backgroundAlpha = 0.75f;
float radius = 10.0f;

- (id)initWithView:(UIView *) view {
if (self = [super init]) {
self.opaque = NO;
self.backgroundColor = [UIColor clearColor];
parentView = view;
CGRect rect = CGRectMake(0, - height, parentView.bounds.size.width, height);
self.frame = rect;
label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, rect.size.width, 20)];
label.adjustsFontSizeToFitWidth = NO;
label.textAlignment = UITextAlignmentCenter;
label.opaque = NO;
label.backgroundColor = [UIColor clearColor];
label.textColor = [UIColor whiteColor];
position = MessageBoardBottom;
[self addSubview:label];
}
return self;
}

- (void)dealloc {
[label release];
label = nil;
[super dealloc];
}

- (void) show {
CGPoint startPoint;
if (position == MessageBoardTop) {
startPoint = CGPointMake(parentView.bounds.size.width / 2.0, - height / 2);
} else {
startPoint = CGPointMake(parentView.bounds.size.width / 2.0, parentView.bounds.size.height + height / 2);
}
CGPoint endPoint;
if (position == MessageBoardTop) {
endPoint = CGPointMake(parentView.bounds.size.width / 2.0, height / 2);
} else {
endPoint = CGPointMake(parentView.bounds.size.width / 2.0, parentView.bounds.size.height - height / 2);
}

self.center = startPoint;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(_didEndAnimation)];
self.center = endPoint;
[UIView commitAnimations];
}

- (void) _didEndAnimation {
[NSThread sleepUntilDate:[[NSDate date] addTimeInterval:2]]; //wait
CGPoint endPoint;
if (position == MessageBoardTop) {
endPoint = CGPointMake(parentView.bounds.size.width / 2.0, - height / 2);
} else {
endPoint = CGPointMake(parentView.bounds.size.width / 2.0, parentView.bounds.size.height + height / 2);
}
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
self.center = endPoint;
[UIView commitAnimations];
}

- (void)drawRect:(CGRect)rect {
CGRect allRect = self.bounds;
CGRect boxRect = CGRectMake(1, 0, allRect.size.width - 2, allRect.size.height - 2);
CGContextRef ctxt = UIGraphicsGetCurrentContext();
[self fillRoundedRect:boxRect inContext:ctxt];
}

- (void)fillRoundedRect:(CGRect)rect inContext:(CGContextRef)context {
CGContextBeginPath(context);
CGContextSetGrayFillColor(context, 0.0, backgroundAlpha);
CGContextMoveToPoint(context, CGRectGetMinX(rect) + radius, CGRectGetMinY(rect));
float topRadius = radius;
float bottomRadius = radius;
if (position == MessageBoardTop) {
topRadius = 0.0f;
} else if (position == MessageBoardBottom) {
bottomRadius = 0.0f;
}
CGContextAddArc(context, CGRectGetMaxX(rect) - topRadius, CGRectGetMinY(rect) + topRadius, topRadius, 3 * M_PI / 2, 0, 0);
CGContextAddArc(context, CGRectGetMaxX(rect) - bottomRadius, CGRectGetMaxY(rect) - bottomRadius, bottomRadius, 0, M_PI / 2, 0);
CGContextAddArc(context, CGRectGetMinX(rect) + bottomRadius, CGRectGetMaxY(rect) - bottomRadius, bottomRadius, M_PI / 2, M_PI, 0);
CGContextAddArc(context, CGRectGetMinX(rect) + topRadius, CGRectGetMinY(rect) + topRadius, topRadius, M_PI, 3 * M_PI / 2, 0);
CGContextClosePath(context);
CGContextFillPath(context);
}

+ (MessageBoard *)showMessageBoard:(UIView *)view message:(NSString *) message {
MessageBoard *board = [[[MessageBoard alloc] initWithView:view] autorelease];
board.label.text = message;
[view addSubview:board];
[board show];
return board;
}

@end


使うときは
[MessageBoard showMessageBoard:view message:@"メッセージ"];
で。

既にそういう便利なものがあるとか...こうした方がもっといいよ..とかあれば指摘してもらえると嬉しいです。
• • •

2010年12月2日木曜日

MBA11インチとWiMax

MBA11インチとWiMaxのUSBタイプを購入しました。

今は会社帰りの喫茶店。
いつでもどこでもマシンがあり、ネットがある幸せを噛み締めています。

自宅にはMBP13インチもあるので、MBA買ってもつかうかなぁ? と思っていましたが、
常に持ち運びができるサイズなので結構使います。
自宅でも、RPGゲームをしている際に攻略ページをみながらやるとかにも...w

WiMaxは、UQFlat年間パスポート 3,880円/月 にしました。
価格.comだと、イー・モバイル/UQ WiMAX/FOMA/ソフトバンク 高速モバイル比較というのがあって、なんやらいろいろ割り引きがあって最初の1年は2,580円/月というプランもあったんですが、どうせ何年も契約するんだろうしー ということで本家のやつにしてしまいました。

WiFiルータにするか、USBタイプにするかも迷ったんですが、マシンの充電がまだ残っているのにルータの充電池終了というのは悲しい&充電面倒 なのでUSBタイプに。まぁ、基本は一人で使うことの方が多いでしょうし。
連続8時間つなげれるという噂のAtermWM3500Rも気になったんですが..ね。

こうやって契約していくと、家で使っているやつの契約がなんだかもったいなく思ってきてしまいます。
いっそ解約して、家でもモバイルWifiって手もあるよなぁー
• • •

2010年10月27日水曜日

BacklogのiPhoneアプリ作成中

BacklogのiPhoneアプリをちまちま作っています。
マルチアカウントを設定できて、表示するプロジェクトも任意に設定。
指定プロジェクトのみ一元化して表示。ブックマークを付ける事が出来る。という特徴のアプリになっています。
名前はまだありませんw

画面はこんな感じ。


↑では、会社で使っているBacklogアカウントと、空うさぎのBacklogアカウントを同時に表示しています。
まとめてみたかったので作ってみたのですが、やっぱりプロジェクト毎に見れる画面もあった方が嬉しいかも...と迷ってはいますw
足跡のマークを押すと、ブックマークされます。かわいいでしょ?!

コメントの登録は作成したのですが、課題の登録/更新はまだ出来ていません...
アイコンは、http://glyphish.com/ の freeのものをとりあえず使ってます。これは Creative Commonsライセンスなんですが、正式に使う事にした場合iPhoneアプリではどのようにするのは一般的なんだろう...

さてさて、このアプリは、始めてのiPhoneアプリなので、もぅめっちゃググりまくりで作ってます。
後々コードを見直すことがあった場合、もぅ恥ずかしいコードなんだろうなぁ....(笑

MA6に登録したかったのですが、もう間に合いそうにないので断念。無念。
代わりに空うさぎを再び登録しましたがw

ここまで作ったので、Storeに登録するまで頑張ろうかとー!
• • •

2010年10月3日日曜日

GDD2010にボランティア参加してきました

Google Developer Day2010@東京 が先週9/28に行われました。

今回、ボランティアとして、8/27のbootcamp 8/28のGDD に参加してきました。
bootcampでは受付を、GDDでは進行アシスタントを担当。

進行アシスタントは始めての経験でとても楽しかったです。
いた会場はB5-2。聞けたセッションはその部屋のものだけになってしまいましたが、一番前の特等席&机付き で聞く事ができました♪
...とはいえ、無線は飛び交うし、終了間際になったら時間も気にしなくてはいけないし、忘れ物を届けたり...とバタバタしてあまりゆっくり聞ける感じではありませんでしたがw

海外のスピーカーが多い部屋だったんですが、英語が話せたらもっと交流ができたのに..と残念。
Googleの海外のスピーカーの方は、終わり際に ありがとうと声をかけてくれたり、握手をしてくれたり..とスタッフへの配慮も忘れずしてくれるのに感動。さすがー。

無線で進行の方の話が聞こえてきて、動きを色々知る事ができました。
何か問題があった場合には、リーダーに無線が入るのですが、多分リーダーの方はすぐ聞いて動けるよう、他の作業はせずにその事に集中している感じでした。
人が多くないと難しい所もあるとは思いますが、それなりの規模だったら必ず必要だろうなぁと思いました。
あと、色々トラブルが発生していて、連携もうまくいっていない場面があったのですが、個々人がちゃんと判断して動いていく場面にも遭遇しました。

ただ、思ったのが、
Googleのイベントだけど、ITには特に強いイベント会社って訳ではないのだなぁ...と。
進行がオンスケで進むのは確かに一番重要かとは思うのですが、こぅいぅIT系のセッションは、ネットがつながる状態になっているか?というのも結構重要だと思います。
会場に来れない人は、USTやTwitterなどで状況を知る訳ですし、人数としても会場来る人よりも多いかもしれない。

そう思うと、GDDに限らず大きいイベントで無線がちゃんと入るイベントって結構少ない気がします。
無線の用意だけしてそれでOK!...とはだいたいならないですよねw

...とはいえ、私自身は、結局なにも出来ませんでしたが、無事に終了してよかったです。

最後に、ボランティアですが...
社会人として参加するのはやっぱり大変だなぁーと思いました。
当日だけなら、有給とってしまえばOKなのですが、それまでのボランティア講習会がナカナカ。3回程あったのですがその都度早退の届けを出すのはやっぱり白い目で見られそうです。。
会社として、このイベントのボランティアに参加するなら認めるよ、どう? と最初から言ってくれる ぐらいでないと難しいだろうなぁ

ボランティアの人は、大学生の人がやっぱり多かった。
「教授にいってこい」と言われてきた方がそこそこいました。大学生だから時間があるという訳ではなく、まぁ一緒だよなw と思いました。

ヌーラボは、そこらへんは融通が聞く会社なので(勝手に思っている?)、また機会があればやってみようかなぁーと思います。
...つーことで、人手が足りないときは声かけてください!

P.S. ひがさんと佐藤さんがスピーカー控え室にいないと無線でちょっとした騒ぎになっていましたよ(笑
• • •

TwitterUserStreamをAdobeAIRで使う

先日、TwitterのUserStreamが一般公開されましたね!
空うさぎでも早速取り込んでみました。

UserStreamはbeta期間を経て、今回の一般公開になったのですが、beta期間中はそのAPIを使ったツールは公開できないので、開発用空うさぎでのみ使用できるようにしていました。
一般公開になったタイミングですぐ反映できるね!と思っていたのですが、いざ公開されたものを見ると、https通信のみ許可されている形になっていました。

空うさぎは、AdobeAIRを使用しているのですが、AdobeAIRでhttpsのSecureなSocket通信をするには、
Flex4から採用された SecureSocketというものがあるようです。
Flex3(AdobeAIR1.5)を使用していたので、Flex4(AdobeAIR2.0)にアップしようとまずは試みたのですが...断念。
そんなにすんなり移行できるものではなかったようです。。

NativeApplication.nativeApplication.undo()
NativeApplication.nativeApplication.redo()
のメソッドは無くなっている。

UIについてもmxmlのネームスペースをすべて変更が必要。
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">

sのsparkコンポーネントにすると、無くなった(設定方法が変わった?)プロパティが数多くある。
mxにしてみても、無くなった(設定方法が変わった?)プロパティがちょいちょいある。
無理矢理やってみても、見た目が結構ガラっと変わってしまっていて、すんなり移行できない感。

traceを書いても、コンソールに表示されない。
FlashPlayerをデバッグ版にしたらみれる...という記事もありましたが、AIRだとどうなるかは見きれてません。。

その他、
Flex3で作成したアプリケーションを、Flex4でコンパイルしなおすと、違うアプリと認識されるようでした。
ApplicationDescriptor.xmlのxmlsネームスペースのバージョンを変えると違うアプリになってしまう?
何か方法があったのかもしれませんが...

ということで、AIR1.5で、作成する方向を探しました。
結論としては、as3cryptoのライブラリを使って無事にアクセス成功。

import com.hurlant.crypto.tls.TLSSocket;

public static const STREAM_PATH:String = "userstream.twitter.com";
public static const FILTER_URL:String = "/2/user.json";
private static const STREAM_PORT:int = 443;

public function connect():void {
var socket:TLSSocket = new TLSSocket();
socket.addEventListener(Event.CONNECT, connectHandler);
socket.addEventListener(ProgressEvent.SOCKET_DATA, handleData);
socket.connect(STREAM_PATH, STREAM_PORT);
}

private function connectHandler(event:Event):void {
var path:String = "GET " + FILTER_URL + " HTTP/1.1\r\n";
socket.writeUTFBytes(path);
socket.writeUTFBytes("Host: " + STREAM_PATH + "\r\n");

var oauthParameter:String = ...;
socket.writeUTFBytes("WWW-Authenticate: OAuth\r\n");
socket.writeUTFBytes("Authorization: " + oauthParameter + "\r\n");

socket.writeUTFBytes("\r\n");
socket.flush();
}

private function handleData(event:ProgressEvent):void{
var available:int = socket.bytesAvailable;
var value:String = socket.readUTFBytes(available);
trace(value);
}

こんな感じのイメージで。
• • •

2010年9月14日火曜日

iOS Developer Program activation成功/実機で動かすの巻

前回activationに失敗しましたが、contact usから問い合わせした翌日にメールが届きました。
Apple Developer Program Enrollment Update

Dear hideko ogawa,
We are following up with you regarding your recent Apple Developer Program purchase.
We have reviewed your documentation and have removed the hold on your Program activation. At this time, we ask that you please refer to the original activation code email that you received and click through the link once again.
If you have any questions or need further assistance, please contact us.
Best regards,

Apple Developer Support

もう一回試して!ということなので、先日届いたメールのリンクに再度アクセス。

無事にactivation完了ー。

早速、実機で動かす準備。
証明書を作って....の作業は目指せ!iPhoneアプリ開発エキスパート 第9回 デバイスでアプリを動かすを見つつ設定しました。特に迷う所は無し。自分の実機で動作成功。

後は、自分以外の人でもアプリを動かせるようにadhocのビルドを成功したい所ですが、
sukechan.net iPhone Ad hoc ビルドの配布手順のサイトに書かれているようなので、これを参考にしたら出来そうな予感。

とりあえず今日は実機で動かしつつ楽しんでみます。
• • •

2010年9月13日月曜日

iOS Developer Programのactivationでエラー

iOS Developer Programでactivationでエラーが発生するというのは、多分有名なお話。
アカウント情報に日本語が入っていると上手く行かないらしく、日本語が入っていないアカウントを使えというのが先陣の知恵。

ということで、新しいアカウントを作りつつ,iOS Developer Programを申し込んでみた。
だが、クレジットカード入力画面で、カナの入力が必須ときた。
英語入れても通過されないからしょうがなくカナを入力。カナ入っちゃったなら、ま、いいか。と住所も漢字で入力。

翌日届いた、「Apple Developer Program Activation Code」のメールに記載されているURLをクリックすると、
We are unable to activate your Apple Developer Program membership.
We are unable to activate your Apple Developer Program membership because we are unable to successfully verify your identity. Please contact us and reference Enrollment ID# ******** for further assistance.

のエラー。

iOS dev centerの画面を見てみると、
Your credit card and enrollment information do not match. For ID verification purposes, please download and complete this form. Once we've processed your form, we will send you an email to activate.

Please contact us if you have any questions.

クレジットカードの情報が云々...といっている。やっぱ、あの日本語が悪かったのか?!
DevCenterのアカウント情報みると、日本語で書いた住所が文字化け。。これ?
修正してみたけど変わらず。

contact us からエラー内容を貼付けた問い合わせ文章を日本語で送信。
ホントにクレジットカードが間違えていたらどうしようもないな、私w

いやはや、先人達の足跡に感謝。
感謝しつつ、私も足跡残す。
• • •

2010年9月9日木曜日

箸磨きにはαリノレン酸

先日、北海道に行った際に、北大で購入したお箸。


シンプルで良い感じですが、メンテが必要なお箸でした。
合成塗料は使っていなく、食用油を塗って仕上げているとの事。
使い始めの2週間は使う度に、それ以降は1〜2週間毎に一回のオイル磨きが必要のようです。

おすすめされたのが、クルミの油を使う方法。

油の主成分、脂肪酸には
・ほとんど乾かず、皮膜を作らない「オレイン酸 (オメガ-9)」
・少し乾いて、皮膜を作る 「リノール酸(オメガ-6)」
・良く乾いて、皮膜を作る 「αリノレン酸(オメガ-3)」
があり、箸磨きには、「αリノレン酸(オメガ-3)」が良いようです。

「αリノレン酸(オメガ-3)」は、亜麻仁油、しそ油、えごま油、くるみ油 などがあります。
酸化しやすいので購入するのは高価。
でも体に良い脂肪酸で、LDLコレステロールや中性脂肪を減らしたり、免疫力のアップも見込めます。
しかも、体内で作成できない、必須脂肪酸。

いいヤツなんです。

ということで、くるみを購入して、磨きつつ、ポリポリ... しています。
来年になったら、いい味がでたお箸になってればよいな。
• • •

2010年9月8日水曜日

Eclipse DemoCamp Helios 2010 Tokyoに行ってきた

Eclipse DemoCamp Helios 2010 Tokyoに行ってきました。

Eclipse DemoCampは、海外では何回か行われているイベントですが、日本では初開催のようです。
主催は、Eclipse Japan Working Group.
知識不足でEJWGの存在は知らなかったのですが、wikiをみると最近はEclipseの日本語化(Babelプロジェクト)をメインに活動している団体のようです。
Eclipseの日本語化というと、Pleiadesが真っ先に思い浮かびますが、色々あるのですね。

さて、ではセッションをかいつまんで

ここが変わった!Eclipse 3.6 Heliosの新機能: NTTデータ先端技術 竹添直樹
Win64bit版が増えた
JavaEE6対応
GitクライアントがUpdateManagerからインストールができる(まだIncubation)
EclipseMarketplaceにあるものは検索してインストールが出来る

4.0では...
クイックアクセスがToolbarから操作できる
ViewエリアにEditorを配置したり、EditorエリアにViewを配置したりできる。

e4ことはじめ: 日立製作所 鈴川哲大
e4でPluginの作成方法がガラっと変わったお話と、作成デモ。
今までは plugin.xmlに書いていたものが、モデルエディタという所から設定してモデルを作成していくようになる。
UIも、今までswtで書いていたものが、XWTで書くようになる。(wyswygのエディタ付き。)

今までのPluginって全く動かなくなっちゃうんでしょうか??

Eclipse日本語化活動と翻訳支援ツールBenten: NTTデータビジネスブレインズ 伊賀敏樹、NECソフト株式会社 森素樹
日本語化のお話と、Bentenのお話。
翻訳支援ツールってどんなことをしてくれるのかを知らなかったので面白かったです。
原文と訳文をペアで保存した情報(翻訳メモリ)を使って、完全一致している箇所は翻訳済みと解析し、部分一致の部分は一致していない部分のみ未翻訳になる。

翻訳支援ツールを使って、Webサイトの他言語化を簡単に出来ないものだろうか。。。



あとは、リモートデバッグのお話、xTextのお話、Groovy/Grailsのお話、こんぴろさんの10分ライブコーディング がありました。

最後に主催者による、今後のためのアンケートがあったのですが、一番驚いた事件が。
「pluginを作った事がある人」という問いに対して、4割の手が上がっていた事!
そんなにplugin作っている人って世の中に多いの!?うっへーっ!!
...なのにplugin情報ってあまり検索しても引っかからないのですよねー。やっぱ、オープンソースで作っている人は少ない&企業で作っている人も多いのかな。

そもそも、このデモキャンプってそんなに濃いメンバーが集まる場だったんですかね。
てっきり、Eclipseユーザがワイワイ集まる場かと思ってたんですが。

まぁ、濃い内容であることは嬉しい事でもあるので良かったです。

次回も期待しています!
• • •

2010年9月4日土曜日

Twitterで入力できそうな記号達

使えるかもしれんので、メモ。

♥❥★✡✩
☺☻☹
♪♬♫♩♭♯
♀♂☥
√✔☑☒✖✠✜
☚☛☝☟
✂✁✃✄
✍✎✏
☂☃☁☾
❁❀✺✿✾✽✽✵
♞♘♙♟♚♛♕♔♚♜♖♝♗♠♤
♈♉♊♋♌♍♎♏♐♑♒♓✝☨✡☭♅♇
☎✉
✈♨
©®™
☯☢✇❂☮☼
﹅﹆⏎
█□■▱◇◆▲△▼▽▶▷◀◁⊿○●◎◯◉
〆〃ゞ
✌☤♺❦☠☪☄ლω・ิ​

✖_✖

๏_๏

◉_◉

◪_◪

◮_◮

◔_◔

☉_☉

●_●

סּ_סּ

ↁ_ↁ

◔̯◔

(◕︵◕)

(▰˘◡˘▰)

(◑◡◑)

٩๏̯͡๏۶

٩(͡๏̯͡๏)۶

٩◔̯◔۶
• • •

2010年9月1日水曜日

正規表現の前方/後方一致

正規表現の前方/後方一致の書き方をすぐに忘れてしまうのでメモ。

@Test
public void 後方一致() throws Exception {
String value = "ogawa ogawaです。";
String replace = value.replaceAll("ogawa(?=です)", "おがわ");
assertEquals("ogawa おがわです。", replace);
}

@Test
public void 後方不一致() throws Exception {
String value = "ogawa ogawaです。";
String replace = value.replaceAll("ogawa(?!です)", "おがわ");
assertEquals("おがわ ogawaです。", replace);
}

@Test
public void 前方一致() throws Exception {
String value = "生クリーム大好き。メロン大好き。";
String replace = value.replaceAll("(?<=メロン)大好き", "大嫌い");
assertEquals("生クリーム大好き。メロン大嫌い。", replace);
}

@Test
public void 前方不一致() throws Exception {
String value = "生クリーム大好き。メロン大好き。";
String replace = value.replaceAll("(?<!生クリーム)大好き", "大嫌い");
assertEquals("生クリーム大好き。メロン大嫌い。", replace);
}


TwitterのアカウントをURLに変換する時はこんな感じ。

@Test
public void twitterアカウント() throws Exception {
String value = "@aqubi リンクを@つくってね@ @sora_usagi こっちも。";
String replace = value.replaceAll("(?<!\\w)@(\\w+)", "<a href=\"http://www.twitter.com/$1\">l@$1</a>");
assertEquals("<a href=\"http://www.twitter.com/aqubi\">@aqubi</a> リンクを@つくってね@ <a href=\"http://www.twitter.com/sora_usagi\">@sora_usagi</a> こっちも。", replace);
}


(?<!\\w)の部分は後方一致でGroupではないので、(\\w+)の部分の値は$1になっています。
• • •

2010年8月31日火曜日

空うさぎにGoogleBuzzの機能を追加しました

空うさぎv0.9.8.11を先ほどリリースしました!
今回のバージョンでは、GoogleBuzzの投稿/読込みができるようになりました。

Buzzの投稿画面はこんな感じになります。


画面上部にあるコンボボックスは、privateモードでの投稿をするものです。
コンボの中に表示されているのは、google GmailのContactsで設定されているGroupになります。
privateモードでGroupを指定してポストするとそのGroupの人が見れるポストになります。

privateモードでポストするとWEB上ではこんな感じにみえます。


限定公開のリンクをクリックすると...


Shinichi Ogawa, hideko ogawaとプロフィールのない 1 人

と出ていますが、
このエントリは、Shinichi Ogawaだけが入ったグループに送信してみています。
hideko ogawaは私。自分は必ず入っているのですね。
プロフィールのない 1 人 というのは不明。誰なんでしょうw

ということで、privateモードで送信すると、あるグループの人のみが見れるようなポストになる(はず)
グループに0人だったら、自分だけが見れる投稿になります。
これを利用して、自分のメモを投稿したり...とかも出来きますよ♪

buzzエントリの読込みですが、設定>Buzzにて行えます。
User consumption feed は自分がフォローしている人のフィード。
User personal feed は自分が投稿したフィード
です。

自分が投稿したBuzzだけ抜き出す設定はこんな感じになります。


ぜひお試しくださいー!

P.S. GoogleBuzzの検索機能はまだ付けていないです。どう画面に展開するか思案中。
• • •

2010年8月27日金曜日

iPhoneアプリ開発はじめました

最近、iPhoneアプリを作り始めています。
ある程度設定だけでUIが組み立てできるので便利ですねー。

現在作ってみた所は、まず設定画面

ここでEditボタンを押すと

こんな感じのテーブルに。

テーブルを編集モードに切り替えると、表示の切替が出来るようになってます。
+やーは、アイコンはシステムアイコン。
システムアイコンが色々揃っているのは、とっても嬉しい。アイコンてそろえるの大変何ですよねぇー。
iPhone Human Interface Guideline / System-Provided Buttons and Iconsを見ると、色々あるっぽいのですが、よく見る「メニューに戻る」の形のボタンないのが残念。

↑こういうやつ。
定数としては切られていないけど、ある数値を与えたら出てくるとか...どこかで見た記憶もあるのですが、失念><

あと、Basic認証使ってRSSフィードを取得とかしてみました。
その際、NSDataにBase64のエンコード・デコード機能を追加するのコードを参考にさせてもらったのですが、そこで知ったこと。

既に用意されている、NSDataというクラスを拡張したい時、

@interface NSData (Base64EncDec)
- (NSString *)stringEncodedWithBase64;

とかいたものをimportしておくと、NSDataのメソッドとしてstringEncodedWithBase64があるかのように使えるんですね。
これは便利だなぁー。

手探りでも画面の実装は進んでいってますが、まずは、人のソースを読んでObjectiveCでの書き方の理解をしないとなぁー
良く分からず書いてても、微妙なコードしかかけないなぁー と改めて感じた一日でした。反省。
• • •

2010年8月7日土曜日

北海道旅行

AppEngine ja Night Sapporoへの参加&結婚10周年記念として北海道/札幌に来ています。

昨日に札幌入りしたのですが、空港から出て、始めに思ったのが、東京とあんまり気温が変わらないんじゃないのか?と。
よくよく聞くと、こんなに暑い日は久しぶりだとの話。噂では20数年ぶりの熱帯夜だったとか。
なんというタイミングに来てしまったのでしょうね....
暑いですが、風が吹いたらやはり涼しいですよ。よいです、夏の北海道。
そして! 蛇口からでる水が衝撃的に冷たいw

* 初日
到着してすぐ、回転寿司 根室花まるへ。
回転寿しです。「旬のものを注文するように」との話を聞いていたので、その通りに行動。
いつもの癖で、"すいませんー。ホタテを1つー"と注文してましたが、周りをみると声出している人がいない。。
よくよく見てみると、机の上に注文票があってそれに書いて渡している人がほとんど(笑)

その後、社内勉強会、#ajns1 に参加して終了。

* 本日2日目は札幌を観光してきました。

北海道庁旧本庁舎


時計台


二条市場の海鮮丼

近藤昇商店
見た目通り、めちゃウマでしたよ。北海道来たかいがあった!


さっぽろテレビ塔

小さいw

夜には、大通り公園でやっている さっぽろ夏祭りを覗いてきました。
ビアガーデンが、サッポロ、キリン、サントリー と分かれていて、結構人がいてました。これはいいよなー。東京でもやればいいのにw
キリンのビアサーバが目をひきました。

棒みたいに立っているやつ。各テーブルでポン、ポンとビアサーバが立っているの、分かります??
そんなに飲まない人でも頼みたくなってしまいますねw
私たちは、飲まず、焼きもろこしを満喫して退散。

夜は、自然食レストランのバイキング

自然食バイキング 菜蒔季
焼きオニオンがめちゃウマ。単にオーブンで焼いたタマネギに甘い醤油をかけて食べるものなんですが。

今日はいっぱい歩いてつかれたぁー。
明日は北大を少し散歩して東京に帰る予定。
• • •

2010年7月29日木曜日

Slim3本発売されました




オープンソース徹底活用 Slim3 on Google App Engine for Java
が発売になりました。

私は、原稿チェックをしたため既に読破しております。
恥ずかしながらSlim3についてはほとんど前提知識がなかったのですが、Slim3はGAEのかゆい所に手が届く便利機能がある薄いフレームワークなのですね。

Chapter1 クラウドの本質とGoogleAppEngineの制限
Chapter2 Slim3の設計哲学
Chapter3 Bigtable
Chapter4 Google App Engine のデータストア
Chapter5 Low Level APIによるデータストアの操作
Chapter6 Slim3によるデータストアの操作
Chapter7 開発環境のTips, 設計のテクニック

と、本は進んでいくのですが、本の表題にあるSlim3が詳しく出てくるのはChapter6。
それまでのデータストアの内容が結構ボリュームがありまして、読んでいる最中は「いったいいつSlim3でてくんねん」と思いつつ読んでおりましたよ、正直。
でも、Chapter6を読んで納得。
Slim3はデータストアの知識無しでは語れないし、逆にデータストアの知識があれば語る事はそれほど多くない=とっつきやすい んだな...と。

なので、Slim3には興味はまだ無いが、GAEには興味ある..って人にも役に立つ本になっていると思います。
データストアはどんな感じで動いているのか?を頭の中でイメージできるようになるのが大きい。
「こんな感じで動いている」ってイメージが出来ている状態で、具体的にお勉強なり、アプリ作成などを始めるとひっかかりも少なくなると思われます。
Slim3/GAEを本格的に触っていない私ですが、まずこの本を読んだおかげで、
逆に、「データストアの動きがイメージできない状態で触り始めて、何か業務アプリなりを完成できる気が全くしない」
という思う今日ですw

本の中では、サンプルソースコードがたくさんあります。
ほとんどがテストケースになっていて、その部分だけコピペすれば動く状態のもの。
これを見た時、「あー @shin1ogawa ぽいーっ ぽいーっ」と思いましたw
あと、著者プロフィールで、2人の温度差があるのもウケましたw

最後になりましたが、こういう機会を @shin1ogawa に与えてくれた、ひがさんに感謝!!
• • •

2010年7月6日火曜日

小さなチーム、大きな仕事読んでみました

遅らせばながら、37シグナルズの 小さなチーム、大きな仕事 を読んでみました。


想像通りの内容でした。おもしろかったです。
170ページぐらいの新書で一日で読んでしまえます。

読み終えて感じた事は、「全て自分の頭でしっかり考える事」をしないとな という事。
人間の頭って知識としてあるモノは、考える事をせずにやってしまいがち。その方が楽ですし...そのために、記憶もあるのだとは思います。
過去の知識は財産なのであるに越した事はないのですが、プラスアルファで 「今、この状況ではどうだろう?」と、無理矢理にでも考えてみる事は意識したい。

さて、本の内容に少し戻りますが、内容は基本的に小さい会社での話ですが、普遍的な成功の道筋があります。

小さい会社と、大きい会社とでは、問題に対する対処方法は全く違う。
言葉を変えると、小さい会社で大きな会社と同じことをしても勝てるわけない。
プロモーションとかそうですよね。
今の時代は、莫大な費用を投資してプロモーションのプロを雇うよりも、社員個人を味方にしてプロモーションしてもらう方がリターンは大きい可能性も。

なるほど、なるほど と思いながら読み進められますが、小さい会社の場合はトップの考えが重要になるので、平社員の立場でこの本を読み終えるとフラストレーションが溜まってしまう可能性も(笑)
まぁそう感じた人は、自分で何かを始めてみればいいじゃん って内容でもあるのとは思います。

見方を変えて、私自身を「一つの会社」と捉えてこの本を感じることもできます。
私だから出来る事、情報発信できることはなんだろう...?

「私という会社」の魅力は、考えられる範囲で最高に身軽だということ。
こんなものが欲しい!と思ったものを、夜な夜な作っているのはその現れでもありそうです。
最近は、夜な夜な 空うさぎ

空うさぎを「とても特徴的だ」と言って頂いたことがあって、それは本当に嬉しかったです。
もちろん否定的な 「使いにくい」, 「機能足りない」 という言葉も頂いています。ですが、これに関しては、"このアプリの特徴に合っていない使い方をする人なんだろう。そういう人は他の合っているアプリが見つかるといいな" と思います。
...もちろん、残念な気持ちもありますがねw
万人受けするモノは、既存の有名アプリ にお任せ..です。

そんな事を振り返ると、利益なしで自分自身で欲しいもの...と考えて、その思いをまっしぐら!で作ったものって、結構 この本で言っていることに近くなるのかなとも思いました。

利益、顧客、会社、上司、同僚...としがらみが増えると、どうしてもまっしぐらができなくなり目的が曖昧になってしまいがち。(日本人的考えかもしれませんが)
サービスの存在自体疑問に思いつつ、自社サービスだから..とやっている人も結構多いんじゃないでしょうか?
でも、これはしょうがないと思うんですよね。
サービス発案初期メンバーが出した目的はブレることなく進むべきだと思うので。

もし、初期メンバーがそのプロジェクトからすっかり抜けてしまい、目的があやふやになっている場合は最悪ですが。その場合は、その会社が悪いですねw

とはいえ、一人で仕事をするのは限られています。
じゃあ、どうしたら人と意見を一致して気持ちよく考えていけるのか? と考えると、尊敬している人同士(一方通行NG)、目的/目線が合っている人同士で仕事する事なんかと思います。

そんな事を考えていたら出てくるのが、オープンソースのプロジェクト。
そのプロジェクト自身に共感した人が集まり、お互いを尊敬している。
しかも、携わっている皆がそのソフトを欲している。おぅ、ばっちり!
今後、オープンソースのプロジェクトと同じような方式で人が集まり、お仕事として生業がたてれたら幸せになりそうーっ

現実に戻って... (笑)
オープンソースのようなプロジェクトと、生業とする仕事はやっぱり壁があります。メンバーの話に限らず。
自分で企業するつもりが無い私としては、これからも給料が得て生きていける方法について悩んでしまいますが、この本にあった「大きなタスクじゃなくて、小さいタスクに分割してモチベーションを下げずに進んでいこう」というのを参考に、現時点できることをこなしていこう。
• • •

2010年7月4日日曜日

iPhone4 はじめました

とうとう、本日 iPhone4を入手しました。
3G + iOS が遅くて、イライラしていたのも解消されました。良かった♪

3Gで味わえなかったiOSの機能を早速試してみよう!と思ったのですが、操作が分からないw
まぁ、一回知ったら良い事なので特に説明とかのウザイダイアログはいらないし、やれる操作は限られているのでいいちゃーいいんですけどもね。


iOSでの基本操作

フォルダを作成する (3G端末でも可)
アプリアイコンを、その他のアイコンの上に移動させる

起動している一覧を表示
ホームボタンをダブルタップ

アプリを終了する
ホームボタンをダブルタップ → 該当アプリを長押しして削除マークを出す。

音声コントロール
ホームボタン長押し


音声コントロールを試してみたんですが、ご認識して変な電話番号で勝手に電話をかけられてビビりました。
曲名を喋っただけだったのにw
...使わないかな(笑)

ビデオ通話のFaceTimeは、子供がいる家庭とかは子供と、おじいちゃん/おばあちゃんとお話したりと、楽しいのかも。
まぁーこれも私は使いませんが。

じゃー、気を取り直して、私の嬉しいBEST3。
第1位:サクサク動く
やっぱ、これでしょう。フリック入力の際にイライラする時が多かったですが、これも無くなるんですよね。今の所大丈夫。

第2位:文字が見やすくなった
解像度があがったおかげで、文字がくっきり、はっきり。まるで、本を見てるよーな。。
Bylineで見るフィードも、見やすくなりました!

第3位:カメラの性能アップ
3Gの端末に比べたらアップしただろうカメラ性能。
マクロ撮影は少しは出来るようになった気がします。あと、明るい/暗いが混在している時も綺麗にとれるようなった気がします。
オートフォーカス機能はついているのですが、マクロのものについてはちょっと微妙。でもあるだけまし。嬉しい。

本体ですが、背面も指紋がつくようになったので、ケースある方が綺麗に使えそうです。
3Gの時は何も付けていなかったのですが、今回は買うかどうか悩みます。
まぁ携帯の寿命は2年ぐらいっぽいwので、汚くなってもいいやーという感じでアップルマーク全開で使うのも手ですが。
• • •

2010年6月26日土曜日

餃子パーティ

Places(プレイシズ), Nulab(ヌーラボ)合同餃子パーティを開催しました。
開催地は我が家!
餃子を作ってくれた, @TakedaEさん、やきそばを作ってくれた@tabaturboさん、有り難うございました!
家で開催はゆっくりできるし、お金もかからないし、よいっすねー。

@shin1ogawa の Tweetより

上記は、餃子が出来るまで、みんなでwiiのマリオをやっている図。私は映ってませんがw

@horri の tweetより

出来上がった餃子。綺麗に出来上がってます!

会社帰りに10人前の料理を作るのはさすがに大変ですね。
次回は、下ごしらえがいるような材料はあらかじめ買っておいて、料理に取りかかる人。買い出しに向かう人。 とチームプレイをしないと...と実感した次第。

皆さんには、我が家の使い勝手も慣れてもらい、スーバーの場所とかも覚えてもらい...私がなーんにも動かなくても済むような会ができるよーになるようにしたいなw

...ということで、また家に遊びにきて下さい。
• • •

2010年6月22日火曜日

Twitter連動WorldCup応援

普段サッカーをあまり知らない人でも思わず見てしまう、ワールドカップ。
各国のサポーターの動きで、お国柄も分かったりして面白いですね。
南米系の人はいつも踊っているイメージ。楽しそうだなぁー!

今年はTwitter連動の応援サイトが結構ありますね。
Twitterでみるとテレビ解説では伝わらない辛口メッセージがあったりして、より楽しめます。

気づいたものを集めてみました。

まずTwitter本家。
http://twitter.com/worldcup/worldcup

シンプルで結構好き。ハッシュタグに連動して出てくるちょっとした国旗はナイスアイデアだと思う。かわいい。

FIFA ワールドカップ ツィートトレンド
http://wctrends.twinavi.jp/

なんか、力いれてつくってますね。。でも私的には正直イマイチw リアルタイムのモリモリ感がないんですよね、なんか。

CupBuzz
http://www.titletweets.com/cupbuzz/

WorldCupの楽しみの一つは、各国との疑似交流かと思っています。「この国はここにあるのかー 」「この国の人はどんなtweetしてるんだろ?」と楽しむにはよさそうです。

CupTweets
http://www.cuptweets.com/

点数を予想する感じ?サイトも見やすいし、やっている目的も明確でいい感じ!

私の一番のお気に入りは、単純に #2010wc とか #jpg のハッシュタグでtweetを垂れ流しで見る方法。
やっぱね、Tweetはリアルタイムでみるのが一番楽しい。リアルタイムじゃなかったら楽しさ半減以下だと思います。
特にサッカーのようなものは、リアルタイムだからこそ、みんなで盛り上がっている感も得られる!

これからもtwitter連動サービスが、何かのお祭り毎に色々出てくるのでしょうが、この切り口は面白い!と思えるものが出てくるのか..それもまた楽しみですね。
twitterを使いこなしている人でないと、よいサービスは出来ない気もするのでー!
• • •

2010年6月8日火曜日

TwitterStreamingAPIのOAuthでハマリ中

TwitterStreamingAPIのOAuthでハマリ中...です。
/1/statuses/filter.json?track={パラメータ} で、Streamの情報を取得しているのですが、
OAuthにすると、スペースの含むパラメータ、日本語のパラメータ を指定すると認証エラーになっちゃいます。

現状のパターンはこんな感じ。

█パターン1
パラメータ : iPad
sigBaseでのパラメータ : track%3DiPad
URL : GET /1/statuses/filter.json?track=iPad HTTP/1.1

→ 取得OK


█パターン2
パラメータ : iPad Apple
sigBaseでのパラメータ : track%3DiPad%2520Apple
GET /1/statuses/filter.json?track=iPad%20Apple HTTP/1.1

→ 取得NG 401が返る

█パターン3
パラメータ : iPad&Apple
sigBaseでのパラメータ : track%3DiPad%2526Apple
GET /1/statuses/filter.json?track=iPad%26Apple HTTP/1.1

→ 取得OK

█パターン4
パラメータ : iPad+Apple
sigBaseでのパラメータ : iPad%252BApple
GET /1/statuses/filter.json?track=iPad%2BApple HTTP/1.1

→ 取得OK

█パターン4
パラメータ : 日本
sigBaseでのパラメータ : track%3D%25E6%2597%25A5%25E6%259C%25AC
GET /1/statuses/filter.json?track=%E6%97%A5%E6%9C%AC HTTP/1.1

→ 取得NG 401が返る

Basic認証だったら、スペース/日本語ともに取得できたんだけどなぁー。
何か分かる人がいたら教えて下さい><

2010/10追記
現在は上手く動くようになっているようです! Twitter側のバグだったんでしょうねw
• • •

2010年5月31日月曜日

GoogleBuzz

先日行われたGoogleI/O 2010でGoogleBuzzのAPIが公開されました。
それからというもの、BuzzAPIと戯れる日々でした。

Buzzについては、周りの反応では「使ってないし...これからも使うつもりないなぁ...流行らないんじゃ?」って感じの人が多いみたい。
FriendFeedを良く触っている人からみると、FriendFeedの代わりになるものになるん? って感じもあるかと。

FriendFeedは、deliciousに登録する程でもないけど、気になったリンクを投稿して、コメントも付けておく。
後から検索できたらいいな..って感じで使う事が多いです。
Twitterでは、FriendFeedでの投稿 + 後で為にならないつぶやきも って感じ。
使う人によって用途は違うとは思いますが。
あと、たまに恩恵に預かれるのが、Twitterの調子が悪い時....FriendFeed経由だったらTwitterのエントリが取得できる時があること。
Twitterの調子が悪い時に、他の道筋で取得できるのは嬉しいですね。
FriendFeedの欠点としては、古いエントリが削除されてしまうこと。これは結構イタイ。
せっかく投稿しておいたリンク/コメントが消えてしまいますのでー。

さて、そんなFriendFeedの代わりにBuzzを使えるのか? なのですが、今の時点ではなんだか微妙。
第一に、Twitterのエントリが配信されるタイミングが遅い。
第二に、リアルタイムに取得できる口がない。リアルタイムじゃないTwitterの情報なんていらない><
第三に、リンクはあくまで補足情報の扱い。メインはユーザ入力の文字列。
第四に、Comment/Likeの情報はエントリの一覧からは取得できず、別途取りにいく必要がある。

第三についてですが...
FriendFeedの場合、リンクのポストをする場合、
1. リンクのタイトル
2. リンク
を投稿して、それについてコメントを入力していく形になっています。
その結果として取得できるエントリの文字列は、リンクタイトル + リンク になります。
リンクについては、短縮URLになっていたら展開してURL文字を返してくれ、URLが長かったら後ろを...にしてくれる賢い機能付きです。


それに対してBuzzの場合は、
1. リンクのタイトル
2. リンク
3. エントリの文字列
を投稿します。3.ユーザの文字列が無い場合、勝手に文字がはいるっぽい

これは、エントリの文字を空にしてWeb上から送信した時の状態。勝手に 「1 photo」と入ってくるみたい。
Buzzでのリンクはあくまでエントリ文字の補足情報としての扱いみたいですね。
エントリの文字列にリンクも含まれていないようですし。(上図はのリンクは、リンク情報を展開しているので見えているだけ)

FriendFeedの代わりに使う為には、クライアント側で整形してエントリを投稿してあげないとイマイチですねぇー。

とりあえず、空うさぎの次のバージョンには含めない形になりそーですが、色々模索を続けようと思っています。
あ、そうだ、Buzzの取得方法について、Javaに落としたサンプルをhttp://sites.google.com/site/shin1ogawa/googlebuzzに載っけてみたので、よければどうぞ。
• • •

2010年5月10日月曜日

ChirpUserStreams

ChirpUserStreams を試してみました。
これはまだTwitterの新しいStreamAPIらしいのですが、まだベータのものです。
正式に対応している Streaming API Documentationでは、PublicTimelineから特定のキーワードなどを指定して取得はできますが、自分のHomeTimelineの情報を取得することができません。
そこで、ChirpUserStreams。これを使うと、HomeTimelineがStreamで取得できてしまいます!

StreamAPIがを使うと、リアルタイムにエントリが取得でき、嬉しい事になります。
何か更新があった時にすぐに情報が取得できるのと同時に、何回もアクセスする事がないのでAPI消費も少なくする事ができます。
ちなみに、現在のChirpUserStreamsでは、通常のAPIで使用できる回数:350は全く消費されないようです。

ただ、残念なのが、認証方式がBasic認証しかまだないという事。うむー。
良く分かってないのですが、Basic認証情報が入ったユーザ/パスワードの情報が入ったHTTP HEADERは最初のアクセス時に送信されるだけなので、それ以降のエントリ情報受信が始まればヘッダー情報は流れないから傍受されても致命的ではないのかな? まぁ、だからといって...ですが。

そんな、ChirpUserStreamを空うさぎの開発版に組み込んでみました。
実装は、すぎゃーんメモを参考にさせて頂きました。有り難うございます!

エントリがリアルタイムに反映されていくのはやっぱり気持ちいい!
FriendFeedのリアルタイムAPIの時と同じ感動を味わいました。
これを味わってしまうと、今までの定期的に取得するタイプに戻るのがツライですw

ChirpUserStreamsでは、ツイート情報だけでなく、「フォローした」「Favoriteつけた」「Retweetした」という情報も入ってきます。
これを空うさぎで通知を出すように試してみたら、凄い量の情報量でビックリしてしまいましたw
この人、めっちゃフォローしまくってる...手当たり次第やってんの? とか丸分かりでちょっと怖い感じもしますが。

空うさぎ正式版でも、ChirpUserStreamsを使えるように空うさぎでは対応したいなぁーと思っているのですが、Basic認証の危険性をちゃんと警告してから使えるようにしないとダメですね。
しかも、API変更や、そもそも無くなるってこともあるし。

そう考えると、クライアントアプリで採用するのはまだ早い感じですが、空うさぎぐらいのマイナーなクライアントであれば許される?!そう思いたい程、やっぱリアルタイムでの取得はいいもんですー♪

...ということで、明日からはもうちょっとChirpUserStreamsでの実装を詰めていこうとおもいます。
• • •

2010年5月6日木曜日

AdobeAIRでサイズの再計算

空うさぎで、通知画面の改造を行っています。
今までは、前面に全画面を覆う透明のパネルを一つ貼って、その中に通知パネルをペタペタ貼っていたのですが、これでは問題が。
こぅすると、その他のアプリで前面表示するものと競合するようで、FireFoxのダウンロード完了ウィンドウとか、GoogleChromeでのタブの順番を移動しようとすると上手く行かなくなってしまいました。

そもそも、透明パネル対応をしたかというと、ウィンドウ(mx:Window)を作って消すというのは凄く負担のかかる処理で、CPUの消費も尋常じゃない><
通知の画面なんて、絶えずいっぱい出して閉じるものなので、それだとキツイんですよね。

で、今回の空うさぎでは、透明パネルをやめ、通知用ウィンドウを再利用することによりCPUの消費も押さえつつ、問題解決を試みています。

ここで問題が出たのが通知用のウィンドウのサイズ変更。
通知用ウィンドウは、表示する文字のサイズによって高さを自動的にぴったりになるように表示するようにしたい。
mxmlの設定ではheightの設定は行わず、自動的に計算するのに任せていました。

こーすると、ウィンドウ再利用時、上手く再計算をしてくれない。
AdobeAIRでは、サイズが指定されていないため計算を行った値を explicitWidth, explicitHeight という変数に格納しています。
一度計算がおわったものについてはこの値を使い、再計算を省くことにより速度を改善するんですね。

もちろん、width, height の属性に値を設定していればその値が使用されます。
実際どんな値を使うのか? は、getExplicitOrMeasuredHeight() , getExplicitOrMeasuredWidth() というメソッドが使えます。

ということで、計算させたいコンポーネントにて
explicitHeight = NaN;
explicitWidth = NaN;
validateNow();

をしてあげることにより、再計算してくれるようになりました。

mx:Textに入れた文字列の表示サイズを判定については、
1行のものであれば、measureText(txt)メソッドで取得できるTextLineMetricsから取得できます。
が、複数行になるものであれば、上記のvalidateNow() してあげれば大丈夫です。

ここらへんの、サイズ変更については、SwingでもSWTでもハマったな。
まぁーまだマシに解決できたAdobeAIRは良いのかも。

さて、次回の空うさぎは↑の処理を加えつつ、通知ウィンドウでいろんな処理ができるようになります。
お楽しみにー。
• • •

2010年4月20日火曜日

QConTokyo2010にいってきた

去年は旦那が参加したので、今年は私が参加してきました。

ですが、開始前から残念なお知らせ。
アイスランド火山噴火の影響による欧州航空便の欠航に伴い、
以下2名によるセッションを変更いたしました。

4/19(月) 16:00-16:50 Erich Gamma 氏
4/20(火) 14:30-15:20 Jim Webber 氏
残念すぎます><

でも、参加者は200名弱はいた模様。女性は...平日のセッションの割には少なめだったかなぁー。
特に2日目は少なかった。1日目はFlex/Flashのセッションあったからか?!

会場の雰囲気としては、イマイチ盛り上がりに欠けてる感触。
盛り上げたいなら日本の有識者やコミュニティをもっと招待してみるとかしたらどうなんだろうか。
そうじゃないのであれば、twitterとかfacebookとかQConでしかきけないようなセッションをもっと時間をかけてやってみる方が私は嬉しいなぁー...とアンケートに書いてきた。

ま、聞きたかったセッションは面白かったですよ。
ピックアップしたセッションのみですが、内容報告。


Data Architecture at Twitter Scale
Nick Kallen

Twitterでのscaleのお話。最初からメインディッシュな感じです。

Twitterの初期は、MySQLのRDBで組んでた。項目は、[ID] [USER_ID] [TEXT] [CREATED_AT] ぐらい。
最初に発生した問題はディスクスペースだった。
それまで縦方向のスケールしていたのを、横方向へのスケールへ転換することになったが、どのようなパーティショニングするかの検討を行った。
(1) IDを、奇数と偶数の2つに分ける → ユーザについての全ての情報を取りたいときに不便
(2) USER_ID 毎にわける → (1)と逆の問題
(3) 時間軸でわける
Twitterの特性として、検索される大半のデータは新しいデータが多いため、(3)を採用。

cassandraに移行する予定があるが、cassandraが「魔法の杖」なんかじゃない。
Twitterだったら時間軸に特性があったように、アプリ毎の特性を判断して考える必要がある。
事前にフェッチしておくなども一つの手。

人のつながり情報関連(フォローしている、フォローされている)について、膨大な処理件数になってしまう。
そんなSocialGraphの処理の方が処理件数が多い (4:1)
フォローしている人/されている人 は重複してレコードを持っている(非正規な状態)
速度のために、データの近くで演算するようにする


有機的なユーザーインターフェイス実装における課題とアプローチ
隈元 章次 SiTE4D

アスクルのAdobeAIRガジェットを作られた会社の方です。
デザイナ、プログラマ、テスター 、IAが同じポジションで協力しながら開発していっている姿に感動。
特に、デザイナさんと企画段階からいろいろ相談して何かをつくってみたい..と思っている日々だったものでw

2ndオペレーション
右から出てきたウィンドウ、右にドラッグしたら実は消えるのでは? と想像して、できるとインパクトがあったりする。
でも、それを1ndオペレーションにすると、分かりにくい/使いにくい となるので、2ndでやる。

仕様/コンセプトは開発前にプレビズ(動画)を作成して固める。
最終的なゴールは、このプレビズのものとブレない。 (確かにブレてなくてビックリ!)
ブレさせないためにいろんな規格化(進むボタン系は黄色とか)をしている。
---> そのため、途中で客の担当者が変わって違うことを言い始めても修正できる。
---> そのため、作業の人展開もできるようになる。
α版アプリを毎日客に使ってもらう。
テストは全て動画で記録する。納品はその動画を入れたハードディスク毎行っている。


Scaling Memcache at Facebook
Marc Kwiatkowski

メインディッシュ2つ目です。
えと、内容のボリュームがでかいうえ、難しかったため、あまりついていけず。
なので間違っていたらごめんなさいベースでw

Facebookは友人の情報が密接につながっているため、膨大な処理量になる
PHPでシリアライズしているが、thriftを使うようになって、3倍の早さ/30%小さくなった
2つのデータセンターwest,east には memcache proxyを使って一貫性を保っている

データを更新すると、
(1) Databaseのupdate
(2) memcacheのdelete
(3) (複数の)クライアントからmemcacheへget
(3') 存在しないため(複数の)クライアントにfailが返る
(4) failを受け取ったら、databaseへadd (勝ったクライアント1つのみ反映される)

タイミングにより、違うバーションの2つのKEYが存在する状態が発生する可能性がある。
その解決として、Keyに、スキーマバージョンとオペレーションバージョンを含んでいる。

memcacheのdelete処理をより早くするために、
複数のKeyをまとめて送っている。
LocalでのDeleteなのか、GlobalでのDeleteなのか?を認識。
データが存在しなかった時には、PlaceHolderのオブジェクトを作り、情報を格納して処理を進める。
テストは、 python 、ctypesで書いていて、コマンドラインから実行できるようなものを作成している。


Programming the Cloud
Gregor Hohpe

急遽開催となったセッション。講演者はBest Software Writingにあった、"Starbucks Does Not Use Two-phase Commit"を書いたGoogleの方です。
Googleで提供している、GFS, BigTable, MapReduce, Sawzall(そーぞる)。SawzallはDSL。

(1) Uncertainty(不確実性) これはしょうがない。つきあっていくしかない。
(2) Asynchrony(非同期) 結果の順番が一緒になるとは限らない
(3) Interaction(相互作用) 不確実性をカバーするもの。でもfreeではない。
(4) Conversation(会話) 会話のパターンができるはず。講演者がまとめている最中らしい。本でるのかも?
(5) Back to Basics(基本に戻る) Bigtableはその例。必要なもののみシンプルに作成している。よく陥りがちなのが、不確実性をカバーし一貫性を保とうとするためいろんなレイヤーで処理を挟んで、システムを複雑にしてしまう事。トラブルが発生した時逆に原因追及しにくくなる。シンプルな方がいい。
(6) Empower the Run-time(ランタイムに合わせて) 決めすぎると分散しにくい。人間が頭で考える事と、その言語/環境に合ったものは違うこともある。
例として、int[4] の配列の値を全て足す処理を作成する場合。Loopを使ってしまいがちだが、int[0], int[1], int[2], int[3] の順番で足す必要はない。結構、ループ指向に陥りやすものだが、頭の切替が必要。

今まで(Before)と、これから(After) との比較
BeforeAfter
Object-OrientedProcess-Oriented
Rich Domain ModelEvent based
Method CallsChannel based
PrescriptiveDescriptive
SingleThreadParallelizable
Easy to debugDifficult to debug


不確実性のため、会話が必要 という観点は実世界と同じ。
逆に、今までのオブジェクト指向は、思い描いていた理想の世界だったのかも?

• • •

Flex4のコードネームGumboって。。

Flex4が先月(?)にリリースされたので、ちゃんと見てみなければと思っているaqubiです。ども。

Flex4のコードネームがGumboらしいのですが、goo辞書でみてみると
gumbo
[名](複 〜s)1 《植物》オクラ(okra);そのさや.2 [U][C]((米))ガンボシチュー:オクラと鶏肉, 青野菜などでつくる.3 [U](米国西部の)ねば土:湿るとねばねばする.━━...

オクラ ですよ、オクラ! !

今までのAdobe製品のコードネームをちょっとググってみたら、
AdobeAIR → Apollo(アポロ)
Flash9.0 → BLAZE(炎)
Flex3 → Moxie(元気)
Flex4 → Gumbo(オクラ)
Mobile用Flex → Slider(滑るもの)

うーん、由来をおききしたくなる感じ。

せっかくなのでその他のコードネームもまとめてみた。

MacOS
Mac OS X v10.0 → Cheetah(チータ)
Mac OS X v10.1  → Puma(ピューマ)
Mac OS X v10.2 → Jaguar(ジャガー)
Mac OS X v10.3 → Panther(ヒョウ)
Mac OS X v10.4 → Tiger(トラ)
Mac OS X v10.5 → Leopard(ヒョウ)
Mac OS X v10.6 → Snow Leopard(雪ヒョウ)

ビュンビュン走りそう!

java
J2SE 1.3  → Kestrel (タカ)
J2SE 1.3.1  → Ladybird(テントウムシ)
J2SE 1.4.0  → Merlin(ハヤブサ)
J2SE 1.4.1  → Hopper(バッタ)
J2SE 1.4.2  → Mantis(カマキリ)
J2SE 5.0  → Tiger(トラ)
Java SE 6  → Mustang(馬)
Java SE 7  → Dolphin(イルカ)

いろんな動物。

Eclipse
Eclipse 3.2 → Callisto
Eclipse 3.3 → Europa
Eclipse 3.4 → Ganymede
Eclipse 3.5 → Galileo

木星の衛星の名前。
イオ(io)がないのは、 I/Oと混乱するかららしい。
そのかわり発見者の名前ガリレオが採用されたらしい。
次のEclipseは e4と呼ばれている?
なんかちょっと寂しい。
• • •

2010年4月18日日曜日

GeekToolでGit情報をデスクトップに表示



GeekToolでGitの情報を表示してみた。

Shellのcommandの設定で、
/opt/local/bin/git --git-dir={/pass/to/project/}.git --work-tree={/pass/to/project/} {gitのコマンド}
とすればOK.

私の主な目的は更新漏れ防止なので、更新間隔は30secで設定。
ディスプレイがもっと横長で大きくなってほしくなります。
• • •

2010年4月17日土曜日

良い目を養う

「良い目を養うには本物を見ること」
私の父親は、骨董品収集が趣味だったので、良く言っていたのを思い出します。
実家はドがつく田舎でしたので、大きな美術館もなく本物の絵画や彫刻を見るタイミングはほとんどありませんでした。
小さい頃、都会の美術館に連れて行ってもらった事があり、その時は本で見た絵画との差に愕然とした記憶があります。
私は覚えていないのですが、”美術館でaqubiがいなくなった” と両親が探しまわった事件があり、「普通の子供はすぐに飽きて美術館の外にでてしまっているだろう」と先入観を持っている両親は外をいろいろ探していたらしいのですが、その時には私はまだ館内にいたオチ。
私はあまりにも熱心に見ていたので進むペースが遅かったというのが原因だったようです。

では、私には美術的才能があったのか?というと全然ない。(周りの人はもぅご存知だと思いますが)
いま思うと原因は、自宅に飾られていた水墨画やら、彫刻やらを普段から目にしていたからなのだと思います。
(それらが果たして本物だったのかどうかはいささか疑問ですがw)

これと同じ事を先日感じたのが、Webデザイン。
私はプログラマなので、主に見ているのはEclipseとプロジェクト管理ツールとメーラ...です。
プロジェクト管理ツールについてなのですが、ヌーラボに転職する前はTracを使っていたのですが、転職後はBacklogを使うようになりました。
Backlogのデザインは、デザイナさんが行っているのでデザインがいい!と評判(!?)のものです。
それをよく見るようになって、より自分が作るページのなんちゃってデザインが許せなくなる度が高くなった気がします。

もちろん以前より、「いいデザイン」というのには興味があって情報収集とかしてはいたのですが、普段常に見る のと 見ていない のとでは無意識的に差がでてくるような気がします。

そう思うと、仕事を行う職場風景についても大きく差がでてくるのではないかと思います。
洗練されたデザインの職場、遊び心がたっぷりの職場.... おじさんがいそうな職場、若者がいそうな職場... モノトーンな職場、ポップな職場...よくありそうな職場、独創的な職場...。
それらの雰囲気については、外部からのお客さんが感じるだけでなく、普段からいる社員についても洗脳のように刷り込まれていくのかもしれない。

起業する場合、まず「こんな企業にしたい」という思いを事務所のデザインとして表す というのもよいのかもしれないですね。

まぁ私が起業を考えている訳では全然ないのですが(笑)
• • •

2010年4月15日木曜日

GoogleBuzzボタン

Googleのブログを見てみると、GoogleBuzzのボタンをサイトに配置する方法が紹介されています。

http://www.google.com/buzz/stuffにアクセスすると、「バズに投稿」「バズでフォロー」のJavaScriptがコピーできます!



ここで作成されたリンクからBuzzの投稿を表示してみると、こんなダイアログが出てきてポストができた。


このTechCrunchとかと同じようにBuzzボタンが...私のページにも作れる!

このボタンのリンクの詳細は GoogleBuzzAPI-Buttons and Gadgetsにあるよーです。

単純に
http://www.google.com/buzz/post
というリンクで、バズが投稿できるリンクになります。

パラメータに、message, url, imageUrl, hl が指定できるようになっていて、
http://www.google.com/buzz/post?message=Here's%20Buzz!&url=http://www.google.com/buzz
こんな感じになる。
ちなみに、hlはロケールっぽい。

<a href="http://www.google.com/buzz/post"
class="google-buzz-button" title="Google Buzz"
data-message="Here’s Buzz!"
data-url="http://www.google.com/buzz"
data-locale="en"
data-button-style="normal-count"></a>
<script type="text/javascript" src="http://www.google.com/buzz/api/button.js"></script>

と書いてるのが↓ 見えてる?


• • •

2010年4月12日月曜日

ImageIOを使って画像操作

Javaのjavax.imageio.ImageIOを使うと、画像操作が簡単に出来ます。

たとえば、gifファイルをjpegファイルに変換するには以下のコードで行えます。
BufferedImage image = ImageIO.read(new File("input.gif"));
ImageIO.write(image, "jpeg", new File("output.jpg"));


簡単ですね。素晴らしい。

カラーのJPEG画像を、グレースケールに変換するには以下で。
BufferedImage image = ImageIO.read(new File("input.jpg"));
BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
newImage.getGraphics().drawImage(image, 0, 0, null);
ImageIO.write(newImage, "png", new File("output.jpg"));


BufferedImageのタイプには、
public static final int TYPE_INT_RGB = 1;
public static final int TYPE_INT_ARGB = 2;
public static final int TYPE_INT_BGR = 4;
public static final int TYPE_BYTE_GRAY = 10;
public static final int TYPE_BYTE_BINARY = 12;

などなどあり、前記の例では、TYPE_BYTE_GRAYのBufferedImageに書き込んだのでグレースケールにしています。

そんな便利なBufferdImageですが、透過GIFの場合は注意が必要です。
透過GIFを、ImageIO.readで読込みして作成したBufferedImageのタイプは、TYPE_BYTE_BINARY = 12 になります。
TYPE_INT_ARGBではないのですねー。

透過GIFを新しいBufferedImageに書き込みして編集し、再び透過GIFとして出力したい場合にて癖があるみたい。
例えば、単純に以下の操作をしてみる
BufferedImage image = ImageIO.read(new File("alpha.gif"));
BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
newImage.getGraphics().drawImage(image, 0, 0, null);
ImageIO.write(newImage, "gif", new File("output.gif"));

すると、出力結果は透過GIFではなくなってしまいます。

透過GIFとして出力するためには...
一つ目の方法としては、書き込み先のBufferedImageをインデックスカラーのタイプ(BufferedImage.TYPE_BYTE_INDEXED)にして、カラーパレットを作成し、透過の色を指定してあげると透過GIFとして出力できるようです。以下は、透過gif, 透過pngファイルを一つにして出力した例。

public static void main(String[] args) {
try {
BufferedImage image = ImageIO.read(new File("alpha.png"));
BufferedImage image2 = ImageIO.read(new File("alpha.gif"));
BufferedImage newImage = convertToIndexed(image);
newImage.getGraphics().drawImage(image2, 0, 0, null);
ImageIO.write(newImage, "gif", new File("output.gif"));
} catch (Exception ex) {
ex.printStackTrace();
}
}

public static BufferedImage convertToIndexed(BufferedImage src) {
BufferedImage dest = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_BYTE_INDEXED);
Graphics g = dest.getGraphics();
g.setColor(new Color(231, 20, 189));
g.fillRect(0, 0, dest.getWidth(), dest.getHeight());
dest = makeTransparent(dest, 0, 0);
dest.createGraphics().drawImage(src, 0, 0, null);
return dest;
}

private static BufferedImage makeTransparent(BufferedImage image, int x, int y) {
ColorModel cm = image.getColorModel();
if (!(cm instanceof IndexColorModel))
return image;
IndexColorModel icm = (IndexColorModel) cm;
WritableRaster raster = image.getRaster();
int pixel = raster.getSample(x, y, 0);
int size = icm.getMapSize();
byte[] reds = new byte[size];
byte[] greens = new byte[size];
byte[] blues = new byte[size];
icm.getReds(reds);
icm.getGreens(greens);
icm.getBlues(blues);
IndexColorModel icm2 = new IndexColorModel(8, size, reds, greens, blues, pixel);
return new BufferedImage(icm2, raster, image.isAlphaPremultiplied(), null);
}

透過色をベタっと塗りつぶしてあげる感じ。
だけど、画質が落ちてしまうんですよねー。

もう一つの方法としては、BufferedImage.TYPE_INT_ARGBのBufferedImageに透過の変換をしたイメージ書き込んで透過画像を出力する方法。以下で出来る様子。

public static void main(String[] args) throws IOException {
BufferedImage image1 = ImageIO.read(new File("alpha.png"));
BufferedImage image2 = ImageIO.read(new File("alpha.gif"));

Image transpImg1 = makeColorTransparent(image1, new Color(image1.getRGB(0, 0)));
Image transpImg2 = makeColorTransparent(image2, new Color(image2.getRGB(0, 0)));
BufferedImage dest = new BufferedImage(300,300, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = dest.createGraphics();
g2.drawImage(transpImg1, 0, 0, null);
g2.drawImage(transpImg2, 0, 0, null);
g2.dispose();

File outFile2 = new File("sample2.png");
ImageIO.write(dest, "PNG", outFile2);
}

public static Image makeColorTransparent(BufferedImage im, final Color color) {
ImageFilter filter = new RGBImageFilter() {
public int markerRGB = color.getRGB() | 0xFF000000;
public final int filterRGB(int x, int y, int rgb) {
if ((rgb | 0xFF000000) == markerRGB) {
return 0x00FFFFFF & rgb;
} else {
return rgb;
}
}
};
ImageProducer ip = new FilteredImageSource(im.getSource(), filter);
return Toolkit.getDefaultToolkit().createImage(ip);
}

どっちも、x=0, y=0の位置のものを透過色としているって感じ?あってる?

後者の方が画質が落ちないのですが、Toolkit.getDefaultToolkit().createImageを使うと環境依存がある的な記事もみたので、ちょっと気になったりもする。
• • •

2010年3月20日土曜日

MacOSXにCassandra,Thriftをインストール

Cassandraと、ThriftをMacOSXにインストールしてみたのでメモ。

JavaHomeを設定


export JAVA_HOME=/Library/Java/Home

cassandraインストール


sudo mkdir -p /opt/cassandra
sudo chown -R {you} /opt/cassandra

sudo mkdir -p /var/log/cassandra
sudo chown -R {you} /var/log/cassandra
touch /var/log/cassandra/system.log

sudo mkdir -p /var/lib/cassandra
sudo chown -R {you} /var/lib/cassandra

svn co https://svn.apache.org/repos/asf/incubator/cassandra/tags/cassandra-0.5.1 /opt/cassandra/cassandra-0.5.1

cd /opt/cassandra/cassandra-0.5.1
ant

// 起動してみる
bin/cassandra -f

// CLIを起動してみる
bin/cassandra-cli --host localhost --port 9160


Thriftインストール


sudo port install boost
sudo port install libevent
sudo port install pkgconfig

svn co http://svn.apache.org/repos/asf/incubator/thrift/tags/thrift-0.2.0 /opt/cassandra/thrift-0.2.0

cd /opt/cassandra/thrift-0.2.0
./bootstrap.sh
./configure --with-boost=/opt/local --with-libevent=/opt/local --prefix=/opt/local
sudo make install

cd lib/py
python setup.py install

cd ../perl
perl Makefile.PL
sudo make install

cd ../rb
ruby setup.rb config
ruby setup.rb setup
ruby setup.rb install

// 試してみる
cd /opt/cassandra/cassandra-0.5.1/interface/
thrift --gen py:new_style cassandra.thrift
• • •

2010年3月14日日曜日

HTML5の本を読んで思ったこと

HTML5&API入門 の本をさっと一通り読み終えました。

さっと機能をみるのにも綺麗にまとまっているし、リファレンス的にまとめてくれている所もあり、良い本でした!


マークアップについては、分割された文章を一つのHTMLとして表示するとかやりやすくなりますね。

Canvas,Video,Audio系でFlashの分野に踏み込む感じ。
Flashを書かない開発者にとったら出来る事が増えて嬉しい。tween系とかのライブラリがいっぱい出てくるんでしょーねw

WebWorkerは待ってました的な機能ですね。
でも、マルチスレッドに慣れてない人が使うと、ハマってしまうかも。Flasherとか、フレームワーク上でしか開発した事が無い人とか。

WebSocket,Server-SentEventsの機能はなんか作ってみたくなる機能ですね。
簡単なTwitterクライアントアプリで機能をお試しする人が多そうですねw

この前のGoogleDevFesで出ていたらしい、NotificationAPI。How to use Notifications APIをみつつ試してみました。
NotificationAPIも、ストレージ関係も、URLパス(オリジンというの?
)毎に情報を保存していくので、色々試すには気軽に試せるサーバを作っとくのがよさそうです。

サーバー側で書いていたものが、どんどんクライアント側に移動していく時代の流れなんでしょうか。
結構5年後はその反対の流れになっているのかもしれないけど、こぅいぅ流れはぐるぐる回っていきながら進化していくものなので乗っておきたい。

クラウドのサーバ側 と HTML5のクライアント側。
今後、1人の開発者がこの両方ともカバーしていくのは難しい気がします。開発者の中でも2手にわかれていくのかもしれない。。
いや、もっと細分化していくのかもしれないですねー。

気になる所としては、「管理しやすいソース」を求めて進んでいた流れはどうなるんだろうー?
  1. 管理しやすいソースデザイナが触る所と、開発者が触る所とのソース との分離

  2. MVCのような機能毎に疎結合にしてソースの分離

とかしてた所。

サーバとクライアントについては、TwitterのAPIのような感じで分離するんだろうなぁーと思うのですが、ボリュームの増えたクライアント側はまた考えないと。
非同期とバシバシ使っていたら、結構な量のソースになるし、メンテが難しくなりますし。。
• • •

2010年2月15日月曜日

GoogleBuzz

Buzzにとても興味があるが、まだどんな感じで使っていったらいいのかが分からずいるaqubiです。こんにちは。

APIもまだ全て公開されておらず、クライアントを作成することが出来ない状態なのが残念ですね。
が、情報収集はしておこう...と思っている日々です。

ということで今まで知った事をメモ。

Gmailで本名を入れている場合は、その名前が公開されます。
ニックネームがでればよかったんですけどねー。
Google バズ を快適にお使いいただくために

Emailを使ってBuzzに投稿するには、buzz@gmail.comに送る
ちょっとしたマークアップが使える
*word* = 太字
_word_ = 斜体
-word- = 打ち消し線
-- = 全角ダッシュ

Buzzのエントリは、label:buzz のラベルがつく。

twitterサービスを除いたものは -twitter でいけるらしい。 Stefan Svartlingのバズより

Buzzの検索

is:buzz - Type this while searching from your Inbox to find Buzz posts that were emails.
has: [link/video/image] - finds all posts with either a link, video, or image.
author: - finds all posts in your stream authored by the person whose name you enter.
commenter: - finds all the posts in your reading stream that that person commented on.


FeedBurnerを使った連携 - Google Buzz と Twitter の連携について

TwitterとBuzzとの同時ポスト - BuzzTweep
Twitterアプリから送られたメールを、Gmailの転送機能を使って、buzz@gmail.comに送信してるっぽい。
• • •

2010年2月7日日曜日

空うさぎのBTSをBacklogに移行しました

空うさぎのソース管理、チケット管理をBacklogに移行しました。

場所は Backlog-空うさぎ です。
guest/guestで入ればチケットが見れます。

実装予定はあんのー? とか気になった時とか、よければ見て下さい。
Twitterで #sora_usagi のハッシュ付きでつぶやいてくれても反応しますので、それでもいいんですが。

guestの権限では、残念ながらソースコードは見れないです。
オープンソースのプロジェクトでも使えるように、ログイン無しで 課題とソースコードを見れるような設定がほしー!と要望はしておいたので、今後その機能が実装されることを期待。

Backlogにはスペースという概念があって、1スペース毎の契約になります。
契約内容により、プロジェクトがいくつ作成できるかが決まります。

スペース名を「sorausagi」にしちゃったんですが、他のプロジェクトをたてることも考えたら、違う名前にした方がよかったかも。。失敗。
まぁ、他のアプリを作るときにも「空うさぎシリーズ」にしてしまったらいいのか!

空うさぎという名前、うさぎクラスタの方々の反応がとてもよいです。
名前でひっかかって試してくれた方もいるみたいー。うれしいですねー。

TwitterのTLもうさぎアイコンの方が増えていい感じ!

空うさぎのページも更新しなくっちゃなぁー。
日本語だけじゃなく、英語ページも作りたいんだけど、作りやすい良いツールないですかね?
Google Translate ToolKitみたいなUIで翻訳作業できたら便利でいいんだけどなぁー。
Google Translate Toolkit の メニュー>共有に「ソース ページに公開」ってあるんだけど、これを自分のページへの設定ができたらいいのになぁ。。
• • •

AdobeAIRで常駐アプリを作る

FriendFeed,Twitter,RSSのクライアントとして作成中の空うさぎですが、どこから皆さん見つけてきているのかが分からないのですが、新しいバージョンのダウンロード数が336件になりましたー。
有り難うございまっす。

んで、前から要望のあった常駐化対応をやっている最中です。

やりたい動きとしては
- メイン画面を閉じてもアプリは終了せず常駐する
- Windowsの場合はタスクトレイ、Macの場合はDocを表示し、アイコンをクリックしたらメイン画面を復帰

メイン画面を閉じてもアプリは終了せず常駐する

画面の×ボタンを押されたタイミングで画面のvisibleをfalseにすればよさそう。
mx:WindowedApplication の closingのタイミングで以下のコードを書く。

/* WindowをCloseするタイミングでの処理 */
public function onWindowClosing(e:Event):void {
visible = false;
e.preventDefault();
}

closingのタイミングであれば、処理をキャンセルすることができるので、e.preventDefault(); で画面終了処理をキャンセルしてます。

Windowsの場合はタスクトレイ、Macの場合はDocを表示し、アイコンをクリックしたらメイン画面を復帰


if (NativeApplication.supportsMenu) {
// Mac用のDocを作成する処理
} else {
// Windows用のタスクトレイを作成する処理
}

でまずは処理を切替。

/* DocIconの設定 */
private function setDockIcon(menu:NativeMenu):void {
var doc:DockIcon = NativeApplication.nativeApplication.icon as DockIcon;
doc.bitmaps = [new icon128x128()];
doc.menu = menu;
NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, systemTrayIconClickHandler);
}

/* SystemTrayの設定 */
private function setSystemTrayIcon(menu:NativeMenu):void {
var tray:SystemTrayIcon = NativeApplication.nativeApplication.icon as SystemTrayIcon;
tray.bitmaps = [new icon32x32(), new icon16x16()];
tray.menu = menu;
tray.tooltip = applicationName;
tray.addEventListener(MouseEvent.CLICK, systemTrayIconClickHandler);
}

/* タスクトレイ、Docをクリックした時の処理 */
private function systemTrayIconClickHandler(event:Event) :void {
if (!mainWindow.visible || mainWindow.nativeWindow.displayState == NativeWindowDisplayState.MINIMIZED) {
if (!mainWindow.nativeWindow.visible) {
mainWindow.nativeWindow.visible = true;
}
mainWindow.nativeWindow.restore();
mainWindow.activate();
mainWindow.setFocus();
}
}

で、Docとシステムトレイを作成します。

クリックのタイミングを拾うには、Windowsではタスクトレイに対して addEventListener(MouseEvent.CLICK, handler); をすれば拾えるっぽいのですが、MacのDocは拾えないみたい。
Docの場合は、マウスをクリックすると、NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, handler); が呼ばれるようなので、これで対応。

これで今の所、動いている感じ。。
• • •

2010年2月1日月曜日

Flexで重複チェックする

FlexでのチェックはValidatorを使えます。

このサブクラスとして既に実装されているValidatorは
CreditCardValidator, CurrencyValidator, DateValidator, EmailValidator, NumberValidator, PhoneNumberValidator, RegExpValidator, SocialSecurityValidator, StringValidator, ZipCodeValidator があります。

これ以外のValidatorって自作する場合、どう作るんだろう? と思い作成してみました。

今回欲しかったのは、重複チェックのValidator。
複数のObjectを登録できるが、名前は重複させたくない という場合の時に使うためのものです。

- ArrayCollectionの中にAオブジェクトが複数入っている。
- Aオブジェクトには name という属性がある。
- 新規追加する時は、ArrayCollectionの中に同じnameが入っていたらエラー。
- 更新する時には、更新対象オブジェクト以外でチェックする。(excludeの設定)
- 必須入力の項目でもある

という前提だと、


var validator:Validator = new DuplicateValidator(arrayCollection, "name", excludeObject);
validator.source = txtName;
validator.property = "text";
validator.required = true;

ように設定するものになります。


/**
* リストの中に重複がないかチェックする
* @author ogawa
*/
package org.sorausagi.air.ui.setting.rss {
import mx.validators.Validator;
import mx.validators.ValidationResult;
import mx.collections.ArrayCollection;

public class DuplicateValidator extends Validator {
/* 元々のリスト */
private var list:ArrayCollection;

/* リスト内オブジェクトの名前 */
private var listName:String;

/* 除外するオブジェクト */
private var excludeObject:Object;

/* このValidatorのErrorMessage */
private var _fieldError:String = "既に使われている名前です";

public function DuplicateValidator(list:ArrayCollection, listName:String, excludeObject:Object = null) {
this.list = list;
this.listName = listName;
this.excludeObject = excludeObject;
}

public function set fieldError(message:String):void {
this._fieldError = fieldError;
}

public function get fieldError():String {
return _fieldError;
}

override protected function doValidation(value:Object):Array {
var results:Array = super.doValidation(value);
var val:String = value ? String(value) : "";
if (results.length < 0 || ((val.length == 0) && !required)) {
return results;
}
return validateDuplicate(this, value, null);
}

public function validateDuplicate(validator:Validator, value:Object, baseField:String):Array {
var results:Array = [];
for each (var item:Object in list) {
if (excludeObject != null && excludeObject == item) {
continue;
}
if (item[listName] == value) {
results.push(new ValidationResult(
true, "","deplicated",
fieldError));
break;
}
}
return results;
}
}
}


使ってみた画面はこんな感じ。
• • •

2010年1月24日日曜日

SuperTable内のラジオボタンの選択が有効にならない

HTMLでテーブルのスクロールを実現したいため、SuperTableというのを使ってみました。

SuperTableは縦スクロール、横スクロールも実現できます。


ですが、RadioButtonを入れると、選択表示にならないという状態になる。HTMLのinputにはcheckedついているのに!
その原因は、スクロールテーブルの実現方法にあるんですが、SuperTableのスタイルシートを外すと見えてきます。

まず、fixedCol:0 = 列固定を無し に指定してみると、こんな感じになります。

行ヘッダーの列を2つにして、cssで縦スクロールを実現しているんですね。

次に、fixedCol:1 = 1つ目の列を固定 に指定してみると、こんな感じになります。

テーブル内のラジオボタンの行までガシガシ作られちゃってます。
ラジオボタンはグループ内で1つのみの選択という作りをしますので、複製された行は未選択状態になります。
この状態でSuperTableのcssをあてると、綺麗に全部未選択状態に見えてしまいます。


そこで、複製された方の列のラジオをJavaScriptで無理矢理選択状態にしてみる

try {
var myST = new superTable("matrixb41dbb", {
cssSkin : "sDefault",
headerRows : 0,
fixedCols : 1,
colWidths : [150,100,100,100]
});
} catch (e) { }
checkRadio(document.form1.test1, "あ");
checkRadio(document.form1.test2, "い");
checkRadio(document.form1.test3, "う");
checkRadio(document.form1.test4, "あ");
checkRadio(document.form1.test5, "い");
checkRadio(document.form1.test6, "う");

function checkRadio(radios, selected) {
for (i=radios.length - 1; i>=0;i--){
if (radios[i].value===selected) {
radios[i].checked = true;
break;
}
}
}

すると、上手く表示されるようになります。

この状態で、fixedCols : 2 = 2列目まで列固定 にして試してみると、2列目のラジオの選択が見えなくなってしまいます。


つまり、列固定している列は1つめのテーブルの情報を、列固定していない列は2つ目のテーブルの情報を見てるよーです。
なので、今回の例では2列目の「あ」の選択値の場合は、1つ目のテーブルのラジオを選択してあげれば見れるようになります。

checkRadioFirst(document.form1.test1, "あ");
checkRadio(document.form1.test2, "い");
checkRadio(document.form1.test3, "う");
checkRadioFirst(document.form1.test4, "あ");
checkRadio(document.form1.test5, "い");
checkRadio(document.form1.test6, "う");

function checkRadioFirst(radios, selected) {
for (i=0; i<radios.length - 1;i++){
if (radios[i].value===selected) {
radios[i].checked = true;
break;
}
}
}

cssを当てない状態ではこんな感じに仕上げる。


たまたま、ラジオで選択が表示されなくなって気づきましたが、textやcheckboxも2重に生成されることになります。
なので、HTMLで情報送信したがサーバで上手く反映されない...とハマるパターンもありそう。

なんにも考えずに使うと怖いなーと思った一件でした。
• • •

2010年1月22日金曜日

HTMLを後でiPhoneで見る

前回のエントリで、
Web上でチェックした項目を、iPhoneでさっと見れるようなアプリもあったらいいな。

と書いたのですが、ReadItLater,Instapaperというサービスを教えてもらいました。

両方とも、URLをサービスに送信して登録できて、iPhoneアプリからそのHTMLを見る事ができます。もちろん、Webからでも。
これで、気になった記事をバシバシとうろくして、喫煙所でゆっくりと見れる!
iPhoneのUIはReadItLaterの方が好きなので、こっちをメインにしてみようかなぁー

なかなか便利なので、空うさぎにReadItLater、InstapaperにURLを登録する機能をつけてみようかと考え中です。
それとともに、短縮URLの元URLと、HTMLタイトルを取ってくるようにしてリンクのリストを作ろうかと。

元URLはHEADでリクエストを投げて、Locationが入っていたらその値を元エントリとしてます。

var req : URLRequest = new URLRequest(url);
req.method = URLRequestMethod.HEAD;
req.followRedirects = false;
var loader:URLLoader = new URLLoader();

var expandUrl:String;

function onResult(event:HTTPStatusEvent):void {
for each(var rh : URLRequestHeader in event.responseHeaders) {
if (rh.name == "Location") {
expandUrl = rh.value;
return;
}
}
}

loader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, onResult);
loader.load(req);


HTMLのタイトルは、単純にHTMLを取得して、<title>のタグの値を取得してます。
ここの所は@kisさんにサンプルコードを頂きました。

@aqubi 使い物にならないものならこちらで! http://d.hatena.ne.jp/nowokay/20100121

文字コードが問題になるので、HTMLヘッダのContent-Typeにcharsetが入っていたら、その文字コードで判断してるんですが、結構charsetが入っていないサイトが多いんですね。。

この部分のActionScript3は、

var req : URLRequest = new URLRequest(expandUrl);
req.method = URLRequestMethod.GET;
_loader = new URLLoader();
_loader.dataFormat = URLLoaderDataFormat.BINARY;
_loader.addEventListener(Event.COMPLETE, onResult);
_loader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, httpResponse);
_loader.load(req);

という感じで、dataFormatをURLLoaderDataFormat.BINARYにしてバイナリでまず取得。
HTTPStatusEventでresponseHeadersの中から、Content-Typeを引っこ抜いて、charsetをとる。


protected function onResult(event:Event):void {
var bytes:ByteArray = _loader.data as ByteArray;
var content:String = ba.readMultiByte(bytes.length, charset);
}

結果をreadMultiByteで変換してStringを作成。
んで、titleを取ってくる感じ。

charsetが入っていない場合でも、utf-8であるものも結構多い気がするのでとれなかったらutf-8にして文字化けしたらごめんなさいね。。。って感じかなぁー。うーむ。

ちなみに、AIRには、flash.html.HTMLLoaderというLoaderもあって、これを使うとHTMLをレンダリングしてくれる状態まで情報を取得/用意してくれます。
ここから取得できる、HTMLHistoryItemというオブジェクトには、リダイレクト前のURL、リダイレクト後のURL、HTMLのタイトルが取得できるようになっているんで、今回必要な情報はばっちりとれちゃいます。んが、悪意あるHTMLだったときにどんな事になるか分かんないので怖くて使ってません。

ということで、現在つくっている空うさぎではこんな感じの画面がでるようになっています。


ここまでやると、ペーストした値がURLだったら、短縮URLに変換するとかしてみたいなぁ。とも考え中。
• • •

2010年1月9日土曜日

今年作成するアプリ

年始め恒例の社員総会のためヌーラボ本社@福岡に行ってきました。

昨年に引越をした本社はとっても綺麗&広くて良かったです。
初めて本格的な水炊きを食べたのですが、これが美味しくて感動!
誤解してたんですが、水炊きって鍋とは違うんですね。今までは、鶏肉が入った鍋の事を水炊きって言うんだと思ってた。
福岡の皆様、色々お世話になりました!

さてさて、社員総会では各自今年の目標を短冊に記入するのですが、私の今年の目標は「iPhoneアプリを作る」にしてみました。
ここ2年間、ずっとAdobeAIRでアプリ作っていたのでそれ以外のものをやりたい。
Objective-Cは触った事がないのもあるし。

問題はどんなアプリを作るか...ですが、ちょっと悩み中。

タイムトラッキングのアプリもいいな。
ASlimTimerっていうSlimTimerのAdobeAIRクライアントを作ってはいるのですが、開始とか停止とか忘れちゃう事があるんですよね。会議が始まる!とバタバタ移動してしまった時とか。モバイル端末だったら持ち歩いているので気づいた時に操作できるからいいかも?

Web上でチェックした項目を、iPhoneでさっと見れるようなアプリもあったらいいな。
使う場面なんですが、PC上で一通り読みたいWEBページがあった時、それをさっとiPhoneで見れるようにしてから、iPhone共々喫煙コーナーに移動して読む って事ができたらいいなーと思って。
どんな仕組でするのかはまだ考えてないけども。

あと...iPhoneアプリではなくなってしまうかと思うのですが、(オレオレ)ブックマーク/スクラップのアプリも欲しい。
ブックマークってdeliciousとか、ブラウザのものとか使ったりするんですが、後で見るブックマークって、よく知っているページがほとんど。あのサイトはブックマークしたって覚えているようなもの。
そうでないものは、結局またGoogleで検索した方が見つけるのが早かったりして。

なんかの探し物している時は特に、"ここは関連しそうな気がする "と思ったものはタブで残しつつ、新たな検索結果のページもどんどん見ていくので、大量なタブで大変になったりすることが結構あります。

といって、そういうモノはブックマークに登録しても、なんて名前のサイトだったかとか覚えてない とか、なんの情報が気になったから登録したおかも覚えてない とか、そもそも登録した事すら忘れてしまう ので、すぐには登録しない。
中には、掲示板の中に書いてある一部分のコードだけがきになっただけ...とかもあるしね。
でも、そういう検索結果は、残さずに消しちゃうのももったいないし、ブラウザが突然落ちたらどうしよう...とドキドキして使ってたりする時も多いので、なんとかしたいと思うんですよ。

よくあるブックマークの情報って、
URLがメインの情報で、tagで簡単な補足情報(カテゴリ)を入れる感じが多いと思うのですが、その逆で、
一部の引用文章/画像 がメインで、URLが補足情報 トントンと登録しやすいものがあったら、調べ中のものをガシガシ記録として残していきやすくならないかなぁーと思うんですが、どうでしょうかね。
これの場合だったら、HTML5を使って色々できたりするかも?!

どちらにしろ、自分にとって何かしら楽になるツール を作りたいですね。
個人的に作るアプリって、自分の生活の中で楽できるものってのが、やっぱ頑張れるので。(私だけ?)

ま、最初は欲張らずに簡単なものを作りつつ温めていきたいですねw
• • •

2010年1月1日金曜日

2010年始まりました

明けましておめでとうございます。始まりました、2010年。

ということで、昨年をちょっと振り返りエントリ。

春 転職。新しい職場が渋谷なため、若者の勢いに少し圧倒され気味。

AIR GEARにコード補完機能を追加。このコード補完は欲しいー!機能ですがなかなか難しくて、現在もまだ中途半端な状態。
もう少し手を入れねば..と現在も良い方法を思案中。

ASlimTimerにGrowl風の通知ウィンドウを追加。
これが出来るなら、FriendFeedのクライアントもできるんじゃないかなぁ?と思い、AFriendFeed(現在は空うさぎ)を作成開始。
これがきっかけとなった問題発言(笑)

冬 業務でDocomo,Softbank携帯 , Blackberry のアプリ開発をしてた。携帯の開発って難しいなぁ...と思う。
何が難しいって、エミュレータと実機とで状況が変わってしまう とか、Unitテストがしにくい とか、提供されているライブラリのソースが公開されていない とかで。
あと、エミュレータを動かすEclipseプラグインにちょっとイラつくw
残念ながら、Android/iPhoneはやってなかったのですが、やっぱこれからはAndroidかなぁーなんて。
やっぱり、一般開発者に開発しやすい環境を提供するのは大事ですよー。
企業単位で囲い込みじゃなくて、個々の開発者単位のファンを増やす環境=オープンな環境 ってのは大事だよなーと思う。

FriendFeedクライアントとして作り始めた空うさぎは、FriendFeedユーザでないTwitterのフォローアーの状況も一気に取り込みたい...欲求からTwitterのAPIを使ってTwitter情報もどんどん取り込みしてしまった。
結局、自分が使いやすいFrinedFeed+Twitterクライアントになっていく。。

後半を振り返ると、夜な夜な空うさぎをメンテしている日々で、AIR GEARもなかなか触れず。
Twitter/FriendFeedは日々使うツールだからあれも、これも...と色々欲しくなってくるからですねー。

作り始めて半年ぐらいですが感じることとしては、"気に入るTwitter/FriendFeedクライアントがないのであれば作ってしまえばいい"
TLの量/内容/チェックしたい内容の量/家なのか、会社なのか などなどにより、見る方法、チェックしたい内容 がかわってきます。
だから、誰にとっても完璧なクライアントって作れないんじゃないかと。(まぁ、発想の転換でできるんかもしれないけど)

Twitter クライアント作者ミーティングに参加させて思ったんですが、たとえ新たなクライアントを作ったとしても、既に作っている人にとっての敵になるわけじゃーない。
気軽に作ってみて、こんな新たなUI/機能 はあると良くない? というのを世の中に伝えるだけでも凄くいいと思う。
(企業で作ってるのであれば、敵になるんかもしれませんが)

作るのは面倒だしちょっと...というのであれば、
"いいクライアントがないー"
"このクライアントはいまいち..." とつぶやくぐらいなら、
"こんなクライアントないかなぁー? "
"こんな機能があると嬉しい!"
という前向きな事をつぶやいて、世の中のクライアント作者のよいヒントになるようにすればいいと思う。

そうして、いろんな人が知恵をしぼり合って、今後もよいクライアントがどんどん増えていけばいいなぁーと思います。
もちろん、空うさぎも、おー!これはいい! と思う機能を発見しつつポチポチ機能を増やしていきたいな。と思うし、他のクライアント作者へよいヒントにもなったら嬉しいな。と思う。

...と、昨年はこんな感じでしたが、今年はまた違うものを作ってみたいなぁ と思ってます。
いろんな面白そうな技術やインフラがどんどん出てくる世の中なので、凄く迷いますよねー! 楽しい世の中だ。体が複数欲しい。
• • •