読者です 読者をやめる 読者になる 読者になる

DRYな備忘録

Don't Repeat Yourself.

個人開発程度のOCRサーバならHerokuに立てればいいじゃない

go heroku

このエントリはGo (その2) Advent Calendar 2016 - Qiitaの5日目です。
WETな方でもお世話になっております、otiai10です。

とある個人開発が、もうかれこれ3年ぐらい続いているんですが、ブラウザ上に描画されたちょっとしたテキストをOCR(文字認識)する要件があって、それをずっとさくらVPSPythonでやってましたが、3年もやってると、他の個人開発だったりとか、副業だったりとかでサーバリソースを一緒にしたくないなあ、っていうことが発生してきて、しかもべつに広告とかアフィとかで報酬が発生するタイプの個人開発でもないので、なんで俺が身を削って維持せなあかんねんという気持ちにもなったので、いいかげん、無料でOCRサーバ立てるのをやりました。Goで。Go好きなので。

tl;dr

Deploy

これ押したらもう立ちます。

特徴

  1. Google Cloud Vision API のように自由画像から文字座標を検出したりしない
    • 位置と矩形が確定している場合の文字認識に適してます
  2. Google Cloud Vision API では指定できないchar_whitelist(検出文字制限)ができる
    • 想定される文字が限られている場合に適しています
  3. 無料 ← つよい

みなさんバンバン自分のOCRサーバインスタンスを立てて、レシートを読むなり、アイドルのスタミナ回復時間を読むなりしてください。

やったことその1: GoでC++のライブラリを叩く

Goはcgoっていうのがあって、GoからC/C++C/C++からGoを呼べたりするんですけど、これを使って既存の光学文字認識ライブラリであるTesseract-OCRを呼んでます。

GitHub - otiai10/gosseract: Golang OCR library, wrapping Tesseract-ocr

例。includeしているtess.hは自作のヘッダファイルで、cppファイルが実際にTesseract-OCRを叩いてます。このGoファイルをビルドすると、C/C++のライブラリにリンクされた実行ファイルが手に入る、という寸法です。

package tesseract

/*
#cgo LDFLAGS: -llept -ltesseract
#include "tess.h"
*/
import "C"

// Simple executes tesseract only with source image file path.
func Simple(imgPath string, whitelist string,languages string) string {
    p := C.CString(imgPath)
    w := C.CString(whitelist)
    l := C.CString(languages)

    s := C.simple(p, w,l)
    return C.GoString(s)
}

やったことその2: せっかくなのでWAFっぽいものをつくる

僕がGoの好きなところのひとつは、DIY(Do It Yourself)感がすごいところで、始めやすいし、Write&Runが手軽だし、標準ライブラリが簡潔かつ充実してるし、釘一本からチェーンソーまであって、隅にはペットコーナーすらある的な、ホームセンターみたいな雰囲気が好きです。

ということで、最低限よくやるルーティングと、あとHTTPのフィルタリングあたりをやる小さなツールキットをつくりました。

GitHub - otiai10/marmoset: The very minimum web framework for Golang

func main() {
    router := marmoset.NewRouter()
    router.GET("/hello", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("hello!"))
    })
    http.ListenAndServe(":8080", router)
}

Viewのレンダリングもやるんですけど、なんかHerokuで動かなくて、アドベントカレンダー的に合わなかったのでocrserver側ではdirty hackしてます…

やったことその3: 1と2を、Uh…!合わせる

PPAPの画像をコラって貼りたいと思ったんだけど、ライセンスフィルタ付きで画像検索したら1個も無えの。

marmosetで小さいサーバをつくって、gosseractでOCRするところをやったのが、こちらになります。

github.com

やったことその4: Herokuデプロイできるようにする

なんかHerokuはbuildpackっていうのがあって、言うなればUbuntuベースのCedarっていうイメージをベースに、自分で好きな拡張をしていけるようになってるっぽい。

上記のgoseractは当然、GoのコンパイルにはTesseract-OCRのヘッダファイル/共有オブジェクトファイルが必要なので、これをHerokuインスタンスに配置して、サーバアプリケーションが立つときに参照できるようにしてやらないといけないんだけど、どうしようかな、と思ってたら直でaptitudeが使えるマジ神なbuildpackがあったので一発解決しました。

