OmniAICreator/Qiita-1.07M huggingface dataset:
MATLABでGitを操作しよう (第5回 : リモートリポジトリとの連携 (git push/git pull))

引き続きMATLAB GUIによるGit操作の第5回目
そろそろ佳境に入ってまいりました。
リモートリポジトリとの連携ということで、MATLABを使ってGitHubと連携するとことまでを紹介してみます。

作成環境 MATLAB R2019b
作業前提 GitHubアカウントを作成しておくこと

[第1回 : プロジェクト作成とGUIの説明](https://qiita.com/stozaki/items/e4fa14c36f6c134e53e7)
[第2回 : git add/git commit](https://qiita.com/stozaki/items/4bacb2e988c74f7a16e4)
[第3回 : チェックアウト "特定のコミットに戻る"](https://qiita.com/stozaki/items/e618748b867b6a609333)
[第4回 : ブランチ作成](https://qiita.com/stozaki/items/9711d48b63fcf4be4b20)
**▶ 第5回 : リモートリポジトリとの連携 (git push/git pull)**
第6回 : クローンを作成する
第7回 : 応用1
第8回 : 応用2



今回紹介するのは、以下のフローです。
1. リモートリポジトリとしてGitHubにリポジトリを作成する
2. MATLABプロジェクトを作成する
3. 作成したMATLABプロジェクトとGitHubを連携する

#### 操作1 : GitHubにリポジトリを作成する
GitHubでリポジトリを作成する手順は様々な記事がありますので、検索等をして調べて頂ければ簡単に出来ます。従って本記事では省略し、作成時の画面のみ。
READMEの作成を有効にして、Create repositoryをクリックし完了です。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324583/bf0becee-3d93-f100-c20f-04ce653b596b.png)


#### 操作2 : MATLABプロジェクトを作成する
例によって、MATLABプロジェクトを作成しますが、詳細手順は[**第1回**](https://qiita.com/stozaki/items/e4fa14c36f6c134e53e7)の記事を参照下さい。
プロジェクト作成が完了し、プロジェクトを開く前に「リモート」をクリックします。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324583/abbd9591-f9ed-5b0e-00b5-6a2e6df980c5.png)

作成したGitHubのURLを設定し「検証」をクリックします。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324583/8f968f85-cd64-f1a7-faf9-468ee77089e8.png)

検証済みとなってグリーンのチェックが付けばOKです。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324583/d40e47b8-b89d-951e-b722-412c9e79f0ac.png)

foo.mというダミーの関数ファイルを1つ用意し、プロジェクトに追加`git add`します。
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324583/9a93c6a1-8376-2610-6d32-e3f3575a2770.png)

#### 操作3 : MATLABプロジェクトとGitHub連携
リモートリポジトリで作成したREADME.mdをプルしてみます。
プロジェクトタブの「プル」をクリックします。
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324583/6ba9d811-33dd-1642-ce2c-d09500c38a75.png)
README.mdファイルがフォルダに追加されたことがわかります。
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324583/a30b7198-a0cc-021d-6bb0-8ab8536948ac.png)
README.mdをプロジェクトに追加します。ファイルを右クリックして「プロジェクトに追加」をクリック。
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324583/7e3efb85-e60d-f579-d5fd-09c4f93d9839.png)

foo.mをコミットし、プロジェクトウィンドウのステータスでグリーンのアイコンになったことを確認し、プッシュします。
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324583/c8b138fc-3176-384a-5eec-6f7467fd8310.png)
今回はhttps接続で連携するので、GitHubのIDとパスワードが聞かれます。
入力して、「OK」をクリックします。
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324583/bed30f81-48c9-3541-4650-da1242745a4f.png)

プロジェクトの表示ウィンドウにてGitのステータスが「/origin/master/に一致」となります。
![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324583/38cf5a5c-b218-036a-60f8-66c74a315461.png)

GitHub上で確かにfoo.mが追加されていることを確認して終了となります。
![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324583/8a9e8c01-076f-067e-cdae-0134dc28fbc3.png)

こういったGUIツールはその操作手順のわかりやすさや、見た目の格好良さなども重要かと思います。
操作手順はプロジェクトに追加する操作が`git add`であることを思い出して頂ければ、それほど迷うことは無いかと思います。
アイコンの見た目もシンプルでわかりやすいかと思います。
CloudWatchでのEC2空き容量アラートがめんどくさい

#序章
空き容量をCloudWatchに通知・アラート設定する方法は世に出回っているけど、これインスタンス変えたらメトリックスも変わっちゃうからインスタンスが変わるたびにアラート設定が消える？（**気がする。**）

EC2インスタンスにcron仕掛けるしかない（**気がする。**）

#ということで今回は、お手製のシェルスクリプトでディスク使用率が大きくなったらSNS経由でメールを送って優勝していくことにするわね。
とっくん26歳風
https://www.youtube.com/watch?v=wtinMFr_uxs

#シェルのコード
EC2のどこかにシェルを潜影蛇手！

```bash

#!/bin/sh
#アラート閾値（%）
threshold=95
#送信元SNS
sns_topic_arn="arn:aws:sns:*************"

#dfコマンドの結果を取得、Used列の数値の部分だけ取得
lines=`df -h|sed -e 's/[ \t][ \t]*/ /g'|cut -d ' ' -f 5|sed -e 's/%//g'|grep -e "[0-9]"|bc`
while read line
do
        #もし閾値を超えていたら
        if [ $line -gt ${threshold} ]; then
                #Instance Id
                id=`curl -s 'http://169.254.169.254/latest/meta-data/instance-id'; echo -en "\n"`
                #インスタンスのタグ
                tag=`aws ec2 describe-instances --region ap-northeast-1 --instance-id ${id} --query 'Reservations[].Instances[].Tags[].Value[]' | grep [0-9a-zA-Z] | sed 's/^.*"\(.*\)".*$/\1/'`
                #インスタンスのIP
                ip=`aws ec2 describe-instances --region ap-northeast-1 --instance-id ${id} --query 'Reservations[].Instances[].PrivateIpAddress' | grep [0-9a-zA-Z] | sed 's/^.*"\(.*\)".*$/\1/'`
                #dfコマンド結果
                df=`df -h`
                #メール本文に改行を入れたいので改行を入れて対応（雑）
                body="id:${id}
ip:${ip}
tag:${tag}
df:-----
${df}"
                #送信!!
                aws sns publish --region ap-northeast-1 --topic-arn "${sns_topic_arn}" --message "${body}" --subject "${ip}のディスク使用率が${threshold}%を超えました。"
        fi
done << END
$lines
END
```

リージョンとかは適宜変更してくださいね。

動くことを確認したらcrontab に潜影蛇手！

#まとめ
メモリとかディスク容量とか何もしないでもCloudWatchに自動的に送ってくれるようになったらいいのに。

##キーワード
空き容量　アラート EC2 インスタンスID インスタンスのIP SNS 

##変更点
2020.03.17
・ルートディレクトリだけでなくすべてのディレクトリ/パーティションがチェック対象になるように修正
Windowsのバッチファイル、シェルスクリプトでハマったところ

