OmniAICreator/Qiita-1.07M huggingface dataset:
GCEのプリエンプティブインスタンスがどのくらい落とされるのか調べてみた

## 概要

1. GCEのプリエンプティブVMを延べ60日モニタリングしてみた
2. 24時間以内に落とされることは1回しかなかった

## プリエンプティブVMとは？

Google Cloud Platform(以下GCP)で提供されている**プリエンプティブVM**は通常の約7割引の価格で利用できるお得なVMです。以下は公式の料金表記で、通常の3分の1以下の料金であることが確認できると思います。

<img width="635" alt="スクリーンショット 2018-09-16 12.13.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/79302/0f3563f8-1b41-4123-b494-e829ee1a4599.png">


詳細な仕様に関しては、以下のリンクが詳しいです。

[プリエンプティブ VM インスタンス](https://cloud.google.com/compute/docs/instances/preemptible#understanding_the_preemption_process)

## プリエンプティブVMの制限

プリエンプティブルは格安で利用できる代わりに、以下のような制限があります。

- GCP側の都合で、いつでもVMが強制終了される可能性がある
- プリエンプティブVMは最大でも24時間で強制終了される

## 24時間以内に強制終了させられることはどのくらいあるのか？

プリエンプティブVMは、GCP側の都合でいつでも強制終了させられる可能性があります。では、実際にどのくらいの頻度で強制終了させられてしまうのでしょうか？

実際にプリエンプティブVMを複数立ち上げて、モニタリングしてみました。

## 計測方法

### GKEのノードとしてプリエンプティブVMを5台配置

まず、GKE(Google Kubernetes Engine)でクラスタをプリエンプティブVMの5台構成で立ち上げました。通常のGCE(Google Compute Engine)でプリエンプティブVMを立ち上げた場合は、強制終了させられた場合に、再起動がかかりません。しかし、GKEのノードとして立ち上げた場合は、これらのVMが一つのインスタンスグループとして設定されます。インスタンスグループを設定すると、グループ内のインスタンスが予め設定されたインスタンス数よりも少なくなると、自動で新しいインスタンを立ち上げます。つまりこの構成なら、プリエンプティブVMが強制終了させられた直後に、新しいプリエンプティブVMが自動で立ち上がります。

### Stackdriver Monitoringでインスタンスをモニタリング

プリエンプティブVMの起動状況は、Stackdriver Monitoringでモニタリングします。デフォルトだとGKE立ち上げ時にStackdriver Monitaringでの集計が有効になるので、特に追加で設定の必要はありません。

## 計測結果

上記で設定したように、5台のプリエンプティブVMを**12日間**動かして状況をモニタリングしてみました。

結果、12日の間で起動から24時間以内にVMが強制終了したのは、**1度だけ**でした。今回は5台×12日観察したので、1/60という事です。それ以外は、ちょうど起動から24時間で終了していました。

## まとめ: プリエンプティブVMは滅多に落とされない!

プリエンプティブVMは、従来的なVMの使い方だと検証・開発環境としてしか使えそうにありません。しかし、GCPのkubernetes Engineやインスタンスグループなどで大規模クラスタを組むことを前提として構成すれば、高性能なクラスタを格安で本番運用できるかもしれません。

特にGKEの場合は、もともとkubernetes自体がVMに状態を持たせない前提で設計することがほとんどだと思うので相性が良さそうです。機会があればプリエンプティブVMで中規模のシステムを本番運用してみたいですね・・・。
Grove シリアルカメラモジュールキットのケーブルの謎

# 2種類のケーブル
Groveの[シリアルカメラモジュールキット](https://www.switch-science.com/catalog/1626/)を購入すると、以下が同封されてきます。

- カメラモジュール
- レンズ（2種類）
- ケーブル
- レンズキャップ

この中で気になるのがケーブルです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/130771/97c9eab8-eff3-85c7-762a-27289607a48b.png)
何故か片側のつなぎの順番が変わっています。

# Groveのコネクタ
通常、Groveのコネクタは、以下の順番に[決まっています](http://wiki.seeedstudio.com/Grove_System/)。

1. 信号1：黄色
2. 信号2：白
3. VCC：赤（3.3V or 5V）
4. GND：黒

そのため、通常使用するケーブルは、両端とも同じになっています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/130771/5ef6f9e8-bc69-7d29-2bea-b6545d22c60d.png)

# カメラモジュールのコネクタ
カメラモジュールのコネクタも以下の順番になっています。
（※[資料](http://wiki.seeedstudio.com/Grove-Serial_Camera/)は古いバージョンのカメラモジュールです）

1. GND：黒
2. VCC：赤（5V）
3. RX（受信）：白→Arduinoの送信PINとつなぐ
4. TX（送信）：黄色→Arduinoの受信PINとつなぐ

# つなぐとどうなる？
Arduinoとカメラモジュールを直結したところ、私のカメラモジュールでは、煙が出ました（苦笑）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/130771/66331fa2-d2e9-cdf4-8448-beeade5c676a.png)

※サンプルコードでは、SDカードシールド経由の接続になっていましたが、無視してコードを書き換えました

そのせいかどうかはわかりませんが、今のところ、Arduinoと繋がりません．．．
皆様もお気をつけください。

【後日談】
新しいカメラモジュールを購入し、直結のケーブルで繋いだところ、送受信できている風（正確にはできていない）なので、間にSDカードシールドを『挟まない』場合はストレートのケーブルを使う必要がありそうです。
Dockerはサーバー屋さんだけのものではない。 画像屋さんも使おう

画像認識関係のGithub上のリポジトリをアクセスしてみると、最近はdockerのための設定 Dockerfileが含まれることが増えてきた。

[Dockerはコンテナ型の仮想化環境を提供するオープンソースソフトウェアである](https://ja.wikipedia.org/wiki/Docker)


使った方がいい理由：
- さまざまなライブラリの組み合わせで、目的のソフトウェアが動くような共通の環境を整備しにくくなっていること。Docker環境下では、指定のライブラリの構成が、Docker環境の外とは別に構築されるので、ライブラリの組み合わせの問題に悩む必要がなくなる。
- 必要なソフトウェアの環境を整備する手順をDocker環境下では自動化できること。



- [機械学習を勉強するときはDockerを使うと便利](http://dr-asa.hatenablog.com/entry/2017/08/21/185301)

- [Dockerによる深層学習及び機械学習環境構築](http://nykergoto.hatenablog.jp/entry/2017/11/11/Docker%E3%81%AB%E3%82%88%E3%82%8B%E6%B7%B1%E5%B1%A4%E5%AD%A6%E7%BF%92%E5%8F%8A%E3%81%B3%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89)

- [NLP/機械学習/データ分析系のDockerイメージ8選 + 1](https://qiita.com/yamitzky/items/80be0ec14c95ac793958)

- [【TensorFlow】Docker for Windowsで動かす機械学習！](https://www.sejuku.net/blog/55941)

- [Dockerで作る機械学習研究開発環境](https://hyt-sasaki.github.io/docker_slides/#1)

- [Docker入門 ~Tensorflowも超簡単に！！~](https://qiita.com/yakigac/items/f14f12f182a564c091d0)


- [Docker上でWebカメラ(UVC)を使う方法](https://qiita.com/Eliza_wb/items/6ac73679b6d2a2316a2b)
command+Q 二度押しでアプリケーション終了 / quit application by pressing command+Q twice

BetterTouchToolには今の所アクティブなアプリケーションを終了するActionがないため、メニューバーの終了アクションを呼び出してアプリケーションを終了させる方法を取る。（現在実装中ではあるらしい [issue](https://github.com/folivoraAI/BetterTouchTool/issues/752#issuecomment-381191397)
Add New Shortcut or Key Sequenceで以下を追加。

- Key-Sequence: `cmd・Q・Q`
- Trigger Predefined Action: `Trigger Menu-bar Menu-Item`
- Value: `(2);*quit*||*終了`

![スクリーンショット 2018-09-18 0.44.59.png](https://qiita-image-store.s3.amazonaws.com/0/140073/e8c36c67-013e-66fa-f55f-47918c417799.png)

`(2);` でメニューバーの左から２番目のメニューアイテムを選択し `*quit||*終了` で `*quit` もしくは `*終了` というテキストをもつサブメニューアイテムを選択する。基本的にアクティブなアプリケーションのメニューは左から２番めであること、終了のメニューアイテムは `quit` または `終了` というテキストを持つことを利用している。

ついでに `command Q` に `No Action` を割り当てておくとアプリケーション終了の誤爆を防げて良い。

##### 追記 2018-09-18
アプリケーションによっては`Quit ~` というテキストもあるので `*quit*` に変えた
ISUCON9 に出る自分に言いたいこと（ISUCON8 敗退記録）

まず何より ISUCON 初心者で、実は予定もあるような感じだけど出てみたいといった自分と一緒に参加してくれた [@overlast](https://github.com/overlast)氏, [@sugyan](https://github.com/sugyan)氏 ありがとうございました。あと運営の皆様お疲れさまでした。

今年は**余裕の予選敗退**だったけど、来年は（も）優勝目指して参加や！

（テンパらなければ予選はいけるで君）

# ISUCON 2019 に出る自分へ

* とりあえず ISUCON 2018 のタイムライン的なものを読み返して悔しかった感半分行けてないところを思い出すの半分したらいいんじゃないかな。
 * https://memo.sugyan.com/ すぎゃーんしのメモも
* **これはチーム戦です**。去年は実感が無かったとおもいますが、そういうことです。
* **環境はほぼ完璧に構築しておくべし**。個人的な敗因の半分ぐらいはこれ。特に言語が決まっているなら、前年の環境がチェックアウトしてコマンド一発で動くかどうかは意識しておくべきだった。
* 他の準備項目（細かい所含めて）
    * git repo作る
    * みんなの公開鍵は集めておく？
        * すぎゃん氏が git から抜いてきてくれててすごかった
* 集中できる場所はないと駄目ですね。まぁ去年は言い訳半分スケジュール半分でこんな感じで面白かったけど。勝ちに行くとよいでしょう。https://twitter.com/LINE_DEV/status/1040847262690078721
* ansible 変に使って時間を使ってしまったかも。単純なコマンド集をどんどん集めていくとそれだけでよかった。3台並列にログインして `git pull; sudo systemctl restart torb.perl` 的な。
* プロファイルの仕方も慣れておくべし。ltsv の見方、ツール使うとたぶんいいし、あらかじめ考えておけば。。
* mysql も見るところなんとかなれば
    * サブクエリは当然だけど
    * `FOR UPDATE` がやばい
* 自分は比較的**nginx ログ芸**が得意なので覚えておくといいでしょう。普段の業務でつかってるアレです。
* ネットワークは
    * ltsv の集計でボトルネックになってるかどうかは判る、ぐらいかなぁ
* マシンの使い方、人ごとに別のマシンで try&error しまくるとかもよかったかもなぁ。
* ルールとか雰囲気的な学び
    * 余分なフィールド増えても駄目なの！？ って気付くのにけっこうかかってしまったので良くない。↓に続く
    * Fail した理由は結構詳細に出る。つまり十分なテストが書かれているわけでもっと Go BOLD に行けたのでは。これが（コーディングが遅いことを除けば）残りの半分ぐらいかなぁ。
    * 環境構築に罠は基本的に無いから**信じて色々つっこめば良かった**。仕事だと、このビルドは本当に安定なのか・・・？ みたいな所からはいらないといけないことも多いので。
* alp は入れておこう。っていうか採点ルールをみて Excel 芸発揮できたな。。
* MBP 13 はきつい。。。

# ISUCON 2018 のタイムライン的なもの
## 午前中
* 当日の朝ぐらいに ISUCON 用のリポジトリ作りますか。みたいな事言われて実際それは作ってたので共有したんだけど、事前準備がそれぐらいになってしまった。
* 気付いたら 10:00 で、東京と奈良を LINE 電話で繋いでの ISUCON が始まった。
* へー、サーバーが　3台用意されて、コンソールからべんちーまーくできて、そういうことか完全に理解した(ry、って初めてなったのかこのタイミング。
* すぎゃんしが公開鍵ログインできるようにまとめてくれたりしてる裏で、自分は作成したキーを各マシンに配って git pull/git push できるようにしてたりしたらなんとなく午前中が終わっていた。
* スコアはデフォルト 1,500 ぐらい。 (?)
* すぎゃんしがトップページの最適化を、overlast 氏がインフラ構築（1台の nginx で受けて、2台に流す）、自分が MySQL のクエリとインデックスを見ようって話になった。（けどコミットログみたら行数の少なさに引く
* このあたりですぎゃーん氏が『perl の hashmap って。。。。どう作るんだっけ？』みたいな事を言って、電話の向こうで効いてた overlast 氏が `{key => "value"}` を slack で送ってくれて緊張がほぐれて良い感じになる。

## 12:00~
* ここらへんで別のイベントの設営手伝ったりもしつつ（まぁ、これが本業なので）、クエリを見てどーしょうも無いところではなく、一個シートの空き数を count しとくかということで ISUCON やデプロイへの慣れも踏まえてやった。（これはやりきれた）
    * が、このあたりは事前に問題トレースしておけばもうチョット重いところから手を付けられたのでは説はある
* 余分なフィールド返すと落ちるっていうのに気付くのもこのぐらい(?)。カラム追加しただけで落ちるのそういうことかと。
    * でも対応策として、ちゃんと `select *` を分割して書いたらよかったのは間違いない
* `IS NULL` してる部分もあって、あーこれ INDEX 効かないから直したいなぁみたいな所もあったけど結局手は付けられず。
* 最終的には Event が一番の勝負所だったんですよねぇ。。。気が落ち着いたら読もう。

## 16:00~
* このあたりから結構質問とかも出て、すぎゃん氏とそれぞれ質問対応とかしてたりしながら、個人的には諦めたくは無かったが時間は無常にフィニッシュ。

最終スコア4,000弱。。いやー難しい。
Rails 5.2でBootsnapのキャッシュファイルの出力先を変更する

Rails 5.2からBootsnapというgemがデフォルトで使われるようになった。

- [【アプリ起動時間を50%削減】Rails5\.2からデフォルトGemに採用されたBootsnapを検証した · カウル Tech Blog](http://techblog.housmart.co.jp/2017/12/11/ruby-gem-bootsnap/)

これはアプリの起動時間を削減してくれるものだが、tmp/cache/以下にたくさんの小さなファイル(2000個とか)を作成するので、例えばDropboxを使ってプロジェクトディレクトリを同期させていると鬱陶しいことがある。

そんな時は、config/boot.rbを以下のようにすることでキャッシュファイルの出力先を変えられる。

```rb:config/boot.rb
#require 'bootsnap/setup' # Speed up boot time by caching expensive operations.
require 'bootsnap'
app_name = File.basename(File.expand_path("#{__dir__}/../"))
Bootsnap.setup(cache_dir: "/tmp/bootsnap/#{app_name}")
```

ここでは、Railsアプリがあるディレクトリ名を`app_name`として、`/tmp/bootsnap/<app_name>`にキャッシュファイルを作るようにしてみた。例えば/Users/yhara/proj/myapp1にRailsアプリがあるとしたら、/tmp/bootsnap/myapp1がキャッシュファイルのディレクトリになる。
Docker化したFlaskをデバッグする

## 背景
ISUCON8に参加したときのメモです。  
提供されたFlaskアプリをDocker化してローカル環境でデバッグしながら動かしていました。

## 使うもの
- 何かしらのFlaskアプリ  
- wsgiサーバー（今回はgunicornですが、uwsgiなどでも応用できるはず）
- Docker compose


## 1. docker-compose
https://gist.github.com/nerixim/bbbe10bf9fbfb2242be2b3f835e10188

環境変数の設定を`docker-compose`に寄せています。`DEBUG`は真値っぽいものなら何でもいいです。  
gunicornに渡す引数もこちらで指定しています。gunicornに`--workers`引数を渡してしまうとフォークモードになりデバッグができなくなるのでご注意を。

## 2. FlaskのDockerfile
https://gist.github.com/nerixim/00839bba3037b2a611b11179038c633f
Gunicornの設定は`docker-compose`で済ませているのでこちらで指定必須のモジュール名だけをしてしています。
関係ないですが、`apk add mariadb-dev build-base`でpythonの`MySQLdb`に必要なパッケージをインストールしています。

## 3. Flaskの設定
https://gist.github.com/nerixim/339bc86327870b6e0691adc0b717585c

Werkzeugの`DebuggedApplication`を挿入するのですが、`PROPAGATE_EXCEPTIONS`を指定しないとgunicornとうまく連携できないのでご注意を。

## 4. nginxの設定（一応）
https://gist.github.com/nerixim/fd2f1684299b641789654bd6e7e72951

## 終わりに
以上のファイルをうまく（？！）配置できればポート80から`nginx -> gunicorn -> flask`にアクセスができデバッグもできるのでFlaskで環境構築を始めてやる人には少し参考になれば嬉しいです。
sassの繰り返し処理を使ったクラス付与のメモ

# コンパイル後のCSS

仕事にて、最終的に以下のようなCSSになるsassを書きたいとします。

```css
.class0-0 {
  width: 0.0px;
}

.class0-1 {
  width: 0.1px;
}

.class0-2 {
  width: 0.2px;
}

.class0-3 {
  width: 0.3px;
}

.class0-4 {
  width: 0.4px;
}

.class0-5 {
  width: 0.5px;
}

.class0-6 {
  width: 0.6px;
}

.class0-7 {
  width: 0.7px;
}

.class0-8 {
  width: 0.8px;
}

.class0-9 {
  width: 0.9px;
}

.class1-0 {
  width: 1.0px;
}

.class1-1 {
  width: 1.1px;
}

.class1-2 {
  width: 1.2px;
}

.class1-3 {
  width: 1.3px;
}

.class1-4 {
  width: 1.4px;
}

.class1-5 {
  width: 1.5px;
}

.class1-6 {
  width: 1.6px;
}

.class1-7 {
  width: 1.7px;
}

.class1-8 {
  width: 1.8px;
}

.class1-9 {
  width: 1.9px;
}

.class2-0 {
  width: 2.0px;
}

.class2-1 {
  width: 2.1px;
}

.class2-2 {
  width: 2.2px;
}

.class2-3 {
  width: 2.3px;
}

.class2-4 {
  width: 2.4px;
}

.class2-5 {
  width: 2.5px;
}

.class2-6 {
  width: 2.6px;
}

.class2-7 {
  width: 2.7px;
}

.class2-8 {
  width: 2.8px;
}

.class2-9 {
  width: 2.9px;
}

.class3-0 {
  width: 3.0px;
}

.class3-1 {
  width: 3.1px;
}

.class3-2 {
  width: 3.2px;
}

.class3-3 {
  width: 3.3px;
}

.class3-4 {
  width: 3.4px;
}

.class3-5 {
  width: 3.5px;
}

.class3-6 {
  width: 3.6px;
}

.class3-7 {
  width: 3.7px;
}

.class3-8 {
  width: 3.8px;
}

.class3-9 {
  width: 3.9px;
}

.class4-0 {
  width: 4.0px;
}

.class4-1 {
  width: 4.1px;
}

.class4-2 {
  width: 4.2px;
}

.class4-3 {
  width: 4.3px;
}

.class4-4 {
  width: 4.4px;
}

.class4-5 {
  width: 4.5px;
}

.class4-6 {
  width: 4.6px;
}

.class4-7 {
  width: 4.7px;
}

.class4-8 {
  width: 4.8px;
}

.class4-9 {
  width: 4.9px;
}

.class5-0 {
  width: 5.0px;
}
```


- classの前の数字は、0から始まり、10回繰り返したら、1増えます
- classの後の数字は、0から9まで1づつ増えるを繰り返します

これを51回繰り返したいとします。さて、どう書きますか？先輩のコードが勉強になったので、記録しておこうと思いました。

# 結論

はじめに、sassから書いていきます。

```sass
@for $i from 0 through 50 {
  $v1: floor($i / 10);
  $v2: $i % 10;
  .class#{$v1}-#{$v2} {
    width: #{$v1 + "." + $v2}px;
  }
}
```

## $v1の行の説明

`$v1`にくるのは、

- 0が10回
- 1が10回
- 2が10回
- 3が10回
- 4が10回
- 5が1回

の**51回**の繰り返しができればOKです。

```sass
$v1: floor($i / 10);
```

`floor`は、小数点以下を切り下げます。四捨五入ではなく切り下げなので、0.9でも0とします。

- 0.0でも1
- 0.1でも1
- 0.2でも1
- 0.3でも1

・・・省略

- 0.8でも1
- 0.9でも1

で、0が10回を実現しています。最初の、`@for $i from 0 through 50`で、51回繰り返すこととしているので、5は1回だけの実行で終わります（51回目の実行なので）。

## $v2の行の説明

`$v2`にくるのは、

- 0 % 10 = 0
- 1 % 10 = 1

・・・省略

- 9 % 10 = 9
- 10 % 10 = 0
- 11 % 10 = 1

・・・省略

- 41 % 10 = 1

という感じで、（0,1,2,3...9）が5１回繰り返されます。

- 0回目は（`0 % 10 = 0`）なので、結果は0
- 51回目は（`50 % 10 = 0`）なので、結果は0

という感じになります。

# 試したい方へ

https://www.sassmeister.com/

ここで、sassをリアルタイムでコンパイルされますので

```sass
@for $i from 0 through 50 {
  $v1: floor($i / 10);
  $v2: $i % 10;
  .class#{$v1}-#{$v2} {
    width: #{$v1 + "." + $v2}px;
    comment: #{$i + 1}回目 // これは分かりやすくするためのコメントです
  }
}
```

6行目は、実際にcssとしてコンパイルする際は消しておきましょう。今回は、何回目かをしるためにつけただけです。

実際の画像↓
![スクリーンショット 2018-09-17 23.47.32.png](https://qiita-image-store.s3.amazonaws.com/0/14191/86243351-cb10-7bab-c579-698a3193dbe5.png)

以上です！

# 参考
- https://hacknote.jp/archives/1647/
Active Storageで添付した画像ファイルのピクセル情報を取得する

# 概評
* Active Storageで添付した画像ファイルを扱うには[mini_magick](https://github.com/minimagick/minimagick)を使う
* 画像ファイルをmini_magickで処理するときは `MiniMagick::Image.read(xxx.yyy.download)` 経由にする
* ピクセル情報は MiniMagick::Imageの get_pixelsで取得する

# 背景
機械学習で画像取得するrailsアプリ作ろうと思って、railsで画像を保存する方法を調べていたらactive storageに興味がわき、使ったら予想以上に便利だったので紹介。

# 参考
* [【Rails 5.2】 Active Storageの使い方](https://qiita.com/hmmrjn/items/7cc5e5348755c517458a) 
*  [Active Storage の概要](https://railsguides.jp/active_storage_overview.html) 
*  [activestorage/README.md on GitHub](https://api.rubyonrails.org/files/activestorage/README_md.html)）

# 環境
* rails 5.2.1 (5.2でOK)
* imagemagick (入っていなければbrewとかapt-getとかでインストールしてださい。)

# ActiveStorageを使えるようにする
まず、active_storageのインストールをする

```console
rails active_storage:install
```

そうすると、下記のようなmigrationファイルが作成されます。このファイルはとくに何もしなくてOKです。

```db/migrate/20180917060213_create_active_storage_tables.active_storage.rb
# This migration comes from active_storage (originally 20170806125915)
class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
  def change
    create_table :active_storage_blobs do |t|
      t.string   :key,        null: false
      t.string   :filename,   null: false
      t.string   :content_type
      t.text     :metadata
      t.bigint   :byte_size,  null: false
      t.string   :checksum,   null: false
      t.datetime :created_at, null: false

      t.index [ :key ], unique: true
    end

    create_table :active_storage_attachments do |t|
      t.string     :name,     null: false
      t.references :record,   null: false, polymorphic: true, index: false
      t.references :blob,     null: false

      t.datetime :created_at, null: false

      t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
    end
  end
end
```

上記ファイルをmigrationします。

```console
rails db:migrate
```

画像ファイルを扱いたいモデルに下記記述を追加します。たとえば、Foodモデルにhogeという名前で画像ファイルを扱いたい場合は以下のような感じ。


```app/models/food.rb
class Food < ApplicationRecord
  has_one_attached :hoge
end
```

画像処理をしたいので、下記のgemもインストール。
Gemfile

```Gemfile
gem 'mini_magick'
```

これで、準備OK。

# ActiveStorageをコンソール上でファイルを添付する
webのフォームを使う例は、今回は特に説明しません。前述の参考に示したリンクに詳しいです。

コンソールで画像を添付するには `attach` をつかいます。

例えば、 `public/images` 配下に画像ファイルを配置しているとしているとしたら下記のような感じです。

```irb
> food = Food.first
> food.hoge.attach(io: File.open("public/images/#{ファイル名}"), filename: 'image.jpg', content_type: 'application/jpeg')
```

# 添付したファイルをmini_magickに渡してピクセル情報を取得する

downloadメソッドでデータを取得して、取得したdataを `MiniMagick::Image.read` で読み込みます。


rails c で以下実行します

```irb
food = Food.first
data = food.hoge.download # downloadメソッドでデータが取得できる
mini_magick_obj = MiniMagick::Image.read(data) データを読み込む
```

ピクセル情報を取得するには[get_pixels](https://github.com/minimagick/minimagick#pixels)をつかいます。

```irb
mini_magick_obj.get_pixels
```

# 所感
* Active storage便利。carrierwaveと違って、 __モデルにカラムを追加しないでいい__ のがgood。少なくともlocalで扱う限りは、設定最小限で画像がすぐ使える。
* すくなくとも、プロトタイプで画像ファイルを扱うなら、active storageで十分だとおもう。
CycleGANを用いたスタイル変換

2018年9月15日の 機械学習名古屋 第17回勉強会 で話した内容をまとめておきます。
内容は CycleGAN 使って遊んだという話です。そんなに上手くいかなかったけど供養として。

CycleGAN の keras 実装は [https://github.com/kiyohiro8/cycleGAN_keras](https://github.com/kiyohiro8/cycleGAN_keras)
CycleGAN の問題設定や損失設計については [CycleGAN](https://qiita.com/hrs1985/items/050acb15ce33675f07ec) にまとめました。

# Unpaired Image-to-image translation
![image.png](https://qiita-image-store.s3.amazonaws.com/0/134222/d365b56d-8b06-920c-d00b-527c5d1c31bd.png)

# CycleGAN の構造
![image.png](https://qiita-image-store.s3.amazonaws.com/0/134222/71e956ba-4390-0b65-0ebe-f4b9ce5ae090.png)

# Adversarial Loss
![image.png](https://qiita-image-store.s3.amazonaws.com/0/134222/34713aa5-7c72-0f67-ae11-be5294f62d48.png)

# Adversarial Loss だけでは不十分
![image.png](https://qiita-image-store.s3.amazonaws.com/0/134222/f41f66de-68cc-fb94-e0ce-294f203e2974.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/134222/16673b60-f01b-78cf-aa24-88ca712f17af.png)

# Cycle Consistency Loss
![image.png](https://qiita-image-store.s3.amazonaws.com/0/134222/605e02b4-dfa6-6405-147a-1725485c4f5c.png)

# Fully Objective
![image.png](https://qiita-image-store.s3.amazonaws.com/0/134222/d30c8479-d3dd-d6ff-fddf-cd3ebab62160.png)

# 例1 チーズケーキ ⇔ チョコレートケーキ
![image.png](https://qiita-image-store.s3.amazonaws.com/0/134222/1e42fbeb-37e5-1fa6-3e8d-a9023c3189f0.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/134222/ead63fee-4122-0699-1e84-e83833008e0d.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/134222/70bf2316-5ac9-9c6a-7a26-8ac01ac2acea.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/134222/3074a4ab-21c5-3911-0f2a-5ffe07b730af.png)

# 例2 風景写真 ⇔ Magic: the Gathering のイラスト
![image.png](https://qiita-image-store.s3.amazonaws.com/0/134222/58ba3b0e-e312-bb12-3c7d-0abcc5c07fbd.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/134222/6fc82930-f435-7572-9ce2-246de98d875f.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/134222/6b2204f3-2ab5-ab08-1db5-5470af48ff5d.png)

# フルサイズの画像に対する変換例 (風景写真 → イラスト)
全体として暗く妖しい雰囲気になってしまいます。
![000000.jpg](https://qiita-image-store.s3.amazonaws.com/0/134222/46fca055-a6d7-6e51-6407-f3d2913631ec.jpeg)
![000000.jpg.png](https://qiita-image-store.s3.amazonaws.com/0/134222/3511e14c-37c9-9950-6215-2a80c541c952.png)
![000022.jpg](https://qiita-image-store.s3.amazonaws.com/0/134222/2c1c606d-846c-1ed4-61a7-2c92ca7c30d2.jpeg)
![000022.jpg.png](https://qiita-image-store.s3.amazonaws.com/0/134222/955e45d2-4d49-0f64-7411-3ce889e34e22.png)
Teraterm_サイレントインストール

# Teratermのオプション

Teratermをサイレントインストールする要件がある場合。
インストーラー実行時に、下記オプションを追加。

`teraterm.exe /VERYSILENT`
または
`teraterm.exe /SILENT`


# オプションを使う理由
通常のインストールだったら
インストーラー起動して、[次へ]ボタンを押していけばOK。

というかこれ以外の方法でインストールすることはほぼないと思う。

ただ
会社の全パソコンにTeratermを入れることになって
ADのログオンスクリプトで配布するか、資産管理ツール(S●●●●●)で配布するかってなったけど、
その際に[次へ]のユーザー操作が面倒があるから、
インストール実行まではできるけど、そのあとのマウス操作を台数分しないとダメじゃない？ 結局大変じゃね？

→ と思っていたら、 サイレントインストールのコマンドがあった！
　危ない危ない。


# 参考ページ
　[ManageEngine Desktop Central](https://www.manageengine.com/products/desktop-central/software-installation/silent_install_Tera-Term-4.74.html)


~~英語で Google 検索しても英語ページが出にくいの~~
~~どうにか一瞬で切り替えられないですかね……。~~
pdfkitがHostNotFoundErrorを吐く

表題の通りでハマったのでメモ。

PDFKitはPythonからPDFファイルを生成するためのライブラリです。もととなるHTML、あるいはURLからPDFファイルを生成することができます。

しかし、このPDFKit、場合によって`HostNotFoundError`というエラーを吐くことがあります。Tracebackを見ても手掛かりらしい情報が見つからないので難儀しました。

ただこれ、原因は以下のどちらか(あるいは両方)です。

* 元となるHTMLにリンク切れのリソースがある
* 元となるHTMLに「゛」などの特殊な文字が含まれる

もし、PDFKitに通す前のHTMLファイルが残せるようであったら、そちらを確認してみましょう。リンク切れの画像などはないでしょうか？あればリンクを修正するか、そのリンクを消すようにしてみてください。

後者の方は特に、macOSなどの環境からファイルを受け取ったときに注意が必要です。macOSは、「ガギグゲゴ」等の濁点つき文字を「カキクケコ」＋「゛」という二文字で表す場合があるようで、これらがHTMLファイルの名前に含まれていると、上記エラーを吐いてしまう場合があるようです[^1]。

どうしてもmacOSからファイルを受け取らなければいけないときなどは、上記のような問題が起こらないように気をつけるようにしましょう(まあ、英語だけを使うように強制するとかができれば、楽なんでしょうが…)。

[^1]: 濁点文字について、軽く調べたらこんな記事もありました [macOSの濁点問題について \- Qiita](https://qiita.com/mimizq/items/3ebe279d4c2819758ae0)
Androidでビルドにどれくらい時間をかけているというのか。

# 目的

[失われた2人日をiMac Proで取り戻し、開発体験を向上するまでの軌跡　| Pixiv inside](https://inside.pixiv.blog/kobaken/4943)


に触発された。件の記事にはMacbookで500~1000sを一回のビルドあたり溶かしているとある。自分の場合は更にオンボロPC使っているので、より悪い結果になるはず。これを上司につきつけて新しいPCを手に入れるのだ！
僕はAndroid開発なので、Gradleスクリプトを組み、ビルドにどの程度時間がかかっているかトラッキングしてみる。

# トラッキング用コード

トラッキングするコードは以下にようになる。
これをプロジェクトルート側の <code>build.gradle</code>に追加すると、build.logにビルド時間が吐き出される。

``` gradle
long startTime
gradle.beforeProject {
    startTime = System.nanoTime()
}

gradle.buildFinished {
    println "build finished!"
    long execution = (System.nanoTime() - startTime) / 1000000
    println "TIME: ${execution} ms"
    new File("build.log").text += "${Calendar.getInstance().getTime()} : ${execution} ms \n"
}
```

# 環境・条件

PCのスペックは以下のとおり。

| OS | Ubuntu 16.04 |
|---|---|
| CPU | Core i5-660 3.33GHz |
|Memory| ４GB |

確か2011年製だったはず。かなりボロい。メモリはいつもパンパン。

計測するのはAndroidアプリ。ちょっとしたチャットアプリでサンプル程度の規模感です。
clocの結果は以下（ちょっとはしょってる）。

```
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
JSON                           119              0              0           8766
Java                            21             22          12462           7636
XML                             88            478              2           6088
Kotlin                          11             57             12            307
Gradle                           3              9              6             70
-------------------------------------------------------------------------------
SUM:                           245            613          12524          23055
-------------------------------------------------------------------------------
```

# 結果

一日計測してみた。生ログは以下のようになる。

```
Tue Sep 11 09:37:49 JST 2018 : 64257 ms
Tue Sep 11 09:39:09 JST 2018 : 7430 ms
Tue Sep 11 09:39:19 JST 2018 : 8168 ms
Tue Sep 11 09:54:01 JST 2018 : 35668 ms
Tue Sep 11 10:07:39 JST 2018 : 9058 ms 
 :
```

これを合計すると

``` bash
$ cat build.log | cut -c 32- | sed "s/ ms//g" | awk '{sum=sum+$1}END{print sum}'
3247781
```

3247718ms‥ おもったより少ないな。
結果としては、54.1分である。ほぼ0.9時間だな。

# 人月換算

一日0.9時間なので、ビルドにかかる人月は

```
0.9 x 20 = 18 H = 2.25 D
```

というわけで、2人日ちょいのビルド時間を溶かしていることになる‥
あれ？元記事とかわらない‥
もっと時間とかしてる印象なのに‥

# 考察

これを上司につきつけても、「まあ、根性でしばらくがんばれや」と言われかねない。

実は計測するまでもなく、Android StudioのUIのレスポンスはガックガクだし、エミュレータは全く動かない（というか、そういうものだと思っていたら、自宅MacbookでAndroid Studioを動かしてみると、UIがサクサクで、エミュレータも快適だったことに驚愕した記憶がある）くらいにはPCは明らかにオンボロだったのである。

その割にビルド時間が案外短かった要因としては、ビルド後必ずスワッピングするため、UIにコントロールが戻ってくるまで10分程度かかってしまい、単純にビルド回数が少なくなったことが挙げられる。

また、計測したのが、本格的なアプリでなく、ちょっとしたサンプルアプリだということも勘案しなければならない。複雑な市場アプリとはビルド時間はかなり変わってきてしまうだろう。

# 所感

というわけで、あまりに低スペックPCだとビルド時間で上司と戦うのはやめたほうが良さそうだ‥ UIがもさもさした時点でもうこのPCでは開発が**不可能**ですと言い切ってもいいかもしれない。

# ポエム

というか、IDEを諦めたり、UIのコントロールが戻るまでに10分待ったりするような、オンボロ環境と戦っている時間は、人生の無駄でしかない。オートコンプリートを切るだとか軽量エディタを使うだとかのスキルもPCを買えば済む話なので、何の役にも立たないだろう。竹槍で爆撃機は落とせないのだ。

開発会社は現場にこのような悩みを抱えさせず、エンジニアに最良の環境を与えてやるべきだと感じた‥
Pythonで競プロに挑む日誌 vol.12 ~eval 関数~

"可読性" と "コードの長さ" はどちらを優先すべきなのだろうか.  個人的には可読性と思ってる.

# 現在の目標
* 今年の10月内に茶色を取得する
 * [ABC](
https://kenkoooo.com/atcoder/?user=&rivals=&kind=category) の A, B 問題を全部解く**←イマココ**
* 年内に緑色を取得する
 * [ABC](
https://kenkoooo.com/atcoder/?user=&rivals=&kind=category) の C, D 問題を全部解く
* [APG4b](https://beta.atcoder.jp/contests/apg4b) で C++ にも手を出す

#今日の問題
ABC017A - プロコン 
https://beta.atcoder.jp/contests/abc017/tasks/abc017_1

# 結果

```answer1.py
#coding: utf-8
ans = 0
for _ in range(3):
    s, e = map(int, input().split())
    ans += s * e
print(ans // 10)

# 実行時間：17 ms
# メモリ　：2940 KB
# コード長：117 Byte
# 得点　　：100/100

#======================================

#coding: utf-8
li = [list(map(int, input().split())) for _ in range(3)]
print(sum(s * e for s, e in li) // 10)

# 実行時間：17 ms
# メモリ　：2940 KB
# コード長：114 Byte
# 得点　　：100/100
```
普通に書いたらこんな感じになると思います.  ほかの解答を見たら, なるほどな, と思う回答がやはりありました.

```answer2.py
#coding: utf-8
print(sum(eval(input().replace(" ", "*")) for _ in range(3)) // 10)
```
eval 関数を使うと, 引数として与えた文字列が実行されるんですね.

# 今回学んだこと
* [eval 関数](https://qiita.com/Kodaira_/items/30c84806b61792b613f2)

#明日やること
 * [ABC](
https://kenkoooo.com/atcoder/?user=&rivals=&kind=category) を解き続ける.
python37のGoogle App Engine でもバーコードを作る

[PHPでバーコードを作った](https://qiita.com/fumihiko-hidaka/items/6ce6d5651b06ac5595cc)ばかりなのに……
何が自分を駆り立てるのだろうか:neutral_face:

今回は[pyBarcode](https://pythonhosted.org/pyBarcode/barcode.html)というライブラリを使ってみました。

# 実装物！
https://github.com/fumihiko-hidaka/gae-py37-barcode

# 内容！

そんなに難しいことはしていないのです。
Flaskがわかれば簡単かな？

```pybarcode.py
import barcode
from barcode.writer import ImageWriter
from flask import Flask, send_file

@app.route('/', defaults={'_': ''})
@app.route('/<path:_>')
def index(_):
    byte_io = BytesIO()

    ean = barcode.get_barcode('ean13', '4902102072618', writer=ImageWriter())
    ean.write(byte_io)

    byte_io.seek(0)

    return send_file(
        byte_io,
        as_attachment=True,
        attachment_filename='barcode.png',
        mimetype='image/png',
    )
```

>    byte_io = BytesIO()

ファイルを実際に書き出さずにレスポンスとして返してあげたいので書き込み先を用意してあげています。

>    ean = barcode.get_barcode('ean13', '4902102072618', writer=ImageWriter())
>    ean.write(byte_io)

pyBarcodeの使い方に則って、コカコラーのバーコードを作ってます。
作ったものは、先ほど用意した変数に書き込んでいますね。

>     byte_io.seek(0)

ここでシーク位置を元に戻してあげないと、次のdownload処理でゼロバイトのデータが帰ってきてしまうので戻してあげましょう。

>    return send_file(
>        byte_io,
>        as_attachment=True,
>        attachment_filename='barcode.png',
>        mimetype='image/png',
>    )

Flaskのファイルダウンロード処理を実行させて完成です！

# 実際に作成されるもの！

![barcode.png](https://neko-tech-test.appspot.com/gae-py37-barcode)
https://neko-tech-test.appspot.com/gae-py37-barcode

# 今回、本当に確認したかったもの

はい、バーコードは作れたんですが、じゃあこれが本来の目的か？　と言われると少し違っていて。
pyBarcodeって、pythonの画像処理系のライブラリ、PILを使っているんですね。

Google App Engineってstandard環境に、python27を提供していたんですが、PILとかのライブラリってそのままだと使えなかったんですよ。
[third-party-libary](https://cloud.google.com/appengine/docs/standard/python/tools/using-libraries-python-27)として使用するのであれば、app.yamlに使用するように書いてね？っていう。
そうすると、GAE側でインストール済みのものを提供するんで、参照・使用できるよーっていう。

使えるならいいではないか。という話ではあるんですが、ただこれって、利用できるバージョンは制限されてしまうし、逆にPILを使用するようにrequirements.txtとかに書こうものなら今度は動かなくなるみたいな色々と問題があったりして。
デフォルトのものではないので、Google提供のものを使用すると上手く動かないッ！？　みたいなものもポツポツあったりと。

そもそもなんで使えないんだろう？となると、PILを使用する処理の中にgoogleのコンテナの中で動かされると、よろしくないものがある……ので、対策をほどこしたものを提供しているのかな？とは推測しているんですが、そこは確認も取っていないので一回置いておきます。

ただ今回のpython37 runtimeのGoogle App Engineでは、そこが問題にならずにサクッとバーコードを作成できてしまっている。
そう、python37ではこのあたりの問題がクリアされているのです。
gVisorを使用したものでGoogle App Engineを動かしている……らしいんですが、そこのおかげでだいぶ便利になってきたなと。

このまま、もっともっと便利になって貰えることを祈るばかりです:sob:
新しいAndroid向けCUI環境アプリ「UserLAnd」

注意：**UserLAnd正式版がリリースされました**。インターフェースはだいぶ変わっているのでご注意ください。**この記事はベータ版をもとにしています**。

つい最近、Android用の新たなCUI環境としてUserLAndというアプリがベータ版でリリースされた。日本語のドキュメントがなかったので、使ってみた所感をまとめようと思う。

#GNURoot Debian開発終了のお知らせ
最近GNURootDebianがバグって立ち上がらなくなったので再インストールしようとしたら、

>GNURoot Debian has not been maintained in over a year and is broken in many ways.
So, I am sending new users to a new app called UserLAnd which has a paid active dev team, but is still open and does most of what GNURoot Debian did, but better.
You are now sent to UserLAnd in the following cases:
1) you are using android 8.0+, because GNURoot Debian is completely broken for those users.
2) you are creating a new rootfs (unless coming from GNURoot Octave or GNURoot Runescape Installer)

と書かれていた。簡単にまとめると

「もうGNURoot Debianはメンテナンスされてないしいろいろバグってるので、新たに環境構築するならUserLAndという新しいアプリを使ってね」

ということだ。GNURoot Debianをインストールしようとすると、アプリはインストールできるが内部システムがインストールできなくなっていた。

#UserLAndについて
UserLAndは今年の夏ごろに出た新しいアプリだ。なので今はβ版のみがリリースされている。
https://www.linuxjournal.com/content/userland-turnkey-linux-your-pocket

GNURootDebian同様Debianベースのシステムが構築できる他

* OSとしてUbuntuも使える
* bVNCを使ったGUIも使える

という点で上位互換になっているらしい。

#インストール
GooglePlayからインストールする。
https://play.google.com/store/apps/details?id=tech.ula

また使うにはConnectBotというSSHクライアントが必要になる。
https://play.google.com/store/apps/details?id=org.connectbot
今後は別のSSHクライアントでも利用できるようにする予定らしい。

UserLAndを起動すると、ホストの一覧が表示される。インストールした直後は項目が何もない。

![IMG_7gr93i.jpg](https://qiita-image-store.s3.amazonaws.com/0/107045/27ffae4e-bd86-b662-1d6f-2883150ef5c4.jpeg)

新たにセッションを作成するときは右上の「＋」を押す。

![Screenshot_20180917-223951.png](https://qiita-image-store.s3.amazonaws.com/0/107045/0432e66d-afb2-3526-3182-26ea588b7635.png)

ここでセッション名やファイルシステムを指定する。Service TypeはSSH（CUIのみを使うとき）かbVNC（GUIも使うとき）を選択する。Userは現段階では変更できなくなっている。

最初はファイルシステムが存在しないので、画像ではUbuntuとなっている部分がCreate Newとなっており、選択するとファイルシステムの新規作成へ移る。

![Screenshot_20180917-223957.png](https://qiita-image-store.s3.amazonaws.com/0/107045/00cc1499-58ae-07d1-48c6-57af986ac0a5.png)

ここで作成したファイルシステムは、ホストを複数作成した際に共用することができる。FileSystemはDebianとUbuntuから選択する。

設定が完了したら、右上のフロッピーっぽいマークを押す。セッションの設定が終了すると、tarがダウンロードされて解凍され、ログイン画面へ遷移する。このときConnectBotがインストールされていないとエラーが出る。


ログを見る限りでは、localhostにSSHでつないでいるようだ。認証に成功するとめでたくbashが立ち上がる。なおこの画面はどういうわけか通常では縦画面でしか開かず、ハードウェアキーボードをつないでいると横画面になる。

![Screenshot_20180917-225006.png](https://qiita-image-store.s3.amazonaws.com/0/107045/d4ac5724-8c1f-965a-1255-bc8d1aa12c06.png)

debian/Ubuntuベースなのでaptでパッケージをインストールする(sudo必須)。ユーザーはデフォルトはuserとなっているが、```sudo su```でrootになることもできる。useraddすれば新規ユーザーの作成もできる。

ConnectBotの設定で、画面の縦横やフォントサイズを指定できる。フォントサイズについてはボリュームキーでも変更できる。

#所感

* GNURoot Debianの上位互換というのはそのとおりだと思う。GNURoot Debianで使えたパッケージはだいたい使える。新規で使うならUserLAndを使っておけばいいと思う。
* SSHを経由するので、ConnectBotと連携が微妙な印象。詰まったときはどっちもkillしてやり直せばOK。
* openmpiでmpiexecするとmpi_finalizeでシステムごと落ちるバグがつぶれていない（そもそもこういう環境でそんなものを求めるなとも）。
* 環境側ではユーザーがuserで固定なのにuseraddできるのは少し不可解。
【イベント参加】Osaka Mix Leap Study 特別編 - CTO Night KANSAI

こんにちは、@tacashionです。

# CTO Night KANSAI

9/14（土）、ヤフー株式会社大阪オフィスで行われた「[Osaka Mix Leap Study 特別編 - CTO Night KANSAI](https://yahoo-osaka.connpass.com/event/98286/)」に参加してきました。

> 関西に拠点のあるテクノロジー企業のCTOを迎えて各企業のエンジニアのトップがどういった役割を担っているか、CTOのこれまで、今、そしてこれからについてトークやディスカッションを行います。

とのことで、各社の、というかCTOをされている方の役割や、どんなことを考えているのかに興味があり、行ってきました。

最初に、「ブレイクアウトセッション」という各社のエンジニアの方がプレゼンテーションされるイベントもあったのですが、予定が合わず参加できず。本編の各社CTOの皆さんのパネルディスカッションから参加しました。

## 登壇者の皆様
まずはじめに、登壇されるCTOの皆さんの自己紹介がありました。

* [株式会社はてな](http://hatenacorp.jp/)大坪 弘尚（@motemen）さん CTO+APPエンジニア。 技術部門の生産性向上・評価・育成や技術情報の横展開を行う。 
* [株式会社ハカルス](https://hacarus.com/ja/)染田 貴志（@tksmd）さん ベンチャー立ち上げからCTOという立場になり、現在は株式会社ハカルスCTO。 業務では機械学習による診断・治療支援などを提供している。

* [ヤフー株式会社](https://about.yahoo.co.jp/)藤門 千明（@mikanmarusan）さん 秒間250万トラフィックのYahoo! JAPANを支える技術の責任者。 CTOとして一番難しいのは「決断」して「伝える」こと。

※自己紹介の際、名前と並んでアカウントがあるのがITっぽいです。

*当日のメモ。盛りだくさん。*
![4A5CD8DE-D353-4C23-9402-BDA070303CEC.jpeg](https://qiita-image-store.s3.amazonaws.com/0/289530/d94090c2-9058-f9cb-dce2-e05a7b1d2454.jpeg)

##パネルディスカッション

![2313491D-FB10-4CDC-B7D6-E5A854879E7B.jpeg](https://qiita-image-store.s3.amazonaws.com/0/289530/94559b10-2563-60b1-5036-c182c72acb37.jpeg)

*大盛況の会場*

モデレーターである[株式会社シナジーマーケティング](https://www.synergy-marketing.co.jp/)CTOの伊藤純一さんの進行で、用意されていたお題の他、会話の中から派生した質問の意見や考えなどを登壇者が語っていく、という形式でした。

いくつか印象に残ったものをメモ…

### エンジニアの魅力と覚悟とは

* はてな大坪さん 
魅力：サービスを生み出すこと
 覚悟：学び続けること

* ハカルス染田さん 
魅力：コードを書くことの楽しさ！世の中に与えるインパクト
 覚悟：（やはり）学び続ける

* ヤフー藤門さん 
魅力：ユーザーが使ってくれる！ 
覚悟：（やはりやはり）学び続ける

ここでは皆さん表現は違っていても、意見はほぼ一致しているようで、魅力としては「サービス・ユーザーに利用されて、世の中に影響を与えるものを生み出すこと」、覚悟としては「常に新しい技術を知り、学び続けること」が必要なようです。
このあたりはエンジニア・デザイナー共通して言えることかなと思い、共感しつつ、CTOといえど（むしろだからこそ、という雰囲気）学び続ける姿勢に感銘を受けました。

### CTOの考えるCTOの役割とは

* はてな大坪さん 
技術部門調の長として、個々人の幸福や全体の生産性に責任を持つ。

* ハカルス染田さん
 テクノロジー業界における自社の立ち位置を認識する。

* ヤフー藤門さん
 非技術の経営陣と会話し、理解してもらう。

このフジモンさんの回答に対し、染田さんが「説得の際にコツみたいなものはあるんですか？」という質問に「1つ1つ説明していくしかないんです…！」と答えていたのが印象的でした。何事にも銀の弾丸はない、と。皆さん会社の経営陣や、顧客の方とのコミュニケーションは重要かつ苦戦しているようです。

どうすればより伝わるか、理解してもらえるかはどんな立場でもずっと付きまとう課題なんですね。。

### CTOの次のキャリアは…

* はてな大坪さん 
経営に関わる→さらに役割をスケールする

* ハカルス染田さん
 自分たちの世代は80くらいまで働かないといけないと思うので…w50くらいで再び学生したりしたいですね。

* ヤフー藤門さん 
若い世代につないだ後、全く新しい25年を自らが作る。

人生100年といわれていることもあり、CTOという役割は「終着点」ではなく、そこから更に発展していく考えをお持ちのようです。（キャリアのギア・チェンジと表現されていた）

### 部下の方が技術力が高い問題
会場からの質問として「最近、部下の方が技術について詳しくなってきたのですがどうすればよいでしょうか」という質問がありました。
それに対しては、

もちろんすべての技術について精通していることはありえない
技術力でマウントを取るのではなく、CTOとして別の役割があるのだと認識すること
それは部下が育ったということ。良い組織になったと誇るべき

などなど、ポジティブに捉えましょう、という意見でした。

ここでも様々な話が広がっていたのですが1点印象に残っているのが、はてな大坪さんの「若いエンジニアにCTOとしてスべきと思っているのは場を整えること。若者のモチベーションを会社の利益へつなぐ役目」とおっしゃっていたこと。
これをやりなさい、ではなく、若手エンジニアがやりたいと思っていることをどう活かすかを真剣に考えられているCTOがいることで、「お客さんの声を技術者もみている。それによりやる気が上がる」「俺たちイケてるよね！を大切にしている」「[Mackerel](https://mackerel.io/ja/)のスピード感すげえ！（試用していたらアンケートが来て回答するとすぐに改善リリースされた事がある！という藤門さんのエピソードのあと。）」というはてなさんの良い社風につながっているのかなと感じました。

## まとめ

あっという間に50分のディスカッションも終わり、皆さんの最後の一言へ。

* はてな大坪さん 
自分としても勉強になりました！今日の話をきっかけにCTOを慮ってください（笑）

* ハカルス染田さん 
これから先、色々なタイプのCTOが生まれてくると良いなと思います。

* ヤフー藤門さん
 成長し続けるものがCTOです（生）温かく見守ってください（笑）

デザイナーの自分から見るとスーパープログラマーというイメージしかなかったのですが、若手の育成や、組織にどんな技術を採択するかの選定、また非エンジニアの関係者とのコミュニケーションなど、様々な一面を垣間見ることが出来て大変興味深いイベントでした。
Firebase OSSにPRしたけど「もう少し確認したら良かった」と思いながら自らCloseした経験談

# 前置き
技術的な原因よりもOSS　PRの経験に焦点を当てた記事です。誤解を防ぐため最初に結末をお伝えすると自らCloseしています。「ビルドエラー」などOSSのソースコードに不備があるかような表現は「途中まで思っていた」と解釈してください。故にタイトルに「もう少し確認したら良かった」とつけています:bow:
個人でiOS/Androidのネイティブアプリを作ろうとしてFCMの[サンプルコード](https://github.com/firebase/quickstart-ios/tree/master/messaging)を触っていたところ私の環境ではビルドエラーになりました。原因判明したのでPRしました。

# PRしたOSS
iOSのFCMでプッシュ通知を受信するためのサンプルコードです。
https://github.com/firebase/quickstart-ios/tree/master/messaging

# PRの内容
[GoogleのCLA](https://cla.developers.google.com/about/google-individual?csw=1)に同意して「importするモジュールが不足している」旨を[PR](https://github.com/firebase/quickstart-ios/pull/544)しました。Githubをご覧頂ければCloseした経緯はネタバレ同然:sweat_smile::sweat_smile:なのですが、記事として最後まで書きます。[修正個所は1行](https://github.com/firebase/quickstart-ios/pull/544/commits/0973b6b19ccdd6935eeec89bdd824f3b7bec2189)のみです。

```swift:messaging/MessagingExampleSwift/AppDelegate.swift
  import Firebase
+ import FirebaseMessaging
```
この1行が無いとそれに該当するモジュールのクラスが認識されずビルドエラーになっていたのです。なお、現在Githubをみるとfromのリポジトリがunknown repositoryになっていますが筆者が削除したためだと思います。

# PRした直後
ここは余談になります。CLAの同意確認やTravis CIのビルドが動いていました。
![git1.png](https://qiita-image-store.s3.amazonaws.com/0/240974/36126344-b32c-09da-5fcc-1a5126c9dbe4.png)
![git2.png](https://qiita-image-store.s3.amazonaws.com/0/240974/527a721e-a606-78ad-8fa0-44e8435bc8d4.png)

# レビュー
レビュアーさんからコメントを頂きました。Google機械翻訳です。
> その上にあるFirebaseのimport文に自動的にインクルードされるはずですが、これが失敗したのは初めてではありません。このビルドの問題は、実際にプロジェクトをビルドしようとすると消え去るのですか、それともビルドに失敗するのでしょうか？

もう一度筆者の修正を見ながらレビュー結果と照らし合わせると、要するに```import Firebase```があれば問題無いはずの想定のようですね。

```swift:messaging/MessagingExampleSwift/AppDelegate.swift
  import Firebase
+ import FirebaseMessaging
```

# 調査する
> Firebaseのimport文に自動的にインクルードされるはず

指摘頂くと「なぜ自動的にインクルードされないのか？」を調査したくなりました。結果としてはCocoaPodsのキャッシュ周りをクリアしてビルドしたら```import FirebaseMessaging```を削除しても問題無く動作しました。なんだか申し訳ない気持ちになりました:pray:

```
rm -rf ~/Library/Caches/CocoaPods/
rm -rf Pods
pod install
```

# 結果を伝える
調査した結果を伝え問題が解決したことと、レビュアーさんに筆者のこのコメントを確認して頂いたらCloseする旨も伝えました。

# Closeする
> このインポートを追加する価値があるかもしれません。

とコメントを頂きましたが、CocoaPodsのキャッシュをクリアしたら動いたわけですし、筆者はシンプルな方を好むのでCloseさせて頂くことにしました。

# 終わりに
「PRしてマージしてもらった！」とか「PRしたのでマージされることを気長に待ちましょう！」という情報は多かったのですが「自らCloseした」情報はあまり見かけなかったので書いてみました。(実際の事例はあるのでしょうが情報として発信していないのかもしれません。)
タイトル名に繋がってきますが「もう少し確認したら良かった」とは思いますね。今回の例で言えばレビューして頂き初めて「自動的にインクルードされる」と分かりOSSで想定されている動作を調査することができたので勉強になりました。熟練した方々はすぐに「自動的にインクルードされる」と分かるのかもしれませんね。OSS PRの意欲が萎えたりしていませんので引き続きやっていこうと思います。初マージされたら記事を書かせて頂くかもしれません。
wordpressテンプレートづくり

##テンプレート作成手順
1. テンプレート用のhtmlを作成
2. index.phpとstyle.cssを作成
3. index.phpからheader.php, footer.php, sidebar.phpを作成
4. 固定ページ（page.php）を作成
5. 記事一覧ページ（blog.php）を作成
6. 記事ページ（single.php）を作成
7. テーマのための関数（function.php）を作成

##共通パーツの読み込み方
`適当なスラッグ名-適当なテンプレート名.php`という形で共通パーツのファイルを作成。テンプレート名はなくてもOK。読み込みたい箇所で下記のメソッドを呼ぶ。
`<?php get_template_part('スラッグ名', 'テンプレ名'); ?>`
引数のテンプレ名を省略することもできる。該当のテンプレ名のつくファイルが無ければ、`スラッグ名.php`が読み込まれる。

##functions.php
1. カスタムフィールドやカスタムウィジェットを使うとき、何かの処理のかたまり（関数）を作りたい場合には`functions.php`に書いていく
2. カスタムヘッダー機能を使うには`add_theme_support()`を使う
3. カスタムヘッダーを表示するimgタグのパスには`header_image()`を使う
4. カスタムメニュー機能を使うには`register_nav_menu()`を使う
5. カスタムメニューを表示する箇所には`wp_nav_menu()`を使う

##カスタムフィールドとは
管理画面に入力フォームをつくり、入力された情報を指定した箇所へ表示できる仕組み。投稿ページか固定ページの入力画面に作れる。基本的にはカスタムフィールドで入力した値は固定ページなら入力した固定ページ内でしか使えない。

##カスタムフィールド作り方
管理画面にフォームを表示する関数、フォームをどこに表示するか設定する関数、フォームに入力された情報をDBへ保存する関数の３つを作る。

##カスタムウィジェット作り方
1. カスタムウィジェットは、ウィジェットを登録するエリアを作る関数と、ウィジェット本体を作成するクラスを作る。
2. ウィジェット登録エリア作る関数内では`register_sidebar()`を使う。
3. ウィジェット本体を作成するクラス内では、初期化メソッド、入力フォームを作成するformメソッド、入力情報を保存するupdateメソッド、htmlテンプレートを作成するwidgetメソッドの４つを作る。


>[ウェブカツ！！](https://webukatu.com/?afid=p5lxu1kvh03rayd2ctjsw4e9bgzq8nom)
EC2(Amazon Linux) に構築したアプリのログを CloudWatch に転送する

## 事前準備

EC2 から CloudWatch へアクセスできるように、EC2 に適用されているロールに CloudWatchLogsFullAccess を追加する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30578/d6b3cfa0-ecec-fbfc-ca39-be8fc591ca43.png)

## awslogs のインストール

- EC2 に SSH 接続
- awslogs をインストール
<pre>
>sudo yum install awslogs -y
</pre>

## awslogs の設定変更

### 念のため既存設定をバックアップしておく
<pre>
>cd /etc/awslogs/
>sudo cp awscli.conf awscli.conf.org
>sudo cp awslogs.conf awslogs.conf.org
</pre>

### awscli.conf の編集

<pre>
>sudo vi awscli.conf

リージョン変更（おそらく転送先の CloudWatch のリージョンのこと）
  region = ap-northeast-1

</pre>

終わったら、上書き保存する

### awslogs.conf の編集

CloudWatch Logs エージェントのリファレンス - Amazon CloudWatch ログ
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/AgentReference.html

<pre>
>sudo vi awslogs.conf

末尾のほうのセクションごと以下に書き換える。
元々存在する [/var/log/message] のセクションごと上書きして、以下のような設定にする。

例）ログファイルごと
[/logs/MyApp/MyAppLogin]
datetime_format = %Y-%m-%d %H:%M:%S
file = /logs/MyApp/MyAppLogin.log
buffer_duration = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = /logs/MyApp/MyAppLogin

例）ログファイルまとめて
[/logs/MyApp]		
datetime_format = %Y-%m-%d %H:%M:%S		
file = /logs/MyApp/MyApp*.log		
buffer_duration = 5000		
log_stream_name = {instance_id}		
initial_position = start_of_file		
log_group_name = /logs/MyApp		

それぞれ以下のような意味
[]  セクション名（CloudWatch Logs のロググループ名とあわせておくとよさげ）
datetime_format = ログの日時フォーマット
file = ログファイルパス
buffer_duration = バッファ（おそらくこの時間分貯めて、送信している？）
log_stream_name = ロググループ内のストリーム名
initial_position = 初期ポジション（特に変える必要はないかな、、）
log _group_name = CloudWatch Logs のロググループ名

</pre>

編集が終わったら、上書き保存する。

## awslogs サービス制御

<pre>
>sudo /etc/init.d/awslogs start
Starting awslogs:                                          [  OK  ]

>sudo chkconfig awslogs on
>sudo chkconfig --list | grep awslogs
awslogs         0:off   1:off   2:on    3:on    4:on    5:on    6:off

</pre>

## 料金例

調べた時の料金です。（参考）
リージョン：ap-north-east1

| サービス       |　料金 |    補足    |
|:-----------------|------------------:|:---------------------|
| S3              |0.025 $/GB| 標準ストレージ、最初の 50 TB/月        |
| CloudWatch Logs |0.760 $/GB|  取り込み GB あたり        |
| CloudWatch Logs |0.033 $/GB|  GB あたりのアーカイブ        |

- アーカイブ料金は S3 とそこまで大差ない
- 取込料金が若干かかるので、ログ量が膨大な場合は料金に注意が必要


## 参考資料

AmazonLinux2のシスログをCloudWatch Logs に転送させてみた ｜ Developers.IO
https://dev.classmethod.jp/cloud/aws/awslogs-amazonlinux2/

Amazon CloudWatch Logsを試してみる | 株式会社ビヨンド
https://beyondjapan.com/blog/2016/07/amazon-cloudwatch-logs
sedコマンドメモ

# 1行目に文字列を追加

```bash:sample.com
$sed -i '1s/^/line to insert\n/' test.txt
```

# 1行目を削除
```bash:sample.com
$sed -e '1d' test.txt
```

# 最後の行を削除
```bash:sample.com
$sed -e '$d' test.txt
```

# htmlタグを消す
```bash:sample.sh
$ sed 's/<[^>]*>//g'
```

# 空白削除
```
$ sed 's/ //g'
```

# 参考

http://takuya-1st.hatenablog.jp/entry/2014/08/07/012422
Kotlinとポケモンで学ぶデザインパターン【第3章 TemplateMethod 】

# はじめに
1. [Kotlinとポケモンで学ぶデザインパターン【第1章 Iterator】](https://qiita.com/rui_qma/items/4d4fd9a85834485519cb)
2. [Kotlinとポケモンで学ぶデザインパターン【第2章 Adapter】](https://qiita.com/rui_qma/items/f519733966b86b8ab5b9)
3. Kotlinとポケモンで学ぶデザインパターン【第3章 TemplateMethod 】

第三回となります。今回はTemplateMethodパターンを書いていきます。
#【第3章 TemplateMethod 】
TemplateMethodパターンは、文字通りテンプレートの機能を持つパターンです。
大まかな流れとしては、**スーパークラスで処理の枠組みを定め、サブクラスでその具体的内容を定める**ことになります。
TemplateMethodパターンを適用するメリットは以下のようになります。

- 一連の処理の手続きを関数にまとめることが出来るので、関数の抽象度が高まる
- 関数を継承によって差し替えるだけでいいので、拡張性が高まる

# 実装
今回はTemplateMethodパターンを適用してモンスターボールを投げてポケモンをゲットする流れをまとめます。
まず、ポケモンと遭遇し、ボールを投げて、結果を表示する。という処理を抽象化した抽象クラスを作ります。
AbstractCaptureクラスでは、encount, ballThrow, resultメソッドが実体のない抽象クラスとなり、抽象メソッドを使っているcaptureが**テンプレートメソッド**となります。

```Kotlin:AbstractCapture.kt
abstract class AbstractCapture {
    abstract fun encount(pokemon: Pokemon)
    abstract fun ballThrow()
    abstract fun result(pokemon: Pokemon)

    fun capture(pokemon: Pokemon) {
        encount(pokemon)
        ballThrow()
        result(pokemon)
    }
}
```
ポケモンを表すデータクラス

```Kotlin:Pokemon.kt
data class Pokemon(val name: String)
```
野生のポケモンを捕まえる具象クラス

```Kotlin:WildCapture.kt
class WildCapture: AbstractCapture() {
    override fun encount(pokemon: Pokemon){
        println("あ！ やせいの\n${pokemon.name}が とびだしてきた！")
    }

    override fun ballThrow(){
        println("レッドは モンスターボールを なげた！")
    }

    override fun result(pokemon: Pokemon) {
        val num = Random().nextInt(2)
        println(if(num == 0) "やったー！\n${pokemon.name}を つかまえたぞ！" else "ああ！\nつかまえたと おもったのに！")
    }
}
```
人のポケモンを捕まえる具象クラス

```Kotlin:TrainerCapture.kt
class TrainerCapture: AbstractCapture() {
    override fun encount(pokemon: Pokemon){
        println("あいては\n${pokemon.name}を くりだした！")
    }

    override fun ballThrow(){
        println("レッドは マスターボールを なげた！")
    }

    override fun result(pokemon: Pokemon) {
        println("トレーナーに ボールを はじかれた！")
        println("ひとの ものを とったら どろぼう！")
    }
}
```
抽象クラス型の変数に具象クラスのインスタンスを代入し、テンプレートメソッドを呼び出します。

```Kotlin:MainActivity.kt
val pikachu = Pokemon("ピカチュウ")

val wild: AbstractCapture = WildCapture()
wild.capture(pikachu)

val trainer: AbstractCapture = TrainerCapture()
trainer.capture(pikachu)
```

```:実行結果
あ！ やせいの 
ピカチュウが とびだしてきた！
レッドは モンスターボールを なげた！
やったー！
ピカチュウを つかまえたぞ！

あいては
ピカチュウを くりだした！
レッドは マスターボールを なげた！
トレーナーに ボールを はじかれた！
ひとの ものを とったら どろぼう！
```
1回しか見たことないはずなのに記憶にずっと残ってます。

#【Kotlin文法】式展開
Kotlinは文字列中に`$`で変数が、`${}`で式が書けます。

```Kotlin:Kotlin
fun encount(pokemon: Pokemon){
    println("あ！ やせいの\n${pokemon.name}が とびだしてきた！")
}
```

Javaならばこう

```Java:Java
void encount(Pokemon pokemon){
    System.out.println("あ！ やせいの\n" + pokemon.name + "が とびだしてきた！")
}
```

変数使ってSQLをベタ書きする時とかに式展開できる言語だと凄い楽ですね。
ちなみにRubyの式展開は`#{}`です。
クリーンアーキテクチャの書籍を読んで

# 書籍
[この本](https://www.amazon.co.jp/gp/product/B07FSBHS2V) を読んだ所感をまとめる。
あくまで個人の所感なので、見当違いな可能性もあるかと。

# この書籍の伝えたいことの理解
アプリケーション境界をどのように定め、依存関係をコントロールするかの方針を教えてくれる本。
フレームワークの選定とかの話はささいな詳細として取り上げられている。

# クリーンアーキテクチャを採用する利点
1. テストしやすい
2. UI/DB/フレームワークを変更しやすい
3. ロジックがある個所が明確になる
4. 依存性が明確になる

# 気になったところ
## ビジネスルールとアプリケーションルールの違いは？
### ビジネスルール
アプリケーションがなくても存在するルールのこと。
例）
### アプリケーションルール
アプリケーションがあるからこそ出現するルールのこと。
例）Web から入力された値のバリデーション
## いつ境界を引くべきなのか？
詳細についての決定を遅らせることの重要性を力説している。
フレームワークの選定、DBの選定。

一方で、重要なものはいつ決定すべきか？
境界を後から追加するのはコストが高い。

書籍には明記されていて、まずは未来を見据えてシンプルに作り、その後は見張り続けることが重要。
境界を作らないことによるコストと境界を作るコストを比較し続ける。

## クリーンアーキテクチャを厳密に守るべきか？
クリーンアーキテクチャを採用した場合でも、すべてを厳密に守る必要はない。
実際、書籍にも「部分的な境界」を引くための例が書かれている。
なので、厳密に守るうえでのコストと守らないうえでのコストを対比させて判断すればよい。

ただし、依存関係を守らないコードが生まれやすくなる個所が発生することになるので、当時その判断をしたこと自体を明確にし、将来的にも再度対比できるようにしておくべき。

# さいごに
クリーンアーキテクチャの思想の理解をするのにとても良い本。
アプリケーションの「設計」を考える上で迷ったらこの本を読んで、原理原則を整理できると思う。
Go言語を真剣に勉強してみた〜環境構築編〜


#はじめに
こんにちは。ご無沙汰しております。某学校でプログラミング等の勉強中のサーバーサイドのプログラマーのわたのん改めワタタクです。わたのんよりワタタクの方がしっくり来ますw
さて、今回PHP等のオブジェクト指向の言語ばかりやって来た僕なんですが何故かGoを真剣に勉強してみたいと思い、真剣に勉強中です。:point_up_2:
#環境構築
*まず初めに事前準備として、[Homebrew](https://brew.sh/) をインストールしておいてください。*
1. goのインストール

```
$ brew install go
```

2.インストールが完了したら以下のコマンドを叩いて、ヴァージョン情報が出ればインストールが完了！お疲れ様でした。

```
$ go version
```

#HelloWould
では、インストールもでき環境も構築できたので、Hello Wouldと表示してみたいと思います。
以下のコードをエディターに記述してください。

```golang:hello.go
package main
import "fmt"

func main() {
	fmt.Println("HelloWould");
}
```
軽くコードの説明をしますと、go言語には便利な機能をまとめたパッケージと言うものがあり、その中の**"fmt"**と言うパッケージを読み込み(**import**)使用します。
*＊パッケージについてはまた後日深く触れようと思います。*
その**"fmt"**パッケージのPrintlnを使って表示しています。ちなみにgoはmain()関数から実行されます。
#実行
Go
|-hello.go 

**cd**コマンドでGoディレクトリまで移動して来て、以下のコマンドを叩く。

```
$go run hello.go
```
#ビルド

```
$go build hello.go
```

以上。
goは真剣に勉強を始めてまだ日も立っていないので、間違っている点、知識不足な点などがいっぱいあると思いますがよろしくお願いします。
もし何か間違っている等のご指摘があればご連絡ください。
最後まで読んで頂きありがとうございました。
次回は「Go言語を真剣に勉強してみた〜基本構文編〜」です。
PostgreSQL＋JPAのIDカラムで「relation "hibernate_sequence" does not exist」となったときの対処

PostgreSQL＋JPAのIDカラムでシーケンス利用時にエラーになった際の対処メモ。

# 現象

PostgreSQL（10.0）で

```sql
create table employee (
  employee_id serial not null,
  employee_name text,
  constraint employee_PKC primary key (employee_id)
);
```

のようなテーブルがあったときに、JPAで

```java
@Entity
public class Employee {
    @Id
    @SequenceGenerator(name = "employee_employee_id_seq")
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Integer employeeId;

    private String employeeName;

    // Getter/Setter
}
```

とアノテーションを付与しておくと、レコードのsave時に

```
org.postgresql.util.PSQLException: ERROR: relation "hibernate_sequence" does not exist
```

というエラーが出た。
どうやら、デフォルトのシーケンス名が参照されてしまう模様。

# 対処

2通りある。

## シーケンス名を明示的に指定する方法

何回もシーケンス名を書かないといけないのが難点。

```java
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "employee_employee_id_seq")
@SequenceGenerator(name = "employee_employee_id_seq", sequenceName = "employee_employee_id_seq")
private Integer employeeId
```

## GenerationType.IDENTITYを使用する方法

こちらの方がシンプル。

```java
@Id
@SequenceGenerator(name = "employee_employee_id_seq")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer employeeId;
```
AWS SNS で unsubscribe できないようにする

# AWS SNS で unsubscribe できないようにする方法

間違って unsubscribe しないようにするための手順メモ。

## AWS CLI 環境を用意する

## SNS トピック購読時の URL を用意する

<pre>
https://sns.ap-northeast-1.amazonaws.com/confirmation.html?TopicArn=arn:aws:sns:ap-northeast-1:123456...

</pre>

みたいな URL。

### URL の構造

本当は一行だけど、パラメータごとに改行したら、以下のような感じ。

<pre>
https://sns.ap-northeast-1.amazonaws.com/confirmation.html?
  TopicArn=arn:aws:sns:ap-northeast-1:1234567890:XXXXYYYYZZZZ&
  Token=やたら長いトークン&
  Endpoint=hogehoge@sample.com
</pre>


## 前項の URL の情報からコマンドラインを作成する

本当は一行だけど、パラメータごとに改行したら、以下のような感じ。

<pre>
aws sns confirm-subscription
  --topic-arn arn:aws:sns:ap-northeast-1:1234567890:XXXXYYYYZZZZ
  --token やたら長いトークン
  --authenticate-on-unsubscribe true
  --region ap-northeast-1
</pre>

## AWS CLI の環境で、前項で作成したコマンドを実行する

<pre>
> aws sns confirm-subscription --topic-arn arn:aws:sns:ap-northeast-1:*** --token *** --authenticate-on-unsubscribe true --region ap-northeast-1

を実行して成功すると、以下のような出力が得られます。

{
    "SubscriptionArn": "arn:aws:sns:ap-northeast-1:***"
}
</pre>

## 動作確認

購読した時の unsubscribe リンクを押してみる。（以下の「赤線」部分）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30578/8073535c-fa30-92b3-6555-561eb18aa0d3.png)

以下のように「Subscription not removed」と表示されて、無効化できていることが確認できます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30578/b5d746f5-674e-14f2-61cc-53b2cd4c595b.png)

## 参考リンク

unsubscribe - AWS CLI
https://docs.aws.amazon.com/cli/latest/reference/sns/unsubscribe.html	

Amazon SNS メール通知の「unsubscribe」リンクを無効化する
https://dev.classmethod.jp/cloud/aws/amazon-sns-disable-unsubscribe-link
Matlab の図を余白のない pdf で保存する方法

このメモでは Matlab の図を無駄な余白のない pdf ファイルで保存する方法についてまとめます。

# 問題

普通に figure 画面で「ファイル」->「名前を付けて保存」から pdf 形式で保存をすると、次のような無駄に余白のある pdf ファイルができます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/229492/a50ec880-d19f-fb44-7f58-a7ea6e8b3485.png)

png 形式で保存するとこんなに大きな余白はできないのですが、LaTeX でベクトル形式の図を貼りたかった私は pdf 形式でも無駄に大きな余白がない図を保存したいと思い、設定を調べてみました。

# 対処法

pdf への出力では印刷用の用紙サイズの設定が利用されているようなので、それを一旦変更してから保存を行うスクリプトを作成しました。

~~~~~{SaveFig.m}
function SaveFig(fig, filename)
%
% SaveFig(fig, filename)
%
% 引数figに指定されたfigureをfilenameの名前のpng,pdfファイルで保存する。
% filenameは拡張子をつけない。
%
% 例：SaveFig(figure(1),'example')

% 終わってない描画処理があったら終わらせる
drawnow;

% 紙のサイズを変える。
temp.figunit = fig.Units;
fig.Units = 'centimeters';
pos = fig.Position;
fig.PaperPositionMode = 'Auto';
temp.figpaperunit = fig.PaperUnits;
fig.PaperUnits = 'centimeters';
temp.figsize = fig.PaperSize;
fig.PaperSize = [pos(3), pos(4)];

% 保存する。
print(fig,filename,'-dpdf','-r300','-bestfit')
print(fig,filename,'-dpng','-r300')

% 設定を元に戻す。
fig.PaperSize = temp.figsize;
fig.Units = temp.figunit;
fig.PaperUnits = temp.figpaperunit;

end
~~~~~

なお、この関数は png 形式の図も一緒に作っています。
（png の方が Microsoft Office では使いやすい。）

この関数を使って、例えば

~~~~~{.m}
h = figure;
fplot(@sin);
xlabel('x');
ylabel('y');
title('y=sin(x)');
SaveFig(h,'test');
~~~~~~

とすると、次のような test.pdf ファイルが生成されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/229492/3da6d52a-289a-cff1-0302-e6613178bd6a.png)

無駄な余白のない pdf 形式の図が出力できました。

# あとがき

今回は2年くらい調整しながら使い続けているスクリプトを紹介しました。
ちょっとしたスクリプトですので、私に責任を問わないという条件のもとであれば自由にコピペして構いません。ただ、役に立ったことをコメントやいいねで告げていただけると喜びます。