これがたぶん今回のミソでした。Tesseract-OCR叩くパッケージにも、webのツールキットにも、OCRサーバのUIにもまだまだTODOが多いので、使いながらブラシアップしていきたいです。

まとめ

Deploy ← これ押したらあなたのOCRサーバがもう立ちます。無料で。

個人開発、いいですよね。知らない技術に触れるチャンスになるので。

追記

現場からは以上です。

Dockerでホストのファイルをコンテナに持って行くメモ

docker

というか、マウントである。

メモ

まず入って出れることだけ確認。--rmで終了時にコンテナも抹消する。

% uname
Darwin
% docker run -i -t --rm library/ubuntu
root@7f3902552705:/# uname
Linux
root@7f3902552705:/# exit
exit
% docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
%

適当にホストにおいてファイルつくる。

% echo "田井中律は俺の嫁" > hoge.txt

カレントディレクトリをコンテナ内における/dataかなんかにマウントしつつコンテナを立ち上げる

% docker run -v `pwd`:/data -i -t --rm library/ubuntu
root@d02c8d9170a1:/# ll /data/
drwxr-xr-x  1 1000 staff      374 Dec  3 08:45 ./
drwxr-xr-x 35 root root      4096 Dec  3 08:47 ../
-rw-r--r--  1 1000 staff       25 Dec  3 08:42 hoge.txt
root@d02c8d9170a1:/# cat /data/hoge.txt
田井中律は俺の嫁
root@d02c8d9170a1:/# exit
exit
%

できた。 {ホスト内ファイルパス}:{コンテナ内ファイルパス}

DRY

UITableViewの左にある謎の余白を消したい

swift

やることは3つ

  1. UITableViewのseparatorInsetをゼロにする
    • これはインターフェースビルダーからでも変更可能
  2. UITableViewCellのlayoutMarginsをゼロにする
  3. UITableViewCellのpreservesSuperviewLayoutMarginsを無効にする
func viewDidLoad() {
    super.viewDidLoad()

    // 1) TableViewのinsetをゼロにする
    reasonsTable.separatorInset = UIEdgeInsetsZero
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = UITableViewCell()

    // 2) 自分自身のmarginをゼロにする
    cell.layoutMargins = UIEdgeInsetsZero
    // 3) superviewからmarginを引き継がない
    cell.preservesSuperviewLayoutMargins = false

    cell.textLabel?.textAlignment = .Center
    cell.textLabel?.text = self.reasons[indexPath.row].germanText
    return cell
}

Tesseract-OCRをソースからコンパイルする

tesseract-ocr

コンパイルして、共有ライブラリとして読み込まれる.soファイルをつくれることを確認したい。APIファイル(.hとか)はReleases · tesseract-ocr/tesseract · GitHubを解凍すれば同梱されてる。ついでに同環境下でそのTesseract-OCRがちゃんと動くことも確認したい。

事前準備: Dockerで雑に使い捨て開発環境つくる個人的なメモ - DRYな備忘録

参考

ログ

root@f456604ccbed:/# cd
root@f456604ccbed:~# mkdir workspace && cd workspace
root@f456604ccbed:~/workspace#
root@f456604ccbed:~/workspace# wget https://github.com/tesseract-ocr/tesseract/archive/3.04.01.tar.gz
root@f456604ccbed:~/workspace# tar -zxvf 3.04.01.tar.gz
root@f456604ccbed:~/workspace# cd tesseract-3.04.01/
root@f456604ccbed:~/workspace/tesseract-3.04.01#
root@f456604ccbed:~/workspace/tesseract-3.04.01# ./autogen.sh
Running aclocal
./autogen.sh: 60: ./autogen.sh: aclocal: not found

  Something went wrong, bailing out!

root@f456604ccbed:~/workspace/tesseract-3.04.01# apt-get install -y autotools-dev
root@f456604ccbed:~/workspace/tesseract-3.04.01# apt-get install -y automake
root@f456604ccbed:~/workspace/tesseract-3.04.01# ./autogen.sh
Running aclocal
Running libtoolize
./autogen.sh: 65: ./autogen.sh: libtoolize: not found
./autogen.sh: 65: ./autogen.sh: glibtoolize: not found

  Something went wrong, bailing out!

