Hatena::ブログ(Diary)

d.aql

 

2011.02.22

地雷 - 全宇宙を引き合いに出してしまう件について

もう2回目なので、表立って言わなければならない。プログラマに3回目はない。

全宇宙のはてなスターが100億個を突破しました - はてな広報ブログ

おめでとう。でも。

宇宙と言うのは、とても広いのである。だから人類にはまだ全然分からない事だらけだ。星の数ですらそう。宇宙は未知のフロンティアであり(以下数時間)

まぁ言いたいのは、全宇宙を引き合いに出すにはまだ時期尚早だと言うことだ。以下に、星=恒星と考えて、現在言われている数(の一説)をまとめてみた。

マゼラン2,000,000,000
はてなスター10,000,000,000
大マゼラン雲20,000,000,000
天の川銀河200,000,000,000
アンドロメダ銀河1,000,000,000,000
全宇宙1,000,000,000,000,000,000,000,000?

我々天の川銀河の伴銀河、大マゼラン雲とは、もうちょっとで張り合えるかも知れない。だが、現在分かっている範囲でしか言えないけれども、全宇宙はオーダーが14桁ほど違うんだと言うのも分かって欲しい。

要するに「人間の感覚ではわからないくらい多い」で統一されているだけなのではないか。だがそんなふうに思考停止してはいけない。なので分かりやすく、人間に全体が把握出来るくらいに収めた場合はどのくらいになるかと考えてみよう。

例えば25mプールの水量がだいたい400tくらいだと仮定する*1。400tも人間にとっては多いが、25mプールは「見渡せる範囲」な感じもする。で、オーダーが14桁違うのだから、0を14個削ればいい。その前に0を削れるように単位を変えておく。400t = 400,000kg = ... = 400,000,000,000,000μg。つまりマイクログラム単位で考えればちょうど良い。

これを使って、件のタイトルを同じように表現すると、「25mプールの全水量に、4μgの水を追加しました」みたいな感じだ。

全宇宙を引き合いに出すにはまだ早い。先はまだまだ長いのだ。

全宇宙を引き合いに出すには

人類が例えば100億人になったとして、一人が毎日100個星を付けたら、一日1,000,000,000,000(10^12)個の星が付くので、およそ1,000,000,000,000(10^12)日 = 30億年弱(3*10^9年弱)で張り合えるようになる。地道な努力が必要だが、ちょうど良いことに太陽はまだ存在していそうだ。ただ、地球環境の変化はもっと大きなものになるだろうから、早めに宇宙進出し、より安全で恒久的な文明を構築していくことこそ、「全宇宙」を引き合いに出す為の第一歩と言えよう。

ヒートアップした弁明

別に揚げ足取りをしたいんじゃないんだけど、「全宇宙」とか言ってしまうのは、完全にaqlの地雷踏んでるんですよ。自分に向けてネタ振りされているとしか思えない。

前日にこそっとネタを振られたあげく、なんとなく予想はしてたんですがまたもやこれをやられてしまうと、もう黙っていられないのです。1回目もこらえ切れなくて、ブックマークとかに書いちゃったし、他のところにも(見えないように)書いてたんです。でもね。2回目だもの。プログラマは繰り返し作業を見つけたら即排除ですよ。

張り合ってるんじゃないのは分かります。はてなスターは今のところ地球ローカルなサービスなので、太陽系と書こうが銀河系と書こうが、正しいですよ。張り合ってるのは私ですよ、ええ。一方的に。

だって宇宙とか!もう!そこ踏まないでよ!他のたいていのことなら良いんですけれど、宇宙だけは、宇宙だけはひと言(ふた言み言…以下略)言わせてもらわないと気が済みません。

確かに「はてなスターには大マゼラン雲より多くの星があります!!!」とか言われても99%の人には伝わりませんよ。まあね。でもaqlには伝わる。マゼラン雲超えちゃったかーみたいに思います。

そもそもはてなスターとか。+☆をぽちぽち押したら、星の数が増えるんじゃなくて質量増えるべきじゃないのか!とか思ってますよ。思ってますとも。小粒なエントリなら矮星、徐々に大きくなりそこそこ平凡な太陽クラスのG型や超弩級O型、何だか輝きが安定しない脈動変光星、唐突に華々しい新星や、明らかに終わったエントリなのに復活して大フィーバーするIa型超新星、何だかひきつけて止まないブラックホール。宇宙は多様であるべきと思っていますよ。

何の話だっけか。うん、つまりaqlが気付きそうな範囲内で宇宙の話題を不用意に出さないと良いと思います。或いは訳の分からない方向から食いついてくるのをニヤニヤ眺めるか、二択です。

