Home

Shin x blog

GoogleAppEngine に関する議論について思うこと

この記事の所要時間: 210

appengine関連でTogetterから議論が巻き起こってますね。最近すっかりappengineをご無沙汰だった自分としては、一連のtweetやblogを読んだおかげですっかり熱が戻ってきました。

議論の発端になったのは以下のTogetter。

Togetter – 「Google AppEngineについて思うところ」

議論を見ていて感じるところがあったので、ざざっと。

  • @makotokuwata さんの主張自体は自分はそれほど違和感無かった。ただ表現がキツイ箇所があったのが琴線に触れてしまったのかな。
  • 議論から有用なtweetやblogエントリが生まれてきた。これはとても参考になった。
  • 意識的にそうしていたわけではないだろうけど、寄ってたかって反論していくのは見ていて @makotokuwata さんが気の毒に感じた。
  • @makotokuwata さんがこれまでされてきた活動(Python4PHPer)は素晴らしいと思う(自分もイベントは気になってた)し、これからも続けられると良いのでは。(
    大きなお世話かもしれませんが)
  • ちなみに反論していた人には「appengine ja night」な方も多かったけど、自分がイベントに参加した時はアットホームな雰囲気でとても楽しかったです。技術的な内容ゼロの自分のLTも笑顔で聞いてくれたし。別にこわいひとたちでは無い(と思う)。
  • ようは、表現が少し過激だったり、ちょっとした言葉の行き違いが原因かと。自分も感情的になるとついつい余計なことを書いてしまうから気をつけないと。
  • 多分、飲み屋で同じ話すれば「おまえなにいうてんねん」というノリで軽い議論になるだけで、こんなややこしい話にはならなかったでしょうね。オンラインのコミュニケーションは難しい。。。
  • どちらかがどちらかのイベントに参加して懇親会とかで話せば、わだかりも解けると思うんだけどなー。

今回のことでこれまで頑張ってこられた @makotokuwata さんが辛い思いをされているのは、とても悲しいことなので、気にせずに頑張って下さい。

そういえば appengineを追いかけてる時に作ろうと思って放置していたものとかあるから、またやりだそうかな。

appengine について参考になったエントリ

GPSリアル勇者シリーズ「誰がドラゴンを殺したか?」

この記事の所要時間: 113

10/31(日)、京都でGPS携帯を利用したゲームイベント「誰がドラゴンを殺したか?」が開催されます。

このイベントは、「リアル脱出ゲーム」など熱狂的なファンを持つイベントを手がけているSCRAPさんが開催するイベントです。

こちらで利用するWebシステムの開発を1×1が担当させて頂いています。

GPS 携帯をゲームに利用したイベントというのはこれまでなく、さらに、こういったイベントが東京ではなく関西(京都)で開催されるというのは珍しいと思います。

先日、実地試験というわけで京都に行ってゲームを体験してきたのですが、これはなかなか新しい感覚ですね。具体的な内容については書けないのですが、こういった新しいイベントは東京先行が多いので、今回は関西で体験できる貴重な機会になりそうです。

ゲームに参加するには、GPS対応携帯(docomo/au/Softbank)もしくはiPhoneが必要です。つまりGPS必須なイベントというわけです。

そろそろ涼しくなってきて観光にも良い季節になりました。次の日曜日は携帯もって秋の京都にお越し下さい:D

チケットは絶賛発売中なので、下記リンクからお買い求め下さいー。

=> 誰がドラゴンを殺したか|イープラス
=> フリーペーパー:SCRAP:京都全域で配布中 » GPSリアル勇者シリーズ第一弾「誰がドラゴンを殺したか?」

PHPerのためのYAPC::Asia2010

この記事の所要時間: 21

YAPC::Asia2010 の発表資料、動画が面白いので、まとめ。

YAPC=Yet Another Perl Conferenceは、その名のとおりPerlのイベントです。PHPで言うならPHPカンファレンスにあたるでしょうか。(違ったらごめんなさい)

Perl のイベントということで特に気にしていなかったのですが、先日行われたYAPC::Asia2010の発表資料を見ると PHPer が見てもかなり面白いです。もちろんPerlならではの発表もあるのですが、言語を問わずWebシステム開発をするなら参考になる内容が多くあります。

Perl だから、という理由だけで避けるのはホントに勿体無いので是非見てみて下さい。