root@f456604ccbed:~/workspace/tesseract-3.04.01# apt-get install -y build-essential libtool
root@f456604ccbed:~/workspace/tesseract-3.04.01# ./autogen.sh
Running aclocal
Running libtoolize
libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, `config`.
libtoolize: copying file `config/ltmain.sh`
libtoolize: putting macros in AC_CONFIG_MACRO_DIR, `m4`.
libtoolize: copying file `m4/libtool.m4`
libtoolize: copying file `m4/ltoptions.m4`
libtoolize: copying file `m4/ltsugar.m4`
libtoolize: copying file `m4/ltversion.m4`
libtoolize: copying file `m4/lt~obsolete.m4`
Running autoheader
Running automake --add-missing --copy
configure.ac:321: installing 'config/compile'
Running autoconf

All done.
To build the software now, do something like:

$ ./configure [--enable-debug] [...other options]
root@f456604ccbed:~/workspace/tesseract-3.04.01#

autogen.shの成功

root@f456604ccbed:~/workspace/tesseract-3.04.01# ./configure
# 中略
checking for leptonica... configure: error: leptonica not found
root@f456604ccbed:~/workspace/tesseract-3.04.01# cd ..
root@f456604ccbed:~/workspace# wget https://github.com/DanBloomberg/leptonica/archive/v1.73.tar.gz
root@f456604ccbed:~/workspace# tar -zxvf v1.73.tar.gz
root@f456604ccbed:~/workspace# cd leptonica-1.73/
root@f456604ccbed:~/workspace/leptonica-1.73# ./configure
bash: ./configure: Permission denied
root@f456604ccbed:~/workspace/leptonica-1.73# chmod 755 ./configure
root@f456604ccbed:~/workspace/leptonica-1.73#
root@f456604ccbed:~/workspace/leptonica-1.73# ./configure
root@f456604ccbed:~/workspace/leptonica-1.73# make

root@f456604ccbed:~/workspace/leptonica-1.73# make install
Making install in src
make[1]: Entering directory '/root/workspace/leptonica-1.73/src'
make[2]: Entering directory '/root/workspace/leptonica-1.73/src'
test -z "/usr/local/lib" || /bin/mkdir -p "/usr/local/lib"
# 中略
----------------------------------------------------------------------
Libraries have been installed in:
   /usr/local/lib

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR`
flag during linking and do at least one of the following:
   - add LIBDIR to the `LD_LIBRARY_PATH` environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH` environment variable
     during linking
   - use the `-Wl,-rpath -Wl,LIBDIR` linker flag
   - have your system administrator add LIBDIR to `/etc/ld.so.conf`

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
# 後略
root@f456604ccbed:~/workspace/leptonica-1.73# ls -l /usr/local/lib/
total 22156
-rw-r--r-- 1 root staff 14116202 Nov  6 20:35 liblept.a
-rwxr-xr-x 1 root staff      943 Nov  6 20:35 liblept.la
lrwxrwxrwx 1 root staff       16 Nov  6 20:35 liblept.so -> liblept.so.5.0.0
lrwxrwxrwx 1 root staff       16 Nov  6 20:35 liblept.so.5 -> liblept.so.5.0.0
-rwxr-xr-x 1 root staff  8559120 Nov  6 20:35 liblept.so.5.0.0
drwxr-sr-x 2 root staff     4096 Nov  6 20:35 pkgconfig
root@f456604ccbed:~/workspace/leptonica-1.73#

leptonicaのコンパイルは完了

root@f456604ccbed:~/workspace/leptonica-1.73# cd ../tesseract-3.04.01/
root@f456604ccbed:~/workspace/tesseract-3.04.01# export LIBLEPT_HEADERSDIR=/root/workspace/leptonica-1.73/src
root@f456604ccbed:~/workspace/tesseract-3.04.01# ./configure
# 中略

Configuration is done.
You can now build and install tesseract by running:

$ make
$ sudo make install

You can not build training tools because of missing dependency.
Check configure output for details.

training toolsがうんちゃらと言っているものの、tesseractのconfigureは完了

