HubotからGithubのissueを扱う
HubotからGithubのissueを扱う
http://shokai.org/blog/archives/9560
こちらコードに少し手を加えて、HubotからGtihub issueを扱えるようにしてみた。
create, list up, close github issues via hubot
使い方
Githubのトークンが必要:
$ curl -i https://api.github.com/authorizations -d '{"scopes":["repo"]}' -u "username" $ heroku config:set HUBOT_GITHUB_TOKEN=token_value
TODO listとかブログ記事のネタとかのために使う。
hubot issue list
hubot issue create タイトル body コンテンツ
hubot close issueのナンバー(#)
Processing のエディタとして Atom を使う
Processing のコーディングを快適にするために、Atom を使ってみる。
Processing とは
ビジュアルアートを学ぶためのオープンソースのプログラミング言語であり、開発環境。Java でビルドされており、その構文は Java をシンプルにしたもの。
エディタも備わっているが、より快適にコーディングするために、Atom に Processing 用のパッケージを導入してみる。
インストールするパッケージ一覧
これらのパッケージをインストールする。
$ apm install processing processing-autocomplete processing-language
Processing の導入
まずは、こちらから Processing の開発環境をダウンロード。
Processingを立ち上げて、Toolsメニューからprocessing-java
をインストールする。
which コマンドでパスを確認し、
$ which processing-java /usr/local/bin/processing-java
processing の実行パスに設定する
実際に使ってみる
.pde
ファイルを作成し、コーディングする。
ctrl-alt-b コマンドでビルドされれば、成功。
Atomのマークダウンプレビュー内で数式を扱う
Atomのマークダウンプレビュー内で数式を扱う
まずは必要な以下のパッケージをインストール
$ apm install markdown-preview-plus mathjax-wrapper
必要なパッケージ
-
マークダウンプレビューを可能にするパッケージ
-
MathjaxをAtomでも実現するパッケージ (インストールに時間が掛かる)
マークダウン
文章を記述するための軽量マークアップ言語
Mathjax
さまざまな数式用のマークアップ言語を表示するJavaScriptエンジン
マークダウンプレビュー内で数式を扱う
準備が完了したら、適当なマークダウンファイル(.md)を作成し、編集する:
<h3>The Quadratic Formula</h3> \[ x = {-b \pm \sqrt{b^2-4ac} \over 2a} \] <h3>The Cauchy-Schwarz Inequality</h3> \[ \left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right) \] <h3>A Cross Product Formula</h3> \[\mathbf{V}_1 \times \mathbf{V}_2 = \begin{vmatrix} \mathbf{i} & \mathbf{j} & \mathbf{k} \\ \frac{\partial X}{\partial u} & \frac{\partial Y}{\partial u} & 0 \\ \frac{\partial X}{\partial v} & \frac{\partial Y}{\partial v} & 0 \end{vmatrix} \] <h3>The probability of getting \(k\) heads when flipping \(n\) coins is</h3> \[P(E) = {n \choose k} p^k (1-p)^{ n-k} \] <h3>An Identity of Ramanujan</h3> \[ \frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} = 1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}} {1+\frac{e^{-8\pi}} {1+\ldots} } } } \] <h3>Maxwell’s Equations</h3> \[ \begin{aligned} \nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\ \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\ \nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\ \nabla \cdot \vec{\mathbf{B}} & = 0 \end{aligned} \]
Ctr+Shift+M
でマークダウンプレビューを、Ctr+Shift+X
で数式のレンダリングを起動する:
(そろそろ大きいディスプレイが必要)
終わり。
おまけ
いろいろググっていると、こんなサイトを見つけた。数学の質問を聞くことができるようだ。文系にはありがたい。英語が出来ればの話だが。
webpack, React Hot Loader + Browsersync でクロスブラウジング+ホットリロード開発
React Hot Loader + Browsersync
React Hot Loader を使えば、エディタを保存した時点で、React コンポーネントの変更が検知され、ブラウザの更新が自動で行われます。さらに、React Hot Loader はHotModuleReplacementPlugin(HMR) を使用しているため、更新時にページの全読み込みが発生せず、state が保持されたまま React コンポーネントの変更した箇所のみが部分更新されるため、いちいち手動でブラウザをリロードする手間が省けることに加え、チェック毎に state を変える必要がなくなります。
通常はデベロップメントサーバーに webpack-dev-server を使うことで、このホットリローディング機能を使うことができるのですが、今回は Browsersync を使って、クロスブラウジングとさらなるホットリローディングの強化を目指します。Browsersync は、ファイル群の変更を監視して、ブラウザを自動で全読み込みしてくれます。また、他のデバイスからもブラウジングができる、クロスブラウジングを可能にしてくれます。これと、React Hot Loader を使えば、快適に React フロントエンドが開発できるようになります。
まとめると、次のようになります。
React Hot Loader : React コンポーネントの変更を監視し、変更があれば最小限のページ更新を行う。
Browsersync :
js
ファイル以外のファイルの変更を監視し、変更があればページの全読み込みを行う。クロスブラウジングを可能にする。
導入
まずは必要な物をインストールします。package.json
は次のようになります。
"dependencies": { "react": "^0.13.3", "react-dom": "^0.14.7" }, "devDependencies": { "babel-core": "^5.8.38", "babel-loader": "^5.4.0", "browser-sync": "^2.11.2", "react-hot-loader": "^1.3.0", "webpack": "^1.12.14", "webpack-dev-middleware": "^1.5.1", "webpack-hot-middleware": "^2.10.0" }
通常の React Hot Loader に必要なライブラリに加えて Browsersync と webpack-hot-middleware
と webpack-dev-middleware
の ふたつのミドルウェアをインストールしておきます。webpack のホットリローディングは webpack-dev-middleware
がファイル変更イベントを検知して webpack-dev-server
に送信することで可能になりますが、 webpack-hot-middleware
を合わせて使うことで、その他のデベロップメントサーバーにイベントを送信して、自動でブラウザをリロードさせることができます。
webpack config
プロジェクトファイルの構成:
|___app/ | |___main.jsx |___dist/ | |___css/ | |___index.html |___server.js |___webpack.config.js
まずは webpack.config.js
を編集します。
下記は React Hot Loader での webpack.config.js
です。
// React Hot Loader var webpack = require('webpack'); var path = require('path'); module.exports = { debug: true, devtool: '#eval-source-map', entry: [ 'webpack-dev-server/client?http://localhost:3000', 'webpack/hot/only-dev-server', './app/main.jsx' ], output: { path: path.join(__dirname, 'dist'), publicPath: '/', filename: 'bundle.js' }, plugins: [ new webpack.HotModuleReplacementPlugin(), ], module: { loaders: [ { test: /\.jsx?$/, exclude: /node_modules/, loaders: ['react-hot', 'babel'] } ] } };
ここに、プラグインを2つ加えます。
plugins: [ // Webpack 1.0 new webpack.optimize.OccurenceOrderPlugin(), // Webpack 2.0 fixed this mispelling // new webpack.optimize.OccurrenceOrderPlugin(), new webpack.HotModuleReplacementPlugin(), new webpack.NoErrorsPlugin() ]
また、webpack-hot-middleware/client
をエントリーポイントに設定します。
したがって、webpack.config.js
ファイルは次のようになります。
var webpack = require('webpack'); var path = require('path'); module.exports = { debug: true, devtool: '#eval-source-map', entry: [ 'webpack/hot/dev-server', 'webpack-hot-middleware/client', './app/main.jsx' ], output: { path: path.join(__dirname, 'dist'), publicPath: '/', filename: 'bundle.js' }, plugins: [ new webpack.optimize.OccurenceOrderPlugin(), new webpack.HotModuleReplacementPlugin(), new webpack.NoErrorsPlugin() ], module: { loaders: [ { test: /\.jsx?$/, exclude: /node_modules/, loaders: ['react-hot', 'babel'] } ] } };
Browsersync
サーバーに、ミドルウェアを加えます。Browsersync を実行する server.js
ファイルは次のようになります。
/** * Require Browsersync along with webpack and middleware for it */ var browserSync = require('browser-sync'); var webpack = require('webpack'); var webpackDevMiddleware = require('webpack-dev-middleware'); var webpackHotMiddleware = require('webpack-hot-middleware'); var webpackConfig = require('./webpack.config'); var bundler = webpack(webpackConfig); browserSync({ server: { baseDir: 'dist', middleware: [ webpackDevMiddleware(bundler, { publicPath: webpackConfig.output.publicPath, stats: { colors: true } // http://webpack.github.io/docs/webpack-dev-middleware.html }), webpackHotMiddleware(bundler) ] }, files: [ 'dist/css/*.css', 'dist/*.html' ] });
baseDir
: サーバーのベースとなるディレクトリ。middleware
: 使用するミドルウェア。devMiddleware
ではpublicPath
の指定が必須となります。files
: Browsersync が変更を監視するファイル群。変更がなされると、ページ全体をリロードします。js
ファイル群の監視は webpack に任せるので、ここに記述する必要はありません。
クロスブラウジング
次のコマンドで、サーバーが立ち上がります。
node server.js
同時に、次のような URL が表示されます。
[BS] Access URLs: ------------------------------------ Local: http://localhost:3000 External: http://{PCのIPアドレス}:3000 ------------------------------------ UI: http://localhost:3001 UI External: http://{PCのIPアドレス}:3001 ------------------------------------
この URL に繋げば、同じネットワークに接続している他のデバイスからも、ブラウジングすることができます。 モバイルデバイスからの UI や UX のチェックに便利です。
npmのバージョン管理まとめ
たまにしか活用しないから忘れるのでメモ
参考: semver | npm Documentation
バージョン管理
npmでは、「セマンティックバージョニング」と呼ばれるバージョン管理法によって、依存パッケージやリリース物のバージョンを定義している。
npmにあるプロジェクトは少し異なるものもあるが、他の人と共有するようなプロジェクトは、普通 1.0.0 から始めるべきだ。
このルールに加えて、プロジェクトに変更を行った時のバージョンは次のように扱われる。
- バグの修正やその他のマイナーチェンジ: パッチリリースでは最後の数字をインクリメントする (e.g. 1.0.1)
- 既存の機能を壊さないような新しい機能: マイナーリリースでは、真ん中の数字をインクリメントする (e.g. 1.1.0)
- 後方互換性のない変更: メジャーリリースでは、最初の数字をインクリメントする (e.g. 2.0.0)
npm では依存パッケージを package.json
ファイルで管理する。そこでは、パッケージのバージョンを範囲指定することもできる。
もし、あるパッケージ 1.0.4 を範囲指定する時、次のようになる。
- パッチリリースの範囲指定: 1.0 / 1.0.x / ~1.0.4
- マイナーリリースの範囲指定: 1 / 1.x / ^1.0.4
- メジャーリリースの範囲指定: * / x
詳しくは、このエントリの最後の後半で説明する。
演算子を用いて、更に細かく範囲指定することができる。これを、comparatorと呼ぶ。
- < 未満
- <= 以下
- > より大きい
- >= 以上
- = イコール(演算子の指定がなければ適応される)
例えば、>=1.2.7 は 1.2.7 / 1.2.8 / 2.5.3 / 1.3.9 に一致するが、1.2.6 / 1.1.0 には一致しない。
また、comparator はホワイトスペースで結合できる(comparator set)。範囲指定は、さらにこの comparator set を || で結合して示されることがある。
例えば、 >=1.2.7 <1.3.0 は 1.2.7 / 1.2.8 / 1.2.99 に一致するが、1.2.6 / 1.3.0 / 1.1.0 には一致しない。
1.2.7 || >=1.2.9 <2.0.0 は 1.2.7 / 1.2.9 / 1.4.6 には一致するが、 1.2.8 / 2.0.0には一致しない。
プレリリースタグ (Prerelease Tags)
もし、バージョンがプレリリースタグ(e.g. 1.2.3-alpha.3)を持っていれば、同じ [major, minor, patch] で、プレリリースタグを持つ comparator しか、指定できない。
例えば、 >1.2.3-alpha.3 は 1.2.3-alpha.7 に一致するが、 3.4.5-alpha.9 には、一致しない。この場合、バージョンの範囲指定は、1.2.3のプレリリースタグにのみ適応される。3.4.5はプレリリースタグを持たず、1.2.3-alpha.3 より大きいので、これは条件を満たす。
こうした振る舞いには2つの理由があり、ひとつはプレリリースバージョンは頻繁に更新され、多くの前衛的変更を含む。従って、デフォルトでは範囲指定から外されている。
また、プレリリースバージョンを使用することを選んだユーザーは、特定の alpha/beta/rc バージョンを使用する意思をはっきりと示すことができる。範囲指定にプレリリースタグを含めることで、ユーザーはそれを使用することのリスクを自覚していることを示している。
更に詳しく
Hyphen Rangees X.Y.Z - A.B.C
以上/以下の範囲指定:
- 1.2.3 - 2.3.4 := >=1.2.3 <=2.3.4
最初と最後を含めて範囲指定する。欠けているものがあれば、0が代わりに使われる。
- 1.2 - 2.3.4 := >=1.2.0 <=2.3.4
- 1.2.3 - 2 := >=1.2.3 <3.0.0
X-Ranges 1.2.x / 1.x / 1.2.* /*
X / x / * はあらゆる数字の代わりになる。
- * := >=0.0.0 (すべてのバージョン)
- 1.x := >=1.0.0 <2.0.0 (メジャーバージョンの範囲指定)
- 1.2.x := >=1.2.0 <1.3.0 (メジャーバージョン、マイナーバージョンの範囲指定)
Tilde Ranges ~1.2.3 / ~1.2 / ~1
Tilde rangesでは、comparator 上でマイナーバージョンを指定していれば、パッチレベルの変更は許容される。
- ~1.2.3 := >=1.2.3 <1.(2+1).0 := >=1.2.3 <1.3.0
- ~1.2 := >=1.2.0 <1.(2+1).0 := >=1.2.0 <1.3.0 (Same as 1.2.x)
- ~1 := >=1.0.0 <(1+1).0.0 := >=1.0.0 <2.0.0 (Same as 1.x)
- ~0.2.3 := >=0.2.3 <0.(2+1).0 := >=0.2.3 <0.3.0
- ~0.2 := >=0.2.0 <0.(2+1).0 := >=0.2.0 <0.3.0 (Same as 0.2.x)
- ~0 := >=0.0.0 <(0+1).0.0 := >=0.0.0 <1.0.0 (Same as 0.x)
- ~1.2.3-beta.2 := >=1.2.3-beta.2 <1.3.0 (プレリリースタグの範囲指定は 1.2.3 上でのみ適応される)
Caret Ranges ^1.2.3 / ^0.2.5 / ^0.0.4
Caret ranges ではパッチとマイナーチェンジは許容される。
Caret ranges は 0.2.4 と 3.0.0 の間にブレイキングチェンジ(既存の機能の削除など後方互換性のない変更)があることを想定している。しかし、 0.2.4 と 0.2.5 の間にブレイキングチェンジが絶対にないと想定していることに注意する。
- ^1.2.3 := >=1.2.3 <2.0.0
- ^0.2.3 := >=0.2.3 <0.3.0
- ^0.0.3 := >=0.0.3 <0.0.4
- ^1.2.3-beta.2 := >=1.2.3-beta.2 <2.0.0
- ^0.0.3-beta := >=0.0.3-beta <0.0.4
欠けている patch や minor の値は 0 とみなし、それ以上のバージョンのパッチやマイナーの変更を許容する。
- ^1.2.x := >=1.2.0 <2.0.0
- ^0.0.x := >=0.0.0 <0.1.0
- ^0.0 := >=0.0.0 <0.1.0
- ^1.x := >=1.0.0 <2.0.0
- ^0.x := >=0.0.0 <1.0.0
ブラウザでマルコフ連鎖を用いた文章を要約できる要約器を作った
ブラウザでマルコフ連鎖を用いた文章を要約できる要約器を作った
作ったもの
ブラウザでマルコフ連鎖(Website)
hubotでマルコフ連鎖(Twitter)
hubotはこんな感じのことを10分毎にツイートしている。
使用したもの
今回、要約器や要約スクリプトを作成するにあたって、markov-chain-kuromojiを作成した。
kuromoji.jsは、mecabと違ってJavaScriptのみで記述されているので、hubotへの組み込みが容易。
ソースコード
hubotのスクリプトは次の通り
cronJob = require('cron').CronJob MarkovChain = require('markov-chain-kuromoji') Twit = require 'twit' client = new Twit({ consumer_key: process.env.HUBOT_TWITTER_KEY consumer_secret: process.env.HUBOT_TWITTER_SECRET access_token: process.env.HUBOT_TWITTER_TOKEN access_token_secret: process.env.HUBOT_TWITTER_TOKEN_SECRET }) module.exports = (robot) -> cronjob = new cronJob( cronTime: "00 00,10,20,30,40,50 * * * *" start: true timeZone: "Asia/Tokyo" onTick: -> client.get 'statuses/home_timeline', {count: 200}, (err, tweets, response) => if !err input = null for i in tweets input += "#{i.text}。" input = input.replace /。。/g, '。' input = input.replace /(https?:\/\/[\x21-\x7e]+)/g, '' input = input.replace /(@[\x21-\x7e]+)/g, '' input = input.replace /\s*/g, '' markov = new MarkovChain(input) markov.start(1, (output) => robot.send {room:'Twitter'}, "#{output}" ) else console.log err )
hubotの作成手順はこちら
- node-cron : 10分ごとにツイートし、同時にホームライムラインのツイートの取得。15分に15回程度だったと思うが、TwitterAPIの制限[rate limit exceeded]に引っかかるかもしれないので適度に取得回数を調節する。
- twit : ホームタイムラインのツイートを最大200件取得できる。
あとは適当に要らない記号等を正規表現で取り除いて、マルコフ連鎖モジュールで要約している。
タイムラインから取得したツイートやマルコフ連鎖モジュール内の要約用の辞書をデータベースに保存すれば、もっといろいろな文章ができそう。
Hubotでビットコインbotを作る
参考: http://qiita.com/hkusu/items/36ce56f3df4e7a0937cb
今回作ったもの
自然言語処理 bot (@hubot_uraway) | Twitter
必要なもの
- Herokuのアカウントと基礎知識
- TwitterのBot用アカウント
- NPM
基本方針
- Herokuにデプロイ(無料枠だと24時間のうち6時間スリープしてしまう)
- リフォローする
- 定期的にツイートする
- リプライに返信する
こんな感じのbotを作ります。
Hubotジェネレーター
npmでインストールします。
$ npm install -g generator-hubot
Hubotの雛形を作成。
$ yo hubot ? Owner: ? Bot name: ? Description: ? Bot adapter: twitter-userstream
一旦Hubotを起動して、動作を確認しよう
$ ./bin/hubot hubot> hubot ping hubot> PONG
Twitterアプリケーションの登録
Bot用のアカウントを取得後、ログインしたまま https://apps.twitter.com/ にアクセスして、アプリケーションを登録し、次の情報を控えておきます。
- Consumer Key (API Key)
- Consumer Secret (API Secret)
- Access Token
- Access Token Secret
ローカルで動作させる
Hubot起動スクリプトを作成します。
local_run.sh
#!/bin/sh export HUBOT_TWITTER_KEY="key" export HUBOT_TWITTER_SECRET="key_secret" export HUBOT_TWITTER_TOKEN="token" export HUBOT_TWITTER_TOKEN_SECRET="token_secret" export HUBOT_NAME = "hubotのスクリーンネーム" bin/hubot -a twitter-userstream
起動スクリプトに実行権限を付与して、実行します。
$ chmod +x local_run.sh $ ./local_run.sh
実行中はTwitter Hubotが常に起動しています。botスクリプトに変更を加えた時の確認に便利です。
Herokuにデプロイ
先ほどのlocal_run.sh
と同じ立ち上げ方をHeroku上で出来るようにしましょう。
Procfile
web: bin/hubot -a twitter-userstream
gitでコミットします。トークン等を記載しているので、local_run.sh
をコミットしないように注意しましょう。
$ git init $ git add . $ git commit -m "firs comment"
Herokuへプッシュします。
$ heroku create $ git push heroku master
アプリケーションのページを確認します。エラーが出ているはずです。
$ heroku open
環境変数を追加してから、もう一度$ heroku open
して、エラーが出ていなければ、Twitterで動作を確認しましょう。
$ heroku config:add HUBOT_TWITTER_KEY="key" $ heroku config:add HUBOT_TWITTER_SECRET="secret" $ heroku config:add HUBOT_TWITTER_TOKEN="token" $ heroku config:add HUBOT_TWITTER_TOKEN_SECRET="token_secret" $ heroku config:add HUBOT_NAME="hubotのスクリーンネーム"
このような表記であれば、Hubotは動作しています。
Botを作成する
scriptsディレクトリにスクリプトを記述したファイルを作成すれば、自動で読み取ってくれます。
次のことを実行するスクリプトを記述します。
- リフォローする
- 定期的にツイートする
- リプライに返信する
リフォローする
Botをフォローしたユーザーをフォローし返すには、twitter-userstream が提供する followed イベントを使用します。
module.exports = (robot) -> robot.on 'followed', (event) -> robot.logger.info "followed #{event.user.name}!" robot.adapter.join event.user
定期的にツイートする
定期的にツイートするには node-cron を利用します。今回は node-zaif を使って取得したビットコインのlast_price(終値)をツイートするスクリプトを記述します。
cronJob = require('cron').CronJob zaif = require('zaif.jp') publicApi = zaif.PublicApi module.exports = (robot) -> cronjob = new cronJob( # 実行する時間。今回は10分毎 cronTime: "00 00,10,20,30,40,50 * * * *" # 自動発火するかどうか start: true # タイムゾーン timeZone: "Asia/Tokyo" # cronが実行する関数 onTick: -> publicApi.lastPrice('btc_jpy') .then (res) -> robot.send {room: 'Twitter'}, "1 BTC = #{res.last_price} JPY" .catch (e) -> robot.send {room: 'Twitter'}, "ERROR: #{e}" )
詳しくはそれぞれのドキュメントで。
リプライに返信する
便利なAPIが用意されているので、一度目を通す。正規表現でリプライの内容を取得できる。
module.exports = (robot) -> # 「おみくじ」リプライを受け取ると、結果をランダムにツイートする robot.respond /おみくじ/i, (msg) -> msg.send msg.random ["大吉", "中吉", "小吉", "凶"] # タイムラインに「疲れた」が流れると、「頑張って」とツイートする robot.hear /疲れた/i, (msg) -> msg.send "頑張って!" # 「x BTC」リプライを受けると、JPYを計算して結果を対象ユーザーに返信する robot.respond /(.*) BTC/i, (res) -> btc = res.match[1] publicApi.lastPrice('btc_jpy') .then (response) -> jpy = btc*response.last_price res.reply "#{btc} BTC = #{jpy} JPY" .catch (e) -> res.reply "ERROR: #{e}" 「x JPY」リプライを受けると、BTCを計算して対象ユーザーに返信する robot.respond /(.*) JPY/i, (res) -> jpy = res.match[1] publicApi.lastPrice('btc_jpy') .then (response) -> btc = jpy/response.last_price res.reply "#{jpy} JPY = #{btc} BTC" .catch (e) -> res.reply "ERROR: #{e}"
最後に
このBot、Herokuの無料枠だと問題がある。
説明にある通り無料枠だと、
- 30分間のアクセスがないとスリープ状態に
- 24時間のうち、必ず6時間はスリープ
ひとつ目の、アクセスに関してはcronやこれを使えば問題なさそうだが、ふたつ目の問題は有料版を使う以外に解決策がない。うーん...
ソースコード
自然言語処理 bot (@hubot_uraway) | Twitter
MITライセンス。終値や計算結果、このbotを利用したことによる損害の責任を保証しない。