PHPerにオススメな発表

PHPユーザの自分が見て面白かった発表です。リンク下にある一言は自分が面白いと思った点で、要約では無いです。内容は各発表を見てみて下さい。

来年は

PPTやKeynoteなどいわゆるプレゼンツールを使っていない発表が多いのも特徴的ですね。

こうしてあげてみるとPHPerでも楽しめる発表が多いです。来年は行ってみようかな。

Facebookをスーパーマリオに例えると

この記事の所要時間: 113
  • 登録(復帰)直後は、通常マリオ。ジャンプ力も無いから投稿する内容も無難なものだし、クリボーにちょっと当たるとダメ。
  • 戦々恐々としながら投稿していくと、キノコ(いいね!)やフラワー(コメント)がもらえる。
    => スーパーマリオやファイヤーマリオになると(気持ちの中で)色んなことができるようになる。写真も投げてみたり、他の人にも絡んでいったり。
    => 手にするアイテムによっては、グループやファンページを作ったりも。
  • でも、やっぱりクリボーに当たるとびっくりするくらいすぐに前の状態に逆戻り。イケイケで投稿していたのが、いきなり遠慮気味になったり。
  • 何かの拍子にスターを手に入れれば、無敵マリオに!なんでも来い状態で、バンバン投稿するし、ガンガン絡んでいく。そんな空気は伝播するのか、いいね!やコメントが付きまくり。まさに光り輝いてる状態。
  • でも無敵マリオは長くは続かない。無敵状態を維持するにはスターを取り続けるしかない。
  • だから、誰かが通常マリオで不安げにウロウロしていたら、キノコ(いいね!)やフラワー(コメント)でパワーアップさせて上げましょう。

「クリボーに当たる」というのは「批判」とかより「無反応」ですかね。ここ数日はボーナスステージ状態の盛り上がり方なので、体感してみたい方は混ざっとくと良いですよ。

ちょっと無理矢理感がありますが、まあfacebook面白いよってことで。

スクリプト言語間における「lexical closure」の違い – PHPの場合

  • 2010-10-09 (土)
  • PHP
この記事の所要時間: 045

via. スクリプト言語間における「lexical closure」の違い、それともプログラムの違い? – karasuyamatenguの日記

PHPも5.3からクロージャがあります。クロージャの指定の仕方によって挙動が異なりますが、PHPで書くと以下のようになります。

ループでiを0から4まで回す
ループブロック内で:
iを埋め込んだlexical variable、’localvar’を定義。
localvarを参照したclosureをリストに追加。
5つのclosureの値をプリント

スクリプト言語間における「lexical closure」の違い、それともプログラムの違い? – karasuyamatenguの日記

各クロージャの$localvarが独立しているパターン。

foo0 foo1 foo2 foo3 foo4

各クロージャで$localvarを共有しているパターン。(use で指定する変数が参照渡しになっている。)

foo4 foo4 foo4 foo4 foo4

Lithiumのフィルタシステム

この記事の所要時間: 1624

次世代CakePHPとも言うべきフレームワークLithiumのフィルタシステムを見てみました。

Lithiumは対象がPHP5.3以上ということで、5.3ならではの機能を活用したアーキテクチャになっています。中でも特徴的なのがフィルタシステムです。

全体のアーキテクチャとしては、CakePHPの流れを汲んで標準的なMVCフレームワークになっています。ただそれを実現する手段としてフィルタシステムを多用しています。これまでのフレームワークとは異なる点があり、いざフレームワークの動きを掴もうとすると戸惑います。

そこでLithiumのフィルタシステムをざっくりと見てみましょう。

サンプルソース

サンプルとして、SampleControllerとそのビューテンプレートを用意します。

フィルタの動きを見るだけなので、indexアクションでは、ログに__METHOD__を記録するだけです。

[app/controllers/SampleController.php]

<?php
namespace app\controllers;

class SampleController extends \lithium\action\Controller {
  public function index() {
    \lithium\analysis\Logger::debug(__METHOD__);
  }
}
&#91;/php&#93;
<p>[app/views/sample/index.html.php]</p>

<h1>Sample</h1>

ログをファイル(app/resources/tmp/logs/debug.log)に出力するようにしておきます。

[app/webroot/index.php]