root@f456604ccbed:~/workspace/tesseract-3.04.01# make
root@f456604ccbed:~/workspace/tesseract-3.04.01# make install
# 中略
----------------------------------------------------------------------
Libraries have been installed in:
   /usr/local/lib

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR`
flag during linking and do at least one of the following:
   - add LIBDIR to the `LD_LIBRARY_PATH` environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH` environment variable
     during linking
   - use the `-Wl,-rpath -Wl,LIBDIR` linker flag
   - have your system administrator add LIBDIR to `/etc/ld.so.conf`

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------

tesseractのmake, make installも完了。確認する

root@f456604ccbed:~/workspace/tesseract-3.04.01# cd
root@f456604ccbed:~# ls -l /usr/local/lib/
total 137364
-rw-r--r-- 1 root staff 14116202 Nov  6 20:35 liblept.a
-rwxr-xr-x 1 root staff      943 Nov  6 20:35 liblept.la
lrwxrwxrwx 1 root staff       16 Nov  6 20:35 liblept.so -> liblept.so.5.0.0
lrwxrwxrwx 1 root staff       16 Nov  6 20:35 liblept.so.5 -> liblept.so.5.0.0
-rwxr-xr-x 1 root staff  8559120 Nov  6 20:35 liblept.so.5.0.0
-rw-r--r-- 1 root staff 87030250 Nov  6 20:45 libtesseract.a
-rwxr-xr-x 1 root staff      987 Nov  6 20:45 libtesseract.la
lrwxrwxrwx 1 root staff       21 Nov  6 20:45 libtesseract.so -> libtesseract.so.3.0.4
lrwxrwxrwx 1 root staff       21 Nov  6 20:45 libtesseract.so.3 -> libtesseract.so.3.0.4
-rwxr-xr-x 1 root staff 30937064 Nov  6 20:45 libtesseract.so.3.0.4
drwxr-sr-x 2 root staff     4096 Nov  6 20:45 pkgconfig
root@f456604ccbed:~# which tesseract
/usr/local/bin/tesseract
root@f456604ccbed:~#

まあたぶんtraineddataが無いのでtesseractコマンド自体は失敗すると予想される。今回の目的は「OSのパッケージマネージャを使わず、tesseract/leptonicaのヘッダファイルとコンパイル済み.soファイルの入手」だったので、とりあえず目的達成できたと思う。

番外: tesseractコマンドの挙動確認

root@f456604ccbed:~# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
root@f456604ccbed:~# tesseract --list-langs
Error opening data file /usr/local/share/tessdata/eng.traineddata
Please make sure the TESSDATA_PREFIX environment variable is set to the parent directory of your "tessdata" directory.
Failed loading language 'eng'
Tesseract could not load any languages!
Could not initialize tesseract.
root@f456604ccbed:~#

予想通り、eng.traineddataが無いと言われる。

root@f456604ccbed:~# mkdir -p data/tessdata
root@f456604ccbed:~# wget https://github.com/tesseract-ocr/tessdata/blob/master/eng.traineddata?raw=true
root@f456604ccbed:~# pwd
/root
root@f456604ccbed:~# mv eng.traineddata\?raw\=true /root/data/tessdata/eng.traineddata
root@f456604ccbed:~# export TESSDATA_PREFIX=/root/data
root@f456604ccbed:~# tesseract --list-langs
List of available languages (1):
eng
root@f456604ccbed:~#

traineddataの配置と認識確認できた。

root@f456604ccbed:~# cd
root@f456604ccbed:~# wget https://cloud.githubusercontent.com/assets/931554/20041852/bda107d4-a46f-11e6-8c49-6d022007e445.jpg -O sample.jpg
root@f456604ccbed:~# tesseract sample.jpg stdout
Error in pixReadMemJpeg: function not present
Error in pixReadMem: jpeg: no pix returned
Error during processing.
root@f456604ccbed:~#

むむ。

stackoverflow.com

Leptonicaを入れる前にlibjpegを入れる必要があったっぽい。このへんでもう別コンテナで仕切り直したいな、という気持ちがある。

