OmniAICreator/Qiita-1.07M huggingface dataset:
[漏洞预警]Apache Flink任意Jar包上传导致远程代码执行

### 漏洞描述
近日,有安全研究员公开了一个`Apache Flink`的任意Jar包上传导致远程代码执行的漏洞.经过亚信安全网络攻防实验室研究,发现该0day漏洞真实存在,并且可以攻击最新版本的`Flink`.官方暂未发布补丁.

### CVE编号
暂无

### 漏洞威胁等级
高危

### 影响范围
<= 1.9.1(最新版本)

目前公网(中国地区)共有653台机器收到影响

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/02000b5e-8c95-0784-44d3-ea05c8123061.png)
### 漏洞验证
攻击者只需要自己定制一个恶意jar上传以后提交即可

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/0b633e44-6f45-4934-905d-7d033b94a137.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/651a261d-9d17-50e5-7d4a-2b4370037bbd.png)
### 修复建议
暂无,请等待官方更新

### Reference
https://flink.apache.org/downloads.html
LaTexに日本語を含むソースコードの記載

# 結論

```
\usepackage{listings, 任意パス/jlisting}
```
任意パスとは、上記の行を含むtexファイルに相対するパス。
そこには、[jlisting.sty](https://osdn.net/projects/mytexpert/downloads/26068/jlisting.sty.bz2/) を配置されてあること。

---------

# そもそも問題は何？

LaTexで論文を記載する時、ソースコードを記載したいなら [listings package](https://ctan.org/pkg/listings) を使いますが、日本語は対応していなくて、文字順番が狂います。


例えば、texにこのように記載すると

```latex
\begin{mylisting}[language=matlab,caption=表題,label=mylist1]
   abc日本語def混在ghi
\end{mylisting}
```

コンパイルしたPDFはこんな感じになる

```
1 日本語混在
2     abcdefghi
```

# だから jlistings 入れろってみんな言ってるじゃないか

以下参考節に引用される資料は、インストール方法について、システムフォルダーコピーすることと、mktexlsr実施の手順が必要とされている。手間だけでなく、[overleaf.com](https://overleaf.com) のような環境を利用する私、できない。T_T

そこで、上記結論に記載された方法を発見しました。texの近くにstyファイルを配置すればよい。しかも、フォルダー内に配置してもよい。便利でしょう。

# そうだ、タイトルも変えられるよ

jlisting導入後、各リストの表題が Listing 1から ソースコード１ のように変わります。もし他の文言がほしいなら、jlisting.styの138行ご覧ください。


# 参考
[LaTeXにソースコードを"美しく"貼る方法](https://qiita.com/ta_b0_/items/2619d5927492edbb5b03)
[TeXでソースコードを埋め込む](https://qiita.com/ayihis@github/items/c779e4ab5cd7580f1f87)
[jlisting.styのインストール](https://ie.u-ryukyu.ac.jp/e075729/2009/08/02/jlistingsty%e3%81%ae%e3%82%a4%e3%83%b3%e3%82%b9%e3%83%88%e3%83%bc%e3%83%ab/)
Materialize CSS(v1.0.0)とmaterialize-select2を併用してみたときの気づき

### 概要
* Materialize(マテリアルデザインフレームワーク)を導入したWebページで、**v0.100.2→v1.0.0へアップデートしつつSelect2を導入し、プルダウン検索させたい**というのがきっかけでした。
* で、実際にやってみたら変な引っかかり方をしたので覚書がてら投稿しようと思いました。

### この時の実装要件
* Materializeをv0.100.2からv1.0.0にアップデートする(今更感ありますが)
* そして、MaterializeっぽいSelect2を実装したかった

### 登場人物
* Materialize
    * https://materializecss.com/
* materialize-select2
    * https://github.com/nikitasnv/materialize-select2

### 遭遇した現象
前提として、こんな感じのselectがhtmlに実装されていることとします。

```index的な.html
<select id='select-form' placeholder='選んでね！'>
  <option disabled selected placeholder>選択してね！</option>
  <option value="1">アップル</option>
  <option value="2">オレンジ</option>
  <option value="3">バナナ</option>
  <option value="4">メロン</option>
</select>
```

materialize.cssをインクルードしている場合、JavaScriptで次の通り実装してあげる必要があり、この実装もされている前提とします。

```script的な.js
$(document).ready(function(){
  /* 略 */
  $('select').formSelect();
  /* 略 */
}
```

この状態で生成されたUIがこんな感じ

<img width="493" alt="スクリーンショット 2019-08-06 18.23.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238745/636d0475-4383-dc61-7cf1-b727efd6c5e6.png">

さあ、ここに先述のselect2を適用したい！適用するぞ〜

```script的な.js
$(document).ready(function(){
  /* 略 */
  $('select').formSelect();
  $('#select-form').sm_select();
  /* 略 */
}
```
(勘のいい方はこのあたりでおや？ってなると思います)

この状態で生成されるのが...

<img width="495" alt="スクリーンショット 2019-08-06 18.24.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238745/040e30a5-4aba-9c33-9220-a676067c5161.png">

### 解決方法

* まあ当たり前ですが、materializeのメソッドとselect2のメソッドは完全に別々に動いているため、呼び出すのは片方でよかったということでした。

```script的な.js
$(document).ready(function(){
  /* 略 */
  // $('select').formSelect();
  $('#select-form').sm_select();
  /* 略 */
}
```

* 上記の通り、materialize-select2を採用するのであれば、片方だけでよかったということです。

### 気づき

* フレームワークで生成するDOMを二回呼んでいるのがよくなかった。**フロントエンドで複数のFWを読んでいる時は相互に邪魔しないことをちゃんと確認しないといけない**ですね。
    * 同じ属性のDOMに対して作用するライブラリを同時に読み込むとどうなってしまうのか、というところは当然ですがそれぞれのライブラリのページで解説なんてされていません。というところをちゃんと考えていくことが必要なのかと思いました。
* マテリアルデザインのフレームワークを採用する場合、そのフレームワークで何ができて何ができないのか、そして拡張するならどのように実装を書き換える必要があるのかと言う点が**バックエンドでライブラリを追加するのとは勝手が違う**ということを思い知らされました。
    * それでなくとも、フロントエンドは(僕の認識では)バックエンド以上にトレンドとなる技術の入れ替わりが激しい印象なので、今後フロントの技術選定に携わる機会があるとしたら、膨大なフレームワーク・ライブラリに対して何ができて何ができないかというところを詳細に把握することで、その後の改修・グロースに影響することを今回の件で学びました。フロントエンドって大変だあ。。。
kubectl get podとkubectl top podを一緒に表示するスクリプトを書いた

# はじめに
kubectl get podでCPU/メモリの使用率も一緒にみたかったので、
愚直に出力結果を合わせるシェルスクリプトを書きました。

# スクリプト
```bash
#!/bin/bash

getpods=$(kubectl get pod --field-selector=status.phase=Running --all-namespaces | tr -s " " | tr " " "," )
array_get=(`echo $getpods`)
toppods=$(kubectl top pod --all-namespaces | tr -s " " | cut -d ' ' -f 3-4 | tr " " "," )
array_top=(`echo $toppods`)

merge=""
for (( i = 0; i < ${#array_get[@]}; ++i )); do
    merge+="${array_get[$i]},${array_top[$i]}\n"
done
echo -e ${merge} | column -s, -t
```

# 実行結果
適当な環境で実行

```
gashirar:~$ ./script.sh 
NAMESPACE     NAME                              READY  STATUS   RESTARTS  AGE    CPU(cores)  MEMORY(bytes)
gashirar-app  some-app-6bdf69db8b-4rjrx         1/1    Running  0         3m9s   0m          9Mi
gashirar-app  some-app-6bdf69db8b-sbksz         1/1    Running  0         2m41s  0m          8Mi
gashirar-app  some-app-6bdf69db8b-tbdps         1/1    Running  0         2m43s  0m          9Mi
kube-system   coredns-5c98db65d4-gntsd          1/1    Running  3         13d    5m          9Mi
kube-system   coredns-5c98db65d4-r5wzz          1/1    Running  3         13d    5m          9Mi
kube-system   etcd-minikube                     1/1    Running  1         13d    30m         51Mi
kube-system   kube-addon-manager-minikube       1/1    Running  1         13d    14m         32Mi
kube-system   kube-apiserver-minikube           1/1    Running  1         13d    53m         210Mi
kube-system   kube-controller-manager-minikube  1/1    Running  1         13d    27m         69Mi
kube-system   kube-proxy-49m2n                  1/1    Running  1         13d    2m          23Mi
kube-system   kube-scheduler-minikube           1/1    Running  1         13d    2m          22Mi
kube-system   metrics-server-84bb785897-9kz2x   1/1    Running  1         13d    0m          21Mi
kube-system   storage-provisioner               1/1    Running  2         13d    0m          18Mi
```

Podごとではなくコンテナごとの場合はもう少し工夫がいりそう。
kubectlで取得する部分をいじれば他の結果も一緒に表示できるはず。

# おわりに
探したらすでにkubectl pluginとかありそう。
pythonでcronジョブの管理しよう

[![Build Status](https://travis-ci.com/dakc/cronpi.svg?branch=master)](https://travis-ci.com/dakc/cronpi) [![pypi](https://img.shields.io/pypi/v/cronpi)](https://pypi.org/project/cronpi/) [![GitHub license](https://img.shields.io/github/license/dakc/majidai.svg?style=popout)](https://raw.githubusercontent.com/dakc/cronpi/master/LICENSE) 

# cronpiとは
crontabの処理がもっと簡単に管理できないかと色々悩んだ結果、Pythonでパッケージを作ることにしました。本当は名前を「cronpy」にしたかったのですが、すでにほかの方が登録していたので「cronpi」にしました。
[cronpi](https://pypi.org/project/cronpi/)とはUNIX系のパソコン(linux/mac)で定期的に実行する処理をcrontabに登録するパッケージです。Python2系と3系で動きます。

crontabの処理を**読みやすく**してくれます。


## Installation
```bash
pip install cronpi
```

## サンプル
```sample.py
# パッケージのインポート
import cronpi

# 毎日午後5時半に実行する処理を登録
cronpi.run_every_day("/opt/backup.sh").on("5:30pm")
```

## 機能一覧
cronpiは以下の機能のもつ関数をもちます。

| SN  |      関数名       |                         説明                                    |
| --- | --------------- | --------------------------------------------------------------------------------- |
| 1.  | run_by_date     | 日付をYYYY-MM-DD HH:mmに指定して実行できる処理                |
| 2.  | run_every_day   | HH:mmに時間を指定する事で毎日できる処理                                    |
| 3.  | run_every_week  | 曜日名を指定して実行できる処理                     |
| 4.  | run_every_month | 日にちを指定して実行できる処理              |
| 5.  | run_every_year  | 月の名前と日を指定して実行できる処理                    |
| 6.  | run_custom      | "crontab -e" に入力する1行の内容を指定して実行できる処理|

上記の関数が二つの引数を受け付けます。
**cronpi.XXXX(&lt;command&gt;, &lt;isOverwrite=bool&gt;?)**

|  parameter  |  type  |                                       description                                        |
| ----------- | ------ | ---------------------------------------------------------------------------------------- |
| command     | string | 定期的に実行するコマンド                                            |
| isOverwrite | bool   | falseの場合は、常に新しいジョブを追加します。デフォルトはFalse |

>第1引数のコマンドがすでにジョブに存在しかつ、第2引数がisOverwrite=Trueの場合は、新しいジョブではなく既存の内容を新しい内容に変えます。


## 使い方
#### ① 一度のみ実行する処理
・日付を指定して実行する処理の登録

```python
cronpi.run_by_date("/some/command").on("2020-10-20 5:30pm")
```
<font color="red">※ Cronの仕様上「年」の指定ができないため、2020年以降も毎年実行されます。</font>
実行後1年以内に手動で削除する必要があります。

#### ② 毎日実行する処理
・毎日実行する処理の登録

```python
cronpi.run_every_day("/some/command").on("5:30pm")
```

#### ③ 毎週実行する処理
・毎週特定の曜日に実行する処理の登録

```python
cronpi.run_every_week("/some/command").on("sunday", time="17:30")
```

・複数曜日の指定も可能

```python
cronpi.run_every_week("/some/command").on(["sat", "sun"], time="5:30PM")
```


#### ④ 毎月実行する処理
・毎月実行する処理の登録

```python
cronpi.run_every_month("/some/command").on(10, time="17:30")
```

・ 複数日の指定も可能

```python
cronpi.run_every_month("/some/command").on([10,20], time="17:30")
```

#### ⑤ 毎年実行する処理
・特定の月で実行する処理の登録

```python
cronpi.run_every_year("/some/command").on("january", day=10, time="5:30am")
```

・複数の月の登録が可能

```python
cronpi.run_every_year("/some/command").on(["jan", "oct"], day=10, time="5:30")
```

#### ⑥ カスタム処理
・カスタム登録

```python
cronpi.run_custom("* * * * * /some/command")
```

## 補足
「get_job_list」関数を使う事で現在のジョブの一覧をListとして取得する事ができます。

```python
cronpi.get_job_list()
```
tar.gzに関するコマンド簡易メモ

#.tar.gzに関するコマンドについてメモっとく
忘れがちなので...
##tar
###ファイルをまとめる
```
tar -cf archive.tar file1 file2 
　　#file1とfile2からarchive.tarを作成
```
###ファイルを取り出す
```
tar -xf archive.tar
　　#archive.tarからファイルを取り出す
```
###ファイルの中身を見る
```
tar -tf archive.tar
　　#gzipで圧縮済みのアーカイブでも問題なし
```

##gzip
###gzipで圧縮
```
gzip archive.tar
```

###gzipを解凍
```
gunzip archive.tar.gz
```
新米エンジニアは「先人が作ったWebサービスを活用して課題を乗り越えろ！」

#はじめに

先日[「事実と解釈を見極めろ」](https://qiita.com/msht0511/items/1c8b7bdff0ab65f7f6aa)という記事を投稿しました。
秋に入り新人さんも仕事に慣れてきたのではないでしょうか。
急に話は変わりますが、ITの業界という言うのは仕事が飽和しているにもかかわらずエンジニアが不足しています。
特に日本はエンジニア不足が顕著です。
新人のあなたのも慣れてきたとはいえ常に新しいことを覚えつつ、覚えた仕事をフルに活用して業務の消化に追われているでしょう。

新しいことを覚えることはとても重要です。
しかし、具体を構築して成果物として納めなければならない我々エンジニアに対して無神経な上司は平気で「この仕事お願いね。（＝これちょうだい）」と言ってきます。

今回はあなたの負荷を少しでも減らす方法を共有します。

#新米エンジニアは「先人が作ったWebサービスを見つけて活用しろ」とは
というのはどいうこと？
言葉の通りです。
あなたがやろうとしている仕事、またはその一片は既に`他のエンジニアがもうチートツールを作ってWEB上で使える`という意味です。
あなたが頑張る必要はありません。
ITの業界は日進月歩。
大体あなたがやる仕事の一片は自動化されています。
サービスを活用しましょう。
では、そのサービスをどのように見つけるか？
これも簡単です。
本題に入る前に例を出します。

**「いすを取り合う遊びは何でしょうか？」**

ん？
小学生でもわかりますね。
**「椅子取りゲーム」**です。

例を見たらピンとくる方がほとんどだと思いますが、`○○○ゲーム` って結構耳にしますよね？
シミュレーションゲーム、人狼ゲーム、サバイバルゲームなど、知ってる言葉ありますよね？
そうです。
我々は何かの遊びを調べるとき`○○○ゲーム`とGoogle先生に聞くと思います。

こんな感じで、WEBサービスを探せばいいんです。

次項では実際に私がよく調べるキーワードを共有します。
#どのようにWEBサービスを検索するのか

#○○○作る、○○○生成
基本的には下記で何かを作ってくれるサービスがヒットすると思います。
#####○○○ Generator（ジェネレーター）
#####○○○ Maker（メーカー）
#####○○○ Creator（クリエーター）
ダミー画像作成、パスワードの生成といったときに検索してみてください。


#○○○確認
#####○○○ Checker（チェッカー）
#####○○○ Simulator（シミュレーター）
#####○○○ Test（テスト）
#####○○○ Demo（デモ）
導入予定のライブラリのデモ、実際に動かした場合のプログラムコードのシミュレーションなど。
PHPといったサーバサイドの言語もonブラウザでコードを書いて動きを確認するサービスもあります。

#○○○整形
#####○○○ Formatter（フォーマッター）
SQLの整形、JSON文字列整形、プログラミング言語の整形といったときに。

#○○○変換
#####○○○ Convert（コンバート）
#####○○○ Encode（エンコード）
#####○○○ Decode（デコード）
#####○○○ To ××× または ○○○ 2 ×××
暗号化された文字を複合するときや、ファイル形式を変換するときなど、PDFから画像、Excelから画像といったかゆいところに手が届くサービスが結構あります。
ただ注意しないといけないのはファイルの変換系はサーバへのアップロードするケースが多いため、機密的な文書をこの手のサービスに上げるのはリスクがあるため、信用できるサイトを使うか、クライアントアプリをインストールしてソフトウェアで変換する方がいいかもです。

#おわりに
まだまだ`○○○編集`といったキーワードはあるのですが、上げるときりがないのですが、あくまでも検索前に、**作業の細分化と様々な作業の抽象化することが大切だ**ということが当記事で伝われば幸いです。
Unityでビルド時、Succeededと表示されるがビルドデータが出力されない

#原因
ビルドしたフォルダ、またはプロジェクトがあるフォルダのパスに、2バイト文字が含まれている。

#症状
今までビルドされたが、突然ビルドされなくなった。しかしログではSucceededと表示される...
私の初期状況では、赤のエラー表示すらも出ませんでした。そのため、同名のビルドファイルが上書きして保存されているものだと思い、症状の発覚に気づくまで時間がかかりました。
発覚後、Unityを再起動しビルドした所、Succeededと表示されますが、以下のようなエラーが出現しました。
`D:\Unity\�����\Game\.....`
つまり、ファイルのパスに日本語等の2バイト文字があるため、何かおかしいことが起こっているようです。そこで、日本語ファイル名を英語に変えビルドしたところ、きちんとビルドデータが出力されました。
EC2のログをfluentdでCloudWatchに投げる


# 概要
`fluentd` でEC2で動いているアプリケーションのログをGUI上で監視したいと思いました。
そのため、 `CloudWatchLog` に投げ、GUI上でログを見れるようにしていきます。 

# IAMロールの作成

IAMでロールを作成します。
今回はCloudWatchにフルアクセスできるロールを新規に作成しました。

![IAMロールの作成](https://cdn-ak.f.st-hatena.com/images/fotolife/j/juve534/20191112/20191112011946.png)

これをEC2にアタッチします。
アクション>インスタンスの設定 からIAMロールの割当を行ってください。  

IAMの設定は以上で完了です。

# 導入
まずは公式サイトに沿って導入します。

```
$ curl -L https://toolbelt.treasuredata.com/sh/install-amazon2-td-agent3.sh | sh
```

次にCloudWatchに投げたいので、プラグインを導入します。  
プラグインは [fluent-plugin-cloudwatch-logs](https://github.com/fluent-plugins-nursery/fluent-plugin-cloudwatch-logs)を使います。

```
$ td-agent-gem install fluent-plugin-cloudwatch-logs
```

次にApacheをインストールします。
fluentdがアクセスできるように、ログディレクトリの権限変更も行います。

```
$ yum install -y httpd
$ chmod 777 -R /var/log/httpd
```

以上で導入は完了です。

# 設定

設定は `/etc/td-agent/td-agent.conf` に記載します。  
今回はテストとして、Apacheのログをターゲットにします。

```/etc/td-agent/td-agent.conf

# アクセスログ
<source>
  @type tail
  format apache
  path /var/log/httpd/access_log
  pos_file /var/log/td-agent/httpd.access.log.pos
  tag td.apache.access
</source>

# logsへログを転送
<match td.apache.**>
  @type cloudwatch_logs
  region ap-northeast-1
  log_group_name apache
  auto_create_stream true
  use_tag_as_stream true
</match>
```

これで設定はOKです。

では早速動かしてみます。

```
$ systemctl start td-agent
```

これで起動したので、ログを吐き出してみます。

```
$ curl -vvv http://127.0.0.1
```

するとCloudWatchのapacheロググループに、td.apache.accessというログストリームができ、Apacheのアクセスログがあることが確認できると思います。

![スクリーンショット 2019-11-12 1.35.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39671/c569b5e1-4c96-775f-ceec-a93cfc447307.png "スクリーンショット 2019-11-12 1.35.32.png")

![スクリーンショット 2019-11-12 1.37.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39671/6a5988c1-a4bd-b308-2aa6-677d33d470c2.png "スクリーンショット 2019-11-12 1.37.33.png")

# 個人的に詰まったポイント

## AWSアカウントを読み込まない

プラグインでAWSアカウントが必要なので、設定しようとしましたが、苦戦しました。  
最初はrootユーザのenvに設定しましたが読み込まず、設定ファイルにアカウントのキーとシークレットキーを記載して動かしました。
(FYI [EC2のログをfluentdでCloudWatchに投げる - juve534のブログ](https://juve534.hatenablog.com/entry/2019/11/09/023554))

最終的には「AWS的にはロールで管理した方が良い」というアドバイスを受け、EC2にロールを設定することで解決としました。  

## ログストリーム名が動的にならない

ログストリーム名をタグ名にしようと設定ファイルに、 `log_stream_name {$tag}` と設定しましたが、 `{$tag}` というストリーム名になってしました。  
こちらはプラグインのREADMEを見直し、 `use_tag_as_stream` という設定値を見つけたので、これを設定して解決しました。

# まとめ
EC2のログをCloudWatchに投げることができました。  
fluentdを使うことで、サーバにsshしなくても、ログを確認できるようになりました。
自分の詰まったポイントと合わせ、参考になれば幸いです。

以上、最後まで読んでいただきありがとうございました。
[備忘録] CentOS7 に PHP7.2 をインストール

`yum` で `php7.2` をインストールしたときの手順メモ

```shell
$ sudo yum install -y http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
$ sudo sed -i -e "s/enabled *= *1/enabled=0/g" /etc/yum.repos.d/remi.repo

$ sudo yum install -y https://repo.ius.io/ius-release-el7.rpm
$ sudo sed -i -e "s/enabled *= *1/enabled=0/g" /etc/yum.repos.d/ius.repo

$ sudo yum update -y 
$ sudo yum install -y httpd httpd-tools zip unzip
$ sudo yum install --enablerepo=epel -y libmcrypt libwebp
$ sudo yum install --enablerepo=remi -y gd-last
$ sudo yum install --enablerepo=epel,remi-php72 -y php php-devel php-gd php-mbstring php-mcrypt php-pdo php-xml php-opcache php-xdebug
$ sudo yum install --enablerepo=ius -y git2u
$ sudo yum clean all
```

# 変更履歴

- ius リポジトリの URL 変更 (2020-07-02)  

# 参考

- [iusの最新リンクが変更になったので注意 - Qiita](https://qiita.com/seal_qiita/items/981a9284ecd44e54af96)
Laravel で API用のdumpヘルパを作成する

Laravelを使ってAPI開発をしていて、ClockworkとPostmanを使ってるのですが
サクッと変数を見たいときに癖で`dd()`を使うのですが、APIのときだと使い物にならず...
Logも、仕込んで、飛ばして、確認とひと手間感があまり慣れず
`dd()`改造すればすぐだなと思ったので作ってみました。

#ddの実装

`VarDumper::dump`で階層だったり、視覚的に見やすくするようにしているようです。(多分)

```php:/vendor/symfony/var-dumper/Resources/functions/dump.php
if (!function_exists('dd')) {
    function dd(...$vars)
    {
        foreach ($vars as $v) {
            VarDumper::dump($v);
        }

        die(1);
    }
}
```

#作成
[こちら](https://s8a.jp/laravel-custom-helper)の記事を参考にhelperのファイルを作成しました。

いろいろ試して、オブジェクトの中身すべて表示するレベルにすると、レスポンスの容量がすごかったのでこれに落ち着きました。
ddってすごかったんだなぁ...


```php:app/helpers

if (!function_exists('ddfa')) {
    /**
     * dump & die for api
     *
     * @param mixed ...$vars
     */
    function ddfa(...$vars)
    {
        foreach ($vars as $v) {
             echo (is_object($v) ? json_encode($v, JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE) : var_export($v)) . PHP_EOL;
        }
        die(1);
    }
}


```

あとは随所で`ddfa()`でサクッと見れます。

<img width="495" alt="スクリーンショット 2019-11-13 0.36.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174757/580d27fe-e8b1-9558-9223-eec25c77ff6a.png">


ミスやおすすめの方法や、よりよい方法がありましたらご指摘いただけますと幸いです。
nuxtのmiddlewareメモ

# middlewareとは

このライフサイクルの最初の方にあるもの。レンダリングする前に処理を行いたいときに使う。また全ページ共通の処理としてもかけるので共通のものを書きたいときにも使う。

http://lab.astamuse.co.jp/entry/2019/05/29/114500

# 書き方

https://ja.nuxtjs.org/guide/routing/#%E3%83%9F%E3%83%89%E3%83%AB%E3%82%A6%E3%82%A7%E3%82%A2

* middleware/ ディレクトリに書く
* middleware/auth.js は auth ミドルウェアになる
* ミドルウェアは第一引数として コンテキスト を受け取ります
* 下記のように

```javascript:nuxt.config.js
export default {
  router: {
    middleware: 'auth'
  }
}
```

```javascript:middleware/stats.js
import axios from 'axios'

export default function ({ route }) {
  return axios.post('http://my-stats-api.com', {
    url: route.fullPath
  })
}
```
ペアプロット図って何なの？

# はじめに
Kaggleやっててpandasでpairplot（=散布図行列）をよく見かけるが、
毎回見てて「だから何なの？」の疑問がぬぐい切れず
一念発起して何のための図なのかを調べることにした

# 今時点の結論
変数間の相関関係を俯瞰できるようにするための図。
一つ一つの解釈は分布図を調べればわかるので譲るとして…
俯瞰出来たら何がよいか、というと。
例えばその相関が説明変数と強いかどうか、という観点で見れば
どの変数を特徴量に使用するのに向いているのか？にも使えるのかなと。

そうすることで特徴選択のヒントになるかな？と思った。

# 参考URL
とにかく「こんなにオシャレにpairplot描けるよ！」ってサイトばかりで
悲しかったので、参考にしたサイトを残す。

★散布図行列の要素である分布図の主成分分析の考え方についてまとまって理解のきっかけになった
https://logics-of-blue.com/principal-components-analysis/

★散布図行列をシンプルなお手本で紹介してくれたので理解しやすかった
https://www.jmp.com/japan/support/help/Discovering_JMP_21.shtml#123526
【ubuntu 18.04】左クリック効かない時の対処法

備忘録です。
ubuntu 18.04で左クリック効かない時が謎に多くあったので、私の環境下での解決策を。。。

・左クリック効かない時
step1:
Ctrl+Alt+F3仮想環境へ？

step2:
Ctrl+Alt+F2で戻る

なんかこれしたら治りました。詳しくはよくわかりません。。。
内部関数を用いた際の変数スコープ

何回か使うけど、外出しのmethodにする必要もないなという場合に使う関数の入れ子。

```python
def hoge():
    def fuga():
        pass
```

これを使うときに変数の扱いがどうなるのかなと思ったので検証。

## ローカル変数
```python
def hoge():
    x = 1
    def fuga():
        x = 3
    fuga()
    print(x)
```
実行結果

```python
hoge()
1
```
ローカル変数の場合はそれぞれ別の変数として扱われるようだ。当然っちゃ当然。
ただ、これは`nonlocal`宣言で変更することができる。

```python
def hoge():
    x = 1
    def fuga():
        nonlocal x
        x = 3
    fuga()
    print(x)
```
実行結果

```python
hoge()
3
```

## クラス変数
```python
class Sample:
    def __init__(self):
        self.hoge = None

def hoge():
    smp = Sample()
    smp.hoge = "abcde"
    def fuga():
        smp.hoge = "fghijk"
    fuga()
    print(amp.__dict__)
```
実行結果

```
hoge()
{'hoge': 'fghijk'}
```

クラス変数の場合はグローバル扱いになるのかな。

## おまけ
これを使って条件によって別の値をクラス変数に入れたいときにコードをスッキリできる

```python
class Sample():
    def __init__(self):
        self.hoge = None
        self.fuga = None

def hoge(list):
    smp = Sample()
    def set_val(val1, val2):
        smp.hoge = val1
        smp.fuga = val2
    if len(list) == 1:
        set_val(list[0], None)
    else:
        set_val(list[0], list[1])
    print(smp.__dict__)
```
実行結果

```
hoge(['aaaa', 'bbbb'])
{'hoge': 'aaaa', 'fuga': 'bbbb'}

hoge(['cccc'])
{'hoge': 'cccc', 'fuga': None}
```

使いどころがあるのかは知らない！
CentOS7上のpyenvで作った環境にpython3.8.0をインストールした

# はじめに

pyenvを使う機会があったので、ついでにpython3.8（現時点で最新）をインストールしてみました。
その際の、記録です。
pyenvは簡単に言うと、OSにインストールされているpythonと干渉せずに、別バージョンのpythonをインストール・実行できるツールです。
この記事は、2019年11月時点で作業記録です。

## 環境
- CentOS Linux release 7.6.1810
- git version 2.20.1
- pyenv 3.7.5
- python 3.8（pyenv環境にインストールするバージョン）
- python 2.7.5（OSにインストールされているバージョン）
- python3 3.6.8（python3としてインストールされているバージョン）

※gitは、pyenvのインストールに使用しているだけです。

## pyenv で環境作成

python 3.8 は、pyenvで作った環境にインストールします。
これにより、OSにインストールしているpythonと別バージョンのpython環境を用意できます。
pyenvの詳細については、[pyenv/pyenv: Simple Python version management - GitHub](https://github.com/pyenv/pyenv) を参照してください。

### pyenvのインストール

下記のコマンドを実行し、ptenvをインストールしてください。

    $ git clone https://github.com/pyenv/pyenv.git ~/.pyenv

pyenvのための環境変数を設定します。
.bash_profile に下記を追記します。

    $ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
    $ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
    $ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile

追記したら、.bash_profile を再読み込みします。

    $ source ~/.bash_profile

pyenvのバージョンを確認します。

    $ pyenv --version
    pyenv 1.2.15-1-g49bf5952

### pythonのインストール
作業ディレクトリを作成します。

    $ mkdir python380
    $ cd python380

インストール可能なpythonのバージョンを確認します。

    $ pyenv install --list | grep 3.8
    3.8.0
    3.8-dev
    miniconda-3.8.3
    miniconda3-3.8.3

python をインストールします。

    $ pyenv install 3.8.0

インストールが終わったら、使用するpythonのバージョンを指定します。

    $ pyenv local 3.8.0

ディレクトリ内に、.python-version が作成されているはずです。
中をみると、

    $ cat .python-version
    3.8.0

となっています。
念のため以下のコマンドで確認します。

    $ pyenv version
    3.8.0 (set by /home/ユーザ名/python380/.python-version)

これで、このディレクトリ内で使用するpythonは、3.8.0になります。
確認します。

    $ python -V
    Python 3.8.0
    $ python3 -V
    Python 3.8.0

まさかのpython3も、3.8.0になっていました。

## 他のディレクトリでは・・・

別のディレクトリへ移動して、バージョンを確認すると・・・

    $ cd ..
    $ python -V
    Python 2.7.5
    $ python3 -V
    Python 3.6.8

元のバージョンになっています。
これで、使い分けができるようになりました。

## 最後に

別バージョンのpythonが必要だったため手順をまとめていました。
後々に、使えそうな気がしたので記事にしました。
未来の自分と、他の方々のお役に立てたら幸いです。
数値の丸め方について

## 数値を丸めたい！
UISliderのvalueを取得した際、小数第５位まで表示されてしまったため数値の丸め方についてまとめました。


## 方法1　formatを使用する
```swift:howToChangeDigits
let number = 12.34567

print(String(format: "%.0f", number))   // -> "12"
print(String(format: "%.1f", number))   // -> "12.3"
print(String(format: "%.2f", number))   // -> "12.35"
print(String(format: "%.3f", number))   // -> "12.346"
```

結果より、四捨五入して丸められていることがわかります。
丸めた後のデータ型は、String型になります。

## 方法２　round()を使用する
```swift:howToChangeDigits
let number = 12.34567

print(round(number)                  // -> 12.0
print(round(number * 10) / 10)       // -> 12.3
print(round(number * 100) / 100)     // -> 12.35
print(round(number * 1000) / 1000)   // -> 12.346
```

formatを使用した時と同様に四捨五入されます。
丸めた後のデータ型はDouble型またはFloat型になります。特に型を指定せずにnumberを定義した場合はDouble型になります。
`round()`の代わりに`floor()`を使用すると切り捨て、`ceil()`を使用すると切り上げて丸めることができます。

##### 参考サイト
- https://program-life.com/524
動画からキャプチャ画像を撮る方法(OpenCV)

# きっかけ
[OpenCVを使って長い動画を一部だけ保存する方法]
(https://qiita.com/satsukiya/items/9647e20c4e27b3d0362a)で取得した1分動画から画像処理のサンプル画像用に好きなところでキャプチャを撮るスクリプトを作ってみたっす:laughing:

# 開発

Viewを表示して キーボードの s[save] ボタンを押すとキャプチャが保存されます。


```Python
import cv2

if __name__ == '__main__':

	cap = cv2.VideoCapture('one_minutes.mp4')
	window_name = "Drop Out NHK"

	save_press_count = 1
	while True:
		presskey = cv2.waitKey(1)

		if not cap.isOpened():
			break

		ret, frame = cap.read()

		if presskey == ord('q'):
			break
		elif presskey == ord('s'):
			cv2.imwrite("capture_{}.png".format(save_press_count), frame)
			# capture ボタンを押しただけ 画像を保存
			save_press_count += 1
		cv2.imshow(window_name,frame)

	cap.release()
	cv2.destroyWindow(window_name)
```

# 結果
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288206/6c9e8b9a-4fd2-0227-0046-bcf8183d9b79.png" width=50%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288206/2b15f06f-3cea-dbc3-6c7d-b200952442ea.png" width=50%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288206/9dd08f2e-7556-d7ce-af9c-76acb904cfeb.png" width=50%>


![50302312_378887672660592_5700332032704316718_n.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288206/ccbe40fd-8547-026c-5cbc-d08006e8ce96.jpeg)


# おわりに
[OpenCV 2 プログラミングブック](https://book.mynavi.jp/ec/products/detail/id=22688) にあったコードを思い出して C++ -> Python に書き換えただけです。
処理用に複数枚の画像が欲しかっただけです。

# 参考にしたリンク
- [opencv-cookbook カメラ画像をキャプチャする](http://opencv.jp/cookbook/opencv_io.html#id6)
スクロールさせた際にナビゲーションバーの背景色を変更させる方法について

先輩の会社のホームページを制作中です:smile:

- 使用言語
    - HTML5, CSS3, jQuery3.3.1, BootStrap4

- テキストエディタ
    - Visual Studio Code

　今回は、スクロールさせた際にナビゲーションバーの背景色を変化させたいと思い、色々調べてみたところ、以下のjQueryのコードを使うとスクロールさせた際にナビゲーションの背景色が`#6c757d`に変わることが出来ました。

```javascript:qiita.js
$(function(){
    $(window).scroll(function() {
        if ($(this).scrollTop() > 0) {
            $('nav').css('background-color', '#6c757d'); /* htmlファイルのnavタグの背景色変更 */
        } else {
            $('nav').css('background', 'none'); /* htmlファイルのnavタグの背景色変更 */
        }
    });
});
```
また、スクロールさせた位置からトップの位置まで戻したら背景色が元に戻ります。

一体、どういう動きをしているのか:thinking:

調べてみました:smile:

###$(window).scrollとは？

windowオブジェクトのscrollメソッドはスクロール位置を指定座標（モニタ上の絶対位置）へ移動します。

モニタ上の絶対位置とは、モニタの左上を基準にして水平方向・垂直方向の距離を指定した位置のことです。
（window.scrollの説明は、 http://www.htmq.com/js/window_scroll.shtml より引用）

つまり、スクロールさせた際の処理については、「２行目以降の{}ブロック内のコードを実行する」という解釈が出来ます。

###if文の中身

```javascript:qiita1.js
if ($(this).scrollTop() > 0) {
    $('nav').css('background-color', '#6c757d');
} else {
    $('nav').css('background', 'none');
}
```

条件式にscrollTop()というのが出てきました。

これは、ブラウザの画面をスクロールした時の位置（スクロール量）を取得できるメソッドになります。

画面横のスクロールバーと捉えても良いようです。

また、取得だけでなく、任意の数値を設定することで、指定された位置にスクロールを移動させることもできるみたいです。

一般的に画面のスクロール位置を取得したい場合には、対象要素は「window」になりますが、今回$(this)というjQueryオブジェクトとセットで使い、scrollTop()の引数を省略することで、対象となる要素のスクロール位置を取得していると考えます。
(scrollTop()メソッドの説明は、 https://www.sejuku.net/blog/61689#scrollTopより引用)

つまり、上記のコード(qiita1.rb)は、**トップ位置から少しでもスクロールされた場合に背景色が`#6c757d`へ変わり、トップ位置の場合は透明色にする**という意味になります。

試しに、条件式を下記コード(qiita2.rb)に変えた場合、

```javascript:qiita2.js
if ($(this).scrollTop() > 100)
```

垂直方向へのスクロール位置がトップ位置から100より大きいになってから、ナビゲーションバーの背景色が変わりました。

また、スクロール位置がトップ位置より100以内になると透明色に戻りました。

ただ、今のままだとスクロールさせると直ぐに色が変わるため、アニメーションによって格好よく切り替わる方法を勉強していきます。
IPhoneでカメラを使ったアプリの基本(swift)

https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/avcam_building_a_camera_app

#####UIImagePickerController
→実装がすごい簡単
 できることは少ない

#####AVCaptureStillImageOutput
→iOS10でdeprecated

#####AVCapturePhotoOutput
→iOS10以降
・API Reference - AVCapturePhotoOutput
・LivePhotoなどの撮影が可能
・UIImagePickerControllerと比べると実装が複雑


#####AVCaptureVideoDataOutput
→iOS4以降
動画撮影を行う
コンピューターの５大装置

基本情報技術者の勉強過程で学んだことを書いていく記事です。
勉強にはこの本を使いました。
https://www.amazon.co.jp/exec/obidos/ASIN/4297102110/hsby07-22/

今回はコンピューターのCPUと５大装置について書いていきます。
コンピュターのハードウェアは大きく５つに分けることができます。

##制御装置
各装置を制御する役割を持つ
CPU(Central Processing Unit)
コンピューターの中核であり制御と演算を行う装置
プログラムの命令を受けてコンピューター全体の制御を行う

##演算装置
命令に従い演算を行う役割を持つ
CPU
四則演算などの計算とデータの演算処理などを行う
CPUの演算部分はALU(Arithmetic and Logic Unit)とも呼ばれる

##記憶装置
動作に必要な情報を保持したりファイルに保存する役割を持つ

主記憶装置(RAMなど)
動作に必要なデータやプログラムを一時的に記憶する装置
代表的なものはメモリであり、電源を落とすと内容は消えてしまう

補助記憶装置(ROMなど)
データやプログラムの長期記憶する装置
ハードディスクやCD-ROMなどがあり、電源を落としても内容は消えない

##入力装置
コンピューターにデータを入力するための装置
キーボード、マウス、スキャナなど

##出力装置
コンピューターのデータを出力するための装置
ディスプレイ、プリンタなど


##まとめと各装置のデータの流れ
制御装置は装置全体を制御する
入力装置から記憶装置であるメモリにデータを入力→演算装置で計算し主記憶装置にデータを返す→主記憶装置のデータを出力装置で出力
SSH接続のRaspberry PiにGoogle Driveをマウントする

Raspberry PiでGoogle Driveを使うハウツー記事はすでにいくつかありますが，実際に自分でやってみたらいくつかハマリポイントがあったので，やり方をまとめておきます．

##環境など
- Raspberry Pi 3 Model B+
- Raspbian Lite（GUIなし） ←ラズパイ上でブラウザは起動しない
- ラズパイの操作は全てssh接続で行う
- Google Driveクライアントはgoogle-drive-ocamlfuse
- 検証した日 ... 2019年11月12日

## google-drive-ocamlfuseのインストール
ラズパイ上で以下のコマンドを実行します．

```
sudo apt-get upgrade
sudo apt-get install opam mccs
opam init --solver=mccs
opam update
opam install depext
opam depext google-drive-ocamlfuse
opam install google-drive-ocamlfuse
```
`opam`コマンドはroot実行非推奨とのことです．
`opam init`をするときにデフォルトのsolverを使うとSolver Failedで落ちるので，`mccs`を導入し，それを`opam init`のsolverに指定することで落ちるのを回避しています．

## マウント先のディレクトリを作成する
GoogleDriveフォルダをマウントするディレクトリを作成します．ホームディレクトリ直下に作るなら`mkdir ~/googleDrive` のようになるでしょう．

## google-drive-ocamlfuseの認証をする
通常であればgoogle-drive-ocamlfuseを実行するとブラウザが立ち上がるので，そこでログインすれば認証できます．しかし，今回はラズパイの操作をssh上で行っているため，ニセのfirefoxを作成し認証に介入します．

まず，カレントディレクトリに`firefox`という名前で以下のスクリプトを作成します．

```shell:./firefox
#! /bin/sh
echo $* > /dev/stderr
```

このスクリプトに実行権限を付与します． 

```shell
chmod 777 firefox
```

続いて以下のコマンドでOAuth認証を起動します．

```shell
PATH=`pwd`:$PATH ~/.opam/default/bin/google-drive-ocamlfuse
```

すると，https://accounts.google.com で始まる URLが表示されます．**URLが表示された端末を開いたまま**，お手元のブラウザで表示されたURLを開いてください．Googleの認証を求められるので，素直に従って認証します．

端末に以下の文字列が表示されたら認証成功です．

```
Access token retrieved correctly.
```

## GoogleDriveフォルダをマウントする

```shell

~/.opam/default/bin/google-drive-ocamlfuse ~/googleDrive
```
これで`~/googleDrive`にめでたくお使いのGoogleDriveがマウントされたと思います．

##参考にしたURL
- https://kamchatka.blog.ss-blog.jp/2018-10-07 （全体の手順）
- https://github.com/ocaml/opam/issues/3827 （`opam init`のエラー回避）
- http://moguno.hatenablog.jp/entry/2016/03/24/010502 （sshでの認証方法）
k9s で k8s Surfing (kubectl には戻れない)

## 本日(2019-11-12)、下記記事を読ませてもらった勢いで書く。

- [k9s で一歩進んだ Kubernetes クラスタマネジメントを🐶 Goodbye to kubectl！ - okadato の雑記帳](https://okadato623.hatenablog.com/entry/2019/11/11/075700)

## インストール (Mac)

- [公式](https://github.com/derailed/k9s#installation) 通り。

```
brew install derailed/k9s/k9s
```

## 実行

```
k9s
```

- 終了する時は `:q`

## k9s

![k9s-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201797/82ac1c20-3fd6-897a-96c7-115d68d9a2e4.png)

- とりあえず以下の手順を試す。
    1. `:ns` 打つと namespace 一覧。
    1. `j` か `↓` で、namespace を選んで、 `return` で、namespace 内の pods 一覧。
    1. `:svc` 打つと、選んだ namespace 内の service 一覧。
    1. 画面下部に View (`<pods>` `<ns>` `<po>` `<svc>`) が並んでいる。view のひとつ前に戻る時は `p` 。
        - `return` で潜っていった時は、 `esc` で抜ける。
    1. `control+a` で、エイリアスが確認できる。
    1. `?` でヘルプ。
- 何か選んで `y` で、yaml が見れる。
- 何か選んで `e` で、yaml が編集できる。
- 何か選んで `l` で、ログが見れる。
- namespace を渡り歩いていると、`0`、`1`、`2`、`3`、`4`、のように数字でアクセスできる namespace が増えていく。

## そして何と言っても Port Forwards

- Service からでも、直で Pod でも、Pod View に入り込んだら `shift+f` で、ポート選択のダイアログが出る。
- ダイアログ上は、 `tab` で移動。必要であればポートを編集して OK で `return`。
- `:pf` すると Port Forwards 一覧。
    - 終了する時は、 `control+d` で削除。たぶん。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201797/823d1d66-9cbc-5137-060f-c209467550ed.png)

- [ベンチマーク](https://github.com/derailed/k9s#benchmarking)もできるっぽいが試していない。

## まとめ

やばい、便利すぎる。
AWSに登録したら一番最初にやること

## 目的

このエントリーはIAMのダッシュボード画面のセキュリティステータスを全て完了させるのが目的です。

AWSを利用するにあたって必ずしも必要な設定ではないですが、アカウントが乗っ取られたり悪用されて身に覚えのない請求が発生する可能性を最小限に止めることができます。

## 免責

社内カリキュラム利用を想定し、一部簡略化して記載しています。

不明な点があれば質問してください。

共同編集のリクエストもOKです。

## 早速始める

### AWSにルートユーザーでログインする

ルートユーザーであることを確認してログインしてください。

<img width="1029" alt="ルートユーザーでログイン.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87431/f287a8ed-afff-9a22-3c02-f2374af3bd21.png">

### AWSマネジメントコンソールからIAMを開く

「サービスを検索する」にて`IAM`を検索しましょう。

<img width="1406" alt="AWSマネジメントコンソールからIAM画面を開く.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87431/827b185c-d6cf-5654-f5ab-7d6155ad05f9.png">

IAMのダッシュボード画面に遷移します。

### IAMのアクセスキーをロックする

IAMは`Identity and Access Management`の略です。

ユーザーやグループ、ロール、権限等を管理できます。

ここでルートユーザーアカウントをロック（=`削除`）します。

※「`無効化`」だと後述するダッシュボードのセキュリティステータスが完了にならないため注意してください。

<img width="1396" alt="ルートユーザーのアクセスキーを削除する.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87431/5773dc6f-6f66-23b5-de33-a10e50392cf4.png">

### IAMユーザーを作成し、管理者権限を付与する

グループを作成し、そのグループに管理者権限を付与します。

次にユーザーを作成し、権限を付与したグループにそのユーザーを割り当てます。

※直接ユーザーに管理者権限を付与することも可能ですが、ダッシュボードのセキュリティステータスが完了になりません。

#### グループに管理者権限を付与し、ユーザーを割り当てる

グループを作成し、`AdministratorAccess`のポリシーを付与してください。

<img width="1396" alt="Administratorsグループを作成.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87431/ef6c38f8-e909-8781-e193-302fe2b91da0.png">

その後ユーザーを作成し、そのグループに追加してください。

<img width="1396" alt="ユーザーを管理者権限グループに割り当てる.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87431/eec62e0a-d990-fbd8-1ef1-f6a04d54539c.png">

### 多要素認証（MFA）を設定する

まずMFAデバイスに認証アプリをインストールしてください。

<img width="375" alt="Google_Authenticatorをインストールする.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87431/a0142951-6f79-2557-223e-5127c1939bd5.png">

次に表示された認証キーをAWS画面に入力してください（6桁入力が2回あります）。

<img width="375" alt="認証番号を入力する.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87431/30065ca7-ebc5-798f-2b2b-2e758288d4c9.png">

ダッシュボードに戻り、以下のようになっていれば設定完了です。

ルートユーザーからログアウトし、以降は管理者権限のユーザーでAWSを利用してください。

お疲れ様でした。

<img width="952" alt="ダッシュボードのセキュリティステータスが5:5になれば完了.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87431/5b2fa4e2-2af5-204c-91ba-42e0905119c3.png">
Git ブランチの復活


「あれ？作ったはずのブランチが見つからない。。。
　間違って消しちゃった！」

そんな経験ありませんか？
「ブランチ管理がいい加減だからそんなことになるんだ！」
そう思ってた僕もとうとうやってしまいました。
結構差分が大きいコミットだったんですが、まだ元に戻せる可能性は残ってるみたいです。

## 方法

Gitには**Reflog**というのがあって、ローカルリポジトリでのHEADの変遷を全て記録しています。
この**Reflog**を使って戻したい時点のコミットを探せば元に戻すことができます。
**Reflog**の履歴は`git reflog`コマンドで見ることができます。

```sh:Terminal
$ git reflog
f5fd3ef39 (HEAD -> feature/switch_enabled_address) HEAD@{0}: rebase finished: returning to refs/heads/feature/switch_enabled_address
f5fd3ef39 (HEAD -> feature/switch_enabled_address) HEAD@{1}: rebase: mail有効化の切り替えを非同期通信に変更
2f1138f9b (origin/master, origin/HEAD, master) HEAD@{2}: rebase: checkout master
b3946b35a HEAD@{3}: checkout: moving from master to feature/switch_enabled_address
2f1138f9b (origin/master, origin/HEAD, master) HEAD@{4}: merge origin/master: Fast-forward
c8ae0c424 HEAD@{5}: checkout: moving from feature/switch_enabled_address to master
b3946b35a HEAD@{6}: rebase -i (finish): returning to refs/heads/feature/switch_enabled_address
b3946b35a HEAD@{7}: rebase -i (squash): mail有効化の切り替えを非同期通信に変更
57080d0bf HEAD@{8}: rebase -i (start): checkout HEAD~9
a9a5a5894 (fork/feature/switch_enabled_address, test/switch_enabled_address_circle) HEAD@{9}: checkout: moving from test/switch_enabled_address_circle to feature/switch_enabled_address
a9a5a5894 (fork/feature/switch_enabled_address, test/switch_enabled_address_circle) HEAD@{10}: Branch: renamed refs/heads/feature/switch_enabled_address to refs/heads/test/switch_enabled_address_circle
```

例えばこれは僕の**Reflog**なんですが、大まかにいって下記のような形式をしてます。
`HEAD{n}`のnはHEADが変わった回数を記録していて、0が今のHEADで数が大きくなるほど過去のHEADを表します。
僕の例でいうと、現在のHEAD、`HEAD{0}`のコミット番号は`f5fd3ef39`でrebaseをした直後であることがわかります。

rebase前にコミットを戻してみましょう。

僕の例では3回前のHEAD、`HEAD@{3}`が、rebase前の`HEAD`になります。`Reflog`から、`master`ブランチから`feature/switch_enabled_address`に`checkout`した直後です。

あとはブランチを作成する要領で、

```sh:Terminal
$ git switch -c revive HEAD@{3}
```

これで元に戻すことができました。

## Reflogについて

Reflogはかなり便利で、`master@{one.week.ago}`みたいな指定もできるみたいです。
詳しくは、[https://git-scm.com/docs/git-reflog]()に解説があるので読んでみてください。
ドッグフーディング用にiOSアプリからslackにフィードバックをする方法 

Debug中のアプリをSlackに簡単にスクショとか動画をメッセージ付きで投稿できる
[AppFeedback-ios](https://github.com/yahoojapan/AppFeedback-ios)を入れる

![](https://github.com/yahoojapan/AppFeedback-ios/raw/master/assets/demo.gif)



## SDKの導入

### Carthageでの導入

Cartfileに以下を追記する

```
github "https://github.com/yahoojapan/AppFeedback-ios"
```

```
carthage update
```
Build PhasesのLink Binary With LibrariesからAppFeedback.frameworkを追加

<img width="860" alt="スクリーンショット 2019-10-25 19.09.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64331/5e51beae-9fda-386e-a132-6668c326825f.png">



リリースするバージョンには表示しないようにするため、
Build PhasesからRun Scriptで以下を追加

<img width="677" alt="CopyFrameworks.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64331/298c01a8-583b-f2fb-adcd-c1d06920b36c.png">


```
if ["${CONFIGURATION}" != "Release" ]; then
  /usr/local/bin/carthage copy-frameworks
fi
```
Input Files

```
$(SRCROOT)/Carthage/Build/iOS/AppFeedback.framework
```

### Bridging HeaderにSDKを追加

<img width="723" alt="スクリーンショット 2019-10-30 12.50.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64331/e9632d27-5557-4ab4-bb48-02c99caedbb2.png">


まだ、Briding Headerがない場合は適当にObject-Cのファイルを追加するとBridging Headerを追加するかどうか聞かれるので追加する。その後Obj-Cのファイルは削除

<img width="562" alt="スクリーンショット 2019-10-25 18.36.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64331/09e37c3a-5376-9f4d-fc02-0e4f0a51a976.png">

 

Briding HeadeファイルにAppFeedBackを追加

`Bridging-Header.h`

```
#import <AppFeedback/AppFeedback.h>
```

## 実装

### AppDelegateに以下のように記載

```
import AppFeedback


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // ……
    
    #if DEBUG
        AppFeedback.configure(withSlackToken:"<your token>", slackChannel:"<slack channel id>")
    #endif

    // ……
}
```

###もし、SceneDelegateに対応している場合

```
import AppFeedback


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        AppFeedback.configure(withSlackToken: "foo", slackChannel: "hoge")
        AppFeedback.readyFeedbackGesture()
        AppFeedback.readyScreenShot()
        guard let _ = (scene as? UIWindowScene) else { return }
    }
```



slackのtokenはログインした状態で[ここ](https://api.slack.com/custom-integrations/legacy-tokens)のcreate tokenから取得する。
チャンネルIDはslackのチャンネルを右クリックでコピーすると分かります。

これで表示完了！！
<img width="499" alt="スクリーンショット 2019-11-05 17.54.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64331/488fc651-bb39-96b5-e15b-2ad15d53542d.png">
Android フォアグラウンドからバックグラウンド、その逆のイベントとる

![スクリーンショット 2019-11-12 23.09.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67083/1848c92b-0a0c-5095-3ce0-5c0e51303f6e.png)


ハマりすぎたのでメモ２
参照とかnugetからパッケージ落としてくるとこは前記事を参照

仕組みはarch.lifecycle extentionsって言うのでなんでもライフサイクルが管理できる様になる
何も入れないとActivityはonPauseとonResumeとかあるのでこれはいらないが、
これをアプリケーション自体に適用するとアプリケーションがフォアグラウンドになった時とかバックグラウンドになった時のイベントをハンドリングできる様になる

画像を見れば以下のことが分かる
・アプリケーション自体のクラスの実装の仕方
・アプリがバックグラウンド、フォアグラウンドに行った時のイベントハンドリングのメソッド
・nugetから落とすパッケージ
・参照に入れるもの（参照を追加で検索＞Extentionでヒットするやつを一つ追加）

ちなみにアプリのバージョンは8.1
arch.lifecycle extentionsとかはlatestじゃなくて1.1.1（これは前の記事参照

このProcessLifeCycleObserverを使うサンプルはJavaのやつとかはインターネットにたくさん落ちてるがC#のやつはまじで落ちてない。
のでここに書いておく

###追記
ProcessLifecycleObserver.Get()..
のくだりはクリーンと言うかプロジェクトを別のPCに移してvs立ち上げ直したらエラーが取れた
特任准教授でもわかる！SSL/TLSでは安全なサイトかどうか判別できない理由


![SSLTLSのおはなし2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59084/57338973-6f94-1997-7b02-93dc0ba42b31.png)

（このがぞうはじゆうにつかっていいよ！おともだちにせつめいしてあげてね！）
【Docker-compose】MySQLの環境構築

# なぜDocker-composeなのか?
他のコンテナと合わせて使用することを考えdocker-composeにしました。

# 構成

```
├── docker-compose.yml
├──.env
└── mysql
    └── initdb
        ├── 1_create_tables.sql
        └── 2_insert_seed.sql
```

## docker-compose.yml

今回はブラウザからもアクセスできるようにしてMySQLをGUIでも操作できるようにしました。

```docker-compose.yml
version: '3'

services:
  mysql:
    image: mysql:8.0
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    env_file: .env
    environment:
      TZ: "Asia/Tokyo"
      
    ports:
      - 3306:3306
    volumes:
      - mysql:/var/lib/mysql
      - ./mysql/initdb:/docker-entrypoint-initdb.d

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    restart: always
    ports:
      - 8080:80
    environment:
      PMA_ARBITRARY: 1
    env_file: .env
    depends_on:
      - mysql

volumes:
  mysql:

```

## .env
docker-compose.ymlファイルに書くこともできますが分けた方がいいと思います！

```.env
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: test_db
MYSQL_USER: test
MYSQL_PASSWORD: test

PMA_HOST: mysql
PMA_USER: root
PMA_PASSWORD: root
```

## 初期化用sqlファイル
以下のファイルはあくまで一例です。
自由に書き換えて使用してください。
### 1_create_tables.sql

```1_create_tables.sql
create table users
(
    id serial primary key,
    username varchar(50) unique not null,
    password varchar(50) not null,
    email varchar(255) unique not null
);
```

### 2_insert_seed.sql

```2_insert_seed.sql
insert into users (username, password, email) values ('keid', 'keidpass', 'keid@developer.com');
insert into users (username, password, email) values ('jobs', 'jobspass', 'jobs@developer.com');
insert into users (username, password, email) values ('mask', 'maskpass', 'mask@developer.com');
```

## 起動
docker-compose.ymlファイルのあるディレクトリに移動してください

```
docker-compose up -d
```

### コンテナに入ってMySQLを起動

```
docker-compose exec mysql bin/bash

root@30bffee726ff:/# mysql -u test -p
Enter password: test # 入力しても表示されません
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.18 MySQL Community Server - GPL

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```
### phpMyAdminからアクセス
ブラウザなどから`localhost:8080`でphpMyAdminにアクセスできます。


# まとめ

今回はDockerをやって欲しいというリクエストがありましたのでdocker-composeを使用してMySQL環境を構築してみました。
一人でも多くのクジラ信者が増えるようにdockerの良さが伝わればいいなと思います！！
OSのいろいろ

未来電子テクノロジーでインターンをしているtokky08です。
OS/Linuxについて勉強したのでアウトプットとして書いていきます。

プログラミング初心者であるため、内容に誤りがあるかもしれません。
もし、誤りがあれば修正するのでどんどん指摘してください。

#OSって何？
OSとは、「オペレーティングシステム」の略のことです。パソコン全てのハードとソフトをユーザーが利用しやすいように管理・制御してくれます。もし端末にOSがなければ、タスクの管理/ファイルの管理/周辺機器の管理/などなどができなくなります。

##タスクの管理って何？
端末が行う仕事の管理のことです。複数のウィンドウを開いたり、調べながらWordを使ったりができるのはOSのおかげです。

##ファイルの管理って何？
MacだとFinderのようにファイルは階層構造になっていたり、ファイルの名前を変えたり、内容を保存・書き換えたりと言ったことをOSが管理しています。

##周辺機器の管理って何？
キーボード、マウス、ディスプレイ、外付けハードディスクなどの動作をOSが管理しています。

#Mac
Appleが販売しているコンピュータのMacだけでしか利用できないOSです。

##メリット
- UIが整っていてシンプルで使いやすい印象。
- プログラミング環境が整っている。
- アプリのクオリティが高い。

##デメリット
- 導入コストが高い。

#Windows
Windowsは世界で一番利用されているOSです。日本のほとんどの企業で導入されているPCは、ほぼWindowsです。

##メリット
- カスタマイズ性が高い
- Macよりも安い

##デメリット
- ウィルスの標的になりやすい
- UIが分かりにくい

#Linux
無料かつオープンソースなOSである。

##メリット
- 動作が軽い
- シェル・ターミナルが便利

##デメリット
- 敷居が高い
- 学習難易度が高い


#まとめ
簡潔にまとめましたが、OSにも種類があってそれぞれの利便性があることが分かりました。僕はMacユーザーなので言うまでもなくMacが好きですね。しかし、就職するとなったらWindowsも使う必要性が出てくると思うので慣れておく必要もあるかなと思いました。Linuxに関してはMacがあるからいいやと思っていましたが無料なのでトライしてみたいですね。（腰が重いですが）
Ruby勉強日誌3

クラス

```class.rb
   class ◯◯◯◯◯
     attr_accessor :□□□, :△△△
   end
```

インスタンス

```instance.rb
   変数 =　クラス名.new
   変数.属性 = ✖️✖︎
   puts 変数.属性
```
インスタンス変数：名前が＠で始まる変数

initializeメソッド：インスタンス作成時の初期値を設定

```initialize.rb
   class BillRecord 
   attr_accessor :name, :bill
   def initialize(name, bill)
     @name = name
     @bill = bill
    end
   end
   data = BillRecord.new("◯◯","✖︎✖︎")
```
rails newする時にActive Jobをスキップできない理由

# rails newのスキップオプション

railsアプリを新規で作成する時に実行する`rails new`ですが、不要な初期設定がある場合は`rails new --skip-active-storage`の様にスキップする事ができます。

skipで指定できるオプションは以下のファイルで確認できます。
https://github.com/rails/rails/blob/master/railties/lib/rails/generators/app_base.rb#L33-L85

## --skip-active-jobが見当たらない

ですが、`--skip-active-job`の指定ができないので、調べてみました。

githubで調べた所、以下のPRを発見
https://github.com/rails/rails/pull/16584
内容を見てみると、

> Active Job is like Active Model. It defines an API that can be used for other components of Rails. If you choose to not use a queue implementation Active Job will use its inline queue which will behaves in the same way of you not using it.

> Keeping Active Job always available will make possible to engines to rely on it without having to add it as explicit dependency or check if it is available.

Active JobはActive Modelの様に、他のコンポーネントから使用されるAPIを含んでいます。
Active Jobを常に使用可能にしておく事で、エンジンは明示的な依存関係として追加したり、使用可能かどうかを確認したりすることなく、エンジンに依存することができます。
その為、Active Jobのスキップオプションは追加しません。

らしいので、Active Jobはスキップできない様にしたみたいです。
SSDT for Visual Studio 2017 へのプロジェクトのアップグレード時の文字化けの解消法

Reporting Service のプロジェクトをSSDT for Visual Studio 2017 へのプロジェクトのアップグレード時の不具合が起きたので、その解消法についてメモしておきます。

※本記事で使用しているSSDTのバージョンは「SQL Server Data Tools for Visual Studio 2017 15.9.7」です。

過去のReporting Service のプロジェクトを SSDT for Visual Studio 2017で開くと、アップグレードする旨のメッセージダイアログが表示される。

更新前のバージョン：SQL Server Data Tools for Visual Studio 2013
更新後のバージョン：SQL Server Data Tools for Visual Studio 2017

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130481/97e8ff0a-e6d3-8ce3-0c4d-08c86d1ce319.png)

「はい」を選択してプロジェクトを起動すると正常に表示される。

しかし、いったんソリューションを閉じて、もう一度起動するとファイル名に日本語を含む場合、文字化けしてしまう。

この問題を解決するには、ソリューションのフォルダの中にあるプロジェクトファイル「XXXX.rptproj」ファイルのエンコードをUTF-8に変更すると解決する。


「XXXX（プロジェクト名）.rptproj」ファイルをメモ帳で開き、エンコード付きでUTF-8保存し直すと解決する。

その際、rptprojファイルを保存する時に、1行目のencodingを変更する。

```
   <?xml version="1.0" encoding="shift-jis?>
```

を

```
   <?xml version="1.0" encoding="UTF-8?>
```
に変更する。
【サルが書く】Laravelのpassportでの認証するテーブルをカスタマイズ方法

わきゃ〜〜

LaravelのPassportを使い、OAuth2.0のユーザー認証を行いました。
そこで、標準のemail,passwordのみの認証ではない認証方法を取りたかったので、ちょっと調べてみました。

実行環境
Laravel 5.5
Laravel Passport 4.0
PHP　7.x

Laravel Passportは導入した状態でのお話になります。


## 認証するカラムを変更したい
といっても、かなり簡単にカスタマイズは簡単です。
認証するテーブルのModelに下記のコードを追加するだけです。

**usernameを認証するカラムを変更する場合**

```Model/User.php
public function findForPassport($username)
{
    // 認証カラム名が name の場合
    return $this->where('name', $username)->first();
}
```

これは実際に認証を行っている、Laravel Passportの `Laravel/Passport/Bridge/UserRepository.php ` にある  `getUserEntityByUserCredentials() ` というメソッドがあります。
そのメソッドにModelがfindForPassportというメソッドを持っていれば、メソッドを上書きするような処理があるためです。

##  認証する条件を変更する
whereをつなげて認証する条件を追加することもできます。
whereで表現できるものであれば、カスタマイズ可能だと思います。

```Model/User.php
public function findForPassport($username)
{
    // nameとrole_idの2つの条件で認証を行う
    return $this->where('name', $username)->where('role_id', $role_id)->first();
}
```

## 参考文献
http://hakaikosen.hateblo.jp/entry/2017/11/11/084621
1文字が2文字になる？toCharArrayメソッドの罠

# はじめに


以下は、@tak777 さんの[【Java】文字列を一文字ずつ切り出しする方法](https://qiita.com/tak777/items/a065a2ed8fef3f95974c)という記事に書かれた、@saka1029 さんの以下のコメントです。

> Javaのchar型は16ビットですが、Unicodeの文字集合の符号空間は0x0から0x10FFFFで16ビットを超えます。
> Javaは内部コードとしてUTF-16という符号化方式を採用していて、16ビットを超える文字はchar2個で1文字を表現します。
> 例えば「𩸽(ほっけ)」のUnicode番号は0x29E3Dであり、Javaでは0xD867と0xDE3Dの連続した2個のcharから構成されます。
> 記事にあるコードでは1文字の半分を切り出してしまう可能性があることに注意する必要があります。

このコメントを読んで、[サロゲートペア](https://ja.wikipedia.org/wiki/Unicode#%E3%82%B5%E3%83%AD%E3%82%B2%E3%83%BC%E3%83%88%E3%83%9A%E3%82%A2)を用いて表された文字だとtoCharArrayメソッドがどのような結果になるのかが気になったので、実際に検証してみました。


# テスト

## テストコード

* [【Java】文字列を一文字ずつ切り出しする方法](https://qiita.com/tak777/items/a065a2ed8fef3f95974c)に私がコメントとして書いたコードをベースとして、以下のテストコードを作成しました。
* @saka1029 さんから「𩸽（ほっけ）」という字を例として挙げて頂いたので、「𩸽」を使った文言をテストに使ってみました。
 * この他に、「𠮷野家」の「𠮷」もサロゲートペアで表された文字だそうです。

```java:CharArray.java
public class CharArray {
	public static void main(String[] args) {
		String text = "𩸽の煮付け";
		char[] charAry = text.toCharArray();

		for(char ch : charAry) {
			System.out.println(ch);
		}
	}
}
```

## 実行結果

```text:標準出力
?
?
の
煮
付
け
```

**@saka1029 さんが指摘した通り、「𩸽」という文字が2文字に分かれてしまい、正しく取得できませんでした...**

# 解決策

色々と検索した結果、サロゲートペアを含む文字列を1文字ずつ切り出すには、[Stringクラス](https://docs.oracle.com/javase/jp/8/docs/api/java/lang/String.html)のcodePointAtメソッドやoffsetByCodePointsメソッドを使えば実現できることが分かりました。

* [Java とサロゲートペアについて](http://aoking.hatenablog.jp/entry/20120820/1345460364)
* [JavaでUnicodeのサロゲートペアを扱う練習](https://qiita.com/msakamoto_sf/items/bdc62f95f6d342705001)

この他に、BreakIteratorクラスを使う方法もあるそうですが、今回は割愛させて頂きます。

## 作成したコード

* `text.length()`はサロゲートペアを考慮せずに文字列の長さを求めるため、`len`には6が代入されます。
 * `𩸽`という文字が2つのcharとして判定されるため、人間が見ると5文字でも、内部的には6文字としてカウントされます。
* `text.offsetByCodePoints(i,1)`は、「`text`中の指定された位置（`i`）から、1コードポイント分だけオフセットされた位置のインデックスをを返しています。
 * `text="𩸽の煮付け"`の時、1文字目がサロゲートペアとなるため`i`の値が`0,2,3,4,5`と変化します。
 * 一方で`text="鰈の煮付け"`となる場合は、サロゲートペアが存在しないので`i`の値が`0,1,2,3,4`と変化します。
* `text.codePointAt(i)`では、指定された位置のコードポイントを取得しています。

```java:CharArray2.java
public class CharArray2 {
	public static void main(String[] args) {
		String text = "𩸽の煮付け";

		int len = text.length();

		for (int i = 0; i < len; i = text.offsetByCodePoints(i, 1)) {
			System.out.println(Character.toChars(text.codePointAt(i)));
		}
	}
}
```

## 実行結果

* サロゲートペアで表される文字についても、きちんと出力されました。

```text:標準出力
𩸽
の
煮
付
け
```

# 補足

* 以下のコードは @saka1029 さんにコメント欄で教えて頂いた方法で、上記のコードと同様にサロゲートペアを含む文字列を1文字ずつ切り出すことができます。
* Java9以降では`String#codePoints()`というメソッドが使えるため、以下のようにシンプルなコードにすることができます。
 * `String#codePoints()`を使うだけでなく、StreamAPIを利用してさらにスッキリしたコードになっています。

```java:CharArray3.java
public class CharArray3 {
    public static void main(String[] args) throws Exception {
        String text = "𩸽の煮付け";
        text.codePoints()
            .forEach(c -> System.out.println(Character.toChars(c)));
    }
}
```


# まとめ

* これまでの業務ではサロゲートペアを考慮したコーディングをする機会が無かったので、とても良い勉強になりました。
* IBMのサイトには「[サロゲートペアを考慮したコードを定型処理の標準として採用すべき](https://www.ibm.com/developerworks/jp/ysl/library/java/j-unicode_surrogate/)」という趣旨の記事もあるので、今後はこういった部分にもう少し気を付けてみようと思いました。
* サッと書いた記事なので、記事に誤りなどがあればご指摘頂けると幸いです。
rails 発展その13 画像について

railsの画像に関する内容です。

# ImageMagick

ImageMagickは、コマンドラインから簡単に画像の保存形式の変更などが行えるツールです。


ターミナル

```bash:ターミナル
$ brew install imagemagick
```
ImageMagickがインストールできたら、mini_magickをインストールします。
gemfileに追記しましょう。

```ruby:gemfile
gem 'mini_magick'
```
次にターミナルでbundle installします。

```bash:ターミナル
$ bundle install
```

# Active Storage

rails active_storage:installコマンドを実行すると
Active Storageが使用するテーブル用のマイグレーションファイルが作成されます。

```bash:ターミナル
$ rails active_storage:install
$ bundle exec rake db:migrate
```

Active Storage用の設定として

```ruby:model
   class User < ApplicationRecord
     has_one_attached :avatar
   end
```

この記述を追加することで、ユーザーのレコードと画像を紐づけることができます。ユーザーテーブルにカラムを追加する必要はありません。


# image_tag

image_tagは、htmlの<img>タグを生成するヘルパーメソッドです。

```html:sample.html.erb
  <%= image_tag "image/sample.jpg" %> 
  <!-- <img src="image/sample.jpg">  -->
```