at kaneshin

Free space for me.

【Git】コミットメッセージのスペルチェック

f:id:laplus-knsn:20161209000103p:plain

この記事は Git Advent Calendar 2016 - Qiita の8日目の記事です。

スペルチェッカー - aspell

スペルチェックをするために aspell というスペルチェッカーを使用します。

f:id:laplus-knsn:20161209000151j:plain

インストール on macOS

macOS では Homebrew 🍺 を使ってインストールします。

# To install aspell
$ brew install aspell

# make sure that the aspell has been installed.
$ which aspell
/usr/local/bin/aspell

インストール on Debian

Debian しか使っていないものでして…

# To install apell
$ apt-get install aspell -y

# make sure that the aspell has been installed.
$ which aspell
/usr/bin/aspell

使い方

list コマンドを使用して、STDIN から文字列を流します。

# Test (Typo beautifl)
$ echo What a beautifl sky | aspell list
beautifl

上の例では beautiful をわざとタイポしています。

Git フック

どのタイミングで検証をするかはやはり Git フックで対応することになりますが、pre-commit などのクライアントサイドフック はよくあるので今回はサーバーサイドフックを使用します。

サーバーサイドフック

サーバーサイドフックスクリプトは知らない人は結構いる気がします。GitHub で特定のブランチのフォースプッシュを禁じる設定があると思いますが、あれはサーバーサイドフックが設定されているからです。

クライアントサイドフックの他に、いくつかのサーバーサイドフックを使うこともできます。これは、システム管理者がプロジェクトのポリシーを強制させるために使うものです。これらのスクリプトは、サーバへのプッシュの前後に実行されます。pre フックをゼロ以外の値で終了させると、プッシュを却下してエラーメッセージをクライアントに返すことができます。つまり、プッシュに関するポリシーをここで設定することができるということです。

サーバーサイドフックには下記の3種類存在しています。

  • pre-receive
  • post-receive
  • update

pre-receive, post-receive フック

クライアントからのプッシュを処理するときに最初に実行されるスクリプトが pre-receive で、処理が終了した後に実行されるのが post- receiveです。スクリプトは、プッシュされた参照のリストを標準入力から受け取り、ゼロ以外の値で終了させるとプッシュが却下されます。post-receive フックについては処理の完了通知などに使うことができます。

update フック

update フックは pre-receive フックと似ていますが、pre-receive と違うのは複数のブランチへのプッシュがあったときにブランチ単位でそれぞれ一度ずつ実行されます。

スペルチェック方法

1. pre-receive

下記のスクリプトを .git/hooks/pre-receive に記述します。

#!/bin/sh

which aspell > /dev/null
if [ ! $? -eq 0 ] ; then
  exit 0
fi

while read oldrev newrev refname
do
  misspelled=`git log --format=%B -n 1 "$newrev" | aspell list`
  if [ -n "${misspelled}" ] ; then
    echo >&2 "Possible misspelled words in the commit message:"
    for e in $misspelled; do echo >&2 " - ${e}"; done
    exit 1
  fi
done

2. コミットメッセージ例

今回、下記のようなコミットメッセージを用意しました。beautiful をタイポしています。

$ git log
commit f4eb3de
Author: Shintaro Kaneko <kaneshin0120@gmail.com>
Date:   Thu Dec 8 14:03:37 2016 +0000

    Initial commit: What a beautifl sky

3. git push

下記のようにプッシュを行うと、メッセージとともにプッシュがリジェクトされます。

$ git push origin master 
Counting objects: 1, done. 
Writing objects: 100% (1/1), 190 bytes | 0 bytes/s, done. 
Total 1 (delta 0), reused 0 (delta 0) 
remote: Possible misspelled words in the commit message: 
remote:  - beautifl 
To /home/kaneshin/foo/rem 
 ! [remote rejected] master -> master (pre-receive hook declined) 
error: failed to push some refs to '/home/kaneshin/foo/rem' 