*1:25*12*1.3[m^3]と考えたとき390[t]

2010.05.05

TwitterのOAuth認証なボットを書くのは簡単

Twitterボットを書くこと自体はとても簡単だけれど、OAuth認証?面倒そう!って人がいそうなので、全然そんなこともないよ、と言う話を書いておこうと思う。いろいろ探すといくらでも出てくる情報ではあるのだけれど、APIへのアクセスライブラリに任せているのならば、要するに問題はどうやってAccess Tokenを取得するかってことだけになると思うので、それについて。

ここではPerlNet::Twitterを使って書くけれど、どんなライブラリでもたいして変わらないだろうと推測される。

Net::TwitterでOAuth

Net::Twitter::Role::OAuthのperldoc見て!と言ったら元も子もないので(本当にそれだけの話だけれど)、サンプルコードで。これもperldocに書いてある。

use Net::Twitter;
my $nt = Net::Twitter->new(
    traits          => ['API::REST', 'OAuth'],
    consumer_key    => '...',
    consumer_secret => '...',
);
$nt->access_token('...');
$nt->access_token_secret('...');

# あとはいつも通りで

さて、ここでconsumer_keyとconsumer_secretは、dev.twitter.comから登録出来るアプリケーションのConsumer Key/Secretなので疑問はないだろう(ボットならクライアントアプリとして登録しておくこと)。問題は、access_tokenとaccess_token_secretをどうやって取得するのか(面倒くさそう!)というところ。

Access Tokenを取得する

これもNet::Twitter::Role::OAuthのサンプルコードを見ると書いてあるのだけれど、ちょっとだけ書き直してみた。

#!perl
use strict;
use warnings;
use Net::Twitter;

print "Consumer Key:\n";
my $consumer_key = <STDIN>;
chomp $consumer_key;

print "Consumer Secret:\n";
my $consumer_secret = <STDIN>;
chomp $consumer_secret;

print <<EOD;
--- CONSUMER KEY AND SECRET ---
consumer_key    : $consumer_key
consumer_secret : $consumer_secret
EOD

my $nt = Net::Twitter->new(
    traits          => ['API::REST', 'OAuth'],
    consumer_key    => $consumer_key,
    consumer_secret => $consumer_secret,
);

print "Authorize this app at ", $nt->get_authorization_url, " and enter the PIN#\n";

my $pin = <STDIN>;
chomp $pin;

my($access_token, $access_token_secret, $user_id, $screen_name) = $nt->request_access_token(verifier => $pin);

print <<EOD;
--- ACCESS TOKEN ---
access_token        : $access_token
access_token_secret : $access_token_secret
user_id             : $user_id
screen_name         : $screen_name
EOD

これを実行すると、まずはconsumer key/secretを聞かれる。アプリケーション登録時のものを答えるだけなので、コピペでなんとかなるだろう。

そのまま進むと、認証用URIが表示される。ここにボットを動かしたいアカウントログインした状態のブラウザでアクセスする。そうするといつもの「許可」「拒否」のページになるので、「許可」してPINを得る。

スクリプトに戻りPINをペーストして実行を続ければ、無事Access TokenとAccess Token Secretが得られるはずだ。あとはこれをconfigに書くなりbotにハードコードするなりすれば、その先はこれまで通りのやり方で済む。

まとめ

OAuthが面倒と言っているのは、認証実装上の諸問題をNet::Twitterなどのライブラリに任せるならば、Access Tokenの取得フェーズが面倒と言う話であり、それは上記のような専用の取得スクリプトを用意しておくことで簡単に解決出来る。

おまけ

ちなみに、アプリケーション登録をしたアカウントとボットを動かすアカウントが同じ場合は、dev.twitter.comに書いてあるAccess Tokenを使えば良い*1ので、上記の操作すら不要です。

*1:右カラムのMy Access Tokenからアクセス出来ます

2009.09.19

IM::EngineとStardustで3分クッキング

YAPC::Asia 2009で(少なくとも個人的に)話題だったセッションから、StardustとIM::Engineを使って3分クッキングしてみる。(実際どのくらいかかるかはよくわからん。)

概要

Stardust(CPAN, github)は簡単に使えるCOMETサーバ。COMETでStardust…ああ、ネーミングセンスが良すぎる…。てのはともかく、COMETのデモはやっぱりインパクトがあって楽しい。起動すると/channel/の下にAPIが出来て、外からそいつに適当にアクセスすれば話は済むようになっている。APIにPOSTしてあげればデータが登録されて、APIからGETすることで引き出せるってわけだ。