// ログをファイルに出力
\lithium\analysis\Logger::config(array('default' => array('adapter' => 'File')));

echo lithium\action\Dispatcher::run(new lithium\action\Request());

?>

これでブラウザから「http://localhost/sample」にアクセスすると以下の内容がログに記録されます。

2010-09-30 00:11:16 app\controllers\SamplesController::index

フィルタを追加する

では、Dispatcher#runメソッドにフィルタを追加してみましょう。

まず、フィルタをクロージャで定義します。(__invokeメソッドを定義したクラスでも可)

そしてフィルタを追加する際は、applyFilterメソッドを利用します。この際に、第一引数にフィルタを追加する対象のメソッド名を、第二引数にフィルタ(クロージャ)を指定します。

[app/webroot/index.php]

// フィルタを定義
$c = function($self, $params, $chain) {
  \lithium\analysis\Logger::debug('Before');

  // 次フィルタを実行
  $res = $chain->next($self, $params, $chain);

  \lithium\analysis\Logger::debug('After');

  // 次フィルタの戻り値を返す
  return $res;
};

// フィルタを追加
lithium\action\Dispatcher::applyFilter('run', $c);

echo lithium\action\Dispatcher::run(new lithium\action\Request());

フィルタの内容は単純で、lithium\action\Dispatcher::runの処理の前後でログに文字列を出力しています。

これを実行すると以下のログが出力されます。フィルタで定義したログ出力部分が実行されており、フィルタとして機能しているのが分かります。

2010-09-30 00:11:16 Before
2010-09-30 00:11:16 app\controllers\SamplesController::index
2010-09-30 00:11:16 After

フィルタ定義でのポイントは、$chain->nextの箇所です。LithiumのフィルタシステムはChain of Responsibilityパターンになっており、フィルタ自らが次ぎのフィルタを呼び出す構造になっています。

あくまでもフィルタ自身が次のフィルタを実行するかどうかを決定できるので、サンプルのように前後に処理を実行することもできますし、あえて次のフィルタを実行させないということもできます。

CakePHPのフックメソッド(beforeSave()/afterSave()等)をフィルタとして書くというように考えるとイメージしやすいかもしれません。フックメソッドと異なるのは、まずサブクラスと作ってメソッドを継承する必要が無いと言う点があります。さらに大きく違うのはフィルタは複数追加することできるので多彩な処理をプラグインのように加えることが可能という点です。

次は、複数のフィルタを追加してみます。

複数フィルタを追加する

3つのフィルタを追加します。フィルタの内容は単純で、文字列をログに出力するだけです。ただ、どのフィルタから出力された文字列かを識別するためにフィルタごとに番号を追加しています。

ここでは、applyFilterの第二引数に直接クロージャ定義を記載しています。

[app/webroot/index.php]

$no = 1;
lithium\action\Dispatcher::applyFilter('run', function($self, $params, $chain) use ($no) {
  \lithium\analysis\Logger::debug('Before'.$no);
  $res = $chain->next($self, $params, $chain);
  \lithium\analysis\Logger::debug('After'.$no);

  return $res;
});

$no = 2;
lithium\action\Dispatcher::applyFilter('run', function($self, $params, $chain) use ($no) {
  \lithium\analysis\Logger::debug('Before'.$no);
  $res = $chain->next($self, $params, $chain);
  \lithium\analysis\Logger::debug('After'.$no);

  return $res;
});

$no = 3;
lithium\action\Dispatcher::applyFilter('run', function($self, $params, $chain) use ($no) {
  \lithium\analysis\Logger::debug('Before'.$no);
  $res = $chain->next($self, $params, $chain);
  \lithium\analysis\Logger::debug('After'.$no);

  return $res;
});

echo lithium\action\Dispatcher::run(new lithium\action\Request());

実行すると以下のログが出力されます。これを見ると$chain->next前の処理は、フィルタ追加順に実行され、$chain->next後の処理はその逆順で実行されているのが分かります。

2010-10-01 01:20:46 Before1
2010-10-01 01:20:46 Before2
2010-10-01 01:20:46 Before3
2010-10-01 01:20:46 app\controllers\SampleController::index
2010-10-01 01:20:46 After3
2010-10-01 01:20:46 After2
2010-10-01 01:20:46 After1

このように複数の処理を任意に追加できるのがフィルタシステムの特徴です。

フィルタシステム

