アクトインディ技術部隊報告書 http://tech.actindi.net アクトインディ技術部隊報告書 Thu, 11 Mar 2010 20:25:11 +0900 ja UITableViewCellの高さを内容に合わせて変化させる http://tech.actindi.net/3477191382 こんにちは。

今回はUITableViewにおいてcellの高さをcellの内容に合わせて変化させるということをやってみます。

Natsuliphoneのソースを参考にさせていただきました。

UITableViewでcellの高さを設定するには、UITableViewDelegateのtableView:heightForRowAtIndexPath:メソッドを実装して高さを返してあげます。
ただ、ここに問題があってこのメソッドが呼び出される時点ではcellができていないのです。
ですので、cellForRowAtIndexPath:メソッドなどでcellを取得してそのcellの高さを返すというような方法をとることができません。

そこで対象となるcellに高さを計算するためのクラスメソッドを実装し、そこで得られた値をtableView:heightForRowAtIndexPath:に返します。

+ (CGFloat)heightWithContents:(NSString *)contents
{
    CGFloat result;
    CGSize  labelSize;

    result = 0.0;
    labelSize = [contents sizeWithFont:[UIFont systemFontOfSize:16.0]
                     constrainedToSize:CGSizeMake(300.0, 10000)
                         lineBreakMode:UILineBreakModeWordWrap];
    result += labelSize.height;

    return result;
}

複数行にわたるtextの高さを求めるにはsizeWithFont:constrainedToSize:lineBreakMode:メソッドを使用します。
sizeWithFont:forWidth:lineBreakMode:メソッドは1行だけのサイズを返しますので、名前にだまされないようにしてください。

参考: Natsuliphoneのソース

]]>
Wed, 10 Mar 2010 15:29:42 +0900
衝突判定でウロウロする http://tech.actindi.net/3477066280 身に覚えの無い商品がAmazonから送られてくる。komagataです。

canvasでウロウロするものに衝突判定を追加してみました。

(今回はAndroidエミュレーターで機種はNexus Oneで動作させてみましたが、webkitなのでiPhone用から何の変更も無しに動いたのは楽でした。)

5554:nexus_one

http://komagata.org/canvas-prowler/3/

(iPhoneやAndroidでアクセスしてみて下さい)

自分で作る前に、文系プログラマー的にはゲームプログラムはどういう実装をすればいいのかを言葉で知りたかったので実装のイメージ的なところを以前のモノと合わせて言葉で説明したいと思います。

移動方法の実装イメージ:

まず、キャラクターの描画はフレーム毎に定期的に(30fpsとかで)描画します。描画はキャラクタの現在持っている座標に単に描画するだけです。

それとは別にクリックイベントをトリガーとしてプレイヤーキャラクターとクリック地点をプレゼンハムアルゴリズムで直線を引き(実際には描画しない)、その直線の座標を配列としてプレイヤーキャラクターの移動のためのバッファ(キュー)に格納します。

キャラクターはクリックイベントには感知せず、1フレーム毎に自分の移動バッファに座標があれば一つづつ消費しながら自分の座標を変更していき、バッファに無ければ何もしません。

クリックイベント時には移動バッファが残っていても空にした上で新しい経路を設定するのでクリックした瞬間に進路を変更します。

衝突判定:

何かが有る度に、それぞれのオブジェクト(プレイヤー、背景、障害物など)を全て走査、それぞれのオブジェクトが持つプレイヤーフラグ、障害物フラグを見て処理します。(これは関係無いオブジェクトも毎回走査することになるのでとてもヘボイやり方でした。イベント毎にイベントリスナーを登録するように次は変更したいです。)

プレイヤーキャラクターの移動バッファの次の移動場所が障害物フラグを持つオブジェクトと衝突している場合に移動を中止して以降の移動バッファもクリアします。

シンプルなドット絵を対象にしているので四角形と四角形の衝突を判定するのはとても楽です。

少しハマったのは、衝突した時点で移動バッファをクリアするのではなく、衝突する一歩前で次の移動地点を見てバッファをクリアしなければならないというところです。

衝突した時点でバッファをクリアすると、見た目上は分かり辛いですが、一歩分障害物にめり込んでいるので障害物に接触した瞬間動けなくなります。

この変な動きも面白かったですが、プログラムを見直して、なるほどなあと思いました。

次回もこれに新しい要素を付け加えたいと思います。

]]>
Tue, 09 Mar 2010 04:44:40 +0900
多段 ssh で vnc http://tech.actindi.net/3476755810 こんにちは!! tahara です。

例えば host1 を経由して host2 に vnc したい場合どうすればいいか調べてみました。 結果 ↓ のページに書かれてあるとおりすれば可能でした。ありがとうございます。

ssh を多段に使ってずっと遠くにあるマシンに port forward する|裏表(Phinloda のもう裏だか表だか分からないページ)

蛇足になりますが、次の手順で host2 に vnc できました。

]]>
Fri, 05 Mar 2010 14:30:10 +0900
MacOSX上でMacPortsを使わずにRails開発環境を作る http://tech.actindi.net/3476702991 MacOSX上などにRails開発環境を複数作らなくてはいけなくて色々試行錯誤しています。
環境は、
  • デザイナーさん制作ツール: Coda
  • Ruby on Rails
  • Apache2
  • MacOSXだったり
  • Linuxだったり
  • 貧乏
という感じで、OS環境を2〜3種跨ぎ、かつ、MacOSXとWindowsは主にデザイナーさんが利用するプラットフォームです。
  1. Linuxなら直にRoR環境を構築してしまえば良いし、デザイナーさん達がLinuxは使うことはない
  2. MacOSXも直にMacPortsなどを利用してRoR環境を構築すれば良いけれど、デザイナーさん達はMacOSXをメインに使うらしいので、勝手に各自RoR環境を構築してみて下さいとも言いがたい
  3. 何か問題が起きた場合に、各自で環境を構築してもらうと、何がどうなってエラーになっているのか探るのが面倒臭い
という状況でした。
適当に考えた末、VirturlBox上にRoRの環境を構築し、そのVMイメージを皆で共有すれば楽チンで良いに違いない!ということで試しに、MacOSXの上にVirturlBoxを導入してみました。
ホスト<=>VM間のファイル共有はNFS。
本当は、VirturlBoxの共有ファイル機能を利用したかったのですが、なんだか上手く動かせなかったのでNFSに。
ローカルのファイルをCodaで編集して、Apache/VirturlBoxがホストするページをローカルのブラウザで眺める、という感じで作業してもらうことになりました。
MacOSXは、NFSなどの上で作業すると、._unkoや、.DS〜というファイルを大量にばらまきますが、この構成の場合、作業ディレクトリはホスト側なのでそういうこともありません。
とりあえず、LinuxとMacOSXをホストにして実際に使ってみていますが、可もなく不可もないような、微妙な環境ができあがりました。
もっと他にナイスな組み合わせを教えてください…。■ ]]>
Thu, 04 Mar 2010 23:49:51 +0900
canvasでウロウロする(2) http://tech.actindi.net/3476597468 火曜日担当なのに間に合わずに水曜日にアップしている2010生まれてこなかった方が良かった男オブザイヤー候補、komagataです。

canvasでウロウロするのをiPhoneにフィットするように修正しました。

canvas prowler2

http://komagata.org/canvas-prowler/2/

解像度がファミコンは224x256に対してiphoneは320x480なので細かいですね。

ソース:2 at master from komagata's canvas-prowler - GitHub

]]>
Wed, 03 Mar 2010 18:31:08 +0900
UITextFieldに入力されている文字数を動的に、非同期に数える。 http://tech.actindi.net/3476570782 2週間連続で原稿を落としたmasudaです。
こんにちは。

あまりググればわかるということは書きたくはないなと思っているので、なかなかネタを見つけるのは難しいです。

今回はiPhoneアプリを書いているときにはまったところで、ググってもなかなか答えが見つからないことを書きたいと思います。

2つあるので2週間はこれで持つ!

とあるUITextFieldによる入力フォームと、UIBarButtonItemによる「完了」ボタンがある画面を考えます。

今回のエントリの目的はUITextFieldに文字が入力されていない、つまり空であるときは、「完了」ボタンを表示しない画面を作成するということです。

ポイントはUIControlEventEditingChangedイベントを使うこと。
最初はUITextFieldDelegateのtextField:shouldChangeCharactersInRange:replacementString:とかを使用することを考えましたが、文字を消去したときにボタンが消えない等々うまくいきませんでした。

サンプルコードを書いてみます。

- (void)setupUserInterface
{
    UIView      *contentView;
    UITextField *textField;

    contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [self setView:contentView];
    [contentView release];

    doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
                                                               target:self
                                                               action:@selector(respondsToDoneButtonTouchDown:)];

    textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 20)];
    [contentView addSubview:textField];
    [textField release];
    [textField addTarget:self
                  action:@selector(respondsToEditingChanged:)
        forControlEvents:UIControlEventEditingChanged];
}


- (void)respondsToEditingChanged:(id)sender
{
    if ([sender isKindOfClass:[UITextField class]])
    {
        // 本当はsenderを用いずにメンバ変数とかにしておけばいいのだけれど、今回はあえて型変換をしてみる。
        if ([[(UITextField *)sender text] length])
        {
            [[self navigationItem] setRightBarButtonItem:doneButton animated:YES];
        }
        else
        {
            [[self navigationItem] setRightBarButtonItem:nil animated:YES];
        }
    }
}

参考
Disable button if textField is empty - iPhone SDK Development

]]>
Wed, 03 Mar 2010 11:06:22 +0900
iPhone アプリケーションの開発 http://tech.actindi.net/3476158930 こんにちは!! tahara です。

突然ではありますが、とりあえず読むべきは iPhone Dev Center にある以下のドキュメントでしょうか。

まずは iPhone ヒューマンイン ターフェイス ガイドライン を読んでみました。

iPhone が他と違うところ

  • 小さい画面サイズ。 480x320
  • メモリ少ない。OS が警告をくれたらすぐにメモリ開放すべすし。didReceiveMemoryWarning
  • 1画面。ある意味 Stumpwm!
  • さらに、同時に1アプリケーション。
  • 標準に準拠してヘルプコンテンツを最小限にすべし。

3つのアプリケーションの形態

  • iPhone アプリケーション
  • Web 専用contents
  • ハイブリッドアプリケーション(上の2つの組み合わせ)

3つのアプリケーションスタイル

  • 生産性型アプリケーション(例 Mail)
  • ユーティリティ型アプリケーション(例 Weather)
  • 没入型アプリケーション(例 ゲームアプリ)

デスクトップアプリを移植する場合はよく使われる 20% の機能のみに絞る。

ヒューマンインターフェイスの原則

  • 自然なメタファで
  • 具体的なものを直接いじる感覚
  • テキスト入力を最小限に、選択肢を提示
  • ユーザの操作に対するフィードバック、効果的なやりとり
  • ユーザが開始でき、それを停止できる動きであること
  • インターフェイスの一貫性

製品定義ステートメントを作りましょう。

  • 対象ユーザを明確化
  • 実装機能の限定

簡潔さと使いやすさ

  • 使い方を明白に
  • 頻繁に使用される情報を画面上部に集中
  • テキスト入力を最小限
  • 重要な情報を簡潔に
  • タップ可能な要素の領域は指先サイズに

製品ステートメントにふさわしい主たる機能に焦点を当て、 簡潔かつ入力を最小限にする。

