common lisp で何か書いてみる(その2)

どうも。
最近の投稿ペースが速くて自分でも驚きながら書いています。

さて、引き続き caveman2 で何か書いてみようという話です。
が、今回もまた自前のコードを入力する機会は訪れませんでした…

とりあえず目次は以下の通りです。

  • Road to qlot:quickload
  • 穴居人が立ち上がる時

■Road to qlot:quickload

結論:行ってみた限りでは全部行き止まりでした。

や、色々試したんですよ、ホントに。

qlfile の中身を次のようにして、それぞれコメントアウトしながら全部試しました。

# qlfile

github caveman2 fukamachi/caveman
# git caveman2 https://github.com/fukamachi/caveman.git
# ql caveman2 :latest

インストールコマンドも色々やってみました。

  • プロジェクトディレクトリで
    • (qlot:install :myproj1)
    • (qlot:install)
    • (qlot:install :caveman2)
  • プロジェクトディレクトリの一つ上で
    • (qlot:install :myproj1)
    • (qlot:install)
    • (qlot:install :caveman2)

見付けた変数を変えてみたりもしました。

(setq ql-setup:*quicklisp-home* #P"~/myproj1/")
(qlot:quickload :caveman2)

上の色々な組み合わせも試しました。

最終的に挫折しました…(泣)

■穴居人が立ち上がる時

で、qlot を使わずに caveman2 だけでも動かしてみようと試行錯誤して、こちらは何とかサーバを立ち上げる事ができました。

前回で (ql:quickload :caveman2) は通るようになったので、github の README を読みながら進めていきます。

最初のプロジェクト作成は caveman2:make-project で問題無く終了です。

続いて、とりあえずテスト稼動が目的なので、ルーティングとかデータベース操作とかはどんどん飛ばして、サーバの立ち上げに入るわけです。

書いてある通り、おもむろに (myproj1:start :port 8080) を実行… 当然パッケージ myproj1 が無いと怒られます。
そして毎度の如く、苦闘の日々が始まるのです。

まあ、状況としては windows ユーザに linux の bash プロンプト使わせるようなものですね。
やりたい事は分かってるのに、どうやればいいのか分からないというジレンマに陥るわけです。

最終的に動くようになるまで

  • ファイルパスの指定方法
  • 読み込ませるファイル選択

で悩む事になりました。

パスの指定方法は make-project の引数にあったので、それでいけるはずです。
が、カレントディレクトリが何処なのかとか、うっかり #P を付けずに文字列で書いてしまったりとかで、なかなかうまく行きませんでした。

さらに、読み込むファイルが分からないという点が問題の複雑さに拍車をかけることになります。

コマンドの方は load か require あたりだろうと推測しましたが、ファイルに関しては見当もつかなかったので、考えていても仕方無いと割り切って総当たりして解答に辿り着きました。

誰かの役に立つかどうか怪しいところですが、いちおう最終形を載せておきます。

(ql:quickload :caveman2)
(caveman2:make-project #P"~/myproj1/" :author "myname") ; '#P' を付けないとエラー、ディレクトリは未作成でもよい

(load #P"~/myproj1/myproj1.asd") ; これと次は '#P' 無しでも動いたが、一応付けておく
(load #P"~/myproj1/app.lisp")
(myproj1:start :port 8080)

以上です。

VirtualBox のホストオンリーネットワークアダプタで困った件

ここ数日、いろいろ躓いてばかりな気がしますが、今度は VirtualBox のお話です。

毎回だらだらと長い文章になってしまうので、簡潔に書いてみます。

問題:ホストオンリーアダプタのネットワークでホストマシンだけ接続できない
結論:以前の設定が悪さをしてる場合があるので、未使用のサブネットアドレスを割り当ててみると改善される事がある

以上… では説明不足ですよね、はい。

まず VirtualBox の仮想マシンでホストオンリーネットワークアダプタを使っていました。
それで、ホストマシン(VirtualBox 自体を実行してる方ですね)をスリープしてから復帰すると、ホストだけが該当のネットワークで通信できない状態になっていました。
その間もゲストマシン(仮想マシンの方です)同士では問題無く通信できていました。

このような状況でも、最近までは仮想マシンを利用しての開発が無かったので特に問題ありませんでした。
ところが、ここ数日で やれDockerだ common lisp だと仮想マシンを使い倒すようになったため、この接続不良による再起動の嵐が非常に面倒になりました。

同じ問題で悩んでいる人がいるかと思い google 先生に検索してもらって幾つか事例を見て回ったのですが、現象が微妙に違っていたり、書いてある通りに試してみても効き目が無かったりと、うまくいきませんでした。
しかも、途中から「コントロールパネルのネットワークアダプタを無効にするとアイコンが消える」という新たな問題も発生したのです。

その後紆余曲折があり、最終的にはクリーンな状態になるよう

  1. 今あるホストオンリーアダプタを全部削除
  2. 再起動
  3. 今のバージョン(Ver 5.0.x)をアンインストール
  4. 再起動
  5. 以前のバージョン(ver 4.3.x)をインストール
  6. 再起動
  7. ホストオンリーアダプタを新規追加
  8. 再起動
  9. 仮想マシンのネットワークアダプタを新しいのに変更

という作業をして、接続を試しました。
ところがやっぱり駄目で、途方に暮れかけた時にゲスト側に不自然な点を発見したのです。
この時は VirtualBox の設定で DHCP サーバを OFF にしてあったのですが、何故かゲストが DHCP で IP アドレスを取得していました。
不思議に思って別のサブネットに変更してみたところ、それが大当りだったらしく嘘のように素直に仮想マシンと通信できるようになったのです。

それまでに散々いじったので、最後のサブネット変更が決定打だと言い切ることはできませんが、これが最も有力だと思います。
思い返してみると、確かに以前ホストオンリーアダプタを作成したまま virtualbox をアンインストールしたことがありました。
その後に新バージョンを入れ直した時にも、何故かインストール直後にアダプタが有り、気になった覚えもあります。

このような点から、最初に書いた結論が導きだされた次第です。
この記事が解決事例の一つとして、どなたかの参考になればいいなと思います。

common lisp で何か書いてみる(その1)

いつもの如く、唐突に common lisp の勉強をしようと思い立ち、色々見ながら環境設定をしたのでメモ。

思い付きで行動したので、あちこちで袋小路に突き当たりまくっているのは相変らずである。

■alpine linux で環境設定してみた

始まる前から後のことを考え、docker コンテナで動かすと面白そうということで virtualbox で新しく VM を作って alpine linux をインストールした。
debian とか ubuntu と違って、ISO 起動でインストーラが走ってくれるわけではなくて、Wiki を見ながら何とか導入。
パッケージは sbcl と clisp があったから「apk add」で簡単に入った。
ちなみに何度も「apt install」と入力してしまったのはご愛嬌。

問題はここからで、common lisp のパッケージ管理ライブラリ quicklisp を入れてみたが動かない。
ライブラリ自体の読み込みはできるけれど、そこから他のライブラリの自動ロードをするとデバッグモードになってしまう。
しばらく格闘してみたが、このまま環境設定で時間を食ってもアレなので、alpine は放置することにした。

■debian GNU/Linux で環境設定してみた

というわけで、愛用の debian GNU/Linux の VM を立ち上げて、こっちで環境設定してみた。
慣れ親しんだ「apt-get install」で、あっと言う間に sbcl のインストールが完了。
cl-quicklisp というパッケージもあったので、それも入れた。

で、プロジェクトごとにパッケージ管理をしてくれる(ruby の bundler みたいな) qlot というのを入れてみた。
これもすんなりと入ったので「よーし、これでコードが書けるぜー」とか思いながら、web フレームワークの caveman2 を入れ「ようとし」てみた。
…入ったよ、うん、結果的には。それだけで 1時間かかったのを気にしなければ。

その経緯

  1. qlot が初期化できない
    qlot が入った。ql:quickload でロードした。qlfile 書いた。
    さあ (qlot:install :myproj) …あれ?
    エラーした。
    qlfile を空にしてみてもエラーした。
    ライブラリ取得先を ql から git に変えてみてもエラーした。
    …よし、一旦放置。

  2. ql:quickload で caveman2 をロードできない
    さすがに直接 ql:quickload すれば動くだろう… あれ?
    エラーした。パッケージ名の書き方間違ったっけ?
    文字列で “caveman2” … エラー。
    キーワード形式で :caveman2 … エラー。
    クォートして ‘caveman2 … エラー。

    …落ち着け、キーボードは投げるもんじゃない。
    近場には HHK2Lite(英語) は売ってないんだ。
    それに買ったばかりのディスプレイに当たったらどうする。
    とりあえずお茶でも飲んで落ち着くんだ。

    (30分経過)…ふぅ、今日の茶菓子は美味かった。
    お、よく見たらエラーファイル名あるじゃん。cffi?
    とりあえず「apt-cache search」して… cl-cffi …って、そのまんまかい!
    駄目元でインストールっと。これで直ったら微妙だなぁ…
    (ql:quickload :caveman2) Enter!
    え、通るの?原因これだけ?私の30分を返せ!(←責任転嫁:嫁居ないけど)

  3. 改めて qlot
    んー、これなら qlot も動きそうな気がする。
    (qlot:install :myproj) っと。ん、エラー?
    …落ち着け、深呼吸だ。吸ってー、吐いてー、吐いてー、吐…けるかボケェ!吸わんと死ぬわ!
    ……やめよう、一人ボケツッコミは寂しすぎる…

    そうだ、さっきと同じくダイイングメッセージにヒントがあるに違いない。エラーでプロセス死んでるしな。
    死体は語る、犯人は現場に戻る(違)
    えーと…

    error while parsing arguments to DESTRUCTURING-BIND:
    invalid number of elements in
    ("caveman2:latest")」

    …待て、google 翻訳に頼るんじゃない。たぶん翻訳しても、そんなに変わらんし。
    一つずつ順番に行こう。

    • エラー
    • ↓している間
    • 解釈
    • 引数
    • ↓のため
    • DESTRUCTURING-BIND
    • (区切り)
    • 不正な
    • ↓の
    • 要素
    • ↓の中の
    • “caveman2:latest”

    まとめると
    「DESTRUCTURING-BIND のため(に)引数(を)解釈している間(に)エラー」
    「”caveman2:latest” の中の要素の数(が)不正」
    …ん?「caveman2:latest」って qlfile の書き間違い?
    あー、うん。たしかに違うわ。スペース必要なのね。

    よーし、これで動くはず。今日のおやつを賭けてもいい。
    (qlot:install :myproj) …エラー?え、おやつ抜き?えぇっ?
    くそぅ、この恨み晴らさでおくべきか。(←自業自得)
    二度ある事は三度あるのであるからしてヒントはエラーメッセージにあるのである。
    というわけでチェック!
    Component "myproj" not found
    うん、myproj は見付からないよね、今から作ろうと思ってるんだから。
    ……… もしかして :myproj の部分いらない?
    (qlot:install) っと… あー、うん。動いたね。動いちゃったね。
    私のおやつ返せ!(←再度の責任転嫁:もちろん嫁は居ない)

補足:没収されたおやつはスタッフ(= 私)がおいしくいただきました。

MySQL のテーブルコピーでやらかしてしまった件

はい、タイトル通り、今回はやらかしてしまった件です。
幸いにも被害は自分だけに留まったので大目玉をくらう前にコッソリ修正できましたが…

で、何をやったかというと、データごとテーブルのコピーを取るのに「CREATE TABLE test_t SELECT * FROM current_t」と叩いて test_t テーブルを作成したわけですよ。
それで、test_t テーブルをいろいろいじってから「RENAME TABLE current_t TO old_t, test_t TO current_t」として現行のテーブルと入れ替えました。
念の為にちょこっと動かしてみて、問題が無いようなのでそのまま利用することにしました。

悲劇はその後に起こったのです!

機能の追加を行った後で動作確認をしようと、テーブルに新規レコードを追加してからそのレコードを検索したところ… 見付からない…?
慌てて同じ条件で SQL コマンドを叩くと、ちゃんと居る…?
まさか幽霊かと思っても、この相手には見て確かめるための足はありません。
首を傾げながらレコードを消しては作り、消しては作り… 何度目かにふと思い立って SELECT * で全カラムを表示させてみました。
するとそこには… ああ、今思い出しても恐しい… プライマリキー値 0 (ゼロ)が居たのです!!

この時の動作は、レコードを探してそのプライマリキーを得るというものでした。その関数はエラー時に FALSE を返します。
ここで親切な PHP さんは、boolean の文脈では空文字列や数値の 0 (ゼロ)も FALSE だと判断してくださいます。
賢明な読者様にはもうお分かりでしょう。上の新規レコードが返すプライマリキー値 0 はエラー処理ルーチンの方へ入ってしまうのです。

まあ、ここまでは比較的よくある話とも言えます。
しかし、今回の真の敵はコイツであるはずが無いのです。何故ならそのカラムには AUTO_INCREMENT 属性が付けてあったのです。
つまり、新規レコードには自動的に新しい ID値が付与されるため、値 0 が設定される事実とは矛盾します。
この矛盾が今回の密室殺人の謎を解くカギになるはずだっ!(違)

と、ここまでが前置きです。
本題は「SHOW CREATE TABLE current_t」を実行した時に発見した驚愕の事実にあります。
コピー元(リネーム後の old_t)では「NOT NULL PRIMARY KEY AUTO_INCREMENT」となっていた部分が「NOT NULL DEFAULT ‘0’」に変わっているではありませんか。
確かにこれならプライマリキー値を指定しない新規レコードで、その値がデフォルトの 0 になるのは納得です。

実はテーブルのコピーを行う SQL 命令はもう一つあります。
こちらはテーブルの形だけコピーし、レコードは拾って来ない「CREATE TABLE new_t LIKE current_t」というものです。
この命令では、上で問題になった部分も元のまま「PRIMARY KEY AUTO_INCREMENT」で引っ張ってくれます。

以上から導き出される結論が「テーブルの全コピーを取るには CREATE TABLE LIKE で定義をコピーしてから INSERT INTO SELECT でレコードをコピーするという二段階で行うべし」というものです。
まあ、それ以前に作業した後にはちゃんと確認しろ(この場合は SHOW CREATE TABLE)という事なんですが…

ということで、今回の(イタい)レポートはこれで終わります。

コミPo! からキャラ絵を切り出す方法

またまた、お久し振りです。

今回は死蔵してあった コミPo! を利用して、ゲームの立ち絵などに使えるキャラ絵を切り出す方法をメモします。

コミPo! は、本来マンガ作成ソフトなのですが、作成した絵の二次利用(制限あり:詳細は 公式サイト参照)ができます。
そこで、様々なポーズ・表情のキャラ絵を作成してゲーム内で表示するために、何とか指定サイズで簡単に切り出せないか試して、とりあえず以下の方法に落ち着きました。
(ちなみに、今のところコマンドラインから操作するため、マウスクリックでホイホイというわけではありません)
続きを読む

Android Accessory 対応マイコンの調査

またしても興味分野がガラッと変わって Android ですよ。
だいぶ前から Android と外付けデバイスを接続できる Android Open Accessory という規格が出ていて、面白そうだとは思っていたのです。

で、改めて調べてみると、ベースは arduino を使っているのが多く、開発用ボードは数千円くらいでした。
それを買えば、面倒なことをしなくても開発がすぐ開始できるのは分かってはいるものの、いつも通り天邪鬼な性格が出て「マイコンで作れるんじゃないか?」ということで調査を始めたのでした。
続きを読む

altJSを始めるにあたって

いい加減 Webアプリに必須になってきた javascript を始めてみようと思ったが、素の JS は色々と面倒だという話を聞いた覚えがあったため、altJS と呼ばれる言語の方が良さそうだと思い、調査してみた。
何箇所かWebをサーフィンしてみて、結局のところ次のページが一番参考になった。

モダンな言語でHTML5を開発しよう! 俯瞰して理解するaltJSの比較 (前篇 – TypeScript, CoffeeScript, Haxe)
続きを読む

vagrant共有フォルダにmvしたらファイルが消えた…

docker をいじっていて、設定ファイルをメインマシンに移そうと思って、ディレクトリを vagrant 共有フォルダの /vagrant に移動したら、ディレクトリまるごと消えた…

幸いなことに、スクロールバッファにテキストが残っていたので何とか復旧できた。

使ったコマンドは「mv docker /vagrant/」だったので、もしかしたら「mv docker /vagrant/docker」としたら期待通りに動作したのかもしれない。

システム境界での作業には十分注意が必要だと痛感した出来事だった…

debian 7.6 に docker をインストール

docker がブームらしいという事で、仮想マシンの debian 7.6 にインストールしようとしたら躓いたのでメモ。

探してみた手順では以下のようになっていた。
$ sudo apt-get install -qqy ca-certificates
$ sudo apt-get install apt-transport-https
$ sudo sh -c "wget -qO- https://get.docker.io/gpg | apt-key add -"
$ sudo sh -c "echo 'deb https://get.docker.io/ubuntu docker main' | tee /etc/apt/sources.list.d/docker.list"
$ sudo apt-get update && sudo apt-get install -qqy lxc-docker

ところが、この手順で apt-get update したところ、docker リポジトリが取得エラーになってしまった。メインマシンから https で対象サイトにアクセスすると、ちゃんと Packages が取得できてたので悩んだ。

色々試してみたところ、結局 docker.list の中身を次のように書いたら動いてくれた。
deb http://get.docker.com/ubuntu docker main
(サイトの「io」を「com」に、「https」を「http」に変更した)

wget では https でも取得できてるので、何故こうしないと動かないのかは不明。

追記:よく見たら関連リンクに 7.6 用の手順があった…

メモ帳の置き換えで手間取った話

ずっと前に windows7 のメモ帳を置き換えて、別アプリで起動するように設定していました。ところが、一部のアプリでレポート表示を行うとエラーになる事があり、直らないかと色々試した経過を、忘れないように書いておきます。

まず結論から言うと、レジストリの HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe 中で Debugger に文字列(REG_SZ)としてアプリへのフルパス(とオプション)が書いてある場合、拡張子の関連付けよりも優先されていました。このため、いくら関連付けや notepad.exe の置き換えを試しても効果がありませんでした。おそらく環境設定系のアプリを利用した際に追加されたのだと思うのですが、普段使っているツールフォルダの中には入っていなかったようで、具体的にどうやって設定されたのかは不明です。

更に面倒を増やしていたのが、拡張子によって動作を変更するソフトを経由していた事でした。当時の自分としては設定の柔軟性を期待していたのだと思います。しかし、これがまた問題で、関連付けに従ってファイルを表示する場合は大丈夫なのですが、自力でメモ帳を指定されてしまうと exe ファイルへの拡張子別設定が利用されてしまい、肝心のテキストファイルが開かれない状態になっていました。

以上のように複数レイヤで設定されていたため、結論に辿り着くまでに散々 Try & Error を繰り返すことになりました… つくづく作業記録の重要性を感じた2時間でした。

最後に備忘録として、メモ帳置き換えを行うために試したアプリを挙げておきます。

  • Terapper : notepad.exe 置き換え型。手作業版。(本来はTerapad用)
  • NotepadBranch : notepad.exe 置き換え型。インストール版。
  • Anterix : 拡張子関連付け変更型。関連する拡張子をまとめて設定可能。
  • Contexter : 拡張子関連付け変更型。「新規作成」や「送る」の変更も可能。