IM::Engine(CPAN, github)はAPI Designのセッションで登場するのだけれど、HTTP::Engineのように使える(らしい)Instant Messaging処理エンジン。なんせインターフェイスがさっぱりしていて使いやすそうだ。

となると、当然やるのはIRCのデータをIM::Engineで引っ張って、Stardustでリアルタイム出力するやつ。と思ってやってみたのだけれど、オリジナルなコードはほとんどなしに書けてしまう。なんてラクチンな世の中。

方針は、IM::Engineを仕込んだスクリプトを使って、発言の度に別で立てたStardustにPOSTする。StardustはAPIとして使って、フロントエンドインターフェイスはペラのHTMLを用意する。HTMLはStardustのDEMOでついてくるcurl_commandsの出力を真似ることにしよう。

Stardustを立ち上げる

ではまず、Stardustから行こう。

Stardustをインストールしたら、起動する。

$ stardust.pl
Please contact me at: http://localhost:5742/

終わり。

StardustはSquatting(CPAN, github)というフレームワークをベースに作られている。(どちらも同じ作者。)小さなフレームワークだが、個人的にはこれまであまり見かけない書き方だったので、ちょっとドキッとした。Squatting::Cookbookがあるので、これを見るとざっくり掴めるかもしれない。3分クッキングではそれで良しとしよう。(本体もさほど大きくないので、ざっと読んでもそれほど苦労は無いが、後述するがちょっと特殊な感じがする。)

StardustのAPI

StardustのAPIは、以下のようになっている:

  • GET /channelでチャンネル一覧取得
  • GET /channel/$fooで任意のチャンネルの情報を取得
  • POST /channel/$fooで任意のチャンネルにメッセージを送信
  • GET /channel/$foo/stream/$connection_idがlong-poll用のAPI

つまるところ、Stardustは基本的に、COMETで必要なサーバ側APIをざっくり提供してくれるわけだ。

ついでなので、ここでデモページを見ておこう。デモページは起動時に--demoオプションを指定しておくと見れるようになる。

% stardust.pl --demo
      The demo is at: http://localhost:5742/demo/
Please contact me at: http://localhost:5742/

で、http://localhost:5742/demo/を見るとcurl_commandsというリンクあるので、そこを辿る。ターミナルから指定されているcurlコマンドを投げれば、ページ内に表示されることが分かるだろう。

インターフェイスになるHTMLを作る

今回作るフロントエンドのインターフェイスは、このcurl_commandsページを参考にする(というかコピーする)。以下のようなものにしてみた。ちょっと長いが。

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <meta http-equiv="Content-Script-Type" content="text/javascript" />
    <meta http-equiv="Content-Style-Type" content="text/css" />
    <title>ShootingStar</title>

    <style type="text/css">
div.message {
    border-width: 0px 0px 1px 0px;
    border-style: solid;
    border-color: #999999;
}
span.time {
    font-size:small;
    color: #999999;
}
span.name {
    color: #666699;
    padding: 0em 0.5em;
}
span.message {
    color: #000000;
}
    </style>

    <script type="text/javascript" src="/js/fx.js"></script>
    <script type="text/javascript" src="/js/jquery-1.3.2.js"></script>
    <script type="text/javascript" src="/js/jquery.color.js"></script>
    <script type="text/javascript" src="/js/jquery.ev.js"></script>

    <script type="text/javascript">
var clientId = Math.random().toString().replace(/\./, '');
jQuery.ev.loop(
    '/stardust/channel/shooting_star/stream/'+clientId,
    {
        incoming_callback: function(ev){
            var dt = new Date();
            jQuery('#messages').prepend(
                '<div class="message">'
                    + '<span class="time">' + dt.getHours() + ':' + dt.getMinutes() + '<' + '/span>'
                    + '<span class="name">(' + ev.incomming.sender.name + ')<' + '/span>'
                    + '<span class="message">' + ev.incomming.message + '<' + '/span>'
                    + '<' + '/div>'
            );
        }
    }
);
</script>
  </head>
  <body>
    <h1>ShootingStar</h1>
    <p>#perl-casual@chat.freenode.net</p>
    <div id="messages">
    </div>
  </body>
</html>

肝になるjQueryの部分は短い。COMET接続部分をjQuery.ev(github)がやってくれるからだ(Stardustと作者は同じ)。あとはちょっと体裁を整えたりとかそういうことだ。$app_root/templates/index.htmlとして保存した。

Stardustのchannel名はshooting_starにした。もちろんこれは任意だが、COMETでStardustときたらShooting Starにせざるを得ない。

アプリケーションのパス構成を変える