おわりに

pre-commit とかでは個人の環境に依ってしまうので、サーバーサイドフックでカバーできるところは積極的にカバーしていきたいものです。

たまに尾道

f:id:laplus-knsn:20160514155221j:plain

この記事はたまに広島 Advent Calendar 2016の6日目の記事です。

生活圏は東京都心に住んでいますが、広島の尾道は昔から気になっていて、今年、初めて訪れることができました。 気になっていた大きな理由として、大林宣彦監督の『ふたり』と小林俊彦先生の『ぱすてる』がとても好きだからです。

ちなみに、私はまだ28歳なので『ふたり』が好きなのは親の影響が大きいですね…同年代の友人で知ってる人は居ないですね…


ふたり

『ふたり』は、赤川次郎の小説。1989年1月新潮社刊。事故死してしまったしっかり者の姉と、姉に頼ってばかりいた妹との、奇妙な共同生活を温かくつづる。大島弓子がカバーイラストを手がけた。

ふたり - Wikipedia

大林宣彦監督が『新・尾道3部作』の第1作として1991年に劇場公開されています。私は VHS か Beta のどちらかで見た記憶があります。(20年くらい前)

上の動画にも出てきますが、『ふたり』で有名な電柱も探し出しました。

f:id:laplus-knsn:20161122015509j:plain

土堂小学校の付近の横道を少し先に進むと突然現れます。ここで撮影している人は絶対に『ふたり』好きでしょうね。

ぱすてる

『ぱすてる』 (Pastel) は小林俊彦によるラブコメディ漫画作品。2002年より『週刊少年マガジン』で連載を開始し、後に『マガジンSPECIAL』に掲載誌を移し、連載中。

ぱすてる - Wikipedia

『ぱすてる』を読んでから尾道に訪れると色々なところで「あ!ココ見たことある!」という状況になるので、是非、『ぱすてる』を読み込んでから訪問してもらいです。

f:id:laplus-knsn:20161122015517j:plain

f:id:laplus-knsn:20161122015523j:plain

新久千映

新久千映のまんぷく広島<ご当地グルメコミックエッセイ>

新久千映のまんぷく広島<ご当地グルメコミックエッセイ>

そういえば、他にも新久千映先生の書いている漫画も好きなので、この本を読むたびに色々と巡ってみたい気持ちになります。

尾道と広島

時間があれば積極的に訪れたいですし、厳島神社などのメジャーな観光地にも訪れたいので来年も数回旅行しようかと考えています。 どこかオススメのところがあれば教えてもらいたいです!

最適化理論とカーマーカー特許と歴史

f:id:laplus-knsn:20161207173200j:plain

この記事は 数学 Advent Calendar 2016 - Qiita の6日目の記事です。

大学生の頃、ORを専攻していたため最適化理論について登壇した経験があります。

時々は最適化理論のことを書いて、最適化理論をアピールしようかと思います。

単体法について

最適化理論についての概要を知りたい場合は先ほどのリンクにあるスライドや動画を参照することをオススメします。 さて、線形計画問題の解法の一つに Dantzig 教授によって提案された単体法(シンプレックス法)という有限回で最適解に到達するということが保証されたアルゴリズムが有名です。 有限回で最適解に到達するのが保証されている理由は、最適解が端点に現れることを利用しているためです。

単体法の問題点

有限回で最適解に到達することが保証されているのですが、制約式の本数が増えることによって計算時間が指数関数的に膨大になる可能性があります。

カーマーカー法について

単体法に対して、1984年にカーマーカー法の発表によって注目されるようになった内点法は大規模な線形計画問題をより効率的に解くことが期待されています。この内点法は制約領域の内部を通って最適解に近づく方法であり、その計算時間が多項式オーダーに留まることが理論的に保証されています。

カーマーカー特許の概要

