UbuntuでDwarf fortressを動かそうという奇特な人へ

Ubuntu 10.04 (IA_64)でDwarf fortressを動かそうとしたら

./dwarfort.exe: error while loading shared libraries: libncursesw.so.5: cannot open shared object file: No such file or directory

とか怒られる場合は「lib32ncursesw5」をSynapticパッケージマネージャからインストールしましょう。

動いた!

Windowsがどんなにクソだろうがインストールしておくべき3つの理由

先に言っておきますが、拙者はわずか1年前まではWindows一本の人で、その他のOSなんかクソだと思ってました。

Macに最初に触れたのは、卒業後初めて就職した会社で、共有ディレクトリにMacバイナリぶちこんで壊しまくるのを目の当たりにしてこんなクソOSつかわねー!と心に誓いました。あと、その後出会ったムカつく奴が大概Mac信者だったから(これが一番デカい

鯖管の仕事ではCentOS,RHEL,FreeBSDなどをメインに使ってましたが、デスクトップ環境にXを使うのとか2,3回試したきりで、使い物にならなくてすぐやめました。単なる技術的趣味で使う意図以外、私のスキルじゃ開発やらネット巡回さえまともに行えないものだと思ってました。

一年前までは。

VistaのようなクソOSのバージョンアップを見送り、私がWinXPでくねくねしている間に、気がつけば世間はあっという間に様変わり。

OSXBSD系にMacのツラを被せたOSとなり、Ubuntuは「まず"使える"こと」を目標にリリースと共に洗練を繰り返していて、フリーライセンスのOSにもかかわらずぶったまげるほどのCOOLさと完成度を備えるに至っていました。

そんなわけで、定期的に訪れる技術的興味に惹かれてまたも新OSを試し始めたのが一年前。ちょうどiPhoneの開発も手がける事になり、不慣れなMac機を客先に借りる事になったのも一年前のこと。

そのときはどうせすぐWindowsに帰ってくると思ったんです。だってフリーソフトいっぱいあるし。使いやすいし。

でもね。OSX/Ubuntuに触れて、Windowsの時間は10年前から止まってるみたいに感じました。で、Windows7出たけど、デスクトップがクネクネするから何だっつーのよ。とか。

でもね。Windows7とか実は使った事無いんです。世間が7発売で盛り上がってる頃、私は生まれて初めてWindows以外のOSの世界に飛び込んで、キャッキャウフフの最中だったんですから。

Windows嫌いじゃないんです。少なくとも15年はお世話になったし。NT3.5時代からだもの。だけど、僕にとっての「選択肢」が初めて出現したんだと思うんだ。だから、自分がPCに期待するアクションをそれぞれどう感じたかの評価をまとめてみようと思う。

起動から使えるようになるまで

Ubuntu:超はぇえ
OSX:早い
Windows:クソ遅い

ちなみにほぼ同一スペックのCore2Duo 2.4〜3GHzマシンでの体感。

Eclipse

仕事が開発だけに、どこでも動くSubversionクライアントとエディタ兼用で3年前ぐらいからEclipseを使うようになりました。一つには仕事のメインツールだけに、これが動かないと話にならないのですが幸いJavaで書かれてるのでOSを気にしなくてよかったのでWin離れに一役買いました。

Winである必要なし

ブラウザ

IEはそもそもブラウザとして論外なので動かなくて問題無いです。もっとも銀行系やらIE以外のブラウザサポートを拒絶してる時代がありましたが、最近はさすがにFirefox/Safariぐらいは対応してくれるようになりました。IE専用とか書かれるとそれだけで「見る/使う必要がない」と判断してるので全く困りません。
Safariは使わずにChromeFirefoxなので、どちらも(ほぼ)最新版がOSX/Ubuntuで動くので全く問題なし。
数年前までSleipnr使ってましたが、ロボなんとかというアドウェアが同梱されるようになってすぐに捨ててFirefoxに乗り換え。ここんとこChromeでしたがTomblooすごすぎでやっぱりFirefoxにもどってきました。Winで使ってた時はクソ重いブラウザだと思ってたけどOSX/Ubuntu64で動かすとアホ早いので問題なしです。

Win以外でつかうほうがいいです。でもIEの動作確認には必要。ものすごいバッドノウハウ

Twitter

TweenやらTwitやらTwitter専用クライアントを乗り換えてきましたが、複数のOSを渡り歩くようになってからはPeraPeraPrvさんのお世話になってます。こちらもJavaクライアントなのでOSを気にせず使い勝手が変わらないのはすばらしいの一言。
最初コメ付きRTがなくてがっかり・・・とTweetしたら「設定でOffになってるだけ」と教わりました。P3ではQTと言うようですね。

自分が使う機能は過不足無くあるのでWinである必要なし。

SSH

開発やら鯖管の仕事では必須のツール。インストール直後からアイコン一発で起動するOSX/Ubuntuサイコー。TeraTermやらPuttyやらGuevaraやら、お世話になったけど、単なるSSHが一番よかったです。

Winじゃソフト入れて設定作業しないとつかえない。Winイラネ。

メール,ToDo管理,RSSリーダー

3年以上前からネット経由なので専用クライアントでやる気なし。

Winイラネ

IM

OSXはちと面倒かも。MSN/GoogleTalk/Skypeがメインなので、別途クライアントいれないと?統合ツールあるのかな。調べてない。
Ubuntuは全部しゃべれる奴が最初から入ってます。すばらしい。
Windowsは・・・mirandaでも入れとけ。

Ubuntuさいきょー!

ニコニコ動画

結論は「Winが最適」
理由はUbuntuFlashプラグインでは日本語入力がまともにできず、コメントがつけれないため。じゃあOSXでやればいいじゃん?ていうけど、OSXはゲストにはなれないのでそうすると、ゲストOSとしてWinまたはネイティブWinで動かすしかない。

OSX・・・といいたいところだがWindows無いとだめかなぁ・・・

DirectXゲーム

FPS好きなので、やはりフルスペック動作させるには仮想マシンじゃ厳しいんでしょうね・・・というわけでこればっかりはWindowsの一人勝ちです。そりゃMacでもゲームは出てますが、やりたいゲームはWindows(かXBOX)にしかないのですが我が家はコンシューマ機を買わない方針なのでWinゲーム1本。こればかりは譲れない。

こればかりはWindowsじゃないとだめ。

まとめ

いままでWindowsを使い続ける理由がたくさんあったので数えてみようなどと思った事はありませんでした。今日、自分がPCに期待することをこうして並べてみると、もはやWindowsを維持する必要はたった3つになりました。

「ゲーム」と「ニコニコ動画」と「IEで動作確認」

まだまだWindowsとつきあう日々は長そうです。

[雑感]Firefoxのメニューバーとか消してみる

ちなみにFirefox3.6,Ubuntu9.10での話。

  1. Personal Menuをいれる。「メニューバーで非表示にする項目」は全部選択。
  2. Hide Menubarをいれる。
  3. userChrome.cssに下記を追記。
    (場所がわかんねー!って人はChromEditでも入れるとよろしい。[ツール]->[ChromEdit Plus]->[ChromEdit]でいきなり編集できる。)
/* prevent menubar shows after pressing alt */
toolbar[autohide="true"]{visibility:collapse}
/* prevent menus shows up after pressing alt+* */
toolbar[autohide="true"]>*{display:none}

これはHide Menubarの機能によりALTキーで(すでに空っぽになった)メニューツールバーがトグル表示されるのがうざったいのでuserChrome.cssでそもそも出てこないようにする為。

第39回PHP勉強会@関東にいってきました

Event Entry::第39回PHP勉強会@関東に株式会社ディノさんにお邪魔してきました。
下の階がウノウ/サノウさんでびびったw

・AuthComponentをちゃんとテストしてみようとおもた。
ディストリビューターとして貢献できるのはうれしいことだな、と改めて認識。今後もビビらずにテストケース書いてチケット投げてみよう。
・SetクラスをhogeらないとCakePHPのモデルは冗長にしか感じないだろうなぁ。
PythonTrac,RubyRedMineとくればPHPChawってことですね!
・gitの作者が日本人だとは知りませなんだ。しかも一人とか。yandodさん曰く「世界に誇っていい」と全くその通りかと思います。
ビジネス忍者www
・docrtineがすごいよさそうに見えたのでひさびさにsymfonyに戻ってみようかな、と一瞬思いました。
・アシアルの中の人に聞いたらVS.PHPが継子扱いでワロタw
Delphi for PHPってなんぞ・・・
・Fabien働き過ぎ><

以上備忘録でした。

Event#fire()でネイティブイベントも対応させる

どにかならんもんか・・・と思っていたら、見事に先人の知恵を発見
Prototype.js 1.6.0 - Event.fireでNative DOM Eventを呼び出し可能にする

ただし

  • コメントされてるけどW3C_MOUSE_EVENTSのIE対応んとこに抜けが1行
  • ネイティブイベント時にfireの第二パラメータに渡せるmemoが渡らないという罠がある

ファイルで公開されてないので引用そのままコードコピペって追記!(暴挙

Object.extend(Event, (function() {
 // DOM Level 3 events
 var W3C_MOUSE_EVENTS = $w('click mousedown mousemove mouseout mouseup');
 var W3C_KEYBOARD_EVENTS = $w('keydown keyup keypress');
 var W3C_BASIC_EVENTS = $w('abort change error load reset resize scroll submit unload');

 function createDOMEvent(aEventName, aEventParams)
 {
   var event;
   if(W3C_MOUSE_EVENTS.include(aEventName)) {
     var p = Object.extend({
       bubble: true,
       cancelable: true,
       view: window,
       detail: 0,
       screenX: 0,
       screenY: 0,
       clientX: 0,
       clientY: 0,
       ctrlKey: false,
       altKey: false,
       shiftKey: false,
       metaKey: false,
       button: 0,
       relatedTarget: null
     }, aEventParams);
     if(document.createEvent) {
       event = document.createEvent('MouseEvent');
       event.initMouseEvent(aEventName, p.bubble, p.cancelable, p.view, p.detail, p.screenX,
           p.screenY, p.clientX, p.clientY, p.ctrlKey, p.altKey, p.shiftKey, p.metaKey,
           p.button, p.relatedTarget);
     } else {
       // TODO: IE
       event = doument.createEventObject();   // ここ追加!
       Object.extend(event, p);
       event.eventType = 'on' + aEventName;
     }
   } else if(W3C_KEYBOARD_EVENTS.include(aEventName)){
     var p = Object.extend({
       bubble: true,
       cancelable: true,
       view: null,
       ctrlKey: false,
       altKey: false,
       shiftKey: false,
       metaKey: false,
       keyCode: 0,
       charCode: 0
     }, aEventParams);
     if(document.createEvent) {
       event = document.createEvent('KeyboardEvent');
       event.initKeyEvent(aEventName, p.canBubble, p.cancelable, p.view, p.ctrlkey, p.altKey, p.shiftKey, p.metaKey,
                           p.keyCode, p.charCode);
     } else {
       // TODO: IE
       event = document.createEventObject();
       Object.extend(event, p);
       event.eventType = 'on' + aEventName;
      }
   } else if(W3C_BASIC_EVENTS.include(aEventName)) {
     var p = Object.extend({
       bubbles: true,
       cancelable: true
     }, aEventName);
     if(document.createEvent) {
       event = document.createEvent('HTMLEvents');
       event.initEvent(aEventName, p.bubbles, p.cancelable);
     } else {
       // TODO: IE
       event = doument.createEventObject();
       Object.extend(event, p);
       event.eventType = 'on' + aEventName;
     }
   }
   return event;
 }

 return {
   fire_with_native_events: function(element, eventName, eventParamsOrMemo) {
     var event = createDOMEvent(eventName, eventParamsOrMemo);
     if(event) {
       event.memo = eventParamsOrMemo; // ここも追加!
       document.createEvent? element.dispatchEvent(event) : element.fireEvent(event.eventType, event);
     } else {
       Event.fire(element, eventName, eventParamsOrMemo);
     }
   }
 };
})());

// Replace an Element#fire 
Element.addMethods({
 fire: Event.fire_with_native_events
});
  • prototype.jsのロード後に読み込むとfire()でネイティブイベントもよしなにしてくれます。

AjaxでPaginateする

タイトル通り。ぐぐってもスマートな方法が見当たらなかったので、PaginatorHelperからModelまでソースを読む羽目になったが、わかってみれば至極簡単だった。

口で説明するよかサンプルのが早いと思われるので、掲示板でも作りましょうか。

まずモデル。名前はテキトーにThreadに。命名規則にしたがってテーブル名はthreadsね。

<?php
/** 
CREATE TABLE threads (
      id SERIAL NOT NULL -- Postgres以外の人は適当に読み替えて
    , handle VARCHAR(100) DEFAULT '名無しさん'
    , email VARCHAR(100)
    , comment TEXT not null
    , created TIMESTAMP
    , PRIMARY KEY (id)
)
*/
class Thread extends AppModel {
    var $name = 'Thread';
    // ほんとはちゃんとバリデータ書こうね
    var $order = 'created desc'; //最新の書き込みを先に
}
?>


コントローラをつくる。controllers/threads_controller.php

<?php
class ThreadsController extend AppController {
    // RequestHandlerを呼んでおくとAjaxかどうか自動的に判断してくれる
    var $component = array('RequestHandler'); 

  // JavascriptHelperはprototype.jsをview側で読まないなら不要(layoutで読むとか)
    var $helpers = array('Html', 'Form', 'Ajax', 'Javascript'); 

    // 2行で書ける掲示板\(^o^)/
    function index(){
        if(!empty($this->data)) $this->Thread->save($this->data); // $this->dataあったら投稿
        $this->set('threads',$this->paginate()); // 再表示
    }
}
?>

次にビュー作る。views/threads/index.ctp

<?php
    $javascript->link('prototype',false); // prototype.jsを読み込みlayoutで読むなら不要

    // 投稿後に最新の場所に移動させるためのURL。
    // order by created descでひっくり返してるのでpage:1。最後ならpage:lastとすればOK。
    $url = '/threads/index/page:1';

    // Ajax.UpdaterをかけるDOM_ID
    // optionsにarray('update'=>DOM_ID)って書くのダルいからcompact('update')ってかけるように$update
    $update = 'ThreadsIndex';  
?>
<?php if( !$ajax->isAjax() ): ?>
    <h2>掲示板だゴルァ</h2> <!-- Ajaxリクエストじゃなかったらタイトル表示 -->
<?php endif; ?>
<?php echo $ajax->div($update) ?> <!-- AJAXリクエストの時は表示されない -->
    <?php echo $paginator->prev("<<",compact('update'))?> 
    <?php echo $paginator->numbers(compact('update'))?> 
    <?php echo $paginator->next(">>",compact('update'))?>
	
    <?php if(empty($threads)):?>
		<p>書き込みはまだありませんが何か(゚Д゚)?</p>
    <?php endif;?>
    <?php foreach( $threads as $thread ):?>

    <!-- カキコ表示ループ部分 エスケープわすれてはならぬぞ -->
    <div>
        <p>
            <?php echo $html->tag('span',$thread['Thread']['handle'],array('title'=>$thread['Thread']['email']),true)?>
            <?php echo $html->tag('span',$thread['Thread']['created'],array(),true)?>
        </p>
        <p>
            <?php echo $html->tag('span',$thread['Thread']['comment'],array(),true)?>
        </p>
    </div>
    <?php endforeach; ?>

    <!-- このへんからフォーム -->
    <?php echo $ajax->form(null,'post',compact('update','url'))?>
        <!-- ほんとうは普通にform->input並べようね -->
        <?php echo $ajax->Form->inputs(array('Thread.handle','Thread.email','Thread.comment'))?>
    <?php echo $ajax->Form->end('投稿')?>

<?php echo $ajax->divEnd($update) ?> // AJAXリクエストの時は表示されない

CakePHPの流儀を知らないとかなり意味不明な感じになりますが(アクションとかマジで)
とりあえずこんな記事読む人ならCakePHPはそれなりに使ってるだろうということで要点だけ

  • $ajax->div(),divEnd()はAjaxでリクエストされた場合、何も出力しない
    • 何も考えずにAjax/通常リクエストを1つのビューで出力すると同じIDのDIVがどんどん増えちゃうのねw
  • ビューでAjaxかどうかの分岐には$ajax->isAjax()を使う
    • あんまりにも2つのビュー(AJAXとそれ以外)が違う場合はコントローラで$this->RequestHandler->isAjax()で分岐して$this->render()とかやるべき?
  • $ajax->form(),$paginator->prev(),next(),numbers()などは$options['update']='DOMエレメントのID'を投げてあげると全部AjaxリクエストとしてよしなにEvent.observe吐いてくれます。
  • Configure::write('debug',0)にしないとデバッグライトがずどーんて出るので適当に(beforeFilterとか)挿入してネ。

次は同一ページで複数モデルのPaginateネタとかやろう。

Windows版PHPでLOG_DEBUG定数でハマる

発端はCakeLogクラスのwrite関数。76行目あたりから抜粋。

		$levels = array(
			LOG_WARNING => 'warning',
			LOG_NOTICE => 'notice',
			LOG_INFO => 'info',
			LOG_DEBUG => 'debug',
			LOG_ERR => 'error',
			LOG_ERROR => 'error'
		);

LOG_*定数がちゃんと入っていればこの配列は正しく定義されるんだが、Windowsの場合この定数が怪しい。
d:id:Tetsujin:20070524さんが書かれているように、全然違う定義になっとる。

Windowsで上記の配列はどのように展開されるかというと

array
  5 => string 'warning' (length=7)
  6 => string 'debug' (length=5)
  4 => string 'error' (length=5)
  2 => string 'error' (length=5)

なんじゃこりゃ(´・ω・`)

で、何が起こるかというと

  • LOG_WARNING : warning.logに出力
  • LOG_DEBUG : debug.logに出力
  • LOG_INFO : debug.logに出力
  • LOG_NOTICE : debug.logに出力
  • LOG_ERROR : error.logに出力
  • LOG_ERR : error.logに出力

となる。noticeとinfoがすっ飛んだ!

どうすっかなぁ・・・ということで強引にrunkitエクステンションを使ってLOG_INFOとLOG_NOTICE定数を再定義しちゃえばいいんじゃね?俺天才じゃね?

さっそくPHPマニュアルを参照。こんなすばらしい関数が。runkit-constant-redefine

    var_dump( runkit-constant-redefine('LOG_NOTICE',5) );

だが無情にもfalseが返る。悪そうなところもないので、もしかしてrunkitバージョンの問題じゃね?ってことでマニュアルを参照

(PECL runkit >= 0.7.0)

うむ。問題なさそうだが。念のためxamppのphpinfo()でrunkitバージョンを確認したところ"1.0.0-dev"

なんでうごかんの?(´・ω・`)

いやな予感がして英語マニュアルを見る。

(PECL runkit:0.7-0.9)

  _, ._
  ( ゚ Д゚)
  ( つ旦O
  と_)_)

    _, ._
  ( ゚ Д゚)   ガシャ
  ( つ O. __
  と_)_) (__()、;.o:。
          ゚*・:.。

万事休す。CakeLog書き換えるしかないのか?