OmniAICreator/Qiita-1.07M huggingface dataset:
コマンド(curl)でPushテストする方法（Android）

メモ書き

iOSに続き、Androidでもテストが必要になったのでメモします。
必要な方はご参考ください。

## 事前作業

- Serverkey取得

Firebaseコンソールから確認できます。
![スクリーンショット 2020-03-27 13.23.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32323/a0d2e829-e712-8f2d-577a-624b35d27eea.png)

- token取得

- 
```kotlin
FirebaseInstanceId.getInstance().instanceId
        .addOnCompleteListener(OnCompleteListener { task ->
            if (!task.isSuccessful) {
                Log.w(TAG, "getInstanceId failed", task.exception)
                return@OnCompleteListener
            }

            // Get new Instance ID token
            val token = task.result?.token

            // Log and toast
            val msg = getString(R.string.msg_token_fmt, token)
            Log.d(TAG, msg)
            Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
        })
```

## スクリプト

```shell:push_test.sh
#!/bin/bash
token='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxWmdyQhVDolOSTp_XRjmv'
server_key='AAAAjfX2vXY:APxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

read -r -d '' payload <<-'EOF'
{
     "title":"ホゲホゲ",
     "body":"hugahuga"
}
EOF

echo $payload

curl \
    --header "Authorization: key=${server_key}" \
    --header Content-Type:"application/json" \
    https://fcm.googleapis.com/fcm/send \
    -d "{
        \"to\" : \"${token}\",
        \"data\": $payload
    }"
```

## 実行
下記のスクリプト叩くだけ

```
/bin/bash push_test.sh
```


以上。
U-Boot起動時のコンソール メッセージを削減する方法

# はじめに
Linuxを利用した組込み開発において、x86アーキ以外のプロセッサを使用する場合、多くの場合ブートローダにU-Bootを利用していると思います。
開発初期は必要と感じていたメッセージも、後半になると必要がなくなってくることが多いです。また、少しでも起動速度を速くしたい場合、コンソールに出力されるメッセージを少なくすることで得られる改善は意外に馬鹿にできません。今回は、比較的手軽に行える出力メッセージ削減方法を紹介したいと思います。

# 抑止方法
U-Bootビルド時に指定するコンフィグでほぼすべての場合に適用できる方法を紹介します。
コンフィグと適用結果についてそれぞれ示していきます。

### 特に手を加えない場合の出力例
まずは何もしない場合の起動メッセージ例を示します。以下の環境で取得しました。
- ボード : i.MX6DL Sabreボード
- U-Bootバージョン : BSP U-Boot (rel_imx_4.1.15_2.0.0_ga)
- 使用コンフィグ : imx6sabresd_defconfig

```c:手を加えない場合
U-Boot 2016.03 (Mar 26 2020 - 18:18:32 +0900)

CPU:   Freescale i.MX6DL rev1.1 996 MHz (running at 792 MHz)
CPU:   Commercial temperature grade (0C to 95C) at 48C
Reset cause: POR
Board: MX6-SabreSD
I2C:   ready
DRAM:  1 GiB
PMIC:  PFUZE100 ID=0x10
MMC:   FSL_SDHC: 0, FSL_SDHC: 1, FSL_SDHC: 2
No panel detected: default to Hannstar-XGA
Display: Hannstar-XGA (1024x768)
In:    serial
Out:   serial
Err:   serial
switch to partitions #0, OK
mmc1 is current device
Net:   FEC [PRIME]
Normal Boot
Hit any key to stop autoboot:  0
``` 
特になくても困らない情報もありますね。

## CONFIG_SYS_CONSOLE_INFO_QUIET
CONFIG_SYS_CONSOLE_INFO_QUIETを有効にしてビルドするとコンソールに関する情報が出力されなくなります。

```c:CONFIG_SYS_CONSOLE_INFO_QUIETを有効にした場合
U-Boot 2016.03 (Mar 26 2020 - 20:17:30 +0900)

CPU:   Freescale i.MX6DL rev1.1 996 MHz (running at 792 MHz)
CPU:   Commercial temperature grade (0C to 95C) at 48C
Reset cause: POR
Board: MX6-SabreSD
I2C:   ready
DRAM:  1 GiB
PMIC:  PFUZE100 ID=0x10
MMC:   FSL_SDHC: 0, FSL_SDHC: 1, FSL_SDHC: 2
No panel detected: default to Hannstar-XGA
Display: Hannstar-XGA (1024x768)
switch to partitions #0, OK
mmc1 is current device
Net:   FEC [PRIME]
Normal Boot
Hit any key to stop autoboot:  0
``` 
メッセージ出力先を示す表示がなくなりました。

## CONFIG_DISPLAY_CPUINFO と CONFIG_DISPLAY_BOARDINFO
CPUに関する情報やボード情報はいらないという場合、これもコンフィグを変更することで簡単に抑止することができます。
多くの場合、共通に使用されるコンフィグ ヘッダなどですでに有効になっていることが多いので、ボード固有定義を記述するファイル内で今回はundefを追加し無効化しました。

```c:/include/configs/mx6sabresd.h
/* 以下を追加 */
#undef CONFIG_DISPLAY_CPUINFO
#undef CONFIG_DISPLAY_BOARDINFO
```
```c:CCONFIG_DISPLAY_CPUINFOとCONFIG_DISPLAY_BOARDINFOの無効をさらに追加
U-Boot 2016.03 (Mar 26 2020 - 20:41:50 +0900)

I2C:   ready
DRAM:  1 GiB
PMIC:  PFUZE100 ID=0x10
MMC:   FSL_SDHC: 0, FSL_SDHC: 1, FSL_SDHC: 2
No panel detected: default to Hannstar-XGA
Display: Hannstar-XGA (1024x768)
switch to partitions #0, OK
mmc1 is current device
Net:   FEC [PRIME]
Normal Boot
Hit any key to stop autoboot:  0
``` 
始めと比較するとかなりすっきりしました。

# まとめ
今回は簡単にできるメッセージ抑止方法を紹介しました。ほかにも削減に利用できるコンフィグはあり、これらを組み合わせて利用すると必要なメッセージ以外を抑止することができます。
（今回出力例として採取したものはもともと量が多くないものでしたが、場合によっては大幅に減ることがあります）
あと少し速くしたい！といったときには試してみてください。
G検定受けてみた

# G検定受けてみた

2020/3/14(土)にG検定を受けてみた感想とどんな勉強をしていたかを述べていきたいと思います。

## 1. 勉強法

勉強する前に公式ページやQiitaの他の方のページを見ながら決めました。
基本的に以下の2つで勉強し、この本に書いてあったものの中で興味があった本をプラスして2冊読みました。
#### 勉強用
・<a href="https://www.amazon.co.jp/%E5%BE%B9%E5%BA%95%E6%94%BB%E7%95%A5-%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0G%E6%A4%9C%E5%AE%9A-%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%A9%E3%83%AA%E3%82%B9%E3%83%88%E5%95%8F%E9%A1%8C%E9%9B%86-%E3%82%B9%E3%82%AD%E3%83%AB%E3%82%A2%E3%83%83%E3%83%97AI%E6%A0%AA%E5%BC%8F%E4%BC%9A%E7%A4%BE-%E6%98%8E%E6%9D%BE/dp/4295005665/ref=pd_bxgy_img_2/357-3599918-5531051?_encoding=UTF8&pd_rd_i=4295005665&pd_rd_r=ad4ffdaf-98a1-4b6a-8ac2-64a584056a63&pd_rd_w=tRawY&pd_rd_wg=21fvk&pf_rd_p=b9729c8d-ce20-4965-91d6-4b7b85375d7a&pf_rd_r=3DQ5YMZWXBRSFJ0V2WNV&psc=1&refRID=3DQ5YMZWXBRSFJ0V2WNV">深層学習教科書 ディープラーニング G検定(ジェネラリスト) 公式テキスト</a>
・<a href="https://www.amazon.co.jp/%E6%B7%B1%E5%B1%A4%E5%AD%A6%E7%BF%92%E6%95%99%E7%A7%91%E6%9B%B8-%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0-G%E6%A4%9C%E5%AE%9A-%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%A9%E3%83%AA%E3%82%B9%E3%83%88-%E5%85%AC%E5%BC%8F%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88/dp/4798157554/ref=asc_df_4798157554/?tag=jpgo-22&linkCode=df0&hvadid=280479698370&hvpos=&hvnetw=g&hvrand=49069852058606525&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009430&hvtargid=pla-525639118005&psc=1&th=1&psc=1">徹底攻略 ディープラーニングG検定 ジェネラリスト問題集</a>

#### 気になった本
・<a href="https://www.amazon.co.jp/%E4%BA%BA%E5%B7%A5%E7%9F%A5%E8%83%BD%E3%81%AF%E4%BA%BA%E9%96%93%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%8B-%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0%E3%81%AE%E5%85%88%E3%81%AB%E3%81%82%E3%82%8B%E3%82%82%E3%81%AE-%E8%A7%92%E5%B7%9DEPUB%E9%81%B8%E6%9B%B8-%E6%9D%BE%E5%B0%BE-%E8%B1%8A/dp/4040800206/ref=pd_bxgy_img_3/357-3599918-5531051?_encoding=UTF8&pd_rd_i=4040800206&pd_rd_r=ad4ffdaf-98a1-4b6a-8ac2-64a584056a63&pd_rd_w=tRawY&pd_rd_wg=21fvk&pf_rd_p=b9729c8d-ce20-4965-91d6-4b7b85375d7a&pf_rd_r=3DQ5YMZWXBRSFJ0V2WNV&psc=1&refRID=3DQ5YMZWXBRSFJ0V2WNV">人工知能は人間を超えるか ディープラーニングの先にあるもの</a>
・<a href="https://www.amazon.co.jp/AI-vs-%E6%95%99%E7%A7%91%E6%9B%B8%E3%81%8C%E8%AA%AD%E3%82%81%E3%81%AA%E3%81%84%E5%AD%90%E3%81%A9%E3%82%82%E3%81%9F%E3%81%A1-%E6%96%B0%E4%BA%95-%E7%B4%80%E5%AD%90/dp/4492762396/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=%E4%BA%BA%E5%B7%A5%E7%9F%A5%E8%83%BD+%E5%AD%90%E4%BE%9B&qid=1585282228&s=books&sr=1-1">AI vs. 教科書が読めない子どもたち</a>

