OmniAICreator/Qiita-1.07M huggingface dataset:
cAdvisorとprometheusをSingle Nodeで連携させてみた

Dockerのモニタリング等って最近はどういうのがあるのかな、と見ていたらcAdvisor([^1])を見かけました。

InfluxDB, Grafanaと連携させて可視化もできるようです。([^2])

InfluxDB使いたいなー、と思いつつ、直近はprometheusに慣れていきたいので、連携できるか見てみました。
ぐぐってみるとすでに実装している人がいますね。

* https://www.ctl.io/developers/blog/post/monitoring-docker-services-with-prometheus/

すなおに写経してみようと思います。

## 実施順

### 1. cAdvisorコンテナを起動

```bash
sudo docker run -d \
  -v /var/run:/var/run:rw -v /sys:/sys:ro -v /var/lib/docker/:/var/lib/docker:ro \
  -p 8080:8080 --privileged --name=cadvisor_with_influxdb \
  google/cadvisor:latest
```

### 2. prometheus.ymlを用意

prometheusがメトリクス収集をするためのエンドポイントを設定します。
ここで、AWS環境を利用していたのでVPCのプライベートIPアドレス、および、１．で指定したcAdvisorの8080ポートを指定しました。

すると、[プライベートIP:8080/metrics]から収集した情報を蓄積・可視化してくれるようです。

```prometheus.yml

global:
  scrape_interval: 15s # By default, scrape targets every 15 seconds.
  evaluation_interval: 15s # By default, scrape targets every 15 seconds.
  # scrape_timeout is set to the global default (10s).

  # Attach these extra labels to all time-series collected by this Prometheus instance.
  #labels:
    #monitor: 'panamax-monitor'

rule_files:
  - '/etc/prometheus/alert.rules'

# A scrape configuration containing exactly one endpoint to scrape:
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.

  # Panamax
  - job_name: 'panamax'
    scrape_interval: 5s

    # Override the global default and scrape targets from this job every 5 seconds.
    scrape_interval: 5s
    scrape_timeout:  3s

    target_groups:
      - targets: ['プライベートIP:8080']
        labels:
          group: 'development'
```

### 3. alert.ruleを追加

ここはまだ深堀していません。下記のように丸コピしました。

```text
ALERT pmx_down
  IF up == 0
  FOR 5m
```

### 4. prometheusサーバの起動

下記のように起動しました。
alertmanager.urlで、パブリックIPを指定しました。[0.0.0.0]や[localhost]を指定すると怒られました。地味に賢いですね。。

```run-prometheus.sh
docker run -i -p 9090:9090 \
              -v $PWD/prometheus.yml:/etc/prometheus/prometheus.yml \
              -v $PWD/alert.rules:/etc/prometheus/alert.rules \
              prom/prometheus \
              -config.file=/etc/prometheus/prometheus.yml \
              -alertmanager.url=http://${AWSのパブリックIP}:9093
```

### 5. UIを見てみた。

４．で指定したUIを参照すると以下のようにメトリクス収集された結果を確認できました。

