OmniAICreator/Qiita-1.07M huggingface dataset:
Pythonスクレイピングによる画像ダウンロード

#0. はじめに
ホームページの模写をするのに画像をすべてダウンロードするのが面倒だ、と思ったことはないだろうか。urlと保存先のディレクトリ名を入力しただけでそのページに使われている画像をすべてダウンロードする機能を作成したから以下にまとめる。

#1. 必要なモジュール
必要なモジュールは以下の通りだ。`requests`、`bs4`はあらかじめpip等でインストールする必要がある。又、importする必要はないが`html5lib`も使用する。

```python
import os, time, requests, urllib
from bs4 import BeautifulSoup
```

```powershell:powershell
python -m pip install requests
python -m pip install bs4
python -m pip install html5lib
```

#2. urlとDL先ディレクトリ名の指定
urlとディレクトリ名は`input`で指定する。又、`savedir`には任意のパスを渡すことで好きな場所にディレクトリを作成することができる。

```python
page_url = input("urlを入力してください")
img = input("フォルダ名を入力してください")
save_dir = "./{}".format(img)
```

#3. 画像の抽出
HTMLを勉強している人は知っていると思うが、画像は`<img>`というタグでページ内に埋め込まれており、`src`でパスが指定されている。そこで、`BeautifulSoup`を用いて画像タグを抽出する。

```python
def get_img_urls(html):
    soup = BeautifulSoup(html, "html5lib")
    res = []
    for img in soup.find_all("img"):     #soup.find_all("img")でimgタグを抽出
        src = img["src"]     #画像のパスを抽出
        url = urllib.parse.urljoin(page_url, src)     #ページのurlと画像のパスで絶対urlを作成する
        print("img.src=", url)
        res.append(url)
    return res
```

#4. 画像のダウンロード
指定したディレクトリが存在しなければディレクトリを作成する。その後作成した絶対urlから画像をダウンロードする。又、1枚ダウンロードするごとに`sleep`で1秒処理を休止する。これはサーバーに高負荷を掛けないようにする処理である。

```python
def downloads(urls):
    if not os.path.exists(save_dir):
        os.mkdir(save_dir)
    for url in urls:
        fname = os.path.basename(url)
        save_picture = save_dir + "/" + fname     #画像ファイルのパスを作成
        r = requests.get(url)
        with open(save_picture, "wb") as pi:
            pi.write(r.content)
            print("save:", save_picture)
        time.sleep(1)     #1秒処理を休止
```

#5. メイン処理
画像を抽出して絶対urlを作成、そのurlを用いて実際に画像をダウンロードする関数を作成する。

```python
def download_pictures():
    html = requests.get(page_url).text
    urls = get_img_urls(html)
    downloads(urls)
```

#6. 実行
以下を追記しデバッグしてみよう。指定したパスにディレクトリが作成され画像のダウンロードが開始する。

```python
if __name__ == "__main__":
    download_pictures()
```

#7. まとめ
今回はスクレイピングによる画像ダウンロードの自動化を行った。ページによってはスクレイピングを禁止しているところもあるので利用規約には十分に注意してほしい。
システム環境変数Pathにパスを追加する

作成しているアプリケーションを別のPCに実装することになりました。その中で、システム環境変数Pathへの登録が前提となっているソフトがあるので、どうせならその設定を自動で行ってくれるアプリを作成しようと考えました。
##管理者権限の付与
システム環境変数の変更なので**管理者権限での実行**が必要となります。

1. 「ソリューションエクスプローラー」の中にあるプロジェクトのノードを右クリックする
2. 追加を選択し、その中の「新しい項目」を左クリックする
![スクリーンショット (169).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669580/2f0b074f-103e-be14-7955-9b711b95d522.png)


3. Visual C# アイテムから「アプリケーション マニフェスト ファイル」を追加する（名前はデフォルトのままでOK）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669580/73ed11d1-7108-4216-8002-f6283d41333c.png)

app.manifestは下のような構成をしています。

```app.manifest
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
        <!-- UAC マニフェスト オプション
             Windows のユーザー アカウント制御のレベルを変更するには、
             requestedExecutionLevel ノードを以下のいずれかで置換します。

        <requestedExecutionLevel  level="asInvoker" uiAccess="false" />
        <requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />
        <requestedExecutionLevel  level="highestAvailable" uiAccess="false" />

            requestedExecutionLevel 要素を指定すると、ファイルおよびレジストリの仮想化が無効にされます。
            アプリケーションが下位互換性を保つためにこの仮想化を要求する場合、この要素を
            削除します。
        -->
        <requestedExecutionLevel level="asInvoker" uiAccess="false" />
      </requestedPrivileges>
    </security>
  </trustInfo>

  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>

(以下略……)
```
このうち19行目付近にある`requestedExecutionLevel level="asInvoker"`内「asInvoker」を「requireAdministrator」に変更することでアプリケーション実行前に付与の確認を行うウィンドウを出すことができます。
このほかコードで処理ごとに付与の確認をする方法もありますが、実行時に挙動がおかしくなったのでおすすめしません。
## 環境変数Pathへの追加
さて本題。システム環境変数への追加は`Environment.SetEnvironmentVariable`を使うと楽に設定が可能です。こんな風に。

```Form1.cs
Environment.SetEnvironmentVariable("SofTalk", 
$"C:\\softalk\\", EnvironmentVariableTarget.Machine);
```

しかし、追加と言っても実際はPathといった**既に変数が存在する場合は値を上書きしてしまいます**。システム環境変数を変更前に戻すには修復ポイントからのシステム修復くらいしか方法がないため、非常に面倒。そこで変更前のPath内の値を取得し、それに追加したいパスを付け加えた値を新たに定義する必要があります。
という事で、以下がパスの追加に関するコード。`C:\\softalk\\`の部分は適宜変えてください。

2/11改訂：文字列取得した場合、複数の値の場合は「;」で区切っているため追加したいパスの前に「;」を追加した方がいいようです。コードは修正済み。

```Form1.cs
//変更前の環境変数Pathの値を全て取得
string base_paths = System.Environment.GetEnvironmentVariable("Path", 
System.EnvironmentVariableTarget.Machine);

//環境パス設定
Environment.SetEnvironmentVariable("Path", 
base_paths + ";" + "C:\\softalk\\", EnvironmentVariableTarget.Machine);
```

## 参考サイト
管理者権限の付与方法
https://www.ipentec.com/document/csharp-run-as-administrator-using-manifest-file
システム環境変数への追加方法
http://hensa40.cutegirl.jp/archives/2733
sleepという荒業

ラズパイのカメラ画像データ（定期撮影）を、自動でサーバーと同期させたくてrsyncです。
ちょっとはまって一応解決できたので共有します。
一応＝後述の通り、あまりスマートな解決策ではない気もします。

**このスクリプトを実行するとあっさり動きます**、ちょっと感動します、イケないことをしている感もあります。

```shell

#!/bin/sh
expect -c "
  spawn rsync -arv 同期元ディレクトリ 同期先ユーザー名@同期先ホスト:同期先ディレクトリ
  expect \"Password:\"
  send \"同期先ユーザーのパスワード\n\"
  interact
"
```

**しかし、Cronから実行すると沈黙します。**
ええぇぇ…そんなことあるのかしら。

http://tm.root-n.com/unix:command:expect
>interact命令は、「制御をユーザに返す」ことを指示します。
>そのため、cron の場合、制御を返されても引き継ぐユーザーがおらず、正常に動作していなかったようです。

なるほど。

```shell
#!/bin/sh
expect -c "
  spawn rsync -arv 同期元ディレクトリ 同期先ユーザー名@同期先ホスト:同期先ディレクトリ
  expect \"Password:\"
  send \"同期先ユーザーのパスワード\n\"
  expect eof
  exit
"
```

Cronから実行すると、同期先ディレクトリにテンポラリファイルが一瞬出来て、動いた気がしました。
ターミナルで実行すると、同期対象のリストまでは表示されますが、そのまま終了してしまいます。

https://stackoverflow.com/questions/18502236/rsync-giving-error-when-executing-witin-expect-script-using-cron
の通りにしたら機能しました。

```shell
#!/bin/sh
expect -c "
  spawn rsync -arv 同期元ディレクトリ 同期先ユーザー名@同期先ホスト:同期先ディレクトリ
  expect \"Password:\"
  send \"同期先ユーザーのパスワード\n\"
  expect eof
  sleep 90
  exit
"
```

**exitをsleepさせるって…荒業ですが、まあいいか。**
同期が完了しない場合は、次回の同期に先送りされるのが、ちょっと嫌な感じです。
AWS Cloud9起動時の"Your environment is... resize EBS..."

## 起動するたびに出てくる赤字通知
__原因：一時ファイル
解決策：AWSのEC2でCloud9のサーバーを再起動__

![スクリーンショット 2021-01-27 19.29.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620852/2939c96e-0aad-ef16-c68b-11c5de5384a7.png)


## AWS EC2を開く
AWSにログインして、「EC2」を探す。
<img width="300" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620852/139205c6-9c41-e7ff-f852-507ee9a721e4.png">
　
　
「インスタンス（すべての状態）」をクリック
<img width="300" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620852/1d38dbcb-d5c9-e4fd-9885-b4d7a70f1483.png">
　
　