よくある勉強法になると思いますが、一通り教本を読んで、問題集で苦手分野を洗い出し、不足している個所を勉強しなおすという感じです。
土日を中心に3か月ほど前から少しずつ進めていきました。
どこでも受験できるが、問題数がとても多いという試験が初めてだったため、<a href="http://study-ai.com/generalist/"> Study-AI</a>さんの模擬問題や問題集の過去問題を本番と同じ時間で解くことで、本番で焦ることがなくなると思います。


## 2. 感想
上述したテキストだけでは出題範囲を網羅できていなかったので、時間が取れる方は、<a href="https://www.amazon.co.jp/dp/4049110148/"> AI白書 2019</a> という本も読まれた方がよりよいと思いました。内容は他のテキストと重複することも多いかと思いますが、法律に関係する部分が他のテキストではほとんど書かれていないため、そこの知識を獲得するために必要と感じました。
また、問題数が多いだけに書いてあることをすぐに理解できるような日本語の理解力も問われていた気がします・・・

最後に、今回の合格率は67%(4200人 / 6300人)だったそうです。

今後、G検定を受験される方の参考になればと思います。
npm upTypeError [ERR_INVALID_ARG_TYPE]

# 状況
以下のようなメッセージが出たので実行してみました。

```information.sh

   │   New patch version of npm available! 6.14.1 → 6.14.4          │
   │   Changelog: https://github.com/npm/cli/releases/tag/v6.14.4   │
   │               Run npm install -g npm to update!                |   

```

```update.sh

$ Run npm install -g npm

```

updateが完了してgulpを実行しようとしたところ
変更していないタスクにて以下のエラーが発生。

```error.sh

TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type object

```

# 解決方法
邪道ではありますが
gulp-combine-media-queries/index.jsの
152行目付近の以下の部分をコメントアウトします。

```index.js

file.contents = new Buffer(cssJson);

```

自分の場合globをインストール（npm i glob）しており
gulp-combine-media-queriesがインストールされていた。
何度か踏んでいるバグだったので割とすぐ気がつけてよかった。
上記コメントアウトでタスクが実行できました。

# 原因
今回Run npm install -g npmの実行で
gulp-combine-media-queriesのjsファイルの
コメントアウトが外れる（上書きされる？）という事象に出会うことが出来ました。
たまたま原因が見つかったからよかったものの
エラーが出ていたタスクや直近でgulp-combine-media-queries関連の
変更はしていなかったのでハマってもおかしくない状況だったと思います。
このエラーはissueは立っているものの放置され
新しいものもフォークされているようです。
https://github.com/konitter/gulp-combine-media-queries/issues/19
しかしながらプラグインが依存しているという状態だと
そちらが変更されないといけない状況ですから応急処置として前述の回避策をしています。
gulpファイルの書き方で解消できるかもしれませんが
何かもっと良い解決方法をご存知の方はコメントいただけましたら嬉しいです。
ZOOMを使ってリモートワークでも、オフィスにいるような自然な会話環境を整える具体的な手順

## 目的
東京では週末3/28,29の外出自粛要請が出され、今後平日の出勤自粛要請ややロックダウンが行われる可能性も出てきました。
そこで、今のうちにより快適で自然なリモートワーク体制を整えていこうと考え、ZOOMを使って各社員を自宅から常時接続してみました。

ちなみに、後述しますが弊社は創業当時からリモートワーク自体は可能な環境を整えています。今回はより自然なオフィス環境に近づけるための取り組みです。自然なオフィス環境とは、「仕事を指定ながら自然な会話があちこちで発生していて、気が向けばそれに参加できる状態」だと考えています。

ZOOMで全員を常時接続した結果、

- 全員が1つのルームに入っていると、誰かの発言が全員にフラットに届いてノイズになる
- その結果、気を使って会話が少なくなってしまう

という課題が見つかりました。

リアルな音声には方向性が含まれているため、人間は自分に向けられた会話とそうでないものを識別できるのですが、デジタルの音声になると、同じ強弱で全員に届いてしまうんですね。

## ZOOMで自然なオフィス環境に近づける方法
調べてみるとZOOMには「ブレイクアウトルーム」という機能があり、この機能を使うと
・全員が参加する大きなルーム
・任意のテーマごとに分けられた小分けされたルーム
を各ユーザーが行き来できる事がわかりました。
この機能を使うことで、Slackの「チャンネル」に対応したルームを作成し、テーマごとに関係するユーザーだけで会話できるようになります。
ZOOMの日本語のヘルプページがわかりやすいものではなかったので、その手順を画像つきで紹介します。

### 設定の前提
- ホストもユーザーもZoomアカウントを持っていること
- アカウントは無料アカウントと有料アカウントの場合で変わらない

### アカウント設定：ホスト側
手順は簡単です。
まずは３STEPで、「ブレイクアウトルーム」という機能を有効にします。

1. Zoomウェブポータルにサインインして[設定]を選択
2. 「ミーティングにて（詳細）」メニューを選択
3. 「ブレイクアウトルームを有効にする」にチェック


### ミーティング画面で作成：ホスト側
次にミーティング画面でブレイクアウトルームを作成していきます。

1. ブレイクアウトルームが有効になると、トップアイコンに「ブレイクアウトルーム」アイコンが表示されるので、これを選択します。
2. 好き数だけブレイクアウトルームを作成し、名前を変更できます
3. 参加者を任意のブレイクアウトルームに割り振ります

### ブレイクアウトルームへの参加：参加者側

1. ブレイクアウトルームが割り当てられると、通知が届くのでクリック、もしくは管理パネルの「ブレイクアウトルーム」アイコンをクリックすると参加できます。
2. 右下の「ブレイクアウトルーム セッションから退出」からメインルームに戻ることが出来ます。

## ブレイクアウトルームを使った結果
結論から言うと、「使い勝手はイマイチだな」という印象です。
致命的な点が2つあり、

- 参加者はメインルームと決められた1つのブレイクアウトルームにしか参加できない
- 参加者が他のブレイクアウトルームに移動するには、ホストが操作する必要がある

これは当初想定していた「自然な会話があちこちで発生していて、気が向けばそれに参加できる状態」とは程遠く、難しいなという印象です。

Slackはチャンネルごとに、1クリックでグループ通話を開始できるので、グループ毎のスムーズな会議設定ならそちらの方が使いやすいなと。
自然な会話が起こっている状態を再現するのはまだ試行錯誤が必要ですが、「ブレイクアウトルーム」の使い方を探している方はぜひ参考にしてみてください。



また、リモートワークが快適になるアイデアがあれば、ぜひコメントいただければと思います！
【ツール】WinMargeでExcelなどのdiffをとる

WinMargeはテキストファイル以外でdiffを取ろうとすると以下のようになります。


![WS000051.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439247/6b2382b5-3054-4dc8-0f84-b15edf488112.jpeg)

Excelでdiffを取りたい場合は下記の手順で行います。

プラグインタブ→プラグインの設定
![WS000052.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439247/7e13bdb0-cfa4-33d1-43ad-733927270823.jpeg)

該当のファイルのプラグインを選択、プラグインの設定へ
![WS000053.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439247/036ed1ee-54f2-2cc6-ad50-1b12963e4236.jpeg)

「ワークシートを画像化して比較」は処理時間がかかるようです。
Excelの見たままの状態を比較したければチェックすればいいですが、今回は中身がただの文字列ですのでチェックをしませんでした。
![WS000054.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439247/4b6d080d-9fa3-0a73-48ec-6e9cb96e1724.jpeg)

これで設定は完了で、再び比較画面に戻ります。
「展開プラグインで開く」をクリックすると、展開プラグインの選択画面が出てきます。
![WS000055.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439247/bbac2fad-6269-eb09-9ca7-3121a8d64bcd.jpeg)

該当のプラグインを選択し、OKを押します。
![WS000056.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439247/387b2385-a1dd-b5d3-176f-d4dfa6ce6f83.jpeg)

比較結果が「テキストファイルは異なります」のものを開きます。
![WS000057.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439247/3c5e6419-13d2-2be2-53ce-22ea5ae6fe66.jpeg)

テキストデータとして比較することができます。
ありがとうございました。
![WS000058.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439247/fde65b57-ab5c-5282-ed94-2a50b8d2704b.jpeg)
【Google Apps Script】Script Editorがエラーで開けないときの対処法

さて、本日はそんな`Google Apps Script`において、`Script Editor`を開けようとするとファイルが開けないとエラーで怒られる事象が起きたのでその対処方法についてまとめます。

解決方法を先にお伝えすると、サインアウトした後に`Script Editor`を使いたいGoogleアカウントでログインし直すと開けるようになりました。（パソコンの調子悪かったら一旦再起動的なノリの対処法で治ります。そして、シンプルな結論ゆえこれ以降は読む必要ないかもです。）