このカーマーカー法は優れているのですが、カーマーカーはカーマーカー特許として線形計画法の解法に関する特許を取得しています。このカーマーカー特許はアルゴリズム特許の代表例で、カーマーカーと米国のAT&T社がその特許を取得し、当時は「アルゴリズムが特許となり得るのか」といった社会問題となって物議を醸したことでOR界隈では有名になっています。

カーマーカー法の歴史

出来事 詳細
1985 カーマーカー特許申請(米) カーマーカーとAT&Tが数学理論(数式)の特許を申請。アメリカは先発明主義のため顕在化せず。
1986 カーマーカー特許申請(日) カーマーカー氏とAT&Tが日本に特許申請。
1988 カーマーカー特許申請認可(米) 数学理論(数式)が始めて特許認定される。
1989 AT&TがKORBXを発売 アフィン変換法を用いたソフトを890万ドルで発売。
1990 XMPがOB1を発売 内点法を用いたソフトを5万ドルで発売。AT&TがXMPに対し、OB1はカーマーカー特許に抵触すると警告し、売上5%の特許使用料を支払うことで和解。
1991 カーマーカー特許申請拒絶(日) カーマーカー特許は計算手法そのものであるという理由で拒絶。これに対し、AT&Tは審判請求。
1993 カーマーカー関連特許申請公告(日) 1991年の請求により逆転審判。これに対し、異議申立てが出される。
1998 カーマーカー関連特許無効審判請求 無効審判の請求は成り立たないとの審決。は不成立との審決(日)
1999 カーマーカー関連特許無効審判請求 審判請求人が審決の取り消しを求める裁判を提起。不成立審決の取り消し要求裁判(日)

おわりに

数学やアルゴリズムは研究が積み重なることによって、改良されていく分野なのですが、特許として囲まれてしまうとその発展が閉ざされるのではないかと若干不安になります。

リソース

もっと詳しく知りたい方はこちらの書籍を参考にしてみてください。

今野浩,カーマーカー特許とソフトウエア,中公新書

カーマーカー特許とソフトウェア―数学は特許になるか (中公新書)

カーマーカー特許とソフトウェア―数学は特許になるか (中公新書)

伊庭 斉志,システム工学の基礎―システムのモデル化と制御,数理工学社

Firebase Remote Config for iOS

f:id:laplus-knsn:20161204223220j:plain

この記事は Firebase Advent Calendar 2016 - Qiita の4日目の記事です。

最近は Golang を用いたサーバサイド開発を専らの仕事としていますが、約2年前はガッツリと iOS アプリ開発を行っていました。そのときから「アプリの振る舞いや見た目、A/Bテストをサーバサイドでどうにかコントロールしたい」と思っていたので、今回はそれを満たすことのできる Firebase Remote Config について紹介しようと思います。

Firebase Remote Config とは

Firebase をご存知の方は多いと思いますが、Remote Config は Database, Storage と同じ立ち位置となる Firebase の一つのサービスです。この Remote Config が提供する機能は Firebase 上である値を定義し、その値を iOS、Android や Web のアプリ(主にクライアント)で取得し、使用することができます。ここでいう使用方法は実装者次第になりますが、設定した値に対してセグメントさせたユーザにのみ配信してA/Bテストに役立てたりします。 これによって、アプリ開発者が「開発〜検証〜リリース」という作業を行わずとも、アプリをアップデートすることができるようになります。 また、Firebase Analytics とも連携することができます。

開発

今回は iOS アプリでの開発で説明します。

0. Firebase on iOS

Add Firebase to your iOS Project」を読んでプロジェクトで Firebase を使用できる状態にします。

1. Xcode Project 作成

Xcode プロジェクトに Podfile ファイルがなければ pod init で作成し、下記のように Podfile に pod 'Firebase/RemoteConfig' を追加します。

target 'YourTargetName' do
  use_frameworks!

  pod 'Firebase/RemoteConfig'
end

追加したら pod install で RemoteConfig をインストールし、ワークスペース(.xcworkspaceファイル)を開いて開発を行います。

