OmniAICreator/Qiita-1.07M huggingface dataset:
GPSモジュールを使ってローカルでNTPサーバーを立ててみた

サーバーの時間を正確にしたいのだけど、閉じたネットワークなのでインターネット上の
NTPサーバーを使えないので、GPSデータから時刻を取得するローカルなNTPサーバーを
作った。

（raspberry piでは、いろんな方が作っているのだけど普通のPCでなかなか見つけれなかったので
覚書として、、）

使ったGPSモジュールはこれ
https://www.amazon.co.jp/HiLetgo-U-blox-%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E3%83%BC-GPS%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB-Arduino/dp/B01D1D0F5M/ref=sr_1_2?ie=UTF8&qid=1481961666&sr=8-2&keywords=gps+%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB

結果は、RS232C（TTLレベル）で出力されるので秋月のこれをつかって
PCとはUSB接続。

http://akizukidenshi.com/catalog/g/gK-06693/

必要なパッケージ（gpsd,gpsd-clients,ntp)をインストール。

●GPSモジュールの確認
gpsd-clientsをいれるとgpsmonで確認できます

また、pythonでも確認可能。
import serial
s=serial.Serial("/dev/ttyUSB0") #環境によってデバイスの名称変わります。通信速度は
モジュールが9600で、pythonもデフォルトが9600なのでこれだけで大丈夫
while True:
 s.readline()

これでつらつらっと流れてくればGPSモジュールの接続確認OK。
窓際に置かないと測位はできないけど、時間だけなら部屋の中でも受信できました。

・gpsdの設定
　/etc/default/gpsdが設定ファイルです
　START_DAEMON="true"
  GPSD_OPTION=""
  DEVICES="/dev/ttyUSB0"
  USBAUTO="true"
  GPSD_SOCKET="/var/run/gpsd.sock"

・ntpdの設定
 /etc/ntp.confが設定ファイルです
 下記をコメントアウト（先頭に#）
　server 0.ubuntu.pool.ntp.org
　server 1.ubuntu.pool.ntp.org
　server 2.ubuntu.pool.ntp.org
　server 3.ubuntu.pool.ntp.org

  その下あたりに下記を追加
　server 127.127.1.0 minpoll 4 maxpoll 4
  fudge 127.127.1.0 refid GPS time1 0.0 stratum 10
  restrict 192.168.11.0 mask 255.255.255.0

いろいろ調べると127.127.28.0にして共有メモリを介してgpsd→ntpdがやり取りを
するとあったのですが、どうもうまくいかなかったので、127.127.1.0にして自分を参照する
ようにしたらうまくできた

とりあえずばっちりあっているけど、ずれてこないか心配です。
初めてNTPサーバー立てたので自信がない。。
【Excel】INDEX関数について