ここまでフィルタがどのように動作するかを見てきました。

ではフィルタがどのように呼ばれているかを掴むためにフレームワークのソースを見てみましょう。

まずlithium\action\Dispatcher#runメソッドのソースを見てみましょう。

20行弱のソースなのですが、実質は3行しかありません。まず2行でパラメータのセットを行います。あとはstatic::_filter()を実行して終わりです。

lithium\action\Dispatcher#runメソッドとしての実質の処理(MVCの実行)は、static::_filter()の第3引数にあるクロージャの中に記載されています。

[libraries/lithium/action/Dispatcher.php]

  public static function run($request, array $options = array()) {
    // パラメータセット
    $router = static::$_classes['router'];
    $params = compact('request', 'options');

    // static::_filter()を実行
    // クロージャの中身が、本当の処理
    return static::_filter(__FUNCTION__, $params, function($self, $params) use ($router) {
      $request = $params['request'];
      $options = $params['options'];

      if (($result = $router::process($request)) instanceof Response) {
        return $result;
      }   
      $params = $self::applyRules($result->params);

      if (!$params) {
        throw new DispatchException('Could not route request');
      }   
      $callable = $self::invokeMethod('_callable', array($result, $params, $options));
      return $self::invokeMethod('_call', array($callable, $result, $params));
    }); 
  }

では、次はstatic::_filter()のソースです。lithium\action\Dispatcherはlithium\core\StaticObjectを継承しているので、実際に実行されるのはlithium\core\StaticObject#_filterメソッドです。

第三引数の$callbackにlithium\action\Dispatcher#runメソッドで定義したクロージャが格納されています。applyFilterメソッドによってフィルタが追加されていれば、フィルタチェイン(フィルタリスト)の最後に追加され、Filters::run()でフィルタ実行が開始します。フィルタが無い場合は、直接$callbackを実行します。

つまりポイントは、lithium\action\Dispatcher#runメソッドの処理自体もフィルタとして扱われるということです。これによりフィルタチェインを順々に実行すれば、メソッド自身の処理が実行できるというわけです。

[libraries/lithium/core/StaticObject.php]

  protected static function _filter($method, $params, $callback, $filters = array()) {
    $class = get_called_class();
    $hasNoFilters = empty(static::$_methodFilters[$class][$method]);

    if ($hasNoFilters && !$filters && !Filters::hasApplied($class, $method)) {
      // フィルタが空ならそのまま$callbackを実行
      return $callback($class, $params, null);
    }   
    if (!isset(static::$_methodFilters[$class][$method])) {
      static::$_methodFilters += array($class => array());
      static::$_methodFilters[$class][$method] = array();
    }   
    // $callbackをフィルタチェインの最後に追加する
    $data = array_merge(static::$_methodFilters[$class][$method], $filters, array($callback));
    return Filters::run($class, $params, compact('data', 'class', 'method'));
  }

最後にフィルタチェインを実行している\lithium\util\collection\Filters#runメソッドです。

最後の3行で、フィルタチェインの先頭にあるフィルタを実行して終了します。ここではあくまで先頭のフィルタだけを実行しています。それ以降のフィルタを実行するかどうかはフィルタ自身に委ねられています。

[libraries/lithium/util/collection/Filters.php]

  public static function run($class, $params, array $options = array()) {
    $defaults = array('class' => null, 'method' => null, 'data' => array());
    $options += $defaults;
    $lazyFilterCheck = (is_string($class) && $options['method']);

    if (($lazyFilterCheck) && isset(static::$_lazyFilters[$class][$options['method']])) {
      $filters = static::$_lazyFilters[$class][$options['method']];
      unset(static::$_lazyFilters[$class][$options['method']]);
      $options['data'] = array_merge($filters, $options['data']);

      foreach ($filters as $filter) {
        $class::applyFilter($options['method'], $filter);
      }   
    }   

    // 先頭のフィルタを実行
    $chain = new Filters($options);
    $next = $chain->rewind();
    return $next($class, $params, $chain);
  }

フィルタ実行が可能なメソッド

このようにフィルタシステムでは、メソッド自身の処理をクロージャにして、フィルタとして動作させることで実現しています。つまりどのメソッドでもフィルタシステムが利用できるわけではなく、あらかじめそれを想定して実装されたメソッドのみにフィルタが適用できます。

