ぷよぷよを作ろう

* [Top](/) * [Softwares](/#Softwares) * [Auto Complete Mode](/software/auto-complete/) * [RSense](/software/rsense/) * [Undo History](/repo/undohist.git/) * [Publications](/#Publications) * * * * * Contact * [tomo@cx4a.org](mailto: tomo@cx4a.org) * [Twitter](http://twitter.com/m2ym/) * [GitHub](http://github.com/m2ym/)
* [Top](/) * [Softwares](/#Softwares) * [Auto Complete Mode](/software/auto-complete/) * [RSense](/software/rsense/) * [Undo History](/repo/undohist.git/) * [Publications](/#Publications) * * * * * Contact * [tomo@cx4a.org](mailto: tomo@cx4a.org) * [Twitter](http://twitter.com/m2ym/) * [GitHub](http://github.com/m2ym/)

"<"i><"""""""""">T"p<""><""i>"<"i><"""""""""#S"""""""s">S"""""""s<"">""<"i><"""""""""s"""""""""u""-"""p"""""">Au"""C""p"""""M"d"<""><""i>"<"i><"""""""""s"""""""""s"ns""">RS"ns"<""><""i>"<"i><"""""""""""p""und""is""gi""">Und""His"""y<""><""i>"<"u"><""i>"<"i><"""""""""#Pub"i"""i"ns">Pub"i"""i"ns<""><""i>"<"u">""<"""">"""<"i>C"n""""""<"i><""""""""""i""":""""@"x4""""g">""""@"x4""""g<""><""i>"<"i><"""""""""""p:""""i""""""""""2y""">T"i""""<""><""i>"<"i><"""""""""""p:""gi""ub""""""2y""">Gi"Hub<""><""i>"<"u"><""i>"<"u">

1 必要な物

  • Emacs 22 or higher

2 Emacs の基本操作

  • C-x はコントロールキーを押しながら x を押す
  • M-x はメタキー(Altキー)を押しながら x を押す
    C-x C-fファイルを開く
    C-x C-sファイルを保存する
    C-x bバッファを切り替える
    C-f, C-b, C-n, C-p:カーソルを移動する
    C-wカット
    M-wコピー
    C-yペースト
    C-d一文字削除
    C-x C-eカーソルの前の S 式を実行する
    M-:S 式を評価する
    M-x COMMANDコマンドを実行
    C-x kバッファを削除する

3 進め方

  • puyo.el というファイルを作って指示に従って作っていってください
  • M-: あるいは scratch バッファによって評価して結果を確かめることができます

4 Emacs Lisp の概要

  • Emacs を拡張するための Lisp の方言

4.1 データ

4.1.1 整数

  • 固定幅整数
  • リテラル
    123         ; => 123
    -123        ; => 123
    
  • 基本演算
    (+ 1 2)     ; => 3
    (- 2 1)     ; => 1
    (* 2 3)     ; => 6
    (/ 6 2)     ; => 3
    

4.1.2 シンボル

  • 値を入れる箱
  • 一つのシンボルに値セルと関数セルが存在する
  • リテラル
    hello                  ; => hello の値
    foo-bar                ; => foo-bar の値
    
  • setq
    • シンボルに値を設定する関数
      ; x というシンボルに 100 をいれる
      (setq x 100)            ; => 100
      x                       ; => 100
      
  • set
    • setq と同じだが第一引数はクオートされない
      (set 'x 200)            ; => 200
      (setq xref 'y)          ; => y
      (set xref 123)          ; => 123
      y                       ; => 123
      
  • symbol-value
    • シンボルの値を取得する関数
      (symbol-value 'x)       ; => 200
      
  • fset
    • シンボルに関数を設定する関数
      (fset 'x 300)           ; => 300
      
  • symbol-function
    • シンボルに設定された関数を取得する関数
      (symbol-function 'x)    ; => 300
      
  • クオート
    a
    
    はシンボル a の値を返すが
    'a
    
    はシンボル a 自体を返す。 クオートによって値を評価するかどうかを制御できる。

4.1.3 コンスセル

  • car と cdr の二つのペアを持つオブジェクト
  • コンスセルを連結させてリストを表現する
  • リテラル
    ; コンスセル
    '(1 . 2)
    ; リスト
    '(1 2 3)
    ; リストはコンスセルで表現できる
    '(1 . (2 . (3 . ())))
    
  • car
    • コンスセルの car 部を返す
      (car '(1 . 2))         ; => 1
      
  • cdr
    • コンスセルの cdr 部を返す
      (cdr '(1 . 2))
      
  • setcar
    • コンスセルの car 部に値を設定する
      (setq c '(1 . 2))      ; => (1 . 2)
      (setcar c 3)           ; => 3
      c                      ; => (3 . 2)
      
    • コンスセルの cdr 部に値を設定する
      (setq c '(1 . 2))      ; => (1 . 2)
      (setcar c 3)           ; => 3
      c                      ; => (1 . 3)
      

4.1.4 配列(ベクター)

  • ランダムアクセスが高速なベクター
  • aref
    • 配列から指定したインデックスの値を取得する
      (setq a [1 2 3])    ; =>b [1 2 3]
      (aref a 0)          ; => 1
      
  • aset
    • 配列から指定したインデックスに値を設定する
      (setq a [1 2 3])    ; =>b [1 2 3]
      (aset a 0 2)        ; => 2
      a                   ; => [2 2 3]
      

4.1.5 文字列

  • リテラル
    "foo"                   ; => "foo"
    
  • substring
    (substring "hello" 0 4)        ; => "hell"
    
  • concat
    (concat "Hello" " world")      ; => "Hello world"
    

4.1.6 シーケンス

  • リストや配列、文字列はシーケンスとして扱うことができる
  • length
    • シーケンスの長さを取得する
      (length '(1 2 3))               ; => 3
      (length [1 2 3])                ; => 3
      (length "foo")                  ; => 3
      
  • mapcar
    • シーケンスの要素をマッピングして返す
      (mapcar 'identity '(1 2 3))     ; => (1 2 3)
      (mapcar 'identity '[1 2 3])     ; => (1 2 3)
      (mapcar 'identity "foo")        ; => (102 111 111)
      (mapcar (lambda (x) (* x x)) '(1 2 3)) ; => (1 4 9)
      
  • elt
    • 要素を取得する
      (elt '(1 2 3) 1)                ; => 2
      (elt '[1 2 3] 1)                ; => 2
      (elt "foo" 1)                   ; => 111
      

4.1.7 関数

  • (lambda (x y z) …) という lambda 式が関数の本体になる
  • defun
    • 関数を定義する
      ; 二乗を求める関数
      (defun square (x)
        (* x x))
      (square 2)     ; => 4
      
  • funcall/apply
    • 関数を呼び出す
      (funcall 'square 3)    ; => 9
      (apply 'square '(3))      ; => 9
      
  • lambda
    • 関数を生成する
      (setq square2 (lambda (x) (* x x)))
      (square2 4)            ; => (void-functoin square2)
      (funcall square2 4)    ; => 16
      (fset 'square2 square2)
      ;うまく呼べる
      (square2 4)            ; => 16
      

4.1.8 特殊

  • t
    • 真を意味する
      t   ; => t
      
  • nil
    • 偽を意味する
      nil ; => nil
      ()  ; => nil
      

4.1.9 比較

  • eq
    • オブジェクトの比較(ポインタ的)
      (eq 1 1)            ; => t
      (eq 1 2)            ; => nil
      (eq 'foo 'foo)      ; => t
      (eq '(1) '(1))      ; => nil
      (eq 1.2 1.2)        ; => nil
      (eq "foo" "foo")    ; => nil
      
  • eql
    • eq に加えて浮動小数点数の比較に対応
      (eql '(1) '(1))     ; => nil
      (eql 1.2 1.2)       ; => t
      (eql "foo" "foo")   ; => nil
      
  • equal
    • リストの構造や文字列の比較が可能
      (equal '(1) '(1))   ; => t
      (equal "foo" "foo") ; => t
      
  • =
    • 数値の比較
      (= 1 1)             ; => t
      (= 1 2)             ; => nil **** /=
      
    • 数値の否定比較
      (/= 1 1)            ; => nil
      (/= 1 2)            ; => t **** >/>=
      (> 1 2)             ; => nil
      (>= 1 2)            ; => nil **** </<=
      (< 1 2)             ; => t
      (<= 1 2)            ; => t
      
  • 否定
    (not t)             ; => nil
    (not nil)           ; => t
    

4.2 構文

4.2.1 if

(if COND THEN ELSE...)

(if (eq 1 1)
    (message "OK")
  (error "error")
  (error "do something"))

4.2.2 when

(when COND BODY...)
(if (not COND)
    (progn
      BODY...)) と同等

(when (eq 1 1)
  (message "do")
  (message "something"))

4.2.3 unless

(unless COND BODY...)
(if COND
    nil
  BODY...) と同等

(unless (eq 1 1)
  (message "oh")
  (message "my")
  (message "god"))

4.2.4 or

(or CONDITIONS...)

(or nil)    ; => nil
(or nil t)  ; => t
(or nil 1)  ; => 1

4.2.5 and

(and CONDITIONS...)

(and nil)   ; => nil
(and nil t) ; => nil
(and 1 2)   ; => 2

4.2.6 while

(while TEST BODY...)

(setq i 0)
(while (< i 5)
  (message "%s" i)
  (setq i (1+ i)))
; => 0 1 2 3 4

4.2.7 dotimes

(dotimes (VAR COUNT) BODY...)

(dotimes (i 5)
  (message "%s" i))
; => 0 1 2 3 4

4.2.8 dolist

(dolist (VAR LIST) BODY...)

(dolist (i '(1 2 3))
  (message "%s" i))
; => 1 2 3

4.2.9 let

  • 束縛を生成するために使う
  • ブロックのローカル変数みたいなもの
    (let VARLIST BODY...)
    
    (let ((x 100) (y 200))
      (message "%s %s" x y))    ; => 100 200
    

4.3 スコープ

  • Emacs Lisp はダイナミックスコープ
    (setq x 1)
    (defun scope-test ()
      (+ x 2))
    (scope-test 2) ; => 3
    (let ((x 3))
      (scope-test 2) ; => 5
    
  • クロージャーなし
    (defun make-adder (m)
      (lambda (n) (+ m n)))
    (funcall (make-adder 1) 2) ; => (void-variable m)
    

4.4 末尾再帰最適化

  • Emacs Lisp は末尾再帰最適化しない
  • ループを書くには再帰を使わず mapcar, while, dotimes, dolist を使う

4.5 スレッド

  • Emacs Lisp はシングルスレッド
  • 非同期 IO やタイマーコールバックはアイドル時に実行される

5 基盤

  • ゲームボードを作成するところまで
  • gamegrid というライブラリを使っている
  • M-: (progn (switch-to-buffer "Puyo") (puyo-init) (puyo-init-buffer)) してみよう

file:puyo0.el

6 ゲームスタートからゲームオーバーまで

  1. ぷよぷよを開始する puyo という関数を定義する
    (defun puyo ()
      "ぷよぷよをはじめる"
      (interactive)
      (switch-to-buffer "*Puyo*")
      ...)
    
  2. メジャーモードを定義する
    (defun puyo-mode ()
      "ぷよぷよモード"
      (interactive)
      (setq major-mode 'puyo-mode)
      (setq mode-name "Puyo")
      (puyo-init))
    
  3. puyo 関数から puyo-mode を呼ぶ
  4. ぷよぷよを開始する puyo-start-game という関数を定義する
    (defun puyo-start-game ()
      "ぷよぷよをはじめる"
      (interactive)
      (puyo-init-buffer)
      (gamegrid-start-timer puyo-default-tick-period 'puyo-update-game))
    
  5. puyo-update-game 関数を定義する
    (defun puyo-update-game (puyo-buffer)
      "ゲームをすすめる"
      (let (hit)
        (setq puyo-drop (+ puyo-drop (/ puyo-default-tick-period puyo-default-drop-speed)))
        (when (>= puyo-drop 1)
          ...)))
    
  6. ぷよを表示する
    • puyo-get-cell と puyo-set-cell という関数を定義する
      (defun puyo-get-cell (x y)
        (gamegrid-get-cell (+ puyo-top-left-x x)
                           (+ puyo-top-left-y y)))
      
      (defun puyo-set-cell (x y color)
        (gamegrid-set-cell (+ puyo-top-left-x x)
                           (+ puyo-top-left-y y)
                           color))                     
      
    • (0, 0) に赤のぷよを表示する
      (puyo-set-cell 0 0 1)
      
    • (1, 1) に黄のぷよを表示する
      (puyo-set-cell 1 1 3)
      
    • (puyo-init-buffer) で初期化できる
    • ぷよを描画する関数を定義する
      (defvar puyo-shape nil)
      (defun puyo-get-shape-cell (x y)
        (aref puyo-shape (+ (* y 3) x)))
      (defun puyo-draw-shape ()
        "ぷよを描画する"
        (dotimes (y 3)
          (dotimes (x 3)
            (let ((c (puyo-get-shape-cell x y)))
              (if (/= c puyo-blank)
                  (puyo-set-cell (+ puyo-pos-x x) (+ puyo-pos-y y) c))))))
      
    • ぷよを描画してみよう
      • ぷよは3*3のベクター
        (setq puyo-shape [0 1 0 0 1 0 0 0 0])
        (puyo-draw-shape)
        
  7. ぷよを消去する関数を定義する
    (defun puyo-erase-shape ()
      "ぷよを消去する"
      (dotimes (y 3)
        (dotimes (x 3)
          (let ((c (puyo-get-shape-cell x y)))
            (if (/= c puyo-blank)
                (puyo-set-cell (+ puyo-pos-x x) (+ puyo-pos-y y) puyo-blank))))))
    
  8. ぷよを作る関数を定義する
    (defun puyo-make-shape ()
      "ぷよを作る"
      (vector 0 (1+ (random 4)) 0
              0 (1+ (random 4)) 0
              0 0               0))
    
    • 使ってみる
      (progn (setq puyo-shape (puyo-make-shape)) (puyo-draw-shape))
      
  9. 次のぷよを出す関数を定義する
    (defun puyo-new-shape ()
      "次のぷよを出す"
      (setq puyo-pos-x (- (floor (/ puyo-width 2)) 2))
      (if (/= (puyo-get-cell (+ puyo-pos-x 1)
                             puyo-top-left-y)
              puyo-blank)
          (puyo-end-game)
        (setq puyo-pos-y 0)
        (setq puyo-shape (puyo-make-shape))
        (puyo-draw-shape)))
    
  10. puyo-end-game を定義する
    (defun puyo-end-game ()
      "ゲームオーバー"
      (interactive)
      (puyo-cleanup)
      (message "ゲームオーバー"))
    
  11. ゲームをすすめよう
    • puyo-update-game にロジックを追加する
            ...
            (puyo-erase-shape)
            (setq puyo-pos-y (1+ puyo-pos-y))
            (setq puyo-drop 0)
            (puyo-draw-shape))))
      
    • puyo-start-game に以下を追加する
      (puyo-new-shape)
      
  12. 衝突判定
    • 衝突判定関数を定義する
      (defun puyo-test-shape()
        "ぷよが衝突したか"
        (let ((hit nil))
          (dotimes (y 3)
            (dotimes (x 3)
              (unless hit
                (setq hit
                      (let ((c (puyo-get-shape-cell x y))
                            (xx (+ puyo-pos-x x))
                            (yy (+ puyo-pos-y y)))
                        (and (/= c puyo-blank)
                             (if (< yy 0)
                                 (or (< xx 0)
                                     (>= xx puyo-width))
                               (or (>= xx puyo-width)
                                   (>= yy puyo-height)
                                   (/= (puyo-get-cell x y)
                                       puyo-blank)))))))))
          hit))
      
    • puyo-update-game 関数にロジックに変更する
            (puyo-erase-shape)
            (setq puyo-pos-y (1+ puyo-pos-y))
            (let ((hit (puyo-test-shape)))
              (if hit
                  (setq puyo-pos-y (1- puyo-pos-y))
                (setq puyo-drop 0))
              (puyo-draw-shape)
              (if (and hit (>= puyo-drop 2))
                  (puyo-new-shape))))))
      

file:puyo1.el

7 動かせるようにする

  • メジャーモードに keymap を定義する
    (defvar puyo-mode-map
      (let ((keymap (make-sparse-keymap)))
        (define-key keymap "x" 'puyo-move-down)
        (define-key keymap "s" 'puyo-move-bottom)
        (define-key keymap "z" 'puyo-move-left)
        (define-key keymap "c" 'puyo-move-right)
        (define-key keymap "v" 'puyo-rotate-left)
        (define-key keymap "b" 'puyo-rotate-right)
        keymap))
    
  • メジャーモードになったときに puyo-mode-map を使うようにする puyo-mode 関数に以下を追加する
    (use-local-map puyo-mode-map)
    
  • puyo-rotate-left 関数を定義する
    (defun puyo-rotate-left ()
      "ぷよを反時計回りに回す"
      (interactive)
      (let ((old puyo-shape))
        (puyo-erase-shape)
        (setq puyo-shape
              (vector (aref puyo-shape 2) (aref puyo-shape 5) (aref puyo-shape 8)
                      (aref puyo-shape 1) (aref puyo-shape 4) (aref puyo-shape 7)
                      (aref puyo-shape 0) (aref puyo-shape 3) (aref puyo-shape 6)))
        (unless (puyo-try-rotate-move)
          (setq puyo-shape old))
        (puyo-draw-shape)))
    
  • puyo-rotate-right 関数を定義する
    (defun puyo-rotate-right ()
      "ぷよを時計回りに回す"
      (interactive)
      (let ((old puyo-shape))
        (puyo-erase-shape)
        (setq puyo-shape
              (vector (aref puyo-shape 6) (aref puyo-shape 3) (aref puyo-shape 0)
                      (aref puyo-shape 7) (aref puyo-shape 4) (aref puyo-shape 1)
                      (aref puyo-shape 8) (aref puyo-shape 5) (aref puyo-shape 2)))
        (if (puyo-test-shape)
            (setq puyo-shape old))
        (puyo-draw-shape)))
    
  • puyo-move-left 関数を定義する
    (defun puyo-move-left ()
      "ぷよを左に動かす"
      (interactive)
      (puyo-erase-shape)
      (setq puyo-pos-x (1- puyo-pos-x))
      (if (puyo-test-shape)
          (setq puyo-pos-x (1+ puyo-pos-x)))
      (puyo-draw-shape))
    
  • puyo-move-right 関数を定義する
    (defun puyo-move-left ()
      "ぷよを右に動かす"
      (interactive)
      (puyo-erase-shape)
      (setq puyo-pos-x (1+ puyo-pos-x))
      (if (puyo-test-shape)
          (setq puyo-pos-x (1- puyo-pos-x)))
      (puyo-draw-shape))
    
  • puyo-move-down 関数を定義する
    (defun puyo-move-down ()
      "ぷよを下に動かす"
      (interactive)
      (puyo-erase-shape)
      (setq puyo-pos-y (1+ puyo-pos-y))
      (if (puyo-test-shape)
          (progn
            (setq puyo-pos-y (1- puyo-pos-y))
            (puyo-draw-shape)
            (puyo-new-shape))
        (puyo-draw-shape)))
    

file:puyo2.el

8 ちぎれるようにする

(defvar puyo-task nil
  "実行中のタスク")

  • (puyo-new-shape) となっているところを (puyo-shape-done) にする
  • puyo-shape-done 関数を定義する
  • puyo-update-game 関数にタスク処理を追加する
    (defun puyo-update-game (puyo-buffer)
      "ゲームをすすめる"
      (let (hit)
        (setq puyo-drop (+ puyo-drop (/ puyo-default-tick-period puyo-default-drop-speed)))
        (when (>= puyo-drop 1)
          (cond
           ((eq puyo-task 'drop)
            (puyo-drop)
            (setq puyo-drop 0))
           (t
            (puyo-erase-shape)
            (setq puyo-pos-y (1+ puyo-pos-y))
            (let ((hit (puyo-test-shape)))
              (if hit
                  (setq puyo-pos-y (1- puyo-pos-y))
                (setq puyo-drop 0))
              (puyo-draw-shape)
              (if (and hit (>= puyo-drop 2))
                  (puyo-new-shape))))))))
    
  • puyo-drop 関数を定義する
    (defun puyo-drop ()
      "浮いてるぷよを落とす"
      (dotimes (y (1- puyo-height))
        (dotimes (x puyo-width)
          (let* ((yy (- puyo-height y))
                 (c (puyo-get-cell x yy)))
            (when (/= c puyo-blank)
              (while (= (puyo-get-cell x (1+ yy)) puyo-blank)
                (setq yy (1+ yy)))
              (puyo-set-cell x (- puyo-height y) puyo-blank)
              (puyo-set-cell x yy c))))))
    

file:puyo3.el

9 連鎖できるようにする

  • 連鎖できるかをテストする puyo-chain 関数を定義する
    (defun puyo-chain-1 (x y c color footprint)
      (if (or (< x 0)
              (< y 0)
              (>= x puyo-width)
              (>= y puyo-height)
              (= (aref footprint (+ x (* y puyo-width))) 1))
          0
        (let ((d (puyo-get-cell x y)))
          (if (= c d)
              (progn
                (aset footprint (+ x (* y puyo-width)) 1)
                (if color
                    (puyo-set-cell x y color))
                (+ (puyo-chain-1 (1- x) y      c color visit)
                   (puyo-chain-1 x      (1- y) c color visit)
                   (puyo-chain-1 (1+ x) y      c color visit)
                   (puyo-chain-1 x      (1+ y) c color visit)
                   1))
            0))))
    (defun puyo-chain (x y color)
      "連鎖する"
      (let ((c (puyo-get-cell x y)))
        (if (/= c puyo-blank)
            (let ((footprint (make-vector (* puyo-width puyo-height) 0)))
              (+ (puyo-chain-1 (1- x) y      c color visit)
                 (puyo-chain-1 x      (1- y) c color visit)
                 (puyo-chain-1 (1+ x) y      c color visit)
                 (puyo-chain-1 x      (1+ y) c color visit)
                 ))
          0)))
    
  • puyo-update-game 関数に連鎖ロジックを追加する
    (defun puyo-update-game (puyo-buffer)
      "ゲームをすすめる"
      (let (hit)
        (setq puyo-drop (+ puyo-drop (/ puyo-default-tick-period puyo-default-drop-speed)))
        (when (>= puyo-drop 1)
          (cond
           ((eq puyo-task 'drop)
            (puyo-drop)
            (setq puyo-task 'chain)
            (setq puyo-drop 0))
           ((eq puyo-task 'chain)
            (let ((count 0))
              (dotimes (y puyo-height)
                (dotimes (x puyo-width)
                  (let ((c (puyo-chain x y nil)))
                    (message "%s" c)
                    (when (>= c 4)
                      (puyo-chain x y puyo-blank)
                      (setq count (1+ count))))))
              (if (> count 0)
                  (setq puyo-task 'drop)
                (setq puyo-task nil)
                (puyo-new-shape)))
            (setq puyo-drop 0))
           (t
            (puyo-erase-shape)
            (setq puyo-pos-y (1+ puyo-pos-y))
            (let ((hit (puyo-test-shape)))
              (if hit
                  (setq puyo-pos-y (1- puyo-pos-y))
                (setq puyo-drop 0))
              (puyo-draw-shape)
              (if (and hit (>= puyo-drop 2))
                  (puyo-shape-done))))))))
    

10 仕上げ

  • 連鎖中はキー入力できないようにする

11 遊ぶ

  • M-x puyo でゲーム開始です

Author: MATSUYAMA Tomohiro <matsuyama@ariel-networks.com>

Date: 2008/11/15 19時28分00秒

HTML generated by org-mode 6.05b in emacs 23


Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <m2ym.pub@gmail.com>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <tomo@cx4a.org>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <tomo@cx4a.org>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <tomo@cx4a.org>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <tomo@cx4a.org>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama <tomo@cx4a.org>
http://cx4a.org/
[FSF Associate Member]

Tomohiro Matsuyama tomo@cx4a.org
http://cx4a.org/
[FSF Associate Member]