ジェスチャを適切にサポートする。

  • 単純かつ簡単な方法は必須
  • 新しいジェスチャを定義しない

ブランドはささやかで控え目に。 ただしアプリケーションアイコンにはブランドももりこむ。

一般的なタスク

  • 開始
    • ステータスバーに適切なスタイルを設定する
    • 最初の画面に似た起動画面を用意して感覚的起動時間を短縮する
    • 余計なスプラッシュ画面は不要
    • 基本縦で起動
    • 最後に実行したときの状態を復元する
  • 停止
    • いつでも停止できるように
    • 停止時は次の起動のために可能なかぎり詳細の情報を保存しておく
  • 設定(Settings)と設定オプション
    • 設定は一度設定したら変更しないもの
    • 設定オプションは頻繁に変更する可能性があるもの
    • 理想はユーザに設定を要求しないこと
  • その他いろいろ ... ちょっと省略してしまいました。

ユーザインターフェイスの設計

  • ステータスバーはあまりいじらない
  • ToolBar は 44x44 で5つ以下が妥当
  • Tab Bar はモードの切り替え。 5つまでは横に並んで、それをこえたものは More に。 バッジを表示できる。
  • モーダルビューは煩わしいので乱用しない。
  • Action Sheet はユーザの選択肢でり複数のボタンを備える。 害のあるものは赤で一番上に。
  • モーダルビューは主たる機能が関連する自己簡潔型のタスクで(例 Mail のメッセージ作成)
  • アクティビティインジケータ
    • ステータスバーのは1〜2秒ネットワークにアクセスする場合
    • もっと時間がかかる場合はツールバーに表示
  • 進捗がわかるものは Progress View
  • Text Field は左端に使用目的、右端に追加機能
  • システムが用意しているボタン、アイコンを意図されたとおり使う
    • ユーザにやさしい
    • 工数削減

アイコン、画像の作り方の説明でおしまい。

このようなドキュメントがしっかり用意されているのは素晴しいですね。

]]>
Fri, 26 Feb 2010 16:42:10 +0900
C-s/C-rを使おう http://tech.actindi.net/3476099961 WordPressのことを調べようと思って前フリしてましたが、これまた全然進んでません。

ということなので、最近知ったEmacsの知ってる人には、当たり前な機能を紹介したいと思います。
Emacs使いの方は、C-sはもちろん良く利用すると思いますが、C-sで検索モードに入ってからの、C-w、M-yが便利であることを最近知りました。
C-wで単語単位で検索ワードを漸増しつつ検索できたりしますし、M-yは最新のキルリングの内容で検索できます。

また、C-sの応用として、カーソル移動に積極的にC-s/C-rを利用するのも非常に便利であることを再認識しています。
viだとf〜などが便利なのでfを良く使うのですが、EmacsでもC-sで似たようなことはできるんだなあと。
10年位使っていますが、この10年間だいぶ損をしていたなあと思った次第です。
■ ]]>
Fri, 26 Feb 2010 00:19:21 +0900
プレゼンハムでウロウロする http://tech.actindi.net/3475914255 komagataです。

前回は矢印キーでウロウロしたのでマウスクリックでウロウロするものを作りました。

canvas

http://komagata.org/canvas-prowler/1/

直線や曲線を整数で高速に描画するプレゼンハムアルゴリズムでクリック地点までの経路を計算して近付きます。

グラフィックのプログラミングは間違えても変な動きをしたりして面白いですね!

]]>
Tue, 23 Feb 2010 20:44:15 +0900
Lisp on Rails 第4回 〜 has-many http://tech.actindi.net/3475577346 こんにちは!! tahara です。 Lisp on Rails 第4回です!

今回は ActiveRecord の has_many アソシエーションもどきを実装したいと思います。 前回の belongs_to とほとんど同じです。 ar-has-many-direct-slot-definition と ar-has-many-effective-slot-definition を定義します。

(defclass ar-has-many-slot-mixin ()
  ((has-many :initarg :has-many
             :initform nil
             :accessor has-many)
   (class-symbol :initarg :class-symbol
                 :initform nil
                 :accessor class-symbol)))

(defmethod initialize-instance :after ((self ar-has-many-slot-mixin) &rest args)
  (declare (ignore args))
  (unless (class-symbol self)
    (setf (class-symbol self)
          (sym (singularize (has-many self))))))

(defclass ar-has-many-direct-slot-definition (ar-direct-slot-definition
                                              ar-has-many-slot-mixin)
  ())

(defclass ar-has-many-effective-slot-definition (ar-effective-slot-definition
                                                 ar-has-many-slot-mixin)
  ())

direct-slot-definition-class と effective-slot-definition-class と compute-effective-slot-definition でゴニョゴニョすると上記の slot-definition が使えるようになります。

slot-value-using-class と (setf slot-value-using-class) で関連テーブルの 取得と設定を行います。

(defmethod c2mop:slot-value-using-class
  ((class active-record-class)
   instance
   (slot-def ar-has-many-effective-slot-definition))
  (aif (call-next-method)
       it
       (setf (slot-value instance (has-many slot-def))
             (all (find-class (class-symbol slot-def))
                  :conditons (list (key-sym (class-name class) '-id)
                                   (%value-of instance :id))))))

(defmethod (setf c2mop:slot-value-using-class) :after
           (new-value
            (class active-record-class)
            instance
            (slot-def ar-has-many-effective-slot-definition))
  (loop with id = (%value-of instance :id)
        with column = (str (class-name class) "-id")
        for x in new-value
        do (setf (%value-of x column) id)))

で、だいたいこんな感じで使えるようになります。

(def-record comment
    (:belongs-to post))
(def-record post
    (:has-many comments))
(let* ((post (car (all post)))
       (comments (comments-of post)))
  (mapc #'describe comments))

以上、なんとなく has-many できました。 ソースはこちらから http://github.com/quek/lisp-on-rails

第5回につづきます

]]>
Fri, 19 Feb 2010 23:09:06 +0900
真の豊かさとは何か http://tech.actindi.net/3475492156 今回は、WordPressのフォームネタの続きの筈なのですが、準備が全く間に合ってないので全然関係ない話を。
当社は、社内のコミュニケーションにskypeが活用されているのですが、Emacs派の私とtaharaさんは、もちろんskype.elを愛用しています。
複数人で会話しているので会話が埋もれがちになるのですが、これまでみんなに見ておいて欲しい作業の報告等には、目立つように絵文字をちりばめて派手にしていました。
しかし、それもだんだんスルーされるようになって来たことに危機感を抱いた私は、報告メッセージをAA化し出力することにし、それのためのelispをやっつけで書いてみました。
(defun omatase (arg title name mesg)
  (interactive "p\nstitle: \nsname: \nsmesg: ")
  (let* ((title-chars (append title nil))
         (last-1~3 (last title-chars 3))
         (butlast3 (butlast title-chars 3))
         (last3 (first last-1~3))
         (last2 (second last-1~3))
         (last1 (or (third last-1~3) 12288)))
    (insert (format "
.
┌○┐%s
│%c|ハハ  お待たせしました、%sさん
│%c|゚ω゚)
│%c| //
└○┘ (⌒)
  し⌒ 

%s

  ハハ  以上、よろしくお願いします
 (゚ω゚)
_(_つ/ ̄ ̄ ̄/_
  \/___/
"
                    (if (null butlast3)
                        ""
                      (apply 
                       #'concat 
                       (mapcar (lambda (c) 
                                 (format "\n│%c|" c))
                               butlast3)))
                    last3
                    name
                    last2
                    last1
                    mesg))))
M-x omataseで
title: 死んでもいやです
name: 名無し
mesg: そんなことできません
と入力すると、
.
┌○┐
│死|
│ん|
│で|
│も|
│い|
│や|ハハ  お待たせしました、名無しさん
│で|゚ω゚)
│す| //
└○┘ (⌒)
  し⌒ 

そんなことできません

  ハハ  以上、よろしくお願いします
 (゚ω゚)
_(_つ/ ̄ ̄ ̄/_
  \/___/
という風に出力されます。ただバッファにAAが出力されるだけですが、Emacsって良いですね。
メッセージは依然適当にスルーされています。 ■ ]]>
Thu, 18 Feb 2010 23:29:16 +0900
犯罪的なコミットエンドランを簡単に防ぐ http://tech.actindi.net/3475242539 komagataです。

犯罪的な戦術 - p0t

上記の様な戦術を簡単に防ぐ方法を考えてみました。

リポジトリがsubversionなのでpost-commitのhookを使ってテストを実行し、失敗していたら嫌なメールを送るという方法です。