さて、以下事象と解決方法についての（念の為の）説明です。
#Script Editorが何故か開けない事象
今回Google Formsで一部Scriptを書きたいところがあったので、Script Editorを開こうとしました…
<img width=100% alt="gas_script_editor_open-1024x568.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609490/df1bf3c6-c8c0-03e4-ed41-c70ab83f05f9.jpeg">
が、何故かファイルが開けないとエラーが出てきて、エラー文をみる限りだとファイルのアドレスに問題があるのかなと思い関係ありそうなところを探っていましたが、地味になかなか解消できずに若干はまってしまいました。
~~ちなみに下部のURLにアクセスすると、Google Driveに飛ばされるだけでエラーを解消するために役立つ情報は微塵もないので気をつけてください。期待感だけもたせるリンクは実際やめてほしい…~~

![gas_script_editor_error.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609490/bfaa1c46-e742-2d24-ad8d-3cedc13373f2.jpeg)

#一旦サインアウトして再度ログインで解決！！
解決策を探っているときに別のGoogleアカウント（普段、複数のGoogleアカウントを切り替えながら使っています）で`Script Editor`を開こうとすると難なく開けたので、サインアウトしてその上で今回Script Editorを使いたいアカウントにて再度ログインしてみました。
<img width=100% alt="gas_script_editor_sign_out-2-1024x544.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609490/0972e33f-eb06-8c98-995b-0d08496c6a4a.jpeg">
その上で、`Google Script`を開けると何事もなかったかのようにすんなり開けました。（エラーメッセージではファイルパスが違うかもと怒られていましたが、変なところでアカウントが競合しているのかもしれません…）
<img width=100% alt="gas_script_editor_page-1024x143.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609490/710b36a5-00fe-e47a-652f-c77a97a41d19.jpeg">
真の原因はわかりませんが、ひとまずこの方法で`Script Editor`を開けることはできるようになったので、同じ問題でハマった方がいらっしゃいましたらぜひ試してみてください。
【Unity】MonoScript is registered as both Editor and Runtime script! というエラーについて

#  はじめに

何の前触れもなく次のようなエラーが出ることがありました。

```
MonoScript is registered as both Editor and Runtime script!
```

このようなエラーが何故起こるのか、そしてどういう意味があるのかを調べてみたところ、Unity Forumで言及されていたので、その内容を和訳してメモしておきたいと考え、この記事を書きました。

# エラーの原因

- Unityの内部では、どのスクリプトがエディタスクリプトで、どのスクリプトがランタイムスクリプトであるかを記憶するキャッシュがある
- 同じスクリプトがランタイムキャッシュとエディタキャッシュの両方に存在するせいで起こるバグがある。(このバグはエディタとランタイムアセンブリ間でスクリプトを移動する際に発生する)
- そのバグが起こるのはどのようなケースかを調べるためにこのエラーが存在する


# 解決法

エディタを再起動する。(エディタを再起動するとキャッシュが再構築されるため)

# 参考
- https://forum.unity.com/threads/improve-monoscript-is-registered-as-both-editor-and-runtime-script-error-message.763931/
Jestの比較メソッドについて

リファクタリングを行ってる時にJavaScriptのテストの比較周りの知識が曖昧だったのでまとめます。

## 調べるきっかけとなったコード

``` is.test.ts
it("Jest's test", () => {
    ....
    assert.deepStrictEqual(value, [{ id: 1, name: "aaaaa" }]);
});
```

JestでAssertionがエラーとなった。

``` is.test.ts
assert.deepStrictEqual(received, expected)

Expected value to deeply and strictly equal to:
  [{"id": 1, "name": "aaaaa"}]
Received:
  [{"id": 1, "name": "aaaaa"}]

Difference:

Compared values have no visual difference.
```

`assert.deepStrictEqual`は値の完全一致と思い込んでいたので、なんで失敗するのだろう？と少しはまりました。

## Jestの比較

Jestにも同様の関数が存在するので試した結果が以下。

``` is.test.ts
class LaCroix {
    public flavor: any;
    constructor(flavor: any) {
        this.flavor = flavor;
    }
}
it("同一の確認", () => {
    // "レモン" === "レモン" -> 成功
    expect("レモン").toBe("レモン");

    // true === 1 -> 失敗
    expect(true).toBe(1);

    // 1 == true -> 成功
    expect(1).toBeTruthy();

    // LaCroix {
    //     "flavor": "レモン",
    // }
    // Object {
    //     "flavor": "レモン",
    // }
    // 値が同じなので成功
    expect(new LaCroix("レモン")).toEqual({flavor: "レモン"});

    // LaCroix {
    //     "flavor": 1,
    // }
    // Object {
    //     "flavor": "1",
    // }
    // 値が違うので失敗
    expect(new LaCroix(1)).toEqual({flavor: '1'});

    // LaCroix {
    //     "flavor": "レモン",
    // }
    // Object {
    //     "flavor": "レモン",
    // }
    // 値は同じだがオブジェクトの型が違うので失敗
    expect(new LaCroix("レモン")).toStrictEqual({flavor: "レモン"});

    // LaCroix {
    //     "flavor": "レモン",
    // }
    // LaCroix {
    //     "flavor": "レモン",
    // }
    // 値もオブジェクトの型も同じなので成功
    expect(new LaCroix("レモン")).toStrictEqual(new LaCroix("レモン"));

    // LaCroix {
    //     "flavor": "レモン",
    // }
    // Object {
    //     "flavor": "レモン",
    // }
    // 値は同じだがオブジェクトの型が違うので失敗
    assert.deepStrictEqual(new LaCroix("レモン"), {flavor: "レモン"});

    // LaCroix {
    //     "flavor": 1,
    // }
    // LaCroix {
    //     "flavor": "1",
    // }
    // 値もオブジェクトの型も同じなので成功
    assert.deepStrictEqual(new LaCroix("レモン"), new LaCroix("レモン"));
});
```

名前的に`=== （厳格な等価性比較）`と`toStrictEqual`が同じものと思っており、プリミティブ値に使ってたことがあります。
`toBeTruthy`より`toBe(true)`のほうが厳密なテストですね。

## まとめ

プリミティブ値の比較を行う場合は `toBe` を使う。
オブジェクトの値の比較を行う場合は `toEqual` を使う。
オブジェクトの値、型の比較を行う場合は `toStrictEqual` を使う。（`assert.deepStrictEqual`でも可）


## 参考

[等価性の比較と同一性 - JavaScript \| MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Equality_comparisons_and_sameness)

[Object.is() - JavaScript \| MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/is)