#今回のテーマ
　前回までの記事でSalesforceの開発組織から自動でメタデータを取得して、バックアップを取るツールを紹介しました。そのツールの作成にあたって、非常に苦労したbatファイルに関して、書いていこうと思います。
###前回までの記事
- [Salesforce組織のメタデータを自動バックアップするツール作ってみた](https://qiita.com/bigyoujdb/items/b0331ad0df5511ec6b6a)
- [SF組織でObjのCRUD権限を時間帯で制限する（Salesforce組織のメタデータを自動バックアップするツール作ってみたその２）](https://qiita.com/bigyoujdb/items/13ea15e8869b4c9dabbd)
- [Salesforce組織のメタデータを自動バックアップするツール作ってみたその3](https://qiita.com/bigyoujdb/items/512a2ac3fb16bf5e2a73)


#batファイルで実行したかったこと
　まず、上記のツールを作成する上でやりたかったことは以下の通り。
・SF組織からメタデータを取得する
・差分をGitCommitする（差分がなければ空コミットする）

とても単純でcmdから実行するには以下のコマンドを順番通り実行すれば、想定通り動作する

```cmd
cd targetdirectory
sfdx force:source:retrieve -u username@mail.com
git add --all
git commit --allow-empty -m"message"

```

とても単純なので、上記を実行するバッチファイルを作成

```backupSFmeta.bat
sfdx force:source:retrieve -u username@mail.com
git add --all
git commit --allow-empty -m"message"
```

そしてのこのファイルを実行すると....
なぜか失敗する。SF組織からメタデータを取得するところまでは、そのあとの処理で落ちる。

#原因
　上記のバッチファイルのように、1つずつのコマンドを実行させると、sfdxの実行後にcmdが実行完了で、
終了してしまっていた。全てのコマンドを1タスクとして実行させるように以下のように記述することで、
sfdxコマンド後にcmdが終了することを回避できた。

```backupSFmeta.bat
sfdx force:source:retrieve -u username@mail.com　& git add --all & git commit --allow-empty -m"message"
```

#他に起きたこと・試したこと
　

1.
windows.batではGitコマンドは使えないのかと思って色々調べたら、batファイルと同様のshファイルをGit bashに渡してあげれば
上手くいくという記事を見つけたので下記のようなことを試しました。

```backupSFmeta.bat
sfdx force:source:retrieve -u username@mail.com
git-bash C/Users/user Name/Desktop/sforg/commit.sh
git add --all
git commit --allow-empty -m"message"
```

```commit.sh
cd targetdirectory
git add --all
git commit --allow-empty -m"message"
```

ここでの問題点
上記のファイルではgit-bashコマンドに引数で渡しているファイルが実行されません。git-bashに引数として渡す実行ファイルを指定する際は

```
git-bash "C/Users/user Name/Desktop/sforg/commit.sh"
```

のようにダブルクオートでくくって上げる必要があります。

2.
windows.bat実行後に、結果が出力されると次のコマンドが実行されないのではないこと思い「@echo off」を付けましたが、
やはり最初のコマンド実行後cmdが終了してしまいました。
上記のように「&」で各コマンドを繋げるしかないようです。

#結論
　コマンドを「&」で繋げないと、最初のコマンドで終了してしまうことがあるという記事が、
なかなか見当たらず、今回はかなり苦労しました。どなたかの役に立てば幸いです。

参考
https://www.adminweb.jp/command/action/index1.html
CocoaPodsでライブラリを簡単に管理する

## この記事に関して
この記事ではCocoaPodsで外部ライブラリを利用する場合の方法を説明していきます。
※CocoaPodsでのライブラリ公開方法に関しては触れていません。

- 想定読者: CocoaPodsを初めて利用する方
- CocoaPodsのバージョン: 1.9.0

## CocoaPodsとは
- SwiftとObjective-CのためのDependency Manager
- 7万以上のライブラリがCocoaPodsから利用可能
- 依存関係はPodfileというひとつのテキストファイルで管理する

## CocoaPodsのインストール方法
下記実行するだけ。CocoaPodsのバージョンをあげたい場合も下記でOK

```
sudo gem install cocoapods
```

## CocoaPodsをプロジェクトで利用開始するには
- プロジェクトのルートディレクトリで `pod init` コマンドをたたく
- `pod init` を実行するとプロジェクト配下に `Podfile` という設定ファイルが作成されているので開く。Podfileに利用したいライブラリとバージョンを記述していく。
  - Podfileの最初の行はサポートバージョンとプラットフォームを記述する
  - targetセクションは `target $TARGET_NAME do` で作成し `end` で終了する

```
platform :ios, '8.0'
use_frameworks!

target 'MyApp' do
  pod 'AFNetworking', '~> 2.6'
  pod 'ORStackView', '~> 3.0'
  pod 'SwiftyJSON', '~> 2.3'
end
```

- Podfileを編集して利用したいライブラリの記述が完了したら、 `pod install` コマンドをたたく
- `pod install` 実行後、依存関係が解決するとワークスペースが自動的に作成されるので、Xcodeでプロジェクトを開いている場合は一度閉じてワークスペースを開き直す
- ワークスペースを開くと、 `Pods` というプロジェクトが新たに作成されていることを確認できる。Podsディレクトリ配下に追加したライブラリが格納される
- 以上でライブラリをimportできるようになる
- 特定のライブラリをRemoveしたい場合は、Podfileからそのライブラリの記述を削除した上で `pod install` を実行するとそのライブラリとの依存関係が解消される

## 既存のワークスペースとCocoaPodsを統合したい場合
- CocoaPodsを利用すると自動的にワークスペースが作成されるが、既にワークスペースを利用しているプロジェクトでCocoaPodsを利用したい場合はどうすれば良いか
  - Podfileのtargetブロックの外側に、ワークスペース名を一行足すだけでOK

```
workspace 'MyWorkspace'
``` 

## `pod install` と `pod update` の使い分け
`pod install` と `pod update` コマンドはどう使い分けるか混同されるケースが多く、 `pod install` はプロジェクトをセットアップする際の最初の1回だけ実行してそれ以降は `pod update` を使用すると思われがちだが、そうとは限らない。原則として **ライブラリを最新バージョンに更新したい場合のみ `pod update` 、それ以外は `pod install` を使用する**  
### `pod install` を実行した場合の挙動
- `pod install` コマンドを実行して新しいライブラリをインストールするたびにPodfile.lockにインストールされたライブラリのバージョンが書き込まれる。 Podfile.lockは各ライブラリのバージョンをトラッキングする
- `pod install` ではPodfile.lockに記述されたバージョンをインストールし、そのライブラリに最新のバージョンがあるかどうかは確認しない
- ライブラリがPodfile.lockにまだ記述されてない場合、Podfileに記述されているライブラリのバージョンを取得する
- CocoaPodsは `pod update` が実行されない限り、Podfile.lockに記述されたバージョンを優先する

### `pod update` を実行した場合の挙動
- `pod update` は特定のライブラリを最新バージョンにあげたい場合のみ実行する
- Podfileで指定したバージョン制限を超えてない場合、最新のバージョンに更新する

## `Podfile.lock` はgit管理に含めよう
- `Podfile.lock` ファイルは `pod install` を実行すると自動的に作成される、ライブラリバージョンをトラッキングするためのファイル  
- 開発チーム内での意図しないライブラリ更新を防ぐためにも、 `Podfile.lock` はgit管理に含めた方が良い
  - 例えばプロジェクトでライブラリCの1.0.0を利用していた場合、ライブラリCが最新バージョンの2.0.0をリリースしていてもPodfile.lockがあることで1.0.0を利用していることが担保される
  - 開発メンバー間で同じバージョンのライブラリを利用していることを担保するには、 `Podfile.lock` をgit管理して `pod install` と `pod update` コマンドを適切に使い分ける必要がある

## Podsディレクトリはバージョン管理すべきか否か
- Podsディレクトリ配下に追加したライブラリが格納される
- Podsディレクトリは公式ではgit管理に含めて `.gitignore` しないことが推奨されいている

### git管理する場合のメリット
- 開発メンバーがCocoaPodsをマシンにインストールしてなくてもリポジトリをcloneしたらすぐにビルドしてアプリを起動できる
- clone元とclone後で利用しているライブラリが同じであることが担保される

### git管理しない場合のメリット
- リポジトリのサイズが小さくなる
- 異なるライブラリのバージョンに依存関係を変更した上でブランチをマージする際などにコンフリクトの心配がない

参考
https://guides.cocoapods.org/
Jasmine、 PromiseでErrorをThrowするメソッドのテスト

Jasmine 3.3

Jasmine 3.3以降だと簡単らしい。まとめると当たり前のメモ、、。
Asyncのメソッドは慣れてないとしんどい。

```javascript:test.service.ts
export class TestService {
  obj: Something

  async test() {
    await func(); 
    //funcメソットで、下が帰ってくるような場合
    //new Promise((reject) => {reject(new Error('Some Error is occured!')); }
  }
}
```

Jasmine 3.3 以降だとexpectAsyncにtoBeRejectedWithのMatcherが利用可能なので、それで簡単に補足可能
https://jasmine.github.io/api/3.3/async-matchers.html

```javascript:test.service.spec.ts
describe('TestService', () => {
let testService: TestService();

  beforeEach(() => {
    testService = new TestService(); //サービスの初期化
  });

  it('test') async () =>{ //とりあえず普通にasync
    await expectAsync(testService.test())
    .toBeRejectedWith(new Error('Some Error is occured!'))
  });
});
```

ExpectAsyncやtoBeRejectedWithを使わないのであれば、テスト側でcatchすれば良い。

```javascript:test.service.spec.ts
describe('TestService', () => {
let testService: TestService();

  beforeEach(() => {
    testService = new TestService(); //サービスの初期化
  });

  it('test') () =>{ 
    testService.test().catch((error) => {
      expect('Some Error is occured!').toEqual(error.message);
    })
  });
});
```

####参考
ここもみておくとヨシ！（猫
https://stackoverflow.com/questions/44876306/jasmine-expecting-error-to-be-thrown-in-a-async-function
https://ja.stackoverflow.com/questions/50706/async%E3%81%AE%E4%B8%AD%E3%81%A7%E3%81%A0%E3%81%91-try-catch%E3%81%8Crejected%E3%81%95%E3%82%8C%E3%81%9Fpromise%E3%82%92catch%E3%81%A7%E3%81%8D%E3%82%8B%E7%90%86%E7%94%B1%E3%81%8C%E3%82%8F%E3%81%8B%E3%82%89%E3%81%AA%E3%81%84
AHC task (3)　CSVを辞書として読み込む

csvを辞書として読み込む際にはDictReaderを使う

```python:DictReader.py
import csv
data = []

with open('stimuliSet.csv', encoding = 'utf-8_sig') as f:
   reader = csv.DictReader(f)
   
   for row in reader:
      data.append(row)
```
Carthageを使用したQuick導入でトラブった話（platform ios指定でビルドできない問題）

# はじめに
自分が最近触り始めたプロダクトで謎の設定によりビルドが成功してたのが、自分が触り始めて失敗するようになったので原因を調査した時のメモになります。

# 先に結論
気が早い人向けに事象と解決策を先に記載します。

* 事象：Bitrise上で`carthage update/bootstrap --platform ios`を実行するとQuickのビルドで失敗する
* 解決策１：--platform iosを外す（苦肉の回避策）
* 解決策2：Quickはcarthageからpodsに切り替える

# Carthageを使用したQuickの導入方法
導入方法については[公式のGitHub](https://github.com/Quick/Quick/blob/master/Documentation/en-us/InstallingQuick.md)上にて説明がある通りですが、ここで軽く説明しておきます。

* Cartfile.privateにQuickを追加する（github "Quick/Quick"、github "Quick/Nimble"）
* carthage updateを実施する
* 対象のtest targetの Link Binary With Libraries に Quick.framework と Nimble.framework を追加する

内容を読む限りは簡単なステップで導入できそうです。

# 実際におきた問題
## 問題1：API rate limit exceeded
Bitrise上で`API rate limit exceeded`のエラーが起きたのがスタートで、調査を開始しました。
これはGithub APIの利用制限に引っかかっただけなので、GITHUB_ACCESS_TOKENを設定すれば良さそうです。
参考：https://qiita.com/watanave/items/c12859b2cb57dc599288

しかしこの調査のとき、プロダクトの方で何故かcarthageの実行を二回行なっていることに気づきました。
一回目がBitriseのworkflowでのcarthage実行、二回目がfastlane内でのcarthage実行になります。
これはおそらく無駄なので、一回目のworkflowでのcarthage実行を削除することにしました。

## 問題2：何故かQuickのビルドで失敗する
二回行なっていたcarthageのうち一つを削除すると、carthageに失敗するようになりました。
調べてみたところこんなissueを見つけました。
https://github.com/Quick/Nimble/issues/702
なんと、Nimbleでは `carthage update/bootstrap --platform ios` のようにplatformを指定すると失敗するようです。
どうやら削除した一回目のworkflowでのcarthageはplatform指定がなく、二回目の方はplatform指定がある模様。
おそらく一回目で成功して、二回目はキャッシュで成功していたのでしょう。
このissueが解決されない限りはplatform指定はできないですね。
ということで、今回はplatform指定を外すか、CocoaPodsに戻すようにしようと思います。
【python】私的作成&利用してる小規模関数(ファイル操作等)

小ネタ的な記事ですが…

pythonは色々な操作がやりやすく、また環境変数「PYTHONPATH」へ作成済みモジュールを配置しておけば
再利用が効きやすいため、細かなスクリプトを作るときには便利な言語です

当記事では、私的に作成、利用している関数について
メモ置きついでに紹介します
(ありきたりな物が多いため、既出の物も多いかと思います)


# ファイル読み込み/書き込み操作

```python
import codecs
def pfreadlines(filename,encoding=None,**args):
    with codecs.open(filename,Mode="r",encoding=encoding,**args) as f:
        ret = f.readlines()
    return ret

def pfwritelines(data,filename,encoding=None,**args):
    with codecs.open(filename,Mode="w",encoding=encoding,**args) as f:
        f.writelines(data)

```

上の関数を一つ呼び出せば、ファイルへの書き込み/読み込みができます
状況に応じてread/writeも作って行けば利便性も上がりそうです

# 複数Replace操作
正規表現での対応も手ですが、そこまでしなくても良い時等に

```python
def replace_all(src,new,*old):
	for i in old:
		src = src.replace(i,new)
	
	return src
```

引数が本来のreplaceと逆なので混同しそうですが…

# 対象dictにキーが見つからなかったとき、新たな要素を追加する
```python
def dict_insert(src,key,value=True):
    if(src.get(key) == None):
        src[key] = value
```

「対象キーが見つからなかった時に～」的な操作が多い時に便利です(でした)


# おわりに
「この操作、こう書くことが出来るよ」とか、「このライブラリめっちゃ便利なのでオススメ」といった物がありましたら
是非コメントお願いします。
クラウドってなんぞや？

そもそもクラウドとはクラウドコンピューティングのことです。

従来のように、パソコンないのアプリケーションやデータを使用するのではなく、インターネットを通じてアプリケーションやデータを使用することを言います。

クラウドとは様々なサービスがありますが、その中でも仕組みを大きく分けると

- SaaS
- PaaS
- IaaS

の三つに分類されます。

# SaaS（サース）とは
Software as a Service
サービスとしてのソフトウェア
を意味することです。
クラウドで提供されるソフトウェアのことを指します。
ユーザー側にソフトウェアをインストールするのではなく、ベンダー（プロパイダ）側でソフトウェアを稼働させ、ユーザーはネットワーク経由でソフトウェアを機能させます。
自由度は低い
提供されているものを使用する。

# PaaS（パース）とは
Platform as a Service
サーピスとしてのプラットフォーム
を意味します。
アプリケーションソフトが稼働するためのデータやプログラム実行環境が提供されるサービスのことを指します。
自由度中
インフラから開発する手間を省きたいけれど、ある程度カスタマイズしたいというときに利用するのが良いでしょう。Google Apps EngineやMicrosoft AzureなどがPaaSです。

# IaaS（イアース）とは
Infrastructure as a Service 
サービスとしてのインフラ
を意味する。

情報システムの稼働に必要な仮装サーバーやハードディスク、ファイウォールなどのインフラをインターネット上のサービスとして提供する形態。

自由度が高い反面、OSやネットワーク知識やセキュリティ関連をも自身で対応しないといけません。
IaaSの例としては、Google Compute EngineやAmazon Elastic Compute Cloudなどが代表的です。
pythonのimaplibでGmailを取得する際のメールボックス選択

pythonの標準ライブラリであるimaplibを用いてGmailを利用する方法は色々紹介されています。
今回はGmailを取得する際のメールボックス選択でつまづいたので、まとめます。

# メールボックスの選択
認証後に、メールの取得をする際には、まずメールボックスを選択する必要があります。
特に設定しないとINBOXが指定された状態になってます。
INBOX以外の送信済ボックスや下書きボックスなどの他のメールボックスに移動するには、以下のメソッドでメールボックス名を指定する必要があります。

[IMAP4.select()](https://docs.python.org/ja/3/library/imaplib.html#imaplib.IMAP4.select)

ここでメールボックス名を調べるには、以下のメソッドでできます。

[IMAP4.list()](https://docs.python.org/ja/3/library/imaplib.html#imaplib.IMAP4.list)

私の環境では、`IMAP4.list()`の結果は以下のようになっていました。

```python

from imaplib import IMAP4_SSL
from pprint import pprint
user = 'xxx'
passwd = 'xxx'
gmail = IMAP4_SSL("imap.gmail.com", '993')
gmail.login(user, passwd)
mboxes = gmail.list()

pprint(mboxes[1])
```
```
[b'(\\HasNoChildren) "/" "INBOX"',
 b'(\\HasChildren \\Noselect) "/" "[Gmail]"',
 b'(\\All \\HasNoChildren) "/" "[Gmail]/&MFkweTBmMG4w4TD8MOs-"',
 b'(\\HasNoChildren \\Trash) "/" "[Gmail]/&MLQw33ux-"',
 b'(\\Flagged \\HasNoChildren) "/" "[Gmail]/&MLkwvzD8TtgwTQ-"',
 b'(\\Drafts \\HasNoChildren) "/" "[Gmail]/&Tgtm+DBN-"',
 b'(\\HasNoChildren \\Junk) "/" "[Gmail]/&j,dg0TDhMPww6w-"',
 b'(\\HasNoChildren \\Sent) "/" "[Gmail]/&kAFP4W4IMH8w4TD8MOs-"',
 b'(\\HasNoChildren \\Important) "/" "[Gmail]/&kc2JgQ-"']
```

ここで、先程の`IMAP4.select()`を使って、例えば送信済ボックスに移動する場合は、以下のように各リストの末尾にある`[Gmail]xxxx`の部分で指定することができます。

```python

gmail.select('[Gmail]/&kAFP4W4IMH8w4TD8MOs-')
```
AHC task (2)　append

末尾に要素を追加するときappend()を使用
[引用元](https://note.nkmk.me/python-list-append-extend-insert/)

```python:append.py
fruitList = ['リンゴ', 'オレンジ', 'ナシ']

print(fruitList)
#['リンゴ', 'オレンジ', 'ナシ']

fruitList.append('ブドウ')
print(fruitList)
#['リンゴ', 'オレンジ', 'ナシ', 'ブドウ']
クローリングした内容の高速重複判断方法

# 目的

クローリングしたデータがデータベースにすでに存在しているかどうか知りたい際に、
対照(select id from database where content like '%クローリングしたデータ%')で重複判断するのは効率が悪いため、
もっと効率が良い判断方法です。

# 流れ
1.クローリングされたデータをハッシュ（hash）化します。
　そのハッシュは数字と英文字で組み合わせた文字列です。SHA-512バリエーションを使い、64ビットに拡張されています

2.ハッシュ文字列の列をユニークインディクスします。

3.クローリングした内容をハッシュする
　mysql関数を使います
　SHA2('My secret passphrase',512)

4.insert ignore into を使ってデータベースに追加します
　insert ignore into (content,content_hash) values ('クローリングしたデータ',SHA2('クローリングしたデータ',512))

5.content_hashはユニークインディクスなので、重複があれば、エラーと判断し、重複したデータは無視（insert ignore into）で処理します。

スピードが速い、誤差が少ないことはメリットです。

# 参考
https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_sha2
https://dev.mysql.com/doc/refman/8.0/en/insert.html
できるだけお金かけたくない人のG検定合格体験記

# G検定って
ディープラーニング周りの資格の中にG検定というものがあります。　（[公式](https://www.jdla.org/business/certificate/?id=certificate_No01)）
曰く，
>ディープラーニングに関する知識を有し、事業活用する人材（ジェネラリスト）

であるかどうかをみるための試験なんだそうです。
これ持ってると，ある程度はディープラーニングってこんなものって知ってますよ！って言っていいって感じだと認識してます。
ディープラーニング初心者はまず勉強して受けてみてもいいんじゃないかって思ってます。
しかしこれ，受験料がめっちゃ高い（後述）。そこでなるべくお金かけずに受験しようとしてみた私の合格体験記書いてみます。

# 受験者
会社員になってディープラーニングを始めた2019年7月の私（DL学習歴８ヶ月）

# 受験のきっかけ
- なんか資格が欲しくなった
- DL知ってます！の実感がほしかった

# 受験までにやったこと
- 2019年５月31日：申し込み開始日当日に意気揚々と申し込み
- 公式ページにのっている模擬問題β版を解いてみる　([模擬問題](http://study-ai.com/generalist/))
- 受けた人の感想ブログ読んで感じ確かめる（[参考にしたやつ](https://wakarublog.com/archives/619)）
- 模擬問題β版を３周くらいして，選択肢に出てくる単語の意味もさらう
- 松尾先生の「人工知能は人間を超えるか」を読む
- 2019年7月6日：受験
- 2019年7月12日：合格通知

受験にあたっていろんな人の合格体験記読んでみたのですが，
本当にさくっと合格したいなら公式の問題集買うのが手っ取り早そうな印象です．

# 受験のTips
- 受験はオンラインです。受験ページの動作確認で一度感覚掴んでみていた方が良いと思います。
- 受験中は何みてもOKです。WEBでも書籍でも調べる準備しておきましょう
- 飛ばしたい問題にチェックをつけて，あとで見直せる機能があります。わかるところをバンバン解いてわからんのはバンバン飛ばしてあとで調べましょう。
- とにかく時間との勝負（120分で226問）

# かかった金額

- 受験料（これはしょうがない）：一般 12,000円＋税 (学生 5000+税) 
- 人工知能は人間を超えるか kindle版　891円 （2020年３月４日現在）


公式テキストだけは意地でも買わんぞと思って取り組みましたが，模擬問題が優秀だったのでなんとかなりました。
松尾先生の本は前々から買ってたのでついでに読みました。ディープラーニングの世界での著名人の名前などを覚える際に参考になります。

# 所感
- 模擬問題が本当に優秀。出る問題がそこにあると言っても過言じゃない。これさえ完璧にすればきっと受かる
- 普段分類問題ばっかりやっているので回帰が全然わかってなかった→わかってない分野を知ることができる
- 法規の問題は知らないことだらけ。ここを試験中調べるのに時間かかった。受験までに余裕ありそうなら調べてみると良い。ホットなのは自動運転系・著作権系の法規
- とにかく時間との勝負

# 終わりに
是非いろんな人の合格体験記参考にされてみてください。
次の試験は2020年３月14日だそうですね。受験される方，残り１０日ファイトです。
[https://www.jdla.org/business/certificate/?id=certificate_No01](https://www.jdla.org/business/certificate/?id=certificate_No01)
数字の入力チェック

自己解決。備忘録

入力チェックで・・・

```hoge.js
var val = '1,000';
var reg = new RegExp('[0-9]+', 'g');

val == val.match(reg); // true

```

↑これがナゾ

```fuga.js
var val = '1000';
var reg = new RegExp('[0-9]+', 'g');

val == val.match(reg); // true

```

↑これはまぁそうかな

```hoge2.js
var val = '1,000';
var reg = new RegExp('^[0-9]+$', 'g');

val == val.match(reg); // false

```

↑こうしたかった

```fuga2.js
var val = '1000';
var reg = new RegExp('^[0-9]+$', 'g');

val == val.match(reg); // true

```

↑これもそらもちろん


```a.js
var mystr = "1,000";
var result = mystr.match(new RegExp('[0-9]+', 'g'));

$('#result').text(result);     // 1,000
$('#result0').text(result[0]); // 1
$('#result1').text(result[1]); // 000
$('#result2').text(result[2]); // null
```


あ、そうか。
「0から9のいづれかの文字を１文字以上含んでいる」から最初のがマッチしていたのね。
「0から9のいづれかの文字**のみ**が１文字以上ある」ではないのね。
pytestのfixtureを別の箇所でライブラリとして読み込みたい(当該環境にはpytestが存在しない可能性がある)


|pytest|URL|
|:--|:--|
|xdistの-nオプションについて|https://qiita.com/cielavenir/items/3f3319f3fa153c16c703|
|デコレータの作り方|https://qiita.com/cielavenir/items/542f7eaa612c6bb9ed90|
|デコレータに引数を渡す|https://qiita.com/cielavenir/items/2c971ca4bc138c375d17|
|部分テストパラメータの値を使ってテストパラメータを生成する|https://qiita.com/cielavenir/items/ce328313a9f0f498cbcb|
|pytestのfixtureを別の箇所でライブラリとして読み込みたい<br>(当該環境にはpytestが存在しない可能性がある)|https://qiita.com/cielavenir/items/8144774a6ac2eca2e2ce|

fixtureを、pytestのデコレータを無視して普通に関数として呼んでも、シグネチャが合っていれば問題なく動作します。

が、pytest自体が存在しない場合には迂回が必要になります。たとえば以下のようにできます。

```py
try:
    import pytest
except ImportError:
    # provide fake pytest function to keep the script still runnable as standalone script
    def null_decorator_or_decomaker(f=None, **decomaker_kwargs):
        if f:
            # decorator
            return lambda *args, **kwargs: f(*args, **kwargs)
        else:
            # decomaker
            def _(f):
                # decomaker_kwargs can be handled
                return lambda *args, **kwargs: f(*args, **kwargs)
            return _
    def null_decomaker(*decomaker_args, **decomaker_kwargs):
        def _(f):
            return lambda *args, **kwargs: f(*args, **kwargs)
        return _
    def null_decorator(f):
        return lambda *args, **kwargs: f(*args, **kwargs)
    class pytest:
        fixture = staticmethod(null_decorator_or_decomaker)
        class mark:
            parametrize = staticmethod(null_decomaker)
            xfail = staticmethod(null_decorator)
        # other function declarations follow if required.

try:
    from _pytest.compat import get_real_func
except ImportError:
    get_real_func = lambda x:x

##### below program runs "without pytest" #####

@pytest.fixture
def fixture1():
    return 1

def fixture2():
    return 2

@pytest.fixture(name='fixture2')
def fixture2_fixture():
    return fixture2()

@pytest.mark.xfail
def test_a(fixture1,fixture2):
    assert True

get_real_func(fixture1)()
fixture2()
test_a(1,2)
```

\# もはやpytestと関係あるかどうか怪しいですが一応タグは付けますか。。

## 210107

fixtureを直接呼ぶことはPytest 4.x以降できなくなったのを今更知りました。。
get_real_funcを使うか、[関数に別名をつける](https://docs.pytest.org/en/stable/deprecations.html#calling-fixtures-directly)のが良いです(別名をつけるのが公式がおすすめしている方法です。たぶんget_real_funcはpytest自体をテストするためのモック)。
PyTorchでFaster R-CNN 物体検出モデルを作成する

PyTorchでFaster R-CNNの物体検出モデルの作成する手順を紹介します。任意のNotebookとGPUの環境があれば実行可能と思いますが、以降ではWatson StudioのNotebookを使用します。

> Watson StudioではGPU版のNotebookは2020年3月現在ベータ版での提供となります。使用する場合は以下リンク先からリクエストすることで使用可能となります。
https://medium.com/ibm-watson/gpu-powered-notebook-is-coming-to-watson-studio-56876f60c056

# 教師データの作成
以下の様なWatsonのロゴマークを物体検出の対象とします。左側が現行のWatsonロゴ(label: watson)、右側がその他のWatsonロゴ(label: watson_others)になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235649/426cc486-2bb4-e5ba-06eb-c02b444e47af.png)

画像のアノテーションツールを使ってロゴを学習させていきます。画像のアノテーションツールはさまざまものがありますが、私は[labelImg](https://github.com/tzutalin/labelImg)を使用しました。導入手順はリンク先の他、色々なところで紹介されているので割愛します。学習のための画像をWeb等で収集した上で、labelImg で watson および watson_others をアノテーションしていきます。アノテーション結果は Pascal VOC 形式で出力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235649/42b58b1f-0648-82dc-ca91-c0e199770b57.png)

学習で使用した画像とアノテーション結果を[Git](https://github.com/schiyoda/FasterRCNN-PyTorch/blob/master/watson_logos.zip)に置いているので、以降のNotebookではこちらをダウンロードして使用可能です。

# 学習
Watson Studioでプロジェクトを作成して、以下リンク先から Notebook を作成します。

https://github.com/schiyoda/FasterRCNN-PyTorch/blob/master/pytorch_rcnn.ipynb

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235649/61d33ed1-19bb-5cc7-c1cc-f67c3e5baab1.png)


Notebookを実行して行くと、Faster R-CNNによるモデルが作成されます。

# テスト
Notebookの最後のセルでいくつかテスト結果を載せていますが、うまく物体検出ができているようです。


|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235649/bbb80d40-2461-23ec-7e2c-556a2bca97da.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235649/1b1b4f48-e6bb-bc68-c03c-34a7ba1a290b.png)|
|---|---|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235649/9c422e9a-d393-a5cc-db8f-ccd5aed40174.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235649/f202b617-60f5-20a1-e9d7-35c1931baa62.png)|

教師データを入れ替えれば、同様の手順で物体検出モデルを比較的少ないコードで実装可能ですので、お試しください。
vagrant up で docker-compose を起動する

## 目的

* Vagrant で構築する VM 内に Docker と docker-compose をインストールし、docker-compose を起動する。

## vagrant-docker-compose プラグイン

shell プロビジョナ等で Docker や docker-compose をインストールして起動しても良いのですが、まさにこういった用途に合ったプラグインがあったのでこれを利用します。

https://github.com/leighmcculloch/vagrant-docker-compose

```sh
$ vagrant plugin install vagrant-docker-compose
```

## ファイル構成

VM の中で `php` イメージを docker-compose で起動するようにします。
ファイル構成は下記のようにしています。

```sh
public/
  + index.php
docker-compose.yml
Vagrantfile
```

index.php は phpinfo() を実行するだけです。

```php
<?php
phpinfo();
```

docker-compose.yml では、`php:7.4-apache-buster` を起動します。volume に `./public` （VM 内では `/vagrant/public`）をマウントしています。

```yaml
version: '3'
services:
  web:
    image: php:7.4-apache-buster
    ports:
      - "80:80"
    volumes:
      - ./public:/var/www/html:cached
```

Vagrantfile では、`docker` プロビジョンと `docker-compose` プロビジョンを指定しています。`run: "always"` を指定しているので、`vagrant up` 実行時に `docker-compose up -d` が実行されます。

```ruby
Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/bionic64"
  config.vm.network "private_network", ip: "192.168.33.30"

  config.vm.provision :docker
  config.vm.provision :docker_compose, yml: "/vagrant/docker-compose.yml", run: "always"
end
```

## 実行結果

`vagrant up` を実行すると、VM が起動し、docker-compose が実行されます。

```
$ vagrant up
(snip)
==> default: Pulling web (php:7.4-apache-buster)...
    default: 7.4-apache-buster: Pulling from library/php
    default: Digest: sha256:c496c0f962eaaea0f52d9c068bf331fe477703d4657f99b955a2a35a4c3486c4
    default: Status: Downloaded newer image for php:7.4-apache-buster
```

ブラウザで、VM の IP にアクセスすると phpinfo() の結果が表示されます。

<img width="769" alt="スクリーンショット 2020-03-04 17.52.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12272/a31bdd14-0217-c8dc-38b8-81fa90205a15.png">
Catalyst 2960Xでのインターフェイスに対するspanning-tree portfast、bpduguard、bpdufilterの動作検証結果

# 背景
Catalyst2960Xの2つのポートに spanning-tree portfast、bpduguard enable、bpdufilter enable を設定し、そのポートを同じ8ポートスイッチに接続するとループとなりブロードキャストストームが発生する。この挙動について一部不明瞭な点があったのであらためて検証機で検証した。

### 前提条件
・Catalystには spanning-tree mode rapid-pvst コマンドを投入
・LANケーブルを接続する各ポートはVLAN100、スイッチポートとする

### 構成
Catalystと8ポートスイッチを2本のLANケーブルで接続

### テストケース
GigabitEthernet0/1-2、3-4...と奇数-偶数のポートに同じ設定を投入する。

・テストケース1
　portfastとbpduguardを設定

　Gi0/1-2
　　switchport access vlan 100
　　switchport mode access
　　spanning-tree portfast
　　spanning-tree bpduguard enable

・テストケース2
　portfastのみ設定

　Gi0/3-4
　　switchport access vlan 100
　　switchport mode access
　　spanning-tree portfast

・テストケース3
　bpduguardのみ設定

　Gi0/5-6
　　switchport access vlan 100
　　switchport mode access
　　spanning-tree bpduguard enable

・テストケース4
　bpdufilterのみ設定

　Gi0/7-8
　　switchport access vlan 100
　　switchport mode access
　　spanning-tree bpdufilter enable

・テストケース5
　ポートにspanning-treeコマンドを設定しない

　Gi0/9-10
　　switchport access vlan 100
　　switchport mode access

・テストケース6
　portfast、bpduguard、bpdufilterを設定

　Gi0/11-12
　　switchport access vlan 100
　　switchport mode access
　　spanning-tree portfast
　　spanning-tree bpdufilter enable
　　spanning-tree bpduguard enable

・テストケース7
　portfastとbpdufilterを設定

　Gi0/13-14
　　switchport access vlan 100
　　switchport mode access
　　spanning-tree portfast
　　spanning-tree bpdufilter enable

・テストケース8
　bpdufilterとbpduguardを設定

　Gi0/15-16
　　switchport access vlan 100
　　switchport mode access
　　spanning-tree bpdufilter enable
　　spanning-tree bpduguard enable

### 結果

|テストケース1|bpduguardにより片方のポートがerrdisabledとなりループとならない|
|---|---|
|テストケース2|rapid-pvstにより片側のポートがブロッキングとなりループとならない|
|テストケース3|bpduguardにより片方のポートがerrdisabledとなりループとならない|
|テストケース4|pbdpfilterによりBPDUの送受信が停止するためループとなる|
|テストケース5|rapid-pvstにより片側のポートがブロッキングとなりループとならない|
|テストケース6|pbdpfilterが優先されループとなる（bpduguardは無視される）|
|テストケース7|pbdpfilterが優先されループとなる|
|テストケース8|pbdpfilterが優先されループとなる（bpduguardは無視される）|

### 追加検証

①片方のポートにbpdufilter enable、もう片方のポートは設定なしで8ポートスイッチと接続
→ループとなる

②Catalystと8ポートスイッチを1本のケーブルで接続し、8ポートスイッチの2つのポートをループ接続する
→Catalystのポートがスパニングツリーのブロッキングとなりループにならない

### 結論

ループ構成となるいずれか1つのポートに spanning-tree bpdufilter enable コマンドが設定されているとBPDUの送受信がストップされループ構成となる。たとえbpduguard enableが設定されていたとしても無視される。
LaravelでSelect2とBootstrap4を使って、バリデーションエラー時に赤枠で囲む

#やりたいこと
Laravelでバリデーションエラー時に赤枠で囲んでエラーであることを示したい

#やり方
##セットアップ
まずはSelect2インストール
CDN使うならとばします

```
npm i select2
```

select2を適用する
適当にbladeにselect作って適当なクラスを作りました

```html:hoge.blade.php

<select name="hoge" class="js-attachSelect2">
    <option value=1>テスト1</option>
    <option value=2>テスト2</option>
    <option value=3>テスト3</option>
</select>

```
`resources/js/assets/app.js`と同階層に適当なjsファイル作成して`app.js`で読み込みます

```js:app.js
import './bootstrap';

import './select2Test';

```
select2の適用

```js:select2Test.js
import select2 from "select2";
$(function(){
    $('.js-attachSelect2').select2();
})
```

ここで、ようやくバリデーションエラー時の対応を書いていきます
普通ならこれで、bootstrapの赤枠が表示されますが
一瞬表示されて、select2が適用され見えなくなります

```html:hoge.blade.php

<select name="hoge"
        class="js-attachSelect2 @error('hoge') is-invalid @enderror">
    <option value=1>テスト1</option>
    <option value=2>テスト2</option>
    <option value=3>テスト3</option>
</select>

```

selectの一つ親要素にエラー表示のクラスをつけるとうまく表示されます
bootstrap4だと`is-invalid`

```html:hoge.blade.php
<div class="@error('hoge') is-invalid @enderror">
     <select name="hoge" class="js-attachSelect2">
         <option value=1>テスト1</option>
         <option value=2>テスト2</option>
         <option value=3>テスト3</option>
     </select>
</div>

```

これで赤枠が表示されます。
select2側でデフォルトで色が定義されてるのですが、bootstrapより濃いので修正します

```scss:app.scss
.is-invalid {
    .select2-container--focus .select2-selection,
    .select2-container--open .select2-selection {
        -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
        box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
        border-color: #ff0906;
    }
    .select2-dropdown,
    .select2-selection {
        border-color: #ff0906;
    }
}

```

でbootstrapっぽい色になった。
AWS Session Managerでinstance idをいちいち調べるのがだるい

aws ssm start-session は大変に便利なんだけど instance idをいちいち調べるのがだるい
サーバの名前からpecoで選んで繋げるようにする

```bash
#!/bin/bash

# 必要なら aws ec2 commandでリストアップする 基本重いからベタ書き
target_server_name=$(peco --prompt "Select server to start-session >" << EOS
server-a
server-b
server-c
EOS
)

if [ -z "${target_server_name}" ]; then
  exit
fi

instance_id=$(aws ec2 describe-instances --filter "Name=tag:Name,Values=${target_server_name}" --query "Reservations[].Instances[?State.Name == 'running'].InstanceId[]" --output text)

aws ssm start-session --target "$instance_id"
```
Laravel @include したファイルで変数の値を表示させる方法

## Laravel6 で @includeしたファイルに引数を渡して、include先でデータ表示させたい場合

コードを使いまわしたいときって、部分的なviewファイルを用意して別の複数ファイルから呼び出したくなりますよね。
そんなときに @include が便利です。


[公式ドキュメント](https://laravel.com/docs/6.x/blade#including-subviews)では
includeの呼び出し元の記述方法については明記されています。

```
@include('view.name', ['some' => 'data'])
```

これを応用して、 `template.blade.php` ファイルに `$data` 変数を渡して読み込みたいときは以下のように記述すればいいです。

```qiita:呼出し元の記述方法
@include('template', ['data' => $data])
```

読込まれるtemplateビューファイル

```php:tamplate.blade.php
<!DOCTYPE html>
 <body>
   今日の日付は{{ $data }}です。
 </body>
</html>
```

と、ここまではすんなり理解できます。

しかし、肝心の読込んだ templateビューで$dataは下記の様にコードがそのまま表示され、
Laravelの記述方式では表示できない。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531595/2838e68d-59b3-7011-84a2-3e1c0098bf24.png)

なんでや？
ちなみに `{{ $data }}` は `echo $data;`の省略形なので表示されていいはずです。
少しファイルをいじって、試しに@php~@endphpで記述してみました。

```qiita:tamplate.blade.php
<!DOCTYPE html>
 <body>
   今日の日付は@php echo $data; @endphpです。
 </body>
</html>
```

しかし、これも適切に読み込んでくれず

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531595/52ad20c1-68d4-369b-798d-0fa016e999ac.png)

となりました。

つまり、includeされるビューファイルを
###Laravel表記では読み込んでくれない。
というわけで
標準のphp形式でコードを書いてみました。

```qiita:tamplate.blade.php
<!DOCTYPE html>
 <body>
   今日の日付は<?php echo $data; ?>です。
 </body>
</html>
```
とすると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531595/12a4729b-932b-6169-5fd3-836462f7e520.png)

無事、表示されました！

includeされる側での記述方法について明記されていません。

これは、こういう仕様なのでしょうか？
「そんなことないはず！」
という方は@includeする際の注意点を教えてもらえると嬉しいです。
我が家にGravio HubがやってきたのでSSHを通して設置した

我が家にGravio Hubのサンプル機をいただいたのでいろいろやってみることにした。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/9cfec675-187b-5506-c839-4bab2086b7fa.jpeg" width="320">

# 初期設定
初期設定はこちらの手順に従えばそれほど難しくありません。現在（2020/3/4）は設定ツールはAndroid版のみです。 → [Gravio Hubの初期設定](https://doc.gravio.com/manuals/gravio-setup-guide/1/ja/topic/initalsetting)

# SSHを使えるようにしておく
Gravio HubにはHDMI/USB接続用のアダプターが同梱されてますので、電源のUSB-Cとの間に接続すればLinuxとしてコンソールを見ることができます。しかし、我が家にはそもそもUSB接続のキーボードもマウスもありません。なので、SSHの口を開けて置かなければアップデートできませぬ。。
そこで、会社でモニターとキーボード・マウスをつなぎ、こちらを参考にSSHの口を開けておきます。 → [Gravio HubへのSSHでの接続方法](https://doc.gravio.com/manuals/gravio-setup-guide/1/ja/topic/how-to-use-ssh-for-gravio-hub)

まずは上記のサイトの通り、コンソールにログインし、コンソールで `/etc/ssh/sshd_config` を編集して、 `DenyUsers`の行をコメントアウトすればOKです。

```text:/etc/ssh/sshd_config
...
# Authentication:
#DenyUsers gravio
...
```

# ホスト名の変更
ついでにわかりやすいようにホスト名を変更しておきました。

```bash
$ sudo hostnamectl set-hostname ghub.local
```

Gravio Hubではavahiサービスがインストールされてますので、こうしておけばDHCPでIPが変わってもmDNSで見つけることができるんですね。

# 我が家で再設置
我が家に帰って、もういちどGravioHub ToolsでWiFiの設定。
SSHで接続できました。
![gravio-ssh.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/05e612b6-51fd-8016-1e69-316172522658.png)
Gravio Studioからも発見！
![list.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/8a58a2e4-ee7f-8508-d10d-c8e1722e9d76.png)
これで準備完了です。
Alloyでパズル (2) 数独

ネットで見かけた数独の例は、妙に難しい書き方になっていた。
しかし自分で書いてみたら、シンプルなルールはシンプルに書けた。
たぶん、当時は Table View がなくて見やすい形にできなかったのだろう。

ルール説明とかいらないだろうと思うので、いきなりリストを。

```:puzzle2.als
/* 数独 */

// 行内各列(r1.c1, r1.c2, r1.c3, ...)の値はすべて異なる (左のdisj)
// 各行同列(r1.c1, r2.c1, r3.c1, ...)の値もすべて異なる (右のdisj)
abstract sig Row {disj c1,c2,c3,c4,c5,c6,c7,c8,c9: disj (1+2+3+4+5+6+7+8+9)}
one sig r1,r2,r3,r4,r5,r6,r7,r8,r9 extends Row {}

fact {
    // 各 3x3 領域の数字はそれぞれ９種類
    #(r1+r2+r3).(c1+c2+c3) = 9
    #(r1+r2+r3).(c4+c5+c6) = 9
    #(r1+r2+r3).(c7+c8+c9) = 9
    #(r4+r5+r6).(c1+c2+c3) = 9
    #(r4+r5+r6).(c4+c5+c6) = 9
    #(r4+r5+r6).(c7+c8+c9) = 9
    #(r7+r8+r9).(c1+c2+c3) = 9
    #(r7+r8+r9).(c4+c5+c6) = 9
    #(r7+r8+r9).(c7+c8+c9) = 9
}

例: run {
    r1.c1=4 && r1.c4=1 && r1.c9=8
    r2.c2=7 && r2.c3=8 && r2.c5=6 && r2.c7=4 && r2.c8=2
    r3.c9=3
    r4.c6=7
    r5.c2=3 && r5.c5=2 && r5.c6=1
    r6.c5=5
    r7.c1=2 && r7.c2=5 && r7.c4=4 && r7.c8=3 && r7.c9=1
    r8.c3=6 && r8.c5=3 && r8.c8=8
    r9.c6=6 && r9.c7=5 && r9.c8=7
} for 5 int

ノーヒント: run {} for 5 int
```
結果の見やすさを求めて整数1〜9を使うようにしたので、9を表せる5ビット整数（`for 5 int`）を指定した。

例 を実行して Table View で見ると以下のように表示される。
　　<img width="296" alt="数独例.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20005/ec37c546-fed5-6923-fab1-0a1fccba6cc5.png">
解くのに１秒もかからないので「`r1.c1=1 && r2.c2=2 && ... && r9.c9=9`に解はあるのか」など、気になったらすぐに試せる。

例えば..　[本当に解ける人いるの？ フィンランド人数学者が作った“世界一難しい数独”が発表される](https://rocketnews24.com/2012/07/03/22654/)

```alloy
世界一難しい: run {
    r1.c1=8
    r2.c3=3 && r2.c4=6
    r3.c2=7 && r3.c5=9 && r3.c7=2
    r4.c2=5 && r4.c6=7
    r5.c5=4 && r5.c6=5 && r5.c7=7
    r6.c4=1 && r6.c8=3
    r7.c3=1 && r7.c8=6 && r7.c9=8
    r8.c3=8 && r8.c4=5 && r8.c8=1
    r9.c2=9 && r9.c7=4
} for 5 int
```
瞬殺。
　　<img width="369" alt="世界一難しい.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20005/dec8680a-869a-53fc-69ca-ac89869940f0.png">
「数独が難しいとか意味わかんない」（Alloyさん談）
controller.rbでのコードをまとめかた

##コードをまとめかた
controller.rbの記述が繰り返し書かれているときは、before_actionを使用して、メソッドとしてまとめます。
【例】モデル名がPostのとき

```app/controllers/posts_controller.rb
class TweetsController < ApplicationController

  def index
    @posts = Post.all
  end
〜略〜
  def show
    @post = Post.find(params[:id])
  end

  def edit
    @post = post.find(params[:id])
  end

  def update
    post = Post.find(params[:id])
    post.update(post_params)
  end

〜略〜
end
```
上記の記述だとshowとeditの中身が一緒なので、before_actionを使用します。
##before_action
コントローラのすべてのアクションで実行の前に共通の処理を行いたいときに、before_actionを使用すると全てのアクションが実行される前に指定したメソッドを呼び出すことができるのが。before_actionです。
resourcesと同様にonlyやexceptでどのアクションの時に呼び出すか限定することができます。
今回はshowとeditをset_postメソッドで定義していきます。

【例】

```
before_action :処理させたいメソッドの名前
```

```app/controllers/posts_controller.rb
class TweetsController < ApplicationController
  before_action :set_post, only: [:edit, :show]

  def index
    @posts = Post.all
  end
〜略〜
  def show
  end

  def edit
  end

  def update
    post = Post.find(params[:id])
    post.update(post_params)
  end

〜略〜

  def set_post
    @post = Post.find(params[:id]) 
  end
end
```
上記のようにshowとeditをset_postとbefore_actionを使いまとめてみました。
##move_to_メソッド
ユーザーがログインしていないときにindexアクションにリダイレクトするときはmove_to_メソッドを使います。

```app/controllers/posts_controller.rb
class TweetsController < ApplicationController
  before_action :set_post, only: [:edit, :show]
   before_action :move_to_index, except: [:index, :show]

  def index
    @posts = Post.all
  end
〜略〜
  def show
  end

  def edit
  end

  def update
    post = Post.find(params[:id])
    post.update(post_params)
  end

〜略〜

  def set_post
    @post = Post.find(params[:id]) 
  end

  def move_to_index
    redirect_to action: :index unless user_signed_in?
  end
end
```
indexアクションにアクセスした時、indexアクションへのリダイレクトを繰り返し無限ループが起こるので、except: :indexを付け加え、ログインする必要はないものはexcept: [:index, :show]としています。
unless user_signed_in?で判定をして、その返り値がfalseだった場合に手前の式を実行するということになります。
なのでユーザーがログインしていない時にはindexアクションを実行します。
[PHP]Allowed memory sizeの原因がくだらなかった

##[PHP]Allowed memory sizeの原因がくだらなかった

100万件のCSVをPHPで読み込むために、メモリ上限を1024MBに変更したが、
相変わらずメモリエラーが発生するのはなぜだろう。

```
Allowed memory size of 2097152 bytes exhausted (tried to allocate 1052672 bytes)
 in C:\Users\user_name\htdocs\hoge.php on line 32
PHP Stack trace:
```

よく見ると、php.iniでmemory_limiを1024MB と書いていた。
MBと書いたことが原因っぽい。

```php
memory_limit = 128M
```
MB→Mに書き直したら正常に処理できた。（というかデフォルトに戻した）
当たり前すぎるが他にも同じ理由でエラー起こす人がもしかしたらいるかもしれない
ので投稿しました。僕はこれで数日つまづいていました（笑）
Processingで初めて0から作ったプログラム【その２】

どうも私です。
今回は「Processingで初めて0から作ったプログラム【その２】」ということで書いていきます！生温かい目で見守ってください。
#前回のおさらい…
前回の記事：[Processingで初めて0から作ったプログラム【その１】][link1]
[link1]:https://qiita.com/KURIeIGHT/items/9d314f63f310ac05ae04?fbclid=IwAR3dW-Nb9ezyz22Z_dCV1Eng4a7zo2sE4cEBXpvxt5cuMDDOKayA4dSorZY

「画像認識による楽譜の読み取りシステム」の手順を追って説明してましたね。
もう一度手順のおさらいをしましょう。
**1.**楽譜の五線を検出
**2.**音符の検出
**3.**音の出力
（ProcessingとOpenCVを使って開発）
こんな感じですね

前回は五線を画像に処理（グレースケール化＆エッジ検出）を施してHough変換（直線を検出するもの）し、五線を検出しました。

さらに検出した直線のY座標を配列に格納しました。

#音符の検出
今回は**音符の検出**について書いていきます！

音符検出の手順
テンプレートマッチングというのを用いて音符を検出します。
**1.**入力画像から検出したいところを指定
**2.**テンプレートマッチング
**3.**一番類似度の高かった結果を表示する

#####テンプレートマッチングとは
入力画像中からテンプレート画像（部分画像）と最も類似する箇所を
探索する処理。
もう一度言いますよ**最も類似する箇所**です！

楽譜にある音符は、皆さんご存知の通り音符は1つだけじゃないんです！
たくさんあるんです！！
１つだけ検出されるだけじゃダメなんです。

でもこのテンプレートマッチング…ちょっと処理を変えるだけで複数検出可能なんです！
（具体的には類似度が一番高いやつを検出する処理を消せばいいだけ、MaxやMinが書いてある部分）

これで複数検出ができる！と考えるのはまだ早いです。まだ油断できません…
たしかに、複数検出できると思いますが、このままだと同じ音符を何回も検出してしまいます。

その音符が画像内のどこにあるかを知るために検出しているわけで、同じの音符が複数検出されてしまっては、printlnした時のデータ量が大変なことになり、欲しいデータが得られなくなってしまいます。

それを防ぐために、検出される音符のX座標を**±10**の範囲内とY座標を**±50**の範囲内の値で制限してます。

ここまでして、やっと音符を１つ１つ検出できます。


ここまでやってきたことをコードを追っておさらいをしましょう。

```java:Gakuhu.java 
  // 入力画像の準備
  PImage inputImage2 = loadImage(“Gakuhutest1.gif”);
  OpenCV inputCV = new OpenCV(this, im);
  Mat inputMat = OpenCV.imitate(inputCV.getGray());//←グレースケール化です
  // テンプレート画像の準備
  PImage templateImage = inputImage2.get(141, 173, 15, 15);
  // 入力画像の一部を切り出し
  templateImage.filter(BLUR, 1);
  OpenCV templateCV = new OpenCV(this, templateImage);
  Mat templateMat = OpenCV.imitate(templateCV.getGray());
  // 結果格納用の行列の準備
  int resultCols = inputMat.cols() - templateMat.cols() + 44;
  int resultRows = inputMat.rows() - templateMat.rows() + 44;
  Mat resultMat = new Mat(resultRows, resultCols, CvType.CV_32FC1);
  // テンプレートマッチングを実行
  Imgproc.matchTemplate(inputCV.getColor(), templateCV.getColor(), resultMat, Imgproc.TM_CCOEFF_NORMED);
  // 結果を描画
  image(opencv.getOutput(), 800, 0);
  image(inputImage2, 100, 0);
  image(templateImage, 10, 10);

//中略

    if (data[0] > 0.7) {
    //類似度が70%以上
        for (int l=0; l<k; l++) {
          if ((h < x[l]+10 && h > x[l]-10) && (j < y[l]+50 && j > y[l]-50)) {
          //検出される音符のX座標とY座標の値を制限
           
          }
        }
```

検出した画像がこちら！
実行結果：https://drive.google.com/file/d/1vIqHmL-3ZbmaRO5S7Y-vujLGveN5v9To/view?usp=sharing

こちらもX座標Y座標を配列に格納してあります！！

######いままでで判明したもの。
・五線のY座標を格納した配列。
・音符のXY座標を格納した配列。
第二ステップ完了、やったー！！

次回はついに音の出力！！
お楽しみに！
Dockerfileで親ディレクトリにあるファイルを参照できない問題

# 現象
```
├── nginx
|   └── Dockerfile
├── statics
├── Dockerfile
└── docker-compose.yaml
```

Dockerfileから親ディレクトリにあるファイルを参照しようとしてもできませんでした。

```docker:nginx/Dockerfile
FROM nginx
ADD ../statics /var/www/
CMD ["nginx", "-g", "daemon off;", "-c", "/etc/nginx/nginx.conf"]
```

```
$ docker-compose up --build
Building nginx
Step 1/4 : FROM nginx
 ---> be1f31be9a87
Step 2/4 : ADD statics /var/www/
ERROR: Service 'nginx' failed to build: ADD failed: stat /var/lib/docker/tmp/docker-builder740600385/statics: no such file or directory
```
`ADD`で失敗してしまいます。

# 解決
docker-compose.yamlで`context`を親ディレクトリを含むようにすることで、ファイルを参照できるようになりました。

```yaml:docker-compose.yaml
version: '3'
services:
  nginx:
#    build: ./nginx
    build: 
      context: .
      dockerfile: ./nginx/Dockerfile
    container_name: proxy
    ports:
      - 80:80
  api:
    build: .
```
```docker:nginx/Dockerfile
FROM nginx
# ADD ../statics /var/www/
ADD statics /var/www/
CMD ["nginx", "-g", "daemon off;", "-c", "/etc/nginx/nginx.conf"]
```
Collider周りの備忘録

Colliderを子オブジェクトに持たせた時とかの操作を忘れそうなのでわかったことをまとめる
忘れたくないことは多分追記していく
#親がRigidbodyを持ってる
##Collisionを使う
引数の型はCollision
Rigidbodyを持ってる親オブジェクトがCollisionに格納される
子がRigidbodyを持っていたら子が格納される
親オブジェクトを参照したいとき、Rigidbodyが親にのみアタッチされているなら

```C#:Collision.cs
void OnCollisionEnter(Collision collision)
	{
		GameObject obj = collision.gameobject;
	}
```

でいいと思う
##Triggerを使う
引数の型はCollider
colliderが直接アタッチされているオブジェクトがcolliderに格納される
この場合子オブジェクトが格納される
から親オブジェクトを参照したかったら

```C#:Trigger.cs
void OnTriggerEnter(Collider collider)
	{
		GameObject obj = collider.gameobject.transform.parent.gameobject;
	}
```

とかにする
まちがってたら教えてください
macOS 10.15 CatalinaでAnacondaをインストールしようとしたらハマった

macOS 10.15 CatalinaでAnacondaをインストールしようとしたらハマったのでその事象と解決策を書いておきます。

## 前提

* macOS 10.15.3 Catalina
* `Anaconda 2019.10 for macOS Installer (Python3.7)` を使ってanacondaを入れる。
  * 今回はちょっと触ってみたいだけなので出来るだけpyenvとかの世話にはならない。

## 事象

MacでのAnacondaでのインストールは基本的に以下の手順です。 ref:[公式ドキュメント](https://docs.anaconda.com/anaconda/install/mac-os/)

1. GUIインストーラでぽちぽちOKを押す。
2. Spotlight SearchからAnaconda Navigatorを起動できればOK。

<img width="744" alt="スクリーンショット 2020-03-04 16.31.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85822/dcad1e70-b093-109d-0800-d578d20e7b0c.png">

この画面が出ればOKです。簡単ですね。

で、私はSpotlight SearchからAnaconda Navigatorを起動しようとした時点で以下の表示が出ました。

```
[15:59:06]% /Users/{user_name}/opt/anaconda3/pkgs/anaconda-navigator-1.9.7-py37_0/bin/anaconda-navigator ; exit;
zsh: /Users/{user_name}/opt/anaconda3/pkgs/anaconda-navigator-1.9.7-py37_0/bin/anaconda-navigator: bad interpreter: /opt/anaconda1anaconda2anaconda3/bin/python: no such file or directory
```

:confounded: ひぇ〜

## 原因

そもそもAnacondaのGUIインストーラ君はなにをしてるのでしょうか？
彼がやってることは（今回の問題に関係するところだと）大きく２つです。

1. `~/opt/anaconda3` 配下に、 Python本体やライブラリなど配置する。
2. `~/.bash_profile` にPATHなどの設定を追記する。

`~/.bash_profile`に入る内容は具体的に以下。

```bash
# added by Anaconda3 2019.10 installer
# >>> conda init >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$(CONDA_REPORT_ERRORS=false '/Users/{user_name}/opt/anaconda3/bin/conda' shell.bash hook 2> /dev/null)"
if [ $? -eq 0 ]; then
    \eval "$__conda_setup"
else
    if [ -f "/Users/{user_name}/opt/anaconda3/etc/profile.d/conda.sh" ]; then
        . "/Users/{user_name}/opt/anaconda3/etc/profile.d/conda.sh"
        CONDA_CHANGEPS1=false conda activate base
    else
        \export PATH="/Users/{user_name}/opt/anaconda3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda init <<<
```

で、実はMacのデフォルトのシェルはCatalinaでbashからzshになりました。
`~/.bash_profile` 読まれないじゃ〜んという話です。

というか、私が上に書いたエラーはそもそも `~/opt/anaconda3/bin/` 配下のanaconda-navigateではなく、
`/Users/{user_name}/opt/anaconda3/pkgs/anaconda-navigator-1.9.7-py37_0/bin/anaconda-navigator` を参照してます。
なんでやねん。

## 解決策

1. `~/.bash_profile` に追記されてた内容を `~/.zshrc` にコピーする。
2. ターミナルで `env | grep PATH` あたりで `~/opt/anaconda3/bin/`にPATHが通ってるのを確認しましょう。
3. ターミナルから `anaconda-navigator` を実行すればOKです。

## 落ち（この記事を書いたあとに気づいたこと）

公式ドキュメントにもありますが、実はLaunchPadにもショートカットが追加されていて、そこからAnaconda-Navigatorを起動すると `~/opt/anaconda3/Anaconda-Navigator` を参照して起動するようです。Anaconda-Navigatorが色んな所にあり過ぎでわ。
まぁcondaコマンドとかを使うときに結局PATHを通す必要があるので、 `~/.bash_profile` からの移植はやっておいたほうが良いと思います。

## 参考

1. [Anaconda を macOS にインストールする手順](https://weblabo.oscasierra.net/python-anaconda-install-macos/)
2. [macOS 10.15 Catalina でターミナルのやつが zsh になった
](https://mac-ra.com/catalina-zsh/)
AWS キャッシュ活用 ElastiCache

#ElastiCacheとは
AWSが提供するインメモリー型データベースサービス。
ElastiCacheはAZサービスでVPCのサブネットグループに配置する。
ElastiCacheのユースケースとしては、RDSへのクエリ結果をキャッシングしてRDSへのアクセス負荷を軽減することにより、DBの読み書きの性能向上させる。
##キャッシュ とは
一度利用したデータなどを、その後また使う場合に高速にアクセスできるような形で保存しておくこと。

Webブラウザは、一度閲覧したページやそのページで使われている画像をキャッシュとしてハードディスクに保存している。同じページをあとから見る場合や、一度表示した画像やCSSファイル、JavaScriptファイルが他のページでも使われている場合には、改めてサーバーと通信してデータを取得するのではなく、ハードディスクから読み込むことで、表示を高速化している。

###インメモリキャッシュ?
「インメモリ・キャッシュ」とは**メモリ**を活用して高速にキャッシュへのアクセスを可能にしたデータベースの仕組み

<img width="788" alt="スクリーンショット 2020-03-04 16.24.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522222/a205e768-d712-debf-8036-37a481ebcf65.png">

メインメモリキャッシュのデプロイ、運用、スケーリングをクラウド内で簡単に実行できるウェブサービスです。
このサービスは、低速のディスクベースのデータベースに完全に依存せずに、高速の管理されたメモリ内のキャッシュから情報を取得できるようにすることで、ウェブアプリケーションのパフォーマンスを向上させます。
<img width="940" alt="スクリーンショット 2020-03-04 15.41.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522222/502da629-17e9-81b7-5084-ddae4bc90c80.png">
<img width="1285" alt="スクリーンショット 2020-03-04 16.22.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522222/5dd68e8c-4f4c-dbb7-4104-bd2410c89d2a.png">

Amazon ElastiCacheは、**KVS型**のnoSQLである**Memcached**と**Redis**のプロトコルに準拠しているので、幅広い用途に使うことができます。

##Memcached
<img width="657" alt="スクリーンショット 2020-03-04 16.44.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522222/eb605247-f6e4-de22-155a-d73ba93397cb.png">

 高速に値をRead/Writeできるインメモリキャッシュ型DB

 マルチスレッドで動作するインメモリキャッシュDB

 スナップショット機能がない

 データを**永続化できない**

 フェイルオーバーや復元ができない

Memcachedはシンプルなデータ（string）のみしか格納できません。よって、それ以外のデータを保存する場合にはアプリケーション側で格納できる型に変更する必要があります。また、扱えるコマンドも必要最低限しかなく、ほとんどデータの追加、削除以外は使わないと考えてよいでしょう（一応、データの変更や追記も可能です）。
##Redis
<img width="788" alt="スクリーンショット 2020-03-04 16.43.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522222/bed07e6c-0692-0c85-b7de-88b44c4b1259.png">

 高速に値をRead/Writeできるインメモリキャッシュ型DB

 シングルスレッドで動作するインメモリキャッシュDBで全てのデータ操作は排他的

 **スナップショット機能**がある
###スナップショットとは?
- スナップショットとは、ある時点でのソースコードや、ファイル、ディレクトリ、データベースファイルなどの状態を抜き出したもののことです。

- バックアップをする際に、バックアップ処理中にファイルが更新されると、ファイルやディレクトリに不整合が起こることがあります。これを防ぐために使用されるのがスナップショットです。ある時点での状態を統一的に保持しているので、バックアップ時の時間的な不整合を防ぐことができます。

 データを永続化できる

##特徴
RedisではString に加えて、List、Set、Sorted Set、Hash、Bit Array、HyperLogLog と豊富なデータ型を扱えます。さらに正規表現を用いたキーの曖昧検索を行えたり、トランザクションを用いてデータを更新できたりとget/set以外にも豊富な機能があります。

##可用性
ElastiCacheでは最小の構成単位を「ノード」と呼びます。EC2で言うところのインスタンスに相当するものです。このノードを組み合わせた集合体をクラスターと呼びます。ノードに直接接続してしまうと、もしそのノードに問題が発生した場合には新しいノードのアドレス（エンドポイント）をアプリケーション側で書き換えなくてはなりませんし、サービスの成長と共に負荷が上がってくるとノードの台数を増やして負荷やメモリ（キャッシュ）を分散したりといった要件も出てきます。クラスター構成を組んでおいて、常にアプリケーションはエンドポイントを見ておくようにすればノードの増減によってアプリケーションに変更を行う必要がありません。よって、運用を行う上でこのクラスター機能という観点は非常に大事になってくるのです。
参考
https://dev.classmethod.jp/cloud/aws/which-choice-redis-memcached/