OmniAICreator/Qiita-1.07M huggingface dataset:
Railsチュートリアルメモ - 第12章

[メモの目次記事はこちら](https://qiita.com/yokohama4580/items/dedfd5510080273dc2a0)

[公式Railsチュートリアル第12章へのリンク](https://railstutorial.jp/chapters/password_reset?version=5.1#cha-password_reset)

## サマリ
- パスワードの再設定
    - パスワード再設定メールの送信
    - トークンによる認証とパスワードの再設定

## ポイント
- パスワードリセット機能はUserモデルを拡張して使用するため、MVCのうち新たに作成するのはViewとControllerのみで良い
- 処理のコントローラーのアクションがいろいろ登場するので、流れを整理しないと混乱する

```
sessions/new.html.erb
→password_resets_controller#new
→password_resets/new.html.erb
→password_resets_controller#create
→メール送信
→password_resets_controller#edit
→password_resets/edit.html.erb
→password_resets#update
```
- `@user.authenticated?(:reset, params[:id])`でresetトークンとDBに保存されたダイジェストを照合する
- パスワード再設定用メールを送信する際に、パスワードリセットトークンとダイジェストを生成する。
    - トークンはメール内のリンクに埋め込んでユーザーに送付する
    - ダイジェストはDBに保存し、リンクが開かれた際に両者を照合して本人であることを確認する
- #edit時点では、メール内のリンクに埋め込んだURLパラメーターからメールアドレスを取得できるが、#updateは画面から呼び出すので、同じ方法でメールアドレスを取得することができない。そのため、edit.html.erbの中の隠しフィールドにメールアドレスを持たせて#updateに引き渡す。
    - `<%= hidden_field_tag :email, @user.email %>`

## 感想
- 11章と内容的にはほぼ同じだったが、その分説明が少なくて少し混乱した
- herokuでの動作は問題なかったが、ローカル動作時にパスワード再設定用リンクを開こうとすると画面に`このサイトは安全に接続できませんlocalhostから無効な応答が送信されました。`と表示され、ログに以下が吐かれてしまった

```
2020-03-18 02:53:45 +0900: HTTP parse error, malformed request (): #<Puma::HttpParserError: Invalid HTTP format, parsing fails.>
```
- 原因はメールリンクがhttpsになっているためで、httpでリンクを開くと画面が正常に表示された
    - localhostにhttpsで繋ぐ場合は少し追加の設定が必要　[参考記事](https://bokunonikki.net/post/2019/0422_rails_http_paese_error_malformed_request/)
順列と組み合わせ

# 順列（permutation）
$n$個の異なるものから、異なる$r$個をとって１列に並べたものを **順列** と呼び

```math
\begin{align}
{}_n \mathrm{ P }_r & = n(n-1)(n-2)\cdots(n-r+1) \\\\[1pt]

& = \frac{n(n-1)(n-2)\cdots (n-r+1)(n-r)(n-r-1)\cdots2 \cdot 1}{(n-r)(n-r-1)\cdots2 \cdot 1} \\\\[1pt]

& = \frac{n!}{(n-r)!}
\end{align}
```

で表す
$n$ 個の中から繰り返し同じものを取ってくる事を許す順列を特に **重複順列** と呼び
$n$ 個の中から $r$ 回繰り同じものを取ってくる場合は

$$ 重複順列 = n^r $$

## 円順列
順送りすれば同じ表現になる並び方を同じと考えた場合の順列
例えば、a,b,c,d の４文字の並び方は $_４P_4=4!$ 通りあるが、

$a→b→c→d$
$b→c→d→a$
$c→d→a→b$　
$d→a→b→c$　

の４種類を同じとみなした場合、

$$ \frac{4!}{4} = 3! \ 通り$$ 

となる。
$n$個の異なるものから、異なる$r$個をとった円順列は 
$$ \frac{_nP_r}{r} $$
 
通り であり、$r=n$ の場合は
　
$$ \large{ \frac{_nP_n}{n} = (n-1)!} $$ 


# 組み合わせ（combination）
$n$個の異なるものから、異なる$r$個をとって来た場合、その順番を考慮しない（$r!$ 個）パターン数を組み合わせと呼び

```math
\begin{align}
{}_n \mathrm{ C }_r & = \frac{_nP_r}{r!} \\\\[1pt]

& = \frac{n(n-1)(n-2)\cdots (n-r+1)(n-r)(n-r-1)\cdots2 \cdot 1}{r! \ (n-r)(n-r-1)\cdots2 \cdot 1} \\\\[1pt]

& = \frac{n!}{r! \ (n-r)!}
\end{align}
```
と表現する

# 例題
## 例１
男性６人、女性４人の中から、男性を３名、女性を２名選ぶ場合、選び方は何通りあるか？

### 解
|性別|選び方の数|
|---|---|
|男性|$_6C_3$|
|女性|$_4C_2$|

なので

```math
\begin{align}
{}_6\mathrm{ C }_3 \times {}_4\mathrm{ C }_2 = \frac{6 \cdot 5 \cdot 4}{3 \cdot2 \cdot 1} \times \frac{4 \cdot 3}{ 2 \cdot 1} = 5 \cdot 4 \times 2 \cdot 3 = 120
\end{align}
```

## 例２
１２人を次のように分ける場合、何通りあるか

１）４人ずつ$A,B,C$の３組に分ける
２）４人ずつ３組に分ける

### 解
１）
A組の４名を選ぶ方法は

```math
\begin{align}
{}_{12}\mathrm{ C }_4
\end{align}
```
B組の４名を選ぶ方法は、A組以外の８名の中から選ぶので

```math
\begin{align}
{}_{8}\mathrm{ C }_4
\end{align}
```

C組には残りの４名が自動的に決まるので１通り
よって

```math
\begin{align}
{}_{12}\mathrm{ C }_4 \times {}_{8}\mathrm{ C }_4 \times {}_{4}\mathrm{ C }_4 = \frac{12 \cdot 11 \cdot 10 \cdot 9 }{4 \cdot 3 \cdot 2 \cdot 1} \times \frac{8 \cdot 7 \cdot 6 \cdot 5 }{4 \cdot 3 \cdot 2 \cdot 1} = 34650
\end{align}
```

２）A,B,C のグループ名を考慮しない事と同じなので

$$ \frac{34650}{3!} = 5775$$


## 例３
６文字の $a,a,a,b,b,c$ を１列に並べる方法は何通りか？

### 解
まず、$a$ を配置するパターン数を決める。
６つの場所から３つの場所を選ぶ組み合わせと同じなので $ _6C_3$

同様に、残りの３つの場所に $b$ を配置するパターンは $ _3C_2 $

```math
\begin{align}
{}_{6}\mathrm{ C }_3 \times {}_{3}\mathrm{ C }_2 \times {}_{1}\mathrm{ C }_1 & = \frac{6!}{3! \ (6-3)!} \times \frac{3!}{2! \ (2-1)!} \\\\[1pt]
& = \frac{6!}{3! \ 3!} \times \frac{3!}{2! \ 1!} \\\\[1pt]
& = \frac{6!}{3! \ 2! \ 1!} = 60
\end{align}
```

一般に $n$ 個のものの中に $p$ 個の同じもの、$q$ 個の同じもの、・・・$r$ 個の同じものがある場合（$ n = p + q + ・・・+ r $）それらを１列に並べる総数は

$$\frac{n!}{p! \ q! \cdots r!} （n = p + q + ・・・+ r ）$$
タスク管理ツールについて検討


## 要件

* キーボードショートカットでタスク操作
* エクスポート、インポートでの一括書き換え
* カンバン
* ガントチャート
* UIが優しくてプログラマブルじゃなくても使える
* 環境依存や特別なボトルネックがない
* Chromeで動いて欲しい
* できれば2,3ユーザーだが、最低限であれば1ユーザー

## 検討

### Trello

* キーボードショートカットが有能
* これまで使ってきた
* 調べてみたが、今ひとつなのは、セキュリティ（外部サービス依存部分）がいまいち安心感がない
* アドオン周りのデータのエクスポートなど長期的に不安
* 一括での編集やAPIなどやれることは多様だが、複雑に使うには煩雑になりそう

### Asana

* リスト形式では使えるが、カンバンではキーボードショートカットが貧弱
* 一人で使うのができなくて、価格の見積もりがわかりにくい

### Taskworld

* カンバン、ガントチャートも使えそう
* 見た目綺麗、お試しで使える範囲も試しやすい
* テザリング中にガントチャートいじったらフリーズしてブラウザのタブが固まった
* ショートカットは少しだけあるけど全然足りない

### Microsoft Planner

* Microsoftが怖い、office365に登録すれば使えそう
* プラン的に個人では高め、年間契約だと安いが迷いどころ
* カンバンで管理できそう
* エクスポート・インポート、キーボードショートカットなどは、ドキュメントみるかぎりは使えそう
* ガントチャートはproject professional（別売）の機能だった
* ショートカットもchrome on macだと正常に機能しないみたい

### jooto

* キーボードショートカットがない

### Wrike

* カンバンとガントチャートなどの使い勝手を試すのにハードルが高い
* 2ユーザー以上で使うのにはコストが若干高いかもなあ

### Jira

* ベータ的な方でつくるとカンバンのキーボードショートカットが聞かなかった
* クラシックだとガントチャートが使えなさそう

### trello + bigpicture

* 料金体系が理解できなかったのでパス
* だいぶ多機能な印象

### Jira + bigpicture

* Jiraと合わせて使うのありなのかも

### trello + elegantt

* エクスポート
* csv出力はなさそうだが、カレンダーファイルは出せる
* 有料にするならExcelファイルやiCalなどが吐き出せる
* Chrome拡張のみ
* カンバンと同時にガントチャート表示とか表示面でよい感じ
* 月契約なら$5で済ませられる
* 多分、インポートはできない

### trello + planyway

* Chrome拡張とかカンバンと同時にガントチャート表示とか表示面で多機能
* タスクの関連付けができなさそう
* $4の一人用のProプランが良さげ
* csv出力はなさそうだが、カレンダーファイルは出せる
* カスタムフィールドとしてtrelloカード側でデータを制御可能

### trello + teamgantt

* Chrome拡張だけでなく、コンパネがある、カンバンと一緒には見れない
* 見た目がシンプルで使いやすい印象
* helpを深掘りしないと分かりにくいがカレンダー同期などもある
* csv出力が可能（インポートはできない）
* 1プロジェクト以上だと有料、年契約なら$7くらいなのでちょうどいい価格、月額だと$10近い
* タスクの関連付けができる
* 多分、インポートができる（新規プロジェクト扱い）
* 一括編集ができるのは利点と思ったが、新規プロジェクトにしてからtrelloを紐付け直しても思うようには同期できなかった
* カスタムフィールドとしてtrelloカード側でデータを制御可能

### trello + placker

* インポート＆エクスポートが便利かもしれない
* trelloへの双方向の同期もわりといい
* 知見がないとすぐにはうまく使えなさそう
* 有料にはなるが、求めるもの次第では安い気がしてきた
* カードの一括編集は試してみてうまく差分更新できた、素晴らしい

### 他

* Wrike
* Backlog
* Azure Boards
* plus trello

### 現状のまとめ

* 各サービスを無料の範囲で比較するのが面倒、可能なら検証のためだけにアカウントすら作りたくない
* 1ユーザーでMicrosoft Plannerかな、不足だった
* インポートで一括編集できればteamganttもありか
* インポートで一括編集できるplackerも魅力的（最有力）

### 参考

ガントチャートの依存関係機能を無料で使えるアプリ - Double Dot Design
https://scrapbox.io/doubledotdesign/%E3%82%AC%E3%83%B3%E3%83%88%E3%83%81%E3%83%A3%E3%83%BC%E3%83%88%E3%81%AE%E4%BE%9D%E5%AD%98%E9%96%A2%E4%BF%82%E6%A9%9F%E8%83%BD%E3%82%92%E7%84%A1%E6%96%99%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B%E3%82%A2%E3%83%97%E3%83%AA

Pricing | SoftwarePlant
https://softwareplant.com/pricing/

BigGantt - Gantt Chart for Jiraの日本語表示について - RS アトラシアン製品 ユーザーコミュニティ
https://www.ricksoft.jp/qa/questions/47088000/biggantt---gantt-chart-for-jira%E3%81%AE%E6%97%A5%E6%9C%AC%E8%AA%9E%E8%A1%A8%E7%A4%BA%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

Import a Project via CSV
https://support.teamgantt.com/article/20-importing-a-csv/

Trello使ってみた - Qiita
https://qiita.com/umeyee/items/7d09b011ee611cbecce3

How to export your data to Excel | Placker.com Help Center
https://help.placker.com/en/articles/1855051-how-to-export-your-data-to-excel
カレントディレクトリ以下の複数ディレクトリ内ファイルを探索しgzip化（Windows）

自分用メモ

コマンドプロンプトでカレントディレクトリ内の複数ディレクトリをいちいち開いてdatファイルを検索してからgzip化するのが面倒だったので。


```
forfiles /s /m *.dat /c "cmd /c gzip -v @file"
```

初期のままだとgzip化出来ないので[Windowsでgzipが使いたい・・・](http://puyo-twitter.blogspot.com/2012/01/windowsgzip.html)


```
forfiles /s /m *.dat /c "cmd /c if not @file=="*abc.dat" gzip -v @file"
```
が出来るか検証
Elasticsearchで検索が可能になるまでに行われていること

# 3行にまとめると...

- リクエストされたドキュメントをメモリに蓄積して
- 一定量溜まったらセグメントと呼ばれる単位にまとめたあとに
- 検索用オブジェクトに反映される。

# インデックス可能になるまでに行われていること
### 1. メモリバッファにドキュメントを蓄積
インデックスリクエストを受けたあと、すぐに格納されるわけではない。
メモリバッファに蓄積され、一定のドキュメント数が蓄積するかメモリバッファがいっぱいになると後述の格納処理が行われる。

### 2. セグメントへの格納 & マージ
Elasticsearch内部では全文検索ソフトウェアの[Lucene](https://lucene.apache.org/)が使用されており、
ドキュメント情報はLucene内部で **セグメント** と呼ばれる領域に分割して格納される。
ただし、この時点ではまだドキュメントを検索することはできない、

セグメントはサイズが一定を超えると複数のセグメントとマージされ、さらに大きいセグメントとなる。
このマージが繰り返されセグメントのサイズが大きくなっていく。
その様子をビジュアライズしたのが以下の動画。
http://blog.mikemccandless.com/2011/02/visualizing-lucenes-segment-merges.html

### 3. Elasticsearchのrefreshを行い、検索用オブジェクトに反映
Luceneでドキュメントを検索可能な状態にするためには、 **reopen** という操作を行い検索用オブジェクトに反映する必要がある。
Elasticsearchのrefresh操作を行うと内部的にreopen操作が行われ、ドキュメントが検索可能な状態となる。

#### refresh間隔の設定
refresh間隔はデフォルトで `1秒` で行われる。
要件次第ではこの1秒が適切でないことがあり、 [index.refresh_interval](https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules.html#index-refresh-interval-setting
) というプロパティを用いて任意の値に設定を行うこともできる。

要件ごとの設定については以下の記事が参考になる。
https://www.elastic.co/guide/en/elasticsearch/reference/7.0/tune-for-indexing-speed.html#_unset_or_increase_the_refresh_interval

# 参考資料
#### Elasticsearch実践ガイド (impress top gear)
Elasticsearchの内部的な仕組み、運用方法など、非常にわかりやすい書籍。
本記事で説明した内容についてももっと詳しく記載されている。
Elasticsearchを実践導入するのであれば一度は読んでおきたい。
https://www.amazon.co.jp/dp/4295003913/
railsのサーバーの強制終了

#railsのサーバーの強制終了について

railsを使って自宅で開発しているときに、

```
$ bin/rails s
```

を使ってローカルホストのサーバを立てる。

そのとき、間違って
サーバーを起動した状態のターミナルのタブを消してしまって、ctrl + c
での終了ができなくなってしまい、困ったという経験がある。

その時の対処法、すなわち強制終了の方法をメモしておく。

##　kill コマンドを使って強制終了

実際に実験してみると、
まず、

```
$ bin/rails s
```

を打ってローカルのサーバを立ち上げる。

その後確認してほしいのは

`プロジェクト名/tmp/pids/server.pid`

のファイル。

実際に見てみると、

```project/tmp/pids/server.pid
1    1159  　　#ここに何らかの数字が入っているはず
2
```

これはサーバーを立ち上げたときに生成される数字で、サーバーを終了させたときに自動で消去される。

この数字を使って、

```
$ kill 1159
```
とコマンドに打ち込めばサーバーは強制終了される。
PythonモジュールをLambda Layerにアップロードする時のフォルダ構成について

## はじめに
Lambda Layerを使おうとした際にPythonモジュールのフォルダ構成でハマったので、備忘として記事にします。Lambda Layerについては[AWSの公式ドキュメント](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-layers.html)をご確認ください。

## フォルダ構成
プログラミング言語ごとのフォルダ構成については[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-layers.html#configuration-layers-path)でも言及されています。
Pythonの場合、```python/```配下にLambda Layerで使用するモジュールを配置する必要があります。
例えば以下のようなイメージです。

```
python
　├─test1.py
　└─common
　　　└─test2.py
　
```

Layerにアップロードするには、上記```python```フォルダをzipファイルにした上でアップロードします。
上記構成を無視してzipファイルを作成してアップロードした場合、当然ですが、Lambdaで使用する際にエラーになります。
最初はなぜエラーになっているかもわからずハマってました。。。ちゃんとドキュメントは確認しないといけないなと反省しました。
(引用)Datadog からデータ出力を試してみる

素晴らしいエントリ
[Datadog からデータ出力を試してみる](https://htnosm.hatenablog.com/entry/2015/09/24/090000)
の方法でデータ出力可能。

とはいうものの、Datadog側の仕様が変わっているので、
api_keyとapp_keyはheaderで送ってあげないとだめになってる

```
api_key=取得したAPIキー
app_key=取得したアプリケーションキー
to_time=$(date +%s) # UNIXTIME指定
from_time=$(date -v -20M +%s) # UNIXTIME指定

curl -G \
    -H "DD-API-KEY: ${api_key}" \
    -H "DD-APPLICATION-KEY: ${app_key}" \
    "https://app.datadoghq.com/api/v1/query" \
    -d "from=${from_time}" \
    -d "to=${to_time}" \
    -d "query=max:nginx.net.request_per_s{example}by{name}"
```
cf. [Datadog APIリファレンス#時系列ポイントのクエリ](https://docs.datadoghq.com/ja/api/?lang=bash#%E6%99%82%E7%B3%BB%E5%88%97%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88%E3%81%AE%E3%82%AF%E3%82%A8%E3%83%AA)

あと、Datadogからのデータ抽出は、1回のクエリで最高350個にまとめられる。
なので、to_timeとfrom_timeを長くすると、予想外のデータが帰ってくるので注意。
[.rollup()](https://docs.datadoghq.com/ja/dashboards/functions/rollup/) を使って調整するのがGood！
Vue-Cli UI上でビルドするとError：CssDependencyが出る

# はじめに

最近、フロントエンドのお勉強を始めました。
Vue？なにそれ？から二日目です。

Qiitaの投稿もmarkdown記法も初めてなので簡潔に。


ネットで拾ったチュートリアルを終えて、 build してみるかってとこで表題のエラー。


# 環境

vue-cli　4.2.3

# エラー内容

Vue UI上でbuild実行時の出力

>$ vue-cli-service build --mode production --dest dist --target app --dashboard


>\-  Building for production...

> ERROR  Error: No module factory available for dependency type: CssDependency
Error: No module factory available for dependency type: CssDependency
...
...


コンソール上での`npm run build`は正常終了するのに、UI上でビルドするとエラーになる。何故だ。

#原因
実際のパスとVue UIが認識しているパスが異なってるのが原因っぽい。
参考：[Error: No module factory available for dependency type: CssDependency #5154](https://github.com/vuejs/vue-cli/issues/5154)

問題があったのは下プロジェクト。
`C:\Users\...\Vue_CrashCourse\vue_realtime_chat`が正しいパス。
Vue UI上でプロジェクト作成したあと、直接フォルダ名を変えたのが悪かった。

![コメント 2020-03-20 160113.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605939/507c1619-aef5-1b18-de03-0d7d82d917b2.png)


#解決法
インポートし直す。

serveは動くから「なんでなんで」だったけど、シンプルなミスでした。
ネット情報だとwebpackだったり、vueRouterのmodeが原因になりえるみたい。


以上。
Vueおもしろいっすね。
aspidaの隠し機能まとめ

まだまだマイナーなライブラリでして、ソースを漁って見つけたREADMEに載ってないような隠し機能がいくつかあるので、まとめておこうと思います。参考になれば幸いです。(今後も見つければ追記するつもりです。)

### aspidaとは?
[GitHubのrepo](https://github.com/aspidajs/aspida)

TypeScriptと親和性の高いHTTPクライアントのライブラリ。
パスを文字列として持つのではなくメソッドをそれを経由するので、何が嬉しいかというと

- パスに補完が効く(うれしい!)
- 返り値の型を間違えない(うれしい!)

このメソッドを型定義ファイル郡から生成してくれるツールがaspidaです。

## api定義ファイルを作る
### 定義ファイルの書式
- Methods
    - メソッド(`get`,`post`,`patch`,etc)
        - `query`
        - `reqHeaders`
        - `reqBody`
        - `reqFormat` (reqBodyの型)
        - `resBody`

#### reqBody
interfaceとして渡すことができるほか、次の型を指定することができます:

- `ArrayBuffer`
- `Blob`
- `string`

このどれか指定するとこの型のデータをそのまま送ることができます。

#### reqFormat
次の型を指定することができます:

- `ArrayBuffer`
- `Blob`
- `string`
- `FormData`

指定があるとjsonのかわりにこの形式でエンコードしてくれます。

#### よく使うinterfaceを別ファイルに置いておきたい
```ts:src/createTemplateValues.ts
if (file.startsWith('$') || file.startsWith('@')) return
```
とあるように、`$`か`@`で始まるファイルは無視されるため、`@types.ts`とかを作るといいです。
生成されたファイルではimportしているだけなので問題なく利用できます。

#### ファイルをpostしたい
aspidaは奥のXHRのライブラリにデータを受け流すだけなので、`File`型を利用すればよいです。

### パスパラメータの型を指定
`_id@number.ts`といったファイル名にすることで型をnumberに制限できることはreadmeに書かれていますが、この他に自作型を使用することもできます。
大文字始まりの型(非プリミティブ型?)を指定することで、その型を使用できます。
この場合、定義は`apis/`(`$api.ts`と同ディレクトリ)に`@types.ts`を作成しexportする必要があります。
また、型チェックが行われていませんが、文字列の形にすることができる必要があるようです。

## ビルドする
### コマンドライン引数
aspidaコマンドでは`--build`のほか`--version`と`--watch`が引数として有効です。
watchではファイル群を監視して更新があるたび自動でビルドを行ってくれます。
OpenCVを使ったブロブ検知の実行例

# はじめに
　ブロブ（塊）とは、似た特徴を持った画像内の領域を意味します。例えば、下の様な画像では、丸などの図形がブロブだと言えます。

![shapes.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/a93e6794-c68e-b852-480a-2d92a23a149c.jpeg)

　OpenCVには、ブロブを自動的に検知できる関数が組み込まれており、簡単に見つけることができます。

# やりたいこと
　丸形を見つけてカウントしたい。

#　コード

```ruby:blob.py
import cv2 
import numpy as np 
  
# 画像の読み込み
image = cv2.imread('shapes.jpg', 0)

# パラメータの初期化
params = cv2.SimpleBlobDetector_Params() 

# ブロブ領域（minArea <= blob < maxArea）
params.filterByArea = True
params.minArea = 100
  
# 真円度（ 4∗π∗Area / perimeter∗perimeter によって定義される）
#（minCircularity <= blob < maxCircularity）
params.filterByCircularity = True 
params.minCircularity = 0.85
  
# 凸面の情報（minConvexity <= blob < maxConvexity）
params.filterByConvexity = True
params.minConvexity = 0.1
      
# 楕円形を表す（minInertiaRatio <= blob < maxInertiaRatio）
params.filterByInertia = True
params.minInertiaRatio = 0.1

# 検知器作成
detector = cv2.SimpleBlobDetector_create(params) 

# ブロブ検知 
keypoints = detector.detect(image) 

# ブロブを赤丸で囲む
blank = np.zeros((1, 1))  
blobs = cv2.drawKeypoints(image, keypoints, blank, (0, 0, 255), 
                          cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) 

# ブロブの個数  
count = len(keypoints) 
print(f'丸の個数: {count}')
  
# 画像を表示
cv2.imshow("out.jpg", blobs) 
cv2.waitKey(0) 
cv2.destroyAllWindows() 
```

#結果

```
>python blob.py
丸の個数: 8
```

![out.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/1ec8c07e-b708-4281-a779-0852711b7d8d.jpeg)

　※枠が赤から黒に変化したのは、グレースケールで読み込んだためです。

#実行で失敗した話
　他のサイトで紹介されていたコードを試したら、Pythonがクラッシュしました。

![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/57624bfb-9254-2610-fe6f-6ff0a288c5ca.jpeg)

　調べてみるとOpenCVのバージョンが影響してたようです。以前のバージョンのOpenCVでは、SimpleBlobDetector_create()の代わりに、SimpleBlobDetector()という関数が使われており、コピペでコード実行 → 現在は使われていない関数を参照 → クラッシュという流れが発生したのだと思います。
　対策としては、SimpleBlobDetector_create()を使うか、下のコードに書き換えるとエラーを回避できます。

```python
ver = (cv2.__version__).split('.')
if int(ver[0]) < 3:
    detector = cv2.SimpleBlobDetector(params)
else:
    detector = cv2.SimpleBlobDetector_create(params)  
```

# おわりに
　ブロブ検知の応用例としては、個数のカウントや位置検知があります。OpenCVによって簡単に使えるので、この例以外でも試して行きたいと思います。

　最後までご覧いただきありがとうございました。コメント・ご指摘等ありましたらよろしくお願いします。


#　参考URL
https://www.programcreek.com/python/example/89350/cv2.SimpleBlobDetector
https://www.visco-tech.com/technical/direction-presence/blob/
Minecraft Skript 応用編 Part.6 GUIメニュー

# GUIメニューとは
ここでいうGUIメニューというのはインベントリに並んだアイテムをクリックすることで何かを実行するものです。
わたしが運営する[MonsterLifeServer](http://mlserver.php.xdomain.jp/)にもわたくしの作ったプラグインで実装されたGUIメニューはあり、添付画像のような見た目をしています。
![331bdb2d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404179/159dbba2-df34-e0e3-62ca-d50da23c9f64.png)

今回はこれをSkriptで実装するやり方を説明していきます。

# さっそく書いてみよう
説明はあとです！！

```vb:完成コード
command /gui:
    trigger:
        open chest inventory with 6 row named "&a&lGUIMENU" to player
        set {_i} to 0
        set {_glass} to white glass pane named "&c&lクリック不可"
        loop 54 times:
            set slot {_i} of player's current inventory to {_glass}
            add 1 to {_i}
        set slot 13 of player's current inventory to stone named "Yeah"
        set slot 53 of player's current inventory to barrier named "閉じる"

on inventory click:
    name of clicked inventory is "&a&lGUIMENU"
    cancel event
    if event-item is stone named "Yeah":
        send "Yeah" to player
    if event-item is barrier named "閉じる":
        close player's inventory
```

# 説明
`commnad /gui:`・`trigger:`の部分は説明しませんからね？
知りたい人は**[Minecraft Skript 入門編 Part.3 - カスタムコマンドについて・・・](https://qiita.com/meoto2408/items/dc9574d0f9653b261bf7#%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)**をご覧ください。

```vb:3行目
open chest inventory with 6 row named "&a&lGUIMENU" to player
```
これだけで`&a&lGUIMENU`という名前のインベントリを開くことができます。
`6 rows`の`6`部分を変更することでインベントリの大きさを変更可能です。

しかし、1~6の数字以外は指定できないのでお気を付けください。

```vb:4~8行目
set {_i} to 0
set {_glass} to white glass pane named "&c&lクリック不可"
loop 54 times:
    set slot {_i} of player's current inventory to {_glass}
    add 1 to {_i}
```
これで開いたインベントリすべてを白色のガラスで埋めます。

```vb:9,10行目
set slot 13 of player's current inventory to stone named "Yeah"
set slot 53 of player's current inventory to barrier named "閉じる"
```
これで13番と53番のスロットに`Yeah`という名前の焼き石と`閉じる`という名前のバリアブロックが設置されます。

スロット番号は左上から右向きに0,1,2...となっていき、9番は2列目の一番左のスロットになり同じように9,10,11...となります。

よってスロット13は二列目のど真ん中、53は最後の列の一番右となります。

```vb:12~14行目
on inventory click:
    name of clicked inventory is "&a&lGUIMENU"
    cancel event
```
これで`&a&lGUIMENU`という名前のインベントリをクリックした場合キャンセルする仕組みになっています。

```vb:15~18行目
if event-item is stone named "Yeah":
    send "Yeah" to player
if event-item is barrier named "閉じる":
    close player's inventory
```
そしてもし`Yeah`という名前の焼き石をクリックした場合はチャットに`Yeah`と表示し、`閉じる`という名前のバリアブロックをクリックするとインベントリを閉じるというシステムになっています。

クリックと同時にMinecraftのメニュー画面をクリックしたときになる音を鳴らしてあげることでよりいっそうGUI感を出せます。

# 追加1
アイテムが取れてしまうという報告を受けていますので追加させていただきます。

アイテムが取れる場合は`clicked inventory `を`event-inventory`にするだけで治るかもしれません

# 最後に
今では多くのサーバーがGUIシステムを採用しているように思われます。

コマンドよりも便利という点では採用されるのは当たり前なのでしょうね。


~~この記事が役に立ったら金を出せ。~~
この記事が役に立ったらとてもうれしいです。

え？お金がどうしたって？なんのことですか？


それでは次回もよろしくお願いします。

次は[コチラ](https://qiita.com/meoto2408/items/5b96e179b6e6d214f08f)

前は[コチラ](https://qiita.com/meoto2408/items/ba5ff3aa2bdb1127f37c)
【2020年3月時点の補足】Office 365 予定表を Power Automate（旧Flow）でGoogleカレンダーへ同期する

[Office 365 予定表を MS Flow でGoogleカレンダーへ同期する（追加・編集・削除 全対応）](https://qiita.com/yamad365/items/830b64954dcdfcb91fe2)について、トリガー等がVerUpして変更点が発生しているようなので、本日2020年3月20日(金・祝)時点で確認されているポイントをまとめます。

# トリガーがV2になっている
Office 365 Outlook トリガーが更新されて、V2になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/cce0109f-f3db-7f3b-8b57-2f7217d22393.png)

この影響であろう問題が次の項目です。なお、前回までのV1については”無印”という呼称で続けます。（※無印、は当方が勝手に名付けただけです。公式な呼称ではありません）

無印のトリガーで作成した過去のAutomate（旧Flow）は現在も正常に動作しています。Flow時代に作成した方、慌ててVerUp対応をする必要はありませんのでご安心ください。

# 「繰り返しの予定」を回避（全体②の箇所）変更点
[昨年の記事](https://qiita.com/yamad365/items/830b64954dcdfcb91fe2) で、無印のトリガーだった際は「繰り返しの予定」パターンは数値で判定可能でした。
> "The recurrence pattern for the event (None - 0, Daily - 1, Weekly - 2, Monthly - 3, Yearly - 4)"です。つまり、ゼロ以外＝繰り返しではない

V2 では「繰り返しの予定」パターンは文字列での表現に変更されたようです。該当トリガーの説明には書いてないので、[Create event](https://qiita.com/yamad365/items/830b64954dcdfcb91fe2) の 『Recurrence』等を参照ください。
> The recurrence pattern for the event: none, daily, weekly, monthly or yearly

マジックナンバーよりも全然わかりやすいですね。

　none = 単体の予定（Single）
　daily ⁼ 日単位
　weekly ⁼ 週単位
　monthly ⁼ 月単位
　yearly ⁼ 年単位

無印の場合は数値で「0 と等しくない場合＝繰り返しの予定」と判断していました。
V2を利用する場合は「none と等しく無い場合＝繰り返しの予定」と判断するよう設定ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/3fb94489-295d-2991-546d-e2a88386c0fb.png)

# "Missing Time Zone definition" error」対策
Google カレンダーに登録、更新する際、開始・終了時刻の箇所で見出しのエラーが発生した場合の対策です。下記イメージのように、開始時刻と終了時刻の末尾に半角で”Z”を追記すればOKです。

＃ @tutumi-denken さんがコメントで教えてくれました！ありがとうございます！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/122f212e-bf4f-d52d-d1a8-4e12da34a9b8.png)

# タイムゾーン変換はすべき？？
ご利用のクラウド環境設定に依存するので一概に断言できないのですが・・・、タイムゾーンをUTC+0からわざわざ変更する必要は基本的にないハズです。

Office 365（Exchange Online）も、Googleカレンダーも、基本的には内部で保持している時刻はUTC+0で管理されています。それを表示するアプリ（Outlookや、Outlook on the Web）が各個人で指定したタイムゾーンに変換（例：日本だと＋9時間）してくれています。つまり、デフォルト設定のままで、内部的にはUTC+0だったらタイムゾーンは変更しなくて良い、ということです。
※難しくてよくわからない方は、実際に Automate をテスト実行して、予定の開始・終了時刻がズレないか？をチェックしてみてください。そして、ズレていたら環境設定でタイムゾーンが投入されているハズなので、適宜時差対応を実施ください。

# 最後に
本来であれば、現時点の最新化されたトリガーやアクションで説明を焼き直したかったのですが・・・。調べてみらたら、あんまり大幅な変更が見当たらなかったので補足記事にしました(;^ω^)
これで迷子になる方が減れば幸い。

それでは、皆さま。素晴らしい Power Platform Life を！
[Ubuntu 19.10] VirtualBox 6.1.4 (+Vagrant 2.2.6)の環境を作成する

#問題点
VirtualboxとVagrantにバージョンの相性の問題があります。
Virtualbox 5.2 + vagrant 2.2.6 なら動くのでそれで環境を作成したかったのですが、VirtualBox 5.2がUbuntu 19.10に対応していなかったので、VirtualBox6.1で作成しました。

#環境
```
ubuntu 19.10 //ホスト
Virtualbox 6.1.4r136177
Vagrant 2.2.6
```

#VirtualBoxのインストール

## 1.keyの登録
```
wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo apt-key add -
```
##2.レポジトリの追加
```
sudo add-apt-repository "deb [arch=amd64] https://download.virtualbox.org/virtualbox/debian eoan contrib"
```
##3.VirtualBoxのインストール
```
sudo apt install virtualbox-6.1
```

参考
[VirtualBox その100 - VirtualBox 6.1.0をインストールするには・Guest Additionsをインストールするには](https://kledgeb.blogspot.com/2019/12/virtualbox-100-virtualbox-610guest.html)
[VirtualBox Download VirtualBox for Linux Hosts](https://www.virtualbox.org/wiki/Linux_Downloads)

#Vagrantのインストール
適当なディレクトリで実行してください。

```
curl -O https://releases.hashicorp.com/vagrant/2.2.6/vagrant_2.2.6_x86_64.deb
sudo apt install ./vagrant_2.2.6_x86_64.deb
```
# VirtualBox とVagrantを対応させる
こちらのwebサイトを参考に設定します。
[Getting Vagrant 2.2.6 working with VirtualBox 6.1 GA](https://blogs.oracle.com/scoter/getting-vagrant-226-working-with-virtualbox-61-ga)

# Ubuntuをインストールする
適当なディレクトリで実行してください。

```
vagrant box add ubuntu/bionic64 --box-version 20181129.0.0
vagrant init ubuntu/bionic64
vagrant up
```
最終的に Machine booted and ready! という文字列が表示されていれば無事に起動できています。

#つまづきポイント
### 自分がつまずいたエラー
vagrant upの際に出力されたエラーです

```
 There was an error while executing `VBoxManage`, a CLI used by Vagrant
 for controlling VirtualBox. The command and stderr is shown below.
 
 Command: ["startvm", "728a7f9e-0589-4d56-a601-280e78c83841", "--type", "headless"]
 
 Stderr: VBoxManage: error: The virtual machine 'ubuntu64_18_default_1584679530897_81948' has terminated unexpectedly during startup with exit code 1 (0x1)
 VBoxManage: error: Details: code NS_ERROR_FAILURE (0x80004005), component MachineWrap, interface IMachine
```

別のバージョンのVirtualBoxが競合しているようでした。
/sbin/vboxconfigを実行しても直らなかったので、すべてアンインストールをしてから再インストールをしたらエラーが直りました。
Rails5 CSV import 一括ユーザー登録

#Rails5でCSV読み込んで一括ユーザー登録機能作成

CSVの読み込みでちょっとつまずいたのでメモ。
ほんとーに初歩的なミスでした。
基本的にコチラを参考にさせてもらいました。
https://qiita.com/seitarooodayo/items/c9d6955a12ca0b1fd1d4

さて出てきたエラーはコチラ
`ActiveRecord::RecordInvalid (Validation failed: Name can't be blank, Password can't be blank, Password can't be blank, Password is too short (minimum is 6 characters)):`

よくあるバリデーションに引っかかったやつですね。
blankってことはnilになっちゃってると言うことか。
と言うことはcsvファイルが読み込まれてないのか？

`Parameters: {"utf8"=>"✓", "authenticity_token"=>"lzZScpvbb+vbmrJaxYMW3SweQrA0ISM0ssFX9GKIIL1gU6EMWD3IutOb0x5QnaLQwVcW1hUnNMTnZSxTgsHAvw==", "file"=>#<ActionDispatch::Http::UploadedFile:0x00007fe4b41926e8 @tempfile=#<Tempfile:/tmp/RackMultipart20200320-11805-1j4vvvo.csv>, @original_filename="csvimporttest.csv", @content_type="text/csv", @headers="Content-Disposition: form-data; name=\"file\"; filename=\"csvimporttest.csv\"\r\nContent-Type: text/csv\r\n">, "commit"=>"ファイル読み込み登録"}
  User Load (0.2ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` IS NULL LIMIT 1`

パラメータとしては渡っている。。
しかし`SELECT  `users`.* FROM `users` WHERE `users`.`id` IS NULL`
なんでだ、、binding.pryしてみよう。

`11: def self.import(file)
    12:   CSV.foreach(file.path, headers: true) do |row|
    13:     # IDが見つかれば、レコードを呼び出し、見つかれなければ、新しく作成
    14:     user = find_by(id: row["id"]) || new
    15:     # CSVからデータを取得し、設定する
    16:     binding.pry
 => 17:     user.attributes = row.to_hash.slice(*updatable_attributes)
    18:     # 保存する
    19:     user.save!
    20:   end
    21: end`

`[1] pry(User)> puts user.attributes
{"id"=>nil, "name"=>nil, "firstchild"=>nil, "secondchild"=>nil, "thirdchild"=>nil, "password_digest"=>nil, "email"=>nil, "admin"=>false, "created_at"=>nil, "updated_at"=>nil}
=> nil
[2] pry(User)> puts user
=> nil
[3] pry(User)> puts row
Id
9
Name
シーエスブイ太郎１
Password
Csvtest1
password_confirmation
Csvtest1
`
あ、rowには値が入ってる。。
その先に値が渡ってない。
ん？IdとかNameとか大文字入ってるジャン。ひょっとして、、、あーやっぱり。
と言うことでMacbookのnumbersで作成したcsvファイルだったのですがデフォルトで入力値の頭文字が大文字になる仕様でした。。
気づかずそのまま使ってたのが原因でしたね。
初歩的な原因でしたけど、こう言う風に原因追求するのってプログラミングの面白さの一つですよね。
binding.pryはよく使うようにしてます。
ubuntu18.04 への apache2 新規設定時の手順

# 発行コマンド
環境を作成するたび調べることになるので自分用に

```
id taro
sudo usermod -aG www-data taro 
id taro 
mkdir ~taro/www-data
sudo chown -R taro.www-data ./www-data/
sudo chmod -R 2770 ./www-data/
sudo find ./www-data/ -type d -exec chmod 770 {} \;
sudo find ./www-data/ -type f -exec chmod 660 {} \;
sudo sed -i".org" -r "s/DocumentRoot.*$/DocumentRoot \/home\/taro\/www-data/" /etc/apache2/sites-enabled/000-default.conf 
sudo vim /etc/apache2/apache2.conf
```

# 何をしているか
```
# グループ事前確認
id taro
sudo usermod -aG www-data taro 
# 変更反映の確認
id taro 
mkdir ~taro/www-data
sudo chown -R taro.www-data ./www-data/
# SGIDを設定する(https://eng-entrance.com/linux-permission-sgid)
sudo chmod -R 2770 ./www-data/
# 既存のディレクトリ、ファイルのパーミッションを置き換える
sudo find ./www-data/ -type d -exec chmod 770 {} \;
sudo find ./www-data/ -type f -exec chmod 660 {} \;
# sedで書き換える（趣味）。バックアップも作成
sudo sed -i".org" -r "s/DocumentRoot.*$/DocumentRoot \/home\/taro\/www-data/" /etc/apache2/sites-enabled/000-default.conf
# directoryに許可設定を入れる(内容については後述)
sudo vim /etc/apache2/apache2.conf
```

`/etc/apache2/apache2.conf`については、以下の設定を追加しないといけなかった（詰まった）。

```
<Directory /home/taro/>
	Options Indexes FollowSymLinks
	AllowOverride None
	Require all granted
</Directory>
```

# 知見
`~taro/www-data/`という形式でディレクトリを指定すると403が出る。
(`apache2.conf`でも、`000-default.conf`でも)

\<Directory\> 〜 \</Directory\>で使えるpathは、full pathか正規表現だけみたいですね。
> Directory-path is either the full path to a directory, or a wild-card string using Unix shell-style matching. In a wild-card string, ? matches any single character, and * matches any sequences of characters. 

> Regular expressions can also be used, with the addition of the ~ character. For example:

ref: https://httpd.apache.org/docs/2.4/en/mod/core.html#directory

# 補足
phpを使うときは

```
$ sudo apt install libapache2-mod-php7.2
```

# 環境

最近使っているノートPCにインストールしたUbuntu18.04

```
$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="18.04.4 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.4 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
```
- apache2

```
$ sudo apache2 -V
Server version: Apache/2.4.29 (Ubuntu)
Server built:   2020-03-13T12:26:16
Server's Module Magic Number: 20120211:68
Server loaded:  APR 1.6.3, APR-UTIL 1.6.1
Compiled using: APR 1.6.3, APR-UTIL 1.6.1
Architecture:   64-bit
```

# 参考
https://freelance.techcareer.jp/features/16
https://askubuntu.com/questions/325498/apache-cant-access-folders-in-my-home-directory
https://open-groove.net/linux-command/sed-edit-files/
【UE4】ゲームを作る際に便利だったブループリントのノード集(初心者向け) 【UnrealEngine】


今回はUE4で簡単なゲームを作る際に使用頻度の高かったノードを紹介します。

ノード一覧
-------
![BP_1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497331/aa3b5906-d232-84f9-1dad-e304ca5f1d28.png)
![BP_2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497331/313d5bc5-884b-9c3b-7642-c4a79e797f0f.png)

シンプルなゲームであればここに貼られたノード作れたりするかもしれませんね。

注意点
-------
もし目当てのブループリントがなかった場合は一度状況に合わせた表示を切ってみましょう

![全ノードから.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497331/7c061298-ee5d-3d84-0c77-75ba4e94150d.gif)


####あと同じ名前で性能が別のノードもあるのでしっかり内容を確認すべし



他にも使いがっての良いノードがあれば随時追加していきます。
[HowTo/動画解説]Github/プルリクエスト時のテンプレートを作成して効率的にチーム開発する！

Githubでプルリクエストをするときにテンプレートを読み込むように設定しておくことが可能であることがわかりましたので、以下に纏めておきます！

複数人でのチーム開発を行う際に、共通するテンプレートを作成しておくことで、抜け漏れ防止・効率的なプルリクエストのレビューをすることが可能になると思います！
この機能を活用して、効率的に作業をしていきましょう！


#ポイント
今回の実装に関するポイントを纏めます。
1. ".github"フォルダにファイルを作成
2. ファイル名は"PULL_REQUEST_TEMPLATE.md"
以上です。簡単に実装できます。

#作業手順
それでは、作業手順を纏めていきます。
1. Githubの該当リポジトリ上、"create new file"を押す。
2. ファイル名に".github/"と入力
3. さらに"PULL_REQUEST_TEMPLATE.md"と入力
4. テンプレートを空白のテキストエリアに入力
5. タイトルを入力したら、"commit new file"を押す

今回、プルリクエストのテンプレートは以下のようにしました。
＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
What
- Gem変更:
- DB変更：
- 機能変更：
- スクショ：
- その他：

Why
- 問題：
- 原因：
- 解決方法：
＊問題なく、単純に機能追加などの場合は追加した理由を記載

＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝

#作業手順（イメージ）
実際にやってみます。
手順1~3
![demo](https://gyazo.com/374dfe6d2d187be4d94e512799364add/raw)

手順4~5
![demo](https://gyazo.com/6dd1cba3b17b176e851c1cde7c5e14b7/raw)

以上でファイルが作成完了しております。

#実際にプルリクエストをしてみる。
上記にてプルリクエストのテンプレートが準備できましたので、実際にプルリクエストしてみましょう。
![demo](https://gyazo.com/fed88b552d5f05aea14f2288bd0d7207/raw)

しっかりとテンプレートが挿入されてますね。
これで、複数人で一つのアプリを作成するときに、抜け漏れなくプルリクエストができるようになります。

#ちなみに
今回のテンプレートは、contributingとissueにも対応しております。
その場合は".github"直下に以下のファイル名で作成しましょう。
contributing: CONTRIBUTING.md
issue : ISSUE_TEMPLATE.md

#参照
Issue and Pull Request templates
https://github.blog/2016-02-17-issue-and-pull-request-templates/

GitHubのIssue・Pull Requestのテンプレート機能を使おう
https://qiita.com/nyamogera/items/3fe6985b45fbd5377184

GitHubでディレクトリ作成
http://maeokaka.hatenablog.jp/entry/2016/07/07/001441

以上となります。最後までご覧いただき、ありがとうございました！
今後も学習した事項に関してQiitaに投稿していきますので、よろしくお願いします！
記述に何か誤りなどございましたら、お手数ですが、ご連絡いただけますと幸いです。
Linuxのパーティションをいろいろいじってみる〜続き〜

[前回](https://qiita.com/r_saiki/items/3d35d6ccd26ee090174a)は失敗したので、以下の順番でやっていく。

**作業目標**
①パーティション分割→失敗
~~②マウント~~
~~③ユーザーごとの容量の制限~~
~~④権限設定~~
~~⑤マウントポイントにシンボリックリンク設定~~

#①パーティション分割
今回は基本プラン3つ + 論理パーティション2つで分ける。
[前々回](https://qiita.com/r_saiki/items/894de9660607af22ab2e)と同じようにfdiskコマンドでパーティション分割を以下の状態になるまで行う。

~~~
Command (m for help): p

Disk /dev/sda: 42.9 GB, 42949672960 bytes, 83886080 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x0009ef88

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1            2048    10487807     5242880   83  Linux
/dev/sda2        10487808    20973567     5242880   83  Linux
/dev/sda3        20973568    31459327     5242880   83  Linux
/dev/sda4        31459328    83886079    26213376    5  Extended
/dev/sda5        31461376    41947135     5242880   83  Linux
/dev/sda6        41949184    52434943     5242880   83  Linux
~~~

パーティション作成＆保存後に以下のエラーメッセージが出るので調べた。
→再起動で反映するとの情報が多く得られた。

~~~
WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
Syncing disks.
~~~

一度シャットダウンして、再度vagrant upしたら、やっぱり壊れた^^;
原因がわからないため保留とする！
Eigen 動的 Matrix 型に std::vector などから値をセットする

## 背景

std::vector やポインタから `Eigen::MatrixXd` などの動的サイズの Matrix に変換したい. 

## 方法

Eigen::Map を使う.

https://stackoverflow.com/questions/17036818/initialise-eigenvector-with-stdvector

https://epcced.github.io/2019-04-16-ModernCpp/lectures/eigen/using-eigen.pdf

https://stackoverflow.com/questions/26094379/typecasting-eigenvectorxd-to-stdvector

引数のサイズは, MatrixXd で個数なので, out-of-bounds アクセスにならないように気を付ける.
(map に指定できるのは入力側ではポインタのアドレスだけっぽい)

```
std::vector<double> pts(3 * 100);

Eigen::Map<Eigen::MatrixXd> p(pts.data(), 3, 100);

```

## Row major or column major?

メモリの格納レイアウト.

https://eigen.tuxfamily.org/dox/group__TopicStorageOrders.html

Eigen では default は column-major である(OpenGL と同じ).
三次元座標データだと, std::vector では XYZXYZXYZ... と格納されているのを想定していると解釈されるとの理解でよいかと思います.


## TODO

* [ ] Stride や alignment を考慮した指定方法を確認する.
* [ ] row major, column major 切り替えの方法を探す. 
* [ ] memcpy 的な方法を探す(デフォルトのコンストラクタが memcpy 的かな?)
【Ruby on Rails】kaminariとbootstrap4で日本語に対応したページネーションを実装する。

#はじめに
kaminariとbootstrap4でお洒落なページネーションを簡単に実装する方法をまとめました。
###[前提]
bootstrap4がインストールされている
#使い方
##準備（インストール）
```ruby
#Gemfile
gem 'kaminari'
gem 'bootstrap4-kaminari-views'
```

```ruby
bundle install
#「bundle」だけでもOK
```
##設定
###日本語の設定（任意）
kaminariの日本語設定用ファイルを作成

```ruby:config/locales/kaminari_ja.yml
ja:
  views:
    pagination:
      first: "&laquo; 最初"
      last: "最後 &raquo;"
      previous: "&lsaquo; 前"
      next: "次 &rsaquo;"
      truncate: "..."
```
##実装
###Controller
Controllerでページパラメータ（ **page(params[:page])** ）を取得

```ruby
@movies = Movie.where(status: "公開中").page(params[:page]).per(10)
#Movie.where(status: "公開中") ← Movieモデルからstatusが"公開中"のレコードを抽出
#page(params[:page]).per(10) ← ページパラメータを取得(10件毎)
```
※全件取得する場合は **モデル名.all** で指定

```ruby
@movies = Movie.all.page(params[:page]).per(10)
```
###View
Controllerで指定した変数を指定

```ruby
#paginate @movies ← 変数 movies の中身を１０件毎に表示
#theme: 'twitter-bootstrap-4 ← 使用したいテーマを指定
<%= paginate @movies, theme: 'twitter-bootstrap-4'%>
```

###表示

<img width="762" alt="スクリーンショット 2020-03-20 14.52.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605913/925a42ce-a431-26b4-0d75-18742491f210.png">


**※上手く表示されない方は**

* サーバーの再起動
* 設定ファイルの確認
* **perの設定（データ数以上のper値を設定するとページネーションが表示されません）**

を確認してみてください！

>参考
https://github.com/KamilDzierbicki/bootstrap4-kaminari-views
公開鍵認証方式を用いてクライアントからサーバーにsshで接続する方法

#はじめに
今回は公開鍵認証方式を用いてクライアントからサーバーにsshで接続する方法を説明します。
ちなみにクライアントとは自分のパソコンの中に構築する仮想環境で、サーバーとはホームページを表示するために必要となる情報を格納しておく環境のことです。

##公開鍵認証方式について
公開鍵認証の仕組みを導入することにより、鍵を持っている場合のみsshログインできるようなります。
その際公開鍵と秘密鍵というものを用いるので簡単に説明します。

**・公開鍵**
サーバー側に持たせておく鍵で作ったときには「id_rsa.pub」という名前で作成されます。
基本的には「authorized_keys」という名前にリネームするのあよいでしょう。
複数の公開鍵を作る場合は、authorized_keysに追記していきます。

**・秘密鍵**
クライアント側で保有しておく鍵でその名の通り秘密のものなので誰にも渡してはいけません。

## sshで接続する方法
### サーバーを起動する
今回は例としてクライアント＝phpstorm、サーバー=クラウド9で試していきたいと思います。

```
$ cd /home/ec2-user/（プロジェクトのディレクトリー）
$ php artisan serve --host=0.0.0.0 --port=8080
※ホスト番号ポート番号は正しいもの入れてください。
```

### Phpstormとcloud9同期させる
#### 秘密鍵と公開鍵の作成
```
//cloud9上で以下を実行
$ cd
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ec2-user/.ssh/id_rsa): cloud9 // 「cloud9」と入力しEnter
Enter passphrase (empty for no passphrase): // 空でEnter
Enter same passphrase again: // 空でEnter
```

正常に実行完了すると、 `~/.ssh`ディレクトリ配下に、`cloud9`と`cloud9.pub`が作成されている。

#### 秘密鍵の登録
```
//cloud9上で以下を実行
$ cat /home/ec2-user/.ssh/[作成した鍵のファイル名(ここではcloud9)]
    -----BEGIN RSA PRIVATE KEY-----
    　　　【秘密鍵の内容】
    -----END RSA PRIVATE KEY-----
※上記秘密鍵の内容を全てコピーする。
    
//ローカルで以下を実行
$ cd .ssh/
$ touch [秘密鍵の保存したいファイル名]
$ vim [保存した秘密鍵のファイル名]
※コピーした秘密鍵の内容をペーストする。
$ chmod 400 [保存した秘密鍵のファイル名]
```

#### 公開鍵の登録
```
//cloud9上で以下を実行
$ cat /home/ec2-user/.ssh/scp.pub 
    　　　【公開鍵の内容】
※上記公開鍵の内容を全てコピーする。
$ vim .ssh/authorized_keys 
※コピーした公開鍵の内容を[# Add any additional keys below this lineの下に]ペーストする。
```
参考：[EC2にSFTPさせる](https://qiita.com/tera78/items/5ed9478d7f281f2b557e)

#### ローカルからcloud9に接続
```
$ cd .ssh/
$ ssh -i [保存した秘密鍵のファイル名] ec2-user@[IPアドレス]
```

##さいごに
こちらの手順を用いれば別のエディタなどからも試せるのでやってみてください。
CakePHP4 で dotenv(.env) を有効化する

他のフレームワークを使っているとローカル環境の差は dotenv(.env) を使います。
CakePHP4 にも dotenv(.env) を使うことができますが、最初は有効になっていないので、有効にする必要があります。

# この記事でわかること

- CakePHP4 で dotenv(.env) を利用できるようになります。
- この記事内のソースは以下で公開しています。
    - https://github.com/katsuhiko/cakephp-vue-study


# 有効化する手順

CakePHP4 プロジェクトを作ったときにできる ` ./config/.env.example ` に以下のコメントがあります。

```php:config/.env.example
# To use this file, first copy it into `config/.env`. Also ensure the related
# code block for loading this file is uncommented in `config/boostrap.php`
```

これが手順です。


# ./config/.env

` ./config/.env.example ` をコピーして ` ./config/.env ` を作ります。
CakePHP4 プロジェクトを作った時点で ` ./config/.env ` は、Gitリポジトリの管理対象外になっています(.gitignore に記載されています)。


# ./config/boostrap.php

以下の記述がコメントアウトされているので、コメントを外します。

```php:config/boostrap.php
if (!env('APP_NAME') && file_exists(CONFIG . '.env')) {
    $dotenv = new \josegonzalez\Dotenv\Loader([CONFIG . '.env']);
    $dotenv->parse()
        ->putenv()
        ->toEnv()
        ->toServer();
}
```


これで、 dotenv が利用できるようになります。


# 補足

本番環境では dotenv を使わないのが普通ですが、私は git ハッシュ値を dotenv に書き込んで、バージョン情報として表示したり、ログの毎行に出力したりすることがあります。

なにか問題が起きたときの調査に役立つのでおすすめです。

dotenv は便利ですよね。
[React]コンポーネントの再帰処理でディレクトリ構造を表示する

コンポーネントの再帰処理をやってみた。

サンプルは[こちら](https://curiosity-driven.web.app/tools/recursion)

ディレクトリ構造を表すようなイメージで作成してみたけど、サイドバーとかドロップダウンメニューとか、いろいろと使えそう。

```tsx
import React, { FC, Children } from 'react';

// ディレクトリ構造としてのサンプルデータ
const fileNames = [
  { name: 'file A' },
  { name: 'file B' },
  {
    name: 'file C',
    items: [
      { name: 'file C-1' },
      { name: 'file C-2' }
    ],
  },
  { name: 'file D' },
  {
    name: 'file E',
    items: [
      { name: 'file E-1' },
      { name: 'file E-2' },
      { name: 'file E-3' },
      {
        name: 'file E-4',
        items: [
          { name: 'file E-4-1' },
          { name: 'file E-4-2' }
        ],
      },
    ],
  },
];

// items で files を受ける。 depth は階層を表す。
const RecursionComponent: FC<{ items: any; depth: number }> = ({
  items,
  depth,
}) => {
  return (
    <>
      {Children.toArray(
        items.map((item: any) => (
          <>
            <div style={{ marginLeft: depth * 20 }}>
              - {item.name}
            </div>
            {item.items && (
              <RecursionComponent items={item.items} depth={depth + 1} />
            )}
          </>
        )),
      )}
    </>
  );
};

const Recursion: FC = () => (<RecursionComponent items={fileNames} depth={0} />);

export default Recursion;
```
Atcorder150 A~C問題

Atcorder150
https://atcoder.jp/contests/abc150/tasks

#A問題
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475270/8a1db3e2-b673-c338-246f-20adcf674fba.png)

```A問題.c++
#include <bits/stdc++.h>
#define rep(i,n) for (int i=0; i<(n); i++)
using namespace std;
typedef long long ll;
typedef pair<int,int> P;

int main(){
    int K,X; cin >> K >> X;
    if(500*K>=X) cout << "Yes" << endl;
    else cout << "No" << endl;
    return 0;
}
```

#B問題
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475270/3303e57f-a939-72af-e459-971514f09a81.png)

```B問題.c++
#include <bits/stdc++.h>
#define rep(i,n) for (int i=0; i<(n); i++)
using namespace std;
typedef long long ll;
typedef pair<int,int> P;

int main(){
    int N; cin >> N;
    string S; cin >> S;
    
    int ans=0;
    rep(i,N-2){
        if(S[i]=='A' && S[i+1]=='B' && S[i+2]=='C') ans++;
    }
    cout << ans << endl;
    return 0;
}
```

#C問題
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475270/2048d4d3-3d69-0c9a-054e-5063d5ce1c61.png)

```C問題.c++
#include <bits/stdc++.h>
#define rep(i,n) for (int i=0; i<(n); i++)
using namespace std;
typedef long long ll;
typedef pair<int,int> P;

int main(){
    int N; cin >> N;
    vector <int> P(N),Q(N);
    rep(i,N) cin >> P[i];
    rep(i,N) cin >> Q[i];
    
    vector<int> a(N);
    rep(i,N) a[i]=i+1; //辞書順で一番小さい配列を作る
    
    map<vector<int>,int> mp;
    do{
        mp[a]=mp.size();
    }while(next_permutation(a.begin(),a.end()));
    
    int ans=abs(mp[P]-mp[Q]);
    cout << ans << endl;
    return 0;
}
```

#まとめ
・C問題　**mapとnext_permutation**の使い方がわかった！
配列aに辞書順で一番小さい数を代入すると、next_permutationで並べやすい！
FlutterでURLSchemeを使って他のアプリ(例: Twitter)を開く(開けない場合の回避策も)

Flutterで個人開発をしている[村松龍之介](https://twitter.com/riscait)と申します。
（仕事ではiOSアプリのネイティブアプリ開発を行っています）

今回は、アプリに自分のTwitterアカウントのリンクを載せようと思いました。
最初は普通にURLを貼って、ブラウザで開くようにしていたのですが、アプリ入ってるならアプリが開いた方が良いよね…と思い実装した備忘録です。

## URLを開くためにurl_launcherパッケージを使う
まず、URLを開くために必要な `url_launcher`パッケージを導入済みでなければ導入します。
[url_launcher | Flutter Package](https://pub.dev/packages/url_launcher)

簡単に書きますと、`pubspec.yaml`ファイルの`dependencies`に1行追記します。
VS Codeですと、⌘ + S で保存すれば`flutter pub get`が自動で走りますのでインストールできます。
Android Studioでもおそらく同じ🤔

```yaml
dependencies:
  url_launcher: ^5.4.2 # <-導入時点で最新のバージョンで良いかと思います
```

## 他のアプリを開きたいファイル（クラス）に実装します
ここではTwitterのプロフィールページを例に用います。

### url_launcherパッケージをインポート
```dart
import 'package:url_launcher/url_launcher.dart';
```

### URLを開く
`launch(url)`関数で引数に設定したURLを開けます。
非同期な関数なので`await`を使っています。

```dart
final url = 'twitter://user?screen_name=riscait' // <-Twitterアプリのユーザープロフ画面を開くURLScheme
await launch(url);
```

開くことのできないURLが入ってくる可能性がある場合は `canLaunch(url)`で調べることができます。

```dart
if (await canLaunch(url)) {
  await launch(url);
} else {
	// 任意のエラー処理
}
```

### URLを開けなかったときのためのセカンドURLを用意
```dart
final url = 'twitter://user?screen_name=riscait' // <-Twitterアプリのユーザープロフ画面を開くURLScheme
final secondUrl = 'https://twitter.com/riscait' // <-Twitterアプリのユーザープロフ画面を開くURL

if (await canLaunch(url)) {
  await launch(url);
} else if (secondUrl != null && await canLaunch(secondUrl)) {
	// 最初のURLが開けなかった場合かつセカンドURLが有って開けた場合
  await launch(secondUrl);
} else {
	// 任意のエラー処理
}
```

### メソッド化
```dart
/// 第2引数のURLを開く。開けないURLだった場合は第2引数のURLを開く
Future _launchURL(String url, {String secondUrl}) async {
	if (await canLaunch(url)) {
	  await launch(url);
	} else if (secondUrl != null && await canLaunch(secondUrl)) {
	  await launch(secondUrl);
	} else {
	  // 任意のエラー処理
	}
}
```

### ボタンで使用する一例
```dart
RaisedButton(
  child: const Text('Twitterを開く'),
  onPressed: () => _launchURL(
    'twitter://user?screen_name=riscait',
    secondUrl: 'https://twitter.com/riscait',
  ),
),
```

## iOSのためにinfo.plistを編集する
これでAndroidではTwitterアプリがインストールされていれば開かれることを確認しました！
しかし、iOSに対応する場合にはもう一手間必要です。

### Android StudioやVS Codeで編集する場合
`info.plist`を開きます。
下記のように1行追加します。

```
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>itms</string>
    <string>twitter</string> <!-- この1行を追加 -->
</array>
```

僕の環境下では `LSApplicationQueriesSchemes`が既に存在しましたが、なかった場合は、5行全部追記しましょう！

```
<plist version="1.0">
<dict>
<!-- この間に追記すればOK -->
</dict>
```

### Xcodeで（Property Listとして）開いて編集する場合
`LSApplicationQueriesSchemes`の一要素として`twitter`等のアプリコードを追加しましょう。


以上、これでiOSでもアプリがインストールされていればアプリが開くようになります。


TwitterのURL Schemeについてはこちらのサイトに詳しく載っておりました💡
[【2019】Twitter公式Appのスキーム一覧 │ えぐぷと！](https://egpt.me/blog/archives/616)


## 蛇足
ご覧いただきありがとうございました！
蛇足ですが、Flutterアプリをリリースできたので良かったらインストールしてみてもらえると嬉しいです🙇‍♂️
iOS: [‎「レストル-有給休暇管理」をApp Storeで](https://apps.apple.com/jp/app/id1501984307)
Android: [レストル-有給休暇管理 - Google Play のアプリ](https://play.google.com/store/apps/details?id=jp.altive.restol)
【JavaScript】小数点以下の不要な０を削除する　toLocaleString

小数点の表示で０の場合だけなくすという仕様で困ったことはありませんか？
具体的には以下のような仕様です。

1.000 => 1
1.100 => 1.1
1.110 => 1.11

## 解決方法
JavaScriptのNumberクラスのtoLocaleStringメソッド(optionのmaximumFractionDigits)を使います。


ブラウザーがlocales引数とoptions引数をサポートされていない可能性がありますのでこちらで確認して下さい。
[リファレンス](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString)

`[数値].toLocaleString( locales, { maximumFractionDigits: [有効にしたい小数点以下の桁数] })`

maximumFractionDigitsオプションを省略した場合はデフォルトは３です。(リファレンスにのっていないため自己検証)

## コードで仕様説明
<img width="705" alt="スクリーンショット 2020-03-20 13.57.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287773/4e1e56e7-cc1a-53ed-6d8f-d584178c5114.png">
小数点以下の不要な０が全て切捨てられています。
画像の一番下をみていただくとわかりますがmaximumFractionDigitsが3のため小数点第3位の数字までしか表示されていません。
<img width="707" alt="スクリーンショット 2020-03-20 14.00.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287773/db893e68-b7cc-b83d-b6e6-fd24f43fd82a.png">
maximumFractionDigitsを4にしているため小数点第4位まで表示されています。
【Rails】小数点以下の不要な０を削除する　number_with_precision

小数点の表示で０の場合だけなくすという仕様で困ったことはありませんか？
具体的には以下のような仕様です。

1.000 => 1
1.100 => 1.1
1.110 => 1.11

## 解決方法

ActionView::Helpers::NumberHelperクラスのnumber_with_precision(optionの strip_insignificant_zeros: true)を使います。


`number_with_precision([数値],precision: [有効にしたい小数点桁数], strip_insignificant_zeros: true)`

precisionを省略した場合、デフォルトは３です。

## コードで仕様説明
<img width="978" alt="スクリーンショット 2020-03-20 8.37.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287773/aabeb0ba-a20f-69e5-e940-aa7e08af60d5.png">
小数点以下の不要な０が全て切捨てられています。
画像の[6]をみていただくとわかりますがprecisionが3のため小数点第3位の数字までしか表示されていません。

<img width="964" alt="スクリーンショット 2020-03-20 8.46.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287773/ad91a050-eaf5-fb69-ba90-103c9b14db99.png">

画像の[7]はpricisionを4にしているため小数点第4位まで表示されています。
「Azure SDK for Go」とは別の独自サービスパッケージ

「[Azure SDK for Go のドキュメント](https://docs.microsoft.com/ja-jp/azure/go/)」サイトの「[Azure SDK for Go のインストール](https://docs.microsoft.com/ja-jp/azure/go/azure-sdk-go-install)」ページを読み進みています。

「[Azure SDK for Go を入手する](https://docs.microsoft.com/ja-jp/azure/go/azure-sdk-go-install#get-the-azure-sdk-for-go)」セクションにて、いくつかのAzure サービス用のパッケージは [Azure/azure-sdk-for-go](https://github.com/Azure/azure-sdk-for-go) とは別に用意されているとの記述があり、それらは主にストレージ サービスとメッセージング サービスのパッケージです。

**ストレージ サービス**

[File Storage](https://docs.microsoft.com/ja-jp/azure/storage/files/)（パッケージ：[Azure/azure-storage-file-go](https://github.com/Azure/azure-storage-file-go)）

- Azure上に構築されたSMB プロトコルのファイル共有システム。
- 汎用 OS（Linux, macOS, Windows、など）でのファイル共有で使用。

[Blob Storage](https://docs.microsoft.com/ja-jp/azure/storage/blobs/)（パッケージ：[Azure/azure-storage-blob-go](https://github.com/Azure/azure-storage-blob-go)）

- ファイルをBLOBで扱うストレージ。
- 大量データの蓄積や操作（アーカイブ、ランダム アクセス、データ解析、など）

[Queue storage](https://docs.microsoft.com/ja-jp/azure/storage/queues/)（パッケージ：[Azure/azure-storage-queue-go](https://github.com/Azure/azure-storage-queue-go)）

- RESTでのテキストメッセージをキューイングする。
- Service Busと比べてキューイング（格納）に重きが置かれている。

[Table storage](https://docs.microsoft.com/ja-jp/azure/cosmos-db/table-storage-overview)（パッケージ：なし）

- 分散Key-Valueストア。

**メッセージング サービス**

[Service Bus](https://docs.microsoft.com/ja-jp/azure/service-bus-messaging/)（パッケージ：[Azure/azure-service-bus-go](https://github.com/Azure/azure-service-bus-go)）

- TCP プロトコルのメッセージをキューイングしたりPub/Subで処理する。
- Queue Storageと比べてメッセージングに重きが置かれている。

[Event Hubs](https://docs.microsoft.com/ja-jp/azure/event-hubs/)（パッケージ：[Azure/azure-event-hubs-go](https://github.com/Azure/azure-event-hubs-go)）

- HTTPS/AMQP/Kafka プロトコルの大量のイベントを受け取って、Kafka プロトコルに対応したサービスに振り分ける。
- ビッグ データ向け。

[Event Grid](https://docs.microsoft.com/ja-jp/azure/event-grid/)（パッケージ：なし）

- 対応したAzure サービスからのイベントを受け取って、対応したAzure サービスに振り分ける。

サービスのパッケージが分家する動きは、Azure SDK for Goがベータ版だった時からあり、最初はストレージでした。
Windows10 DCGAN導入

# 概要
win10でDCGANのプログラムを動作させるときに詰まったのでメモしておく。

使用コードはこちら
https://github.com/carpedm20/DCGAN-tensorflow


## 環境
Windows10 Pro (v1909)
Anaconda v4.8.2

## 結論
Anaconda 環境に対して、下記コマンド入力すればよい。
※今回はGPU版 tensorflowをセットアップした。

```cmd:install.bat
pip install tensorflow-gpu==1.15
pip install scipy==1.1.0 --user
pip install pillow
```

## 詰まったところ
tensorflowの最新版では動作しない？
⇒　しない
　　tensorflow.contrib は v1.15以前にしか存在しないため

参考リンク：
https://github.com/tensorflow/tensorflow/issues/31350
Excon::Error::Socket: getaddrinfo: Name or service not known (SocketError)というエラー文の対応

## 環境
$ ruby -v
ruby 2.6.5
$ rails -v
Rails 5.2.4

Amazon Linux 2

## 状況
本番環境としてデプロイした後に、画像をCarriorwave,fogを通じてS3にアップロードしようとすると、エラーが発生。
エラー文は以下の2種類。

```
Excon::Error::Socket: getaddrinfo: Name or service not known (SocketError)
```

```
SocketError: getaddrinfo: Name or service not known
```

## 本件の原因

```ruby:config/initializer/carrior_wave.rb
if Rails.env.production?
  CarrierWave.configure do |config|
    config.fog_provider = 'fog/aws'
    config.fog_credentials = {
      provider: 'AWS',
      region: 'ap-northeast-1a', # 問題箇所
      aws_access_key_id: 'アクセスキー',
      aws_secret_access_key: 'シークレットキー'
    }
    config.fog_directory = 'バケット名'
    config.cache_storage = :fog
  end
end
```

`'ap-northeast-1a'`なんてリージョンはなく、`ap-northeast-1`の間違いであった。

## 解決した対応

問題箇所の`ap-northeast-1a`を`ap-northeast-1`にしてpumaを再起動した。

こんなしょうもないミスで2時間潰しました笑