2. 実装

Firebase シングルトンの初期化

application:didFinishLaunchingWithOptions で Firebase を初期化します。

import UIKit
import Firebase

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        FIRApp.configure()
        return true
    }

}

Remote Config から値の取得

FIRRemtoeConfig.remoteConfig() でシングルトンインスタンスを呼び出し使用します。例えば、ボタンのタイトルを変更するためには下記のように実装します。

let appDefaults: [String: NSObject] = [
    "reaction_button_text" : "Like",
]
FIRRemoteConfig.remoteConfig().setDefaults(appDefaults)

let fetchDuration: TimeInterval = 0
FIRRemoteConfig.remoteConfig().fetch(withExpirationDuration: fetchDuration) { [weak self] (status, error) in

    guard error == nil else {
        return
    }
 
    FIRRemoteConfig.remoteConfig().activateFetched()

    let title = FIRRemoteConfig.remoteConfig()["reaction_button_text"].stringValue ?? "Like"
    self.button.setTitle(title, for: UIControlState.normal)
}

こうすることによって、 "reaction_button_text" を Remote Config の方に値を設定することによって、Firebase 上でボタンのタイトルを変更することが可能になります。仮に、Remote Config に値を設定しないか、通信状況が悪い場合などはデフォルトとして "Like" が表示されるようになります。

3. Remote Config に値を追加

Firebase のダッシュボードからプロジェクトを指定して、Remote Config に値を設定します。プロジェクトを作成していない場合は新規で作成するか、GCP のプロジェクトをインポートしましょう。

Remote Config は Firebase ダッシュボードの左パネルから選択ができます。

f:id:laplus-knsn:20161204223816p:plain

"ADD PARAMETER" で値を追加します。

f:id:laplus-knsn:20161204223848p:plain

値が追加完了したら "PUBLISH CHANGES" を押して、値を配信します。

f:id:laplus-knsn:20161204223859p:plain

これで "reaction_button_text" の値に "Favorite" が設定され、配信されるようになります。

おわりに

軽めに Firebase Remote Config の解説をしましたが、次はもう少し振る舞いを変更させる記事を書こうかなと思います。

golang で始める Slack bot 開発

f:id:laplus-knsn:20161203150907j:plain

この記事は Slack Advent Calendar 2016 - Qiita の3日目の記事です。

昨日は Kinoppyd さんの「今そこにあるSlack」でした。

さて、今回、この記事では golang で Slack bot を実装する方法を紹介しようと思います。

世に蔓延る Slack bot

f:id:laplus-knsn:20161203155008j:plain

これから bot を世に放とうとしている人は、是非、1日目と2日目の記事を読み、事前知識を頭に叩き込んでおくと良いと思います。

基本的に、自身で作成した bot はもちろん好きになると思いますが、人によっては理解不能な bot や、意味不明な場面で反応したりと、「邪魔だな」と思われてしまうことがあります。そのため、bot を開発する人は「謙虚・尊敬・信頼」(Team Geekより)を持った上で、世に放ちましょう。

golang で bot を開発

f:id:laplus-knsn:20161203155235p:plain

Golang の開発環境は整っているとします。

bot の新規作成

Slack の bot の仕様については下記のページに色々と書かれています。

api.slack.com

アプリケーションに統合された bot の開発も可能ですが、今回は簡単に実装するために Slack Bots からトークンを取得します。

Slack Bots の新規作成はこちらから作成ができ、下記のようなページで新規作成となります。

f:id:laplus-knsn:20161203154451p:plain

作成が完了すると、下記の画像の設定ページに遷移するので、ここにあるトークンを使用して bot を稼働させます。

f:id:laplus-knsn:20161203154501p:plain

実装

Go で開発をすすめます。 今回、簡単に Slack API 連携するために github.com/nlopes/slack を先に go get しておきます。

$ go get -u github.com/nlopes/slack

コード全体

package main

import (
    "log"
    "os"

    "github.com/nlopes/slack"
)