root@f456604ccbed:~# cd /root/workspace/
root@f456604ccbed:~/workspace# wget https://github.com/LuaDist/libjpeg/archive/8.4.0.tar.gz
root@f456604ccbed:~/workspace# tar -zxvf 8.4.0.tar.gz
root@f456604ccbed:~/workspace# cd libjpeg-8.4.0
root@f456604ccbed:~/workspace/libjpeg-8.4.0# configure
root@f456604ccbed:~/workspace/libjpeg-8.4.0# make
root@f456604ccbed:~/workspace/libjpeg-8.4.0# make install
# 中略
----------------------------------------------------------------------
Libraries have been installed in:
   /usr/local/lib

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR`
flag during linking and do at least one of the following:
   - add LIBDIR to the `LD_LIBRARY_PATH` environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH` environment variable
     during linking
   - use the `-Wl,-rpath -Wl,LIBDIR` linker flag
   - have your system administrator add LIBDIR to `/etc/ld.so.conf`

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------

で、もっかいleptonicaのmakeをする

root@f456604ccbed:~# cd /root/workspace/leptonica-1.7
root@f456604ccbed:~/workspace/leptonica-1.73# ./configure
root@f456604ccbed:~/workspace/leptonica-1.73# make
root@f456604ccbed:~/workspace/leptonica-1.73# make install

これでどうや

root@f456604ccbed:~/workspace/leptonica-1.73# cd
root@f456604ccbed:~# tesseract sample.jpg stdout
Error in pixGenHalftoneMask: pix too small: w = 173, h = 64
otiai’lO / gosseract

root@f456604ccbed:~#

f:id:otiai10:20161107062656j:plain

これが

f:id:otiai10:20161107062807p:plain

よっしゃ!

これで、OSのパッケージマネージャを使わず、make/make installでTesseract-OCRが動く環境を確認できた。

DRYな備忘録として

Dockerで雑に使い捨て開発環境つくる個人的なメモ

docker

たとえば、Macでdocker-machine使ってて、debianの環境が手っ取り早くほしい。

% docker-machine create -d virtualbox foobar
% eval $(docker-machine env foobar)
% docker run -i -t --rm library/debian
  • -i -t この端末のstdin/stdoutでsshする
  • --rm コンテナ終了時に完全削除もする

んで、たぶん必要になるやつ

root@f456604ccbed:/# apt-get -qq update # これ必要
root@f456604ccbed:/# apt-get install wget # とかするために

DRYな備忘録として

herokuで自作buildpackを作った時に得た知見

heroku go

かつてこれ↓を書いたときからまたHerokuは状況が変わってて、

otiai10.hatenablog.com

今では、buildpackっていう、いうなればインスタンスの初期化スクリプトみたいなのを定義できるっぽい。そこで依存するパッケージのインストール(に相当すること)も可能っぽい。

今回の最終目標は「Goが動いて、なおかつtesseract-ocrC++バイナリとヘッダファイルがある環境をつくる」なのだけれど、まずはミニマムなherokuのbuildpackを自作してみようということになりました。

ゴール

  • HerokuでGoのアプリケーションが動く
  • 自作buildpackにおいて定義した環境変数にGoのアプリケーションがアクセスできる