lithium\core\StaticObjectもしくは\lithium\core\Object(同様のフィルタ実行メソッドがあります)を継承しており、メソッド内部でstatic::_filter()もしくは$this->_filter()を実行しているメソッドが対象となります。

具体的には、\lithium\action\Controller、\lithium\data\Model、\lithium\data\source\Database、\lithium\util\Validator、他といったクラスに該当メソッドがあります。クラス名を見るとCakePHPでフックメソッドが定義されていたクラスですね。

フィルタシステムは便利?

Lithiumのフィルタシステムを見てきました。なんとなくイメージできたでしょうか。

フレームワークの主要な箇所はフィルタシステムを利用しているので、ここをおさえておくと処理が追いやすくなります。(反対に理解しないと?になります。。。)

このようなフィルタシステムをフレームワークの中核に利用しているフレームワークは、PHPではあまりありませんでした。使ってみると上手く実装されているなあというのが率直な印象です。利用の仕方では柔軟な実装ができそうなので楽しみです。

ただ実際問題、不満というかマイナスな点もあります。

まず、理解しにくということ。フレームワークのソースを読むならCakePHPのようにフックメソッドになっている方がgrepもしやすいし、一目瞭然で分かります。

次に、フィルタチェインの中身が掴めないということ。フィルタが格納される変数をvar_dump()してもクロージャが入っていることしか分からず、どのフィルタが入っているのかが分かりません。特にlithium\core\StaticObjectのサブクラスでは、フィルタを様々な箇所で追加できるので、どのフィルタがどの順序で入っているかは掴んでおきたいところです。

最後に、フィルタならではの利用方法がまだ見えてません。CakePHPのフックメソッドは実用には十分なものでした。正直、私自身は実用でフィルタならではの有効性がそれほど見えていないところです。

今後、有効な利用方法を見ていきたいを思います。

PHP5.3を体感するフレームワーク

冒頭にも触れましたが、LithiumはPHP5.3の機能が多くの箇所で活用されています。

ここで取り上げたフィルタシステムはまさに5.3の機能を利用しているので、5.3を理解するにはもってこいの教材です。言語仕様と簡単なサンプルソースを触ったあとは、実際に動くシステムを触ることでさらに理解を深めることができます。

PHP5.3を体感したい方は、Lithiumに触れてみるのはいかがでしょうか。

=> Lithium

PHP5.3+古いCakePHPのDeprecated表示をPHPコードを書き換えずに抑制する

この記事の所要時間: 133

PHP5.3+古いCakePHPで表示される大量のDeprecatedを抑制する方法です。

これはPHP5.3からE_ALLにE_DEPRECATEDが含まれたためで、非推奨な関数や文法を使っているとDeprecatedエラーが表示されます。

Deprecated表示を抑制する一番単純なのは、error_reporting設定でE_ALLからE_DEPRECATEDを外す方法です。

error_reporting = E_ALL & ~E_DEPRECATED

CakePHPでもデバッグレベルが0であれば、この方法で回避可能です。

しかし開発環境でデバッグレベルを1以上にしていると、フレームワークがerror_reportingをE_ALLに上書きしてしまうため、Deprecatedが表示されてしまいます。

E_ALLを設定している箇所を書き換える方法もありなのですが、開発環境にある複数のプロジェクトについて書き換えていくのも中々骨の折れる作業です。

ということで、CakePHP側のソースは書き換えずにDeprecated表示を抑制する方法を考えてみました。

E_ALLからE_DEPRECATEDを外す

方法は単純。PHP自体のソースを変更してE_ALLからE_DEPRECATEDを外すだけです。

変更箇所は1箇所だけ。

[Zend/zend_errors.h]

— zend_errors.h.org 2010-09-23 18:10:00.000000000 +0900
+++ zend_errors.h 2010-09-23 17:05:30.000000000 +0900
@@ -38,7 +38,7 @@
#define E_DEPRECATED (1<<13L) #define E_USER_DEPRECATED (1<<14L) -#define E_ALL (E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE | E_RECOVERABLE_ERROR | E_DEPRECATED | E_USER_DEPRECATED) +#define E_ALL (E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE | E_RECOVERABLE_ERROR | E_USER_DEPRECATED) #define E_CORE (E_CORE_ERROR | E_CORE_WARNING) #endif /* ZEND_ERRORS_H */ [/code]