func run(api *slack.Client) int {
    rtm := api.NewRTM()
    go rtm.ManageConnection()

    for {
        select {
        case msg := <-rtm.IncomingEvents:
            switch ev := msg.Data.(type) {
            case *slack.HelloEvent:
                log.Print("Hello Event")

            case *slack.MessageEvent:
                log.Printf("Message: %v\n", ev)
                rtm.SendMessage(rtm.NewOutgoingMessage("Hello world", ev.Channel))

            case *slack.InvalidAuthEvent:
                log.Print("Invalid credentials")
                return 1

            }
        }
    }
}

func main() {
    api := slack.New("[YOUR-API-TOKEN]")
    os.Exit(run(api))
}

順を追って解説します。

slack.Client の生成

func main() {
    api := slack.New("[YOUR-API-TOKEN]")
    os.Exit(run(api))
}

slack.New 関数に先ほど取得したAPIトークンを渡して、 slack.Client を生成します。これは Slack API のクライアントになるので、bot 以外でももちろん API を叩くことが可能になります。

api := slack.New("[YOUR-API-TOKEN]")

Real Time Messaging API

func run(api *slack.Client) int {
    rtm := api.NewRTM()
    go rtm.ManageConnection()

    for {
        select {
        case msg := <-rtm.IncomingEvents:
            switch ev := msg.Data.(type) {
            case *slack.HelloEvent:
                log.Print("Hello Event")

            case *slack.MessageEvent:
                log.Printf("Message: %v\n", ev)
                rtm.SendMessage(rtm.NewOutgoingMessage("Hello world", ev.Channel))

            case *slack.InvalidAuthEvent:
                log.Print("Invalid credentials")
                return 1

            }
        }
    }
}

Real Time Messaging を使用して、 Websocket から情報を取得します。

rtm := api.NewRTM()
go rtm.ManageConnection()

コネクションを張り次第、ひたすらループして情報を取得します。情報はチャネルの IncomingEvents に enqueue されるので、それを dequeue して型によって振る舞いを変えます。

for {
    select {
    case msg := <-rtm.IncomingEvents:
        switch ev := msg.Data.(type) {
        case *slack.HelloEvent:
            log.Print("Hello Event")

        case *slack.MessageEvent:
            log.Printf("Message: %v\n", ev)
            rtm.SendMessage(rtm.NewOutgoingMessage("Hello world", ev.Channel))

        }
    }
}

今回の例では誰かがこの bot が招待されているチャネルに投稿すると、slack.MessageEvent が発火して、 "Hello world" をそのチャネルに投稿しています。

rtm.SendMessage(rtm.NewOutgoingMessage("Hello world", ev.Channel))

実行

上に記述したコードを main.go という名前で実装していると仮定すると。

$ cd /path/to/slack-bot
$ go run main.go
2016/12/03 06:32:53 Hello Event
2016/12/03 06:32:53 Message: &{{message XX XX Hello world 1480746760.000010 false [] [] <nil>  false     <nil>      [] <nil> false <nil>  1  []} <nil>}

のように出力されれば動いています。

デーモン化

bot が死んでいたら悲しいので、デーモン化をちゃちゃっとしちゃいます。

まず、作成した bot をコンパイルしてバイナリにしておきます。

$ go build -o /path/to/bot main.go

次に、デーモン化ですが、今回は supervisor での例を載せておきます。

[program:bot]
command=/path/to/bot
user=someone
autostart=true
autorestart=true
stderr_logfile=/var/log/bot.err.log
stdout_logfile=/var/log/bot.out.log

上記を conf に用意して、 supervisord を再起動させましょう。これでデーモン化された bot の完成です。

おわりに

慣れている言語でちゃちゃっと bot は実装したいと思うので、各言語での bot 実装法はもっと出回っていいのではと思っています。最近、 Crystal にハマっているので、今度機会があれば Crystal バージョンを書こうと思います。