![Screenshot from 2016-04-21 14-58-54.png](https://qiita-image-store.s3.amazonaws.com/0/49547/8894410a-e87e-ffa8-89f9-80ab31a9ec83.png)


## 参考（というかTODO）

* cAdvisorじゃできないこと（マルチホストの収集と可視化）を実装
* prometheusのデータ層等の隔離
* alert設定の方法の確認。https://prometheus.io/docs/alerting/rules/
* exporterという概念もあり、下記のようなコマンドが紹介されています。

```bash
docker run -d --name PROM_CON_EXP \
  -p 9104:9104 \
  -v /sys/fs/cgroup:/cgroup -v /var/run/docker.sock:/var/run/docker.sock \
  prom/container-exporter
```

* https://prometheus.io/docs/instrumenting/exporters/

上記サイトを見ると、他のサードパーティ群に対応したものも多数あるようです。
概念理解と使えそうならごりっと導入もしていきたいところです。


InfluxDBも使ってみたい

* http://davidanguita.name/articles/simple-data-visualization-stack-with-docker-influxdb-and-grafana/


## 引用

[^1]: https://github.com/google/cadvisor
[^2]: [cAdvisor, InfluxDB, GrafanaでDockerコンテナのリソース監視](http://qiita.com/atskimura/items/4c4aaaaa554e2814e938)
Xamarinでビルドしたアプリを実機で実行した時困ったこと

[ビルド]-[ソリューションの配置]で.apkを作成し実機で試したところ
「パッケージの解析中に問題が発生しました」と出てインストール出来なかった。

色々調べてみてandroid:minSdkVersionを設定してみたり、Gmailで送らずにGoogle Driveで送ってみたりしたが駄目だった。。。

何の気なしに.apkと一緒に生成されていた「～-Signed.apk」を入れてみて実行するとインストールが成功！！

なぜ出来たのかはまったくわかりません、アプリは正常に動作しています。
[Mac]特定のバージョンのSwiftをインストールする

※ 追記:Swift2.2以降のバージョンのみになります
##特定のバージョンのSwiftをインストールする
OSSになったSwiftですが、Swift自体の更新が頻繁にあるので特定のバージョン下でしか動作しない事があり、最新版以外のSwiftをインストールする必要があったので書き残します。

##任意のバージョンのパッケージをダウンロードする
<img width="762" alt="スクリーンショット 2016-04-21 14.52.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/74405/c2fbe816-ec5c-34a9-b422-3802b78cca9c.png">

<a href="https://swift.org/download/#snapshots">ダウンロードリンク</a>

実行形式なので、インストーラーが立ち上がりそのままインストールできます。
あとはコマンドで確認してインストールできていれば成功
`swift --version`
<img width="371" alt="スクリーンショット 2016-04-21 14.54.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/74405/354d3b00-5f95-17cc-5331-ee7666b44551.png">
ERROR: Net::SSH::HostKeyMismatch: fingerprint を一発解決するコマンドを作る

~~~
ERROR: Net::SSH::HostKeyMismatch: fingerprint xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx does not match for "xxx.xxx.xxx.xxx"
~~~

IP一緒だけど、サーバー自体は入れ替わってる場合などまあまあある。
known_hosts をIPで検索して、その行削除すれば直るけど、
週に何度も起こったときにカッとなってやった。

~~~bash:forget_host.sh
#/bin/bash

if [ $# -ne 1 ]; then
  echo "[error] specify host"
  exit 1
fi

host=`echo $1 | sed 's/\./\\\./g'`
sed -i '' "/${host}/d" ~/.ssh/known_hosts
echo "forget $1"
~~~

known_hostsから忘れたいIPを指定してこんな感じで呼べる
`./forget_host.sh 55.55.55.55`

なお、Mac OS 10.9.5では動作確認している。
Linuxの種類によってsedが微妙に仕様が違うっぽいので要注意です。
date_selectのオプション指定の仕方



`<p><%= f.date_select :カラム名, {:discard_day => true}  %></p>`


これで通常、年月日が表示されるのを年月にするようにオプション指定できる。

例えば、もし月もなくしたければ、`:discard_month => true`を追加

で、注意なんだけど、dbのカラムのカラム型はdateにしないとエラーが起こる。
もし<%= f.datetime_select %>だったらそれに合わせてカラム型をdatetimeにする。



オプション一覧


オプション	説明
:use_month_numbers	月を数字で表示
:use_two_digit_numbers	月と日を2桁表示
:use_short_month	月名を省略形で表示
:add_month_numbers	数値 + 月名表示
:use_month_names	月名をカスタマイズ
:date_separator	年月日の区切り文字
:start_year	開始年
:end_year	終了年
:minute_step	分の間隔を変更
:discard_day	日の選択ボックスを非表示
:discard_month	月の選択ボックスを非表示
:discard_year	年の選択ボックスを非表示
:order	並び順を指定
:include_blank	空を含めて表示
:default	デフォルトの日付を設定
:selected	優先した設定
:disabled	選択を無効
:prompt	選択値の一番上を指定
:with_css_classes	スタイルを変更するタグの設定
:discard_type	名前の型を破棄
:prefix	名前の接頭辞を設定
:size	フォームの幅
:maxlength	入力フィールドに入力可能な最大文字数
:accept	フォームで受付可能なMIMEタイプ
:readonly	フォームの内容変更禁止
:disabled	フォームの項目の利用禁止
:tabindex	Tabキーによる入力欄の移動順
:accesskey	フォームに移動するショートカットキー
:id	要素固有の識別子
:class	要素を分類するクラス名
:title	要素の補足情報
:style	要素の補足情報
:dir	表記方向
:lang	基本言語
例
UbuntuでWindows10を抹殺した後、蘇生できたお話し

# DELL PCを買ってデュアルブートした
DELLのInspiron14 3000シリーズを購入し、Windows10と共存させる形でUbuntu14.04LTSを入れた。この作業は慣れていたのですんなりといけた。ここまでは何も問題はなかった。。。

# Ubuntuで音が出ない！？
なぜか、なぜか音が出なかった。ググりながらpavucontrolとか入れてみてなぜかを突き止めようとしたけれど、ダメだった。HDMI出力になっているだけかと思って期待していたのに、変えても何も変化なし。挙句の果てにはoutputがスピーカーになっていながらもRUNNINGを確認。絶望。

# Ubuntuを再インストール
![そうだ！](https://i.ytimg.com/vi/rSw855XKREU/hqdefault.jpg)
そうだ！（あまりに古いネタ）

Ubuntuを再インストールしてみようと決断し、USBを差しながら適当にOKを進めた。

# Windows10を抹殺
Ubuntu14.04を削除して再インストール、これを選択した。Ubuntuだけが消えるものだとばかり思っていたのが運の尽き。インストールが完了して再起動するとGRUBが起動しない（汗）Windows10が完全に跡形もなく抹殺されていた。さらばWindowsｗｗｗ とはいかずやっちまったの一言。

なぜやっちまった、、、、なのか。Win10も入れなおせばいいじゃんと思うかもしれない。しかし！これは！弟の！PC！なのだ！しかも実験データが入っていたらしい。無事爆死。

# Windows10ディスクイメージをDELLからDL
DELL > 製品別のサポート > 製品サポート >  > サービスタグを送信 > ドライバおよびダウンロードを開く

OSの変更というのがあるのでWindows10に変更。するとオペレーティングシステムというのが下に現れる。
![Screenshot from 2016-04-21 11:38:08.png](https://qiita-image-store.s3.amazonaws.com/0/68673/c297cf05-a7f0-12a1-575a-5a6a9a459b24.png)


そこからWindowsリカバリイメージのダウンロードをクリック。そこからは画面通り。

[Microsoft Windowsのリカバリイメージのダウンロード](https://www.dell.com/support/home/jp/ja/jpbsd1/Drivers/OSISO)という直接リンクのもあるんだけど、そのときのダウンロードシステムの挙動がどうもおかしいので避けたほうがいいかも。


# このイメージをUSBに焼くが。。。
[USBメディアを使う方法](http://www.dell.com/support/article/jp/ja/jpbsd1/SLN299044#Create)を参考にした。そこには、
![Screenshot from 2016-04-21 14:14:22.png](https://qiita-image-store.s3.amazonaws.com/0/68673/30569d29-3328-476d-9347-4a7cba58f181.png)


上のように書いてあるんだが、これに従ったら11から実行できなくなってUSBが使用不可になったままフォーマットできなくなった。オプションが違うとか言われた。そうなったUSBはファイルシステムでは認識できず、右クリックした後にフォーマット、なんてことはできない。ここは落ち着いて「ディスクの管理」から該当のUSBをフォーマットした。ディスクの管理はWindows標準の機能らしいので、それぞれのバージョンに従ってググれば起動の仕方もわかると思う。

そのとき、USBが変なものでフォーマットされていたので、一度削除してからFAT32でフォーマットした。それで上手くいった。

# USBにマウントしてブート
これの流れはDELLさんに説明を丸投げ

[OS再インストール手順](https://www.dell.com/support/article/jp/ja/jpbsd1/SLN300351)参照

# 流れ作業の末（戦後処理）
起動すること６時間、なんか色々と画面が切り替わったりした。朝起きても「もうすぐで完了します」の文字が画面を覆う。完了した果て、きっと苦しむであろう

- 日本語フォントがない
- 日本語入力ができない
- USキーボードになってる（汗）

についてはWindows Updateをするとすぐ解決できることがわかった。

1. 日本語フォントがない  
[設定] > [時刻と言語] > [地域と言語] でなんとフォントのDLというボタンがある。従ってDLすれば解決できる。日本語部分が■になる恐怖から解放☆

2. 日本語入力ができない  
Win Updateをするとできるようになります。

3. USキーボードで認識されてしまう  
Windows Updateをすると[Windows 10で日本語キーボードが101英語キーボードと認識されてしまう問題](http://freesoft.tvbok.com/win10/tips/keyboard.html:title)
こちらの対処方法２の①でらくらくイケる。Updateするとハードウェアキーボードレイアウトがある。

# そして、これから
Ubuntu16.04が出るそうなので、少し待ってみようと思う。待って、それから音が出るようにしてみたいと思う。あれだけはドライバ書かなきゃだめなのかな。。。。
gitのサブコマンドで.gitディレクトリのあるパスまで戻りたかったけど無理だった話

背景
-----

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ansibleの構成ファイルいじってるときに、ansibleファイル群のルートディレクトリに一発移動できるコマンドほしい感じがした。</p>&mdash; NPoi（平均身長野郎） (@NPoi) <a href="https://twitter.com/NPoi/status/722982991950020612">2016年4月21日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

ただ、弊社であったり自分でAnsible書くときはだいたいGit管理するので、そのルートに移動できればいいんじゃないかと思いました。

試作
-----

`~/.gitconfig` の `[alias]` にはだいたいこんな感じで内容を書くと思います。

```gitconfig:.gitconfig
[alias]
	co = checkout
	ci = commit
	st = status
	br = branch
```

実はここで、こういう風に書くとシェルスクリプトの内容が実行できます。

```gitconfig:.gitconfig
[alias]
        echo = "!echo 'hello world'"
```

これを使って、cdさせればいいんじゃないかと思った次第です。

設定案
------

いずれも、`git top` と打ったときにgitconfigのあるディレクトリへカレントを移動させることを想定しています。

結果的にいうと、いずれもだめでした。

### 設定案1

```gitconfig:.gitconfig
  top = "!f() { export TOPDIR=$(git rev-parse --show-toplevel); }; f; cd ${TOPDIR};"
```

### 設定案2

```gitconfig:.gitconfig
  top = "!f() { TOPDIR=$(git rev-parse --show-toplevel);  cd ${TOPDIR};}; f"
```

### 設定案3

PATHの通ったディレクトリに以下のファイルを置く。実行権限もつけておく。

```bash:git-top
cd $(git rev-parse --show-toplevel)
```


理由の考察
----------

どうやら、サブシェルで実行されているようです。

コマンド発行→サブシェルに潜る→サブシェル内でカレント移動→元のシェルに戻る（元のカレントのまま）

緩和策
-------

`.bashrc`に以下の内容を記載して、 `source ~/.bashrc`

```bash:.bashrc
alias gitroot='cd `(git rev-parse --show-toplevel)`'
```
他にもやり方はいろいろあると思いますが、一番手を抜いた方法ですね。
関数作ったりでも良いと思います。

まとめ
-----

残念でした。
PixelPicker::ColorName の紹介

# PixelPicker::ColorName の紹介

Ruby の練習がてら RubyGem を作成してみました。

https://rubygems.org/gems/pixel_picker

この Gem は画像ファイルを渡すと、その画像に含まれる色名を返してくれます。
また、カラーパレットを取得するオプションも有ります。

例えば、大量の画像ファイルを色名で分類したい時などに便利です。

## 使いかた

コマンドラインからは以下のようにファイル名を渡してあげると、色名(文字列)が返ります。

例えば、次のような画像を渡すと、以下の様な結果が返ります。

<img src="https://qiita-image-store.s3.amazonaws.com/0/9738/5527a665-9872-0e8f-f7b7-6971fd3b5859.png" width="120px;">

```
$ bin/color_name ~/Pictures/car_logo.png
blue
```

また、 Ruby インターフェースも提供しており、こちらからであればカラーパレットの
取得もできます。

```
$ bin/console
irb(main):001:0> pixel = PixelPicker::ColorName.new('/Users/foobar/Pictures/car_logo.png')
=> #<PixelPicker::ColorName:0x007fa791c7ba60 @image_file="/Users/foobar/Pictures/car_logo.png">
irb(main):002:0> pixel.palette
=> {:orange=>20331, :yellow=>28495, :red=>1030573, :blue=>1379614, :aqua=>1479, :violet=>450, :purple=>1882, :green=>476, :lime=>102}
```

詳しくは、README をご覧くださいませ。

https://github.com/libitte/pixel_picker
sbtマルチプロジェクト下でのsbt-flyway設定

# マルチプロジェクトじゃない時
以下の様な構成の時は問題なく動作する。

```
.
├── build.sbt
├── flyway.sbt
├── project
│   └── plugins.sbt
└── src
    └── main
        └── resources
            └── db
                └── migration
                    ├── V1__create_tables.sql
                    ├── V2__create_tables.sql
                    └── V3__create_tables.sql
```

### plugins.sbt
```
resolvers += "Flyway" at "https://flywaydb.org/repo"
addSbtPlugin("org.flywaydb" % "flyway-sbt" % "4.0")
```

### flyway.sbt
```
flywayUser := "ユーザー名"
flywayPassword := "パスワード"
flywayUrl := "jdbc:mysql://localhost:3306/DBスキーマ"
```

### 操作
ドキュメント通りこんな感じで使える。

```
% sbt -Dflyway.target=2 flywayMigrate
```

詳細は以下を参照。
https://flywaydb.org/documentation/sbt/migrate

# マルチプロジェクトにした場合
構造はこのようになり、

```
.
├── build.sbt
├── project
│   └── plugins.sbt
└── subprojects
    └── XXX
        ├── flyway.sbt
        └── src
            └── main
                └── resources
                    └── db
                        └── migration
                            ├── V1__create_tables.sql
                            ├── V2__create_tables.sql
                            └── V3__create_tables.sql
```

次にsbtの実行。

```
% sbt
> project XXX
[XXX] $ flywayMigrate
```

すると以下の警告が出てしまい、マイグレーション用の各種sqlファイルが読み込めていない模様で当然マイグレーションは実行されない。

> [warn] Unable to resolve location filesystem:src/main/resources/db/migration

少しハマってしまったが、flyway.sbtに以下を設定することで無事認識されるようになった。

```
flywayLocations := Seq("filesystem:./subprojects/XXX/src/main/resources/db/migration")
```
WordpressでAWS Elastic Beanstalk を使った場合の. ebextensionsとSSL証明書の設定

### EC2

> PHP
``64bit Amazon Linux 2015.03 v2.0.1 running PHP 5.6``

### RDS

>MySQL
``MySQL 5.6.23``

### .ebextensions

Elastic Beanstalkのデプロイ時にwordpressプロジェクト内の``.ebextensions/``内の``myapp.config``ファイルの処理を実行

``s3``より``wp-content/uploads``を``sync``します。
``php.ini``のファイルアップロード上限を``64MB``にあげています。


```:.ebextensions/myapp.config

container_commands:
  03_s3_sync-uploads:
    command: "aws s3 sync s3://[Bucket名]/wp-content/uploads [Project名]/wp-content/uploads"

files:
  "/etc/php.d/project.ini":
    mode: "000644"
    owner: root
    group: root
    content: |
      upload_max_filesize = 64M
      post_max_size = 64M
```

### SSL証明書

#### 1. Elastic Beanstalkでの設定
Elastic Beanstalk > 設定 > ネットワーク階層 > ロードバランシング

1. リスナーポート: `80`
ロードバランサーの外部向け HTTP ポート番号です。

- プロトコル: `http`
リスナーによって使用されるプロトコルです。

- 安全なリスナーポート: `443`
ロードバランサーの外部向け HTTPS ポート番号です。

- プロトコル: `https`
安全なリスナーによって使用されるプロトコルです。

- SSL 証明書 ID: `任意のSSL証明書を選択`


#### 2. ロードバランサーでの設定

EC2 > ロードバランサー > ロードバランサー選択
タブメニューに``リスナー``があるのでそこで上記と同じようにhttpsの設定を追加する。

このロードバランサーに対して現在、以下のリスナーが構成されています:

| ロードバランサーのプロトコル | ロードバランサーのポート | インスタンスのプロトコル | インスタンスのポート | 暗号 | SSL 証明書 |
| ----- | ----- |  ----- |  ----- |  ----- |  ----- |  
|HTTP |80 |HTTP |80 | 該当なし | 該当なし |
|HTTPS |443 |HTTP |80|  変更 | my-ssl-filename 変更 |
Mac の libtool を glibtool に差し替えていたら gem install libv8 に失敗した

1ヶ月近く前のことで、[個人メモ](https://sites.google.com/site/keyambwebtech/home/memorandom/20160315#TOC-libtool-glibtool-gem-install-libv8-)に書いていたのですが、libv8 のインストールに失敗する問題は割とあるようなので、自分の環境で発生した問題とその対応もこちらで公開しておきます。

少し前提が特殊だと思っており、当てはまらない人が多いかと思いますが、もし参考になれば幸い。

## 前提

この問題の約2月前に、[こちらの記事](http://keyamb.hatenablog.com/entry/2016/01/28/132515)の要領で、Mac の `libtool` を GNU libtool に差し替えるという作業を行っていました。
実行したコマンドを下に抜粋します。

```bash
brew install libtool
cd /usr/local/bin
ln -s glibtool libtool
ln -s glibtoolize libtoolize
```

自分の場合、これが問題の原因となったようです。

## 発生した問題

`gem install libv8` に失敗しました。
ログの一部を下に貼ります。

```
ERROR:  Error installing libv8:
        ERROR: Failed to build gem native extension.

:
creating Makefile
Compiling v8 for x64
Using python 2.7.7
Using compiler: /usr/bin/c++ (clang version 7.0.2)
libtool:   error: unrecognised option: '-static'
make[1]: *** [/Users/key-amb/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/libv8-3.16.14.13/vendor/v8/out/x64.release/libpreparser_lib.a] Error 1
make: *** [x64.release] Error 2
:
```

## 解決方法

上で作成した symlink を削除したところ、install に成功するようになりました。

```bash
rm /usr/local/bin/libtool*
```

以上です。
再生させ続けたい埋め込みYoutube動画がバッファリング状態で停止し続けてしまう with Safari

## 起きたこと
Youtube動画を背景要素として再生させ続ける実装をしていたが、
OS X 上のSafariで表示するとバッファリング状態で停止し続ける現象が起こった。

バッファリング状態から自動で再生開始されるのが期待される動作なのだが、どうも再生されない。

別の動画を試すとバッファリング状態にすらならなかったりするので、
もしかすると元のアップロードされている動画のサイズやYoutube動画側の設定の影響かもしれないが、
なんとか再生させ続ける方法が見つかったので共有です。

## 回避方法
（根本的な解決ではないので、回避方法としています）
動画プレーヤーのステータスを監視して、バッファリング状態になったら、0.1秒先にシークする。

バッファリングの状態の時に、コントロールバーを表示してシークバーで再生位置を変えると
Safariでも再生が再開されるということをデバッグ中に気づいたので、

じゃあバッファリング状態になったらちょっと先にシークするようにすれば、
停止はしないんじゃないかと思い実装したら、期待の通りに動いてくれました。

⚠️ 僕が扱った動画はミュート状態での再生だったため、見た目上あまり気になりませんが、
音込みでの再生だった場合、気になる部分出てくるかもしれませんね。

### コード
⚠️ パラメーターなどの詳細については、ドキュメントを見てください
https://developers.google.com/youtube/js_api_reference?hl=ja

```js
// 埋め込んだ iframe 要素 *Youtubeの動画IDはXXXXXとして伏せています。
// <iframe id="video" frameborder="0" allowfullscreen="1" title="YouTube video player" src="https://www.youtube.com/embed/XXXXX?autoplay=0&amp;loop=0&amp;playlist=XXXXX&amp;rel=0&amp;showinfo=0&amp;controls=0&amp;enablejsapi=1"></iframe>

/**
 * [init description]
 * @param  {string} targetID iframe の id名
 */
function setYoutube(targetID){
  var tag = document.createElement('script')
    , firstScriptTag = document.getElementsByTagName('script')[0]
    , _this = this
    ;

  window.onYouTubeIframeAPIReady = function() {
     loadPlayer();
  };

  tag.src = 'https://www.youtube.com/iframe_api';
  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

  function onPlayerReady() {...}
  function onPlayerStateChange(event) {
    switch (event.data) {
      case YT.PlayerState.BUFFERING:
        // バッファリングステータスになったら、0.1秒先にシークする
        _this.player.seekTo(_this.player.getCurrentTime() + .1);
        break;
      default:
          
    }
  }
    
  function loadPlayer(_videoID) {
    if(!_this.player){
      _this.player = new YT.Player(
        target, {
          // iframeで埋め込んでいるのでtargetなど指定なし
          // クエリもiframeのに直接指定しているのでここで指定なし
          events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
          }
        });
    } else {
      _this.player.loadVideoById(_videoID);
    }
  }
}
```

## 感想
背景でループ再生させる動画はできるだけ短いものにしたい。
ユーザーはおそらく、あまり動画を見ていない。
ローディング時間が増えて辛くなるだけだぞ。
タブレットとスマホを判別する

この記事は http://buildbox.net/?p=789 からの転載です。

Androidはスマホとタブレットなど、複数の解像度の端末が多数存在します。
何かと面倒だな・・・ということでタブレット対応を後回しにしがちですが、ルールがわかればそこまで難しいものではありません。
今回はタブレットとスマホの判別方法を記事としてまとめておきたいと思います。

Andorid 3.0（Honeycomb）が出た当初から、解像度としてはタブレットは画面サイズが600dp以上のものが対象とされています。
そのことは、Googleの公式ページでも解説されています。

さまざまな画面サイズのサポート
http://developer.android.com/intl/ja/training/multiscreen/screensizes.html

上記のサイトに有るとおり、layout-sw600dpにタブレット用のレイアウトを用意すれば、タブレットに対応が可能です。
しかし、ソースコード上で動的にタブレットの場合の挙動を変える必要があるかも知れません。
その時には、以下の様な手段を取ると良さそうです。

<strong>res/values/bools.xml</strong>

```java
<resources>
  <bool name="is_tablet">false</bool>
</resource>
```

<strong>res/values-sw600dp/bools.xml</strong>

```java
<resources>
  <bool name="is_tablet">true</bool>
</resource>
```

res/valuesとres/values-sw600dpにboolの値を定義し、sw600dpの時にtrueを返すようにします。
後は、ソース中で

```java
getresources().getBoolean(R.bool.is_tablet);
```

と呼び出してやれば、タブレットの時にtrueが返ってきます。
rtc2gitを使って、RTCからGitLabへの移行をやってみた


## 移行ツール

- [rtc2git](https://github.com/rtcTo/rtc2git)


## 作業につかったマシンのスペック

- MacBook Air (13-inch, Early 2015)

- OS X El Capitan (10.11.4)

- プロセッサ: 1.6 GHz Intel Core i5

- メモリ: 8 GB 1600 MHz DDR3

## 事前準備

- [rtc2git](https://github.com/rtcTo/rtc2git)のdevelopmentブランチをpull

- gitとpython 3.5.1の導入 (Homebrewを使った)

	```shell-session:homebrew
	brew install git
	brew install python3
	
	```

- [jazz scmtools 5.0.2](https://jazz.net/downloads/rational-team-concert/releases/5.0.2)の導入

- Javaの導入

## 各種設定

### scmtools

+ `/opt/jazz/scmtools/eclipse/scm` と `/opt/jazz/scmtools/eclipse/lscm` に `-Dosgi.nl=en_US` といれて、英語モードで動くようにする

```shell-session:scm
...
exec java -Dosgi.nl=en_US -Djava.protocol.handler.pkgs=com.ibm.net.ssl.www2.protocol -Dscm.show.own.errors=true -Xmx512m -Dosgi.requiredJavaVersion=1.6 -jar "${PRGPATH}/plugins/org.eclipse.equinox.launcher_1.1.1.R36x_v20101122_1400.jar" -data "@noDefault" "$@"
...
```

```shell-session:lscm
...
if [ "$USE_NATIVE" = "1" ]; then
    "${PRGPATH}/fec" "$@"
else
    java -Dosgi.nl=en_US -classpath "${PRGPATH}/plugins/com.ibm.team.filesystem.cli.minimal_3.1.600.v20140108_0240.jar:${PRGPATH}/plugins/com.ibm.team.rtc.cli.infrastructure_3.1.800.v20140619_0246.jar:${PRGPATH}/plugins/com.ibm.team.filesystem.cli.core_3.2.400.v20141011_0139.jar:${PRGPATH}/plugins/com.ibm.team.filesystem.client.daemon_3.1.500.v20130930_0113.jar:${PRGPATH}/plugins/org.eclipse.equinox.common_3.6.0.v20100503.jar:${PRGPATH}/plugins/com.ibm.team.filesystem.client_3.2.400.v20141015_1622.jar:${PRGPATH}/plugins/org.eclipse.osgi_3.6.50.R36x_v20120315-1500.jar:${PRGPATH}/plugins/com.ibm.team.repository.common_1.4.200.v20141015_2351.jar" com.ibm.team.filesystem.cli.minimal.client.FrontEndClient "$0" "$@"
fi
...
```

+ ホームディレクトリ (`~/.jazz-scm`) にある `preference.properties` を以下のように変更する

```preference.properties
content.threads: 25
refresh.local.changes: false
```

### rtc2git

- `config.ini` はコメントの通り設定するが、以下の2項目はこうした方がいい。

```config.ini
ScmCommand = lscm
UseProvidedHistory = True
```

- 変更履歴は [ここ](https://github.com/rtcTo/rtc2git/wiki/Getting-your-History-Files) の指示に従って準備しておく

## 実行と実行後の作業

- ターミナルから `'python3 migration.py'` として、しばらく放置

- 処理時間はソースの量というよりは、Change Set の数に依存しているようだ。処理するマシンの性能や RTC サーバーとのネットワーク接続状況も効いてくるかもしれない

- 440個の Change Set を処理するのに約35分くらい

- 処理が終わったら、`'git status'`, `'git log'` などで状態を確認

- `master` ブランチも含めていくつかブランチができているので、必要に応じてマージしたり、不要なブランチを削除する

- 今回は `master` ブランチに全ての変更をマージして、他のブランチは削除した

- ローカルでの調整が終わったら、`master` ブランチをリモートリポジトリに push する

- push したリモートリポジトリを見て、必要なソースや変更履歴が登録されていることを確認する
LINE Botで取得できるデータの一覧


LINE BotのCallbackで取得できるデータはcontentTypeごとに異なるようなので表にまとめておきます。
[API reference for BOT API - Receiving messages](https://developers.line.me/bot-api/api-reference#receiving_messages)

 _＊locationデータは Locationメッセージからしか取得できない。_ 
 _　locationデータ付きのスタンプがサポートされるとうれしいなあ。_ 
 

##contentTypeごとのメッセージ有無
 _＊データがないところはnullとなる_ 
 
| contentType     | 1:Text | 2:Image | 3:Video | 4:Audio | 7:Location | 8:Sticker | 10:Contact |
|:-----------|:-----------:|:------------:|:------------:|:------------:|:------------:|:------------:|:------------:|
| id              | ○ | ○ | ○ | ○ | ○ | ○ | ○ |
| contentType     | ○ | ○ | ○ | ○ | ○ | ○ | ○ |
| from            | ○ | ○ | ○ | ○ | ○ | ○ | ○ |
| createdTime     | ○ | ○ | ○ | ○ | ○ | ○ | ○ |
| to              | ○ | ○ | ○ | ○ | ○ | ○ | ○ |
| toType          | ○ | ○ | ○ | ○ | ○ | ○ | ○ |
| contentMetadata | - | - | - | - | - | ○ | ○ |
| text            | ○ | - | - | - | - | - | - |
| location        | - | - | - | - | - | ○ | - |

##contentTypeごとのcontentMetadata有無
 _＊データがないところはnullとなる_ 
 
| contentType    | 1:Text | 2:Image | 3:Video | 4:Audio | 7:Location | 8:Sticker | 10:Contact |
|:-----------|:-----------:|:------------:|:------------:|:------------:|:------------:|:------------:|:------------:|
|STKPKGID        | - | - | - | - | - | ○ | - |
|STKID           | - | - | - | - | - | ○ | - |
|STKVER          | - | - | - | - | - | ○ | - |
|STKTXT          | - | - | - | - | - | ○ | - |
|mid             | - | - | - | - | - | - | ○ |
|displayName     | - | - | - | - | - | - | ○ |


＊データの取得についてはこちらの記事を参照させていただきました。↓
[LINE BOT API Trialでできる全ての事を試してみた](http://qiita.com/betchi/items/8e5417dbf20a62f2239d)
Android で Pocket に URL を送る


処理とか Twitter のツイート画面を呼ぶ処理とかを用意するのが大変すぎたので簡単なラッパーを書いた

##これを

[ActivityIntentFactory.scala](https://github.com/x7c1/Linen/blob/2513a6c93c55d4a1342ff34e6576d3cb39a36af8/wheat-modern/src/main/scala/x7c1/wheat/modern/action/ActivityIntentFactory.scala)
(パッケージ名から text/plain 送信用の Intent を作ってくれる人)

##こうすると

```scala
class PlainTextSender private (context: Context, packageName: String){
  def share(text: String): Unit = {
    ActivityIntentFactory(context) createFor packageName match {
      case Right(intent) =>
        intent.putExtra(Intent.EXTRA_TEXT, text)
        context startActivity intent
      case Left(error) =>
        // アプリがインストールされてない場合など
        Log error s"$packageName not installed"
    }
  }
}
object PlainTextSender {
  def apply(context: Context, packageName: String): PlainTextSender = {
    new PlainTextSender(context, packageName)
  }
}
```

##こう書けるようになる

```scala
def saveToPocket() = {
  val sender = PlainTextSender(context, "com.ideashower.readitlater.pro")
  sender share "http://example.com/"
}
def composeWithTwitter() = {
  val sender = PlainTextSender(context, "com.twitter.android")
  sender share "こんにちはこんにちは"
}
```

便利！

## 備考

* PackageManager#getPackageInfo で
  * そもそも端末にアプリがインストールされていない場合を
* PackageManager#queryIntentActivities で
  * アプリは見つかったが処理できる Activity がない場合を
      * ( アプリの仕様が途中で変わってしまった場合など )

それぞれ判別できる。
今回の例では [ActivityIntentError](https://github.com/x7c1/Linen/blob/2513a6c93c55d4a1342ff34e6576d3cb39a36af8/wheat-modern/src/main/scala/x7c1/wheat/modern/action/ActivityIntentFactory.scala#L58-L62) を参照されたし。
Angular1.5で、@ViewChildっぽいことをしたい

Angular1.5で、どうしてもDOMを扱いたいとき、そのためだけにcomponentの代わりにdirectiveにし、link関数を取ったりするのはすごく癪に障りますね。

そんな時、以下のようなディレクティブでDOMそのものを変数をバインドしてしまえば、component controllerの$postLinkで、DOMが変数に入ってきます。これだと、controllerが、Angular2と同じコードになるし、テンプレートも正規表現で、Angular2形式に変換できるので、移行性が高いという意味でもありなのかなと思いました。

DOMを扱うために、directiveを使うことには変わらないのですが、「controllerからのDOM参照」という機能を特定のdirectiveに集約させてしまうという発想です。

```html
<div view-child="$ctrl.myElement"></div>
```
```js
.directive('viewChild', function($parse){
    return {
        restrict: 'A',
        link: function(scope, element, attr){
            var accessor = $parse(attr.viewChild);
            accessor.assign(scope, element);
        }
    }
})
```
思いついたままに書いたので、コードそのものの動作確認はしているものの、実際に動いているサービスで使ったことがあるわけではありません。それは設計的におかしいだろとか、いやこうした方が良い・・・とかあったら教えてください。
設定は「適用」するものです。

# 適応してどうする
いや、あの、設定は適用しましょう。
平然と適応を使っている人が多いです……なぜ。

> CSSを適応すると

こう言えるケースは、ブートストラップの設定に自分のCSSを適応させる（ブートストラップの命名規則・ルールに自分の設定を合わせる）みたいなケースぐらいだと思います。

# 指摘集
昔からこれだけ指摘が…でもまだ多いですよね。

-  [「適応」と「適用」をごっちゃにしないで下さい。](http://p-shirokuma.hatenadiary.com/entry/20070327/p3)
- [適用 vs 適応](http://qiita.com/magicant/items/229424403fee643b7075)
- [適用と適応の意味は？使い分けはこれでバッチリ！](http://xn--n8j9do164a.net/archives/560.html)
継続していくということ

# 勉強していますか？

技術者として大事なことは継続的なスキルアップでしょう。
以前の派遣先の社員は、サラリーマン技術者で勉強しない人ばかりで困りもんでした。

プロジェクトを進めていくにも、開発していくにも、いろいろ改善していくにも、何かを身に付けなければいけません。

プロジェクトを進めるうえでたくさんの問題が出ているのどうにかしましょうというとき、
何も知らない状態で、いったい何ができるのでしょうか？

世の中にはいろいろな手法やツールがあるので、まずはそれを知ることです。
プロジェクトマネジメントであればPMBOKやBABOKのこと。
開発手法であれば構造化設計やオブジェクト設計、設計の原則のこと。
改善するのであればKPTやTOCやPDCAのこと。
これらは一例なので、もちろん他にもあります。一つに絞りこまずいろいろ知ることです。

# まずは「意識」する

7つの習慣にある「習慣化するためのステップ」を見てみましょう。
![7つの習慣化.png](https://qiita-image-store.s3.amazonaws.com/0/114529/ac2b5295-677c-f040-5e9b-d5100183fba3.png)
ステップ１：何も知らないし、意識もしていない状態です。
ステップ２：まずは意識することです。意識することで知ろうという行動に移れます。
ステップ３：最初は知ったばかりなので、意識して知っている状態を育てていきます。
ステップ４：やがて意識しないでも知っている状態になると、自分のものに出来てきた証拠です。

ステップ２からステップ３は継続していく必要がありますが、ステップ１さえも無いのが現状かも知れません。
まずは意識して書籍やWebサイトを漁っていき、知ったことを磨いていきましょう。
WordPressでscriptタグを出力するためのあれこれ

新人君向けに。


## 基本

[wp_enqueue_script関数][1]を使います
wp_enqueue_scripts、admin_enqueue_scripts、login_enqueue_scriptsアクションフックのいずれかで呼び出しましょう


```php
// functions.php
add_action('wp_enqueue_scripts', function(){
    wp_enqueue_scripts('riot', 'https://cdnjs.cloudflare.com/ajax/libs/riot/2.3.18/riot+compiler.js');
});
```

[wp_enqueue_script関数][1]の第3引数は、配列で依存するhandle名が設定できます
scriptの出力順は、この設定により制御されます

scriptタグの出力は、wp_head関数かwp_footer関数で行われます
どちらの関数で出力されるかは、第5引数の設定と依存関係によります


## 同梱のjQuery以外を使いたい

[wp_deregister_script関数][2]を使い、wordpressが設定するものを解除し、[wp_register_script関数][3]を使い、設定し直します

なお、jqueryなどの一部のscriptは、wordpressが保護しているため、wp_enqueue_scriptsアクションフックで解除しようとする、管理画面/ログインページを表示した際に警告されます
どのscriptが保護されているかは[wp_deregister_scriptのソースコード][4]を確認してください

```php
// functions.php
add_action('wp_enqueue_scripts', function(){
    if (! is_addmin() && 'wp-login.php' === $GLOBALS['pagenow']){
        wp_deregister_script('jquery');
        wp_register_script('jquery', 'https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js');
    }
});
```

## phpから値を渡したい

jsで使う値をphpで制御したい場合は、[wp_script_add_data関数][5](第2引数 'data')を使います
enqueueされていないhandleには、dataを追加できないので、[wp_enqueue_scripts関数][1]の直後にやるか、[wp_script_is関数][6]でenqueueされているか確認してください

```php
// functions.php
add_action('wp_enqueue_scripts', function(){
    wp_enqueue_scripts('riot', 'https://cdnjs.cloudflare.com/ajax/libs/riot/2.3.18/riot+compiler.js');
    wp_script_add_data('riot', 'data', 'var foo = { "bar": "baz" };');
});
```

また、意図された使い方ではないですが[wp_localize_script関数][7]でも、上記同様の出力が可能です
が、`WP_Scripts#localize`の処理によりデータが書き換わる場合があるので気をつけてください

```php
// functions.php
add_action('wp_enqueue_scripts', function(){
    wp_enqueue_scripts('riot', 'https://cdnjs.cloudflare.com/ajax/libs/riot/2.3.18/riot+compiler.js');
    wp_localize_script('riot', 'foo', [ 'bar' => 'baz' ]);
});
```

## IE Conditional Comments

もうそんなに必要になることはないと思いますが、IEの条件付きコメントを使いたい場合は、[wp_script_add_data関数][5](第2引数 'conditional')を使います

```php
// functions.php
add_action('wp_enqueue_scripts', function(){
    wp_enqueue_script('html5shiv', 'https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.js');
    wp_script_add_data('html5shiv', 'conditional', 'lt IE 9');
});
```


## 番外

### js で window.$ が undefined

wordpressに同梱されているjQueryはnoConflictされています

```js
!function($){
    // hogehoge
}(jQuery);
```

で囲うなどして、`window.$`がなくても動作するようにしましょう



[1]: https://wpdocs.osdn.jp/%E9%96%A2%E6%95%B0%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/wp_enqueue_script
[2]: https://wpdocs.osdn.jp/%E9%96%A2%E6%95%B0%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/wp_deregister_script
[3]: https://wpdocs.osdn.jp/%E9%96%A2%E6%95%B0%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/wp_register_script
[4]: https://developer.wordpress.org/reference/functions/wp_deregister_script/#source-code
[5]: https://developer.wordpress.org/reference/functions/wp_script_add_data/
[6]: https://developer.wordpress.org/reference/functions/wp_script_is/
[7]: https://wpdocs.osdn.jp/%E9%96%A2%E6%95%B0%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/wp_localize_script



----
iOS周りの証明書を確認する

#はじめに
Macのキーチェーンアクセスにimportして、有効期限を見る、以外の方法で確認をしたく
ぐぐって検索して分断的なところをまとめました。
pkcs#12フォーマットだと特に期限日周りが取得できなかったので、もやもや作業になっていました。

# Terminal

## 証明書全部

```:すべてtextで表示
$ openssl pkcs12 -nokeys -in xxx.p12 | openssl x509 -text -noout
```

## 日付

```:有効期限の開始日時、終了日時
$ openssl pkcs12 -nokeys -in xxx.p12 | openssl x509 -dates -noout
```

```:有効期限の開始日時のみ
$ openssl pkcs12 -nokeys -in xxx.p12 | openssl x509 -startdate -noout
```

```:有効期限の終了日時のみ
$ openssl pkcs12 -nokeys -in xxx.p12 | openssl x509 -enddate -noout
```

## アプリのbundleIdentifierなど

```:bundleIdentiferなど
$ openssl pkcs12 -nokeys -in xxx.p12 | openssl x509 -subject -noout
```

#最後に
p12ファイルをpemに変換して情報を取り出す、とかなんでやっていたのかと
seed データで、productionとdevelopmentで反映させたいデータが異なる時

<h2>
productionとdevelopmentで反映させたいデータが異なる時
</h2>
やや無理やりなところがありますが、migrationファイルに直書きという手法をとることで解決できました


```ruby:db/migrate/20160225054555_hoge.rb 
class Hoges < ActiveRecord::Migration
  def change
    create_table :hoges do |t|
      t.string :title, null: false
      t.text :description, null: false
      t.string :image, null: false

      t.timestamps null: false
    end
  end
end
hogehogecategories = HogehogeCategory.create (
  [
    {
      name: "hoge1"
    },
    {
      name: "hoge2"
    },
    {
      name: "hoge3"
    },
  ]
)
```

このようにすることで、今はカテゴリをproductionにもdevelopmentでも反映させることができ、
もしdevelopmentのみにしたい時はseedに入れたら反映されます( ^ ^ )/■
Android の PopupMenu がめんどくさすぎる

ので簡単なラッパーを書いた

##これを

```scala
def item1 = PopupMenuItem("sample menu 1"){ _ =>
  Log info "item1"
}
def item2 = PopupMenuItem("sample menu 2"){ _ =>
  Log info "item2"
}
```

##こうして

```scala
def showMenu(context: Context, targetView: View): Unit = {
  PopupMenuBox(context, targetView).show(item1, item2)
}
```

##こうじゃ

![Screen Shot 2016-04-21 at 12.11.54 PM.png](https://qiita-image-store.s3.amazonaws.com/0/7196/697aba22-c8c6-52b4-4b63-6407424f7083.png)


便利！

##コード

```scala
import android.content.Context
import android.support.v7.widget.PopupMenu
import android.support.v7.widget.PopupMenu.OnMenuItemClickListener
import android.view.{MenuItem, Menu, View}
import x7c1.wheat.macros.logger.Log

class PopupMenuBox private (
  context: Context,
  view: View,
  items: Seq[PopupMenuItem]){

  def show() = {
    val menu = new PopupMenu(context, view)
    val pairs = items.zipWithIndex
    pairs foreach {
      case (item, index) =>
        menu.getMenu.add(Menu.NONE, index, index, item.title)
    }
    menu setOnMenuItemClickListener toListener(pairs)
    menu.show()
  }
  private def toListener(pairs: Seq[(PopupMenuItem, Int)]) =
    new OnMenuItemClickListener {
      override def onMenuItemClick(menuItem: MenuItem): Boolean = {
        pairs collectFirst {
          case (item, index) if menuItem.getItemId == index => item
        } match {
          case Some(item) => item.onTapped onItemTapped MenuItemTappedEvent()
          case None => Log error s"unknown menu-id:${menuItem.getItemId}"
        }
        true
      }
    }
}
object PopupMenuBox {
  def apply(context: Context, view: View): MenuHolder = {
    new MenuHolder(context, view)
  }
  class MenuHolder (context: Context, view: View){
    def show(items: PopupMenuItem*): Unit = {
      new PopupMenuBox(context, view, items).show()
    }
  }
}
case class PopupMenuItem(
  title: String,
  onTapped: OnPopupMenuItemTapped
)
object PopupMenuItem {
  def apply(title: String)(f: MenuItemTappedEvent => Unit): PopupMenuItem = {
    val listener = new OnPopupMenuItemTapped {
      override def onItemTapped(event: MenuItemTappedEvent): Unit = f(event)
    }
    PopupMenuItem(title, listener)
  }
}

trait OnPopupMenuItemTapped {
  def onItemTapped(event: MenuItemTappedEvent): Unit
}

case class MenuItemTappedEvent()
```
Firebaseで深い階層のデータを更新する

以下のようなデータがあるときに、

```json
{
  "title" : "Hello World",
  "description" : "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
  "i18n" : {
    "ja" : {
      "title" : "こんにちは世界",
      "description" : "いろはにほへと　ちりぬるを"
    }
  }
}
```

トップレベルの`title`と`i18n.ja.title`を更新して、`description`はそのままにしたい。
以下のようにプロパティ名を`/`区切りで指定すれば更新できる。。

```js
var updateObject = {
   title: 'updated title', 
   'i18n/ja/title': '更新されたよ'
};
firebase.update(updateObject);
```

### 更新後

```json
{
  "title" : "updated title",
  "description" : "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
  "i18n" : {
    "ja" : {
      "title" : "更新されたよ",
      "description" : "いろはにほへと　ちりぬるを"
    }
  }
}
```
Angular2でComponentを再帰的に処理する

Componentを再帰的に処理したいと思い、試してみたところ普通にできたのでやり方を紹介します
Objectの構造やディレクトリの表示とか再帰処理が必要なところで使えそうです
今回はObjectの構造を表示するサンプルです


再帰処理させたいComponent

```ts
@Component({
  selector: 'object-view',
  template: `
    <ul>
      <li *ngFor="#property of getKeys()">
        {{property}}: 
        <span *ngIf="!isObject(property)">
          {{getValue(property)}}
        </span>
        <span *ngIf="isObject(property)">
          <object-view [object]="getValue(property)"></object-view>
        </span>
      </li>
    </ul>
  `,
  directives: [ObjectViewComponent]
})
export class ObjectViewComponent {
  @Input() object: any;
  
  private getKeys(): string[] {
    return Object.keys(this.object);
  }
  
  private getValue(property: string): any {
    return this.object[property];
  }
  
  private isObject(property: string): boolean {
    const value = this.getValue(property);
    return !Array.isArray(value) && typeof value === 'object';
  }
}
```

directivesで自分自身を子Componentとして指定します
そして、templateの部分を見てもらうとわかりますが、プロパティの値がObjectだったら
自身のセレクターで指定したタグをレンダリングします
***きちんとObjectかどうかの判定を入れないとブラウザが死ぬので注意ｗ***


あとは、親Componentで子Componentの＠Inputディレクティブにobjectを渡すだけです

```ts
@Component({
  selector: 'my-app',
  template: `
    <object-view [object]="object"></object-view>
  `,
  directives: [ObjectViewComponent]
})
export class App {
  private object: any = {
    string: 'string',
    boolean: true,
    number: 0,
    array: ['a', 'b', 'c'],
    object: {
      prop1: 'prop1',
      prop2: 100
      prop3: {
        array: ['999', '998', '997']
      }
    }
  }
}
```

[動作サンプル](https://plnkr.co/edit/Anxv8zImWmD0WzizCSVT?p=preview)

# まとめ

ハマるかと思ったけど、普通に再帰処理できる
Upgrade Amazon Linux on Opsworks

As failed to upgrade amazonlinux os from 2014.3 to 2016.3 with opsworks deopyment, I upgraded the os manually and then run opswork's job, update_dependencies to change /etc/motd or so.

```
$ ssh $HOST
$ vi /etc/yum.conf
releasever=2016.03 # change from 2014.03
$ sudo yum clean all
$ sudo yum update
```

Then, go to Opsworks console, change agent version to the latest, then run update_dependencies.

Finally deploy your app :)
RecyclerView用のAdapterをListViewで使えるようにする

元のRecyclerView.Adapterに微妙に手を入れないと行けないけど、
AdapterはAdapterConverter.Adapterを継承するように、
ViewHolderはAdapterConverter.ViewHolderを継承するようにする。

するとRecyclerView用のAdapterを↓のようにListViewで使えるようになる。

```java
HogeRecyclerViewAdapter origAdapter = new HogeRecyclerViewAdapter(/* hogehoge */);
mListView.setAdapter(new AdapterConverter(getContext(), origAdapter));
```

```java
import android.content.Context;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

/**
 * Created by cattaka on 2016/04/12.
 */
public class AdapterConverter<S extends AdapterConverter.Adapter<VH, T>, VH extends AdapterConverter.ViewHolder, T> extends BaseAdapter {
    @IdRes
    public static int VIEW_HOLDER = R.id.viewholder;

    S mOrig;

    public AdapterConverter(@NonNull Context context, @NonNull S orig) {
        super();
        mOrig = orig;
    }

    @Override
    public int getCount() {
        return mOrig.getItemCount();
    }

    @Override
    public T getItem(int i) {
        return mOrig.getItemAt(i);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public int getItemViewType(int position) {
        return mOrig.getItemViewType(position);
    }

    @Override
    public View getView(int position, View view, ViewGroup viewGroup) {
        @SuppressWarnings("unchecked")
        VH vh = view != null ? (VH) view.getTag(VIEW_HOLDER) : null;
        if (vh == null) {
            vh = mOrig.createViewHolder(viewGroup, getItemViewType(position));
            vh.itemView.setTag(VIEW_HOLDER, vh);
        }
        vh.setCompatPosition(position);

        mOrig.bindViewHolder(vh, position);
        return vh.itemView;
    }

    public static abstract class ViewHolder extends RecyclerView.ViewHolder {
        int compatPosition = RecyclerView.NO_POSITION;

        public ViewHolder(View itemView) {
            super(itemView);
        }

        public int getCompatPosition() {
            int p = getAdapterPosition();
            return (p != RecyclerView.NO_POSITION) ? p : compatPosition;
        }

        public void setCompatPosition(int compatPosition) {
            this.compatPosition = compatPosition;
        }
    }

    public static abstract class Adapter<VH extends AdapterConverter.ViewHolder, T> extends RecyclerView.Adapter<VH> {
        public abstract T getItemAt(int position);
    }
}
```
GCE(Google Compute Engine)を使ってみたい！〜ubuntuでindex.html探す編〜


GCE(Google Compute Engine)のOSをubuntu, WEBサーバにnginxを入れています。サーバを起動すると、 **Welcome to nginx!** が表示されていますが、index.htmlはどこにあるのでしょうか！

前記事はこちら
[GCE(Google Compute Engine)を使ってみたい！〜ubuntuにnginxをインストールする編〜](http://qiita.com/haradahirokikiki/items/e0bf65f96067a5bdfabd)

# index.html探す旅

1. VMインスタンスのSSHボタンをクリックすると、コンソールが開きます。
2. nginxのデフォルト設定では、ウェブサイトのルートディレクトリは `/usr/share/nginx/html/` になっており、この中のindex.htmlが表示されています。簡単！　←　**この部分が表示されているわけではないことが分かりました...[こちら](http://qiita.com/haradahirokikiki/items/7f37b0674f0b11ae0c14)の記事で訂正をしておりますので、こちらを御覧ください。申し訳ございません...**

## 困ったコト
コンソールを最初に開いた時のルートは、 `/home/[ユーザ名]` です。勝手にこの下にいろんなファイルができていると思ってずっと探していましたが(lsを連打)、そんなことはありません！
 `cd /` でトップのディレクトリに行くと、いろんなファイルが’あります。ここから上記のルートでindex.htmlに行きましょう！
hipchat API を使って roomに画像を送る

#0. 変数用意

Hipchat APIの使い方は、Atlassianのページにいろいろ載ってます。
https://www.hipchat.com/docs/apiv2/method/send_room_notification
ここでは`card`というオブジェクトを使ってroomへの通知で画像を送る手順のメモを共有します。

試しに、LGTMの画像を表示させます。
必要に応じて`http_proxy`も設定。

```bash
wget -q -O lgtm.html http://lgtm.in/g 
LGTM=`grep '\[LGTM\]' lgtm.html | sed 's/^.*\[/\[\!\[/'`
LGTM=`echo ${LGTM} | sed -e 's/\[!\[LGTM](//' -e 's/)].*//'`
echo ${LGTM}
http://lgtm.in/p/atOSUsdZp
```

これでLGTMの画像URLゲット。こんな感じです。。。ｗ
![LGTM !](http://lgtm.in/p/atOSUsdZp)
次はいろいろとHipchat用の変数準備。
JSONデータを変数に格納するためにはエスケープが必要。


```bash
HIPCHAT_HEADER="Content-Type: application/json" 
HIPCHAT_ROOMCODE="xxxxx"  ## room id みたいなやつ
HIPCHAT_AUTH_TOKEN="xxxxxxxxx" 
HIPCHAT_API="https://api.hipchat.com/v2/room/${HIPCHAT_ROOMCODE}/notification?auth_token=${HIPCHAT_AUTH_TOKEN}"
MESSAGE="test"
THUMBNAIL="{ \"url\": \"${LGTM}\", \"width\": 1193, \"height\": 564 }"
HIPCHAT_CARD="{\"style\": \"image\", \"id\": \"123\", \"url\": \"${LGTM}\", \"title\": \"LGTM :)\", \"thumbnail\": ${THUMBNAIL} }"
HIPCHAT_JSON="{\"color\": \"green\", \"message_format\": \"text\", \"message\": \""${MESSAGE}"\", \"card\":${HIPCHAT_CARD} }"

```
- `id`は外すとAPIが受け付けてくれません。値は適当でも大丈夫だった。
- `message`とか`message_format`も外したらエラーになる。でもここで設定した値はroomでは表示されない。




#1. curlでnotificationを試す

以上をふまえて、`curl`でnotificationを送ります。


```bash
curl -H "${HIPCHAT_HEADER}" -X POST -d "${HIPCHAT_JSON}" ${HIPCHAT_API}
```

これだけです！
だから何？とか言われそうですがジョブが成功したときなどに表示させてみると結構なごみます :)

P.S.) ちなみにslackへのnotificationの場合はもっと簡単にできます。
Elixir on Phoenix アプリへのSSL接続を可能にするためのconfig.exs設定

PhoenixアプリにSSLでアクセスするための設定メモです。

# ssl証明書を配置

どこに置いても特に問題ないですが、公式に乗っかってprivの下においてみます。
いちおうsslディレクトリ切って。

```
~/tutorial/priv/ssl/ --- server.key
                      |- server.crt
```

# configを修正

環境に合わせてconfig.exsなりを修正。
今回は一旦dev.exsでやります

```dev.exs
config :tutorial, Tutorial.Endpoint,
  http: [port: 4000],
  https: [port: 4433,  # ←追加（443使ってたので4433で）
          keyfile: Path.expand("priv/ssl/server.key"),  # ←追加（相対パスで書く）
          certfile: Path.expand("priv/ssl/server.crt")], # ←追加
# 省略
```

# 起動

サーバーを起動してみます。

```bash
$ mix phoenix.server
[info] Running ChildRearingQuestion.Endpoint with Cowboy using https on port 4433
[info] Running ChildRearingQuestion.Endpoint with Cowboy using http on port 4000
```

正常に起動した様子。

これでhttpsを4433で待つようになりました！
GitLab API

# GitLab APIに繋いでみよう

詳しいことはもちろんサイトに記載があります
http://doc.gitlab.com/ce/api/

### プロジェクト一覧を取得しよう

APIを使うにはprivate tokenが必要です。自分のプロフィールのアカウント情報にあります。
http://exsample.com/api/v3/projects?private_token=yyyyyyyyyyyyy

par_page で取得件数が指定できますが、max=100ですので、それ以上はページ指定しながら取得します。
何件取得できたかはレスポンスヘッダーの X-Total、X-Total-Pages で確認できます。
※ここからURLの前半やprivate_tokenは省略します。

/projects?per_page=100
/projects?page=2&per_page=100

### 続いてissueの一覧

プロジェクト一覧から該当するプロジェクトをみつけ、プロジェクトIDを使って取得します。
/projects/xxx/issues

ステータスやラベルで絞り込みできます。
/projects/xxx/issues?state=opend
/projects/xxx/issues?labels=xxx,yyy,zzz
/projects/xxx/issues?state=opend&labels=xxx,yyy,zzz

という調子で他の情報も取得できますし、APIなので作成や更新、削除もできますね。
MinMax法によるお手軽AI入門 in Scala.js

最近MinMax法を勉強したので、アウトプットのために三目並べを実装しました。あとScala.jsも使ってみたかった。
コード自体はほとんど以下のプログラムを参考にしています。

参考
http://postd.cc/tic-tac-toe-understanding-the-minimax-algorithm/

なんとなくAIってつけましたけど、AIなんて呼んでいいのやら・・・

勝つことは無理です

[デモ](http://1984weed.github.io/tic-tac-toe-ai/)

# MinMax法とは

wikiに書いてある通りですが、先読みプログラムです。
playerがAである時はBのスコアを最大化するような手(ノード)を選択。　playerがBである時にはAのスコアを最小化するような手(ノード)を選択します。
ちなみに範囲内の全てのノードのスコアを計算して次の一手を計算するのでパターンが多いゲームだと計算量が恐ろしくなります。

[MinMax法](https://ja.wikipedia.org/wiki/%E3%83%9F%E3%83%8B%E3%83%9E%E3%83%83%E3%82%AF%E3%82%B9%E6%B3%95)

図にすると以下のようになります。wikiの図とは上下を逆にしました。逆にした方が自分的には直感的だったので。

Aの手番の時はスコアを最大化するようなノードを選択します。
<img width="509" alt="a.png" src="https://qiita-image-store.s3.amazonaws.com/0/108588/58ed0e6c-e0c1-d008-6924-b020e449aa13.png">


Bの手番の時スコアを最小化するようなノードを選択します。

<img width="527" alt="b.png" src="https://qiita-image-store.s3.amazonaws.com/0/108588/fec5f3bf-49fe-9787-23ed-d05102a523e3.png">

A, Bは先手、後手で分けることができます。逆に言うと続けて動けるようなゲーム今回の実装では対応できません。

# 三目並べとは

誰でも一回はやったことある遊びです。海外ではTic-tac-toeと呼ばれているみたいです

図のようなゲームです。[^1]

![sanmoku.png](https://qiita-image-store.s3.amazonaws.com/0/108588/e6094983-5dab-a0f5-95a5-95ef5b3086b9.png)

縦横斜めに３つ同じ柄を揃えた方が勝ちとなります

# 評価基準

ここでは一直線揃えた方に対して点数をつけていきます。
ターンの数をdとすると

先手A(X) 勝利: 10 - d 点
後手B(○) 勝利: -10 + d　点
引き分け: 0点

なぜターン数dを考慮するかというと、負けと決まっていても相手によりターンを消費させる手の方がいい手だと言えるからです

ということで具体的な盤面を見ておいた方が分かりやすいかもしれません。例えば次はA（X）の手番でこんな盤面の時
<img width="334" alt="init.png" src="https://qiita-image-store.s3.amazonaws.com/0/108588/8b14712c-ef8d-78b5-95eb-98fe4946f394.png">


Aの選択は下図の一番下の3つの選択肢がります。この選択肢からAは点数を最大化するような手を選択することで最良の手を得ます

<img width="1150" alt="result.png" src="https://qiita-image-store.s3.amazonaws.com/0/108588/30b4598c-af02-ea49-d2bc-61e2d8b45d97.png">

＊ 上に行くほど時間経過していきます

Aは勝つことはできませんが、直近ノードの最大値である**0**を選択することでなんとか引き分けには持ち込めるようです。
また一つ前はBの手番なので最小のノードを選択しているために-2点が選択されています。

必ず一番上まで実行して、勝敗を見た後に最適な手を選択してるのでもはやゲームする必要はないに等しいです。
とこんな感じで再帰的に計算していきブルートフォースアタックしていきます。

# 計算省略の余地

冒頭でも書いたように計算量は結構膨大になります。
今回の9マスのゲームで言えば
9! ほど計算が必要です。つまり *362880* 通り!

もちろん途中で勝負がつく可能性があるので362880より計算回数は少々少なくなりますが、こんなミニゲームにしては多すぎます。。。
ということで計算量を減らしていきます。

## アルファベータ法

いい手を見つけた時点でそれ以外の計算を切り上げることもできそうだなぁって思っていたら、Wikiには改良版のアルファベータ法というのがあるとの記述があります。
[アルファベータ法のwikipediaページ](https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%AB%E3%83%95%E3%82%A1%E3%83%BB%E3%83%99%E3%83%BC%E3%82%BF%E6%B3%95)に疑似コードがあるのでこれをまるっと実装に落とせばうまくいく!!

図にするとこんな感じです。左から順に深さ優先で探索しているイメージです

<img width="416" alt="alpha-beta.png" src="https://qiita-image-store.s3.amazonaws.com/0/108588/f1d6494b-87eb-778f-b6bb-19fff4cadb8a.png">

-8が出た時点で-3 より小さいことは確定しているのであえて次のノードは計算しないようにします。次のノードが-9だったところで最上位のノードには確実に採用されないのでここでは計算する必要がないです。

とこんな感じで枝刈りをしていきます

## ゲームの性質をつく

幸いなことに三目並べは最初の手はどこにおいても同じ評価でした。ということで最初の手はランダムにして計算回数を節約します。
ちなみに自分で計算しましたが、wikiにも書いてあるので常識だったようですね。

# コード

コードはこちらに置いています
[ソースコード](https://github.com/1984weed/tic-tac-toe-ai)

# 何が理解を苦しめたか

自分のレベルが低いせいか再帰のプログラムとターン毎の最大、最小選択の理解に割と苦しみました。
ノートにいっぱい図を書いてようやく理解できたという感じです。。。未だに少し悩みますが。。。

# 今後

三目ぐらいだと計算量がある程度一定なのでゲーム終了までの手を読むことができました。
ということで少し難易度を上げて五目並べを作ってみたいなぁっと

[^1]: https://ja.wikipedia.org/wiki/三目並べ