dorapon2000’s diary

忘備録的な。セキュリティとかネットワークすきです。

Microsoft Bot Frameworkを使ってSkypeボットを作る

Microsoft Bot Frameworkというものが4月から使えるようになっていたらしく、今まで作れなかったSkypeボットもそれで動かせるということで試してみました。ボットはheroku上で動かします。数ヶ月の間にちょくちょく仕様が変わっているようで、よく惑わされました。


公式リンク

必要なもの

  • Microsoftのアカウント
  • herokuのアカウント
  • Node.js

流れ

  1. Bot Builder for Node.js でボットを作る
  2. herokuにデプロイ
  3. Developer Portalでボットとして登録
  4. 登録する過程で得たappIdとappPasswordを環境変数に追加 (or ボットに直書き)
  5. スカイプチャンネルに対応させる

Bot Builderでボットを作る

$ mkdir mybot
$ cd mybot
$ npm init
$ npm install --save botbuilder
$ npm install --save restify

サンプルコードを参考にして、hello worldとだけ返すbot

// app.js

var restify = require('restify');
var builder = require('botbuilder');

//=========================================================
// Bot Setup
//=========================================================

// Setup Restify Server
var server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
   console.log('%s listening to %s', server.name, server.url); 
});
  
// Create chat bot
var connector = new builder.ChatConnector({
    appId: process.env.MICROSOFT_APP_ID,
    appPassword: process.env.MICROSOFT_APP_PASSWORD
});
var bot = new builder.UniversalBot(connector);
server.post('/api/messages', connector.listen());

//=========================================================
// Bots Dialogs
//=========================================================

bot.dialog('/', function (session) {
   session.send('Hello World'); 
});

ボットの機能を左右させる部分はBots Dialogs以下の部分です。Bot SetupではappIdとappPasswordを環境変数から受け取る形式にしているので、appIdとappPasswordがわかり次第、環境変数を設定していきます (まだわからない)。環境変数から受け取らず、直書きしてももちろん大丈夫です。

参考にしたサイトではUniversalBotではなくBotConnectorBotが用いられていたのですが、現在は非推奨のようです。

herokuにデプロイ

$ git init
$ heroku create mybot
$ echo 'node_modules' > .gitignore
$ echo 'web node app.js' > Procfile
$ git add .
$ git commit -m "First commit"
$ git push heroku master

herokuの管理画面でHeroku Domainを確認する (恐らく、mybot.herokuapp.comとなっている)。

Developer Portalでボットとして登録

Register a botでボットを登録します。

  • Bot handle : 一意なボットのID (後の変更不可)
  • Messaging endpoint : http://[Heroku Domain]/api/messages
  • Microsoft App ID : 下のボタンで新しく作る (AdBlockを停止しないと反応しませんでした)。その際パスワードもメモっておく。
  • Privacy statement : http://[Heroku Domain]/privacy (今回は適当)
  • Terms of Use : http://[Heroku Domain]/terms (今回は適当)

appIdとappPasswordを環境変数に追加

先ほどの環境変数を登録します。 ローカルでは

$ export MICROSOFT_APP_ID=[appId]
$ export MICROSOFT_APP_PASSWORD=[appPassword]

heroku上でも環境変数として登録する

$ heroku config:set MICROSOFT_APP_ID="[appId]"
$ heroku config:set MICROSOFT_APP_PASSWORD="[appPassword]"

Skypeチャンネルに対応させる

Developer PortalMy botsの左下でherokuとちゃんとつながっているかTestできます。うまく行くとAcceptedと表示され、エラーなら表示してくれます。参考にしたサイトでは入力のテストもできるようなUIになってましたが、私の時はTestというボタンひとつだけでした。

そして、Skypeチャンネルをaddします。Skypeの[Add to Skype]を押して指示に従うと、ボットとSkype上で会話できるようになります。試しに何かメッセージを送ればHello Worldと返してくれるはずです。

https://join.skype.com/bot/[appID]のリンクで他の人にも紹介できます。ただし公式ドキュメントのQ&Aでは、私的利用や企業内での利用は考慮されていないとあります。調べてみましたが、publishしてない状態でグループにボットを入れることはできなさそうです。

参考

emacs上とシェル上でのバイトコンパイルの結果が違う

前の記事で気づいたバイコンパイル時のエラーについて、同じように困ってる人の助けになればと思い残しておきます。


前提

  • mac OSX Yosemite 10.10.5
  • emacs 24.5
  • init-loader
  • packagesでパッケージ管理

フォルダ構成は前の記事で書きました。

発生したエラー