「aws-cloud9-....」にチェックを入れる。
<img width="300" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620852/c698b96a-1958-6411-e036-3345bf9c9b75.png">
　
　

「インスタンスを再起動」を押す。
<img width="300" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620852/b986dfdf-f5eb-d6d3-0c1a-6be633b9081f.png">
　
　
これで消えているはず。
Firebase×Swiftでアプリを作ろう（環境構築編）

前回はFirebase上での設定を行いましたが今回は実際にFirebaseとSwiftを繋げてみたいと思います。環境構築ができるとあとはコードを書くだけになるのでここが踏ん張りどころですね！

firebaseとswiftを連携させる
まず下の図の画面のを開きます。
<img width="500" alt="dataFlowImage.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679508/9ca246e0-0ec5-06fe-1f5b-ed777d0b6b93.png">
中央の「iOS」のアイコンをタップします。すると下の画面が表示されます。
<img width="300"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679508/de398be1-a4d8-694a-84f1-766dda274d9a.png">
少しここからが複雑です・・・
「iOSバンドルID」を入力する必要があるのですがそれは下の図のようにXCode上での一般画面（緑色になっているファイル）のGeneral（上のメニューバー）を選択し、IdentityのBundleIdentifireの文字をコピー＆ペーストしてください！
<img width="500"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679508/650193ab-74a6-9557-8092-3eb94061af7d.png">
恐らくここで次の段階に行けると思うのであとは指示通りに進めてください！
<img width="500"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679508/6cc3c256-4204-e1c9-a0fb-eec91754ec6e.png">
こんな画面まで戻れたら環境構築終了です！お疲れ様でした！