#  Tips 「INDEX関数」
> **INDEX関数**
> INDEX 関数はテーブルまたはセル範囲にある値、あるいはその値のセル参照を返します。
> [INDEX関数 - support.office.com](https://support.office.com/ja-jp/article/INDEX-%E9%96%A2%E6%95%B0-a5dcf0dd-996d-40a4-a822-b56b061328bd)


```:formula
=INDEX(範囲,範囲中の行番号, 範囲中の列番号)
```
- 第1引数の範囲外を参照することはできない

→ 第1引数によって指定された範囲のサイズが5行4列のとき、
　行番号には1～5、列番号には1～4の数字を指定することができる


**表**

| ⊿ | A | B | C |
|:-:|:-:|:-:|:-:|
| 1  | い  | ろ  | は  |
| 2  |  に | ほ  | へ  |
| 3  |  と | ち  | り  |
| 4  |  ぬ | る  | を  |

例1）`$A$1:$C$4`（`A1`を基準位置とした4行3列の範囲）の中から、2行3列目のセルを参照する


```:example1
=INDEX($A$1:$C$4,2,3)
=$C$2
```
```:result1
へ
```

例2）`$B$1:$C$4`（`B1`を基準位置とした4行2列の範囲）の中から、1行2列目のセルを参照する

```:example2
=INDEX($B$1:$C$4,1,2)
=$C$1
```
```:result2
は
```

#### 範囲が1行n列、あるいはn行1列のとき、第3引数を省略して第2引数でnを指定可能

例3）`$A$1:$C$1`（`A1`を基準位置とした1行3列の範囲）の中から、2列目のセルを参照する

```:example3
=INDEX($A$1:$C$1,2)
=$B$1
```
```:result3
ろ
```

例4）`$C$1:$C$4`（`C1`を基準位置とした4行1列の範囲）の中から、4行目のセルを参照する

```:example4
=INDEX($C$1:$C$4,4)
=$C$4
```
```:result4
を
```
AndroidStudioをemacsのキーバインドにしよう

環境はwindowsです。
macに近づけるために、フリーソフトを使って、CapsLockをCtrlに変更しています。

vimmerな方が多いイメージですが、emacsもなかなか良いです。

#### 何がよいのか？
BackSpaceと矢印キーを押すさいに手首をひねらなくてもいいので、手首や肩に負担が少ないです。（個人の見解）

# 設定方法

Settings を開きます。
![1.png](https://qiita-image-store.s3.amazonaws.com/0/61014/25a31677-4d2a-7be5-a13d-aaac4811d69e.png)

Keymapを開き、Keymapsをにします。
emacs![1.png](https://qiita-image-store.s3.amazonaws.com/0/61014/6d74c397-aa78-a0e3-2c0d-e4de3c04c4e5.png)


キーバインドを変更する場合は、その操作をダブルクリックします。
![1.png](https://qiita-image-store.s3.amazonaws.com/0/61014/8138165f-0d8f-a373-3acf-e3100d5a6799.png)


これで、大枠はできます。
とはいえ、このままだと設定されていないキーバインドがあるので、独自に設定しましょう。

## 現状の設定

現状の設定がどうなっているか調べる方法です。

#### ある操作をしたい場合に、そのキーバインドが何なのかを調べる

右上にある検索窓から、その操作を検索します。（画像はcopyの場合）
![1.png](https://qiita-image-store.s3.amazonaws.com/0/61014/404196ea-575f-f440-f8b8-f3d557e45af9.png)

#### キーバインドから、それがどういう操作なのかを調べる。

検索窓の右側にあるアイコンをタップすると、ウィンドウが出てくるので、そのままキーをストロークします。Mouse shortcutにonMouseすることでマウスもバインドできます。
![1.png](https://qiita-image-store.s3.amazonaws.com/0/61014/9f72d4a5-d1d3-6061-80bb-d0ca697805cd.png)

## おすすめの設定

オリジナルで変更した操作です。

こんな感じで変更を加えます。
![1.png](https://qiita-image-store.s3.amazonaws.com/0/61014/b61c3c40-7d14-d800-8a00-d5ce918216a7.png)

#### editorの操作

Undoをcntl+zに。
windowsと同じ操作にします。

BackSpaceをcntl+hに。
delete(cntl+d)はあるのですが、BackSpaceはないので登録します。

単語(Delete to Word Start)ごとに削除をcntl+wに。
昔は知らなかったのですが、なかなか便利です。

#### AndroidStudioの操作

Runをalt+r、Test Runをalt+shift+rに。
ビルドするのに、わざわざマウスを持つ必要はありません。

## 使い方

よく使う操作です。

#### カーソルを動かす

<dl>
  <dt>矢印</dt>
  <dd>cntl+p ( ↑ )</dd>
  <dd>cntl+ f (→)</dd>
  <dd>cntl+n ( ↓ )</dd>
  <dd>cntl+b (←)</dd>
</dl>
<dl>
  <dt>ジャンプ</dt>
  <dd>cntl+a (行の先頭)</dd>
  <dd>cntl+e (末尾)</dd>
  <dd>cntl+s (検索)</dd>
  <dd>cntl+ l (カーソルを真ん中)</dd>
</dl>

#### 編集する

<dl>
  <dt>コピペ</dt>
  <dd>cntl+k (一行切り取り)</dd>
  <dd>cntl+y (それを張り付け)</dd>
</dl>
<dl>
  <dt>削除</dt>
  <dd>cntl+h (前方削除)</dd>
  <dd>cntl+d (後方削除)</dd>
  <dd>cntl+w (単語削除)</dd>
</dl>
<dl>
  <dt>改行</dt>
  <dd>cntl+m (改行)</dd>
  <dd>cntl+ o (下に改行)</dd>
</dl>
<dl>
  <dt>その他</dt>
  <dd>cntl+j (サジェスト)</dd>
  <dd>cntl+u (親クラスに移動)</dd>
  <dd>cntl+g (escape)</dd>
</dl>

# おわりに

慣れるととても便利です。
15分くらいがちゃがちゃやると慣れるので、面倒だと思わず一度試してみてください。

あと、こういう操作があると便利なのにって思ったら、検索してみましょう。意外とあったりします。
Aurora アップデートをCLIで行なう

# はじめに
初老ともなると日々変化するGUIについてゆくのがつらくなります。とおもったらCLIでも方法がかわっていた Auroraのアップデートについてのメモとなります。

# Auroraアップデートの方式変更

1.8からだとおもいますが、インスタンス単位ではなくクラスター単位でのアップデートとなりました。最近の変更なので日本語のドキュメントと英語のドキュメントで相違がでています。ちょっと古いとおもったら、英語のドキュメントを確認するのが初老の嗜みです。

# CLIでのアップデート方法

7割方自分用なので特に説明なしです。

```
#クラスター名
DBCLUSTER_ID=<<環境にあわせて設定>>
#ARNの作成
DBCLUSTER_ARN=arn:aws:rds:ap-northeast-1:<<AWSアカウントID>>:cluster:${DBCLUSTER_ID}
#AWS CLIのプロファイル設定(必要であれば)
AWS_PROFILE="--profile default"
#事前スナップショット名
SNAPSHOT_NAME="BEFORE-UPDATE-${DBCLUSTER_ID}"

#事前スナップショット作成
aws  ${AWS_PROFILE}  rds create-db-cluster-snapshot   \
--db-cluster-identifier  ${DBCLUSTER_ID}  \
--db-cluster-snapshot-identifier ${SNAPTHOT_NAME}

sleep 10;

#Auroraアップグレード
aws ${AWS_PROFILE} rds apply-pending-maintenance-action \
--resource-identifier ${DBCLUSTER_ARN} \
--apply-action system-update \
--opt-in-type immediate 

```

# 補足情報

- Auroraの更新ではフェイルオーバーがあるとおもってましたが、基本ないです。。DBエンジンの再起動だけの停止時間(体感20秒ないくらい?)ですと、DNSをともなうフェイルオーバーよりも短いというのが理由なので、大規模アップデートだとフェイルオーバーするのかもしれません。まだ経験したことないですが。
- 1.10から [ゼロダウンタイムパッチ](https://aws.amazon.com/jp/blogs/news/amazon-aurora-update-spatial-indexing-and-zero-downtime-patching/) がリリースされたということなので今後停止時間すらなくなるかもしれません
- 意外なことにWriterをアップデートするとReaderも再起動します。ログレプリケーションが止まるためのようです。
【Excel】OFFSET関数について

# Tips 「OFFSET関数」

集計対象を自由自在に変えれるため、使いこなすと超強力な関数。
単体で使うことは少なく、他の関数と複雑に組み合わせて使用することで真価を発揮する。

> **OFFSET関数**
> セルまたはセル範囲から指定された行数と列数だけシフトした位置にあるセル範囲の参照を返します。返されるセル参照は、単一のセル、セル範囲のいずれかの参照です。また、返されるセル参照の行数と列数を指定することもできます。
> [OFFSET関数 - support.office.com](https://support.office.com/ja-jp/article/OFFSET-%25E9%2596%25A2%25E6%2595%25B0-c8de19ae-dd79-4b9b-a14e-b4d906d11b66?ui=ja-JP&rs=ja-JP&ad=JP&fromAR=1)

```:formula
=OFFSET(1_基準セル, 2_行方向シフト数, 3_列方向シフト数, 4_基準から選択する行数, 5_基準位置から選択する列数)
```

## つかいかた

- OFFSETのカッコの中身の第1引数（カンマで区切られた1つ目の部分）で「基準セル」を指定。
- 第2引数（カンマで区切られた2つ目の部分）で「基準セルから縦に何行下を参照するのか」を指定。
- 第3引数で「基準セルから横に何列右を参照するのか」を指定。

ここまでの指定で集計対象のセルの一番左上を指定し、

- 第4引数で「そこから縦に何行分が集計対象なのか」を指定。
- 第5引数で「そこから横に何列分が集計対象なのか」を指定。

下の図では、「B3」セルから4行下、3列右のセルを起点として、
3行2列の範囲に含まれる数値を合計した値をA1セルに出力している。

![image](https://qiita-image-store.s3.amazonaws.com/0/103957/6234315d-b607-8ab3-d7f2-86a644453863.png)

## 計算例

#### 例1) A1から1行下、2列右のセル（=**C2**）を参照する

```:example
=OFFSET(A1, 1,2, 1,1)
```

#### 例2) 「`$B$3`から4行下、3列右のセル」から3行2列分（=**C2:C3**）を参照する

```:example
=OFFSET($B$3, 4,3, 3,2)
```

`=SUM(OFFSET($B$3, 4,3, 3,2))`は`=SUM($E$7:$F$9)`と同じ

基準から選択する行数, 基準位置から選択する列数がそれぞれ1のとき、
OFFSET関数の第4引数、第5引数は省略することができる
以下の2つの例は同じ結果を返す

```:example
=OFFSET(A1, 1,2, 1,1)
```


```:example
=OFFSET(A1, 1,2)
```


OFFFSETの参照範囲は[数式の検証](https://support.office.com/ja-jp/article/%E3%83%8D%E3%82%B9%E3%83%88%E3%81%97%E3%81%9F%E6%95%B0%E5%BC%8F%E3%82%92-1-%E3%83%AC%E3%83%99%E3%83%AB%E3%81%9A%E3%81%A4%E6%A4%9C%E8%A8%BC%E3%81%99%E3%82%8B-59a201ae-d1dc-4b15-8586-a70aa409b8a7)機能を使用すれば簡単に確かめることができる

![数式の検証](https://qiita-image-store.s3.amazonaws.com/0/103957/472f0c4e-a046-3fb7-8c85-548ed8e4f8bf.png)

OFFSET関数の引数には自由に数式を入れることができるので、
例えば、**[MATCH関数](http://qiita.com/AQRiL_1132/items/c1dccb1ac756501926a1)**, **[INDEX関数](http://qiita.com/AQRiL_1132/items/e3999085677c865efae6)**のような関数を組み合わせて使用することにより、
状況に合わせて集計範囲を自由自在に変える超柔軟な数式を作ることができる。
使いこなすと本当に強力。

→**[【Excel】OFFSETで過去n日間平均を計算](http://qiita.com/AQRiL_1132/items/bb28305214098f0e74f6)**
→**[【Excel】 SUMIFS入門からOFFSETを活用した動的集計まで](http://qiita.com/AQRiL_1132/items/922d0d54293e9089f086)**

##参考
[OFFSET 関数 - Office のサポート](https://support.office.com/ja-jp/article/OFFSET-%25E9%2596%25A2%25E6%2595%25B0-c8de19ae-dd79-4b9b-a14e-b4d906d11b66?ui=ja-JP&rs=ja-JP&ad=JP&fromAR=1)
開発速度が上がる順序を考慮して実装を行っていこう（投稿ミスのため削除します）

間違って、同じ内容を２度投稿してしまいました。

[開発速度が上がる順序を考慮して実装を行っていこう](http://qiita.com/nonbiri15/items/21440d648055d0f17977)

そのため、最初の投稿を残しますので、このページは削除します。
MacでFess9でxlsxファイルを検索できるようになるまで

# 背景
本当はFess10がリリースされているのでFess10を使った構築をしたかったが、試しにFess10.2で環境構築したところ、xlsxファイルなどを検索対象にできず、原因を調べたところ、Fess10から検索エンジンがSolrからElasticSearchに変更されていた。
Solrではxlsxファイルなどを検索対象にするプラグインがbuilt-inなのだが、ElasticSearchでは別途プラグインのインストールが必要で、しかもインストール方法がよく分からなかった。
このため、Fess10は諦めてしまった。
Fess10はインターフェースが格好良くなっているので残念。

# 動機
ファイルサーバにいっぱい溜まっているファイルの再活用ができていないのは問題。どうにかして検索性を上げて作業効率を上げたい。
また、IoTとかBig DataとかBIとか言われている訳ですが、検索エンジンのインフラ要素は、それらと共通する部分が多いと感じたので、多少なりとも活用することで、インフラ技術も向上させたい。

# 環境
試しに自分の環境で動作させたい為、ラップトップで実行環境を構築。
検索対象は、ホームディレクトリのDocumentsディレクトリ内。

Mac OS X El Capitan 10.11.6

butada-mac:bin butada$ java -version
java version "1.8.0_71"
Java(TM) SE Runtime Environment (build 1.8.0_71-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.71-b15, mixed mode)

# 手順

## Fessをダウンロードする。

https://ja.osdn.net/projects/fess/downloads/63287/fess-server-9.4.2.zip/
fess-server-9.4.2

## Fessをインストールする。

ダウンロードフォルダから
移動させるだけ。

```bash
cd /Users/butada/Documents
mv /Users/butada/Downloads/fess-server-9.4.2 .
```

起動スクリプトの実行権限を与える

```bash
cd fess-server-9.4.2
cd bin
chmod +x startup.sh
```

Fessを起動

```bash
./startup.sh
```

Safariで開く。

http://localhost:8080/fess/

## Fessの管理画面で設定する

http://localhost:8080/fess/admin/

ユーザー名とパスワードは共に「admin」。

## クロールおよびクロールジョブを設定する

クロール→ファイルシステム
から「新規作成」

設定名: test_for_filesystem
パス: file:/Users/butada/Documents/

以上を入力したら「作成」。

システム→ジョブ管理
から「Crawler」の「詳細」
更に、詳細を開いたら「開始」

これで、設定したクロールを含めて
ジョブが実行される。（たぶん）

## ジョブの状態を確認する

システム情報→ジョブログ
から確認できる。
ステータスが「RUNNING」になっていれば動作している。

## 検索結果の確認

http://localhost:8080/fess/
を開き、検索キーワード(xlsxファイルに含まれる文字列)を入力して「検索」

期待された検索結果が表示されればOK。

# まとめ
まだ実運用を始めていないので、この設定でどれくらいのファイル数などの規模に対応できるのかがわからないが、まずはこれで様子を見たいと思います。
あとは、outlookの検索が遅いので、それを解消する手段としてFessが活躍できると嬉しい。
HOGWILD! 論文要約

#どんなもの？
[HOGWILD!: A Lock-Free Approach to Parallelizing Stochastic Gradient Descent](https://arxiv.org/abs/1106.5730)
著者：Feng Niu, Benjamin Recht, Christopher Re, Stephen J. Wright
2011年に機械学習のトップカンファレンスである[NIPS](https://nips.cc/)で発表された。機械学習で頻繁に使われる確率的勾配降下法（Stochastic Gradient Descent: SGD）の高速並列化手法「HOGWILD!」を提案している。高速化を実現する主なアイディアは、複数プロセッサーの共有メモリへのアクセスをロックしないこと。各プロセッサーが互いの計算結果を上書くケースがあるが、機械学習で用いる対象データがスパースな場合には、上書きによる計算結果への影響は小さく、ほぼ最適な収束率を達成する。

#先行研究と比べてどこがすごい？
Bertsekas and TsitklisのSGDの並列化手法では言及されていなかった、収束率を向上させている。多くの機械学習のアプリケーションにおいて、Langford et alのround-robin手法と比べ、桁違いの速さを達成している。

#技術や手法のキモがどこ？
各プロセッサーの共有メモリへの書き込みをロックしないこと。特定の変数を更新しないように制御ができること。

#どうやって有効だと検証した？
様々な機械学習の問題（Sparse SVM, Matrix Completion, Graph Cuts）を対象に数値実験を行っている。既存手法のround-robinを自分たちで実装し、公平な条件で（むしろ少し既存手法が有利な条件で）処理時間を比較している。それに加え、AIGという手法についても比較している。実験はC++で各手法を実装し、二つのXeon X650 CPU（2xハイパースレッディングを備えた6コア）、Linux 2.6.18-128上で行っている。

#議論はある？
いっさいの競合が発生させずに並列な勾配計算を実現する構造が求められる。B.Recht et al. 2011の行列補間における手法を一般化できれば、機械学習の問題の計算をさらに速くできるだろう。複数のSGDを並列に実行し、平均化する手法では、RCV1データセットの場合に並列化に優位性はない。

#次に読むべき論文は？
- D. P. Bertsekas and J. N. Tsitsiklis. Parallel and Distributed Computation: Numerical Methods. Athena Scientific, Belmont, MA, 1997.
- J. Tsitsiklis, D. P. Bertsekas, and M. Athans. Distributed asynchronous deterministic and stochastic gradient optimization algorithms. IEEE Transactions on Automatic Control, 31(9):803–812, 1986.
Eclipse/Cheのビルドコマンドでエラーが出るときに確認すること

# 症状

[先日の別記事で書いたように](http://qiita.com/monamour555/items/3b1e50a05b57e1f5c787)，Eclipse/Che の IDE 上で build ボタンを押した時に，ビルドが失敗することがあります。
この例は Java ですが，C/C++ 環境でも，これに類似した症状の報告があります。

![ff09cd22-cc35-7e60-eddc-a53ea4a1ce33.png](https://qiita-image-store.s3.amazonaws.com/0/5414/9dffccb8-5287-4d2a-6362-2025d016eb61.png)

この件の原因が判明しました。

# 原因

IDE のコマンドでは，ビルド実行環境が提供している，独自の変数を埋め込むことができます。
そして，大抵のコマンドは `${current.project.path}` という変数を使ってビルドするプロジェクトのディレクトリを取得しています。

ビルド実行環境は， `${current.project.path}` を，Project Explorer タブで選択されているプロジェクトから，値を設定します。

ワークスペースを開いた直後は，Project Explorer タブは何も選択されていない状態になっています。

よって，`${current.project.path}` は空文字列になります。

# 対策

IDE のコマンドを実行する前に， Project Explorer タブのツリーにある項目を(クリックするなどして)選択してください。

## ひとりごと

バグというわけでもないとは思うのですが，選択されていない旨を IDE が警告してくれも良いのにと…思いますよね…。
Elasticsearchをバージョンアップした時の苦労話

この記事は [Origami Advent Calendar](http://qiita.com/advent-calendar/2016/origami) 14日目の記事になります。

Origamiのアプリではお店を現在地から近い順に表示させたり、商品をスクロールで読み込ませたり、商品をキーワードで検索したりといった部分にはElasticsearchが使われています。

|お店|商品|
|---|---|
|![IMG_5452.PNG](https://qiita-image-store.s3.amazonaws.com/0/30623/48d8a40f-845f-d709-19b9-7d03e09ace24.png)|![IMG_5454.PNG](https://qiita-image-store.s3.amazonaws.com/0/30623/e8dd3c77-759e-b8a8-5f5e-87481130f7c9.png)|

少し前ではありますが、今年、OrigamiではElasticsearchのバージョンを1.5から2.3にアップグレードしました。その際の目的や苦労話、やったことについて書きたいと思います。

# 目的とゴール
まずは当時、商品検索が貧弱だという問い合わせが相次いでいたので、ちゃんとしようぜということになりました。（この時点では上記のお店の近い順表示は無かったです）

そして目的とゴールを掲げました。

<目的>

- 安心
- 検索機能の改善
- 検索精度の向上

<ゴール>

- Elasticsearchのクラスターとノードの監視
- クラスターが落ちた時の対応
- マッピング更新、辞書更新、インデックス再構築のフローをつくる
- 検索機能の改善指標を作り可視化できるようにする
- インデックスにカスタムアナライザをセットする

当初、1.5から2.3にバージョンアップすることは目的ではなく、ゴールまでの過程で2.3にするとインデックス再構築が楽になるとか、スループット上がるとか、marvel2.X（無償）が使えるという噂聞いたりだとかあって、バージョンアップしようということになりました。

# 苦労話
当初、構築済みの新ESサーバー（ver2.3）を用意し、旧ESサーバー（ver1.5）で取得したスナップショットを新ESサーバーでリストアし、各マイクロサービスのESサーバーの接続先を切り替えるという手順を考えていました。
しかしver1.5のスナップショットはver2.3でデータをリストアできないことが判明。ver1.X系のスナップショットを2.3でリストアするためには、ver1.5をver1.7に上げる必要がありました。
またスナップショットリポジトリの準備を全ノードに行う必要があるなど、作業が複雑になることがわかりました。

そこでRDB（リレーショナルデータベース）に商品のマスターデータがあるので、RDBからElasticsearchにデータをコピーするスクリプトを作成して、それの実行完了後、旧ESサーバーから新ESサーバーに接続先を切り替える方法にシフトしました。（※最初からこの方法思いついていれば苦労しなかった。）

その都度全てのデータをコピーすると時間を要するため、今後の運用のため、実行スクリプトは引数にタイムスタンプを指定することで、その時間以降のデータをコピーできるようにしました。RDBに保存されている商品データの更新時間（updated）以降のもののみコピーの対象とするようにしています。

スクリプトの例）
$ NODE_ENV=development coffee add_product_to_es.coffee 1481959661

# やったこと

1. 新ESサーバー（ver2.3）を準備する
2. ショップ管理画面を停止、メンテナンス画面の表示（切り替えの間、商品更新されないよう）
3. RDBからElasticsearchにデータをコピーするスクリプトを実行
4. 各マイクロサービスの接続先を旧ESから新ESに切り替え
5. ショップ管理画面を起動、メンテナンス画面の解除

移行中、ショップ管理画面は一時的に停止しました。スクリプトの実行によってESに対してRDBの商品データの商品登録（CREATE）と商品更新（UPDATE）は同期できるのですが、ESに既にコピーされてしまったデータに対してRDBの商品削除（DELETE）は同期できないためです。

# 所感
RDBに保存している商品のマスターデータがあると、Elasticsearchのような検索専用のサーバーを移行する作業はシンプルかつ効率化できることを実感しました。

来年にはElasticsearchをver5.Xに上げたいと思っています。Go製のElasticsearchクライアントには[elastigo](https://github.com/mattbaird/elastigo)を利用しているのですが、Elasticsearch5.0にはまだ対応できていないため、クライアント部分の入れ替えが必要となりそうでこの部分が来年の苦労になりそうな予感がしております。
Djangoの環境をDocker化する（Docker + Django + Gunicorn + nginx）その2

[前回](http://qiita.com/shinyarize/items/bce228f506f894cd825d)は、`nginx.conf`までを記載しました。今回は、`docker-compose.yml`を中心に嵌りどころも含めて書いていきたいと思います。

下記で公開中です。記事と合わせて参考にしてください。
 [Dockerize Django Environment](https://github.com/amazipangu/docker-django)

-----
## docker-compose.ymlの初期設定


```yml:docker-compose.yml
version: '2'
services:
  web:
   restart: always
   build: ./web
   expose:
     - "8000"
   links:
     - postgres:postgres
   command: gunicorn app.wsgi -b 0.0.0.0:8000
   volumes:
     - ./web:/usr/src/app
     - ./web/static/:/usr/src/app/static
  nginx:
    restart: always
    image: nginx
    ports:
      - "80:80"
    volumes:
      - "./nginx/:/etc/nginx/"
      - /www/static
    volumes_from:
      - web
    links:
      - web:web
  postgres:
   image: postgres
   ports:
     - "5432:5432"
```

1. `Django`用コンテナの定義(サービス名：web)
    
    
* 前回のディレクトリ構造にて、`Django`用ディレクトリを`web`としました。その中ににある`Dockerfile`をからビルドします。
* `EXPOSE`命令で、特定のネットワークポート（今回は、`8000`）をコンテナ実行時に公開することを`docker`に伝えます。
* `LINKS`命令で、コンテナを他のサービスと連携します。（今回は、 `postgres` ）
* `command`命令で、コンテナ実行時に実行されるcommandを上書きします。（今回は、`gunicorn app.wsgi -b 0.0.0.0:8000`）※`gunicorn`については別途記載します。
* `volumes`命令で、指定したディレクトリがボリュームであることを宣言します。`（ホスト:コンテナ）`の関係で指定しています。
  * `./web:/usr/src/app`で`Django`アプリケーションディレクトリを指定します。
  * `./web/static/:/usr/src/appstatic`で静的ファイルディレクトリを指定します。

2.`Nginx`用コンテナの定義（サービス名：nginx）

* `IMAGE`命令で、タグもしくはイメージIDを指定し、pullします。今回は、`nginx`イメージをpullします。
* `PORTS`命令で、ホストの80番ポートとコンテナの80番ポートをフォワードするように指示します。
* `VOLUMES`命令で、ホストの`nginx`ディレクトリ配下にある`nginx.conf`ファイルをコンテナの`/etc/nignx`ディレクトリにコピーするように指示します。
* `VOLUMES`命令で、`/www/static`ディレクトリを明示的にボリュームとして使用することを宣言します。(静的ファイルを格納しているディレクトリ)
* `VOLUMES_FROM`命令で、`Web`（Django用ディレクトリ)をマウントするように指示します。（静的ファイルを取り込むため）

3.`PostgreSQL`用コンテナの定義（サービス名：postgres）

* `postgres`イメージをpullします。
* `PORTS`命令で、ホストの5432番ポートとコンテナの5432番ポートをフォワードするように指示します。



------
## 嵌りポイント

1. 静的ファイルのディレクトリを明示的にボリュームとして宣言しないと静的ファイルを配信できない。

-----

次回は、`Django`フレームワークの初期設定を記載します。
iTerm2のコマンド実行時刻表示/非表示の切り替え


# 環境
iTerm2 Build 3.0.12

# コマンド
`Cmd + Shift + e`

# イメージ
画面右端に以下のような時刻表示がされる。
![Kobito.czjlvI.png](https://qiita-image-store.s3.amazonaws.com/0/7902/a9180a1d-6615-84be-e147-67b05757e64e.png "Kobito.czjlvI.png")


# 参考
[iTerm2 3.0の新機能 - Qiita](http://qiita.com/ksato9700/items/49539ec2f19027829f2f)
CureAppの裏側を少し支えるGASのお話

##はじめに
今日の記事はいつもと趣向を変えたテーマで、基本的に私と同じような非エンジニアの方に向けた記事です。
(ほら、毎日手が込んだカレーばっかり食べてると飽きて、お手軽パスタに浮気したくなる気持ちってあるでしょ？それと同じことです。)
CureAppのほんの一部分の雰囲気が伝われば、うれしいです。
## google app script(GAS)との出会い
いきなり本題に入りますが、GASはgoogleが提供しているサービス(gmailやらgooglecalenderやらspreadsheetやら)をつなげるサーバーサイド・スクリプト環境です。

CureAppで財務・管理・いろんな業務をやっている私は、毎月やってくる立替経費や勤務表の集計といった月次締処理をどうにかして無料で楽にできないかと試行錯誤した結果、GASにたどり着きました。

ちなみにGASはjavascriptで動きます。

そしてCureAppはjavascriptでプロダクト開発をしています。

つまり社内には私のようなjavascriptひよこ組の人間にとっては、いっぱい師匠がいるわけです。(ぱちぱち)

## botづくり・自動化にはまる
cureappはコミュニケーションツールとして、chatworkやslackをつかっています。
その中で日次や月次で定期的にアナウンスしなくてはいけない事項がたくさんあるのです。
でもいちいち真心こめて人力入力するわけにもいきません。
そこで、覚えたてのGASでいろいろ定期アナウンスbotをつくりました。
以下が、cureappの中で走り回っているbotちゃんたちのほんの一部です。

- googlecalendarに登録された、今日1日の自分の予定をプライベートチャンネルにつぶやくbot

→このbotが毎朝出社前につぶやいてくれるおかげで、目が覚めてから3秒で一日の予定を簡単に把握することができます。

- googlecalendarに登録された、今日1日の会議室の予約状況を全社チャンネルにつぶやくbot

→会議室予約状況をいちいち見に行く必要がなくなったので、ダブルブッキングの数が激減したと思います。

- 毎日15時に①今日実施した作業内容②これからの作業内容③つまづいている作業内容を質問するbot

→簡単に皆さんが進捗報告及びその確認をすることができるようになりました。(ぱちぱち)

- 勤務表や立替経費システムへの入力を定期的に呼びかけるbot

→これで入力漏れを理由とした修正作業が圧倒的に減りました(大拍手)

## 自動化の返り討ちにあう
そんなこんなでGAS及びjavascriptに馴れてきたある日、ふと会社のお問い合わせメールのような会社宛に届いたメール内容をchatworkへ通知する必要性が発生しました。
概要としては、こんな感じです。

- GASで、gmailの未読メールがあれば、そのメール内容を抽出し、特定のchatworkへ通知すると共にそのメールを既読にするプログラムが走る

- 1分ごとにそのプログラムが起動する。

ここまではある程度比較的にスムーズに設定することができ、ちょうど帰宅時間でしたので、仕事を切り上げ帰宅しました。
ただ、次の日悪夢のような事態が発生しました。

gmailでは基本的にスレッドでまとめて処理するので、私の作成した当初のコードでは、同一スレッドで新着メールが届いた場合、ひたすらにそのスレッドの1番最初(古い)のメールをつぶやき、本来既読にすべき新着メールはそのままの状態であり続けたので、1分ごとに同じメールをchatwork上でつぶやき続けたのでした。。その状態に気づいたのは土曜の夕方だったので、chatworkの未読数が1,000を超えていて、最初何が起こったのかわからず、1時間ほどパニックになりました。(その節は大変ご迷惑をおかけしました。)
今では上記スレッドのルールにも無事対応し、きちんと機能しています。
ただ、自動化する時にはしつこいくらいにテストしてから本番環境にリリースしようという事を身をもって感じました。

## おわり
ここまで読んで、もしかしたらお気づきかもしれませんが、当初の目標であった勤務表・立替経費の自動集計システムの構築はまだ達成できていません。(ただ、言い訳するとgoogleformとspreadsheetでかなり楽チンになってます。)
ただ、私のような非エンジニアでもたくさんぐぐって、ちょっと背伸びするだけで日々の作業を楽チンにして本当に注力しないといけない作業に集中できます。
また、なによりプロダクトチームの方々が私のしょうもない質問に本気で対応してくれることに大感謝です。
以上、つらつらと書いてきましたが、今日はこのあたりで終わりにしようと思います。
またね
AndroidのEclipseプロジェクトをAndroidStudioでデュアル開発したい

## やりたいこと
1. AndroidのEclipseプロジェクトを、そのまま環境をいじることなく、AndroidStudioで開発したい。
2. ndk-build使用のNativeライブラリ（典型的には、上記プロジェクトに付随しているもの）をAndroidStudioのビルド環境に追加したい。

> AndroidStudio 2.2.3、書いている時点で最新のコンパイル・ビルド環境を使用して説明しています。

## AndroidStudioにインポートする

Eclipseで自動生成したものであれば、ルート直下に以下のbuild.gradleを落とし、AndroidStudioでインポートするだけです。環境に合わせて、適宜修正してください。

```build.gradle
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.3'
    }
}

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }
        androidTest.setRoot('tests')
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
}
```

> Nativeライブラリプロジェクトも一緒にインポートする場合は、後半の操作で生成されるexternalNativeBuild設定を最初から記述してインポートして構いません。

## ndk-build使用ライブラリを追加する

ProjectツールウィンドウのAndroidビューで、モジュール（上記ケースでは、兼モジュールのプロジェクト）を右クリッックし、コンテキストメニューから[Link C++ Project with Gradle]を選択します。

![Screen Shot 2016-12-17 at 9.47.20.png](https://qiita-image-store.s3.amazonaws.com/0/49088/3fc0f1d5-57de-a67a-61c7-976a9eb65de8.png)

Build Systemのプルダウンメニューで[ndk-build]を選択し、Project PathでAndroid.mkを指定します。同じディレクトリにApplication.mkがあれば一緒に取り込んでくれます。（典型的にはjniディレクトリ直下に2つそろってあるはず。）

![Screen Shot 2016-12-17 at 9.48.34.png](https://qiita-image-store.s3.amazonaws.com/0/49088/5ab177be-affb-9e77-9856-d1b65f7aaea1.png)

正常に取り込まれれば、External Build Files グループに表示されます。

![Screen Shot 2016-12-17 at 13.52.49.png](https://qiita-image-store.s3.amazonaws.com/0/49088/9e200384-6128-f5a6-2a9a-8d7162d530fa.png)

build.gradleを開くと、externalNativeBuild設定が追記されています。

```build.gradle
android {
    externalNativeBuild {
        ndkBuild {
            path 'jni/Android.mk'
        }
    }
}
```

> 環境更新時は都度Gradleのsync と Build>Refresh Linked C++ Projectsを実行して同期をとります。

Build> Analyze APK...でAPKを開いてみると、ちゃんとライブラリが取り込まれているのが確認できます。

![Screen Shot 2016-12-17 at 15.52.12.png](https://qiita-image-store.s3.amazonaws.com/0/49088/aad144e7-8740-90d6-28bd-b3b48b1aa4f7.png)


詳細は、[プロジェクトへの C / C++ コードの追加](https://developer.android.com/studio/projects/add-native-code.html?hl=ja#link-gradle)を参照してください。

参考までに、NDK Rev.10あたりまでバンドルされていたHelloJniサンプルをデュアル環境化したものを[ここ](https://github.com/tatsu/HelloJni)に置いておきます。
Form - FormFactory - DynamicForm　

#Form - FormFactory - DynamicFormの違うところ、
３つのフォームはHTTP フォームデータの送信することです。
まず、Java Play framework のplay.dataパッケージには
```java
java.lang.Object
　  play.data.Form<DynamicForm.Dynamic>
　　　　　play.data.DynamicForm
java.lang.Object
　    play.data.FormFactory
```
フォーム送信したければ簡単な方法は、既存のクラスをラップする
まず、モデルのクラスは

```java
public class User {
    public String email;
    public String password;
}
```
クラスをラップするには

```java
Form<User> userForm = Form.form(User.class); //Java play 2.4x以下に使うのは
```
```java
Form<User> userForm = formFactory.form(User.class);　//Java play 2.5以上に使うのは
```
リクエストの内容を直接バインドする時に

```java
User requestData = userForm.bindFromRequest().get();   //2.4以下
```
```java
User requestData = formFactory.form(User.class).bindFromRequest();　//2.5以上
```
モデルに関連していないリケエストからデータを取得する場合：

```java
DynamicForm requestData = Form.form().bindFromRequest(); //2.4以下

DynamicForm requestData = formFactory.form().bindFromRequest();//2.5以上
```
2016年 Symfony Meetup まとめ

この投稿は[Symfony Advent Calendar 2016](http://qiita.com/advent-calendar/2016/symfony) 25日目の記事です。 

---
今年から日本Symfonyユーザー会に参加しました。花井です。
2016年に開催したSymfony Meetupを振り返ります。

## Symfony Meetupとは？
Symfony Meetup は Symfony を通じた交流会です。
コミュニケーションや情報交換の場としてご利用いただいております。
「Symfony を通じた」交流会ですから、Symfonyに限らず:flushed:PHPやJSのフレームワーク、OOPなど、毎回幅広い話題についてLTや議論が繰り広げられます。

## 2016年Meetup開催カレンダー
今年は11回開催することができました。参加いただいた皆様、ありがとうございました。
また、会場をご提供いただいている企業の皆様、いつもありがとうございます。:bow: 

|開催日|タイトル|開催場所(敬称略)|テーマ|
|:---:|:---:|:---:|:---:|:---:|
|2016/1/20|[「基本からしっかり学ぶ Symfony2入門」開発環境構築会 #1](https://symfony.doorkeeper.jp/events/37286)|    フォトクリエイト|Symfony2本の写経教室に向けた環境構築|
|2016/1/22|[「基本からしっかり学ぶ Symfony2入門」開発環境構築会 #2](https://symfony.doorkeeper.jp/events/37287)|    フォトクリエイト|Symfony2本の写経教室に向けた環境構築|
|2016/1/24|[Symfony Meetup #8](https://symfony.doorkeeper.jp/events/37261)|UUUM|Symfony2本の写経教室|
|2016/2/27|[Symfony Meetup #9](https://symfony.doorkeeper.jp/events/38802)|ラクスル|Symfony2本の写経教室|
|2016/3/27|[Symfony Meetup #10](https://symfony.doorkeeper.jp/events/40811)|GMOクラウド|Symfony2本の写経教室|
|2016/4/24|[Symfony Meetup #11](https://symfony.doorkeeper.jp/events/42490)|ヒトメディア|Symfony2本の写経教室|
|2016/5/29|[Symfony Meetup #12](https://symfony.doorkeeper.jp/events/44942)|ヒトメディア|Symfony2本の写経教室|
|2016/7/10|[Symfony Meetup #13](https://symfony.doorkeeper.jp/events/47980)|ラクスル|Symfonyにおけるテスト|
|2016/8/28|[Symfony Meetup #14](https://symfony.connpass.com/event/37514/)|フォトクリエイト|Symfonyにおけるテスト|
|2016/9/8|[PHP Testing Study](https://connpass.com/event/39027/)|フォトクリエイト|[短気なプログラマのためのPHPUnitクックブック](https://leanpub.com/grumpy-phpunit-jp)をつかってPHPのテストを書いてみる|
|2016/11/6|[Symfony Meetup #15](https://symfony.connpass.com/event/42799/)|ヒトメディア|[Symfony Best Practices](http://symfony.com/doc/current/best_practices/index.html)|

## 2016年開催のMeetupまとめ
各回の様子やLT資料など、詳細は[#symfony_meetup](https://twitter.com/hashtag/symfony_meetup?f=tweets&vertical=default&src=hash)で確認できます。
###上半期
昨年末に[「基本からしっかり学ぶ Symfony2入門」](http://gihyo.jp/book/2016/978-4-7741-7803-5)が出版され、Symfonyをもっといろんな人に知ってもらいたいという思いから、著者の後藤さん、金本さんにご協力いただき、写経会を開催しました。:blush: 
初心者の方にはSymfonyの全体像を理解することができる、上級者の方にも普段使っていない機能など新しい発見があるとても有意義な会になりました。
### 下半期
写経会最終回は「テスト」にまつわる会でしたが、「仕事でテストを書いていないけど、実際書いてみるとどうなの」、「テストを書くと何が嬉しいのだろう」といった疑問にお応えする形で、SymfonyやPHPのテストにまつわる悩みや、課題、成功体験等を共有する座談会を開催しました。
「実際に書いたことがないから書いてみたい」という方のために、PHPUnitでFizzBuzzのテストを書いてみるスピンオフ勉強会も開催されました。
今年最後のMeetupはSymfony Best Practiceについてでした。
Symfony3のバージョンが順調に上がっていくなか、再度Symfonyで開発する利点や、Symfonyの哲学を見つめなおす会となりました。
### 恒例LT大会
Meetupでは毎回LT大会もしています。Symfonyに限らず、組織づくりの話や、実装や設計についてのお悩み相談など、テーマはなんでもありです。他の勉強会用LTの素振りや再演も歓迎です！私を含め、LTデビューした方も大勢います。
個人的に印象に残っているLTは、DQNEOさんが10分のLT中にライブコーディングしてくださった[オレオレSymfony](https://gist.github.com/DQNEO/e0f516a41e794488c0c5)です。

## 2017年のMeetup
Meetupで扱ってほしいテーマがある、こんなことしてほしい、Symfonyで困ってるといった声にはできる限り答えていきたいと思っておりますので、リクエストがある方は [#symfony_meetup](https://twitter.com/hashtag/symfony_meetup?f=tweets&vertical=default&src=hash) または [#symfony_ja](https://twitter.com/hashtag/symfony_ja?f=tweets&vertical=default&src=hash)のハッシュタグをつけてツイートしてください。
今年こそ温泉合宿したい！
DockerでJupyter立ち上げるワンライナー

Docker Hubに公開されている[enakai00/jupyter_tensorflow](https://hub.docker.com/r/enakai00/jupyter_tensorflow/)というimageがそのまま立ち上がってくれるので便利です。

## イメージ起動

```shell-session
$ docker run -itd --name jupyter -p 8888:8888 -p 6006:6006 -v 同期したいディレクトリの絶対パス:/root/notebook -e PASSWORD=パスワード enakai00/jupyter_tensorflow:0.9.0-cp27
```

`-v`はマウントするディレクトリです。jupyterで実行するファイルなど置いているところを絶対パスで指定します。
`-e`は環境変数設定です。jupyterログイン時のパスワードを設定しています。

起動できたら http://localhost:8888/ にアクセスできると思います。

## コンテナ起動

```shell-session
$ docker start jupyter
```

## コンテナ停止

```shell-session
$ docker stop jupyter
```
CentOS7.2 httpdの設定

centos7.2にapacheをインストールしてwebサーバーを構築したときのメモ

バーチャルドメイン（複数ドメイン）の構築はこちら
https://qiita.com/salt_field/items/31acb1cbb707102e0702

#環境
Centos7.2
apache2.4

#１．各パッケージアップデート

```
yum update
```

#２．Apacheインストール

```
yum install httpd
```

#３．設定変更
必要に応じて読み替えてください。

```/etc/httpd/conf/httpd.conf
#ServerName www.example.com:80
↓
ServerName centossrv.com:80　←　サーバー名を指定

<Directory "/var/www/html">

#
# Possible values for the Options directive are "None", "All",
# or any combination of:
#   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
#
# Note that "MultiViews" must be named *explicitly* --- "Options All"
# doesn't give it to you.
#
# The Options directive is both complicated and important.  Please see
# http://httpd.apache.org/docs-2.0/mod/core.html#options
# for more information.
#
    Options Indexes FollowSymLinks
　　↓
    Options Includes ExecCGI FollowSymLinks　←　CGI,SSIの許可

#
# AllowOverride controls what directives may be placed in .htaccess files.
# It can be "All", "None", or any combination of the keywords:
#   Options FileInfo AuthConfig Limit
#
    AllowOverride None
　　↓
    AllowOverride All　←　.htaccessの許可

#
# The following directives define some format nicknames for use with
# a CustomLog directive (see below).
#

AddDefaultCharset UTF-8
↓
#AddDefaultCharset UTF-8　←　コメントアウト(文字化け対応)

#AddHandler cgi-script .cgi
↓
AddHandler cgi-script .cgi .pl　←　CGIスクリプトに.plを追加
```

##ファイル一覧を表示しないようにする。

```/etc/httpd/conf.d/autoindex.conf
<Directory "/usr/share/httpd/icons">
    Options MultiViews　←　iconsディレクトリのファイル一覧を表示しないようにする
    AllowOverride None
    Require all granted
</Directory>
```

##テストページの削除

```
rm -f /etc/httpd/conf.d/welcome.conf
```

##Perlコマンドへ/usr/local/bin/perlでもアクセスできるようにする。
```
ln -s /usr/bin/perl /usr/local/bin/perl
```

##ドキュメントルート所有者を変更

```
chown [一般ユーザー名]. /var/www/html/
```

#４．サーバー起動

```
systemctl start httpd
systemctl enable httpd
```

#５．firewalldの設定
このままだとfirewallでポートが閉じているためアクセスできない。
そのため80番ポートを開放しアクセス可能にする。

```
firewall-cmd --add-service=http --zone=public --permanent
firewall-cmd --reload
```

http://[サーバーのアドレス]/
にアクセスするとドキュメントルートのhtmlが見えるはず。
誤字脱字・間違いがありましたらご指摘ください。

>引用
この記事は下記ホームページを参考にさせていただきました。
https://centossrv.com/apache.shtml
Geb使う時のアンチパターン

# はじめに

これは[Geb Advent Calendar 2016](http://qiita.com/advent-calendar/2016/geb)の1７日目の記事です。
前日は[Gebでいきいき塾のページを自動化してみた](http://qiita.com/PoohSunny/items/479a0080723f21c4dd6d)でした。

# Gebのアンチパターン
Seleniumもそうですが、何事も使う上ではアンチパターンと呼ばれるものがあります。今回は私がGebで書かれたコードを見る中で感じるアンチパターンをまとめてみました。
Seleniumというか、ブラウザ操作全般についてのアンチパターンといったものは省いています。Seleniumについてであれば、下記のエントリーが参考になります。

- [Selenium Antipatterns](http://www.slideshare.net/miyajan/selenium-antipatterns)

## エレメントが隠蔽されずテストケースで利用されすぎる
例えばログインの自動化で、下記のようなコードがあったとします。[^1]

```groovy
Browser.drive {
    to LoginPage

    username.value("admin")
    password.value("p4sw0rd")
    loginButton.click()

    assert page instanceof AdminPage
}
```

こちら、ログインするにはユーザーの入力欄と、パスワードの入力欄が必要で〜といった、ログイン画面の内容そのものをテストしたいのであれば話は別なのですが、ただ単にログインという処理は途中経過で、他の前提条件になるような場合であれば、まとまった処理はページオブジェクト内に隠蔽し下記のように書いたほうが良いです。

```groovy
Browser.drive {
    to LoginPage
    
    login("admin", "p4sw0rd")

    assert page instanceof AdminPage
}
```

こうすると、ログイン画面に何か変更があった際にも影響が少なくて済みます。
Gebはcontentが簡潔に書けてしまうので、ページオブジェクト内のcontentをついテストケース側で呼びがちになってしまうのですが、まとまった処理はなるべく隠蔽した方が良いですね。下記のスライドも参考になると思います。

- [脱・独自改造！ GebでWebDriverをもっとシンプルに](http://www.slideshare.net/hirokotamagawa/20141018-2selenium-40423299)

## パラメタライズの件数が多すぎる
例えばこんなケース、ログインに失敗した時にエラーメッセージが正しく出るかをチェックしています。

```groovy
class LoginFailureSpec extends GebReportingSpec {

    def "ログインに失敗した時に#errorMessageが表示される"() {
        given: "ログインページにいる"
        to LoginPage
        at LoginPage

        when: "ログインに失敗すると"
        login("user-id", failurePassword)

        then: "ページ遷移せず"
        at LoginPage

        and: "${errorMessage}というエラーメッセージが表示される"
        message == errorMessage

        where:
        failurePassword || errorMessage
        "wrong"         || "ユーザーIDもしくはパスワードが間違っています"
        "expired"       || "パスワードの有効期間が切れています"
        "locked"        || "アカウントがロックされています"
    }
}
```

これはGebと言うよりSpockの話なのですが、Unrollの昨日が強力すぎで、ついついパターンをUnrollでいっぱい書いてしまいがちになるのです。
ただ、当然ブラウザの自動化は実行時間がかかりますし、その他のレベルのテスト（ユニットテストなど）で担保したいものが満たせるのであれば、そちらでテストを書くことも検討しましょう。

# Textでエレメント取得してしまう
これは古いバージョンだとって感じですが、過去エントリーで詳しく書きました。

- [Gebでtextやtitleでのエレメント取得は遅くなる！？](http://qiita.com/PoohSunny/items/c5beac800c2aaab73e6b)

# 画面のユニットテストになってしまう
これはコンテクストに強く依存するのでアンチパターンというかというと微妙だと思うのですが、例えば何かのボタンを押した際に、エレメントのクラス属性が変化するよね、みたいなテストをすることです。

近年だと、テストを標準装備で考えられたフロントエンドのフレームワークは山ほどあるので、そちらのテストでカバーできることはそちらでしたほうが良いと思います。
かくいう私も昔AngularJSでフロントエンドのコードを書いていて、細かい画面制御のテストをGebで書いて後で後悔したことがあります（のちに大部分はフロント側のユニットテストに移した）。Geb慣れてるしー、エレメント取得しやすいしー、Angular習得コスト高いし、とか言ってました本当にすいませんでした（懺悔）

# まとめ
こう見てくると、<b>目的をきちんと意識して、それにGebが一番フィットするときに使いましょう</b>って話な気がしますね。
やってみないと気づかないことも多々あると思いますので、たまに自分たちのGebコードを振り返ってみてもいいかもしれません。

[^1]: http://www.gebish.org/manual/current/#at-checking から引用しています。
GoでCIDRブロック内にIPが含まれているか判定

Goで、CIDRブロック内に指定IPが含まれているか判定するスニペット

string型の`cidr`, `ip`を渡して、含まれているかをboolで返す。

```go:cidr.go
package cidr

import (
	"log"
	"net"
)

// isIncluededInCIDR reports whether the cidr includes the given ip.
func isIncluededInCIDR(cidr, ip string) bool {
	_, cidrNet, err := net.ParseCIDR(cidr)
	if err != nil {
		log.Fatal(err)
		return false
	}

	targetIP := net.ParseIP(ip)
	return cidrNet.Contains(targetIP)
}
```
Heroku new CLI 

# 新しい CLI
[Heroku の 新しい CLI](https://github.com/heroku/cli) が出たので、変更点を確認したく、[リリースの公式ブログ](https://blog.heroku.com/the-new-heroku-cli)を読んでみた。


# 速度改善
実行にかかる時間が結構遅かったのが、改善した。ある結果では、UNIXで1690msから1210msへ高速化、Windowsでは3409msから944msへ高速化した。

# Grep しやすくなった
[行指向になって、grep などでフィルタリングしやすくなった。](https://blog.heroku.com/the-new-heroku-cli#grep-parseable-output)

# JSON
古いCLIでは、実行結果を JSON で取得するためのオプションがコマンドによって、 `--format json` だったり `--json` だったり、そもそも json で結果を取得できないコマンドなどもあった。新CLIでは 多くのコマンドで `--json` で JSON にて結果を取得できるようになった。これで `jq` コマンドなどと組み合わせて実行結果をフィルタリングしやすくなった。

# `heroku` コマンドでダッシュボード確認

各 app の状況などの概観を確認するために`$heroku` （引数なしで実行）を利用するユーザーが多かったため、ダッシュボード的な結果を取得できるように `heroku` コマンドを改善した。`heroku notifications --read` とかやっていると結構いろいろ書いてあったりする。

#タブキー押下による入力補完
こちらまだ開発中らしいですが、タブキーによる入力補完を導入予定とのこと。

とりあえずこんな感じでー。
Qt Creator on Macでショートカットを変更する


今日、初めてQtをMacで動かしました。とても、使いやすそうだなと思ったのですが、ひとつ気になることがありました。 **行頭に戻る、一行削除するなどのMacのキーバインドがデフォルトでは使えなかった** のです。

このままでは使いづらいツールになってしまうかも！と思いましたが、調べたらすぐにでてきました。

## ショートカットを変更する

**Preferences > Environment > Keyboard** でキーボードショートカットの一覧が出てきます。ここで、様々なショートカットの変更ができます。

![Preferences_と_main_cpp_-_first-qt_-_Qt_Creator.png](https://qiita-image-store.s3.amazonaws.com/0/24041/576b6135-13b6-31fe-5cb7-4b89f6e10614.png "Preferences_と_main_cpp_-_first-qt_-_Qt_Creator.png")

僕の場合はとりあえずは、行頭に移動（ `^A` ）、行末に移動（ `^E` ）、行末まで削除（ `^K` ）が出来れば良いと思ったのでその変更をしました。

## 実際の変更手順

### 変更したいショートカットを検索

![Preferences_と_main_cpp_-_first-qt_-_Qt_Creator.png](https://qiita-image-store.s3.amazonaws.com/0/24041/4f3914c0-7522-c5af-5e8b-92effb20c56c.png "Preferences_と_main_cpp_-_first-qt_-_Qt_Creator.png")

ショートカットコマンド名はそれぞれ、

- 行頭に移動: GoToLineStart
- 行末に移動: GoToLineEnd
- 一行削除: DeleteLine

でした。カーソル位置から行末まで削除というのは見当たらなかったのですが、一行削除ができれば十分です。

## 登録したいショートカットを入力

変更したいショートカットコマンドを選択し、ウィンドウ下部の **Record** ボタンを押してショートカットを入力します。

これで完了です！！


## 思ったこと

上記のコマンドは全て初期設定ではショートカットが登録されていませんでした。Macの場合、ここにMacのEmacsキーバインドを入れておくだけで、最初の印象がもっと良くなるのになぁと思いました。

## 参考

- [Keyboard Shortcuts | Qt Creator Manual](http://doc.qt.io/qtcreator/creator-keyboard-shortcuts.html)
jubatusでおすすめのいらすとをレコメンドしてみた

この記事は[jubatus advent calendar](http://qiita.com/advent-calendar/2016/jubatus) 17日目の記事です．
今回はjubatusで[いらすとや](http://www.irasutoya.com/)のいらすとをレコメンドしてみることにしました．

# なんでそんなことをしようと思ったのか

好きなんですよ．いらすとや．

<br>
<br>
<br>

もう少し言うと，いらすとやさんのいらすとはすごい豊富な品揃えで面白いものも多いんですが，それらに出会うためのいい方法があまりないのが不便でした．そこで，jubatusでいい感じにいらすとやサーフィンを楽しむツールができないかなぁと思って試してみました．

# サービス

~~こちらで動かしています．2016年12月25日までは動かす予定です．~~
(追記) 現在はサービスを停止中です。

## 仕組み

FlaskとJubatusでちょちょいと作っています．

使っているのはjubatusのrecommenderで，これはjubatusに学習させたデータの中から類似したデータを探してくる機能を提供します．今回はいらすとやの各エントリのタイトル，説明文，イラストの画像を学習させています．
タイトルは文字列のbi-gram(2文字区切り)，説明文は文字列のtri-gram(3文字区切り)，画像はORBで特徴抽出をしています．
近傍を探す方法は`inverted_index`という転置インデックスを用いてデータ間のコサイン類似度を求める方法を使っています．

ソースコードは[こちら](https://github.com/TkrUdagawa/advent_calendar/tree/master/irasutoya)で公開しています．が，jubatusのモデルとデータセットはリポジトリに置いていないので，各自作る必要があります．

## 動作

トップページにアクセスすると以下のような画面が出てきます。

![top_small.png](https://qiita-image-store.s3.amazonaws.com/0/32245/5487c2e2-2278-8877-18bb-df45f7298316.png)


"title", "text", "img file"の3つのフィールドがあり，それぞれ類似度計算に使う"タイトルの文章"，"説明文"，"いらすと"を指定します．使うフィールドは一部でも全部でもいいんですが，今回は私の顔写真をいれてみます．

![face.png](https://qiita-image-store.s3.amazonaws.com/0/32245/335bec9d-fdd3-6083-f2f6-64ef263961c5.png)

こんな感じです．実際のクエリ画像は目線を外しています．
`recommend num`を今回は10に設定して，`recommend`ボタンをポチッとすると...

![result_10.png](https://qiita-image-store.s3.amazonaws.com/0/32245/e409c97f-0f72-a266-b642-b123976ad228.png)

上の図のようにjubatusが類似したと思う画像を探してきてくれます．
どうやら私の顔はゴキブリのイラストに近いようですね．．．

右側にある"more recommend"というボタンを押すと，今度はここに表示されているエントリのタイトル，本文，画像を使って類似したエントリを探してきてくれます．ゴキブリのイラストでさらにレコメンドしてみます．

![result_g.png](https://qiita-image-store.s3.amazonaws.com/0/32245/b1bdbf94-b3d0-30c1-2e28-eaf04c818cad.png)

なんともよくわからない結果ですね．文章があまり似ていないところを見ると，どうやらかなり画像の類似度に引っ張られているように思います．なんとなくゴキブリと似たシルエットの画像が引っ張られてくることを期待していたのですが，意外とそうでもなさそう？


もうちょっと簡単そうな画像ということで，いらすとやのアルトサックスの画像をクエリにした結果が以下の通りです．
![res_sax.png](https://qiita-image-store.s3.amazonaws.com/0/32245/30f20b0c-125c-4bf8-6881-04321f8cf4de.png)

なんとなく似た形の物が拾えていそうです．

ちなみに本家サイトのアルトサックスのページで表示される関連イラスト等はこちらです(2016/12/17時点)．

![res_sax_original.png](https://qiita-image-store.s3.amazonaws.com/0/32245/d434c62d-b276-ad2d-9bbe-75b0a2d403a7.png)

こちらはカテゴリ情報を使って同じカテゴリに入っているイラストを取ってきているみたいですね．今回の場合は"リクエスト"というカテゴリに入っている最新のものを表示しています．同じカテゴリの画像を見たいときにはカテゴリの検索で十分ですが，似た形のものを探すにはjubatusを使ったほうが有効そうです．


# おわりに

今回はJubatusのrecommenderを使っていらすとやの中から類似したエントリを探してくるアプリケーションを作ってみました．シンプルな画像なら割と似たような画像を探してこれました．一方で，複雑な画像になるとちょっとよくわからない感じになってしまいました．本来の自分の狙いはちょっとよくわからない結果が返ってくるくらいがちょうど良いので，おもちゃとしては使えそうという感想です．

心残りなのはせっかくjubatusを使っているのにオンラインでアップデートさせる機能をつけていないことです．現在は私がデータを収集した201612/10頃までのデータしか入っていません．気が向いたら直します．

余談ですが，Jubatusの画像プラグインにはRGB値を使って画像の類似度を測る手法も実装されています．今回そっちでもモデルを作って同時に起動しようと思ったのですが，非常にメモリを食ってしまった(RGBモデル起動で3GB程度)ので断念しています．recommenderは元のdatumを保持するので余計にメモリを消費してしまいます．近傍を探す機能だけだったらnearest_neighborを使ったほうが良かったかもしれません．今回はパラメータチューニングが嫌だったのでinverted_indexが使えるrecommenderを選んでいました．

さて，明日は[\_\_john_smith\_\_](http://qiita.com/__john_smith__)さんがなんか書いてくれます．\_\_john_smith\_\_さんは毎回コミュニティイベントに参加してくださり，面白い発表で会場を盛り上げてくれます．今回は一体どんな記事を書いてくれるかとても楽しみです．
Slack × hubotで笑いをとる

この記事は[NIFTY Advent Calendar 2016](http://qiita.com/advent-calendar/2016/nifty) 17日目の記事です。
昨日は@qracさんの[リメイクUIコーディング](http://qiita.com/qrac/items/df9247d8952ba67aadf9)という記事でした。

# はじめに

あれは入社一年目でまだ新人の頃です。とある先輩から言われました。

**先輩「chatbot入れたんだけどさ〜、何か面白いこと言うようにしておいて」**
私「え？ は、はい」

果たしてどこまで本気だったのかわかりませんが、ピュアだった私は真面目に面白いことを言わせようとするのでした。。。

# パターンマッチングで笑いをとる

ちょうど[恋するプログラム](https://www.amazon.co.jp/dp/4839917299)という人工無脳について書かれた素晴らしい本を持っていたので、この本を参考にパターンマッチングで応答する`talk.coffee`を書きました。

```
scripts
├── talk
│   ├── pattern.txt
│   └── random.txt
└── talk.coffee
```

このコードはpattern.txtに正規表現と返答の組み合わせを`正規表現<tab>返答`の形式で登録しておいて、正規表現にマッチした場合は登録された内容を返します。

```
はよ|おっはー|オッハー        %user%さんおはようございます！|%match%|おっはー\
|グッドモーニング！
(今晩|こんばん)(は|わ)  こんばんは
お(休|やす)み|オヤスミ  お休みなさい|今日はゆっくり休んでくださいね
```

もしマッチしなかった場合はrandom.txtに登録した内容をランダムに返すというものです。

コードは置いておいて、重要なのは登録内容です。

パターンマッチングでは、みんなが言うわけではないけれど、特定の人だけたまに言う事を登録しておく事がポイントです。

なぜか「おはヨーグルト」と挨拶する面白い先輩がいたので、それに反応するようにしました。

<img width="736" alt="スクリーンショット 2016-12-17 13.16.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/107806/0bd9dd9c-babf-af15-6a83-2c6669c786f3.png">

すると、こんな言葉の場合もちゃんと用意してあるんだ、と笑いが取れます。

パターンにマッチせず、ランダムに返す場合はパワーワードや時事ネタを入れると面白くなります。

当時はLINEの乗っ取りが流行っていたので、「近くのコンビニでiTunesカードを買うのを手伝ってもらえませんか？」と返したら笑ってもらえました。

# 勝手に反応して笑いをとる

話しかけた時に返してくれる機能ですが、正直よっぽど暇な人でない限り話しかけようとはしません。
そんな場合は勝手にワードを拾って反応しましょう。

これも`pattern.txt`に登録された内容を返すものなのでポイントはパターンマッチングの時と同じです。

挨拶に反応して返してくれるような普通の使い方もできます。

<img width="739" alt="スクリーンショット 2016-12-17 14.35.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/107806/5b612b36-8a10-337a-0790-449de238f0f0.png">

誰も反応してくれないと寂しいのでありがたい機能です。

# 役に立たない機能で笑いをとる

chatbotといえばgitのbranchをビルドさせたりredmineのチケットを取得したりと色々便利な機能が思いつきますが、あえて、おおよそ役に立たないであろう今日の六曜を教えてくれるコマンド`rokuyo.coffee`を実装しました。
内部では暦API（http://koyomi.zing2.org/ ）というAPIを使わせていただいてます。

トラブルが多発した時なんかに聞いてみると

<img width="738" alt="スクリーンショット 2016-12-17 13.26.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/107806/cad2793a-d8ae-dfd9-4092-0dd2e22ce114.png">

やっぱりかー！となります。

# おわりに

ブルーマンデーと揶揄される月曜の朝など、ちょっとした笑いで気持ちよく仕事に入っていけることもあると思います。
不適切にならないレベルを見極めつつ、笑いを取っていきましょう！

今回紹介したコードはgithubにありますので、よかったら使ってみてください。
https://github.com/teitaraku/hubot-scripts

明日は@yt09191971さんの「プログラミングレスでIoTデバイスハブのデータをData Visualizer (β)に表示させる」です。楽しみです！
deinに乗り換えよう（第二段階）

# 前提条件

- MacOS ElCapitan 10.11.6
- vim8.0
- homebrew

# 今回の作業

さて先日導入したdein.vim
プラグインを管理するためなので、次はプラグインを入れていく作業
まずは

- neocomplete
- nerdtree

から。ついでにdein.vimを自動で入れる記述も追加。

# 手順

## neocomplete

neosnippetは最初に入れたので、次はneocomplete(スニペットの補完)

```
$ vi .vimrc
・・・略
call dein#add('Shougo/neosnippet-snippets')
call dein#add('Shougo/neocomplete.vim')
・・・略
```

で、もう一度viを開くと

```
[dein] Not installed plugins: ['neocomplete.vim']
[dein] Update started: (2016/12/17 14:39:44)
[dein] (1/1) |neocomplete.vim     | git clone --recursive https://github.com/Shougo/neocomplete.vim.git "/Users/MineDir/.vim/dein/repos/github.com/Shougo/neocomplete.vim"
[dein] (1/1) [====================] neocomplete.vim
[dein] (1/1) |neocomplete.vim     | Updated
[dein] (1/1)  -> 9af19a78e381a13513851d222c17be1bd2679f7e
[dein] Updated plugins:
[dein]   neocomplete.vim(1 change)
[dein] Done: (2016/12/17 14:39:48)
Press ENTER or type command to continue
```

これ超簡単じゃないですか？！（今更）

## nerdtree
次は、ファイルツリーを表示するためにnerdtree

```
$ vi .vimrc
・・・略
call dein#add('scrooloose/nerdtree')
・・・略
```

もう一度viを開き直すと

```
[dein] Not installed plugins: ['nerdtree']
[dein] Update started: (2016/12/17 14:48:32)
[dein] (1/1) |nerdtree            | git clone --recursive https://github.com/scrooloose/nerdtree.git "/Users/MineDir/.vim/dein/repos/github.com/scrooloose/nerdtree"
[dein] (1/1) [====================] nerdtree
[dein] (1/1) |nerdtree            | Updated
[dein] (1/1)  -> eee431dbd44111c858c6d33ffd366cae1f17f8b3
[dein] Updated plugins:
[dein]   nerdtree(1 change)
[dein] Done: (2016/12/17 14:48:36)
Press ENTER or type command to continue
```

これ超簡単(・・・以下略）

## dein.vimの自動インストール設定

dein.vimが入ってない環境で自動的にインストールさせる設定を追加して

```
let s:dein_dir=expand('~/.vim/dein')
let s:dein_repo_dir=s:dein_dir . '/repos/github.com/Shougo/dein.vim'

if &compatible
  set nocompatible               " Be iMproved
endif

if !isdirectory(s:dein_repo_dir)
  execute '!git clone git@github.com:Shougo/dein.vim.git' s:dein_repo_dir
endif

" Required:
execute 'set runtimepath^=' . s:dein_repo_dir

" Required:
call dein#begin(s:dein_dir)

" Let dein manage dein
" Required:
call dein#add('Shougo/dein.vim')

" Add or remove your plugins here:
call dein#add('Shougo/neosnippet.vim')
call dein#add('Shougo/neosnippet-snippets')
call dein#add('Shougo/neocomplete.vim')
call dein#add('scrooloose/nerdtree')

" You can specify revision/branch/tag.
call dein#add('Shougo/vimshell', { 'rev': '3787e5' })

" Required:
call dein#end()

" Required:
filetype plugin indent on
syntax enable

" If you want to install not installed plugins on startup.
if dein#check_install()
  call dein#install()
endif
```

viをもう一度開き直して、エラーにならないのを確認。
これで他の環境でもdein入れるの超簡単（・・・以下略）
Python で requests を使って Slack にログインする

#使用するモジュール
- **requests**
  - HTTP/HTTPS 通信を行うためのクライアント
    - https://github.com/request/request
- **beautifulsoup**
  - HTMLとXMLのパーサー
  - https://www.crummy.com/software/BeautifulSoup

全体のコード

```py
from bs4 import BeautifulSoup
import requests
import re

TEAM_NAME = "hoge"

payload = {
    'signin': "1",
    'email': 'email',
    'password': 'password'
}

login_url = 'https://%s.slack.com/' % TEAM_NAME

# ログインページにアクセス
session = requests.Session()
response = session.get(login_url)

# crumb の取得
bs = BeautifulSoup(response.text)
auth_token = bs.find(attrs={'name': 'crumb'}).get('value')
payload['crumb'] = auth_token

# ログインする
session.post(login_url, data=payload)
```
Postfixでユーザー名の記号が使えないとき

[Server World - Postfixの設定](https://www.server-world.info/query?os=Ubuntu_14.04&p=mail&f=1)のページを参照して設定を行い、例として
```hoge.example@example.com```というメールアドレスに送信すると、デリバリーサービスから、
```Recipient address rejected: User unknown in local recipient table```
と言われ、受信拒否。
ちなみに記号がない場合は受信できた。
いろいろと調べた結果、
> \# 209行目：コメント解除
> local_recipient_maps = unix:passwd.byname $alias_maps
>> https://www.server-world.info/query?os=Ubuntu_14.04&p=mail&f=1 より引用

これが原因と判明。
おそらくこの設定だと```.```を何か勘違いをして受信をしてくれないのだろう。
これの解決方法は、
```local_recipient_maps = proxy:unix:passwd.byname $alias_maps```
と変更すると受信できた。
なしに設定するのも悪くなかったが、それだと望ましくなかったため、この設定にした。
今回は```.```が使えない現象だったが、```-```や```_```をテストしていない為、使えるかどうかは不明。
phina.jsでTiledMapEditorを利用する

この記事は[phina.js Advent Calendar 2016](http://qiita.com/advent-calendar/2016/phinajs)の記事です。
昨日→[Collisionクラスを使った当たり判定 by alkn203さん](https://alkn203.github.io/blog/2016/12/16/phina-advent-16th/)
明日→[phina.jsとWebGLでいろいろ by daishi_hmrさん](http://github.dev7.jp/b/2016/12/22/phinajsadvcal20161218/)

皆様、１２月に入り一層冬めいてまいりましたが、いかがお過ごしでしょうか。
そんな、寒くなってきた折も折、phina.jsでTiledMapEditorのデータを使えるようにしてみた私でございます。
（phina.jsには無かったようなので、tmlib.jsから移植しました。）

#Tiled Map Editorとは
[Tiled Map Editor](http://www.mapeditor.org/)は、マップチップをタイル状に貼って、マップを作成する高機能なマルチプラットフォームのツールです。
この系統のツールは正しくはレベルエディタというらしいです。
![スクリーンショット 2016-12-17 15.01.34.png](https://qiita-image-store.s3.amazonaws.com/0/31052/bac68202-419a-fddc-9e04-108046118a87.png)
こんな感じでマップの作成が出来ます。
ツールの使い方はこちらに詳しい解説がありました。
http://haxeflixel.2dgames.jp/index.php?TiledMapEditor

#使い方
プラグインの使い方は簡単です。
プラグインを読み込み、TiledMapEditorで作成した、`.tmx`を他のアセットと同じようにロードします。

```JavaScript:単体で読み込む場合
var tmx = phina.asset.TiledMap();
tmx.load('.tmx path');
```

```JavaScript:LoadingSceneを使う場合
var options = {
    assets: {
        tmx: {
            "map": ".tmx path",
        },
    },
};
var scene = LoadingScene(options);
```


読み込みが終了した後は、画像を取得してスプライトで表示する事が出来ます。

```JavaScript:画像として取得
//全レイヤーを重ね合わせた画像を取得
var image = tmx.getImage();

//特定のレイヤーのみの画像を取得する
var image = tmx.getImage("LayerName");

//取得した画像をスプライトで表示
var sprite = Sprite(image);

```

マップの生データを使用したい場合は、一次元配列で取得する事が出来ます。

```JavaScript:マップデータの配列を取得
//一次元配列
var mapdata = tmx.getMapData("LayerName");
```

```JavaScript:オブジェクトグループを配列にして取得
var group = tmx.getObjectGroup("ObjectGroupName");
```

#使ってみましょう
実際にこのプラグインを使ってＲＰＧっぽいサンプルを作成しました。
[TiledMapEditorサンプル](https://minimo.github.io/phina.js_advent_2016_2/)
カーソルキーで移動、ZキーでNPCに話しかけられます。
ちょっと雑な上に凝り過ぎて無駄に長いですが、今回のお題で重要なのは以下の部分です。

```JavaScript:マップ読み込み
    //.tmxファイルからマップをイメージとして取得し、スプライトで表示
    this.tmx = phina.asset.AssetManager.get("tmx", "map");
    this.map = phina.display.Sprite(this.tmx.image)
      .setOrigin(0, 0)
      .setPosition(0, 0)
      .addChildTo(this.mapBase);
```
マップの表示はこの様に行ってます。

```JavaScript:マップ上の衝突判定
    //マップデータから'Collision'レイヤーを取得
    var collision = this.tmx.getMapData("collision");

    //指定座標にマップチップがあると真を返す
    var chip = collision[mapy * this.tmx.width + mapx];
    if (chip !== -1) return true;
```
マップ上の進入不可なブロックは`collision`という名前をレイヤーを作成して非表示にして判定を行っています。


```JavaScript:マップ上にNPCを追加
    //オブジェクトグループの取得
    this.npc = this.tmx.getObjectGroup("NPCGroup");
    this.addNPC();
```
NPC情報をオブジェクトグループで登録し、それをマップ上に反映させています。


#おしまい
マップ作成はゲームを作る上で重要ですが、結構時間が掛るため、こういったツールを効率良く活用していきたいですね。
サンプルのソースはこちらから[GitHub](https://github.com/minimo/phina.js_advent_2016_2)
phina.tiledmap.jsを読み込むと使える様になります。
突貫で作ったので色々雑ですが、おおまかな使い方は踏まえております。

サンプルに[ぴぽや](http://piposozai.blog76.fc2.com/)さんのマップチップを使用しています。
ありがとうございます。
delay timeが0のgifアニメーションはブラウザでどのように表示されるのか？

delay timeとはgifアニメーションの各フレームごとの表示間隔のことだが、これは通常だと0より大きい正の値が設定される。

delay timeは **Graphics Control Extension** というセクションに設定されており、内2バイトを利用する。

バイナリエディタなどで適当なgif画像を開いて、 **21 F9** からはじまるバイト列を探し、21から5バイト目と6バイト目がちょうどdelay timeの設定箇所である。

10fpsなら **10 00**、20fpsなら **05 00**と設定されているはず。

ところで、たまにgif画像のメタデータを読むことがあるのだが、delay timeが **00 00** と設定されていることがある。

これはそのまま解釈すると各フレームごとの表示間隔が0msなのでつまり静止画状態でアニメーションしないのではないか？と思ってしまう。

しかし、実際はどのブラウザでもアニメーションとして表示される。

例えばこれはdelay timeが0のgifだ。

![original_nodelay_0.gif](https://qiita-image-store.s3.amazonaws.com/0/13609/02e07854-d225-01de-50cb-11be304172f5.gif)

なぜアニメーションするのか。

理由は、各ブラウザが各々delay timeの下限を設けているからだ。

下記のgif一覧をみてほしい。これらは同じgifをdelay timeを変えて並べたものである。

## 100ms
![100ms.gif](https://qiita-image-store.s3.amazonaws.com/0/13609/5265fd03-0057-2f7e-ca29-337136d434ef.gif)

## 60ms
![60ms.gif](https://qiita-image-store.s3.amazonaws.com/0/13609/24552c80-4dd0-5a80-4860-0c01d999bb13.gif)

## 50ms
![50ms.gif](https://qiita-image-store.s3.amazonaws.com/0/13609/2556d660-10eb-d289-6c60-ace445cdaa9e.gif)

## 40ms
![40ms.gif](https://qiita-image-store.s3.amazonaws.com/0/13609/f5bfedc1-bb71-c7e1-e59c-43a9800f490e.gif)

## 30ms
![30ms.gif](https://qiita-image-store.s3.amazonaws.com/0/13609/a1b66f66-937e-68e9-163f-d4347909f7e3.gif)

## 20ms
![20ms.gif](https://qiita-image-store.s3.amazonaws.com/0/13609/fc6fa0ad-f346-9e7b-39d8-148deed33333.gif)

## 10ms
![10ms.gif](https://qiita-image-store.s3.amazonaws.com/0/13609/4f6eec21-71f1-40ff-fe07-13efc5341070.gif)



ズラッとみると気づくと思うが、もしあなたが最新のChrome,Safari,Firefox,Opera,IEを使っているなら10msのgifと100msのgifが同じ動きをしているとわかるだろう。

これは上述の通り、各ブラウザがdelay timeの下限を20msあたりに設定していて、それ以下のdelay timeのときは100msをデフォルトとして使っているということだ。

よって、表題の「**delay timeが0のgifアニメーションはブラウザでどのように表示されるのか？**」の解答としては「ブラウザごとの仕様によって表示のされ方は変わる。ただし2016年現在、大抵の最新ブラウザではdelay timeが0のときdelay time100msがデフォルト値として利用される。」となる。

なお、[こちらの記事(Animated GIF Minimum Frame Delay Browser Compatibility Study)](http://nullsleep.tumblr.com/post/16524517190/animated-gif-minimum-frame-delay-browser)では2012年時点でのdelay timeのブラウザ比較を読むことができる。IEとSafariはdelay timeの下限が60msだったようだ。