で、ここで気づいたのだけれど、このHTMLを表示するにはまた別にhttpdを立てる必要がある(XHRがクロスドメインを越えられないので、同一ドメイン上の必要がある)。まぁ、別に良いんだけど、ちょっと面倒だなぁ…ってことでちょっと脱線して、StardustがベースにしているSquattingを使い、以下のようなパス構成に変更してみよう。

  • / : インターフェイス。上記のHTMLを表示する
  • /js/* : jQueryのJavaScript各種が入るパス
  • /stardust/* : Stardustのサーバを立てるパス

なんでこんなことを言い始めたかというと、ちょっと調べた限りだと、Squattingだと特定のパスに別にアプリケーションを走らせるのが簡単そうだったから。まぁ要するに試してみたいってだけなんだけど。

アプリケーションの名前は(もちろん)ShootingStarとして、次のようなアプリケーションを書いた。Stardustをコピーして書き換えただけだ。(主にいらないところを消す作業になる…。)

package ShootingStar;
use 5.008;
use strict;
use warnings;
use base 'Squatting';

package ShootingStar::Controllers;
use strict;
use warnings;
use Squatting ':controllers';
use FindBin;
use Path::Class qw( dir );

our @C = (
    C(
        Home => [ '/' ],
        get => sub {
            my ($self) = @_;
            $self->headers->{'Content-Type'} = 'text/html';
            return dir($FindBin::Bin)->file('../templates/index.html')->slurp;
        },
    ),
);

1;

まぁ、静的なHTMLなので、今回はViewは省略。てかコントローラもいらないんじゃないかって感じだが、気分を出すためにもコントローラは書いてみた。もちろんSquattingはMVCフレームワークなので、Viewに渡したり出来ます。

起動用のスクリプトは、stardust.plを参考に書く。以下のような感じになった。

#!/usr/bin/perl
use strict;
use warnings;
use ShootingStar 'On::Continuity';
use Stardust;
use Getopt::Long;
use FindBin;
use Path::Class qw( dir );

my $config = { port => 5742 };

GetOptions(
    $config,
    "port|p=n",
);

ShootingStar->mount('Stardust' => '/stardust');
ShootingStar->init();
ShootingStar->continue(
    port    => $config->{port},
    docroot => dir($FindBin::Bin)->subdir('../static/'),
);

/stardustにStardustをマウントしている。あとcontinueメソッドにdocrootで渡しているのは、/js/*などの静的ファイル置き場。continueメソッドは、Squatting自体ではなくてSquatting::On::Continuityに書いてあり、これが簡単なサーバを実現してくれる。

なお、$app_root/staticの中にはstardust/shareの中に入っているjsディレクトリをそのままコピーしてきた。

ちなみに、Squattingフレームワークには、アプリケーション起動用のコマンドsquatting(まんま)がついてくる。libパスを外から指定する方法はなさそうだが、スクリプトを読むとuse lib 'lib'としているので、少なくともlibの上のパスからであれば起動可能だ。

$ cd shooting-star
$ squatting -p 5742 ShootingStar
Please contact me at: http://localhost:5742/

今回こうしなかったのは、/stardustにStardustアプリケーションを立てるなど、ちょっとしたカスタマイズのためである。

あとは指定されたURIブラウザで叩く。きちんと見えていればOK。

IM::Engineを使って発言をStardustにPOSTする

最後に、発言の度にStardustにPOSTするスクリプトを書こう。といっても、IM::EngineのPODに書いてあるサンプルコードをそのままコピペして、ちょっとだけ書き換えれば良い。

#!/usr/bin/perl
use strict;
use warnings;
use IM::Engine;
use AnyEvent::HTTP;
use JSON::Syck;

IM::Engine->new(
    interface => {
        protocol => 'IRC',
        credentials => {
            server   => "chat.freenode.net", # 任意
            port     => 6667,
            channels => ["#perl-casual"],    # 任意
            nick     => "shooting-star",
        },
        incoming_callback => sub {
            my $incoming = shift;
            return unless $incoming->sender->name;
            my $message = sprintf( 'm=%s', JSON::Syck::Dump({
                type      => 'incoming_callback',
                incomming => $incoming,
            }));
            http_post(
                'http://localhost:5742/stardust/channel/shooting_star',
                $message,
                sub { printf "%s\n", $message; }
            );
            return 1;
        },
    },
)->run;

これでIM::Engineも終わり。チャンネルのところは自分で好きなのに変えておいてください。起動しよう。

$ script/im_engine.pl

完成!

さて、何かしら発言があるのを待とう。あるいは自分で発言したりしても良い。問題なくブラウザ側でも見れたら完成。

ちなみに所要時間は、素晴らしくいろいろ脱線してコードを読んでたので、まったく3分どころじゃなかった。

今後の展望としては、まぁログを取っておいて最初の接続時にちょっと流すとかか。頑張ってください。

ここから先はおまけ

以下はおまけ。さくっと見てみた感想。

Squatting

割とコンパクトなので、Catalystのように読むのに苦労することもないと思われる(相対的な話だけど)。あまり見かけない(気がする)書き方なのだけれど、YAPCの懇親会でご本人プロトタイプベースのオブジェクト指向が好きだと言っていて、そう思って読み返すと多少すっきりするかも。

面白いのは、特定のパスに別のSquattingアプリケーションを割り当てたり出来る点。そういうことをmod_rewriteなどに頼らず出来るのは、ライトユースには便利かもしれない。

例えば、お遊びでCGI書くこととかあるけれど(大きなフレームワーク使うほどじゃないからCGIでいいや、みたいな時だが)、CGIの代わりにSquattingを動かしておいて、その下の特定のパスには必要に応じて別にアプリケーションを差し込むとかが出来そう。

と思って、上記ではSquattingを使ってトップページを作り、適当なパスにStardustを割り当ててみた。もともとStardust::Demoは、--demoのオプション指定時に動的に/demoに差し込まれるようになっている。

Tenjin

「とても速い」テンプレートエンジンらしい。StardustやSquattingが各ページの描画に使っている。

ベンチマークを信じるならTTの5から10倍か。そしてとても対応言語が多い。テンプレート部分の書き方は割合オーソドックスなので、さほど構えずに使えそう。(しかしTTに慣れきった自分には…。まぁ、使い分けなんだろうなぁ。)

とか言いながら今回は省略した。

[perl] TTより5倍速い?テンプレートエンジン"Tenjin"を試す - ありんく tech-logなんていう記事があった。

ちなみにフレームワークとしては、Cookbookにも書いてあるけれど別にテンプレートエンジンに縛りがある訳ではない。TTでももちろんOK。

COMET -> Stardust -> Shooting Star

何の話かってことだけれど、一応。毎年定期的に発生する流星群は、「母彗星」と呼ばれる彗星が吹き出した「ダスト」によって生み出される。なので、「彗星」→「ダスト」となったら次は「流星」なんです。

2009.07.25

日食観望:佐多岬/田浦

日食を見に行ってきた。

まず、鹿児島の最南端、佐多岬で日食を見ようと計画した。佐多岬は食分0.98(全体の98%が欠ける)で、皆既にはならないが地続きの範囲内では最大の食分となる。皆既になるのとならないのでは大きな違いではある(らしい;見たこと無いし)が、かといって皆既帯の中まで行くことも出来なかったので、可能な範囲内の最大を目指してみた。


大きな地図で見る

現地到着は当日の午前2時。到着した時には、既に40台を超える車がゲート前に並んでおり、ゲートの開門時間を待っていた。自分たちも最後尾に並び、空を見上げる。湿度は非常に高く、うっすら霧がかかっていたが、一応明るい星を見る事が出来た。ひとまずそのまま待機。

R0011101

移動するなら5時くらいがタイムリミットと考えていたため、午前5時まで待って再検討を行う。その時点では現地は雨で、多少雷もあるらしい。この日のために準備しておいたデータカードを使ってネットに繋ぎ、天気予報や天気図、ひまわり画像をチェックして検討した。ひまわり画像によると、天候は北西から回復するが、鹿児島では難しそうだった。このまま残って佐多岬の行く末を見るのもなかなか面白いとは思ったものの、今回はもともと皆既ではなく、可能な限り最大の部分食を見に来た訳だから、見れることを優先しようと言うことで、北に向かって移動することに決定。

R0011102

佐多岬出発の時には、車列は80台以上に延びており、帰路でもたくさんの車とすれ違った。もちろん、もし見れるなら佐多岬がベストなので後ろ髪を引かれる思いだったが、今回は単純に可能性だけを評価することにして、北西に走る。

移動中もひまわり画像とにらめっこしつつ、およその行き先を決めていった。北に行き過ぎると食分を犠牲にするので、晴れるぎりぎりを目指したい。天候は北西から変わるので、北に行くだけでなく西にも移動し、熊本の海岸側が良いだろうと判断。気象庁による熊本の天気予報はさんざんだったが、衛星画像でもその辺はちょうど晴れそうだったので、予報を無視してとにかく行ってみることに。

結局は田浦の「御立岬公園」に行き着いた。

R0011107

到着時点では薄曇りで、太陽は見れたり見れなかったり。ただ、雲は流れていて、太陽もたまに顔を出しているし、今後さらに回復すると予想されたので、そのまま留まった。結果的には無事回復していったので、ほぼ全課程を観察出来た。

R0011116

食分が0.8を超えた頃から、周囲はうっすら薄暗くなり、体感温度も若干下がったように感じる。多分実際の気温の変化はさほどではなく、太陽からの赤外線が減ったためにそう感じるのだと思われる。空も不思議な色になってきた。鈴虫が鳴いてツバメがえさを採りまくっていた。夕方のような雰囲気だ。

R0011117

最大食の頃の太陽。もともとGX200しか持って行っていなくて、投影像で撮ろうと思っていたのだけれど、テレ端(35mm版換算で72mm)でもなんとか欠けている様子が分かるということに気づく。これならテレコンとND用意しておけば良かった…。いい具合に雲が被るタイミングがあるので、それを狙って撮ってみた。

R0011125

やや露出オーバー。これが最大付近なのだけれどちょっと太っている。太陽は難しいなぁ。

ビクセンの眼視用日食グラスをレンズ前に当てても撮れるっぽい。露出時間がちょっと長くなるので三脚に載せて。

R0011129

コンパクトデジカメでも撮れるのか。コンデジをなめてた。ちゃんと準備しておけばもうちょっとマシなものが撮れたかも。次回は頑張ろう。(しかし次回は一眼であってほしい。)

おなじみ?木漏れ日。最大の頃はどうにも太陽が暗すぎてよくわからない。が、どうも自分には写っているらしいことに気づいた。

R0011130

つまり白いスクリーンが必要なのかと気付き、ちょっと最大食より太ったが紙を並べて試してみる。

R0011134

てな具合で無事見る事が出来ました。食分0.94程度だったけれど、十分欠けてた。しかしやっぱりばっちり皆既が見てみたいなぁ。

ちなみに、日食だけのために行った訳ではなくて、途中でいろいろ寄り道しました。

R0010945R0010976R0011042R0011051R0011056R0011059R0011061R0011069R0011074R0011003R0011160R0011168R0011187R0011215R0011222

2009.04.07

色のアクセシビリティについて思う事

当然だけど、色弱の人にはカラースターの色の違いが分かんない。 - 日々、とんは語る。

これを読んで初めて「緑」の存在に気づいた。連鎖的に考えた事を記す。ちなみに自分は色覚異常だけど特に困った事はほとんどない軽いもの。程度の差があるのでこれが全てだとは考えないでほしい。

「色が見えない」のではなくて「分離出来ない」

色覚異常で困った事は本当にほとんどないが、高校の授業で絵を描く際に、友人に「見えている通りに描けば結果同じになるんじゃないの?」と言われたことがある。そういう問題ではない事は確実で、一部の色が分離出来ないのだ。例えば緑と燈が同じ色に見える時、見えている通りにと言われても、どっちの色を塗ったら良いのかがわからない。

逆に、色が見えないんだと思っている人もいるみたいだが、もちろんそういう人もいるだろうが大抵そうではなく、「判別が出来ない」のであるということに注意してほしい。

自分の場合、明るさやいろいろな条件で変わるのだけれど、ほぼ確実に駄目なパターンの一つとして、「薄い水色」「薄いピンク」「薄い灰色」はほとんどの場合で判断出来ない。もともと水色とピンクは厳しいが、「薄い」とかなりヤバい。普通の人もそうなんじゃないかと思っているのだけれど、どうもそうではないらしい。

しかし「ふわっとやさしい色」を使っている事はわかるのだ。その差異に重大な情報が載っていなければ、問題になる事なんてほとんどなく、また、「ふわっとやさしい」を伝えたいなら(大抵はそのパターンだろう)、少なくとも自分と同じようなレベルの色覚異常の人には十分に伝わっている。

「区別しやすい色」だけではなく別の方法を

よく言われるが、色だけに情報を持たせないことが基本。色以外の情報だと、例えばアイコンやその他の表現方法に加え、位置なども情報になりうる(例えば信号の色は位置が決まっている)。

あと、原色ばかりとかにしても意味ないという事も付記しておきたい。原色は別に判断しやすくはないように感じるが、それはともかくとして、前述の一文が言っているのは「色だけに情報をのせるのが良くない」であって、「わかりやすい色にしよう」と言っているのではない事に注意したい。

「わかりやすい色」はそれぞれなので、原色を使えば全て解決とか、そういう安易な事にはならない。色覚異常の見え方シミュレータもあるが、あれで判別しやすい色の組み合わせを見つけたところで、「色だけに情報を載せる」事になったら意味が無いのだ。

また、色の判別が難しくても、(もちろんその判断は人それぞれだけど)綺麗だとかそうでないとかはわかるし、どちらかというなら綺麗なほうが好ましく見える。アクセシビリティとデザインは両立出来ない課題ではない。「区別しやすさ優先」ではなく、普通に見て綺麗な色の組み合わせで構わない。そういう組み合わせは、たとえ判別出来なくても、綺麗に感じるのだ。ただ、色だけに頼らず多角的に情報を伝える事、そういった事が重要なのではないか。

自分は色の見え方をワンパターンしか知らないので、「普通の人」や「他の色覚異常の人」がどう見えているか、どういう意見があるかはわからない。でも少なくとも、綺麗かそうでないかはわかるんだよ、と言いたい。この手の話は、大概色の判別しやすさに行くが、そうではない方向でのわかりやすさを目指してほしい。

2009.03.26

perlでUTF-16LE + BOM

稀に、ファイルをUTF-16LE + BOMで保存したいということがある。

そもそもBOMが付いている訳だから、エンディアンがどうであるかを気にする必然は無いと思うし、特定のエンディアンしか読めないのならUTF-16LEと言い切ってしまえば良い訳で、その場合BOMは無用の長物だ。とはいえ、そういうことがしたい場合もあるにはある。(Winとかそっち方面で…しくしく。)

今日は「そういう事がしたい場合」だった。そこでperlで変換スクリプトを書こうと思ったのだが、UTF-16LE + BOMってどう変換するのかがいまいち不明だ。そういうエンコードの指定がある訳ではなさそうだし。ということで、普通にUTF-16LEでencodeしてからBOMを付けることにした。

#!/usr/bin/perl
use strict;
use warnings;
use Encode;
use Encode::Guess;
use Getopt::Std;

my $opts = {}; getopt( 'I', $opts );
my $buffer = join '', <>;
my $enc = $opts->{I} ? $opts->{I} : do {
    my $e = guess_encoding( $buffer );
    ref $e ? $e : 'utf-8';
};
print pack('H*','fffe'), encode( 'utf-16-le', decode( $enc, $buffer ) );
exit;

BOM = Byte Order Markはファイル冒頭、最初の文字より前に入る特殊文字でFEFFが割り当てられているが、これがエンディアンによってFFFEになる(表現される)ことを利用して、エンディアンがどちらかを見分ける。

ということで、LEの場合は逆転させてfffeを頭に付けてあげればOKなはず。スクリプトではファイル内容を読んでEncode::Guessで推測すると言った処理もしている。(doとかちょっと気持ち悪いが…。)ただしこのコードだと最初にファイルを全部メモリ上に置くことになるので、大きいファイルを扱う場合はもう一工夫必要そう。

で結局のところ、正解はどんなんだろう。

cf. Encode::Unicode - search.cpan.org

2009.02.21

Mac入門者のための特殊キー+マウスコンビネーションの基本

Macはもともとマウス主体のインターフェイスなので、いくつかの特殊キーとマウスを組み合わせたショートカットがいろいろと存在しています。しかし、意外とその手の情報をWebで見かけません。

キーボードショートカットの解説はごまんとありますし、全てキーボードで操作したいニーズもあるのだろうと思いますが、逆にマウスカーソルは、一気に2次元的な動きが出来る訳なので、うまく使えば1次元的なキーボードより直感的で効率的なことが出来るのではないでしょうか。てのは言い訳ですが、マウスまわりのショートカットの基本をざっくりとまとめてみました。

ホームポジション

本題に入る前に、Macを操作する際のホームポジションの話。もちろん、キーボードを打つ時は普通にキーボードのホームポジションを使えば良いですが、マウス操作をする時は、左手はキーボードのポジションのまま、右手だけマウスに持っていくのが基本ですね。

そんなの当たり前と思うかも知れませんが、基本的なキーボードショートカット(Undo、カット、コピー、ペースト、全選択、保存、複製、検索、終了、ウィンドウを閉じる)は左手一つで操作できるようになっていて、右手がマウスにあっても操作に困りません。むしろこれらを同時に使い、マウス操作と組み合わせて効率が上がるというもの。

また、ここでは、コマンドキーやオプションキーといった特殊キーとマウス操作を同時に行うようなモノを紹介したいのですが、すばやく特殊キーを押すためにも、左手はキーボードのホームポジション付近を守っているほうが良いでしょう。

ちょっと脇道にそれると、昔のMacのマウスにはボタンが1つしかありませんでしたが、これで特に困らないのもこのポジションのためと言えるかもしれません。OS 8くらいから導入された(Winからの輸入ですね)コンテクストメニューは、Control + マウスクリックという、右クリックに慣れた人には厄介な代物だと思いますが、Mac使い的にはこうしたポジションに慣れているので、大きな問題はなかった訳です。(とはいうものの、当時結構戸惑ったのは確かで、そのおかげというか、FinderPopという機能拡張(長押しでコンテクストメニューが開く、その他の機能追加)が流行しました。)

ファイル操作

まずはFinderの操作です。

クリック選択 
Command + クリック複数ファイル選択 
Shift + クリック複数ファイル選択最初に選択されていたものと、Shift + クリックされたものの間を全て選択
ダブルクリック開く
Command + ダブルクリック別ウィンドウで開く/同じウィンドウで開く『フォルダを常に新規ウィンドウで開く』設定次第で変化
Option + ダブルクリックファイル・フォルダを開いてウィンドウを閉じる開いた後にそのファイル・フォルダの置いてあるウィンドウを閉じる
ドラッグ移動 
Command + ドラッグ移動してグリッドに合せる/グリッドを無視する『常にグリッドに合せる』設定次第で変化
Option + ドラッグコピーする 
Command + Option + ドラッグエイリアスを作る 
フォルダにドラッグして(クリック状態のまま)暫く待つ重ねているフォルダが自動で開くショートカットではないけれど一応書いておく

キーボードショートカットにも言えることですが、Macではかなりのアプリケーションについて、基本的なショートカットがFinderと共通になっているので、上記の操作はFinder以外でも使えたりします。

例えばファイルコピーをする際のOption + マウスドラッグは、PhotoShopやその他のペイント or ドローソフトでも同様に、何らかのオブジェクトのコピーに対応していることが多いです。

あと、最後の『しばらく待つ』は、スプリングフォルダと呼ばれる機能ですが、驚異的に便利な事が多いので、書いておきます。スプリングまでの時間は設定で変更出来ますが、急いでいる時はスペースバーを押すとすぐ開きます。

ウィンドウ操作

これはFinderに限らずウィンドウ全般について。

アクティブなウィンドウのタイトルをCommand + クリックファイル階層をメニューとして表示(もちろん開ける) 
アクティブでないウィンドウのタイトルバーをCommand + ドラッグアクティブにせず移動裏にあるウィンドウをアクティブにせずに動かしたい時など
閉じるボタンクリックウィンドウを閉じる 
Option + 閉じるボタン全てのウィンドウを閉じる 
最小化ボタンクリックDockにしまう 
タイトルバーダブルクリックDockにしまう最小化ボタンと一緒
Option + 最小化全てDockにしまうちなみにDock内の最小化されたウィンドウをOption + クリックで『全てDockから出す』
Shift + 最小化ゆっくりDockにしまう←これはオマケ。Shiftを押している時はExposeとかもゆっくりになる
拡大ボタンクリックウィンドウを適当なサイズに拡大・縮小 
Option + 拡大全てのウィンドウを適当なサイズに拡大・縮小 
アクティブでないウィンドウをクリックアクティブ(前面)にする 
Option + アクティブでないウィンドウをクリック選択されたアプリケーションをアクティブにして、アクティブだったアプリケーションを『隠す』『隠す』は起動したままウィンドウが見えなくなるコマンド

ちなみに『全てのウィンドウ』は『そのアプリケーションが管理する』全てのウィンドウということになるので、例えばSafariの全てのウィンドウを最小化してもFinder等の別アプリケーションのウィンドウは最小化されません。

あと、『拡大』ボタンは、+マークが付いているのでいかにも大きくなりそうですが、Winでいう『全画面』とは違って『最適化』に近いもので、適当なサイズに広げてくれる、と言うような機能になっています。(広げた後に押すと元のサイズに戻してくれます。)

Macでは全画面を占有するような作りのアプリケーションは、まったく無い訳ではないのですがあまり多くはありません。Winでは、アプリケーションを全画面にして使う人を割と見かけるので違和感がある人もいるかもしれませんが、慣れるとどっかしらにデスクトップが見えてないことが不安になるようになります。(たぶん。)

どうしても全画面にしたいという人は、megazoomerというSIMBLプラグインを入れると幸せになれるかもしれません。(もちろん自己責任でどうぞ。)

まとめ

というわけで、基本的なものについて紹介してみました。キーボードショートカットやコンテクストメニューも便利ですが、特殊キーと組み合わせたマウス操作を使いこなすとさらに選択肢が広がるのではないかと思います。うまく使って快適なMacライフを送ってください。