$ emacs -batch -f batch-byte-compile inits/*.el

In toplevel form:
inits/00-basic.el:22:7:Warning: assignment to free variable `show-paren-style'
inits/00-basic.el:64:7:Warning: assignment to free variable `c-default-style'
inits/00-basic.el:82:1:Warning: cl package required at runtime
Wrote /Users/dorapon2000/.emacs.d/inits/00-basic.elc

In end of data:
inits/10-anzu.el:8:1:Warning: the function `global-anzu-mode' is not known to be defined.
Wrote /Users/dorapon2000/.emacs.d/inits/10-anzu.elc

In toplevel form:
inits/10-auto-async-byte-compile.el:5:1:Error: Cannot open load file: No such file or directory, auto-async-byte-compile
Wrote /Users/dorapon2000/.emacs.d/inits/10-color-theme.elc
Wrote /Users/dorapon2000/.emacs.d/inits/10-elscreen-persist.elc

...

いつものようにinits以下の.elファイルをすべてバイコンパイルしようとすると、全体的に上記の様な警告とエラーが出ました。 種類としては3つ。

  1. Warning: assignment to free variable `show-paren-style'
  2. Warning: the function `global-anzu-mode' is not known to be defined.
  3. Error: Cannot open load file: No such file or directory, auto-async-byte-compile

特に3.が出るとそのファイルがコンパイルされないのでなんとかしたかったです。 1.は調べるとあまり気にしなくていい感じでした。 2.は3.と原因が同じという雰囲気をしてます。

2.と3.について同じように悩んでる人はいないものかと検索しても、原因はヒットしませんでした。 同じような環境の人はたくさんいるはずなのに、なぜ自分だけこの問題が発生するのか未だにわかりません。

解決法

初心に戻ってバイコンパイルについて調べていて、 Emacsで設定ファイルを初めてバイトコンパイルする方法とその後自動で更新する方法 にある方法でバイコンパイルしたら、警告もほぼ出ずにするっとコンパイルできました。 しかし、それを.elファイルに書いてシェル上で実行してみてもうまくいきませんでした。

# 全部は長いので10-auto-async-byte-compile.elだけをコンパイルさせる。残りはコンパイルをskip。

$ cat byte-compile.el
(byte-recompile-directory (expand-file-name "~/.emacs.d/inits") 0)

$ emacs --script byte-compile.el
Checking /Users/dorapon2000/.emacs.d/inits...
Compiling /Users/dorapon2000/.emacs.d/inits/10-auto-async-byte-compile.el...

In toplevel form:
10-auto-async-byte-compile.el:5:1:Error: Cannot open load file: No such file or directory, auto-async-byte-compile
Done (Total of 0 files compiled, 1 failed, 36 skipped)

ここで思い当たるのはload-pathです。 ロードパスの通った(設定が一度読み込まれた)emacs上だからうまくいき、シェル上ではロードパスが読み込めておらず2.や3.のエラーがでる。 そこで、$ emacs -qで設定ファイルを読み込まずに起動して、先ほどの方法でコンパイルすると案の定できませんでした。 次に、(package-initialize)(ロードパスを読み込む)を実行してから試すとコンパイルできました。

最終的には以下のようにすることで、シェル上からでも正常にバイコンパイルできるようになりました。 (2.と3.が解決できました)

$ cat byte-compile.el
(package-initialize)
(add-to-list 'load-path "~/.emacs.d/elisp/auto-complete")
(byte-recompile-directory (expand-file-name "~/.emacs.d/inits") 0)

$ emacs --script byte-compile.el
Checking /Users/dorapon2000/.emacs.d/inits...
Compiling /Users/dorapon2000/.emacs.d/inits/10-auto-async-byte-compile.el...
Wrote /Users/dorapon2000/.emacs.d/inits/10-auto-async-byte-compile.elc
Done (Total of 1 file compiled, 0 failed, 36 skipped)

(add-to-list 'load-path "~/.emacs.d/elisp/auto-complete")について。 auto-completeはpackagesで入れたパッケージではなく、野良lispのため、別にload-pathを通す必要があるようでした。 しかし自分自身よくわかっておらず、packagesにもあるパッケージだからとそちらで改めて落としたのに、この行がないとコンパイルできませんでした。 そもそも、(package-initialize)でelisp/auto-completeのパスは通っているはずなのに、やはり書かないといけませんでした。

なぜ自分だけこの問題が起きたのか。なぜ以前はできていたものが今はできないのか。エラーが出るものと出ないものの差はなんだったのか。 疑問は山積みですが、なにはともあれシェル上からコンパイルできるようになって満足とします。

新しい環境に1からemacsの設定を入れる

emacsの設定をgithubにあげておけば、新しい環境でemacsの設定を反映させたい時、未来の自分がなんとかしてくれるだろう。 と後回しにしていたら、案の定大変だったので、さらなる未来の自分のためにやり方を残しておきます。


前提

設定

まずgithubからcloneします。

$ git clone https://github.com/dorapon2000/my-emacs.git .emacs.d

ファイル構成は以下のとおり。

.emacs.d
|__ elpa #package.elで入れたパッケージが入ってる
|__ elisp #それ以外のパッケージが入ってる
|__ inits #inits.elによって読み込まれる設定ファイル
    |__ 00-basic.el
    |__ 10-xxx.el ... 
|__ inits.el #emacsが起動した時に最初に読み込まれる設定ファイル
|__ setup.el #新しい環境でパッケージをインストールするためのファイル
|__ byte-compile.el #バイトコンパイル

設定ファイルはinits以下に入ってるため、必要なパッケージをダウンロードしておく必要があります。 一つ一つ手動では大変なので、setup.elが現在入っていないパッケージを自動でダウンロードします。(入れたいパッケージはあらかじめsetup.elに記述の必要あり)
setup.elはEmacs起動時に自分好みのelispを自動的にインストールする - hnwの日記さんのものをそのまま流用しています

$ emacs --script setup.el

高速化のために設定ファイルをバイコンパイルします。

$ emacs --script byte-compile.el

ちなみに、bytecomp.elという名前はemacsのビルドインライブラリで使われており、自分が書いたファイルには付けない方がいいです。*1

これで新しい環境に今までどおりのemacs環境を構築できます。

実際はバイコンパイルのところで今までログだと思っていたメッセージが実はエラーメッセージだということに気づき、現在格闘中。

追記
様々な理由でエラーメッセージがありましたが、なんとか対応できました。 エラーの原因について次の記事で書きます。

参考文献

fstabをぐしゃぐちゃにしてFreeBSDが起動しなくなった話

研究室の計算機にFreeBSDを入れる際、使い慣れてないviでfstabに項目を追加しようとして、中身をぐちゃぐちゃにしてしまいました。

保存せずに終了するつもりが:q!の:(コロン)が打てず。 仕方なく一度保存して、pkgでemacsをいれて改めて編集しようとするも、emacs24-24.5_3,3の_(アンダーバー)が入力できず。 (# pkg install emacsでは複数のemacsを入れてしまいうまく動かないようです。*1 )

ここで英字配列としてキーボードを認識してるから_が書けないのだと気づくも、:も同じ理由で書けていなかったとまで頭が回りませんでした。 てっきりコマンドモードに移行できていないのかと思っていました。

とりあえず、fstabの問題はおいておき別の設定をし、満足して電源を落とすところから長い格闘が始まります。

結果的にどうでもいいことに悩まされていたのですが、記録に残しておかなくては気が収まりません。


解決方法

fstabはデバイスを起動時に自動的にマウントさせるための設定ファイルです。

私はそのなかのHDDを/(ルートディレクトリ)にマウントする行をぐちゃぐちゃにしてしまっていました。 もちろん、いつも通りにブートしようとするとマウントするデバイスが適切でない旨のエラーが表示され、FreeBSDは起動しません。

その時、適切なデバイスをマウントさせるよう入力モードになります。

mountroot>

ここで入力できる値はヘルプの?と形式にのっとったマウントするデバイスの名前だけです。

?を入力するとその計算機に接続されているストレージ情報が列挙されます。 その中のHDDにあたるものをマウントさせたいわけですね。

今回の私の例ですと以下のように/etc/fstabには書かれていたので、

/dev/ada0p2    /   ufs   rw   1   2

バイス名は/dev/ada0p2、ファイルシステムはufs、オプションはrwとわかります。

形式は[ファイルシステム]:[デバイス名] [オプション]です。 なお、:は英字配列では[shift] + [ ; ]です。[shift] + [ ] ]はブロークンバーなんですが、フォントによっては:に見えるので注意です。

mountroot> ufs:/dev/ada0p2 rw

すると次はシェルが起動します。 正しくブートされたわけではなく、ここでエラーの原因を直せということです。

使えるエディタはviだけではないことを研究室仲間に教えてもらい、ここからはeeを使ってfstabを直しました。 eeはemacsライクなキーバインドを持ちあわせており、親切にも上方にコマンドの説明が書かれています。

ぐちゃぐちゃにしてしまったfstabを正しく直して、リブートすれば元通りにFreeBSDが起動してくれます。

他に試したこと

「fstab いじる」などで検索するとシングルユーザーモードを使えと出ます。 FreeBSDの最初のメニューで選択できるんですが、2.シングルユーザーモードでも結局

mountroot>

が表示されてしまい、本当に悩まされました。

3.Escape to loader promptでは上の問題が起こらずコマンドのようなものを打てるのですが、シェルとは違うようです。 あくまでブートに関するコマンドだけで、詳しくはFreeBSD ハンドブックをご覧ください。

別の手段として、Puppy LinuxをUSBからブートしてHDDのfstabを変更しようと試みたのですが、FreeBSDファイルシステムGPTはPuppy Linuxで読み込めませんでした。 調べているとgdiskというコマンドでGPT内のファイルも書き込めるようです。*2 ただ、難しくて理解できてません。

参考文献