##補足：cocoapodの設定方法
『[cocoapodsのインストールについての記事](https://qiita.com/ShinokiRyosei/items/3090290cb72434852460)』
『[cocoapodをアプリ内に入れる方法](https://qiita.com/agachan0930/items/f8e7b1f0bce8642b0eb4)』
↑一応RealmSwiftの記事ですが途中までは一緒なので参考にしてみてください！
```ターミナル.
cd 自分のインストールしたいファイルのディレクトリーを入れる！（ポイントは後ろの"/"まで切り捨てること）
pod init
open podfile
```
恐らくこのようなファイルが開いていると思います...
下のように『ここに追加してね！！』の部分に下のコードをコピペしてください！！

```podfile.
target 'PhotoLibrary' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for PhotoLibrary
ここに追加してね！！！！！！！
  ↓↓↓（これを追加）↓↓↓
　# add the Firebase pod for Google Analytics
  pod 'Firebase/Analytics'
  # add pods for any other desired Firebase products
  # https://firebase.google.com/docs/ios/setup#available-pods
  ↑↑↑（ここまで）↑↑↑
  
  target 'PhotoLibraryTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'PhotoLibraryUITests' do
    # Pods for testing
  end

end
```

またターミナルに戻って以下のコードを入力してください！！


```ターミナル.
pod install
```
これでインストールは完了しました！！
てことで今開いているファイルを全て閉じてください！！
え？なんで閉じるの？？？？と思うかもしれませんが
実は新しいファイルができているのでそのファイルを開くためです！！
これまでできていたファイルとは別に[.xcworkspace]というファイルができていると思います。
今回からこちらを立ち上げてください！！
<img width="600" alt="スクリーンショット 2020-08-19 0.40.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679508/0a2f9243-b913-272b-8ec6-fcb402de4e89.png">
RealmSwiftの記事の引用をしました！わかりづらくなってたら申し訳ありません・・・
これでステップ３は完了できる思います！


#エラーが出たら・・・
GoogleService-Info.plistのファイルの位置がおかしい
→移動させてください！
間違ってふたつダウンロードしてしまい、名前の違うplistファイルを使ってしまった
→Finderのダウンロード上にあるplistファイルを一度削除してからもう一度試してください。
cocoapodで上手く反応しない！
→podファイルにインストールされているライブラリを削除してからもう一度入れ直して試してください！

他にエラーが出たらTwitterのDMなどで教えてください！
【メモ】Pythonオブジェクト保存方法（pickle）について

* 製造業出身のデータサイエンティストがお送りする記事
* 今回はオブジェクトをpickleで保存／読み出しする方法をメモとして残しておきます。

##はじめに
オブジェクトを保存する際にpickleを使用して保存するのですが、その際に`with open`を使用して保存／読み出しを行っていたのですが、他の方法もある事を知りましたのでメモとして残しておきます。

1.　with openで保存/読み出し
2.　pandasで保存/読み出し
3.　joblibで保存/読み出し

##with openで保存/読み出し
最初に私が良く使っていた`with open`を使用して保存／読み出しをする方法を整理します。

```php
# データ作成
data = [a for a in range(0, 10)]
data
#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

import pickle

#保存
with open("data.pkl", "wb") as f:
    pickle.dump(data, f)

#読み出し
with open("data.pkl", "rb") as f:
    hoge = pickle.load(f)
hoge
#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
```

##pandasで保存/読み出し
次は`pandas`を使用して保存／読み出しをする方法を整理します。

```php
import pandas as pd

# 保存
pd.to_pickle(data, "data_1.pkl")

#読み出し
hoge = pd.read_pickle("data_1.pkl")
hoge
#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
```

##joblibで保存/読み出し
最後に`joblib`を使用して保存／読み出しをする方法を整理します。

```php
import joblib

# 保存
joblib.dump(data, "data_2.jb", compress=3)

#読み出し
hoge = joblib.load("data_2.jb")
hoge
#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
```

##さいごに
最後まで読んで頂き、ありがとうございました。
簡単ですが、オブジェクトをpickleで保存／読み出しする方法をメモとして残しておきました。

訂正要望がありましたら、ご連絡頂けますと幸いです。
MacでEC2にssh接続する

###EC2側の設定

- セキュリティのインバウンドルールにSSHの設定を追加する。

- キーペアを作成して、ダウンロードする。

###Mac側

- .sshフォルダにダウンロードしたpemファイルを格納する。
- pemファイルの権限を400に変更

```
$ chmod 400 <証明書.pemのパス>
```
- ホスト名の取得 
    - EC2 インスタンスページのパブリックDNS名がホスト名にあたります。
- 以下のコマンドを実行して、ssh接続する

```
$ ssh -i <証明書.pemのパス> ec2-user@<ホスト名>
```

###さらに楽に接続する方法

- ~/.ssh/configファイルに接続設定を記述する

```
Host aws
 HostName       <ホスト名>
 IdentityFile   <証明書.pemの絶対パス>
 User           ec2-user
```
- 以下のコマンドを実行

```
$ ssh aws
```
【Unity 認定プログラマー試験】試験勉強中に間違えた問題のメモ

# この記事について
[公式コースウェア](https://unityedustore-global2.pearsonvue.com/unity-certified-programmer-courseware-6-months/p/UCPC-6M_KFDP) で不正解だった問題に関する知識を調査・整理します。
Unityをある程度問題なく扱える方向けの内容です。
「どのような知識が試験に必要か」などの参考にどうぞ。

現在も受講中なので、随時追記予定です。


## 免責
- 問題文自体は載せません。関連知識をまとめます。
- 対策コースで出題される問題は、過去問ではないようです。
- コースワークを日本語化できなかったので英語で受講しました。
    - 問題の理解を間違えている可能性があります。

# ゲーム開発
## 物理演算
###プリミティブコライダの処理速度
Sphare > Capsule > Box > Mesh の順で高速だと思います（Sphareが最速）
[参考](https://forum.unity.com/threads/capsule-vs-box-colliders.34254/)

## パーティクルシステム
### カリングって？
 描画対象外を判定する処理のこと。画面内に映らないなら処理しない。
「simulationSpace」を「World Space」に設定すると無効になる。

## Canvas
### 画像ダウンロードして表示したい
外部から取得するなどビルド後に変更する場合は「RawImage」が適切。

### Pos / Scale / Width Height / Anchors の違い
それぞれの適切なユースケースを認識しておきましょう。
ここは手を動かして確認しておいたほうがいいかなと思います。
[参考](https://docs.unity3d.com/ja/2019.4/Manual/class-RectTransform.html)

## 共通
### timeScale == 0 でも更新されるモノ
- Update関数内の物理演算以外（直接角度を指定する処理など）
- Time.realtimeSinceStartup
- GUI

### ゲーム開発理論
- Finite State Machine
    - ゲームではゲームやキャラの状態管理に使われる理論
    - 「Switch」や「State Pettern」で実現するアレのこと（だと思います）
    - [StateMachineBehaviourについて問われました](https://docs.unity3d.com/ja/current/ScriptReference/StateMachineBehaviour.html)
    - [UnityではAssetを活用して作成するのが一般的なのかも](https://qiita.com/BelColo/items/a94c9ccc2d5174dc29a3)

# 知っておきたい機能
## Unity Collaborate
- Unity向けのバージョン管理システム。無料で使用できる。
- 「Hierarchy window」上で（Unityの画面で）未公開の変更を確認できる。


## Unity Analytics
- 基本的な情報（ユーザー数とか）は自動的に収集される
    - イベントの種類や、収集対象のデータも認識しておく
    - たとえば、ユーザ数はCoreEvents なのか？ StandardEventsなのか？ など。
- ゲーム固有のイベントも設定できる（進行状況とか、ハイスコアとか）

## Remote Setting
- リビルド不要でWebから設定を変更できる


# あとがき
近日中に公式認定試験を受験する予定なので、
実際にどのくらい試験に役だったかも記事にしたいと思います。

良い Unity ライフを！
AWS SAM CLI package-lock.jsonが無視される問題を解決する

##問題

ビルドするとビルドフォルダにpackage-lock.jsonがいない。
そこでnpm installしているため、ビルドしたらバージョンが変わる可能性があるのでなんとかしたい。


##解決

```npm shrinkwrap```で```npm-shrinkwrap.json```を作る。



参考：
https://www.gitmemory.com/issue/aws/aws-lambda-builders/221/763109320

##検証
一回古いバージョン固定でインストール、その後package.json書き換えてビルド、ビルド先のバージョンを調べる。

###package-lock.jsonの場合

package.json
古いバージョン指定

~~~
  "dependencies": {
    "date-fns": "2.16.0",
  }
~~~

インストール
```$ npm intall```

package-lock.json

~~~
  "dependencies": {
    "date-fns": {
      "version": "2.16.0",
~~~


package.json
メジャーバージョン一致してればOK設定に変える

~~~
  "dependencies": {
    "date-fns": "^2.16.0",
~~~

※npm installしてもpackage-lock.jsonは変わらない。

ビルド実行
```$ sam build```

buildフォルダ下のnode_modules/date-fns/package.json
最新になってしまった。

~~~
  "_from": "date-fns@^2.16.0",
  "_id": "date-fns@2.17.0",
~~~

### shrinkwrapの場合


```$ npm shrinkwrap```
```npm notice package-lock.json has been renamed to npm-shrinkwrap.json. npm-shrinkwrap.json will be used for future installations.```


package-lock.jsonをnpm-shrinkwrap.jsonにリネームしたよとのこと。


npm-shrinkwrap.json


~~~
  "dependencies": {
    "date-fns": {
      "version": "2.16.0",
~~~

ビルド

```$ sam build```


buildフォルダ下のnode_modules/date-fns/package.json
古いバージョンに固定されている。

~~~
  "_from": "date-fns@2.16.0",
  "_id": "date-fns@2.16.0",
~~~

ビルドフォルダ下にnpm-shrinkwrap.jsonがちゃんとあった。
記憶を鍛えるには from エンジニアの知的生産術(マイピックアップ)

「[エンジニアの知的生産術](https://www.amazon.co.jp/%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E7%9F%A5%E7%9A%84%E7%94%9F%E7%94%A3%E8%A1%93-%E2%80%95%E5%8A%B9%E7%8E%87%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B3%E3%80%81%E6%95%B4%E7%90%86%E3%81%97%E3%80%81%E3%82%A2%E3%82%A6%E3%83%88%E3%83%97%E3%83%83%E3%83%88%E3%81%99%E3%82%8B-WEB-PRESS-plus-ebook/dp/B07JFRF6MW/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=2GRDGUXMBTF82&dchild=1&keywords=%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E7%9F%A5%E7%9A%84%E7%94%9F%E7%94%A3%E8%A1%93&qid=1608975046&sprefix=%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E7%9F%A5%E7%9A%84%2Cstripbooks%2C272&sr=8-1)」を読み、今の自分にとって大切な考え方をピックアップ !

# 第3章. 記憶を鍛えるには

## アウトプットが記憶を鍛える

脳は似た情報が繰り返し**インプットのみされた場合、「これは役に立たない刺激」であると勘違いする**ため、その情報を無視するようになる。
→　**アウトプットをすることによって、使われたその情報は価値のあるものだと認識するようになる**


###　テストをしてから更に学ぶ

- 1回だけ教科書を読む
- 4回繰り返して読む
- 1度読んだ後、思い出せるだけ思い出して(テスト)、それからもう一度読んで、また思い出せるだけ思い出す

この3つの方法で一番記憶が定着していたのが、一番最後**「思い出せるだけ思い出してから、もう一度学ぶ」**という研究結果であった。
→ 4回繰り返してインプットするよりも、その時間の一部をテスト(アウトプット)に回した方が記憶できる!!
(**自分の記憶の定着していないところを認識し、そこを重点的に学ぶことが出来るため効率的に記憶を定着させることが出来る**)

## 知識を長持ちさせる
### 忘れてから復習する

テストまで6か月間隔開ける実験。
どの試行も、2回勉強して、2回目の勉強の6か月後にテストをする

↓ 1回目と2回目の勉強の間隔

- 20分
- 1日
- 1週間
- 1か月
- 3か月
- 6か月

結果は、1か月間隔をあけた場合が一番正解率が高かった(正解率55%)。
1週間、3か月、6か月な大体同じ(正解率40~50%)。
20分、1日間隔をあけた場合尾が一番低い(正解率25%~33%)。

→　**ある程度まで間隔をあけた方が長期的な記憶をきたえることに有効!!**

## 今の自分のレベルではどうしても覚えることが難しいものへの対応

- 放置する。(自分が適切なレベルになったころに再挑戦)
- 本当に覚える価値のあることかを考え、価値がないなら削除する
- より覚えやすくなるように編集する
matplotlib.pypltをimportできない。(Kernel Restarting)

## jupyter labで、matplotlib.pypltのimportでエラー

```py:
import matplotlib.pyplot as plt
```


>Kernel RestartingThe kernel ~/*******.ipynb appears to have died. 
>It will restart automatically.


## 結論、とにかくmatplotlibを再インストールすれば直る

```zsh:
% pip uninstall matplotlib
% pip install matplotlib
```

## エラーの概要

juypterのkernelエラーでは、よく分からないので、ターミナルにてpythonでimportを試みる。
segmentation faultということが分かる。
pythonは裏ではC言語が動いているので、C言語で言うところのセグフォが原因。
segmentation faultとは、
OSがメモリを割り振っていない処理を実行しようとした時に、OSがプログラムをストップしにくるエラー。
だから、jupyterのエラーにkernelがどうこうでていた。

```zsh:
% python
:
>>> import matplotlib.pyplot as plt
zsh: segmentation fault  python

```
M1チップ搭載のmacでデータ引き継ぎ後にネットワーク接続ができなくなる問題について

M1チップ搭載のmacで初期不良を起こし、製品交換をしてもらった。
timemachine経由でデータを引き継いだ直後にwifiが繋がらなくなってしまった。
その時の対処法をメモ。

1. macをセーフモードで起動
2. ネットワーク接続を確認
3. 適当なソフトを起動してrossetta2をインストール
4. 再起動して、通常モードでネットワーク接続を確認

上記で解決したため、rosetta2を使用するソフトが起動できないことによってネットワークに繋がらなかったものと考えられる。(多分セキュリティソフトのせい)

- rosetta2がインストールできない
- rosetta2で起動するソフトが動かせない
- ネットワークに接続できない
- ネットワークに接続できないからrosetta2がインストールできない

初めてのmacだったこともあり、このループを抜け出すのに苦労した。
Eclipse上でのパスと実行した後のパスが異なる理由

#プロジェクトエクスプローラーと同じパスが通らない
Eclipseでプロジェクトを開発していて、CSSをJSPに適用させたい時など、パスを設定する必要があることがあります。
その時、Eclipseのプロジェクトエクスプローラー上でのパスの通りに設定してしまうと適用されません。

例：Eclipse上では、「/example/WebContent/sample1.jsp」なのに、実際には「/example/sample1.jsp」にパスを通す。
（WebContentが消えている）

その理由について調べました。
#動的Webプロジェクト≠Webアプリケーション
Eclipseで動的Webプロジェクトを編集しているので、その中でパスを通せば通るはずだと思っていましたが、実際には**動的Webプロジェクト≠Webアプリケーション**です。

サーバーで実行してブラウザを表示するとき、**動的Webプロジェクトをデプロイして、アプリケーションサーバ上で動く**ようにしています。

この時、**ディレクトリ構成が自動的に再配備**されます。これは、Java EEのルールで決まっています。

**開発するときと、サーバで実行するときのディレクトリ構成は違う**ということを念頭においておきましょう。
【Vim】Vimのインストール〜基本的な操作について

### 0.はじめに
学習している教材をきっかけにVimのことを知りました。
アウトプットを兼ねて、インストールと基本的な操作を記していこうと思います。

### 1.読んで欲しい人
・テキストエディタを探している
・Vimに興味がある
・インストールしたけどエラーが出てしまっている

### 2.使用環境
mac.os バージョン10.15.6

### 3.vi/Vimとは？

vi(ヴィーアイ)・・・端末で動作するテキストエディタ。マウスはもちろん、矢印キーやファンクションキーのような特殊キーを使用せずに操作できる。
Vim(ヴィム)・・・viの拡張版。

参照リンク1:[Linuxの定番テキストエディタ「vi」をマスターしよう](https://www.atmarkit.co.jp/ait/articles/1712/06/news013.html)
参照リンク2:[【初心者必見】最強エディタVimの使い方/コマンド30種まとめ]
(https://www.sejuku.net/blog/5570)
#### 3.1 vi
##### 3.1.1 viを起動する

viはターミナルから起動することができます。
`vi ファイル名`と入力します。

(例)sample.txtというファイル名で作成したい場合

```:ターミナル

$ vi sample.txt
```

すると、"sample.txt"の名前で新規ファイルが起動します。
<img width="450" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689555/d19a5986-b672-179e-1770-1e0b5444cf50.png">

##### 3.1.2 viで入力〜保存する
(1)モードの切り替え
viを起動時、`ノーマルモード`になっています。ノーマルモードになっていると入力することができません。
そこで、`i`キーを押して`インサートモード`に切り替えます。
<img width="450" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689555/ba6a3fb7-f484-16f2-f3de-605c07fd8826.png">

インサートモードに切り替えると文字の入力が可能になります。

(2)保存する
保存の際は`esc`キーを押して`ノーマルモード`に再度切り替え、`:wq`→`Enter`で保存ができます。
（保存せず強制終了する際は`:q!`です。通常の終了は`:q`です。）

(2補足)保存したファイルはどこに行くのか？
場所を指定していない場合、`ホームフォルダ`に保存されます。
(macの場合、`Shift`+`command`+`H`でホームフォルダが表示されます。)


#### 3.2 Vim
##### 3.2.1 Vimのインストール
Vimに関しては、インストールをすることで使用が可能になります。
Windowsとmacでインストールの手順が異なります。
（今回はwindowsの手順は割愛します）

今回は下記リンクのMacで`Vimを利用する`の章を参考に、MacVim-KaoriYaをインストールしました。
参照リンク:[【初心者必見】最強エディタVimの使い方/コマンド30種まとめ]
(https://www.sejuku.net/blog/5570)

アプリケーションフォルダに`MacVim.app`を入れてクリックすると、「開発元が未確認のため開けません」というエラーが表示されました。
そこで、下記のQiitaを参考に、ダウンロードしたアプリケーションの実行許可を一時的に緩和することで、エラーを解消しました。

参照リンク:[Macで「開発元が未確認のため開けません」とエラーが表示されてアプリが開けない場合の対応](https://qiita.com/g_maeda/items/8c9b38d5ce879f185c82)

##### 3.2.2 Vimを起動する
`MacVim.app`をクリックすると、Vimが起動します。ファイル名は`無名`となっています。
<img width="450" alt="vin起動.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689555/8e8e209e-e3b4-c686-5ee0-3ad2b2535958.png">

##### 3.2.3 Vimで入力〜保存する
※基本的な操作は`vi`と同様です。

(1)モードの切り替え
viを起動時、`ノーマルモード`になっています。ノーマルモードになっていると入力することができません。
そこで、`i`キーを押して`インサートモード`に切り替えます。

インサートモードに切り替えると文字の入力が可能になります。
<img width="450" alt="vim insert_mode.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689555/e6bfe566-e01b-9dc7-d715-2644327b1c84.png">


(2)保存する
名前をつけて保存する際は、`esc`キーを押して`ノーマルモード`に再度切り替え、
`:w ●●（ファイル名）`→`Enter`で保存ができます。
※ファイル名が無名のまま、`上書き保存`である`:wq`→`Enter`行うと`ファイル名がありません！`とエラーが表示されます。
<img width="450" alt="vim E32 error.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689555/ac031bb9-dd37-242b-636b-c4a8b99c1e0d.png">
（保存せず強制終了する際は`:q!`です。通常の終了は`:q`です。）

参照リンク:[Vimをメモ帳程度に使うために覚えておくべきコマンド](https://qiita.com/honeniq/items/201156650310c4968c3a)

### 4.感想
Vimのインストール時にエラーの解消で時間を要したものの、触ってみることでとっつきにくさのハードルが下がりました。
今後実務等で触る機会もあるかもしれないので、操作の仕方に慣れていきたいです。

### 5.最後に
記事の感想や意見、ご指摘等あれば伝えていただけるとありがたいです。
読んでいただき、ありがとうございました。
[Unity] カメラの追従（マウスのドラッグで回転）

**「Unity」ドラッグで回転させる方法です。**

1, CameraControllerを作成し、下記コードを記述する

```C#:CameraController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController : MonoBehaviour
{
    public GameObject playerObject;
    public Vector2 rotationSpeed;
    public bool reverse;

    private Camera mainCamera;
    private Vector2 lastMousePosition;

    void Start()
    {
        mainCamera = Camera.main;
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            lastMousePosition = Input.mousePosition;
        }
        else if (Input.GetMouseButton(0))
        {
            if (!reverse)
            {
                var x = (lastMousePosition.x - Input.mousePosition.x);
                var y = (Input.mousePosition.y - lastMousePosition.y);

                if (Mathf.Abs(x) < Mathf.Abs(y))
                    x = 0;
                else
                    y = 0;

                var newAngle = Vector3.zero;
                newAngle.x = x * rotationSpeed.x;
                newAngle.y = y * rotationSpeed.y;

                mainCamera.transform.RotateAround(playerObject.transform.position, Vector3.up, newAngle.x);
                mainCamera.transform.RotateAround(playerObject.transform.position, transform.right, newAngle.y);
                lastMousePosition = Input.mousePosition;
            }
            else
            {
                var x = (Input.mousePosition.x - lastMousePosition.x);
                var y = (lastMousePosition.y - Input.mousePosition.y);

                if (Mathf.Abs(x) < Mathf.Abs(y))
                    x = 0;
                else
                    y = 0;

                var newAngle = Vector3.zero;
                newAngle.x = x * rotationSpeed.x;
                newAngle.y = y * rotationSpeed.y;

                mainCamera.transform.RotateAround(playerObject.transform.position, Vector3.up, newAngle.x);
                mainCamera.transform.RotateAround(playerObject.transform.position, transform.right, newAngle.y);
                lastMousePosition = Input.mousePosition;
            }
        }
    }
}
```

2, PlayerにMainCameraを入れ、MainCameraのインスペクタ部分にPlayerをアタッチし、PowerObjectを入力する。
![D038D423-3E31-4383-B06B-321E64C52C90.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/5bfe0755-c1c8-77a5-8256-e5429df5a13c.jpeg)
統計検定3級の受かり方！

# 統計検定3級について、ざっくり説明
まず「統計検定」とは、統計に関する知識や活用力を評価する**全国統一試験**です。
その中で「3級」は**大学基礎レベル**と位置付づけられています。

* [統計検定 公式ページ](https://www.toukei-kentei.jp/)
* [3級の出題範囲](https://www.toukei-kentei.jp/wp-content/uploads/grade3_hani_181214.pdf)

# 統計初心者におすすめ！
「資格のための勉強では意味が無い」という言葉をよく耳にします。
基本的に私もこの言葉には賛成ですが、統計検定3級に関しては「資格のための勉強」でも良いんじゃないかと思っています。

数式や統計用語に苦手意識を持つ人もいると思いますが、
3級の勉強をするとそれらに耐性がつき、意外と難しいものじゃないと思えるようになるはずです。

標準偏差、相関係数、正規分布、、、言葉は知っているけれど意味や使い方は分からない。
という状態を脱却し、後に難易度の高い分野を学習する際のハードルを大きく下げることができます。

つまり、**統計学を学びたい人の「第一歩」**として最適な資格です！

# 受かり方！

お待たせしました。
それでは本題の「統計検定3級の受かり方」です。

合格までの道のりは、大きく**2ステップ**！

### 【ステップ1】基礎知識を身につける（約2週間）

* 下で紹介する、おすすめの本「[データの分析](https://www.amazon.co.jp/%e6%97%a5%e6%9c%ac%e7%b5%b1%e8%a8%88%e5%ad%a6%e4%bc%9a%e5%85%ac%e5%bc%8f%e8%aa%8d%e5%ae%9a-%e7%b5%b1%e8%a8%88%e6%a4%9c%e5%ae%9a-3%e7%b4%9a%e3%83%bb4%e7%b4%9a-%e5%85%ac%e5%bc%8f%e5%95%8f%e9%a1%8c%e9%9b%86-2017%e3%80%9c2019%e5%b9%b4/dp/4788925532/ref=pd_lpo_14_t_1/357-8154508-6864531?_encoding=UTF8&pd_rd_i=4788925532&pd_rd_r=09fcd950-345c-4327-ac92-933f7d82046b&pd_rd_w=5vrgy&pd_rd_wg=Jv8PF&pf_rd_p=4b55d259-ebf0-4306-905a-7762d1b93740&pf_rd_r=A3XMBYCQW0X9ZT5THVWT&psc=1&refRID=A3XMBYCQW0X9ZT5THVWT)」か、おすすめのサイト「[統計学の時間](https://bellcurve.jp/statistics/course/#step00)」で基礎知識を身につけてください。
* 両方読めば万全ですが、どちらか一方だけでも大丈夫だと思います。

### 【ステップ2】過去問を解く（約1週間）
* 「合格点（70点）を取るまで同じ過去問を繰り返し解く」を2回分やってください。
* 2回分でも十分ですが、もし3回分やったなら合格はほぼ確実だと思います。

# おすすめの本、サイト

### 【おすすめの本】

* [データの分析](https://www.amazon.co.jp/%e6%97%a5%e6%9c%ac%e7%b5%b1%e8%a8%88%e5%ad%a6%e4%bc%9a%e5%85%ac%e5%bc%8f%e8%aa%8d%e5%ae%9a-%e7%b5%b1%e8%a8%88%e6%a4%9c%e5%ae%9a-3%e7%b4%9a%e3%83%bb4%e7%b4%9a-%e5%85%ac%e5%bc%8f%e5%95%8f%e9%a1%8c%e9%9b%86-2017%e3%80%9c2019%e5%b9%b4/dp/4788925532/ref=pd_lpo_14_t_1/357-8154508-6864531?_encoding=UTF8&pd_rd_i=4788925532&pd_rd_r=09fcd950-345c-4327-ac92-933f7d82046b&pd_rd_w=5vrgy&pd_rd_wg=Jv8PF&pf_rd_p=4b55d259-ebf0-4306-905a-7762d1b93740&pf_rd_r=A3XMBYCQW0X9ZT5THVWT&psc=1&refRID=A3XMBYCQW0X9ZT5THVWT)
  * 日本統計学会公式認定の参考書。
  * 公式なだけあって1冊で3級合格に必要な知識を漏れなく学習できる。
  * 章ごとに練習問題もある。

* [統計検定 3級・4級 公式問題集](https://www.amazon.co.jp/%e6%97%a5%e6%9c%ac%e7%b5%b1%e8%a8%88%e5%ad%a6%e4%bc%9a%e5%85%ac%e5%bc%8f%e8%aa%8d%e5%ae%9a-%e7%b5%b1%e8%a8%88%e6%a4%9c%e5%ae%9a-3%e7%b4%9a%e3%83%bb4%e7%b4%9a-%e5%85%ac%e5%bc%8f%e5%95%8f%e9%a1%8c%e9%9b%86-2017%e3%80%9c2019%e5%b9%b4/dp/4788925532/ref=pd_lpo_14_t_1/357-8154508-6864531?_encoding=UTF8&pd_rd_i=4788925532&pd_rd_r=09fcd950-345c-4327-ac92-933f7d82046b&pd_rd_w=5vrgy&pd_rd_wg=Jv8PF&pf_rd_p=4b55d259-ebf0-4306-905a-7762d1b93740&pf_rd_r=A3XMBYCQW0X9ZT5THVWT&psc=1&refRID=A3XMBYCQW0X9ZT5THVWT)
  * 6回分の過去問とその解説が収録されている。
  * 3級は過去問と似た問題が多く出題されるため、過去問を解くか解かないかで合格のしやすさはけっこう変わる。

### 【おすすめのサイト】

* [統計学の時間 Step0. 初級編](https://bellcurve.jp/statistics/course/#step00)
  * 書籍と比べると解説量や問題量がやや劣るが、このサイトを読んだだけでも3級合格には十分な知識が身につく。
  * スマホでも読みやすいサイトなので、通勤時など隙間時間での学習に活用しやすい。

# ひとこと
好きな確率分布は**ポアソン分布**。
名前が[ポワルン](https://zukan.pokemon.co.jp/detail/351)みたいでかわいい。
[Unity] Playerにカメラを追従する(カメラ位置固定)

Playerにカメラを追従させる
---
**カメラの位置を固定したまま追従させる方法です。**

1, CameraControllerスクリプトを作成し、下記コードを記述する
(Mainカメラにアタッチするのを忘れずに)

```C#:CameraController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController : MonoBehaviour
{
    private GameObject player;  //プレイヤー情報格納用
    private Vector3 offset; // 相対距離取得用

    void Start()
    {
        //　Playerの情報を取得
        this.player = GameObject.Find("Player");

        // メインカメラ（自分自身）とPlayerとの相対距離を求める
        offset = transform.position - player.transform.position;
    }

    void Update()
    {
        //　新しいトランスフォームの値を代入する
        transform.position = player.transform.position + offset;
    }
}
```

これでカメラが追従するようになる。
Tokenを用いて、AndroidStudioとGitHubを連携させる

AndroidStudioとGitHubを連携させようとした際、GitHubのユーザーIDとパスワードを用いた連携が出来なかったため、代わりとして行った処置をメモしておきます。
なお、Gitがインストール済みであり、GitHubのアカウントを所持していることが前提となります。
##AndroidStudioでログインフォームを開く
上のメニューから、
VCS → Import into Version Control → Share Project on GitHub
と進んでいきます。
![Qi1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1086769/8b9df131-5114-5470-d7b5-bb32c036735c.png)

すると下のような画面が現れ、GitHubのIDとパスワードを求められます。![Qi2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1086769/bfa220fc-5822-a8c9-6c9b-a05efb4a9cba.png)

私の場合は、
<font color="Crimson">Invalid authentication data. 404 Not Found - Not Found</font>
とエラーが出てしまいました。![Qi3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1086769/5aa2d75c-5503-b0be-e2b5-1c32a5c38c59.png)

調べても原因がわからなかったので、右上の<font color="CornflowerBlue">Use Token</font>をクリックします。
下の画面になったらAndroidStudioでの作業は一旦おやすみです。![Qi4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1086769/2ac71207-24fb-6e3d-d88a-515e5fbc5b0a.png)

##GitHubでTokenを生成する
GitHubにログイン後、右上のプロフィールアイコンを押し、
Settings → Developer settings → Personal access tokens
と進みます。
Generate new tokenをクリックしましょう。
![Qi5 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1086769/8845212f-01d4-2e53-3c8c-94b880ec5c27.png)

Tokenの名前をつけ、GitHubにおけるアクセス範囲を指定します。
![Qi6 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1086769/3a33553d-f510-bc9c-dfc2-29d4e9636f68.png)

画面下の<font color="LimeGreen">Generate token</font>を押すと、数字とアルファベットの羅列が生成されます。
これをコピーします。
![Token生成.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1086769/8b4a1cc2-2393-9559-2ff5-a794cdb9b79a.jpeg)
##AndroidStudioとGitHubを連携させる
AndroidStudioに戻り、Token:の欄に先ほどコピーしたTokenを貼り付けます。
![Qi8.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1086769/9232e2e9-a3b0-abe5-23a8-fa700e012296.jpeg)

Log In押下後、下のような画面に変われば成功です。
![Qi9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1086769/ac798080-5325-45e9-2dc8-5555f5a0a78b.png)
アプリ開発実践入門2 Controllerとviewの基礎



参考教材
https://www.udemy.com/course/rails-kj/learn/lecture/9330884#overview
Ruby on rails6 超入門

#新しいページの作成

##開発環境の起動、停止、削除
```docker-compose up -d```:起動、docker-compose.ymlが必須
```docker-compose stop```:停止
```docker-compose down```:削除

 - ```docker-compose up```だけで起動したら…？-dなし。ターミナルのフォアグラウンドで実行されるため、ターミナルの画面がログだらけになる。この状態でCtrl＋Cで強制終了するとサーバー.pidファイルが残り次回の起動に失敗することがある
 - その時はserver.pidファイルを削除してから実行する

##ルーティングの編集

routes.rbに必要なコントローラとメソッドを記述する

 - rootはlocalhost:3000へのアクセス時のルーティング

##コントローラの作成
routes.rbに記述したコントローラ名でコントローラを作成

##ビューの作成
###テンプレートファイルの作成(HTMLの作り方、使い方)
コントローラ名でディレクトリを作って、アクション名でファイルを作る
`アクション.html.erb`:.erb拡張子のファイル。「Embeded Ruby」の略称。htmlタグの中にrubyのコードを実行できるようにするrailsの機能の一部。

`render html: テキスト`:レンダリング、Webコンテンツを表示する処理のこと、左だとHTMLを出力する
`変数.html_safe`:htmlをエスケープ無しに表示する際に使うメソッド
クエリーパラメータ:サイトにアクセスする際につけるアドレス部分についたパラメータ`http:/アドレス?名前＝値&名前=値`とか
params: クエリーパラメータに送られた情報をまとめているハッシュオブジェクト、ここに値を送ってif文で出力したりする

###スタイルシートの作成(各コントローラのスタイルシートの編集)
`コントローラ.sccs`:.scss拡張子のファイル(Sass)。コントローラ作成時に自動生成。スタイルシートとしてロードされる。Bootstrapを利用するので必要以上に記載しなくても…？

ビューのHTMLにあるクラスと関連した構文を作成するので両方をチェックしながらコーディング。
なので、対応するHTMLに個別に記述しているタグ(クラス)に対する記述を行う。

###Bootstrapの導入
レイアウトやデザインを簡単に実装できるcssフレームワークの一つ。
必要な定義をGemfileに書き込み、ビルドでインストール。コンテナを立ち上げて実装完了。
`application.html.erb`:ページ全体のレイアウトについて記述しているファイル

application.scssファイルにインポートを追記。

application.jsも編集、追記で使えるように。

####Bootstrapの導入:別のやり方(本の方)
CDNリンクの追加
<link>タグによる埋め込みだけで使える方法もある

[Bootstrapリファレンス](https://getbootstrap.jp/docs/4.5/getting-started/introduction/)

###テンプレートファイルの作成２(HTMLの編集)

対応するコントローラのメソッドは初めは空にしておく。railsではレンダリングしていない場合、勝手に対応するテンプレート、つまりhtmlファイルを読み込んで表示してくれる。

また、コントローラに追記して用意した値をテンプレートに表示することもできる。
`@変数`:インスタンス変数を用意しておき、
<%= 〇〇%>のタグの中に入れる。これはrubyを実行するためのもの。

`application.html.erb`:共通で使用するレイアウト用のビューファイル
各ページのビューはこのファイルの`body`タグの`<%= yield %>`でレンダリングされる。

###スタイルシートの作成2(各ページ共通のスタイルシートの編集)
`base.scss`(仮名)に`h1`タグに対する編集をする。
こちらは全体のビューに関わるタグに記述を行う

###スタイルシートの作成3(全体のスタイルシートの編集)
`@import "〇〇"`でよく使う。Bootstrap導入でも記述した。
ここに`@import "スタイルシート名"`で記述して各スタイルシートを反映させる。

マージンの設定

###リダイレクトの設定


#気になったこと
コントローラのディレクトリにsをつける理由

#わからなかったこと
謎のルーティングエラー
原因は```root 'homes#index'```が```root `homes#index````になっていたこと。
普通に気をつけよう。

計画中のプロダクト

プロダクトの要件

コマンドでコントローラを作成

コントローラにアクションを記入

実装するアクションまとめ
お名前.com、WordPress、CloudFlare、GCPを使ってHTTPS対応Webサイトを公開するまで。

#前提
お名前.com、WordPress、CloudFlare、GCPあたりが今回のキーワードでいろんな記事を参考にさせてもらったので、備忘メモとして残しておく。

#ドメイン取得
ドメイン取得する必要があるが、自分はお名前.comで取得している。「お名前.com」でggると、「whois情報公開代行」について注意喚起する記事が大量にHitするが、2021年2月現在は「whois情報公開代行」はデフォルトで有効になっていた。
そのことに触れてある記事も見つけることができた。
https://netdejiyujin.com/onamaecomwhoisauto/

#GCPでWordpress立ち上げ
この記事をめちゃくちゃ参考にさせていただきました。
https://qiita.com/ulwlu/items/dbb0db5cf7099b7a7cc4

選択したコンテナは記事に従い、「wordpress with nginx and ssl certified by bitnami」とした。

「[3/5]クラウドストレージとの自動連携」の部分は未実施。なぜなら画像のURLがCloud StorageのURLになってしまい、サイトのドメインとは違うものになってしまうから。そこを合わせる仕組みもきっとあるが、そこは重要ではないのでいったん本工程はスキップ。VMのディスク容量が逼迫してきたら、再度導入検討したい。

#CloudFlareでCDNおよびDNSの設定
https://qiita.com/ulwlu/items/dbb0db5cf7099b7a7cc4
同じくこの記事を参考にCloudFlareをFREEプランで登録し、DNSのAレコードを書き換えた。なお書き換え前は、お名前.comのDNSサーバに該当ドメインが登録されており、「このドメインはお名前.comで取得されました」的なページのIPアドレスで解決されるようになっている。
続いてCloudFlare上で表示されているネームサーバーの名前を、お名前.comの設定画面（DNS設定的なもの）にて登録する。これによってレジストラは引き続きお名前.comだが、当該ドメインを管理するネームサーバはCloudFlareのものになる。お名前.comで登録後、30分程度DNSおよびCloudFlareのポータルへの反映には時間がかかるようだ。

その後、CloudFlareの「お客様の SSL/TLS 暗号化モード フル」の設定を「フル」にし、「SSL/TLS 推奨機能（ベータ版）」を「オン」にした。これも登録後30分程度は反映まで時間がかかるとのこと。なおこれらの設定値の名前は2021年2月現在のものであり、今後も設定名などが変わる可能性はある。

2021.11.23追記
CloudFlareはUniversal証明書を使っているが、これの場合は更新はCloudFlare側で自動でやってくれそうである。
https://www.infoq.com/jp/news/2014/10/cloudflare-universal-ssl/

#WordPress側の設定
晴れてドメイン取得し、そのドメインでWordpressログイン、記事を書こうとすると下記のエラーに見舞われた。

- 記事の作成画面で「更新に失敗しました。 現在オフラインのようです。」と表示され、記事の保存ができなくなる。
- 記事に画像を貼り付けようとすると、「n.headers is undefined」というエラーが表示され、画像が投稿できない。

ドメインでHTTPS接続した状態でWordpressログインすると上記エラーが表示されるが、IPアドレス直打ちでHTTP接続だと上記エラーは発生しない。いろいろとggった結果、下記サイトに対処法が記載あった。多分これがなかったら解決できなかったです、大変ありがたいです。
https://h-memo.com/publishing-error-in-wordpress/

WordPressの[設定] > [一般]の`WordPress アドレス (URL)`と`サイトアドレス (URL)`がhttpになっているのがダメだったらしい。私の環境だとこの画面での変更はできなかったので、
VM上で`/opt/bitnami/apps/wordpress/htdocs/wp-config.php`の設定を書き換えるとよいとのこと。GCPコンソールから直接SSH接続し、nanoエディタで書き換えを行う。上記サイト曰く、なぜかnanoエディタ以外ではうまく変更できなかったとのこと。


```wp-config.php
define('WP_SITEURL', 'http://' . $_SERVER['HTTP_HOST'] . '/');
define('WP_HOME', 'http://' . $_SERVER['HTTP_HOST'] . '/');
```

の`'http://'`の部分を`'https://'`にするだけである。
ちなみにnanoエディタは`Ctrl + x`で保存である。保存有無を訊かれたら`Y`で回答し、その後名前を変えるか訊かれたらとりあえず`Enter`うっとけばOKらしい。

あとはnginxを再起動、
`sudo /opt/bitnami/ctlscript.sh restart nginx`
これで上記エラーも解消できた。
link_toの適用範囲を広げる

# link_toとは
名前の通りリンクを生成するRailsメソッドである。
link_toは初期HTTPメソッドがGETのため、扱うメソッドによってはオプションで指定する必要がある。

基本的には下記の様な記述で利用する

```ruby
#公式ドキュメント
link_to リンクテキスト, パス[,オプション, HTML属性 or イベント属性])

#実用例
link_to 'トップページ', root_path
#devise導入によるセッションでの例
link_to '削除', destroy_user_session_path, method: :delete
```
これによりリンクテキスト部分が指定したパスへのリンクとして表示される様になる。
またリンクテキスト部分には画像も使う事ができる。


#改善したい点
この使い方だけだとショッピングサイトの様に一度に画像、商品名などを表示する際に
一つ一つにlink_toを記述する必要があるため面倒であり管理が煩雑になってしまう

#一括でlink_toを適用する
上記の問題を解決するのに用いるのがdo~endによるブロックである。

```ruby
link_to item_path, do
  #画像や文字列など
end
```

上記の様にする事でdo ~ endまでをブロックとしパスを渡す事で
ブロック内の要素全てにリンク要素がつく様になります。
#まとめ
煩雑さを取り払う事ができた。
注意点としては非同期通信などの要素の配置に気をつけないと
結局一つ一つに適用する必要が出てくるためデザイン面も気をつけたい
Firestore（Datastore mode）の全Kindのエンティティを一括削除する

Firestore（Datastore mode）のKindのエンティティを一括削除したい場合、昔はコンソールのDatastore Adminから実行することが出来ましたが、現在はCloud DataflowのDatastore Bulk Deleteテンプレートを使用する手順となっています。

本記事ではCloud DataflowのDatastore Bulk Deleteテンプレートを使用して、一度に全Kindの全てのエンティティを削除する方法を記します。

# 手順

1. コンソールのDataflow→「ジョブ」画面から「テンプレートからジョブを作成」をクリック
2. 必要パラメータを入力
    
    <img width="400" alt="パラメータ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31437/8c895012-180f-386a-5eaf-ed36b6feb851.png">
    - ジョブ名：　任意
    - リージョン：　Firestoreのリージョンを選択
    - Dataflowテンプレート：　Bulk Delete Entities in Datastore
    - GQL Query：　`SELECT * WHERE __key__ < Key(__Stat, '0')`
    - Read data from Datastore Project Id of：　削除したいFirestoreのプロジェクトID
    - Delete all matching entities from the GQL Query present in this Datastore Project IdRead data from Datastore Project id...：　同上
    - 一時的なロケーション：　適当なGCSバケット作ってそのパス＋プレフィクス（任意）を指定
3. 「ジョブを実行」をクリック

以上です。

GQLにKindlessクエリというKindを指定しないクエリを指定するのがミソです。
WHERE句は未指定だと統計用Kindを削除しに行って `The kind "__Stat_Kind_CompositeIndex__" is reserved` というエラーが出るので、それを避ける為のおまじないです^^

# 参考

- [Dataflow Datastore Bulk Deleteテンプレート](https://cloud.google.com/dataflow/docs/guides/templates/provided-utilities?hl=ja#datastore-bulk-delete)
- [Datastore Kindless Query](https://cloud.google.com/datastore/docs/concepts/queries#datastore-datastore-kindless-query-gql)
SimpleDateFormatで日付が変な時

日付を出力するためにSimpleDateFormat()を使ったときに日付が38日とかあり得ない数字になってしまう原因と対策です。
#大文字と小文字で出力が違う
日付の場合、**「dd」と「DD」で出力が異なります。**
**月の中での日付を使いたい場合、「dd」です。**
●月●日という風に使う時がほとんどだと思うので、基本的には「dd」で。
一方「DD」は、年で見た時の日付になります。
今日が1月1日から数えて何日目かを出力してくれます。
実行日が2月1日なら「32」になります。
M1 Mac Book AirにしたらAndroidStudioのビルド時間が37%に短縮できた話

## 概要
Qiitaで**「M1 Mac AndroidStudio」**と検索したところ、意外にもM1 Macでのビルド速度比較結果に関する記事がなかったので、実際に**M1 Mac Book Air**で**Gradle**を**AppleSilicon対応**させた手順の忘備録も兼ねて、**ビルド時間を比較**しました。  
当然プロジェクトの内容によって実際のビルド時間は差が出ると思いますが、一つの参考になれば幸いです。
## 使用した各種バージョン
###  Android Studio - Android Studio Arctic Fox 2020.3.1 Canary 4
https://developer.android.com/studio/archive よりDL
これ自体はIntel版。Gradle7を使うためにInteliJのAndroidパッケージが4.3以上必要なので利用 
![スクリーンショット 2021-02-06 14.47.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69344/8d67654d-7dbe-5bfa-7074-8ee1a07632e8.png)

### Open JDK zulu - 15.0.2+7 macOS向けdmg  
OpenJDKのArm64版 
https://www.azul.com/downloads/zulu-community/?package=jdk よりDL
![スクリーンショット 2021-02-06 14.46.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69344/7056b629-5ff4-d05b-8f69-00bee3185f72.png)
インストール後に、Project Structureより指定
![スクリーンショット 2021-02-06 15.04.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69344/5b76520a-7b29-5623-d772-48b4ee3e1d7a.png)

### Gradle - 7.0-milestone-1 
7.0からAppleSilicon対応しているようなので利用
参考（Gradle公式Twitter）: https://twitter.com/gradle/status/1339958143963582465

```gradle-wrapper.properties
distributionUrl=https://services.gradle.org/distributions/gradle-7.0-milestone-1-all.zip
```


### Android Gradle Plugin - 7.0-alpha05
Gradle7を扱うために必要
ProjectStructureのプルダウンより指定
![スクリーンショット 2021-02-06 14.50.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69344/294493a3-dba2-f41a-a715-4ddb30d80548.png)
    
### Kotolin Gradle Plugin - 1.4.21
Gradleもろもろのバージョン上げたら警告が出たので一緒に最新化
プロジェクト直下のbuild.gradleで指定

```build.gradle
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.21"
```
これを上げたら、Kotlinの型判定が特に厳密になったようでちょいちょいビルドエラー出ました。

### 検証条件
同じメモリ16GBのMac Book Pro15インチで比較しました。 

* Intel Mac Book Pro 15 （2017） 
 * Core i7 2.8GHz Quad Core  
 * メモリ 16GB 2133Mhz
 * 購入時、26万円程度だったはず
* M1 Mac Book Air （2020）
    * CPU Apple M1
    * メモリ 16GB
    * HDD 512GB
    * 16万円ほどで購入
   


プロジェクトはRxKotlin、Firebase、GooglePlayService等のライブラリを含むそこそこ大きいプロジェクトです。

### ビルド時間結果
他のアプリケーションを全て閉じた状態でCleanビルド時間を比較

```
Intel Mac Boook Pro 15 : 3分32秒 (212s)
M1 Mac Book Air : 1分19秒  （79s）  
```
**約37%の時間でビルド完了！！**

計測した際のビルド中のアクティビティモニタです。 
AndroidStudio自体はIntelですが、Gradleビルドを行っているJavaがAppleSiliconで動いています。
![スクリーンショット 2021-02-06 14.55.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69344/ae6ea8cd-4be9-7bf5-71c8-c1d0f8a83ac1.png)

### あとがき
想像以上にビルド時間が高速化されました。
比較対象のIntel Mac Book Pro15が2017年モデルなので、最新のIntelMacだともう少し差は縮まると思いますが、それにしても乗り換えのメリットが十分あるレベルかなと思います。
懸念点としては、プレビュー版のAndroidStudioがちょくちょく落ちたので、今後の安定化と、AndroidStudio自体のAppleSilicon対応にも期待したいと思います。
どんなによいサービスでも運用されなければ意味がない

厚生労働省の接触確認アプリ「COCOA（ココア）」で、陽性登録したアプリ利用者と接触しても検知・通知されない障害が判明したと発表されました。
障害は2020年9月28日のバージョンアップに伴い、Android版アプリで発生。
重大バグが4か月以上も見過ごされてきたことになります。

COCOAの開発は厚生労働省からパーソルプロセス＆テクノロジーに委託され、同社は元請けとして全体の工程管理を担当し、エムティーアイがバグ改修や保守開発を担当しています。
COCOAのベースとされているオープンソースプロジェクト「Covid19Radar」は、オープンソースライセンスであるMPLライセンスによって公開されていますが、同ライセンスには改変内容の公開義務があり、COCOAがCovid19Radarをベースとしている場合は、これに基づいてCOCOA自身もソースコードを公開する必要があったため、厚生労働省は2020年9月1日、「COCOA」のソースコードをGitHub上に公開しています。

今回の件自体は、色々なところで議論されており、「メンテナンスされないソフトウェアはすべてゴミになる」という認識が少しでも一般常識になってくれればというところですが、実際にアプリケーションの運用保守を行う人たちだけではなく、その周りの役割も大変だという話を今回はしてみたいと思います。

私が過去に関わった事例になるので、見る人が見ればどの案件か分かってしまいますが、現在進行中の部分もあるため、フィクションを入れさせていただきます。

最近はCOCOAもそうですが、オープンソースで開発したアプリを企業が引き取って運用保守を行うケースが増えてきています。

今回紹介する案件も、とある公的機関の方から、開発するためのお金はないが社会的に必要なアプリということで、オープンソースでボランティアベースで開始されました。
私が関わった契機も、ボランティアベースなのでプロマネ的な動きができる人がおらず、PMO的な役割の関りでお手伝いを依頼されたものでした。

開発自体は、レベルの高いエンジニアの方々がボランティアとして動いてくださったのでうまくいっていたものの、ローンチが見えてきたところで、運用をどうするかという課題が目前にせまってきました。

というのも、今回の案件の対象となっているのは、東京から離れた田舎の土地。GitHubベースでの開発は全国どころか全世界どこからでもできますが、実際にアプリを使う人たちを現地でオンサイト支援する必要がある。

私はその田舎に住んでいる身なので、オンサイト対応もできないわけではないのですが、ボランティアベースでの稼働ではとうてい足りなくなってしまう。

そのため、少額でもコストをかけて企業に運用保守をお願いしようということになりました。

アプリ側の保守については、必ずしもオンサイトで行う必要はないため、比較的容易に実績のある企業で引き受けてくれるところが見つかりました。

問題は、オンサイトの運用支援をやってくれる企業です。

上記のアプリ保守をやってくれるところは、東京に拠点があるため、田舎の地域のオンサイト対応は現実的に不可能。

田舎といってもソフトウェアベンダ企業はいくつもあるので、心当たりのあるところに当たってみるのですが、なかなかよい返事がもらえない。

理由としては、ソフトウェアベンダなので、オンサイト支援を行う人手が足りないことが大きくありました。
田舎といってもIT系のベンチャー企業も多いのですが、ベンチャーは何しろ人手が足りない。アプリの保守や改修等ならといってくれるところはあったものの、ユーザーからの問い合わせ等の工数を考えると、とてもじゃないが対応しきれないという話になってしまいます。

そこで、大手ベンダのこちらにある開発センターに当たってみました。大手ベンダも数社は地場に開発センターを持っており、ニアショア開発や問い合わせ対応等を行っているところがありました。
その中でようやく1社、条件が折り合いオンサイト支援をやってくれるところが見つかりました。
ただ、かけられるコストも限りがあるので、専任ではなく、問い合わせ時間も限定し、オンサイト対応も月に何回かというように、条件の調整にもけっこうな交渉がありました。

そんなこんなで、開発はオープンソース、アプリ保守は東京の企業、オンサイト運用支援は現地の開発センターという形で運用保守が開始され、今のところ大きな問題なくシステムは動いています。

私はPMOや現地ベンダとの橋渡し的な形で関わらせていただきましたが、どんなによいサービスで、開発がうまくいっても、その後の運用につながらなければ意味のないものになってしまいます。

発注者と開発者だけではサービスはまわらず、運用保守に関わる方や、それらステークホルダーとの調整役がいなければ、サービスは実現できないというおはなしでした。
駆け出しエンジニア必見！IPって？サーバーって？Linux??ネットワーク周りの知識がわからないと転職はきつい

# 対象読者

- web系やIT企業で働くネット周りの知識が浅いすべての書学者
-駆け出しエンジニア
- web形自社開発企業に転職したい

## 概要
最近未経験から自社開発企業に転職を果たし、業務開始1ヶ月。
社内でネットワークの話が飛びかう中ついていけない、、、、、

駆け出しエンジニアのみなさん？プログラミン言語の学習ばかりしていませんか？
就職前にネットワークの知識を曖昧にしていると就職してからとても大変です。
ここですべて勉強しましょう！

## クライアントって？サーバーって？
![スクリーンショット 2021-02-06 13.48.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/825833/c995fafb-66a2-0849-9325-52efc344ed74.png)
まずみなさん例えばyoutbeにアクセスする時ってどうしていますか？
PCやスマートフォンからアクセスしますよね。

まずこのアクセスする側をクライアントといいます。
クライアントはまずyoutbeに向かってyoutubeのデーターをくださーい！！
みたいな感じでいいます。　これをリクエストするといいます。

youtubeのデータがある場所はサーバーです。
サーバーとは...情報やデーターをいつでも提供してくれる提供専用のコンピューター
(※AWSでいうとこれはEC2にあたります)

つまり
クライアント→youtubeのデーターをくれ(リクエスト)
サーバー→youtubeのデータだよ(レスポンス)
クライアント→ありがとーう！！
って感じです

## IPアドレスって？？ドメインって？？DNSって？？

サーバーとクライアントについてはもうわかりましたね。
さっきのはyoutubeのサーバーにアクセスしたって感じだったけど、次はTwitterにアクセスしたい！
ここで出てくる疑問は、クライアントはどうやってアクセスする場所を判断しているの？？

そこで出てくるのがドメインとIPアドレスDNSです！！！

IPアドレス...ネットワークの住所のようなもの
youtubeのIPアドレス... XXX.XXX.XX.XXXX
TwitterのIPアドレス...XXX.XXX.XXxX.xx
みたいな感じでそれぞれにIPアドレスという住所を持っています。

これによってクライアントはアクセスする場所を識別しています！

けどみなさん検索する時、11.333.44.333
見ないな感じでIPアドレス入れて検索することなんてほぼないですよね？笑
そこで出てくるがドメインです。

yotube.com
Twitter.com
簡単にいうとこれがドメインですね。

つまりみなさんが見ているwebサイトやwebアプリケーションはこのIPアドレスとドメインの2種類を持っているということです！

けどあくまで住所を識別しているのはIPアドレスなので、このドメインとIPアドレスを二つ用意してこれらを紐付けて判断しなければいけません。

それをになっているのがDNSサーバーです！
DNS(ドメインネームシステム)...このドメインはこのIPアドレスだよと教えてくれる(この一連の流れを名前交換といいます)
DNSサーバーはこの役割をしてくれるサーバーです.
(※AWSでいうとRoute53にあたります)

図で表すとこんなイメージ
![スクリーンショット 2021-02-06 14.56.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/825833/36dfa7d8-3a75-03df-9891-5a90f6be359e.png)

つまりDNSサーバーがドメインに対するIPアドレスを教えてくれるのでサイトの住所がわかるわけですね！！

クライアントは基本的にIPアドレスは固定されていません。
なぜなら情報を受け取るだけなので固定する必要がないのです。

一方サーバーはIPアドレスが固定されています！
(※AWSのEC2は更新するたびにIPアドレスが変更されてしまう。これを固定するのに使うのがElastic IP address)

## OSって何？？
OS...簡単にいうとスマホやパソコンに搭載されてソフトウェア
代表的なOSはmacOS, WindowsOS, iOS, Androidなどがありますね

実はサーバーにもOSが必要です！！
サーバーによく使われるOSというのが巷で噂のLinuxOSです！！
最初のうちはLinuxOS＝サーバ用のOS程度に覚えておきましょう。

## Linuxとは？？
Linuxは世界で96%も使われているみたいです。
人気な理由として、オープンソース、ディストリビューションでまとめられている。などが挙げられます！！

OSS(オープンソース)...自由にダウンロードして、それを変更して、それをさらに再配布しても良い！！っていうこと(代表的なのはWordPressなど)
ディストリビューション...カスタマイズ済みのLinux（代表的なのはUbuntu, CentOS, EC2 Amazon Linuxなど）

## CUIって？？GUIって？？
サーバーにアクセスするには２種類の方法があります。それがCUIとGUIです！

CUI(キャラクターユーザーインターフェース)...簡単にいうとコマンドから(黒い画面)コンピューターやサーバーに指令を送ることができる
GUI(グラフィカルユーザーインターフェース)...パソコンの画面を触って操作すること
サーバに指令を出すときは基本的にコマンドから指令を送るCUIが使われることがほとんどです！
【Java】 JavaBeans(Form、Entity、Dto)とは

# 概要
Webアプリケーションにおいて、画面のフォームから入力された値や、
DBから取得した値を、どのように保持をし、使用されるかを理解する事で、
Webアプリケーション全体、システム全体についての理解を深める事ができる。

JavaのWebアプリケーションにおいては、**JavaBeans**といったものが上記の役割を担っている。

# JavaBeansとは
データを保存しておくための倉庫のようなもの。

下記のようにプロパティを設定し、プロパティに対するsetter/getterメソッドを持っている。

```Java:PersonBean.java
public class MemberBean {
    private String name;
    private int age;

    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return this.age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
```
上記のようなクラスがJavaBeansとして機能し、
それぞれの役割に応じて、クラス名にPersonForm、PersonDtoといったようなクラス名をつけて使用する。

## Form、Entity、Dtoクラスの特徴

**Formクラス**
・ HTTPのPOSTメソッドで送信された値(=formタグの中身)が入っている。

**Entityクラス**
・ DBに登録・更新する値を入れておく。
・ DBから取得した値を保持しておく。

**Dto(DataTransferObect)クラス**
・データの交換のため使用する。
→FormクラスやEntityクラスの値を直接編集したりすると、元のデータに戻せない場合があるため、
一旦Dtoクラスに入れておき、ビジネスロジック内で値の編集などを行ったりする。

# まとめ
Form、Entity、Dtoクラスは、クラスの構成としてはどれも同じで、
その用途によって名前や役割が異なる。
multipart/form-data なリクエストを VCR でテスト時に VCR::Errors::UnhandledHTTPRequestError で落ちる

## 概要
ファイルアップロードを含む API 通信を Faraday で実装して、 VCR でテストしていた時に、初回のテストは通ったが2回目以降のテスト実行で VCR::Errors::UnhandledHTTPRequestError で落ちた。
既に cassette が存在する場合、リクエストの body との一致まで確認する設定にしている場合、 body 中の boundary は毎回異なるため、2回目以降のテスト実行が落ちてしまう。
気付けば何ということのない話だが、汎用的なエラーメッセージしか出ないと同じリクエストをしようとしているはずなのだけど、と言う先入観に囚われて少し詰まったので記録。

## 暫定的な回避策
該当の RSpec ファイル中での VCR の default_cassette_options を変更して body の確認をしないようにした。

```ruby
VCR.config do |c|
  # 全体設定ファイルでは match_requests_on: [:method, :uri, :body] としていた
  c.default_cassette_options = { record: :once, match_requests_on: [:method, :uri] } 
end
```

これでテスト実行時に作成されるリクエスト中の body が記録した cassette と一致しなくても呼び出されるためテストが通る

## もうちょっとまともな対応をしたい場合
一応それっぽい記事を見つけたのだが、面倒臭そうなので実際には対応していない。恐らく以下の記事を参考にすれば boundary の差分以外を除外したものを比較する対応ができる。
https://www.kabisa.nl/tech/matching-multipart-request-bodies-with-vcr/
【Vue.js】コンポーネントでv-modelを使う方法を図解で理解する。

下記のような、type textのインプットフォームをv-modelを用いてコンポーネント化する。

```vuejs
<template>
  <div>
    <input type="text" v-model="title" />
    <p>{{ title }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      title: "",
    };
  },
};
</script>
```

まずEventTilteというコンポーネントを作成して、フォームをそちらにうつす。

```App.vue
<template>
  <div>
    <EventTitle></EventTitle>
  </div>
</template>

<script>
import EventTitle from "./components/EventTitle.vue";

export default {
  data() {
    return {
      title: "",
    };
  },
  components: {
    EventTitle,
  },
};
</script>
```

```EventTitle.vue
<template>
  <div>
    <input type="text" v-model="title" />
    <p>{{ title }}</p>
  </div>
</template>
```

コンポーネントタグにv-modelを設定する。

```App.vue
<template>
  <div>
    <EventTitle v-model="title"></EventTitle>
  </div>
</template>
```

v-modelはコンポーネントタグに設定された場合、以下のような処理のシンタックスシュガーとなっている。

```App.vue
<template>
  <div>
    <EventTitle :value="title" @input="title = $event"></EventTitle>
  </div>
</template>
```
つまり、inputイベントが発火した場合、イベントオブジェクトをdataのtitleに格納して、value属性をバインドして、titleと同期させている。

つまり、この処理を親と子の相互間でデーターを受け渡せるようにする。

![IMG_311D4E5FF44B-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/b2134643-6139-deac-5be7-ed790a65fdad.jpeg)

1 子コンポーネントでインプットイベント発火
2 \$emitに登録されているinputイベントが発火する。
3 イベントオブジェクトで入力した値を取得し、親コンポーネントの$eventに送られて、titleに格納される。
4 dataのtitleと同期
5 value属性にtitle(入力された値)が格納される。


```App.vue
<template>
  <div>
    <EventTitle :value="title" @input="title = $event"></EventTitle>
  </div>
</template>

<script>
import EventTitle from "./components/EventTitle.vue"

export default {
  data() {
    return {
      title: "",
    };
  },
  components: {
    EventTitle,
  },
};
</script>
```

```EventTitle.vue

<template>
  <div>
    <input
      type="text"
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    />
    <p>{{ value }}</p>
  </div>
</template>

<script>
export default {
  props: ["value"],
};
</script>
```
シンタックスシュガーに置き換えた部分を、v-modelに戻す。

```App.vue
<template>
  <div>
    <EventTitle v-model="title"></EventTitle>
  </div>
</template>

<script>
import EventTitle from "./components/EventTitle.vue";

export default {
  data() {
    return {
      title: "",
    };
  },
  components: {
    EventTitle,
  },
};
</script>
```