あとは通常どおりPHPをビルドしてインストールすればokです。

変更前後でE_ALLの値は以下のように変わります。

変更前(オリジナル)
% php -r 'var_dump(E_ALL);' 
int(30719)

変更後
% php -r 'var_dump(E_ALL);' 
int(22527)

これでerror_reportingにE_ALLが設定されても、Deprecatedは表示されません。

とりあえずですが

本来はDeprecatedな原因を取り除くことが一番なのですが、本番環境はPHP5.2や5.1で、開発環境はPHP5.3にしたいということがあったので、この方法で対処しました。

アプリケーション側のソースは一切変更する必要が無いので楽ですね。まあ開発環境限定ということで。

Twitter で使える8つのコマンド

この記事の所要時間: 244

Twitterで使えるコマンドを試してみました。

昨夜のXSS騒動の時に脆弱性を利用したtweetを見ていたのですが、気になったのが公式RTを発生させるコードでした。

詳細は書きませんが、内容はmouseoverで特定のメッセージを自動でtweetさせるコードでした。自動でtweetするメッセージは以下のようになっていました。

RT XXXX

※XXXXはユーザID

自動tweetするのは分かるのですが、なぜこれが公式RTになるのかが不思議でした。

そこでTwitter Help Centerを見ると、このメッセージはコマンドとして規定されており、公式RTされることが分かりました。

以前からコマンドは知っていたのですが、あらためて見ると知らないものもあったので試してみました。

コマンドの使い方

コマンドの使い方は単純です。各コマンドをpostするだけです。

参照系(GET/STATS/WHOIS)以外はクライアントからpostしても有効です。(Echofon/Twitter for iPhoneで確認)

@username + message

これは説明不要ですね。Replyです。

D username + message

DMを送ります。おそらくDMを送る際は専用画面に遷移して送ることが多いと思うのですが、実はこの形式でtweetすれば、DMになります。

「D username」と入力するとテキストエリア上部の「What’s happening?」が「Direct message username:」に変わります。

RT username

これが今回のXSS騒動で使われていたコマンド。

usernameの最新tweetを公式RTします。例えば以下のようにすれば、@shin1x1の最新tweetを公式RTします。

SET LOCATION placename

locationをplacenameに変更します。

以下の例なら、locationが「kobe」になります。

WHOIS username

usernameのプロフィールを表示します。

以下の内容をtweetすると

shin1x1のプロフィールが表示されます。

GET username

usernameの最新tweetを表示します。

以下の内容をtweetすると

最新tweetが表示されます。

FAV username

usernameの最新tweetにFavを付けます。

私は見ていないですが、これを利用したコードも今回出回っていたかもしれません。

STATS

自分自身のフォロー数とフォロワー数を表示します。

Twitter Help Centerの記載ではbioも表示されるようですが、現状は表示されていません。

あまり使う場面は無いかも。。。

ざっと試してみたものの、正直、ReplyとDM以外は普段はあまり使わないかもしれません。。。

まあ豆知識的に知っておくと良いですね。もしかしたら何かの応用に使えるかも;-p

=> Twitter Help Center

Twitter RTされたtweetだけを見る「RT Reader」

この記事の所要時間: 32

Twitter タイムラインでRTされたtweetだけを見る「RT Reader」を作りました。

フォローするユーザが増えてくると全てのtweetに目を通すのが困難になってきます。まだ100,200ユーザくらいなら読めても、500,1000となるとかなり大変です。

私も2,000ユーザくらいフォローしているので、タイムラインを全て読むのはもう諦めています。。。最近は、Twitterクライアントを起動したタイミングで流れたものを眺めるくらいで、基本はリストにまとめた人を見ています。

これはこれで良いのですが、見る人が固定化されるとTwitterの良さである偶発的な面白さが薄くなり、残念な気がしていました。

そこで今回作ったのが「RT Reader」です。

RTされたtweetだけをタイムラインとして見る

RT ReaderではフォローしたユーザがRT(公式RT)したtweetだけが表示されます。

RTされたtweetというのは、フォローしている誰かが何かしら興味を引かれたtweetです。つまりRTをフィルタにして、自分にとって興味のある面白いtweetを読めるというのが特徴です。

このサービスでは、iPhone版とPC版があります。どちらもブラウザからアクセスすれば利用できます。