対象のリポジトリ内のhookファイルに(大抵は/var/lib/svn/#{repost}/post-commit)を以下の様にします。

#!/usr/bin/env ruby

repos, rev = ARGV[0], ARGV[1]
author = `svnlook author #{repos}`
cmd = "cd /var/www/staging/ossuary/current && rake db:migrate:reset && script/spec spec -f progress"
unless system(cmd)
  `mail -s '[ossuary] #{author} made a commit-and-run in r#{rev}' error@actindi.net`
end

[ossuary] komagata made a commit-and-run in rev256 - komagata@gmail.com - Gmail

「komagataはリビジョン256でコミットエンドランを決めた。」

(´・ω・`)・・・。

]]>
Tue, 16 Feb 2010 02:08:59 +0900
Lisp on Rails 第3回 〜 belongs-to http://tech.actindi.net/3474928504 こんにちは!! tahara です。 Lisp on Rails 第3回です!

今回は ActiveRecord の belongs_to アソシエーションもどきを実装したいと思います。 実行時のイメージとしては次のようになります。

(def-record post)
(def-record comment
    (:belongs-to post)) ; comments テーブルは post_id 列を持っている。

(mapcar #'post-of (all comment))
;; => ポストのリストを取得

これを実装するのに Common Lisp の MOP を使ってみます。 インスタンス変数とそのインスタンス変数へのアクセスを拡張することになります。

まずインスタンス変数の拡張です。 ar-belongs-to-slot-mixin に belongs_to のアソシエーションテーブルと 外部キーを持たせ、それを継承した ar-belongs-to-effective-slot-definition を belongs_to のアソシエーションのインスタンス変数とします。

(defclass ar-belongs-to-slot-mixin ()
  ((belongs-to :initarg :belongs-to
               :initform nil
               :accessor belongs-to)
   (foreign-slotname :initarg :foreign-slotname
                     :initform nil
                     :accessor foreign-slotname)))

(defclass ar-belongs-to-effective-slot-definition (ar-effective-slot-definition
                                                   ar-belongs-to-slot-mixin)
  ())

slot-value-using-class を使い ar-belongs-to-effective-slot-definition にアクセスする際に、 foreign-slotname を外部キーとして belongs-to のテーブルから レコードを取得するようにします。

(defmethod c2mop:slot-value-using-class
  ((class active-record-class)
   instance
   (slot-def ar-belongs-to-effective-slot-definition))
  (aif (call-next-method)
       it
       (setf (slot-value instance (belongs-to slot-def))
             (select (find-class (belongs-to slot-def))
                     (slot-value instance (foreign-slotname slot-def))))))

以上、なんとなく belongs-to できました。 ソースはこちらから http://github.com/quek/lisp-on-rails

第4回につづきます

]]>
Fri, 12 Feb 2010 10:55:04 +0900
低価格レンタルサーバーの共有SSLとWordPress (1) http://tech.actindi.net/3474892431 完全にネタが切れてしまいましたので、普段に遭遇する困ったことを書いて行きたいと思います。
月額500円位からの低価格レンタルサーバーと、WordPressの組み合わせは、個人〜中小企業の強い味方なのではないかと思うのですが、SSLのフォームの設置で一癖あるらしい、と風の噂で聞きました。 具体的には、低価格レンタルサーバーでも共有SSLが追加オプションなしで無料で使えることが多いのですが、共有SSLなので、SSLでないURLとはだいぶ違ったURLになります。 例えば、さくらインターネットならば、
http://www.example.com
に対応する共有SSLのURLは、
https://securexxxx.sakura.ne.jp/example.com
になったり、Joe'sウェブホスティングならば、
https://serverxx.instantssl.co.jp/~example
であったり色々です。
どうやら、この辺りの事情とWordPressのデフォルトの挙動の相性が良くないらしいのですが、この辺りをだらだら探っていきたいと思います。
フォーム作成用のWordPressのプラグインは、Contact Form 7を利用することにし、
  • 1. 何が問題の原因なのかを理解する
  • 2. 先達の解決策を探る
  • 3. WordPressをいじれる位はPHPを勉強する
  • 4. WordPressが設置できる位の人なら簡単に設置/設定できるようなプラグインを作る
  • 位の流れで何回かに分けて書いてゆきたいと思います。
    果してPHPも知らない私にプラグインは作れるのでしょうか。■ ]]> Fri, 12 Feb 2010 00:53:51 +0900 Ruby + R http://tech.actindi.net/3474804152 こんにちは。
    masudaです。

    今回はRubyでRを使うというのをやってみようかなと思います。

    RはWikipediaのよると「オープンソースでフリーソフトウェアの統計解析向けプログラミング言語、及びその開発実行環境である。」そうです。

    RubyからRを呼び出すためのRSRubyというgemがあります。
    これがあるとお手軽にRubyからRの機能を呼び出すことが可能です。

    まずはR本体をインストールします。

    次にRubyGemでRSRubyをインストールします。
    オプションでRの場所を指定してあげます。

    Macだとこのようになります。

    sudo gem install rsruby -- --with-R-dir=/Library/Frameworks/R.framework/Resources

    使い方

    require 'rubygems'
    require 'rsruby'
    
    r = RSRuby::instance
    
    r.eval_R(<<-RCOMMAND)
      # 実行したいコマンド
    RCOMMANDS
    

    たったこれだけです。

    x = [1, 2, 3, 4, 5]
    y = [2, 4, 6, 8, 10]
    
    r.eval_R(<<-RCOMMANDS)
      pdf("~/foo.pdf")
    
      x <- matrix(c(#{x.map do |a| '"' + a + '"' end.join(',')}), 1, #{x.size})
      y <- matrix(c(#{y.map do |b| '"' + b + '"' end.join(',')}), 1, #{y.size})
    
      plot(x, y, xlim = c(1, 10), ylim = c(1, 10))
    
      dev.off()
    RCOMMANDS
    

    上記を実行することで、PDFでグラフが作成されます。
    PDFだと何かと便利なので、PDFにしています。

    RubyのArrayからRのArrayには自分はいつも上記のような書き方をしています。
    もっと良い書き方があるのかもしれません。

    私がRをきちんと学んでいないからR単体だけでできるのかもしれませんが、Rubyの強力な文字列処理とRの強力な統計処理、数値演算を手軽に融合できることが気に入っています。

    Rを使っていらっしゃる方は是非一度お試しください。

    ]]>
    Thu, 11 Feb 2010 00:22:32 +0900
    CanvasとWebSocketsでみんなでウロウロする http://tech.actindi.net/3474648989 火曜日担当のkomagataです。

    Metasploitは一回お休みさせていただいてJavascriptのお話しです。

    仕事は主にwebプログラミングなので身も蓋も無い言い方をすると「DBに入れたり出したり」しかしてません。

    「もう文字列処理はうんざりなんだよ!」

    というのは嘘ですが、たまには動きのある見栄えのするグラフィックとかアニメーションとかプログラムしてみたいと思い、HTML5で使えるようになるらしい、グラフィック機能のcanvasと双方向同期通信のWebSocketsを使ってキャラクターがウロウロするだけのプログラムを作ってみました。

    WebSocketsを実装しているのは現状Google Chrome 4以降だけなので、動作してる雰囲気を伝えるために動画にしてみました。

    最近のChromeには実装されているので下記のように簡単にサーバーに接続することができます。

    ws = new WebSocket("ws://localhost:8080/")
    ws.onopen = function() { console.log('open') }
    ws.onclose = function() { console.log('close') }
    ws.onmessage = function(evt) { ws.send('Hello!') }

    CometなどよりとてもシンプルでたちまちWebSocketsが好きになりました!

    Ajaxのように非同期に小さなメッセージをちょこちょこ飛ばすのではなく、1ユーザーに対して1本ガッシリしたラインを繋ぎ、双方向にドカドカ通信するイメージでしょうか。

    真っ先にネットゲーム的なものでの利用方法が思い付きますが、これが標準的なブラウザで使えるようになれば、他の新しい使い方で出てきて斬新なUIが生まれれば良いなと思います。

    とりあえず現状を下記のURLで動かしています。chromeやsafariのnightlyでは動くみたいです。(windows, mac, linuxどれでも動くことは確認しました。)

    http://verdana.komagata.org/prowler/

    ソースは下記です。

    komagata's prowler at master - GitHub

    ]]>
    Tue, 09 Feb 2010 05:16:29 +0900
    CMYK http://tech.actindi.net/3474323393 こんにちは!! tahara です。 今回は Lisp on Rails はお休みで、Ruby on Rails の Paperclip の話題です。

    IE で RGB の画像は表示できますが、CMYK の画像は表示できません。 CMYK から RGB に変換する手もありますが、変換時に結構色が変ってしまいます。 ということでアップロードする画像が CMYK の場合は、 バリデーションではじくようにします。

    まず CMYK の判定ですが、ImageMagic の identify コマンドで可能です。

    ~% identify -format '%[colorspace]' ~/archive/normal.jpg
    CMYK
    ~% identify -format '%[colorspace]' ~/archive/normal-rgb.jpg
    RGB
    

    ただし古い ImageMagic では -format '%[colorspace]' オプションが認識されないので -verbose オプションを使います。

    ~% identify -verbose ~/archive/normal.jpg
    Image: /home/ancient/archive/normal.jpg
      Format: JPEG (Joint Photographic Experts Group JFIF format)
      Class: DirectClass
      Geometry: 290x200+0+0
      Resolution: 72x72
      Print size: 4.02778x2.77778
      Units: PixelsPerInch
      Type: ColorSeparation
      Endianess: Undefined
      Colorspace: CMYK      <=== これ!!
      Depth: 8-bit
      ...
    

    この identify を呼び出して CMYK をチェックするバリデーションを config/initializers/paperclip.rb に組み込みます。

    module Paperclip
      module ClassMethods
        ...
    
        # CMYK は IE で表示できないため、検証でエラーとする。
        def validates_attachment_not_cmyk name, options = {}
          message = options[:message] || "CMYK フォーマットの画像はブラウザによって表示できないため使用できません。お手数ですが RGB フォーマットに変換してください。"
          attachment_definitions[name][:validations][:not_cmyk] = lambda do |attachment, instance|
            original_file = attachment.instance_variable_get(:@queued_for_write)[:original]
            colorspace =
              begin
                attachment.file? && original_file &&
                  Paperclip.run("identify", "-verbose #{original_file.path}")
              rescue
                nil
              end
            if colorspace && colorspace =~ /^\s*Colorspace: CMYK$/
              message
            end
          end
        end
        ....
    

    これでモデルから validates_attachment_not_cmyk というひどい名前のバリデーションが使えるようになります。

      validates_attachment_not_cmyk :picture_1
    

    まとめるとこうなります。

    (incf ImageMagic)
    (decf IE most-positive-fixnum)
    
    ]]>
    Fri, 05 Feb 2010 10:49:53 +0900
    括り出したい http://tech.actindi.net/3474287022 if pred method(100) else method(200) end のようなものを見ると
    method(if pred
             100
           else
             200
           end)
    
    と書きたくなってしまいます。ifは分岐が2つですが、Rubyのcase等の複数への分岐も同じくそうです。 LISPだと
    (method (if pred 100 200))
    
    という感じですが、このifの纏め方は、LISPではすんなり流れるものの、Rubyだとif〜endが重たくみえるので、なんとなく書いてはいけないようにさえ感じます。
    条件演算子なら
    method(pred ? 100 : 200)
    
    という風にすっきりなのですが、なんとなく読みづらいですね。 ]]>
    Fri, 05 Feb 2010 00:43:42 +0900
    Toll-free bridge http://tech.actindi.net/3474198831 こんにちは。
    masudaです。

    今日は節分でしたね。
    あの豆を食べるのが好きです。

    早くもネタが尽きてきました。
    自分がObjective-Cのポテンシャルがわかっていないので(別にObjective-Cである必要は全然ないのですが)、続き物を書くことができません。

    今回はToll-free bridgeについて書いてみようと思います。
    またもやどこにもあるようなネタです。

    Toll-free bridgeについてはHMDTさんなどで詳しく紹介がされています。
    ダイナミックObjective-C (38) Toll-free bridge(1) – 変換コスト0のブリッジ | エンタープライズ | マイコミジャーナル

    CocoaのオブジェクトとCoreFoundationのオブジェクトを相互にキャストするだけで変換することができます。
    たとえばCocoaのNSStringというクラスは、CoreFoundationではCFStringというものに対応します。

    具体例を示しましょう。
    変換の話の前に、CoreFoundationでは初期化はどうするか?

    NSStringであれば

    NSString *hoge = [[NSString alloc] initWithCString:"piyo"];
    

    のように書くところですが、CoreFoundationでは

     
    CFStringRef hoge = CFStringCreateWithCString(kCFAllocatorDefault, "piyo", kCFStringEncodingUTF8);
    

    となります。

    さて、本題のToll-free bridgeによる変換です。
    どのようなときに使うのか?
    具体例を挙げると、NSStringの遅いメソッドであるcharacterAtIndexを呼び出す代わりに、CoreFoundationにあるCFStringGetCharacterFromInlineBuffer関数を使用して高速に処理するなんて使い方をするとか。
    別にすべてCoreFoundationで書いてもかまいませんが、Cocoaを使うよりも幾分面倒なのでこういう適用が多いのではないかと思います。

    NSString                *hoge;
    CFIndex                 length, current;
    CFStringInlineBuffer    buffer;
    UniChar                 ch;
     
    *hoge = [[NSString alloc] initWithCString:"piyo"];
    length = CFStringGetLength((CFStringRef)hoge);
     
    CFStringInitInlineBuffer((CFStringRef)hoge, &buffer, CFRangeMake(0, length));
     
    current = 0;
    while (current < length)
    {
        ch = CFStringGetCharacterFromInlineBuffer(&buffer, current);
        NSLog(@"%c", ch);
     
        ++current;
    }
    

    こんな風にキャストするだけで渡すことができます。
    昔、NSDictionaryの生成をCFDictionaryの生成に変えたところ劇的に速度が向上したことがあったような気がします。

    ]]>
    Thu, 04 Feb 2010 00:13:51 +0900
    Metasploit3で脆弱性を検証する(1) http://tech.actindi.net/3474035399 Penetration Testing | The Metasploit Project

    火曜日担当のkomagataです。

    Gumblerウィルスが猛威を振るっているので流行に乗ってセキュリティネタです。

    脆弱性検証(というか実際に脆弱性を突くので悪用厳禁)ツールのMetasploit3をMacで使ってみました。

    Macportsのはrb-railsやrb-rackが普通のgemとぶつかって入りません。(port editで依存性を外せば入りましたが気持ち悪いです。)

    なので、svnのtrunkを持ってきました。

    % svn co https://www.metasploit.com/svn/framework3/trunk metasploit

    今回checkoutしたのはrevision8340でした。

    % cd metasploit
    % ./msfconsole
    /Users/komagata/code/metasploit/lib/msf/core/exploit/mixins.rb:46:in `require': /Users/komagata/code/metasploit/lib/msf/core/exploit/capture.rb:358: syntax error, unexpected ')', expecting kEND (SyntaxError)
    /Users/komagata/code/metasploit/lib/msf/core/exploit/capture.rb:375: syntax error, unexpected $end, expecting kEND
            from /Users/komagata/code/metasploit/lib/msf/core/exploit/mixins.rb:46
            from /Users/komagata/code/metasploit/lib/msf/core/exploit.rb:216:in `require'
            from /Users/komagata/code/metasploit/lib/msf/core/exploit.rb:216
            from /Users/komagata/code/metasploit/lib/msf/core.rb:52:in `require'
            from /Users/komagata/code/metasploit/lib/msf/core.rb:52
            from /Users/komagata/code/metasploit/lib/msf/ui/console/driver.rb:1:in `require'
            from /Users/komagata/code/metasploit/lib/msf/ui/console/driver.rb:1
            from /Users/komagata/code/metasploit/lib/msf/ui/console.rb:10:in `require'
            from /Users/komagata/code/metasploit/lib/msf/ui/console.rb:10
            from /Users/komagata/code/metasploit/lib/msf/ui.rb:10:in `require'
            from /Users/komagata/code/metasploit/lib/msf/ui.rb:10
            from ./msfconsole:16:in `require'
            from ./msfconsole:16

    ところがcoreで読み込んでるファイルがsyntax error。ほぼ全てのコマンドが動きません。

    「これは良いコミットエンドラン・・・(ゴクリ)」

    % svn diff
    Index: lib/msf/core/exploit/capture.rb
    ===================================================================
    --- lib/msf/core/exploit/capture.rb     (revision 8340)
    +++ lib/msf/core/exploit/capture.rb     (working copy)
    @@ -355,7 +355,7 @@
                    rescue RuntimeError => e
                            @pcaprub_error = e
                            print_status("Cannot stat device: #{@pcaprub_error}")
    -                       raise RuntimeError, "Pcaprub error: #{@pcaprub_error}")
    +                       raise RuntimeError, "Pcaprub error: #{@pcaprub_error}"
                    end
                    return my_net
            end

    取り敢えずこれで動きますのでお急ぎの方は是非。

    % ./msfconsole
    
                    |                    |      _) |   
     __ `__ \   _ \ __|  _` |  __| __ \  |  _ \  | __| 
     |   |   |  __/ |   (   |\__ \ |   | | (   | | |   
    _|  _|  _|\___|\__|\__,_|____/ .__/ _|\___/ _|\__| 
                                  _|                   
    
    
           =[ metasploit v3.3.4-dev [core:3.3 api:1.0]
    + -- --=[ 176 exploits - 30 auxiliary
    + -- --=[ 104 payloads - 17 encoders - 5 nops
           =[ svn r8340 updated today (2010.02.01)
    
    msf >

    metasploitはversion3からperlからrubyになったらしく、僕にとっては読みやすくて嬉しいです。でもWebインターフェースがRailsなのは少しアグレッシヴですね。

    次回は実際に脆弱性を突いてみようと思います。

    ]]>
    Tue, 02 Feb 2010 02:49:59 +0900
    Lisp on Rails 第2回 〜 メタクラス http://tech.actindi.net/3473716585 こんにちは!! tahara です。 Lisp on Rails 第2回です!

    ActiveRecord::Base ではクラスメソッドとして find や all の検索メソッドが定義されています。

    Common Lisp でそれらを実装するにあたり、メタクラスのメソッドとして実装してみます。 Common Lisp では自分でメタクラスを定義することができます。 次のようにメタクラスを定義します。 なんとなく、テーブル名とカラム情報を持たせています。

    (defclass active-record-class (standard-class)
      ((%table-name :initarg :%table-name :accessor %table-name-of)
       (%columns :initarg :%columns :accessor %columns-of)))
    
    各テーブル毎のクラスはこの active-record-class のインスタンスになり、 インスタンス変数としてテーブル名とカラム情報を持つイメージです。

    メタクラスに全レコードを取得する all メソッドを実装します。

    (defmethod all ((class active-record-class))
      (multiple-value-bind (rows columns)
          (clsql-sys:query (format nil "select * from ~a" (%table-name-of class)))
        (loop for i in rows
              collect (make-instance-from-row class i columns))))
    

    (def-record post) は次のように展開されて :METACLASS ACTIVE-RECORD::ACTIVE-RECORD-CLASS を指定します。

    (PROGN
      (DEFPARAMETER POST
        (DEFCLASS POST (BASE)
          ((ID :INITARG :ID :INITFORM NIL :ACCESSOR ID-OF)
           (NAME :INITARG :NAME :INITFORM NIL :ACCESSOR NAME-OF)
           (TITLE :INITARG :TITLE :INITFORM NIL :ACCESSOR TITLE-OF)
           (CONTENT :INITARG :CONTENT :INITFORM NIL :ACCESSOR CONTENT-OF)
           (CREATED-AT :INITARG :CREATED-AT :INITFORM NIL :ACCESSOR
                       CREATED-AT-OF)
           (UPDATED-AT :INITARG :UPDATED-AT :INITFORM NIL :ACCESSOR
                       UPDATED-AT-OF))
          (:METACLASS ACTIVE-RECORD::ACTIVE-RECORD-CLASS)))
          ...
    
    Ruby のクラス定義と違って Common Lisp のクラス定義ではクラス名に何も束縛しないため、 わざわざ defparameter しています。

    そんな感じでメタクラスによる

    (all post)
    
    ができました。

    ソースはこちらから http://github.com/quek/lisp-on-rails

    第3回につづきます

    ]]>
    Fri, 29 Jan 2010 10:16:25 +0900
    PerlとC++にしかできないような気がした十五の夜 http://tech.actindi.net/3473675040 今年の私のテーマは「挑戦」。 先日、そんな私にぴったりな、盗んだバイクで走り出したくなる挑戦をみつけました。
  • PerlとC++にしかできないような気がするアノ機能(挑戦者募集中)
  • #!/usr/bin/perl
    # PerlとC++は世界一。
    
    srand(time);
    
    my $a = 0;
    my $b = 0;
    for(my $i = 0; $i < 1000; $i++) {
        (rand(2)<1 ? $a : $b) += 1;
    }
    print "$a, $b\n"
    
    これをPerlや、C++以外の言語で書けるのか、と。
    私は、LISP野郎なのでLISPで回答するとして考えましたが「実行時に変数の名前によって任意の変数にアクセスし、その変数に値を代入できるか」という風にお題を解釈しました。 PerlやC++の場合は、?:にそういう機能があるのでしょう。 Common Lispだとどうなるかというと、「実行時に変数の名前によって任意の変数にアクセス」というのは、シンボル名による変数へのアクセスで可能なので、上をCommon Lispに訳すと
    (let ((a 0) (b 0))
      (declare (special a b))
      (dotimes (i 1000)
        (incf (symbol-value
               (if (< (random 2) 1) 'a 'b))))
      (format t "~A, ~A~%" a b))
    ;⇒ NIL
    ----------
    499, 501
    
    こんな感じに書くことになるのかなあと思いました。
    …というようなことをtaharaさんと昼食時に話していたのですが、taharaさん曰くifにsetfが付いてれば可能なんじゃないかとのこと。 なるほど、確かにそうです。
    setfというのは代入する構文のマクロなのですが、ユーザーが色々カスタマイズできます。 実行時に変数名でアクセス→代入というのではなく、そういう構文をマクロで定義するわけですね。
    ユーザーがifにsetfを書けば良いのですが、これが標準で付いている処理系をどっかでみたなーと思ったので調べてみるとCLISPがそうでした。 CLISPだと標準で
    (let ((a 0) (b 0))
      (dotimes (i 1000)
        (incf (if (< (random 2) 1) a b)))
      (format t "~A, ~A~%" a b))
    ;⇒ NIL
    ----------
    513, 487
    
    と書けます。自分はPerlは書けないのですが、+=をカスタマイズすることによって
    for(my $i = 0; $i < 1000; $i++) {
        if (rand(2) < 1) { 
          $a 
        } else {
          $b
        } += 1;
    }
    
    のようにも書けるようにユーザーが勝手に定義できる、という感じでしょうか。
    こんなことをしているとすぐカオスになりそうですが、LISPに構文は無いようなものなので特に混乱もなかったりします。LISPは単純で良いですね■ ]]>
    Thu, 28 Jan 2010 22:44:00 +0900
    iPhoneによる位置情報関係のまとめ http://tech.actindi.net/3473583175 こんにちは。
    先日komagataさんにgit svnの使い方を教えていただいたおかげで、少しは使えるようになってきたmasudaです。

    今回も前回のGeohashに引き続き、位置情報に関する内容です。
    ググれば出てくる内容なので、新しいことはなんにもないのが申し訳ないところです。

    位置情報に関するライブラリは

    • CoreLocation
    • MapKit
    などがあります。

    GPSで現在位置を取得するにはCoreLocationを使用し、地図を表示したり現在地の大まかな住所を取得するためにはMapKitを使用します。

    CoreLocationではCLLocationManagerDelegateを実装し

    CLLocationManager *locationManager = [[CLLocationManager alloc] init];
        if ([locationManager locationServicesEnabled])
        {
            [locationManager setDelegate:self];
            [locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
            [locationManager setDistanceFilter:kCLDistanceFilterNone];
        }
    
    - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
    {
        NSLog(@"%@", newLocation);
    }

    このようにすればLogに現在地の情報が取得できます。

    地図を表示するには

    CGRect screen = [[UIScreen mainScreen] bounds];
    MKMapView *mapView = [[MKMapView alloc] initWithFrame:screen];
    [[self view] addSubview:mapView];
    [mapView release];
    
    MKCoordinateRegion  region;
    region.center = [location coordinate];
    region.span.latitudeDelta = 0.005;
    region.span.longitudeDelta = 0.005;
    [mapView setRegion:region animated:YES];

    とすれば、locationで指定した座標に移動します。

    現在地を取得するにはMKReverseGeocoderDelegateを実装し

    MKReverseGeocoder *reverseGeocoder = [[MKReverseGeocoder alloc] initWithCoordinate:[location coordinate]];
    [reverseGeocoder setDelegate:self];
    [reverseGeocoder start];
    
    - (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark
    {
        NSLog(@"%@", [placemark title]);
    }

    とすることで取得することができます。
    すべてのAPIが非常にシンプルに作られているので、使用するのは非常に簡単です。

    ]]>
    Wed, 27 Jan 2010 21:12:55 +0900
    Lispに興味がない・・・だと・・・? http://tech.actindi.net/3473547098

    興味のある言語にLispと書いておいたら面接で爆笑された

    面接官「Lisp・・・ふははっ!Lisp!」

    面接官「Lispやってるんですか?wwwww」

    俺「(唖然)は、はい・・まだS式を理解したぐらいですが。。」

    面接官「Lisp・・・ニヤニヤ」

    Hunchentootで動いてるこのブログを見て弊社に面接に来た方がCommon Lispに興味なかったらメンバー全員がっかりしますね・・・。

    ]]>
    Wed, 27 Jan 2010 11:11:38 +0900
    Real (World) Git http://tech.actindi.net/3473481089 火曜日担当のkomagataです。

    gitよく分からないのでどういう風に使ってるのかデモってくれと言われたので実際に仕事のコードにコミットしてみました。

    実録!git!

    アクトインディでは「子供とのお出かけ先を探すサイト」いこーよhttp://iko-yo.net)というサイトを運営しています。 リポジトリはデザイナーさんがDreamweaverCodaのsvnクライアントを使うのでSubversionです。

    svnの最新リビジョンだけを持ってくる。(全部持ってくると死ぬほど時間がかかる。)

    % git svn clone -r HEAD https://svn.actindi.net/svn/oyaiku/trunk/outing outing --username=komagata

    Redmineのチケットを見る。 予め仕込んでおいた簡単そうなチケットを発見。(redmineではイシューというみたいです)

    いこーよ - 新機能 #3487: cityモデルのテストを書く - Redmine(タスク管理)

    チケットに対応したブランチを作る。

    % git branch issue3487

    作業ブランチを切り替える。

    % git checkout issue3487
    (git branch foo; git checkout fooはgit checkout -b fooと同じ)

    ブランチ確認。

    % git branch
      master
    * issue3487

    shouldaスタイルのマクロが使いたいのでremarkableを入れる。

    # config/environment.rb
    Rails::Initializer.run do |config|
      config.gem 'remarkable_rails', :lib => false
    end
    # spec/spec_helper.rb
    require 'spec/rails' # ここの下に書く
    require 'remarkable_rails'
    % sudo rake gems:install
    % rake gems:unpack
    % rake gems:refresh_spec

    一旦、コミット。

    % git add vendor vendor/gems/remarkable_rails-3.1.12
    % git commit -a -m'added remarkable'

    app/model/city.rbのテストを作る。

    # app/model/city.rb
    class City < ActiveRecord::Base
      belongs_to :prefecture
    
      validates_presence_of :name, :reading, :roman
      validates_length_of :name, :within => 1..40
      validates_length_of :reading, :within => 1..40
      validates_length_of :roman, :within => 1..40
      validates_uniqueness_of :roman
    end
    # spec/models/city_spec.rb
    require 'spec_helper'
    
    describe City do
      fixtures :cities
    
      should_belong_to :prefecture
      should_validate_presence_of :name
      should_validate_presence_of :reading
      should_validate_presence_of :roman
      should_validate_length_of :name, :within => 1..40
      should_validate_length_of :reading, :within => 1..40
      should_validate_length_of :roman, :within => 1..40
      should_validate_uniqueness_of :roman
    end

    テスト実行(ホントは全部のテストを実行する)

    % ./script/spec spec/models/city_spec.rb
    
    City
    - should belong to prefecture
    - should require name to be set
    - should require reading to be set
    - should require roman to be set
    - should ensure length of name is within 1..40 characters
    - should ensure length of reading is within 1..40 characters
    - should ensure length of roman is within 1..40 characters
    - should require unique values for roman
    
    Finished in 0.770165 seconds
    
    8 examples, 0 failures

    コミット

    % git add spec/models/city_spec.rb
    % git ci -a -m'added city_spec. fixed #3487'

    masterに移る。

    % git checkout master

    最新版を持ってくる

    % git svn rebase

    issue3487をマージする

    % git merge issue3487

    svnにコミット。

    % git svn dcommit

    完了。

    その他の便利機能

    いっこ前のコミットなかったことにする

    % git reset HEAD^

    昔のコミットを修正したい

    % git log --oneline
    c5524b2 * removed foo * removed remarkable
    460bfa1 [デザイン] TOPページ「外へおでかけ」の変更 (refs #3490) * 谷さん修正分
    9b819fd * add city_spec * add remarkable * add foo
    695b1eb [システム] [mobile] /facilities/:id のレイアウト変更。 (refs #2899) * いらないhrを削除。
    % git rebase -i 695b1eb

    エディタが立ち上がるので修正したいリビジョンのpickをeditに変更して終了する。

    pick 9b819fd * add city_spec * add remarkable * add foo
    pick 460bfa1 [デザイン] TOPページ「外へおでかけ」の変更 (refs #3490) * 谷さん修正分
    edit c5524b2 * removed foo * removed remarkable

    指定したリビジョンの状態に戻るので好きにaddしたり編集したりする。

    % git commit --amend
    % git rebase --continue

    修正完了

    複数の適当なコミットを一つにまとめたい

    % git log --oneline
    68fb234 add text2 in foo
    5cd81d6 add text in foo
    43fdcb7 add foo
    fb91711 removed old paperclip
    aa21e65 fixed
    % git rebase -i fb91711
    pick 43fdcb7 add foo
    pick 5cd81d6 add text in foo
    pick 68fb234 add text2 in foo

    次のリビジョンとまとめたいリビジョンの先頭をpickからsquashに変える。

    pick 43fdcb7 add foo
    squash 5cd81d6 add text in foo
    squash 68fb234 add text2 in foo

    コミットメッセージをいれて終了。

    みなさんおっしゃってますが、やはり、svnからgitにして嬉しいのはbranchの作成やcommitが気軽できるところですね。一つの作業をやってる途中に別の優先タスクが入った場合も、現在のbranchをほっぽってすぐにそちらのタスクに移れるのは精神的にもとても楽です。

    適当にfixed, fixedなどとコミットしていっても後で綺麗にまとめられるところもいいですね。

    gitは他にもいろいろ出来るみたいですが、今のところリアルにこんな感じで使っています。便利な使い方があれば教えて頂けると嬉しいです。

    ]]>
    Tue, 26 Jan 2010 16:51:29 +0900
    Lisp on Rails 第1回 http://tech.actindi.net/3473158189 こんばんは!! tahara です。

    いま仕事で Ruby on Rails を使っています。 正直 Active Record いいっすねー。 DB いじるには楽です。

    くやしいので Common Lisp でそれっぽいのを実装してみます。 Lisp on Rails ですね(何だか以前から聞く言葉のような気もします)。

    第1回目の今日は何となく Active Record っぽい雰囲気のような感じだけです。

    (eval-when (:compile-toplevel :load-toplevel :execute)
      (setf *connection-spec* '("localhost" "blog_test" "root" ""))
      (setq clsql-sys:*default-database-type* :mysql)
      (establish-connection))
    
    ;; レコードの定義
    (def-record post)
    ;; インサート
    (save (make-instance 'post :name "名前" :title "タイトル" :content "内容"))
    ;; 検索
    (all post)
    

    ソースはこちらから http://github.com/quek/lisp-on-rails

    第2回につづきます

    ]]>
    Fri, 22 Jan 2010 23:09:49 +0900
    Rubyの好きなところ http://tech.actindi.net/3473072867 x = 3 [0, *if x.even? [1, 2, 3] else [:a, :b, :c] end] ;⇒ [0, :a, :b, :c]
    def iota(n)
      if n.zero?
        0
      else
        [n, *iota(n - 1)]
      end
    end
    
    iota(10)
    ;⇒ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
    
    Proc.new do |x, y| x * y;end [100,2]
    ;⇒ 200
    
    LISP/Schemeでも、書けるといえば書けるのですが、
    ;; Common LISP
    (let ((x 3))
      `#(0 ,@(if (evenp x)
                 '(1 2 3)
                 '(:a :b :c))))
    ;⇒ #(0 :A :B :C)
    
    (defun iota (n)
      (if (zerop n)
          (list 0)
          `(,n ,@(iota (1- n)))))
    
    ;⇒ (10 9 8 7 6 5 4 3 2 1 0)
    
    (multiple-value-call #'* (values-list '(100 2)))
    ;⇒ 200
    
    ;; もしくは
    (apply #'* '(100 2))
    ;⇒ 200
    
    Rubyの方が統一感があって良いですね。 ]]>
    Thu, 21 Jan 2010 23:27:47 +0900
    Objective-C的???Geohash http://tech.actindi.net/3472988345 こんにちは!
    はまっている時間はたいていRSpecに起因するものなのではないかと以前から感じているmasudaです。
    なんとか約束の火曜日に間に合ったでしょうか???

    先日chibaさんがGeohashをdecodeするものをCLで書いていらしたので、それを微妙に参考にしながらCocoaのCoreLocationのCLLocationにgeohashをencode/decodeするメソッド追加してみました。

    本当はビット演算がしたいのですが、文字列処理の方が自分には単純で簡単だったため、とりあえず今回は文字列処理にしてみました。

    我ながらひどいコードだと思いますので、これからリファクタリングをしていきたいところです。

    [CLLocation+Geohash.h]

    #import <CoreLocation/CoreLocation.h>
    #import <Foundation/Foundation.h>
    
    
    @interface CLLocation(Geohash)
    
    @property (nonatomic, readonly)   NSString    *geohash;
    
    + (CLLocation *)locationFromGeohash:(NSString *)aGeohash;
    
    @end
    

    [CLLocation+Geohash.m]

    #import "CLLocation+Geohash.h"
    
    #include <math.h>
    
    NSString *int_to_binary(NSUInteger input)
    {
        if (input == 1 || input == 0)
        {
            return [NSString stringWithFormat:@"%d", input];
        }
    
        return [NSString stringWithFormat:@"%@%d", int_to_binary(input / 2), input % 2];
    }
    
    
    double parse_binary(NSString *binary, double max, double min)
    {
        double mid = 0.0;
        
        for (NSUInteger i = 0; i < [binary length]; ++i)
        {
            if ([binary characterAtIndex:i] == '1')
            {
                min = mid;
            }
            else
            {
                max = mid;
            }
            
            mid = (max + min) / 2;
        }
        
        return mid;
    }
    
    
    NSUInteger binary_to_int(NSString *input)
    {
        NSUInteger result, length;
    
        result = 0;
        length = [input length];
    
        for (NSUInteger i = 0; i < length; ++i)
        {
            if ([input characterAtIndex:i] == '1')
            {
                result += pow(2, length - i - 1);
            }
        }
    
        return result;
    }
    
    
    NSString * generate_binary(double input, double max, double min, int cutoff)
    {
        NSMutableString     *result;
        double              mid;
    
        result = [NSMutableString string];
        for (int i = 0; i < cutoff; ++i)
        {
            mid = (max + min) / 2;
    
            if (input > mid)
            {
                [result appendString:@"1"];
                min = mid;
            }
            else
            {
                [result appendString:@"0"];
                max = mid;
            }
        }
    
        return [NSString stringWithString:result];
    }
    
    
    @implementation CLLocation(Geohash)
    
    - (NSString *)geohash
    {
        int cutoff = 15;
        NSString *base32_characters  = @"0123456789bcdefghjkmnpqrstuvwxyz";
    
        NSString            *bin_lat, *bin_lng;
        NSMutableString     *bin_packed, *result;
        
        bin_lat = generate_binary([self coordinate].latitude, 90.0, -90.0, cutoff);
        bin_lng = generate_binary([self coordinate].longitude, 180.0, -180.0, cutoff);
    
        bin_packed = [NSMutableString string];
    
        for (int i = 0; i < [bin_lat length]; ++i)
        {
            [bin_packed appendFormat:@"%c%c", [bin_lng characterAtIndex:i], [bin_lat characterAtIndex:i]];
        }
    
        result = [NSMutableString string];
    
        // extract by 5-bit.
        for (int i = 0; i < [bin_packed length] / 5; ++i)
        {
            NSUInteger index;
            index = binary_to_int([bin_packed substringWithRange:NSMakeRange(i * 5, 5)]);
            [result appendFormat:@"%c", [base32_characters characterAtIndex:index]];
        }
    
        return result;
    }
    
    
    + (CLLocation *)locationFromGeohash:(NSString *)aGeohash
    {
        NSString *base32_characters  = @"0123456789bcdefghjkmnpqrstuvwxyz";
    
        NSMutableString *bin_packed, *bin_lat, *bin_lng;
    
        bin_packed = [NSMutableString string];
    
        for (NSUInteger i = 0; i < [aGeohash length]; ++i)
        {
            NSString *character;
            character = [[NSMutableString stringWithFormat:@"%c", [aGeohash characterAtIndex:i]] lowercaseString];
    
            for (NSUInteger j = 0; j < [base32_characters length]; ++j)
            {
                if ([character isEqualToString:[NSString stringWithFormat:@"%c", [base32_characters characterAtIndex:j]]])
                {
                    NSMutableString *binary;
                    binary = [NSMutableString stringWithFormat:@"%@", int_to_binary(j)];
    
                    NSUInteger length = [binary length];
                    for (NSUInteger k = 0; k < 5 - length; ++k)
                    {
                        [binary insertString:@"0" atIndex:0];
                    }
    
                    [bin_packed appendString:binary];
                    break;
                }
            }
        }
    
        bin_lat = [NSMutableString string];
        bin_lng = [NSMutableString string];
    
        for (NSUInteger i = 0; i < [bin_packed length]; ++i)
        {
            if (i % 2)
            {
                // a latitude is composed of odd bits. 
                [bin_lat appendFormat:@"%c", [bin_packed characterAtIndex:i]];
            }
            else
            {
                // a longitude is composed of even bits.
                [bin_lng appendFormat:@"%c", [bin_packed characterAtIndex:i]];
            }
        }
    
        return [[CLLocation alloc] initWithLatitude:parse_binary(bin_lat, 90.0, -90.0)
                                          longitude:parse_binary(bin_lng, 180.0, -180.0)];
    }
    
    
    @end
    

    NSStringでかなり遅いcharacterAtIndexを使いまくっている。

    参考

    Geohash - Wikipedia, the free encyclopedia
    GeoHashのdecodeのアルゴリズムの解説します & ScalaのGeoHashライブラリを作ってみました(仮) - ゆろよろ日記

    ]]>
    Wed, 20 Jan 2010 23:59:05 +0900
    テストを通らないリリースを止めるライブラリ http://tech.actindi.net/3472868530 昼にキリンフリーを飲むと機嫌が良くなる火曜日担当のkomagataです。

    rspecのテストが通らないとデプロイを止めてしまうcapistranoのレシピのgemを作りました。

    showstopper 0.1.0

    ShowStopper is capistrano recipe that stop deploy when rspec is red.

    インストール

    $ sudo gem install showstopper -s http://gemcutter.org

    Capfileの中で読み込むだけで設定完了です。

    $ vi Capfile
    (...)
    require 'showstopper'

    これでrspecが通ってないのに誰かがデプロイしようとすると・・・

    % cap deploy
    (...)
      * == Currently executing `deploy'
        triggering before callbacks for `deploy'
      * == Currently executing `deploy:spec'
        rspec test failed

    showstopperがデプロイを中止してしまいます!

    これを投入していい加減なテストのあるプロジェクトを恐怖のどん底に陥れてやりましょう!

    ]]>
    Tue, 19 Jan 2010 14:42:10 +0900
    autotest-stumpwm http://tech.actindi.net/3472528762 こんにちは!! tahara です。

    script/autospec の結果を表示してくれる Growl がうらやましいのですが、私 の使っているのは Linux です。しかし、Linux には Stumpwm があります。 Stumpwm の stumpish を使えば echo でメッセージを表示することができます。

    そこで script/autospec の結果を Stumpwm で表示する gem を作ってみます。

    参考サイト

    gem を作るには Jeweler を使うのがよさそうです。 Jeweler は GitHub の API を使うようなので、まずその設定を行います。 user_name と api_token には自分の Username と API Token を指定します。

    git config --global github.user user_name
    git config --global github.token api_token
    

    Jeweler をインストールしてプロジェクトを作ってみます。

    gem install jeweler
    jeweler --rspec --create-repo autotest-stumpwm
    

    これで綺麗にプロジェクトが作成されます。 おまけに GitHub にリポジトリまでできています。

    次に Rakefile を編集します。TODO になっている次の二箇所を適当に編集すればよさそうです。 あと依存する gem も指定しておきます。

        gem.summary = %Q{TODO: one-line summary of your gem}
        gem.description = %Q{TODO: longer description of your gem}
        gem.add_dependency "autotest-growl", ">= 0.1.7"
    

    次に lib の下のファイルに Stumpwm を使って script/autospec の結果を表示するたコードを書きます。 コードが出きたら次のようにリリースします。

    rake version:write
    rake gemspec
    rake release
    

    これだけで Gemcutter にも自動的に公開されます。 Jeweler すばらしい!!

    修正したら git commit して、次のいずれかでバージョンをあげ rake release するだけ。

    rake version:bump:major              # Bump the gemspec by a major version.
    rake version:bump:minor              # Bump the gemspec by a minor version.
    rake version:bump:patch              # Bump the gemspec by a patch
    

    できあがった autotest-stumpwm を使うには gem install autotest-stumpwm して、 ~/.autotest に次の一行を書きます。これで autospec と Stumpwm の幸せな生活がおくれます。

    require 'autotest/stumpwm'
    

    さて、一番大切な Stumpwm で結果を表示するコードですが、

    # -*- coding: undecided -*-
    require 'rubygems'
    require 'autotest/growl'
    
    module Autotest::Growl
      def self.growl(title, message, icon, priority=0, stick="")
        priority = if priority > 0  # error or feailed
                     1              # red
                   elsif priority == -2 # passed
                     2                  # green
                   else
                     3              # yellow
                   end
        system "stumpish echo ^#{priority}* #{title} #{message}"
      end
    end
    
    ごめんなさい autotest-growl にモンキーパッチをあてただけです。 ]]>
    Fri, 15 Jan 2010 16:19:22 +0900
    Geohash http://tech.actindi.net/3472464385 Geohash - Wikipedia, the free encyclopedia そんな感じで、説明の順番のとおりに書いてできたコードが下記です。 なんとなく仕組みは分かったけど、そういえば、エンコード手順の説明は書いてないんだなあ…、と自分勝手なことを考えながら就寝しました。
    (defpackage :geohash
      (:use :cl)
      (:import-from :shibuya.lisp
                    :$ :$*))
    
    (in-package :geohash)
    
    (defun tr (from to string)
      (map 'string 
           (lambda (c)
             (or (some (lambda (x y) 
                         (and (char-equal x c) y))
                       from to)
                 (char-upcase c)))
           string))
    
    (defun 5bits (string)
      (map 'list
           ($ format nil "~5,'0,B" 
              $ read-from-string 
              $ format nil "#32R~A" 
              $ tr "0123456789BCDEFGHJKMNPQRSTUVWXYZ" 
                   "0123456789ABCDEFGHKJKLMNOPQRSTUV" 
              $ string $)
           string))
    
    (defun longitude-latitude (strings)
      (let ((bit-c-list ($* concatenate 'list strings)))
        (loop :for c :in bit-c-list
              :for i :from (if (char= #\0 (car bit-c-list)) 0 1)
              :if (evenp i) :collect c :into even
              :else :collect c :into odd
              :finally (return 
                         (list :longitude
                               (coerce even 'string) 
                               :latitude
                               (coerce odd 'string))))))
    
    (defun bitlist (string)
      (map 'list ($ parse-integer $ string $) 
           string))
    
    (defun decode (bits min mid max)
      (if (endp bits)
          mid
          ($* decode 
              (cdr bits)
              (if (zerop (car bits))
                  (list min (/ (+ mid min) 2) mid)
                  (list mid (/ (+ mid max) 2) max)))))
    
    (defun decode-geohash (string)
      (let* ((u ($ longitude-latitude $ 5bits string))
             (lon (getf u :longitude))
             (lat (getf u :latitude)))
        (list 
         :longitude 
         ($ float $ decode (bitlist lon) -90 0 90)
         :latitude
         ($ float $ decode (bitlist lat) -180 0 180))))
    
    (decode-geohash "u4pruydqqvj")
    ;⇒ (:LONGITUDE 57.64911 :LATITUDE 10.407439)
    
    ]]>
    Thu, 14 Jan 2010 22:26:25 +0900
    Delaunay Tessellation for iPhone http://tech.actindi.net/3472341020 こんにちは!!!
    今まで更新しろとせっつかれていたのにもかかわらず、全然更新しなかったmasudaです。

    とりあえず最初は今までやったのにアップロードしていなかったプログラムプレゼンテーションのネタを書こうかなと思います。

    過去の部分はこちらを参考にしてください。

    第1回 cocoa*life - Apple Push Notification Serviceを利用した、iPhone クライアントと、Rubyによるサーバの作成。

    第3回 cocoa*life - Grand Central Dispatchを試してみる。

    以下、同様にblogに載せようと思って途中でやめていたものを載せようと思います。

    プログラムプレゼンテーションの第2回は、iPhoneを用いてDelaunay分割をするというものにしてみました。

    本当は他のものをやるつもりだったのですが、前回のプログラムプレゼンテーションではkomagataさんがObjective-Cのキメラさ、カオスさをおもしろがっていたと勝手に仮定して、Objective-C++でさらなるカオスさを目指すことにしました。

    そんな折りに以前ドロネー分割をするためのプログラムをつくって、アップロードしようかなといっていたのを思い出しました。

    ということで、今回はそれを流用することにしました。
    単純に移植するだけだから簡単だろと思ったところ、意外と手直しに時間がかかってしまいました。

    ドロネー分割については計算幾何学で出てくるものですが、この余白はそれを書くのにはせますぎるということで、ググればきっとわかる!!!

    ソースコードはこちらです。
    ライブラリとしてBoost C++ Librariesを使用しています。

    実行すると、毎回ランダムな10点を作成し、下図のようにドロネー分割された図が表示されます。

    Delaunay tessellation   Delaunay tessellation with circumcircles

    右側の図は外接円も表示させた場合です。
    ドロネー分割では生成された三角形によって作られる外接円の中に、その三角形以外の点が含まれてはいけません。

    ランダムな点を生成する部分にはboost::randomを用い、ドロネー分割を計算する部分はC++で書かれています。

    Objective-CとC++のコードを混ぜる場合の注意点は、HMDTさんによくまとめられているのでこちらを参照していただくのがよいかと思います。
    HMDT – Objective-C++

    Objective-C++のソースを書かれるときは、.mとなっている拡張子を.mmにしてくださいね。
    自分はこれをしないでObjective-C++のファイルだと認識されずはまりまくりました。

    こんな風にC++のコードも簡単に使用することができるので、Objective-Cを使われている皆様もぜひ組み合わせてみてはいかがでしょうか???

    P.S.
    本当はNSOperationを使って、スレッドを新しく作ってバックグラウンドで処理をしたかったのですが、プログラムの構造上面倒なのでやめました。

    参考
    Objective-C プログラミング言語:C++ と Objective-C の併用
    HMDT – Objective-C++

    ]]>
    Wed, 13 Jan 2010 12:10:20 +0900
    Webプログラマーチュートリアル http://tech.actindi.net/3472257910 ニコ生はじめました。komagataです。

    新しくtaharaさんをメンバーに加えて、毎日持ち回りでこのブログを更新していくことになりました。

    火曜日:komagata
    水曜日:masudaさん
    木曜日:chibaさん
    金曜日:taharaさん

    このような曜日担当で更新してきます。忘れていたら罵倒してください・・・。

    ほとんどtaharaさんが書いてくれたのですが、Webプログラマーチュートリアルを作りました。

    web-programmer-tutorial - Project Hosting on Google Code

    何らかのプログラム経験さえあれば、これをみて自習するだけで業務するのに必要なスキルが習得できるように、ゴールと参考URL・書籍の一覧を用意しました。

    入社した最初の一ヶ月を研修期間としてこれをやることにしました。(やりながらメニュー自体も改善する)

    これならば自宅を警備しながらスキルを付けることが出来るのではないかと期待しております。

    OJTのみになってしまっているのを改善したいITベンチャーの方や自宅警備員の方でこれを使ってわからないところがあれば全力で支援いたします。

    ]]>
    Tue, 12 Jan 2010 13:05:10 +0900
    Hunchentoot になりました http://tech.actindi.net/3470616064 こんにちは。12月からメンバにくわわった tahara と申します。
    chiba さんの念願でした、このブログの AllegroServe から Hunchentoot への移行を行いました。
    既に chiba さんが Hunchentoot への移植はやってくれていたので Elephant の導入がメイン作業でした。 Elephant は Common Lisp のオブジェクトデータベースです。バックエンドは色々選べるのですが、今回は SQLite3 を使いました。

    現在このブログは次のような構成で動いています。

    それでは、今後ともよろしくお願いいたします。

    ]]>
    Thu, 24 Dec 2009 13:01:04 +0900
    StumpWMは便利です http://tech.actindi.net/3466487639 今回のプログラム・プレゼンテーションのネタはStumpWMです。 StumpWMはタイル型ウィンドウマネージャーなのですが、Common LISPで色々と拡張することができるのが特長です。

    今回は、このちょっとしたカスタマイズネタや使い方です。

    Actindi社内では現在全面的にRedmineで仕事を管理していて、仕事の確認/依頼もチケット番号ですることが非常に多いです。
    いつもチケットの番号でやりとりするのですが、伝えられた番号をぱっと開きたいことが多いので、これをStumpWMで便利にしてみようということで工夫してみました

      
    (DEFPARAMETER *LAST-TICKET* NIL)
    
    (DEFCOMMAND SHOW-TICKET (TICKET-NUMBER) ((:STRING "Ticket#: "))
      (WHEN (RUN-SHELL-COMMAND 
             (FORMAT NIL 
                    "/usr/bin/firefox "https://redmine.example.com/issues/show/~A\""
                     TICKET-NUMBER))
       (SETQ *LAST-TICKET* TICKET-NUMBER)))
    
    (DEFCOMMAND EDIT-IT () ()
      (RUN-SHELL-COMMAND
        (FORMAT NIL
                "/usr/bin/firefox "https://redmine.example.com/issues/edit/~A\""
                *LAST-TICKET*)))
    

    非常にでっちあげ感の漂う適当なコードですが、show-ticket 1234という風に実行すると、Redmineの1234番のチケットがfirefoxで表示されます。
    edit-itコマンドは保存していた直前のチケット番号を編集状態で開くという単純なものです。 ちょっとした工夫ですが、割と便利で愛用しています。
    といった具合で、その他、StumpWMの機能の説明をして1時間をしのぎました。
    みなさんもご興味あれば、StumpWMをお試しあれ。

    ]]>
    Fri, 06 Nov 2009 18:13:59 +0900
    さようならsed、こんにちはCommon Lisp http://tech.actindi.net/3463978702 chibaです。

    今回のプログラム・プレゼンテーションのネタは日常で使うちょっとしたスクリプトをCommon Lispでやってみようというものです。

    ネタ切れなので自分の ブログに書いたネタ を再演しつつ、ブログでは紹介してなかったwgetも併せて動かしてみました

  • 適当なwget
  • Software ToolsのごとくCommon Lisp上にユーティリティを作成して行けば、Common Lispだけでこういう細かい仕事はできるようになるやもしれません。

    ]]>
    Thu, 08 Oct 2009 17:18:22 +0900
    ブログもどき的、あまりにもブログもどき的 http://tech.actindi.net/3463977650 chibaです。

    今回のプログラム・プレゼンテーションのネタはこのブログもどきについてです。 そもそもは、ちょっと変ったことをしてみようということで、技術方面のブログはCLで作ってみようということになりました。

    構成は、

    • CL処理系: SBCL
    • AllegroServe(RubyでいうWEBrickのようなもの)
    という風になっています。

    SBCL処理系は、ライブラリをロードした状態の処理系のメモリイメージを実行可能ファイルとしてダンプできるのですが、適当に手元のノートPCでAllegroServe(CLのウェブサーバー)をロードした状態でダンプしたものを、さくらサーバーに置いたところ動いてしまったので、そのまま動かすことにしました。(x86の実行ファイルです)

    場当たり的に作っていく中で色々な問題に遭遇しました。

    • AllegroServeだとサーバーの処理系を大文字と小文字を区別するように設定することが前提になっているのでそうしないと色々困る。
    • AllegroServeをAllegro CL上で動かさない場合、日本語の扱いに難がある
    等々、割と根本的なところに問題があったりします。
    HUNCHENTOOT というサーバーもちょっと試てみたのですが、上記のような問題はないので、こちらに乗り換えたいところです

    ]]>
    Thu, 08 Oct 2009 17:00:50 +0900
    Emacsでスクラッチファイルを日付順にして管理するライフハック http://tech.actindi.net/3462883892 chibaです。

    自分は特にプログラムを書くのが趣味という訳でもないので、プログラムプレゼンテーションは割と苦手なのですが、今回は、過去に作った便利Emacs Lispをプレゼンして場をしのぎました。

    アイデアとしては、ファイルを

    file-2009-09-26.txt
    のように命名規則を設けて作成するようにし(これもElispで生成するようにする)、その規則を元に前の日のファイルを開いたり、次の日のファイルを編集したりするのをスムースにする、というものです。
    gist: 13417 - GitHub
    この例では、前のファイルに移動するキーとしてsuper+p次のファイルがsuper+nという風に割り当てみています。
    単純なアイデアの割には便利ですので、お使いの環境でもっと洗練/発展させてみて下さい

    ]]>
    Sat, 26 Sep 2009 01:11:32 +0900
    AquesTalk Rubyバインディング http://tech.actindi.net/3462879600

    komagataです。

    “プログラムプレゼンテーション”でAquesTalkのRubyバインディングを作りました。(Windowsのみ)

    win32-aques_talk - AquesTalk rubyバインディング - p0t

    AquesTalkのrubyバインディング作りました。

    komagata’s win32-aques_talk at master – GitHub

    AquesTalkはwindows版dllのみが組み込んで配布することもOKとなっているのでwindows版をRubyから手軽に使いたいと思って作りました。RubyバインディングといってもC言語拡張ではなく、ruby-ffi(Foreign Function Interface)を使っています。

    豊富なCのライブラリをRubyからサッと使いたいと思ってruby-ffiを使ってみました。ヘッダが必要で無く、動的ライブラリを直接実行するのが面白かったです。また、Windows上で、opensshやgitがいつも通り使えるのがちょっと意外でした。(rubyのgitバインディングはうまく動かないけど)

    ]]>
    Sat, 26 Sep 2009 00:00:00 +0900
    継続インテグレーションコマンド http://tech.actindi.net/3462861600

    komagataです。

    “プログラムプレゼンテーション”で継続的インテグレーションコマンドを作って発表しました。

    saimaa - 今すぐ始められる継続的インテグレーション - p0t

    継続的インテグレーションについては、CIサーバー(Continuous Integration Server)というやつが沢山あって非常に機能も豊富です。僕の仕事には少々大げさな気がしたのと、

    「cronでsvn up && rakeじゃ駄目なのかしら?」

    などと思ったのでそれをちょっとだけサポートするコマンドを作ってみました。

    komagata’s saimaa at master – GitHub

    アクトインディではcapistranoのデプロイコマンドにrspecとcucumberのフックが掛けてあるのでテストが通らなければデプロイはできません。ですが、コミットはできるのでテスト通らないコードがコミットされるとすぐにこの仕組みでメールが飛んでくるのでなかなか便利です。

    これを作って感じたのは、rubygemsとgithubはクロスプラットフォームのCUIプログラム(コマンド)を作る環境として素晴らしいなということです。(全開と似たようなこと言ってますが)

    rubygemsはインストールするとPATHが通ってるところに実行できる場所にコマンドをコピーしてくれるんですよね。jewelerでgithubへのアップも簡単です。

    ]]>
    Fri, 25 Sep 2009 19:00:00 +0900
    Talkedbun - 日本語テキストトゥースピーチサーバー http://tech.actindi.net/3462793200 komagataです。

    アクトインディでは週一回、エンジニアが持ち回りで、「動いて、ダウロードできるプログラム」を公開・発表するという“プログラムプレゼンテーション”(まあ単なるプレゼンです)をやることにしました。

    第一回はShu MASUDAさんでしたのでそちらはお任せするとして、僕は2回目にやりました。

    Talkedbun - 日本語テキストトゥースピーチサーバー - p0t

    URLにひらがなを指定すると、そのひらがなの音声がmp3で得られるwebサーバーを作りました。

    komagata’s talkedbun at master – GitHub

    日本語のURLからそのまま音声が取れたら面白いかなと思って作りました。作っていて一番勉強になったのは、RubyはRubygems, Rack, Sinatraなど、クロスプラットフォームでのマイクロウェイブアプリケーションを作る環境が素晴らしく整っているなということでした。RailsがWebrickをローカルに立ち上げて開発するというスタイルを作ったので自然とWebサーバーの実装、WAFの実装、周辺ツールなどの選択肢がたくさんあります。

    ついでにhaml, sassも使ってみましたが、HTMLのインデントやCSSの重複した記述が病的に気になる僕にはぴったりのアホなツールでとても気に入りました。

    (ジェバンニマチダさんが30分でやってくれました)

    ]]>
    Fri, 25 Sep 2009 00:00:00 +0900
    RSSは動いているか http://tech.actindi.net/3459056185 このエントリーがRSSリーダーに捕捉されれば、とりあえず良いのですが、されてない気がします… ]]> Wed, 12 Aug 2009 17:56:25 +0900 こわれたRSSを付けました http://tech.actindi.net/3459054071 どこかが壊れているようですが、Google Readerや、LDRではがんばって表示してくれるようです。 しかし、それも動きがちょっと変なようです。 ]]> Wed, 12 Aug 2009 17:21:11 +0900 社長にお披露目 http://tech.actindi.net/3458970860 公開できると良いですね!! ]]> Tue, 11 Aug 2009 11:31:03 +0900 このブログの更新はSLIMEでしている! http://tech.actindi.net/3458946663 SLIME使ってる人には非常に優しいブログですね
    具体的には、このサーバーが動いているサーバーのSwankの4005番ポートをローカルにポートフォワードして、EmacsからSlimeで接続し、エントリーの関数を定義しています。簡単ですね! ]]>
    Tue, 11 Aug 2009 11:31:03 +0900
    見た目だけはなんとか完成 http://tech.actindi.net/3458828432 デザインされたhtmlをlmlに直したりしているのですが、これが割と大変です。
    lmlとは、htmlをS式で表現したものなのですが、簡潔でS式の編集環境が整ってさえいれば素のhtmlより簡単に編集できます。
    とはいえ、その編集環境を整えるのが面倒なのですが…。 ]]>
    Mon, 10 Aug 2009 02:40:32 +0900
    急激に重くなった様子 http://tech.actindi.net/3458566436 Fri, 07 Aug 2009 01:53:56 +0900 URLを毎度決めている http://tech.actindi.net/3458279537 (get-universal-time) が使えることに気付きました。
    SLIME上で(get-universal-time)を評価してURLにすると良いかもと。 (get-universal-time)はUNIXタイムのように1970年からではなく、1900年からの秒数になります。 ]]>
    Mon, 03 Aug 2009 18:12:17 +0900
    CSSはウェブページの命 http://tech.actindi.net/3458279064 Mon, 03 Aug 2009 18:04:24 +0900 エントリーを後でどういう風に修正したら良いか http://tech.actindi.net/3457825200 エントリーを後でどういう風に修正したら良いか
    めんどくさそうです。

    ]]>
    Wed, 29 Jul 2009 12:00:00 +0900
    Hunchentootにしたい http://tech.actindi.net/3457821600 色々面倒臭そうなのでHunchentootにしたくなってきました。 とはいえ、Hunchentootも使ったことがないのでなんとも言えません。

    ]]>
    Wed, 29 Jul 2009 11:00:00 +0900
    テストエントリー http://tech.actindi.net/3457818000 SBCLだと日本語が通らないので、無理矢理にマクロを通したり、文字列をバイト列に変換したり涙ぐましいのですが、もっと簡単な方法はないんでしょうか。
    根本的に直さないと駄目な気がしてきました。 AllegroServeより良いのってどういうのがあるんでしょう。

    ]]>
    Wed, 29 Jul 2009 10:00:00 +0900
    掃除は大事 http://tech.actindi.net/3448278000 稼働中のPCを触ってみたところかなり高温になっているという報告を受けたので、4月から新しい仲間になったmasuda氏が機転を効かせてPC内部を掃除したところ、ばっちりPCの温度が下がり、調子も良くなりました。
    どうも熱暴走でPCが落ちてしまっていたようです。
    基本ですが掃除は大事だなとあらためて思った一件です。 ]]>
    Fri, 10 Apr 2009 00:00:00 +0900
    こんにちは、こんにちは http://tech.actindi.net/3445570800 どうぞよろしくお願いします!! ]]> Mon, 09 Mar 2009 16:00:00 +0900 非常に重要なアプリケーションの導入 http://tech.actindi.net/3445513200 先週末からchiba2009さんがエンジニアとして入ってくれました。
    chibaさんは一番得意な言語がCommon Lispという素敵な方です。
    ぜひ社内のシステムのそこここにCommon Lispを忍ばせてほしいです。
    そのchibaさんに今日、とても重要なアプリケーション教えてもらいました。
    それはvrmsです。
      % apt-cache search vrms
    vrms - virtual Richard M. Stallman
    
    早速インストールして実行してみました。
      % vrms
                    Non-free packages installed on dev
    
    gdb-doc                   The GNU Debugger Documentation
    
      1 non-free packages, 0.2% of 503 installed packages.
    
    まずい!
    というかなんでgdbのドキュメントがnon-freeなんでしょうか。
      % sudo apt-get remove --purge gdb-doc
    % vrms
    No non-free packages installed on dev!  rms would be proud.
    
    これで安心。rmsもお喜びのようです。 ]]>
    Mon, 09 Mar 2009 00:00:00 +0900
    sakuraba引退記念 http://tech.actindi.net/3445167600 最初から予定されていたことですが、2月末で、中米の荒くれ者ことsakurabaがアルバイトを完了しました。
    沖縄料理屋で送別会をやって、プレゼントを贈りました。
    sakurabaはMac信者なのでMighty Mouseでも送ればちょっとうれしいのは目に見えていたので、一人おでんセットをプレゼントしました。(しかもMighty Mouseより無意味に高い)
    sakurabaは僕とmachidaさんに向かってとびっきりの呪いの言葉を吐きました。
    sakurabaはアルバイトできてから、RailsもLinuxのサーバー構築も自分でどんどん覚えてしまって、一人でできるようになってしまいました。
    いまでは僕が、「もっとテスト書いたほうがいいですよ」と怒られる始末。
    ボリビアにでも旅立ってしまうのかもしれませんが、これからのsakurabaの活躍を陰ながら応援しています。 ]]>
    Thu, 05 Mar 2009 00:00:00 +0900
    ベンチャーでのおすすめアンチウィルスソフト http://tech.actindi.net/3444519600 以前、はじめてベンチャーのシステム管理を担当したときは、張り切っていて、サーバー集中管理型のアンチウィルスソフトの見積もりを取ったりしていたんですが、今回は、「フリーでいいの無いかな?」という、ゆるふわ系です。
    人数が10人程度なのでディレクトリサービスとか、そこまでやらなくてもいいかなと思っています。(以前は10人未満の会社でActive Directoryを使ってましたが、もう設定とか思い出せません)個人ではアンチウィルスソフトは AVG を使っていて、非常に気に入っていたんですが、商用利用は有料なのでGPLの ClamWin を試してみました。
    日本語化パッチも公開されていて、定義ファイルのダウンロードやスキャンのスケジュール設定も簡単にでき、予想以上に「使える!」といった感じでした。
    会社でも導入を進めて行きたいと思います。 ]]>
    Wed, 25 Feb 2009 12:00:00 +0900
    オフィスの引越し(プロバイダー編) http://tech.actindi.net/3444476400 五反田から五反田へオフィス引越しました。
    システム管理者にとっては何かと大変なオフィスの引越しですが、僕は担当することになったばかりなので全体を把握する丁度良い機会になりました。
    予告通り、プロバイダーはインターリンクの固定IP8個にしました。
    社内にクリティカルなサーバは無いんですが、IPも振り直しです。
    /etc/network/intarfaces を変更して安心してたら、Apacheの443番ポートのバーチャルホストの設定のところに固定IPを書いていたのを忘れてました・・・。
    それと、インターリンクはOP25Bしていることを忘れていて、
    (25番で大丈夫でした。)
    「そういやRedmineのチケット関連のメールが来てないな・・・」
    などと思っていました。
    慌ててPostfixをSubmissionポートを使う設定に変えました。
    会社で25番を絶対使いたい場合は別のプロバイダをお考えください。
    参照: Postfix – Submissionポートで通信 – p0t ]]>
    Wed, 25 Feb 2009 00:00:00 +0900
    1人体制での死活監視 http://tech.actindi.net/3444217200 一定規模以上のWebサイトを運営しているエンジニアの方、業務時間外の障害対応ってどういう風にやっていますか? ルールとか体制とかを中心に教えてほしいです。 ちなみに.. – 人力検索はてな
    ちなみにぼくの会社では、監視ツールや自作監視スクリプトでアラートをエンジニア社員全員に送って、誰かが対応することになっています。(たまに誰も対応やレスをしなくて上司に怒られます) これはぼくら社員にとって正直ストレスになるので、なにかよいルールや体制を上司に提案したいなと考えています。
    はてなでこういう質問がありました。たしかに大きいところではストレスになりますよね。 うちは「一定規模以上のWebサイトを運営してい」ないので特にストレスは感じないです。(アラート受ける人も2人しかいないし・・・)
    Montasticという無料でWebのステータスをチェックしてアラートを送ってくれるサービスを使っています。
    これだとHTTPしかチェックしてくれないのでライブドアのDATAHOTEL PATROLというやつも試してみたいところです。
    それとRailsのExceptionNotifierプラグインのみです。
    社内に監視システムを構築するとその監視システム自体の維持が大変なのでやってません。
    品質とのトレードオフだと思いますが、基本的に、
    「人員1人体制想定でどこまで品質を高められるか」
    という方向でがんばってみたいと思います。 ]]>
    Sun, 22 Feb 2009 00:00:00 +0900
    迫る引越し http://tech.actindi.net/3444174000 何で今急いでブログを作ったかというと、会社が明日引越しだからです。
    明日かよ!とお思いかもしれませんが、時は無常にも過ぎ去り、明日です。
    まずは、引越し先に電話回線(FAX)・Bフレッツ回線・プロバイダを用意しました。
    お客様のサービスのようなクリティカルなものは社内に無いので、自社サービスがひとつ乗っかっているサーバー1台だけを先に人力(チャリと人手)で運んで繋いできました。(昨日)
    それ以外は止めても大丈夫なので荷造りして引越し屋さんにまかせます。
    自分のブログで ITベンチャー勝ち組セット などというエントリーを書きましたが、その通りの INTERLINKの固定IP8個のやつ を契約しました。
    カードがあればその場で使えるようになるのは助かりますね。
    引越し先はBフレッツのマンションタイプが元々あったのでVDSLモデムが届きました。
    無線LANルータは COREGA CG-WLBARGPXW を買いました。
    おいおい、こんなので大丈夫か?と思うかもしれませんが、このルーター使ったことあるので大丈夫なんじゃないかなと楽観的に考えています。
    固定IPを使うにはルータにUnnumbered IPという機能が必須だそうで、買うときに気をつけたいポイントです。
    使ったことあるルータなので、特に問題無く、無線LANと固定IPでサーバ一個(Debian etch)設定できました。
    /etc/network/interfaces を新しいIPに変えて、DNSを変更しただけです。
    無線LANはWPA2, AESでパスワードかけましたが、アクセスポイント自体を隠す設定にするかどうかちょっと悩んで隠さないことにしました。(エンジニアでない人はクライアントの設定で混乱するかと思いまして・・・) これはどっちがいいでしょうか。みなさんどうしてますか?
    引越し後の通常社員初出社は明後日で、引越し屋さんが運び込むのは明日です。
    明日中に全クライアント向けの配線や設定を済ませてこようと思います。 ]]>
    Sat, 21 Feb 2009 12:00:00 +0900
    ブログはじめました http://tech.actindi.net/3444130800 先日、アクトインディ株式会社のシステムの担当になったのでこのブログを作ってみました。
    小さくてくだらない作業までこのブログに書いていこうと思うので、「ベンチャーのシステム担当あるある」
    みたいな感じで見ていただければ・・・なとと考えています。
    現状、僕とアルバイトのsakurabaの二人でネットワークと開発(要するにパソコン関係全部)を担当しています。
    僕自身、ネットワークの知識がイマイチなところもあり、「そこはこうすべきだろう、常識的に考えて・・・」
    などというところがあれば教えていただきたいな、という面もあります。
    なにはともあれ、よろしくお願いします。 ]]>
    Sat, 21 Feb 2009 00:00:00 +0900