tl;dr

  1. [heroku/go] 依存パッケージはGodepsなどで管理されている必要がある
  2. [heroku] app.jsonはどうやらDeploy to Herokuボタンなどの時に必要なのであって、heroku createとpushでは用いられない
    1. したがって、heroku createでbuildpackを検証するには別途heroku buildpacks:addなどを用いる必要がある
  3. [heroku-buildpack] buildpacksのフォーマットは、detect,compile,releaseの3段階(物理的にはファイル)を満たしていればよい
    1. detectexit 0
    2. compileは出力に制限は無い
    3. releaseはvalidなyaml形式の出力を標準出力に吐く必要がある
  4. [heroku-buildpack] buildpackのdetect/compile/releaseはあるものの、環境変数を吐くスクリプト.profile.d/*.shであり、compileなどで.profile.d/foo.shexportなどを書き込んでやる必要がある

まず簡単なGoのサーバアプリケーションを作る

package main

import (
    "net/http"
    "os"

    m "github.com/otiai10/marmoset"
)

func main() {

    router := m.NewRouter()
    router.GET("/", func(w http.ResponseWriter, req *http.Request) {
        m.RenderJSON(w, http.StatusOK, m.P{
            "message": "Hello!",
            "FOO":     os.Getenv("FOO"), // ここにbuildpackで定義した環境変数出したいな
            "BAR":     os.Getenv("BAR"),
        })
    })

    // アプリケーションのポートはherokuから環境変数"PORT"として与えられる
    port := os.Getenv("PORT")
    http.ListenAndServe(":"+port, router)
}

で、プロジェクトのルートディレクトリでもってgodep saveを一発キメて、以下のような構成にします。

heroku-simple-app-go
├── Godeps
│   ├── Godeps.json
│   └── Readme
├── Procfile
├── main.go
└── vendor
    └── github.com
        └── 以下割愛

github.com

この状態で、

% heroku create
% git push heroku master
% heroku open

とすると、このGoのアプリケーションが動いていることが確認できる。

自作buildpackをつくる

devcenter.heroku.com

buildpackを配置するレポジトリは、とりあえず以下の様な構成になっていれば十分。

.
└── bin
      ├── detect
      ├── compile
      └── release
# permissionはすべて755

detect

#!/usr/bin/env bash
echo "This is detect of empty buildpatck."
# exit 0 すればdetectは成功判定
exit 0

compile

#!/usr/bin/env bash
echo "-----> [Bla Bla Bla Bla]"

# .profile.d以下に.shファイルを作ってあげる
mkdir -p $1/.profile.d
ENVVARS=$1/.profile.d/build-env.sh

# exportなどのスクリプトは.profile.d以下の
# その.shファイルに記述されている必要がある
echo "export FOO=\"Hey, this variable is set by buildpack!!\"" >> $ENVVARS

release

#!/usr/bin/env bash

cat <<EOF
config_vars:
  BAR: "This is bar"
EOF
# これでBARがexportできてるのかなーと思ったが
# 世の中そんなに甘くないようだ

できたもの

github.com

アプリケーションからこのbuildpackを使うようにする

1. 今からheroku createする場合

heroku create--buildpackを与えればよい

% heroku create --buidpack https://github.com/otiai10/heroku-buildpack-tesseract-devel.git

2. すでにheroku createしている場合

heroku buildpacks:addというのがある

% heroku buildpacks:add https://github.com/otiai10/heroku-buildpack-tesseract-devel.git

3. "Deploy to Heroku"ボタンで使いたい場合 ← これ

app.jsonbuildpacksっていうフィールドがある

{
  ...nameとかそういうの書く...,
  "buildpacks": [
    {
      "url": "https://github.com/otiai10/heroku-buildpack-tesseract-devel.git"
    }
  ]
}

これを書くと、

Deploy

これ押した時のテンプレートにこのbuildpackを使うように指定されることになる。

Deployしてみた

デプロイのログが

-----> This is detect of empty buildpatck. app detected
-----> This is empty build pack
/tmp/build_f6ebcf6d3e5e0e1a26460e09fcd1ca7a
/app/tmp/cache
/tmp/d20161104-61-gu6qsi
export FOO="Hey, this variable is set by buildpack!!"
-----> Go app detected
-----> Checking Godeps/Godeps.json file.
-----> Using go1.7.3
 !!    Installing package '.' (default)
 !!    
 !!    
-----> Running: go install -v -tags heroku . 
github.com/otiai10/heroku-simple-app/vendor/github.com/otiai10/marmoset
github.com/otiai10/heroku-simple-app
-----> Discovering process types
       Procfile declares types -> web
-----> Compressing...
       Done: 2.6M
-----> Launching...
       Released v4
       https://test-foobar.herokuapp.com/ deployed to Heroku

で良い感じに動いてる。heroku openしてみると

f:id:otiai10:20161105092816p:plain

自作のbuildpackがアプリケーションのビルドの前で実行されており、buildpackによって宣言された環境変数をアプリケーションで参照できていることが確認できた。

雑感

  • 次回は、buildpackでC++のライブラリとヘッダファイルを配置し、アプリケーションからそれを参照したい

DRYな備忘録として

RubyのtimesみたいなやつをSwiftでやりたい

swift ruby
count = 5
count.times.map { |i| i * i }
# => [0, 1, 4, 9, 16]
let count = 5
[Int](0..<count).map { $0 * $0 }
// => [0, 1, 4, 9, 16]

こうすか、しらんけど

f:id:otiai10:20161102024057p:plain