iPhone版

まずiPhone版。個人的にはこちらで読むのがおすすめです。

操作はシンプルです。まずRT Readerにアクセスして、OAuth認証でログインします。

ログインした画面です。初期状態でRTされたtweetが20件読み込まれます。画面上部の「▲」で次のtweetへ、「▼」で前のtweetへ移動します。tweetは30秒毎に自動で読む込むので、放っておけば新着tweetがたまっていく仕組みです。(新着tweetが読み込まれると画面上部の件数が増えていきます)

気になるtweetがあれば、ここからFavやRTすることもできます。

RT Reader

iPhoneを左手で持った時に親指で「▲」や「更新」を押しやすいように、このようなボタン配置にしています。

PC版

PC版はtweetを一覧でざーと並べているイメージです。

操作はiPhone版と同じで、OAuth認証でログインするだけでokです。

こちらも30秒毎に自動更新を行っています。新着tweetが読み込まれると上からtweetが挿入されていきます。

使いやすいRetweets By Others

実は、twitter.comには同じくRTされたtweetだけを読める「Retweets By Others」という機能があります。

そもそもRetweets By Othersを見てて、面白いtweetが多いなーと思ったのが出発点です。

現状のRetweets By Othersは自動更新が無いので、新着をどんどん読んでいくというのには不便です。そこで自動更新機能とiPhone用の最適化を行ったのがRT Readerです。(開発がほぼ完了した段階で新twitterが発表されたので、実はこのサービスが不要になる可能性も大いにあります><)

ここ数日iPhone版でRTされたtweetを読んでいるのですが、思わぬ発見があって面白いです。まだフォロー数が少ない頃、見知らぬ人からのtweetを読んで楽しんでいた感覚を思い出しています:D

タイムラインに流れる大量のtweetに疲れたあなたにオススメです!

=> TwitterでRTされたtweetを見る | RT Reader

携帯/iPhoneのGPSを試すサイトを作った

この記事の所要時間: 237

携帯/iPhoneのGPSを試してみるサイトを作ってみました。

いまや、ほとんどのモバイル機にGPSが搭載されており、foursquareコロプラロケタッチなど位置情報を使ったサービスも多くリリースされています。

そんな便利なGPSなんですが、実際のところ、どの程度の精度で位置情報が測定できるのか、そして、その位置情報を使ってどんなことができるのかをあらためて模索するために、簡単にGPSを試すページを作ってみました。

携帯電話GPSで位置情報を見る

内容は単純で、GPSで測定した位置情報を元に Google Map と住所を表示します。参考に緯度経度、誤差も表示しています。

=> 携帯/iPhone GPSテスト

ページにアクセスするとリンクがあるので、クリックします。この時にGPSを送信するか否かを確認されるので、送信に同意します。

GPSを使って測定した位置情報を表示します。

iPhoneも対応

iPhone Safariでも動作します。

iPhone Safari の GPS テスト。

計測できない場合は、「設定」「一般」「位置情報サービス」で位置情報の送信がオンになっているかを確認してみて下さい。

設定でGPSを有効にする。

Geolocation API を使っているので対応ブラウザなら Android でも PC でもおそらく動作します。

手元の環境では Mac OS X(10.6.4)の Firefox3.6.8、Safari5.0.1、Chrome6.0.472.55で動作しました。

ただ今のところ Gears Geolocation API には対応していないので、Xpreia などの Android1.6 環境では動作しません。

実際のところ

やってみると、なんとなく知っていたことをあらためて確認できて面白いですね。

例えば、屋内より屋外の方が精度が良い(誤差が少ない)ですし、やはりAu機は精度が高いようです。

また、iPhone ではWifiをONにした方が(Wifiには接続していなくても)GPSの精度が上がるという話があるのですが、それもやってみると確かにそのとおりでした。(大阪市内ですが:D)
=> clmemo@aka: iPhone の GPS のスピードと精度を上げる方法

機種や場所によってどんな結果が出るか、一度、手元の端末で確かめてみて下さい。:D

=> 携帯/iPhone GPSテスト

参考リンク

緯度、経度から住所を取得で使っています。

携帯GPSで取得した位置情報を簡単にパースしてくれる便利なPHPライブラリ。

Home

検索
フィード
メタ情報

Return to page top