[Expect · Jest](https://jestjs.io/docs/ja/expect#tobevalue)
GAとGTMを駆使してＡ/Ｂテストする方法

# こんな方向け
- 検証期間を同じにして、Ａ/Ｂテストを行いたい
- 対象となるGoogleアナリティクスのビューでUser ID を有効にしているため、Google オプティマイズが使えない

# やれること
- ボタンのＡ/Ｂテスト
- ファーストビューのＡ/Ｂテスト

など

# 前提条件
- Googleアナリティクスが導入済みであること
- GTMが導入済みであること

# やりかた
手順は４つです。
1. Ａ/Ｂテストしたい部分のＨＴＭＬを、テストパターンの個数ぶん書く
2. ランダムで出しわける部分、ＨＴＭＬを書き替える部分をjQueryで書く
3. 書いたjQueryをGTMに登録する
4. ＧＴＭでGoogleアナリティクスにイベントを送信する

### ここでは、ボタンのＡ/Ｂテストを想定して、例を紹介します
以降は、下記ボタンがページにある想定で説明を進めます。

```html
<div id="abcd-button">
	<a target="_blank" href="ページＵＲＬ">
		<img src="ボタン画像パス.png">
	</a>
</div>
```

## １．Ａ/Ｂテストしたい部分のＨＴＭＬを、テストパターン数分だけ書く

下記２つを書き分けたＨＴＭＬを用意してください

- idの値
- ボタン画像

### テストパターンＡのＨＴＭＬ

```html
<div>
	<a target="_blank" href="ページＵＲＬ" id="abcd-button-abtest-a" class="abcd-button-abtest">
		<img src="Ａパターンのボタン画像パス.png">
	</a>
</div>
```

### テストパターンＢのＨＴＭＬ

```html
<div>
	<a target="_blank" href="ページＵＲＬ" id="abcd-button-abtest-b" class="abcd-button-abtest">
		<img src="Ｂパターンのボタン画像パス.png">
	</a>
</div>
```

## ２．ランダムで出しわける部分、ＨＴＭＬを書き替える部分をjQueryで書く

```html
<script>
	$(function() {
		//手順１で作成したテストパターンのＨＴＭＬを変数に代入します
		var htmlA = '';
		var htmlB = '';
		//テストパターンのＨＴＭＬを代入した変数を配列にします
		var testList = [htmlA,htmlB]
		//テストパターンの中からランダムで１つ選びます
		var quantity = testList.length;
		while (quantity) {
				var j = Math.floor( Math.random() * quantity );
				var t = testList[--quantity];
				testList[quantity] = testList[j];
				testList[j] = t;
			}
		//spliceの値は右の値をパターン数から１個引いた値を入れてください
		//今回は２パターンのテストなので、2-1=1となり、１になります
		testList.splice(1,1);
		var abtest = testList.join('');
		//オリジナルのボタンのＩＤ名を値に入れます
		var $content = $('#abcd-button');
		//ランダムで１つ選んだものを、オリジナルと差し替えます
		$content.replaceWith(abtest);
	});
</script>

```

##３．書いたjQueryをGTMに登録する

下記手順で、ＧＴＭに新規タグを登録します。

1. タグ新規作成
2. タグタイプで「カスタムHTML」を選択
3. HTMLの入力欄に、手順２で作成したスクリプトを貼り付ける
4. トリガーを新規作成
5. トリガータイプで「ページビュー」を選択
6. トリガーの発生場所で「一部のページビュー」を選択
7. 「Page URL」「等しい」を選択し、値はボタンがあるページのＵＲＬを入力
8. トリガーを保存する
9. タグを保存する

##４．ＧＴＭでGoogleアナリティクスにイベントを送信する
下記手順で、ＧＴＭに新規タグを登録します。
テストの個数分タグを作成します。

1. タグ新規作成
2. タグタイプで「Google アナリティクス: ユニバーサル アナリティクス」を選択
3. トラッキング タイプで「イベント」を選択
4. カテゴリ、アクションを任意で入力
5. ラベルに「abcd-button-abtest-a」と入力
6. 詳細設定＞タグの順位付け＞●●が発効する前にタグを配信にチェックを入れる
7. 手順３で作成したタグを選択
8. トリガーを新規作成
9. トリガータイプでクリック＞「リンクのみ」を選択（「すべての要素」でも良い）
10. 「Click ID」「等しい」を選択し、値は手順１でリンク要素に記述したクラス名を入力（例ではabcd-button-abtest-a）
11. トリガーを保存する
12. タグを保存する

以上で設定終了です。
Googleアナリティクス＞行動＞イベント　からクリック数を見て、Ａ/Ｂどちらが良かったか、比較することができます。
WSLにてWindowsのパスで移動する

WSL1にてWindowsのパスで移動したかったので探しました。

`wslpath 'パス'`でWindowsのパスをWSLのパスに変換してくれるみたいなので、

```sh
cd `wslpath 'パス'`
```
```sh
# 例
cd `wslpath 'D:\xampp\htdocs'`
```
で移動できます。

シェルスクリプトを作ろうとしたのですが、今WSL側の[バグ](https://github.com/microsoft/WSL/issues/4100)で面倒臭そうなのでやめておきます。

WSL 2楽しみですね。
【jQuery】id値やクラス名が指定してある要素の中にある、特定のタグ要素を取り出す方法

#この記事では、要素の中にあるタグ要素を取り出す方法を解説してます

この記事は、下記サンプルのアンカーテキストの文字列を取り出したい場合の解説です。

```html
<div id="sannple-id">
	<a>アンカーテキスト</a>
</div>
````

```html
<div class="sannple-class">
	<a>アンカーテキスト</a>
</div>
````


#まずは、id値やクラス名で特定の要素を取り出すとき
変数に代入する場合で例示します。

```javascript
var $content = $('#sannple-id');
```

```javascript
var $content = $('.sannple-class');
```

#子要素を取り出す時

```javascript
var $content = $('a[id="sannple-id"]');
```

```javascript
var $content = $('a[class="sannple-class"]');
```
「テスターちゃん」で学ぶソフトウェアテスト②

#1. 「テスターちゃん」について
初心者(新人)向けに描かれたソフトウェアテストの漫画になります
たまたまJSTQBについて調べていた時に見付けたブログの記事がきっかけで読むようになりました
[JSTQBを取るメリット5選](http://testerchan.hatenadiary.com/entry/2018/02/15/001117)

今でも更新がある度にチェックしたり、書籍版を読み返したりしたり、とテスト関連の資料として活用しています

[Blog](http://testerchan.hatenadiary.com/)
[書籍版](https://books.rakuten.co.jp/rb/16202142/)

#2. LOG
[「テスターちゃん」で学ぶソフトウェアテスト①](https://qiita.com/156Musik/items/46111ec9cfae5f9aa88d)
「テスターちゃん」で学ぶソフトウェアテスト② :point_left_tone1:イマココ
[「テスターちゃん」で学ぶソフトウェアテスト③](https://qiita.com/156Musik/items/1a9450a15aa3607fe2d5)
[「テスターちゃん」で学ぶソフトウェアテスト④](https://qiita.com/156Musik/items/77d4471ae21aac937f78)
[「テスターちゃん」で学ぶソフトウェアテスト⑤](https://qiita.com/156Musik/items/b89e104010dfcced3fd0)
[「テスターちゃん」で学ぶソフトウェアテスト⑥](https://qiita.com/156Musik/items/ebb1d2339c3a256f8ec9)
[「テスターちゃん」で学ぶソフトウェアテスト⑦](https://qiita.com/156Musik/items/94a036beb46c2dc68a86)
[「テスターちゃん」で学ぶソフトウェアテスト⑧](https://qiita.com/156Musik/items/fb1aa75351660c1150f8)

#3. 最初に
最初の記事を書いた時は書籍版の「テスターちゃん Vol.1」が発売される直前だったため同人誌版を参考にした旨を書きましたが、現在は書籍版がリリースされています
そのため、今後は同人誌版のみならず書籍版も使用して記事を書いていこうと思っています

#4. テスト実行について
##4.1 テストについて
テストケースとは**テストする項目**のこと
基本的に
>・仕様の確認
・異常系の確認

が書いてある

Excelやスプレッドシートを使う現場が多いが、テスト管理ツールを使うところもある

<font color="red">テストの基本＝テストの実行</font>

##4.2 テストケースの中身
>・前提条件
・入力値(因子)
・Steps(手順)
・期待結果(期待値)
※但し現場によって書き方がさまざまなので、基本的に現場に沿う形で

同じ機能でも対象画面が異なったりする場合もあるので、前提条件に気を付ける

**期待値通りだからPass**
これも現場ごとによって違う
自分の場合は
>・OK
・NG
・BL
・N/A

など

テストケースの時も<font color="red">報連相</font>はしっかりと！
自分の担当範囲が終わったら報告する⇒次の仕事があったりする


<font color="red">多分これのことだろう</font>が一番やっちゃダメ！！

<details><summary>本音</summary>（´-`）.｡oO（とは言え、個人的には設計者の書き方が伝わり難いというのが原因な気もする…
なので、判断に迷うテストケースの設計は完全にOUTだと思う
※投稿者は早く設計者以上のスキルを身に付けたいので心したい所存である</details>

そのため、テストケースは<font color="red">第三者が再現出来る、客観的に判断出来る</font>ように書くのがBEST！！
⇒実行者によって結果が変わっちゃうのが一番の問題
新人でもプロやベテランでも同じバグが出せるような差が出ないはっきりしたケースが良い
φ(.. )ﾒﾓﾒﾓ
絶対忘れないでおこう

#5. バグ票の書き方
##5.1 バグ票って何？
※現場によって言い方は異なる
今の現場では“チケット”と言うのがメジャー
どんなバグがあったか関係者に伝えるもの
⇒バグの修正までの流れも記録される

##5.2 バグ票の鉄則
>- バグの情報が相手に明確に伝わるように
- 関係者が再現出来るように

具体的に書くこと

###バグの内容が明確に相手に伝わるように書く
- 要約は**どこで どうしたら こうなった**と書くのが基本
〔EX〕
〇〇画面で「保存」を押すとエラーが表示される

- 本文で必要な要素は
    >- 環境
    >- 再現手順
    >- 現状(実際の結果)
    >- 期待結果

①環境
バグが出た時の環境のこと
テストしているブラウザ・スマホの情報など
　⇒他の人も同じ状態で作業や確認をしているとは限らない:point_up_tone1:
　　環境を抜かすと「再現するしない」のやり取りが増えてしまう

②再現手順
他の人も再現出来るように手順を書く
基本は<font color="red">1ステップ1行動</font>
　⇒行動を詰め込むと勘違いの元になる

慣れた人ほど雑になり易い場所なので、書き終わった後、**誰でも再現出来るか**を考えて見直してみること

③現状(実際の結果)
どんなバグが発生しているか
調べてわかったことも書いておくと、開発の人の調査の手助けになる
　⇒ただし、自分の推測を書くことは×
　　起きている事実を書く

④期待結果
どう動作して欲しいか

<font color="blue">情報を分けて相手に伝わるように書くことが大切</font>

- その他

・バグの優先度の設定
　優先度はプロジェクトによって決まっているから確認しておく

・画面キャプチャを使おう
　画像や動画があると、それを見るだけで伝わり易い
　※会社で使っていいツールが決まっている場合もあるので、要確認
【Java】compareToが不要な範囲チェック

# 範囲チェックの実装、どうしてる？
数値やら文字の範囲チェックって、`obj.compareTo(value)`の組み合わせで書いてあることが多いですよね。
ですがそのcompareToの戻り値のパターンがどうしても覚えられないんです…
覚えてるのは、一致が「0」ということだけ。`> 0`と`< 0`のどっちが小さい/大きいなのか、毎回実行して確認しています…
でも、compareToメソッドや等号・不等号演算子による「最小値以上かつ最大値以下」の範囲チェックを書かなくて済む方法があったんです。

# やはりApacheCommonsはぐう優秀
`org.apache.commons.lang3.Range`クラス(結構昔からあるのに無知でした)がポンコツSEの救世主でした…これは推せる。
「java 範囲 チェック」でググると、等号・不等号演算子やcompareToによる実装が検索結果の上位にいるので、「commons」とかキーワードをちょっと工夫しないとなかなか辿り着けないんですよね、Rangeクラスには。

## サンプルコード
```java
int num0 = 0;
int num1 = 1;
int num2 = 2;

// 範囲オブジェクトを作成
Range rng = Range.between(num0, num2);

System.out.println("範囲内チェック(" + num1 + ") = " + rng.contains(num1));
System.out.println("範囲内チェック(" + -1 + ") = " + rng.contains(-1));

// Rangeなら範囲チェックだけじゃなくて、いろいろできます
System.out.println("範囲の最小値 = " + rng.getMinimum() + "、範囲の最大値 = " + rng.getMaximum());
System.out.println("範囲が引数より後かチェック(" + -1 + ") = " + rng.isAfter(-1));
System.out.println("範囲が引数より後かチェック(" + num0 + ") = " + rng.isAfter(num0));

// 変数に格納しなくてもメソッドチェーンでも可
System.out.println("範囲内チェック(" + num1 + ") = " + Range.between(num0, num2).contains(num1));
```
## 実行結果
```
範囲内チェック(1) = true
範囲内チェック(-1) = false
範囲の最小値 = 0、範囲の最大値 = 2
範囲が引数より後かチェック(-1) = true
範囲が引数より後かチェック(0) = false
範囲内チェック(1) = true
```
上記サンプルの他、`isBefore`やcompareTo的な戻り値を返す`elementCompareTo`等いろんなメソッドが実装されています。
ちなみにbetweenの最小と最大の値の型が不一致の場合はコンパイルエラー、片方でもnullの場合はIllegalArgumentExceptionが発生します。
また、betweenに渡す最小値と最大値の順番は関係なく、`between(最大値, 最小値)`でも、正しく範囲は設定されます。(`getMaximum`や`getMinimum`の値は崩れない)
範囲とした型とcontainsの引数の型が合わない場合は、ClassCastExceptionが発生します。

## ジェネリクスの恩恵
RangeクラスはcompareToからの脱却というだけで最高なんですけど、素晴らしいのはそれだけじゃないんです。
上記の例はプリミティブのint型(Integerへの変換不要)でしたが、例えば文字列型だって日付や時刻型だって渡せちゃう！Rangeまじ愛してる。

```java
// 日付型(LocalDate)のサンプル
LocalDate ld0 = LocalDate.now().minusDays(1);
LocalDate ld1 = LocalDate.now();
LocalDate ld2 = LocalDate.now().plusDays(1);

Range rng = Range.between(ld0, ld2);
System.out.println(rng.contains(ld0)); // true
System.out.println(rng.contains(ld1)); // true
System.out.println(rng.contains(ld2)); // true
System.out.println(rng.contains(ld2.plusDays(1))); // false
System.out.println(rng.isAfter(ld0.minusDays(1))); // true
System.out.println(rng.contains(null)); // false
```
もっと早く知りたかった…最の高じゃん…

betweenには、Comparatorクラスのオブジェクトを渡すこともできるので、自作オブジェクトの比較も可能です。
もうほんと最高of最高。ポンコツ具合がちょっと改善される気がします。

compareToの戻り値が覚えられないポンコツSEはそんなに多いわけではないと思うのですが、Rangeクラスを使うほうが見た目もすっきりわかりやすいと思います。`contains`使うと論理演算子も不要ですし。
なので、これからの範囲チェックの実装にはぜひRangeクラスを使っていただきたいなと思うのです。
HHKBの設定


## はじめに

自分の環境の備忘録

## 概要

+ HHKモードを用いて、左◇を無変換、右◇を変換にしている。HHKモードの情報がないなぁ。
+ AHKを用いて、無変換をメインとしてショートカットを設定。
+ AHKでLAltをLWinに変更

## 今、欲しいキーボード

+ USキーボードに変換キーと無変換キーとwindows キーがついて、スペースキーがVBNの長さしかないキーボードが欲しい。
+ Windows 10で仮想デスクトプを使用しているため、windows キーも欲しい。

## 設定内容

### [HHKB](https://www.pfu.fujitsu.com/direct/hhkb/) Professional 2の設定

|      | SW1 | SW2 | SW3 | SW4 | SW5| SW6 |
|:----:|:---:|:---:|:---:|:---:|:---:|:---:|
| 設定 | ＿  | ＿  | ￣  |＿  |＿    |＿ |






### [ULE4JIS](https://www.vector.co.jp/soft/winnt/util/se476294.html)によるUSキーボードの認識

ノートパソコンへのUSキーボードの認識のため、ULE4JISを使用。



### [google IME](https://www.google.co.jp/ime/)のキー設定

|            |         変換         |       無変換          |
|:----------:|:--------------------:|:--------------------:|
| 直接入力    | IMEを有効化          |  -                    |
| 入力文字なし| ひらがなに表示切り替え |  IMEを無効化          |
| 変換前入力中| ひらがなに変換        |  全角カタカナに変換    |
| 変換中      | 最初の文節のみ確定    |  半角に変換           |

### [AutoHotKey](https://www.autohotkey.com/)の設定


```AutoHotKey


; 参考url
; https://gist.github.com/toriwasa/64fc9e1a8cce620b8ff92f0ae38075f7/revisions  



;単一キーの設定
;========vk1D(無変換)===========
;========vk1C(変換)===========

vk1D::vk1D
vk1C::vk1C
LAlt::LWin  

;複数キーの設定
;========vk1D(無変換)===========
;========vk1C(変換)==========
;

; 3段目

vk1D & a::Send,{Blind}^{a} ; ctrl + a
vk1C & a::Send,{Blind}^{a} ; ctrl + a

vk1D & s::Send,{Blind}^{s} ; ctrl + s
vk1C & s::Send,{Blind}^{s} ; ctrl + s

vk1D & d::Send,{Blind}^{d} ; ctrl + d  使わない
vk1C & d::Send,{Blind}^{d} ; ctrl + d  使わない

vk1D & f::Send,{Blind}^{f} ; ctrl + f
vk1C & f::Send,{Blind}^{f} ; ctrl + f

vk1D & h::Send,{Blind}{Left}
vk1C & h::Send,{Blind}^{Left} 

vk1D & j::Send,{Blind}{Down} 
vk1C & j::Send,{Blind}{PgDn} 

vk1D & k::Send,{Blind}{Up}
vk1C & k::Send,{Blind}{PgUp} 

vk1D & l::Send,{Blind}{Right}
vk1C & l::Send,{Blind}^{Right} 

vk1D & vkBB::^#Left    ; ";" 仮想デスクトップの切替 ←
vk1D & vkBA::^#Right   ; "'" 仮想デスクトップの切替 →



; 4段目

vk1D & z::Send,{Blind}^{z} ; ctrl + z
vk1C & z::Send,{Blind}^{z} ; ctrl + z

vk1D & x::Send,{Blind}^{x} ; ctrl + x
vk1C & x::Send,{Blind}^{x} ; ctrl + x

vk1D & c::Send,{Blind}^{c} ; ctrl + c
vk1C & c::Send,{Blind}^{c} ; ctrl + c

vk1D & v::Send,{Blind}^{v} ; ctrl + v
vk1C & v::Send,{Blind}^{v} ; ctrl + v

vk1D & b::Send,{Blind}^{b} ; ctrl + b 使わない
vk1C & b::Send,{Blind}^{b} ; ctrl + b 使わない

vk1D & n::Send,{Blind}^{n} ; ctrl + n 使わない
vk1C & n::Send,{Blind}^{n} ; ctrl + n 使わない


vk1D & m::Send,{Blind}{Enter} ; Enter

vk1D & .::AltTab      ;         alt + tab 
vk1D & ,::ShiftAltTab ; shift + alt + tab


; 5段目

vk1D & Space::Del          ; Del
vk1C & Space::BS           ; BS

vk1D & vk1C::Send,{Blind}{Enter} ; Enter 
vk1D & RAlt::Esc           ; Esc

vk1D & Enter::Send,{Blind}^{Enter} ; ctrl + Enter
vk1C & Enter::Send,{Blind}^{Enter} ; ctrl + Enter

vk1D & Up::Send,{Blind}^{Up}         ; 使わない
vk1D & Down::Send,{Blind}^{Down}     ; 使わない
vk1D & Right::Send,{Blind}^#{Right}  ; 仮想デスクトップの切替 →
vk1D & Left::Send,{Blind}^#{Left}    ; 仮想デスクトップの切替 ←

vk1D & Tab::AltTab      ;         alt + tab


```


### 参考 
+ IMEのキー設定：https://pc-plaza.com/ime-key-customize/
vim: dein.vim 導入方法 ~ 初心者 ~

# vim: dein.vim インストール方法 ~ 初心者 ~

以前まで[NeoBundle](https://github.com/Shougo/neobundle.vim) を使用していたのですが、開発中止になったそうです。
[dein.vim](https://github.com/Shougo/dein.vim) を推奨していたので、これを期に dein.vimに切り替えましょう

```
Note: Active developement on NeoBundle has stopped. The only future changes will be bug fixes.

Please see Dein.vim -- A faster, well-tested plugin manager for Vim and Neovim. It can do everything NeoBundle does, including asynchronous installs.
```


## dein.vimインストール
**install script 実行**

```:sh
mkdir -p ~/.cache/dein
curl https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh > installer.sh
# For example, we just use `~/.cache/dein` as installation directory
sh ./installer.sh ~/.cache/dein
```

**以下を$HOME/.vimrc に貼り付けてください**

```:.vimrc
"dein Scripts-----------------------------
if &compatible
  set nocompatible               " Be iMproved
endif

" Required:
set runtimepath+=~/.cache/dein/repos/github.com/Shougo/dein.vim

" Required:
if dein#load_state('~/.cache/dein')
  call dein#begin('~/.cache/dein')

  " Let dein manage dein
  " Required:
  call dein#add('~/.cache/dein/repos/github.com/Shougo/dein.vim')


  " Add or remove your plugins here like this:
  call dein#add('Shougo/neosnippet.vim')
  call dein#add('Shougo/neosnippet-snippets')
  call dein#add('Shougo/deoplete.nvim')

  " Required:
  call dein#end()
  call dein#save_state()
endif

" Required:
filetype plugin indent on
syntax enable

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

"End dein Scripts-------------------------
```

これでインストール完了になります
amazon linux2上でのPython環境構築方法

メモとして残しておく

```sh
# Amazon Linux コンパイラ周りのインストール
yum install gcc gcc-c++ make git openssl-devel bzip2-devel zlib-devel readline-devel sqlite-devel xz-devel


## pyenvのインストールとpath通す
git clone https://github.com/yyuu/pyenv.git ~/.pyenv 
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
source ~/.bash_profile

## pythonのインストール
pyenv install 3.8.1
pyenv global 3.8.1
```

Pythonのversion確認

```sh
$ python
Python 3.8.1 (default, Feb  2 2020, 08:37:37)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
```
Visual Studio Codeでリモート接続ができなくなった

Visual Studio Code 1.43.2
Remove Development 0.20.0

いつものようにvscodeを開いてリモート接続しようとしたところ
このようなメッセージが表示され接続できなくなりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35364/4270d90f-bf8b-41fe-b25a-8382d6597890.png)

「remote.SSH.useLocalServerを無効にしろ」とあるのでそのように。

ファイル > 基本設定 > 設定
「設定の検索」に *remote.SSH* と入力して *Remote.SSH: Use Local Server* を探します。チェックが入っていたら外してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35364/85ed8a28-5564-b17f-d8db-a60c0439929b.png)

接続できるようになりました。
2020年 AWS 認定 DevOps エンジニア – プロフェッショナル に効率的に合格する方法

「[AWS 認定 DevOps エンジニア – プロフェッショナル](https://aws.amazon.com/jp/certification/certified-devops-engineer-professional/)」を2020年03月に受験し、合格できましたのでまとめます。

## 試験結果
試験の結果は、800/1000点でした。</br>
合格基準は750/1000点なのでギリギリでした。</br>
</br>
![score](https://user-images.githubusercontent.com/55865542/77714617-ca152500-701c-11ea-98c7-9d96a1695e4c.jpg)

## AWS経験
実務ではほぼ触ったことはありませんが、2019年夏ごろから少しずつ学習を進めてきました。</br>
会社の部署でAWS資格取得が推奨されていたため、部署のAWSアカウントを利用してある程度自由(費用が多少かかってもよい)にAWS環境に触れられる学習環境でした。</br>
</br>
AWS環境を触って具体的に動かしてみた内容は下記のような感じです。</br>

|No.|やった内容|使った主なAWSサービス|
|----|----|----|
|1|EC2とRDSで3層Webアプリケーション構築|EC2,RDS,EIP|
|2|CodeCommitへのコード登録/管理|CodeCommit|
|3|API GatewayとLambdaでAPI作成|API Gateway,Lambda|
|4|S3で静的Webホスティング|S3|
|5|3と4でSingle Page Apllication|CloudFront,S3,API Gateway,Lambda,DynamoDB|
|6|GitHubコミットを契機としたFargate環境へのWebアプリケーション自動デプロイ|ECS Fargate,Codepipeline,CodeBuild,ECR,ELB|
|7|Elastic BeanstalkへのWebアプリケーションデプロイ|Elastic Beanstalk|

資格取得の状況は下記の通りです。</br>

|No.|資格名|取得時期|
|----|----|----|
|1|AWS 認定 ソリューションアーキテクト – アソシエイト|2019/09/17|
|2|AWS 認定 デベロッパー – アソシエイト|2020/01/30|
|3|AWS 認定 DevOps エンジニア – プロフェッショナル|2020/03/16|

実際にAWS環境でいろいろ動かしてみたことと2つのアソシエイト資格で基礎知識を得られていたことが、経験として活かせたと考えています。

## 学習リソース
- 公式E-Learning
- サンプル問題
- 模擬試験
- Udemy

### 公式E-Learning
動画で試験の概要や各分野の出題傾向と問題の問われ方を知ることができます。</br>
この試験では、**どんな分野のどんな知識が必要かといった全体感**と**長文の問題からキーワードを素早く抽出して適切な回答を選択する必要があること**がわかりました。</br>
[公式ページ](https://www.aws.training/Details/eLearning?id=40664)にある"コースの概要"は下記の通りです。</br>

- コースと試験の概要
- 分野1: SDLC の自動化
- 分野2: 設定管理と Infrastructure as Code
- 分野3: モニタリングとロギング
- 分野4: ポリシーと標準の自動化
- 分野5: インシデントとイベントレスポンス
- 分野6: 高可用性、耐障害性、災害対策

### サンプル問題
「[AWS 認定 DevOps エンジニア – プロフェッショナル](https://aws.amazon.com/jp/certification/certified-devops-engineer-professional/)」から"サンプル問題"をダウンロードできます。</br>
サンプル問題は英語ですが日本語で解説してくださっている方が居られました。([AWS 認定 DevOps エンジニア – プロフェッショナル サンプル問題の解説](https://blog.nijot.com/aws/explanation-aws-devops-sample-questions/))</br>
回答の意味と考え方を理解できるまで実施しました。</br>

### 模擬試験
前回合格した際の特典で無料で模擬試験を受験しました。</br>
結果は40％でした。。。</br>
試験時にスクリーンショットを撮っておき復習しましたが、正答や解説がないためいろいろ調べても確信を持てる回答かどうかは最後まで定かではありませんでした。</br>

### Udemy
Udemyで模擬試験を購入しました。</br>
購入したコースは「[AWS Certified DevOps Engineer Professional Practice Exams](https://www.udemy.com/course/aws-certified-devops-engineer-professional-practice-exams-amazon/)」です。</br>
私は英語がわかりませんが、google chromeの翻訳ツールを利用して理解することができました。</br>
</br>
当初は、**翻訳文がわかりにくい**ことと**知識不足で問題の内容が理解できない**ことのダブルパンチで問題を解き進めることが困難な状態でしたが、解いては解説を確認してをわからないサービスや内容を確認するといったことを繰り返していくうちにある程度解き進める状態になることができました。</br>
(本番の試験でも翻訳文のような日本語で問われるため、翻訳文の模擬試験でキーワードを素早く抽出して適切な回答を選択することを鍛えておいたことも役立ったような気がします。)

解説にはAWSの各種ドキュメントへのリンクが貼ってあるので、その内容を読んで理解を深めることができました。

## 学習方法
上述の学習リソースを以下の順序&方法で実施しました。</br>

|No.|学習リソース|方法|
|----|----|----|
|1|公式E-Learning|動画を見て、設問を解く|
|2|サンプル問題|自力で解いて、解説を確認して回答の意味と考え方を理解する|
|3|模擬試験|解いてみる(解説がないので振り返りは少なめ)|
|4|Udemy|1問毎に解く→解説の確認を繰り返す</br>(全問解けるレベルではなくとも何となく全体的に迷いなく解ける程度まで)|
</br>
【AWS EC2】Amazon Linux 2にMavenをインストールする方法

# 概要
AWS EC2(AMI: Amazon Linux 2)にMavenをインストールして`mvn`コマンドが使えるようにする

# 環境
- AWS EC2
  - OS: Amazon Linux 2
  - AMI ID: amzn2-ami-hvm-2.0.20200304.0-x86_64-gp2

# 構築手順
## 1. JDK8をインストールする
- Amazon Linux 2にはデフォルトでJavaが入っていないのでインストールする
  - Apache Maven 3.3以降はJDK 1.7以上が必要

```console
$ sudo yum install -y java-1.8.0-openjdk-devel.x86_64
$ sudo alternatives --config java
$ java -version
openjdk version "1.8.0_242"
OpenJDK Runtime Environment (build 1.8.0_242-b08)
OpenJDK 64-Bit Server VM (build 25.242-b08, mixed mode)
```

## 2. Mavenをダウンロードする
- ダウンロード先: [Downloading Apache Maven](https://maven.apache.org/download.cgi)
  - `Binary tar.gz archive`のLinkのURLをコピーして`wget`でダウンロード

```console
$ cd /usr/local/lib/
$ sudo wget http://ftp.meisei-u.ac.jp/mirror/apache/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz

Saving to: ‘apache-maven-3.6.3-bin.tar.gz’  
2020-03-27 11:23:54 (23.6 MB/s) - ‘apache-maven-3.6.3-bin.tar.gz’ saved [9506321/9506321]
```

## 3. Mavenを展開して配置する
- ダウンロードしたファイルを解凍して`/opt/`に配置
- 展開した`apache-maven-3.6.3`に`apache-maven`のシンボリックリンクを貼る

```console
$ sudo tar -xzvf apache-maven-3.6.3-bin.tar.gz
$ sudo mv apache-maven-3.6.3 /opt/
$ cd /opt/
$ sudo ln -s /opt/apache-maven-3.6.3 apache-maven
$ ls -l
lrwxrwxrwx 1 root root 23 Mar 27 11:36 apache-maven -> /opt/apache-maven-3.6.3
drwxr-xr-x 6 root root 99 Mar 27 11:28 apache-maven-3.6.3
```

## 4. MavenへのPATHを追加する
- `.bash_profile`に`MVN_HOME`を追加し、`PATH`に`MVN_HOME/bin`を追加する
- `.bash_profile`を反映する
- 全ユーザーにPATHを通したい場合は`/etc/profile`に追加する

```console
$ cd
$ vi .bash_profile
MVN_HOME=/opt/apache-maven
PATH=$MVN_HOME/bin:$PATH:$HOME/.local/bin:$HOME/bin

$ source .bash_profile

// 全ユーザーにPATHを通したい場合
$ sudo vi /etc/profile
MVN_HOME=/opt/apache-maven
PATH=$PATH:$MVN_HOME/bin

$ source /etc/profile
```

## 5.mvnコマンドが使えることを確認する

```console
$ mvn --version
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: /opt/apache-maven
Java version: 1.8.0_242, vendor: Oracle Corporation, runtime: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.242.b08-0.amzn2.0.1.x86_64/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "4.14.171-136.231.amzn2.x86_64", arch: "amd64", family: "unix"
```

# 感想
Maven homeをどこにすべきかちょっと迷った

# 参考
- [Maven on CentOS 7 チュートリアル](https://qiita.com/ryo-sato/items/1022b76ac3b345ca0800)
- [UNIX系OSのディレクトリ構造表(CentOS 7.3)](https://qiita.com/uhooi/items/c1388f8d803641bfb8f3)
【JIN × Easy Table of Contents】目次に意図せず表示される点(テン)の消し方

WordPressのテーマの中でも有名な`JIN`と、ブログ内の目次を自動生成してくれる`Easy Table of Contents`の組み合わせで使う際に、目次の見出しに・(なかてん)が入ってしまう問題の解消法についての説明です。

（後日追記）`Easy Table of Contents`の使用をやめて、現在ではテキストエディタに直入力して目次を作っています。プラグイン多すぎると管理も大変なため断捨離しました。

>以下の記事を参考にしています。
美紀ペディア: [【JIN×Easy Table of Contents】目次の小見出しに点が付いちゃう?丸を消す方法はコピペするだけ超簡単！](https://behappier-miki.com/jin-easy-toc)

#JINとEasy Table of Contentsの組み合わせで目次に意図せず表示される点(テン)の問題
下記の通り、目次の見出しの部分に予期せぬ点が出現し、見出し番号と重複してしまい。大変不格好になってしまう問題があります。「ま、とりあえずこれでいっか」というテンションでは済まされない程度には気になると思います。
![JIN_ETOC_delete_dot_top-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609490/ce17bc8d-c3d8-8232-710b-5082bd814af4.jpeg)
#目次内の点を消すCSSコードの追加
そこでWordPress管理画面のカスタマイズの追加CSSより、冒頭でご紹介した[美紀ペディアさんの記事](https://behappier-miki.com/jin-easy-toc)に記載されているCSSコードをそのままコピペします。

```css:additional.css
/* 目次:目次番号潰れ修正 */ 
.cps-post-main ul:not([class]) li:before, .cps-post-main table ul:not([class]) li:before{
    display: none;
    content: ”;
    position: absolute;
    top: 0.6em;
    left: 10px;
    width: 0;
    height: 0;
    background-color: #2b2b2b;
    border-radius: 100%;
}
```

<img width=100% alt="JIN_ETOC_delete_dot-1024x366.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609490/859e9811-5e3a-8a7b-ddeb-fa853282f7a9.jpeg">

追加CSSをそのまま貼り付けると、目次からあの点を非表示にすることができるようになりました。
#表示させておきたい番号なしリスト上の点が消える問題
上記のCSSコードを追加すると、番号なしリストにおける各項目の文頭に表示されるはずの点がそれはそれはしれっと消失してしまうという新たな課題に直面します。
<img width=100% alt="JIN_ETOC_delete_dot_list-1024x409.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609490/3da8f3ff-bcd3-0e3e-c6df-ebee0f01e627.jpeg">
#番号なしリストの点を取り戻す解決策（妥協案?）
ここからが本ブログのオリジナルとなる内容なのですが、さきほどの追加CSSで追加したコードの下に、下記のコードを更に追加します。

```css:additional.css
/*リスト(ul)表示の修正*/
ul.list{
    text-indent: -1em;
    padding-left: 2.3em;
}

ul.list li{
  padding: 0.2em 0em 0.2em 0.5em;
  margin-bottom: 5px;
}

ul.list li::before{
  display:inline-block; 
  content:'';
    width:0.4em;
  height: 0.4em;
  border-radius: 100%;
    margin-right: 12px;
}
```
CSSを追加して、少し手間ですが番号なしリストの表示に対して以下の作業を行います。
![JIN_ETOC_delete_ul_edit.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609490/223258d8-821b-b224-ab64-3c8885484a4c.jpeg)

```html:sample.html
<!-- 修正前: 冒頭が<ul>のまま -->

<ul class="list">
 	<li>りんご</li>
 	<li>ばなな</li>
 	<li>パイナップル</li>
</ul>

<!-- 以下の通りに修正してください: 冒頭の<ul>に「class="list"」を追加 -->

<ul class="list">
 	<li>りんご</li>
 	<li>ばなな</li>
 	<li>パイナップル</li>
</ul>
```
すると、番号なしリストの各アイテムの先頭に点が再び表示されるようになります。

![JIN_ETOC_desplay_dot_top.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609490/325f7d2d-a5d3-f584-a18e-cdcbb550612c.jpeg)

#この方法のメリット
このやり方だと、番号なしリストを作成するたびに、Textエディタを開いて`<ul>に”class=”list”`を追加する必要があり若干だけ手間ではあります。ですが、例えば番号なしリストの各アイテムに手打ちで「・」を追加するという作業をして、仮にもある項目の文章が長くなってしまった場合に、字下げが適切に行われず見栄えが悪くなるなどの弊害が起こりえます。

しかし、今回の方法を用いると、統一したルールで番号なしリストが表示されるため見た目がきれいになるというメリットがあります。且つ、`JIN`のデフォルト設定である番号ありリストの行間や字下げのルールに揃えているのでページ全体として統一化を出すことができるようになります。


![JIN_ETOC_delete_lists.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609490/71e84d9f-1262-fb4d-c19e-fc6a38c842af.jpeg)
[Angular]コンポーネント間でデータを受け渡す　～＠ViewChildとAfterViewInit～

# ＠ViewChildとAfterViewInitをつかってデータを渡す方法

- ＠ViewChild
- AfterViewInit

を使ってコンポーネント間でデータを渡す。  

これらを使えば子コンポーネントを参照し、親コンポーネント内の変数にアクセスできる。  

## 環境

- Angular： v9.0.4
- Node： v12.16.1
- OS： win32 x64

## 準備

以下を生成しておく

- Angular プロジェクト
- parent.component
- child.component

## app.component

app.componentに生成した親コンポーネントを追加

```html:app.component.html
<app-parent></app-parent>
```

## child.componentの実装

子コンポーネントには親に渡したいデータを用意しておく

```typescript:child.component.ts
/*
省略
*/
export class ChildComponent implements OnInit {

  childValue = 'Hello World'; // 追加

  constructor() { }

  ngOnInit(): void {
  }

}
```

childValueという変数を用意。

## parent.componentの実装

親がわでは、ViewChildとAfterViewInitと参照したい子コンポーネントをimportしておく。

```typescript:parent.component.ts
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from '../child/child.component';
```

子のデータを受け取るようの変数を用意。
ViewChildデコレータで参照する子コンポーネントを設定する。
ngAfterViewInit()で子の値を受け取る。

```typescript:parent.component.ts
// デフォルトだとimplements OnInit になっているので注意
export class ParentComponent implements AfterViewInit {

  parentValue: string;

  // 参照子コンポーネントを設定。
  @ViewChild(ChildComponent) childReference;

  constructor() { }

  ngAfterViewInit() {
    this.parentValue = this.childReference.childValue;
  }


}
```

```html:parent.component.html
<div>
  <app-child-view></app-child-view>
  <p>{{parentValue}}</p>
</div>
```

parentValueにはHelloと表示される。
終わり。

## おまけ

ngAfterViewInit()って？  
ngOnInit()って？  
という人向け

### ライフサイクル・フック

ライフサイクル・フック：コンポーネントの生成、更新、破棄などのタイミングで発生するように行動させるもの

- ngOnInit()：コンポーネント生成直後に呼び出される。OnInitインタフェースのときに存在する。
- ngAfterViewInit()：コンポーネントのビューと子のビューを初期化した後に呼び出される。ちなみにこれと併用して使えるライフサイクル・フックもある。(ngAfterViewCheckedなど)

くわしくは公式ドキュメント（<https://angular.jp/guide/lifecycle-hooks）>

## 次

知らないor使ったことないライフサイクル・フックが結構あるので実際に使ってみてからまとめてみます。
スプレッドシートにある複数シートのうち、1つのシートだけエクセルでダウンロードしたい

## はじめに
お仕事でスプレッドシートにある複数シートのうち、一つのシートだけをエクセル変換するする必要があったのでその方法メモです。

## スプレッドシートにもともと備わってるダウンロード機能
メニューの `ファイル` -> `ダウンロード` からエクセルダウンロードできる機能がありますが、これだと全部のシートが出力され、不要なシートを削除しなければならず少し面倒です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181001/69d6838d-a8c2-f568-c39d-230cac95eb7f.png)


## 特定のシートだけをエクセルダウンロード
以下の形式のURLをブラウザからたたけば特定のシートだけをエクセルダウンロードできます。

- ダウンロードURL ...
`https://docs.google.com/spreadsheets/d/{スプレッドシートID}/export?format=xlsx&gid={シートID}`

URLの **スプレッドシートID** とは開いてるスプレッドシートの①の部分、**シートID** は②の部分です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181001/a9f9eb32-092a-1d88-b127-8dcbd112c74e.png)

ちなみに、 `exprot?format=pdf` にするとpdfダウンロードもできます。

## gasでダウンロードダイアログ表示
ブラウザに入力するのは面倒なので、ダウンロード用のURLをgas側で生成し、ダイアログに表示することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181001/4a1b195e-4f95-9725-6496-9495d39a6193.png)

- gasのコード

```javascript
function myFunction() {
  // 選択中のスプレッドシート
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var spreadSheetId = ss.getId();
  var sheetId = ss.getSheetId();
  var url = 'https://docs.google.com/spreadsheets/d/' + spreadSheetId + '/export?format=xlsx&gid=' + sheetId;
  
  // ダイアログ表示
  var html = HtmlService.createHtmlOutput('<p>リンクをクリックしてダウンロードしてください。</p>')
     .append('<p style="text-align:center;"><a href="' + url +'" style="text-align: center;">Dwonload<a/></p>')
     .append('<div style="text-align:right;"><input type="button" value="Close" onclick="google.script.host.close()" /></div>')
     .setWidth(300).setHeight(200);
   SpreadsheetApp.getUi().showModalDialog(html, 'ダウンロード');
}
```

例えばダウンロードしたいスプレッドシート上に↓みたいな画像挿入して、`スクリプトを割り当て` で作ったmyFunctionを割り当てればダウンロードボタンの出来上がりです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181001/80f60c45-c2eb-15c3-5ae4-d289221bfc9f.png)

以上です :cat:
Rails5 AWS EC2とRDS、S3、paperclipを使用したデプロイ

#デプロイ覚書
基本的に下記記事を参考にさせて頂きました。
https://qiita.com/naoki_mochizuki/items/f795fe3e661a3349a7ce
https://qiita.com/Yuki_Nagaoka/items/975b7598806d6ae0c0b2

上記記事の中では説明がなく自分がハマった箇所について。
まず
・画像投稿のストレージにS3を使用していた為その設定。
・あとRDSでデータベースを作成する際の文字コードの設定。
・デプロイ終わった後に大幅な修正を見つけてしまった際のやり方

#S3使用時の設定について
https://qiita.com/nakki/items/6df87756ef4119cc3e68
コチラの記事を参考に実装しました。
デプロイ時にハマったのはunicornが起動しなかった。。。
ログを調べると
`Cannot load Rails.config.active_storage.service`
`undefined method fetch for nilclass`
コチラのエラーは同じエラー文での記事が見つけられませんでした。
デプロイの参考サイトと違う環境はS3を使っていることだし、active storageのエラーが出ていると言うことはやっぱりS3関係のエラーだろうと考えて調べる。。
ローカルではS3にちゃんと接続できて写真投稿も問題なくできていました。
ここのエラーに一日かかりました。。。
原因は、、、
 config／environments／production.rbの設定でした。
###`config.require_master_key = true`

このコードがデフォルトfalseでコメントアウトされているのですがtrueにして有効化。
これでproduction環境でS3に接続する環境変数が読み込まれるようになったようです。
確かにマスターキーがないと環境変数読み込めないですもんね。
これでunicorn問題なく起動OK。

#RDSの文字コード
デプロイ終わってよっしゃー。会員ログインして動かしてみよ！
「ログイン」！→「エラー」

え？！

log/production.logを調べるとデータベースにレコード保存しようとしたときに文字コードが合わなくて弾かれた、と言うことらしい。
と言うことで下記記事参考に対応
https://qiita.com/kijitora-neko/items/aab58b4c1f684353e075

パッチ当てて再起動したんですがデータベース削除して作り直しても文字コードが変わらない。。。
３回くらいやったらやっと反映されました。。パッチが適用されるのにタイムラグがあるのかな？
同じ問題に当たった方は焦らずに設定確認して時間を置くことも必要かと。
もちろんそもそもRDSのデータベース作成時にパッチを作成して適用しておけばこのようなエラーは出ないかと。
次からは気をつけよう。

#デプロイ後のアプリ修正
まあ、コチラはデプロイする前にちゃんとテストしとけよって話ですが。。。
デプロイしてからあれ？ここのリンク飛ばない？
あれ？問合せフォームから送信できない？
など等結構大幅に修正することがあったのでその時のやり方。

ちょっとした修正ならvimでコード修正してすぐ終わるかと思います。
でもいくつものファイルの修正や移動、削除など多くなってくるとコンソールからだと時間がかかる。。。

そこで一旦アプリ削除することにしました。
EC2インスタンスの/var/www/rails/アプリフォルダ
このアプリフォルダをコンソールで強制削除します。
nignx,unicorn,mysqlなどはこの上階層でインストールしているので影響なし。
アプリフォルダ削除後に再度git cloneして設定し直し。
と言っても作業量は大したことないです。#
その後プリコンパイル、nignx,unicorn,mysqlの再起動して終わり。

以上です。

多分CI／CDパイプラインとかそういうのはここのところを自動化してくれるんでしょうね。。
そこの勉強はこれからですがこの経験があると「何故それを使うのか？」というところが理解しやすいのかなと思います。
FilterでSpringDIしたかったらDelegatingFilterProxyで実装すべし

# やること！

1. Filterクラスの実装
1. Bean定義 or `@Component`+ コンポーネントスキャン
1. `web.xml`の実装

```java:LoggingFilter.java
public class LoggingFilter extends OncePerRequestFilter {
    // ....
}
```

Bean定義

```xml:web.xml
<filter>
    <filter-name>loggingFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>loggingFilter</filter-name>
    <url-pattern>/** </url-pattern>
</filter-mapping>
```
jestでモックしてみたメモ

レガシーコードのテストをjestに移行していた時に、
jestだとどうやってモックしたり、追跡したりするんだ？となったのでその時のメモ

# 最初に
相当アホなところでハマったのだが、jest はnamespaceをそのまま読み込むため以下のようの読み込まないといけない。

```typescript
import 'jest' // OK

import jest from "jest" // NG

jest.xxxx()
```

# 特定の関数をモックする
関数にもろもろについてモックの仕方です。

## テスト用のモック関数の作成

```typescript

const mockFunc = jest.fn().mockImplementation(() => return "mock func");
console.log(mockFunc()); // mock func
```
関数自体のモックは jest.fn()に集約されており、単純に何か値を返すのみの関数は mockImplemantionの引数で定義します。
また、mock関数の引数や、どういった値を返したかの検証も行えます。

### 関数の動作の検証
#### 引数の検証
実際にモックした関数の引数を見たい場合はこんな感じでmock.calls を使います

```typescript

const mockFunc = jest.fn().mockImplementation((message: string) => {
	return message;
});
mockFunc('test1');
mockFunc('test2');
console.log(mockFunc.mock.calls); // [ ['test1'], ['test2']] 
```

#### 戻り値の検証
戻り値の場合はmock.resultsを使います。

```typescript

const mockFunc = jest.fn().mockImplementation((message: string) => {
	return message;
});
mockFunc('test1');
mockFunc('test2');
console.log(mockFunc.mock.results);
/*
[
  {
    type: 'return',
    value: 'test1',
  },
  {
    type: 'return',
    value: 'test2',
  },
];

*/
```

value は実際に返した値で、
typeはその値が正常リターンか、エラーかを判定します。

正常の場合は `return`
エラーがスローされた場合は `throw`
となります。

また、 `imcomplete` というケースがありますが、これはよくわからないので省略します。

### 後処理
テストの後処理は２種類あり、 関数のモック自体を抹消する場合と、関数の引数などの追跡結果を抹消する場合があります。

```typescript
const mockFunc = jest.fn().mockImplementation((message: string) => {
	return message;
});

mockFunc.mockClear() // どういった引数を受取、どういった値を返したかの計測結果をリセット
mockFunc.mockReset() // 実際に実装した関数や戻り値の設定をリセット
```
## 特定のオブジェクトに生えている関数を追跡、モックする
### 追跡対象を指定

```typescript

const spy = jest.spyOn(targetObject , "do"); // オブジェクトの指定とそこから生えている関数を指定

// 関数実行処理

expect(spy).toHaveBeenCalled(); // 関数が実行されたかどうかを検証
```

### 指定した関数をモック関数にする

```typescript
const spy = jest.spyOn(targetObject , "do")
    .mockImplemention(() => "spy");

```

↑のようにすると、指定したオブジェクトの関数は、mockImplementionの中で定義した関数に差し替えられます。
なお、mockImplementionの中には先程解説した jest.fnを渡すこともでき、その場合は引数などの検証も行えると思います(未検証)

# オマケ　現在時刻のモック
特定の時刻でポイントが失効するかどうかをチェックしたい場合に現在時刻をモックする必要があったのでその時のことも書いておきます。

重要なことは、日付を扱うパッケージオブジェクト(moment, dayjsなど)はjavascriptのDateオブジェクトに依存しているため、Dateオブジェクトをモックすれば現在時刻系は騙せます。

なので、 

* jest で Dateオブジェクトをモックする
* [mockDate](https://github.com/boblauer/MockDate) を使う
* 自分でDateオブジェクトをモックする(レガシーコードはこれをやってた)

個人的に、mockDateを使うのが良いかなと思います。使いやすいしリストアなどもやりやすい他、
ドキュメントも充実しているので、情報共有もしやすいです。

# 最後に
時刻関連のモックをしらべるのに一番時間がかかりました。
Dateオブジェクトをいじればいいみたいな結果は出てくるのですが、なぜそれが必要なのかという理由が納得できず、
momentの初期化処理のコードを見に行ってDateオブジェクトに依存しているとわかりました。

それでは、良いjestライフを
Aurora MySQLでSELECT権限のみを持つユーザーを作成する

毎回調べていたのでメモ。
今回はredashからDBに接続するためのユーザーを作成した。  
  
結果的に、Auroraだから特別な設定が必要なことはなく、MySQLのドキュメントを参照しながら進めれば解決した。

# 1. マスターユーザーで接続する

ここは省略。

# 2.  ユーザー作成

```sql
CREATE USER 'redash'@'%' IDENTIFIED BY 'pass';
```

今回は1Passwordのパスワードジェネレーターで64文字のパスワードを生成し設定した。

# 3. 権限付与

```sql
GRANT SELECT ON some_database.* TO 'redash'@'%';
```

SELECTの権限のみ付与した。