OmniAICreator/Qiita-1.07M huggingface dataset:
AWS Lambdaで関数作ってAPIGatewayで公開するまでの学習

# 本記事でやること

![スクリーンショット_2021-03-28_17_22_37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/ea799a62-b7d4-6169-cea7-f51db4cba365.png)

適当なJSONを返す

# 前提
[AWSのアカウント作成後のAdminのIAMユーザー作成](https://qiita.com/Teach/items/8212c06dc9f4a2546800)

# Lambdaのスタート
## Lambdaとは？
サーバー管理せずにコードが実行できるサービス

## コスト
コード実行していない間は無料
https://aws.amazon.com/jp/lambda/pricing/

永久無料枠アリ

## イベント
S3、DynamoDBの変更をトリガーにして発火できる

## 学び方
https://docs.aws.amazon.com/lambda/latest/dg/welcome.html#welcome-first-time-user

1. 動画見る
https://aws.amazon.com/jp/lambda/
英語。adblock切らないとみれなかった

2. Getting started with Lambda
https://docs.aws.amazon.com/lambda/latest/dg/getting-started-create-function.html

## AWS CLIを使ってやってみる
https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-awscli.html
ここやればOK

roleの作成時のパスは`file://`が必須なので注意

# 本題
## 関数作る
![スクリーンショット_2021-03-28_17_32_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/e58a232b-1c4b-f4f4-bb2f-a0b94891e79a.png)

一から作成
関数名: my-function
ランタイム: Node.js 14.x
デフォルトの実行ロールの変更 > 既存のロールを使用する > lambda-ex( AWS CLIの演習で作ったやつ)


で、関数の作成

## 公開する

公開はAPI Gatewayでやる。
登録して12ヶ月は無料枠があるが、永久無料枠はないので注意。

![スクリーンショット_2021-03-28_17_34_38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/6ca5263a-9e28-45ae-fb6e-dfe0601ffeb3.png)

以下のように設定

![スクリーンショット 2021-03-28 17.37.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/5c4fad7d-656d-b66b-0a42-154169b17415.png)


そしたらトリガーができるので選択。

![スクリーンショット 2021-03-28 17.38.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/7c24edd1-c5f3-9c85-3b29-9f9d55bc76b0.png)


そしたら以下のような画面が出る。

![スクリーンショット_2021-03-28_17_38_50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/b4a02ab7-4150-501e-4946-f4c83f1c1d77.png)

この「URLを呼び出す」の$defaultのほうを使う。
このURLの末尾にLambdaの関数名をslachでつなげる。
すると呼べる。
![スクリーンショット_2021-03-28_17_41_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/ddc1f876-d342-f4a5-9a6a-aa2d041d128d.png)

## レスポンスを修正
![スクリーンショット_2021-03-28_17_43_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/036c6565-8a25-d3bd-072c-9c264a647ee5.png)

コードタブで変更してデプロイ

すると、先ほどのURLで別のレスポンスが帰るようになる。

# 参考

[AWS Lambda を Amazon API Gateway に使用する](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/services-apigateway.html)
ECS Serviceを自動起動・停止するAutomation

(2021/4/5追記) APIリファレンスのリンクを追記
(2021/4/4追記) IAMRoleの作成方法とCLIでの作成手順を追記しました。

AWSではEC2やRDSの自動起動・停止を行うためにAutomationという機能がデフォルトで用意されています。CloudwatchEventと組み合わせるだけで簡単に夜間や休日の停止が実現でき、コスト削減が実現できます。

ただ、残念ながら自分がよく使うFargate(ECS)ではそのようなAutomationがなかったため、Runbookを自分で作りました。
（起動はタスク数を1以上に、停止はタスク数を0にする形で実現しています）

どのように記載するかのリファレンスが少なかったですが、 ~~Boto3のSDK~~ AWSのAPI を内部で呼び出しているだけのようだったので特にハマることなく実現できました。

(2021/4/5追記)変数名などはAPIリファレンスを参照してください。
https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_UpdateService.html

## Automation作成方法

SystemsManager > 共有リソース > ドキュメント にて 「オートメーションを作成する」で エディタにYamlを貼り付けるだけ。


### EcsServiceStart Runbook

```EcsServiceStart.yaml
description: ecs service start automation runbook
schemaVersion: '0.3'
parameters:
  EcsClusterName:
    type: String
  EcsServiceName:
    type: String
  DesiredCount:
    type: Integer
    default: 1
mainSteps:
  - name: ECS
    action: 'aws:executeAwsApi'
    inputs:
      Service: ecs
      Api: UpdateService
      cluster: '{{ EcsClusterName }}'
      service: '{{ EcsServiceName }}'
      desiredCount: '{{ DesiredCount }}'
```

### EcsServiceStop Runbook

```EcsServiceStop.yaml
description: ecs service stop automation runbook
schemaVersion: '0.3'
parameters:
  EcsClusterName:
    type: String
  EcsServiceName:
    type: String
mainSteps:
  - name: ECS
    action: 'aws:executeAwsApi'
    inputs:
      Service: ecs
      Api: UpdateService
      cluster: '{{ EcsClusterName }}'
      service: '{{ EcsServiceName }}'
      desiredCount: 0
```

## スケジュール実行設定

作成したAutomationをCloudwatchEventsで自動化します。

Cloudwatch > イベント > ルール　で　イベントソースを cron式 に、ターゲットを **作成したSSM Automation** にするだけです。ここでCluster名やService名も指定しましょう。

できあがり。

# 実行用のIAMロールの作成 (2021/4/4追記)

SsmAutomationRoleという名前で作成。

* 信頼関係 : ID プロバイダー events.amazonaws.com
* ロール
  - AmazonSSMAutomationRole
  - AmazonECS_FullAccess （より限定的にすることも可能）


# CLIでの設定例 (2021/4/4追記)

## Automationの作成

```
aws ssm create-document \
  --name EcsServiceStart \
  --content file://EcsServiceStart.yaml \
  --document-format YAML \
  --document-type Automation
```

## CloudwatchEventsのルールおよびTarget作成

AM9:00に起動する例

```
aws events put-rule --schedule-expression "cron(0 0 * * ? *)" --name "RetoolDailyStartAutomationRule"

aws events put-targets --rule RemoteAppDailyStartAutomationRule --targets file://EcsServiceStartTarget.json
```

タスク数はデフォルトの1となる。Inputの値に `[]` を付与する必要がある点がわかりにくかったです。複数のTargetが必要な場合はJson内にもう一つ設定を追記してください。

```EcsServiceStartTarget.json
[
  {
    "Id": "id1",
    "Arn": "arn:aws:ssm:ap-northeast-1:{アカウント名}:automation-definition/EcsServiceStart",
    "RoleArn": "arn:aws:iam::{アカウント名}:role/SsmAutomationRole",
    "Input": "{\"EcsClusterName\":[\"{クラスター名}\"], \"EcsServiceName\":[\"{サービス名}\"]}"
  }
]
```
【VBA】1つのセルから特定の文字列を抽出する方法

今回は、1つのセルから特定の文字列を抽出する方法です。

下記のように、1つのセルに入れた文字列の中で特定の文字列を
別々のセルに書き出したい。。。そんな時はないでしょうか。

下記は、各職業のステータスを1つのセルに書いてしまいました。
ここから、各ステータスの値のみ抽出をし、それぞれのステータスの欄に
格納したいと思います。

![サンプル](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1242278/b57525fe-86b0-47fd-23c2-d526035298b3.jpeg)

以下がサンプルコードになります。

```vb.ステータスを分割する
Sub ステータスを分割する()

Dim txt As String

Dim i As Long

For i = 3 To 6

    With Sheets("Sheet1")

    txt = .Cells(i, 3).Value
    txt = Replace(txt, " ", "")
            
    .Cells(i + 9, 3) = Mid(txt, InStr(txt, "【HP】") + 4, InStr(txt, "【MP】") - InStr(txt, "【HP】") - 4)
    .Cells(i + 9, 4) = Mid(txt, InStr(txt, "【MP】") + 4, InStr(txt, "【攻撃力】") - InStr(txt, "【MP】") - 4)
    .Cells(i + 9, 5) = Mid(txt, InStr(txt, "【攻撃力】") + 5, InStr(txt, "【防御力】") - InStr(txt, "【攻撃力】") - 5)
    .Cells(i + 9, 6) = Mid(txt, InStr(txt, "【防御力】") + 5, InStr(txt, "【素早さ】") - InStr(txt, "【防御力】") - 5)
    .Cells(i + 9, 7) = Mid(txt, InStr(txt, "【素早さ】") + 5, InStr(txt, "【賢さ】") - InStr(txt, "【素早さ】") - 5)
    .Cells(i + 9, 8) = Mid(txt, InStr(txt, "【賢さ】") + 4)

    End With

Next i

End Sub
```

では、詳細を説明していきます。

```
Dim txt As String

Dim i As Long
```
まずは変数を用意します。「txt」は抽出対象の文字列を格納するもので、
「i」は各行数を格納するものになります。

```
With Sheets("Sheet1")

    txt = .Cells(i, 3).Value
    txt = Replace(txt, " ", "")
            
    .Cells(i + 9, 3) = Mid(txt, InStr(txt, "【HP】") + 4, InStr(txt, "【MP】") - InStr(txt, "【HP】") - 4)
    .Cells(i + 9, 4) = Mid(txt, InStr(txt, "【MP】") + 4, InStr(txt, "【攻撃力】") - InStr(txt, "【MP】") - 4)
    .Cells(i + 9, 5) = Mid(txt, InStr(txt, "【攻撃力】") + 5, InStr(txt, "【防御力】") - InStr(txt, "【攻撃力】") - 5)
    .Cells(i + 9, 6) = Mid(txt, InStr(txt, "【防御力】") + 5, InStr(txt, "【素早さ】") - InStr(txt, "【防御力】") - 5)
    .Cells(i + 9, 7) = Mid(txt, InStr(txt, "【素早さ】") + 5, InStr(txt, "【賢さ】") - InStr(txt, "【素早さ】") - 5)
    .Cells(i + 9, 8) = Mid(txt, InStr(txt, "【賢さ】") + 4)

End With
```
上記を、各行ごとに処理をしていきます。

Withを使うことで、Withの中では指定したシートを省略することができます。
今回は、Sheets("Sheet1")を指定してますので、「.（ドット）」から始まる部分でSheets("Sheet1")を省略しています。

```
txt = Replace(txt, " ", "")
```
こちらは、対象のセルにスペースが入っていた場合に削除しています。
今回は不要でしたが、備忘録として記載しています。

```
.Cells(i + 9, 3) = Mid(txt, InStr(txt, "【HP】") + 4, InStr(txt, "【MP】") - InStr(txt, "【HP】") - 4)
```
こちらで、Mid関数とInStr関数を使用することで、抽出したい文字列を指定し、
値をセルに格納しています。
Mid関数とInStr関数については、下記の記事を参考にしてください。

Mid関数
https://www.tipsfound.com/vba/05mid

InStr関数
https://www.tipsfound.com/vba/05instr

```
For i = 3 To 6
```
そして、For文で抽出対象の行数分ループ処理をして完了です。

以上、1つのセルから特定の文字列を抽出する方法でした。
MacOS Big SurでHomesteadを立ち上げようとしたらエラー

MacOSをBigSurに更新するタイミングで、一気にクリーンインストールを実施。
その後、改めてHomesteadの実行をしようとしたら、vagrant up を実行したタイミングで以下のようなエラーが出た。

### 環境
OS: MacOS Big Sur 11.2.2

### エラー内容

```
There was an error while executing `VBoxManage`, a CLI used by Vagrant
for controlling VirtualBox. The command and stderr is shown below.

Command: ["hostonlyif", "create"]

Stderr: 0%...
Progress state: NS_ERROR_FAILURE
VBoxManage: error: Failed to create the host-only adapter
VBoxManage: error: VBoxNetAdpCtl: Error while adding new interface: failed to open /dev/vboxnetctl: No such file or directory
VBoxManage: error: Details: code NS_ERROR_FAILURE (0x80004005), component HostNetworkInterfaceWrap, interface IHostNetworkInterface
VBoxManage: error: Context: "RTEXITCODE handleCreate(HandlerArg *)" at line 94 of file VBoxManageHostonly.cpp
```

### 原因
色々と探し回ったところ、VirtualBoxの再インストールで解決すると書いてあったため、以下URLより再インストールを実施。
https://www.oracle.com/virtualization/technologies/vm/downloads/virtualbox-downloads.html
それでも同じエラーのため、他を見回ったところ、設定の「セキュリティとプライバシー」からソフトウェアの許可を行う必要がある様子。

### 対処方法

Macの システム環境設定 > セキュリティとプライバシー を表示し、
「開発元"Oracle America, Inc."のシステムソフトウェアの読み込みがブロックされました。」の項目横にある「許可」ボタンをクリックして許可を実施。
その後、念の為VirtualBoxを再インストールしました。

上記を実施することで解決しました。
FlaskでWebAPIを作成しデプロイした

# Python(Flask)でWebAPIを作成しデプロイした際の備忘録

どうもtakeです。  [はてなブログ](https://take2405-first.hatenablog.com/)も書いたりしています。

普段は golangでバックエンドの開発を行っているのですが、1週間ほどPythonについて調べつつWebAPIをデプロイしました。

## 1. WebAPIをローカル環境で作成
#### 前提条件
- Githubに関する知識がある
- Herokuのアカウントがある
  
#### 今回の開発環境 

- MacBook Pro 2018 (OS:Big Sur 11.2.1)
- Python 3.7.10(このバージョンは任意)
- Flask 1.1.2  
**注意事項：後述しますが、デプロイの際にはサポートされているバージョンに合わせる必要があります。**

#### Flaskのinstall

```
pip install Flask
```

#### 簡単なAPIの作成  
今回僕が作ったAPIは外部のAPIを利用して必要な情報のみを返すAPIだったためDBは利用していません。
下記のようなmain.pyを作成します。

```python:main.py
from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/hello', methods=["GET"])
def hello_world():
    return jsonify({'message': 'Hello, world'})

if __name__ == "__main__":
    app.run(debug=True)
```
実行します

```
python main.py
```

[http://127.0.0.1:5000/hello](http://127.0.0.1:5000/hello)にアクセスすると

```
{
  "message": "Hello, world"
}
```

レスポンスが得られました。

##### 注意事項  
ここに書いているAPIは簡単なものです。各々の目的に合わせてエンドポイントを追加し、処理を記述してください。

## 2. 作成したAPIをデプロイする  
#### デプロイ環境  
- Heroku

#### 注意事項：サポートされているveriosnについて  
Herokuでは全てのPythonのバージョンがサポートされているわけではありません。  
下記のサイトからサポートされているバージョンを確認
(なぜかこのサイトに書いてあるものではうまく動作せず、僕の開発段階ではversion3.7.10で動作)
[Herokuサポートバージョン](https://devcenter.heroku.com/articles/python-support)

---
#### デプロイに必要なファイルの準備
- main.py(プログラムファイル)  
Pythonの実行ファイル   
 
- runtime.txt(Pythonのバージョンを記載）  

```
echo python-3.7.10 > runtime.txt
```
- requirements.txt（インストールすべきライブラリ(パッケージ)を記載）

```
pip freeze > requirements.txt
```

- Procfile（プログラムの実行方法を記載）

```
echo web: python main.py > Procfile
```

---
#### いよいよデプロイ

**すでにGit管理下にあるものとして説明しています。**

Herokuにlogin

```
heroku login
```

対象のリポジトリに移動する

Herokuでアプリケーションを作成

```
heroku create [任意のアプリケーション名]
```

Herokuにデプロイする(メインブランチ以外のブランチをデプロイする場合は**<ブランチ名>:main**)

```
git push heroku main
```

## 発生した問題  
- デプロイができたがすぐにクラッシュする  
どうやらFlaskは外部に公開するためには開放するport周りで指定が必要なようだった  
最後の１行を下記のように変更したらいけた

```python:main.py
    app.run(debug=False, host='0.0.0.0', port=8080)
```

- レスポンスの日本語が文字化けする  
下記のように１行文字コードについての指定を加えることで解決

```python:main.py
app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False

```
- ログに関して
Procfileに以下を追加

```
web: gunicorn main:app --log-file -
```

## 参考にした記事
- Pythonのversion変更の際に参考にした記事  
https://qiita.com/TheHiro/items/88d885ef6a4d25ec3020#%E8%A7%A3%E6%B1%BA%E6%96%B9%E6%B3%95  
https://teratail.com/questions/323061

```
# もしかしたらインストールの際に役に立つかも
pyenv install --patch 3.7.2 < <(curl -sSL https://github.com/python/cpython/commit/8ea6353.patch\?full_index\=1)
```

- Flaskのport関連で参考にした記事  
https://qiita.com/miroha-eng/items/cf446a3a012c32a6d03c
https://qiita.com/tomboyboy/items/122dfdb41188176e45b5
【Python】回転行列【AtCoder】

ABC197
[D - Opposite](https://atcoder.jp/contests/abc197/tasks/abc197_d)
ででてきた、**回転行列問題**

今後のためにも自作ライブラリの作成。

※ちなみにこの問題は複素数平面でもとける！
知らなくても競プロで困ることはなさそうだが、教養として知っておいて良さそう。
俺の学生時代は教科書にのっていなかったけど、今や数Ⅲの範囲らしい・・・
ヨビノリたくみさんのyoutubeが参考になった。
[中学数学からはじめる複素数](https://www.youtube.com/watch?v=IQaYyFboK48)


#回転行列

```python:test.py
import math
def RotationMatrix(before_x,before_y,d):
    d = math.radians(d)
    new_x = before_x*math.cos(d)-before_y*math.sin(d)
    new_y = before_x*math.sin(d)+before_y*math.cos(d)
    return new_x,new_y
```

おわり！
[メモ] eslint-config-prettierのv8.0.0以降でextendsの設定の仕方が変わっていた

# 概要
タイトルの通り、eslint-config-prettierのv8.0.0以降でextendsの設定の仕方が変わっていた。

結果、 `prettier/react` 、 `prettier/@typescript-eslint` 等のプラグインを指定しなくても全て `prettier` に含まれるようになったらしい。

ソース： [Prettier > Installation](https://github.com/prettier/eslint-config-prettier#installation)
> information_source Note: You might find guides on the Internet saying you should also extend stuff like "prettier/react". Since version 8.0.0 of eslint-config-prettier, all you need to extend is "prettier"! That includes all plugins.

現場からは以上です。
WaffleでもOLEDに文字を表示してみる

# はじめに
[こちらの記事](https://qiita.com/mine820/items/c9d08a61a0fc15db2916)でArduino Nano EveryでOLEDに文字を表示したので、Waffleでも表示してみることにしました。

# 準備
- [Waffle](https://dotstud.io/docs/waffle/)
- [0.96インチ　128x64ドット有機ELディスプレイ（OLED）](https://akizukidenshi.com/catalog/g/gP-12031/)
- ブレッドボード
- ジャンパーケーブル（4本）
- Groveケーブル（ストレート、1本）
- PC（今回はWindows 10）
- USBケーブル（Type-A（オス）～Type-C（メス））

# 環境構築
Waffleの環境構築は[こちら](https://qiita.com/mine820/items/cab307d684bcc0ffed57)を参照してください。
OLEDの環境構築は[前の記事](https://qiita.com/mine820/items/c9d08a61a0fc15db2916)を参照してください。

# 結線
WaffleにはI2Cのコネクタがあるので、これとOLEDを繋ぎます。
ケーブルの色と接続先の組み合わせは以下の通りです。

| Groveケーブル（Waffle） | OLED |
|:---:|:---:|
| 赤 | VCC |
| 黒 | GND |
| 白 | SCA |
| 黄 | SCL |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130771/4ee951d7-5c6a-3caa-a278-2b5c89009b71.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130771/ee9a6fb9-3631-8609-80f2-0ddc71b86bfb.png)

# サンプルプログラム
「Hello World!」と表示するプログラムを実行してみます。
こちらはArdiono Nano Everyとまったく同じなのですが、念のため、再掲します。

```c
#include<Wire.h>
#include<Adafruit_GFX.h>
#include<Adafruit_SSD1306.h>

Adafruit_SSD1306 display(-1);

void setup() {
  // initialize
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
}

void loop() {
  // clear display
  display.clearDisplay();

  // set text parameter
  display.setTextSize(1);
  display.setTextColor(WHITE);

  // set text position
  display.setCursor(0, 0);

  // display text
  display.println("Hello");
  display.println("World!");

  // draw
  display.display();
  delay(1000);
}
```

I2Cで接続していますので、何も変更しなくても大丈夫です。

表示のされ方も同じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130771/2a1cb333-b738-ee6f-9f73-c9f80e9e6126.png)

# まとめ
もう少し苦労するかと思いましたが、意外と簡単にWaffleでも表示できてしまいました。
Ardiuno互換、恐るべしです。
KiCadで外部ライブラリを使う


Pro MicroボードとRGB LED付きロータリーエンコーダのボードを作りたかった。
どちらもSparkfunのKiCadライブラリに含まれているのでありがたく使わせてもらう。

https://github.com/sparkfun/SparkFun-KiCad-Libraries

ライブラリのインポートの仕方はDigiKeyのフォーラムで紹介されているのを参照して、Project Specific Libraryとして使うことにした。

https://forum.digikey.com/t/importing-the-digi-key-kicad-library-into-kicad-5-0-0/4075

GitHubで公開されているライブラリをローカルにクローンして、

Schematic editor
Preferences --> Manage Symbol Libraries
Project Specific Libraries tab:
Click on the Add existing library to table button:
で.libファイルを選ぶ

同様に
PCB Layout
Preferences --> Manage Footprint Libraries
Project Specific Libraries tab:
Click on the Add existing library to table
で.prettyフォルダを選ぶ


## その他便利そうなライブラリやサイト

https://github.com/Digi-Key/digikey-kicad-library

https://www.snapeda.com/kicad/

https://octopart.com/
laravel8 Auth認証をしていないと表示できないページを作成する

# 目的

- Auth認証を行っていないと表示できないページを実装する方法をまとめる

# 方法

- ルーティングに記載するだけで実装が可能である。
- 下記のようなルーティング情報が記載されていたとする。

    ```アプリ名ディレクトリ/routes/web.php
    Route::get('/top', [TopController::class, 'index'])->name('top.index');
    ```

- 下記のように記載することで当該ページが認証していないと表示できないページにする事ができる。

    ```アプリ名ディレクトリ/routes/web.php
    Route::get('/top', [TopController::class, 'index'])->middleware(['auth'])->name('top.index');
    ```
Udemyメモ「2時間でわかる！確実に商談を前進させる営業トーク50選」

https://www.udemy.com/course/sales_talk_50/

## 成果を出すための3つのポイント

1. Yes を急ぐより、「No を言わせない」
    - 議題について、顧客と課題感を共有する
        - 課題の必要性や対象者は？
        - 具体的にどのくらい必要？
    - 課題感の共有後、自分の知識と掛け合わせ、ソリューションを想像
2. 商品特性より、「判断基準を売り込む」
    - 顧客の課題には、複数あっても大きさに差がある（課題？、予算？、モチベUP？）
    - その課題に応じた判断基準をもって、商品を売り込む
3. スピーディな対応により、「顧客の熱を下げない」
    - 連絡や対応のスピード（遅くても3日）
    - 顧客は、方々から営業を受けるため、紹介した商品の説明も埋もれてしまう
    - 担当者の力量も競合と比較されている

## 訪問前の動き

1. 顧客に聞ける内容は聞いておく
    - 事前の聴取がないと、複数の案がある場合、当日は一方的な話になってしまう
    - ある程度、選択肢を絞らせることで、想定質問への深掘りもできる
2. 社内ノウハウ
    - 社内相談しておくことで、過去の対応実績から、新たな対応ができる可能性が高まる
3. 訪問前に決めること
    - 訪問の目的とゴールは明確であるか（相手の心に残したいこと）
    - 目的とゴールに顧客にとって有益な情報があるか

## 課題の引き出し方

1. テーマの確認
    - 冒頭に「相互に話したい議題を宣言」
2. 課題の洗い出し
    - 担当者と決裁者の課題を聞く（社内では？、管理者では？、あなたは？）
    - 二人が語る課題が、大きな課題である可能性高い
3. 課題の深掘り
    - 課題は、「数値と人」に注目すると、見つけやすくなる
    - 問題は誰に当てはまる？、具体的なシーンは？、どの程度の割合で当てはまる？
4. 課題の焦点化
    - 「重要度、緊急度」で課題を分類分けし、各課題に「絡まり」を持ち、重要性が高い課題を見つける
5. 過去から現在までの取組、新たな課題を引き出す
    - 顧客の成功体験と、失敗経験を踏まえて、提案する
    - 社内資料を獲得できると、本当に刺さる提案への第一歩
6. 取り組みへの共感と、方向性の確認
    - 「他者を追随 or 方向性維持 or 方向転換」への次の一歩について、制約を省きどうしたいか
7. お土産情報を用意する
    - 顧客にとって有益な情報
    - また話したいと思う営業マンへ！

## 失敗しない提案を作成

1. 時期の確認
    - いつ頃に実現できると理想か？
    - 内部のマニュアル的に〇月までに合意を取る必要あるか？
    - 導入にあたり予算獲得時期との兼ね合いも必要のため、スケジュール共同作成等の提案
2. 予算の確認
    - 予算的に無理な提案をしないため、概算でも良いので把握する必要あり
    - 直接的に聞く or 他社サービスの導入例を元に金額感を聞く
3. 検討組織の確認
    - 提案商品サービスによる顧客の課題解決以外にも、導入に至るまでの課題も把握する必要あり
        - 誰が提案承認する？
        - 名刺交換等の顔合わせだけでも試みる
        - 営業の場への同席を打診
4. 競合接触の確認
    - 顧客は、競合の`何に対して`魅力を感じているかに着目
        - どういった点が良いと感じたか
        - 他社のサービスも引き合いに出して判断基準を探る
5. 現在のサービス判断基準と理由の確認
    - 顧客の選定基準に合わせたサービス紹介
        - 直接、選定基準を聞く
        - 曖昧なら、顧客が言語化できていない観点を一緒に探す

## スムーズに提案に移行するコツ
1. 他社の事例からサービス紹介
    - 顧客の課題感と近い、他社の成功事例を切り口へ
    - 違う部分もあるため、顧客に合わせてアレンジ
2. 複数の選択肢を提示
    - 基準を明確にして３案ほど用意
    - 費用が安い案、効果が高い案、他社の成功事例の案

## クロージング
1. 「すぐに受注に結びつきそう！」
    - 提案を書面化
    - 顧客社内の検討スピードを早める
2. 「担当者レベルでは不安...」
    - 不安要素を除外する提案
    - 担当者が社内で導入を進めるにあたり、会議の同席や書面作成など営業マンとしてサポート
3. 「予算がなくて...」
    - OKラインを探る
    - 「顧客の予算に合わせて提案したいから、予算の3パターン程教えてくれると！」
    - 「一番安いプランから試験的に始めて、データを見てプランを考えるとか！」
4. 「導入は急がない...」
    - 外部の動きを比較させる
    - 社会変化へ急ぎ対応することとか、競合の動きとか
    - スタートが早いほど、課題解決へのノウハウを蓄積できる
5. 特別対応など社内交渉が必要な時
    - 論点整理と締め切りを確認
6. 相手の本気度を見極める
    - 1: 具体的なスケジュールと予算を検討します！
    - 2: 決裁者に相談します
    - 3: 関係各所から必要な情報を集めます
    - 4: チーム内に情報共有します
    - 5: 考えておきます

## まとめ
1. 大前提は、信頼を獲得すること
2. ステップを作ってトライ
3. 社外のみならず社内でも実践
Udemyメモ「Google Apps Scriptの仕事効率化・自動化をプログラミングで実現」

## 概要

- [【業務自動化をゼロからマスター】Google Apps Scriptの仕事効率化・自動化をプログラミングで実現 \| Udemy](https://www.udemy.com/course/gasmore1/)
- [Apps Script  \|  Google Developers](https://developers.google.com/apps-script)
- [Google Apps Script でよく使うスニペット集 30 選 \- Qiita](https://qiita.com/tanabee/items/5de3e8715be759ce1c7f)

## Google Apps Script を使用した業務の自動化

### Google Form 送信時における自動メール通知

1. Google Drive から、Google Form を生成
2. 適当に入力フォームを追加
3. `回答`タブから、`回答をスプレッドシートに表示` を押下
4. `ツール`タブから、`スクリプトエディタ`を起動
5. ヘッダー中段の時計アイコンである`現在のプロジェクトのトリガー`を押下
6. FloatingActionButton を押下し、トリガーを生成
7. エディタで、`フォーム送信時`に発火するトリガーを元に起動する function を定義
8. フォームで、右上のプレビュー機能を使用して、フォームを送信
9. 入力したメールアドレスに以下の文面が届いたら成功

```js
// https://developers.google.com/apps-script/reference/gmail
function autoReply(event) {
  const [timeStamp, companyName, name, email] = event.values;
  const subject = `『${name}様』 お問い合わせありがとうございます`;
  const body = `
  お名前 ${name} 様

  お問い合わせありがとうございます
  以下の内容で、お問い合わせを承りました。

  会社名: ${companyName}
  お名前： ${name}
  メールアドレス: ${email}
  `;

  GmailApp.sendEmail(email, subject, body);
}
```

### Google Form 送信時における Slack 自動通知

1. 自分用の workspace を用意
2. 通知したい channel を用意
3. `Setting and Adnimistration`から、`Manage App` を押下して、Webページへ
4. `Incoming Webhook` を探し、対象の workspace に導入すると、設定画面に移動
5. Webhook 用の URL をコピーしておき、下部で設定を保存する
6. 以下の通りコードを用意


```js
// https://developers.google.com/apps-script/reference/gmail

function autoReply(event) {
  const [timeStamp, companyName, name, email] = event.values;
  const subject = `『${name}様』 お問い合わせありがとうございます`;
  const body = `
  お名前 ${name} 様

  お問い合わせありがとうございます
  以下の内容で、お問い合わせを承りました。

  会社名: ${companyName}
  お名前： ${name}
  メールアドレス: ${email}
  `;
  const slackMessage = `
  お名前 ${name} 様

  以下の内容で、お問い合わせを承りました。

  会社名: ${companyName}
  お名前： ${name}
  メールアドレス: ${email}
  `;

  GmailApp.sendEmail(email, subject, body);
  notifySlack(slackMessage);
}

function notifySlack(message) {
  const WEBHOOK_URL = `${slack の web ページでコピーした URL}`;
  const userName = "gasBot";

  const payloadObj = {
    username: userName,
    text: message
  };
  const payloadJson = JSON.stringify(payloadObj);
  const options = {
    method: "post",
    contentType: "application/json",
    payload: payloadJson,
  };

  UrlFetchApp.fetch(WEBHOOK_URL, options);
}
```


### 顧客リストを元に一斉メール送信

```js
//https://developers.google.com/apps-script/reference/gmail/gmail-app#sendEmail(String,String,String,Object)

function sendAll() {
  const ss = SpreadsheetApp.getActiveSheet();
  const range = ss.getDataRange().getValues();

  const file = DriveApp.getFilesByName("Google Driveのマイドライブに存在するファイル名").next();

  for(var i = 1; i < range.length; i++){
    var title = `【${range[i][2]} 様】新商品のお知らせです`;
    var body = `
    ${range[i][1]}
    ${range[i][2]} 様

    新商品のお知らせです。
    `;
    var email = range[i][3];
    var cc = range[i][4];
    var options = {
      attachments: [file],
      cc: cc
    };

    GmailApp.sendEmail(email, title, body, options);
  }
}
```
【Swift】モーダル遷移する、モーダルを閉じる

# これはなに

Segueを使わずにコードで `NextViewController` という名前のControllerへの遷移を想定する。
フルスクリーンで遷移する。

## 遷移

```swift:ViewController.swift
let storyboard = UIStoryboard(name: "NextViewController", bundle: nil)
let vc = storyboard.instantiateViewController(identifier: "NextViewController")

vc.modalPresentationStyle = .fullScreen

self.present(vc,animated: true)
```

一応

**【Swift】モーダル遷移かつNavigationBarも表示させたいかつフルスクリーンで表示させたい**
<https://qiita.com/antk/items/e8bccccfad08a61fb140>

## 閉じる

フルスクリーンなので**モーダルを下げる取っ手**が無いためどこかに閉じるボタンを作る。

```swift:ViewController.swift
self.dismiss(animated: true, completion: nil)
```

おわり(´・ω・｀)
AWSのアカウント作成後のAdminのIAMユーザー作成

# 本記事について
AWSのアカウントを作って、さあやるぞ！って言う時に
いろんなチュートリアルや、手続きで「IAMでユーザー作るのがベストプラクティスです」とめっちゃ押される。

少し経ってからIAMユーザー作って良いことがあったのでそのやり方を書く。

# 前提
AWSにルートユーザーとしてsigninできること

# IAMユーザーを作って役立ったこと
IAMユーザー作成時にそのユーザーのアクセスキー、シークレットキーが作られる。
それらを、aws cliを使い始めるときに入力する。

# 作り方
[Creating your first IAM admin user and group
](https://docs.aws.amazon.com/IAM/latest/UserGuide/getting-started_create-admin-group.html)

の「Creating an administrator IAM user and group (console)」をやればOK

以下和訳と図

1. [IAM console](https://console.aws.amazon.com/iam)にルートユーザーでいく

2. IAM ユーザーによる請求情報へのアクセスを有効にする
![スクリーンショット_2021-03-28_16_48_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/66f3c2fc-b4d6-453a-6fe8-b55580190bc4.png)

下にいくと以下の項目があるので編集を押してチェックつけて、更新。
それで有効になる。
![スクリーンショット_2021-03-28_16_49_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/adbd3c5f-ec5e-1f75-a8f7-daf8960b551c.png)

3. IAMユーザーを作る

![スクリーンショット_2021-03-28_16_53_39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/7ce28e4e-bd9b-bc5f-5aed-1088cf1df716.png)

設定項目が複数あるがここは私は以下のように設定した。(パスワードとかは自由)

ユーザー名: Administrator

アクセスの種類
☑︎プログラムによるアクセス
☑︎AWSマネジメントコンソールへのアクセス

コンソールのパスワード: カスタムパスワード

パスワードのリセットが必要のチェックは外す。


で次にいくと、グループ指定する画面になるので

`Administrators`という名前でグループを作成
権限は`AdministratorAccess`にする

タグはスキップ

これでOK

作ると、アクセスキーやシークレットアクセスキーが表示されるのでそれらはメモっておくこと。

# AWS CLIのインストール

環境はmac
2021/3/28時点

brewを使ってインストールした。
[homebrew](https://formulae.brew.sh/formula/awscli)

```
brew install awscli
```

> ここでインストールされるのはawscliのv2

インストールしたら`aws configure`コマンドで設定ファイルを作る

例

```
$ aws configure
AWS Access Key ID [None]: IAMユーザー作る時にメモっておいたやつ
AWS Secret Access Key [None]: IAMユーザー作る時にメモっておいたやつ
Default region name [None]: ap-northeast-1
Default output format [None]: json
```

そうすると、ホームの`.aws`以下にconfig, credentialsファイルが作られる

```
.aws$ cat config
[default]
region = ap-northeast-1
output = json
.aws$ cat credentials
[default]
aws_access_key_id = IAMユーザー作る時にメモっておいたやつ
aws_secret_access_key = IAMユーザー作る時にメモっておいたやつ
```
対称鍵暗号（共通鍵暗号）と非対称暗号（公開鍵暗号）

## はじめに
以下は私が暗号技術について勉強中の内容を記述しているものです。
間違いありましたら、ご指摘いただけると幸いです！

### 対称鍵暗号（共通鍵暗号）

1. 送信者と受信者が同じ鍵を持つから、復号化ができる
1. 共通鍵なしで復号化することは現実的には不可能とみなされている
1. 当事者間にセキュアなチャネルが必要

### 非対称暗号（公開鍵暗号）

1. 公開鍵（パブリックキー）と秘密鍵（プライベートキー）が対（ペア）で作成される
1. 公開鍵で暗号化されたデータは対となる秘密鍵でしか復号化できない
1. ~~秘密鍵で暗号化されたデータは対となる公開鍵でしか復号化できない~~ ← **これは公開鍵暗号の良くある誤解で、こちらの記事（[秘密鍵で暗号化？](https://qiita.com/angel_p_57/items/d7ffb9ec13b4dde3357d#%E7%A7%98%E5%AF%86%E9%8D%B5%E3%81%A7%E6%9A%97%E5%8F%B7%E5%8C%96)）を参照する！**
1. 当事者間にセキュアなチャネルは不要
1. アリスとボブのメッセージやり取りの例
    1. アリスがメッセージの送信者
    1. ボブはメッセージの受信者
    1. アリスがボブの公開鍵でメッセージを暗号化して送信すると、ボブは自分の秘密鍵を使って復号化してメッセージを読み取ることができる。つまり、ボブ以外の人はボブの秘密鍵を持っていないからアリスのメッセージを読み取ることが出来ない。
    1. でも、ボブの公開鍵は誰もが持っているから、受け取ったメッセージが本当にアリスから送信されたのかは分からない。困る。
    1. ~~そこでアリスは自分の秘密鍵でメッセージを暗号化した後に、さらにボブの公開鍵で暗号化することにした。二重で暗号化した後にメッセージを送信した。これによってメッセージが確かにアリスによって送信されたことが証明出来る。~~
    1. ~~メッセージを受け取ったボブはまず自分の秘密鍵で復号化。続いてアリスの公開鍵で復号化した。うまいことメッセージが複合化できたのでボブは送信者がアリスだということがわかった。~~
    1. ~~よりセキュアにメッセージを送信したいアリスは「デジタル署名」を使うことにした。~~ ← **「デジタル署名」は「公開鍵暗号(の暗号化機能)」の応用ではないらしい！「公開鍵暗号(という総称の技術)の1ジャンル」のようだ。詳細勉強中！**
    1. ~~まずメッセージをハッシュ化して、それを元のメッセージにくっつける。そして、それらをアリスの秘密鍵で暗号化、ボブの公開鍵で暗号化してボブに送信した。~~
    1. ~~メッセージを受け取ったボブは、ボブの秘密鍵で復号化、アリスの公開鍵で復号化して、プレーンなメッセージとハッシュ化されているメッセージ①を取り出す。~~
    1. ~~アリスが使ったハッシュアルゴリズムでプレーンなメッセージをハッシュ化②して、先に取り出したハッシュ化されているメッセージ①とそのハッシュ②が一致するかを検証する。もし一致しない場合、メッセージが送信中に破損あるいは改ざんされたことになる。~~
JavaとJavaScriptの違い

#JavaとJavaScriptの違い

まずJavaとJavaScriptは全く違うプログラミング言語です。そもそもこの二つの言語は違う目的で使われます。

#Javaとは

javaは環境に依存せずに開発を行えます。そしてJavaはシステム開発、Web開発、アプリケーション開発と、使える場面が多岐にわたり、さまざまな開発に利用されています。

#JavaScriptとは

Webページの見栄えをよくしたいユーザーが使用して、主にデザインや簡易的な処理をブラウザ上のみで行えるようにした言語。

JavaScriptの特徴は、あまりプログラミングの知識もなく、開発環境がそろっていなくても手軽に始めることができる点です。

# 具体的にどう違うか？

#1 開発した会社が違う

そもそも開発した会社は違うのでその目的や文法、利用される分野も異なります。

#2 目的が違う

Javaは「Write Once, Run Anywhare（一度プログラムを書けば、どんなハードウェアでも動作する）」ことを目指して開発されました。

JavaScriptは、容易に開発できる手軽さと素早さを求めて開発されています。

#3 文法が違う

Javaは、コンパイル（コンピュータが処理できる形に翻訳）が必要ですが、JavaScriptはコンパイルが必要ありません。

#4 利用される分野が違う

Javaは業務システムやTwitterなどのWebサービス、スマートフォン用（Android）向けアプリなどを開発することができます。

JavaScriptは、Webブラウザ上で色を変えたり、ポップアップ表示をさせるといった動きがあるWebページを開発する際に主に使われています。


#どちらの言語を選べばいいのか

業務システムやアプリ開発をしたいならJava、WebサイトやWebサービスを作りたいならJavaScriptです。また、JavaもJavaScriptも難しいプログラミング言語になるので安易に手を出すのではなく、その他自身の用途にあった言語を学ぶことをおすすめします。
Gatsby.js で material-ui を使用する際は、プラグインを設定する必要がある。

# Gatsby.js で material-ui を使用する際の手順

こんにちは、@ndj です。
現在、Gatsby.js でブログみたいなものを作成しています。
デザインをすべて自前の CSS で作ると、無限に時間がかかってしまうことがこの間判明したので、UIフレームワークとして material-ui を使用することにしました。

いろいろ調べたところ、Gatsby.js で material-ui を使用する際は、単に `yarn add @material-ui/core` すればよいわけではなさそうなことが分かったので、備忘録的に記事に残しておきます。

## 結論

- material-ui をインストールする
- gatsby-plugin-material-ui をインストールする
- gatsby-config.js に記述を追加する

## material-ui をインストールする

まずは、material-ui をインストールします。

```
yarn add -D @material-ui/core
```

## gatsby-plugin-material-ui をインストールする

次に、gatsby-plugin-material-ui をインストールする必要があるみたいです。

```
yarn add -D gatsby-plugin-material-ui
```

## gatsby-config.js に記述を追加する

最後に、gatsby-config.js の plugin に以下のように記述を追加します。

```gatsby-config.js
module.exports = {
    plugins: [`gatsby-plugin-material-ui`],
}
```

以上で、導入は完了です。
最後にテストとして、ヘッダーを作ってみます。

## テスト

```jsx:header.js
import React from 'react';
import { AppBar, Toolbar, Typography } from '@material-ui/core';

const Header = () => {
    return (
        <AppBar position="static">
            <Toolbar>
                <Typography>TEST</Typography>
            </Toolbar>
        </AppBar>
    );
}

export default Header;
```

```jsx:index.js
import React from "react"
import Header from '../components/header';

export default function Home() {
  return (
    <React.Fragment>
      <Header />
    </React.Fragment>
  );
}
```

![スクリーンショット 2021-03-28 165635.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485313/6f164fc9-9022-4091-0d97-803e8268556a.png)

できてるっぽいです。
意外と導入簡単だったかもしれない。

## 参考
[GajiLabo++ blog: GatsbyJS でUIフレームワーク Material-UI を使用する](https://blog.gaji.jp/2020/10/26/5405/)

## さいごに
閲覧ありがとうございました。
誤字脱字、間違いご指摘などございましたら、コメントでご指摘くださるとありがたいです。
フレームワークってべんり。

[twitter: ndj](https://twitter.com/teqndj)
Rubyのyieldとtapとthen

## はじめに
こないだrubyの`then`(`yield_self`のエイリアス)を使ったら、
「`then`が良くわからない」と質問がありました。
自分も昔、躓いた気がするので
rubyの`yield`と`tap`と`then`をまとめておきます。

## yieldとは？
簡単に言うと、「メソッドに渡されたブロックを実行できる」ものです。
(ブロックは `do ~ end`の処理の塊です)

### yieldのサンプル
簡単なサンプルを作ってみました。

```ruby
# 適当なメソッドを定義。中でyieldを実行
def execute_yield
  yield
end

# ブロックをメソッドに渡す
execute_yield do
  puts "Hello World"
end
```
irbなどで実行すると、以下のような出力がされます。

```ruby
Hello World
=> nil
```
これは`execute_yield`メソッドに渡されたブロック(do ~ endの塊)が、
`yield`によって呼び出されたためです。

なので、メソッドの中でyieldがあったら、
**「あ、このメソッドに渡されてるブロックを実行してるんだな」**と思ってください。
:warning: 記事が理解できたら、公式ドキュメントとか他のものも見てください。

### block_given?
ちなみに、メソッドでyieldを使ってるのに、メソッドにブロックが渡されていないと、怒られます

```ruby
# さっき作ったメソッドをブロック(do~endの塊)なしで呼び出してみる
execute_yield
LocalJumpError (no block given (yield))
```
時々、「ブロックが渡されているか」で分岐させたいときがあります。
そんなときは、`block_given?`メソッドが使えます。
さっき作ったメソッドを、以下のように書き換えてみましょう

```ruby
def execute_yield
  if block_given?
    yield
  else
    puts "No block!!"
  end
end
```
それぞれ、以下のような出力がされるはずです。

```ruby
# ブロックあり
execute_yield do
  puts "Hello World"
end
# ブロックがあるときは、ブロックのputs "Hello World"が実行される
Hello World
=> nil

# ブロックなし
execute_yield
# No block!!が表示される
No block!!
=> nil
```

## tap
### 公式ドキュメント
とりあえず、まずは公式ドキュメントです。

https://docs.ruby-lang.org/ja/latest/method/Object/i/tap.html

### tapとは？
公式ドキュメントより抜粋
>self を引数としてブロックを評価し、self を返します。

良く分からなくなってきましたね！
実装のイメージはこんな感じのハズです。

```ruby
def tap(&block) # selfを引数
  yield(self) # ブロックを評価(実行)
  self # selfを返す
end
```
(他の記事や、Cで書かれたRubyを、Rubyで再実装している、[rubiniusのコード](https://github.com/rubinius/rubinius/blob/387c488798d8b911f160d36278710474e526d73f/core/kernel.rb#L924-L927)的にも合っているはずです)

日本語はややこしいですが、してることは単純で、
「yield(渡されたブロックを実行)して、self(レシーバ)を返す」です。

### サンプル
tapの小さめのサンプルを作ってみました。

```ruby
"hoge".tap do |string| 
  # 小文字を大文字に変換
  p string.upcase
end
"HOGE" # pで出力される "HOGE"
=> "hoge" # メソッドの返り値
```

`tap`は中で`yield`を呼び出します。
`yield`なので、ブロック(do~endの間)で渡している`string.upcase`を実行。「"HOGE"」が出力されます。
ただし、tapの返り値はselfなので、メソッドで返されるのは
`"hoge".tap`の「"hoge"」です。

### 使いみち
メソッドチェーンするときのデバッグなどに使えます。
公式ドキュメントのサンプルをそのまま流すと、途中でputsされているのが分かって
分かりやすいですね。(公式ドキュメントが正義)

```ruby
# tapで長くなってますが、していることは、
# 配列にして、偶数だけ取って、二乗してるだけです。
(1..10).tap {|x| puts "original: #{x}" }.
        to_a.tap {|x| puts "array:    #{x}" }.
        select {|x| x.even? }.tap {|x| puts "evens:    #{x}" }.
        map {|x| x*x }.tap {|x| puts "squares:  #{x}" }
# 出力結果と返り値
original: 1..10
array:    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens:    [2, 4, 6, 8, 10]
squares:  [4, 16, 36, 64, 100]
=> [4, 16, 36, 64, 100]
```

## then(yield_self)とは？
実はここまで理解してれば超簡単です。
:warning: ruby2.5以降。エイリアスの`then`は2.6以降でしか使えません。
以下を参照

https://bugs.ruby-lang.org/issues/6721

`tap`はyieldして、selfを返していましたが、`then`はyieldの結果を返します。
### サンプル
同じようなサンプルを使います。

```ruby
"hoge".then do |string| 
  # 小文字を大文字に変換
  p string.upcase
end
"HOGE" # pで出力される "HOGE"
=> "HOGE" # メソッドの返り値
```
返り値がブロックの実行結果("HOGE")になっています。
凄い手抜きぽくなっていますが、
`tap`との違いは、
- レシーバを返すか？
- ブロックの実行結果を返すか？
です。

## 最後に
「何番煎じなんだ？」という記事ですが、
「yieldとは？」「tapとthenの比較」とかあるのに、まとめたものはイマイチない(気がした)
業務では、唐突に出てきた`then`を調べるが、そもそも`yield`が分からなくて詰む。

ということが、昔の自分はあったのでまとめてみました。
それぞれの良さは、別の記事を見てみてください。
個人的には、どれも多用すべきじゃないと思う...
ECSを使って3D弾幕シューティングを作ろうとした際に詰まったところと解決方法

#目次
**1.環境**
**2.作っているもの**
**3.詰まったところと解決方法**
**4.参考URL**
 
##1.環境
UnityVersion:2019.4.17f1
導入Package
-Burst 1.3.0
-Entities 0.11.1
-Jobs 0.2.10
-Hybrid Renderer 0.5.2
-Unity Physics 0.4.1


##2.作っているもの
東方Projrctの2D弾幕シューティングを3Dにしてみよう！って感じで製作中です。
今は最大約9万個の弾を制御しFPSを60以上を保ちながら実行できるようになっています。
![2w.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210726/a50b2d0d-b9d9-8f34-80cf-29f8b1bfd4c0.png)
![4w.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210726/b792612e-7100-719c-3a67-5b511b586552.png)


##3.詰まったところと解決方法
**1.Entityに変換したオブジェクトが出ない！**
└`Hybrid Renderer` の導入を忘れていた！
**2.Unity Physicsで当たり判定を実装したら動作が重すぎた！**
  └1.`Physics Shape`の`CollisionResposns`を `Raise Trigger Events`に変更
※私の作っているものでは当たったかどうかだけでよかったので`Trigger Events`にしました。
![スクリーンショット (99).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210726/990f6d76-27d5-c6c9-db73-8532130ef65b.png)
　2.CollisionResposns 変更に伴いスクリプトの変更 
　下の画像の赤丸の部分を `ICollisonEventsJob`から`ITriggerEventsJob`に変更し、`CollisonEvents`から`TriggerEvents`に変更。
![スクリーンショット (101).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210726/556d6677-1dd3-e539-b963-462e8880f3cd.png)
　3.`Physics Shape`の`Collision Filter`設定
![スクリーンショット (100).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210726/3e1836bc-d7e5-66db-f908-23beace255fe.png)
　`Belongs To`・・・そのオブジェクトの所属するコライダーグループ
　`Collides With`・・・そのオブジェクトと衝突するコライダーグループ
　これらを設定することで30FPSも出なかったものが90FPSで動くようになりました。

**3.シーン遷移時にEntityが残ってしまう!**
　└遷移前にEntityManagerクラスの `public void DestroyEntity(NativeArray<Entity> entities)`でEntityをすべて破棄することで解決。同クラスの`public NativeArray<Entity> GetAllEntities(Allocator allocator = null)`ですべてのEntityを取得することができるので組み合わせて全部破棄できました。

**4.参考URL**
[Unity Scripting API:Unity.Entities](https://docs.unity3d.com/Packages/com.unity.entities@0.0/api/Unity.Entities.html)
[Unity Manual:Unity Physics](https://docs.unity3d.com/Packages/com.unity.physics@0.4/manual/index.html)

DOTSを触り始めて1,2カ月ほどの初心者なので間違っていることろなどがあると思いますので、指摘いただけると助かります！
何かの参考になれば幸いです。
Arduino Nano EveryでOLEDに文字を表示してみる

# はじめに
すでにそこらじゅうに情報はありますが、先日[Arduino Nano Every](https://store.arduino.cc/usa/nano-every-with-headers)を購入したので、環境構築を含め、OLEDに文字を表示するまでの手順を記録として残しておきます。

# 準備
使用する機材は以下の通り。
- [Arduino Nano Every](https://store.arduino.cc/usa/nano-every-with-headers)
- [0.96インチ　128x64ドット有機ELディスプレイ（OLED）](https://akizukidenshi.com/catalog/g/gP-12031/)
- ブレッドボード
- ジャンパーケーブル（4本）
- PC（今回はWindows 10）
- USBケーブル（Type-A（オス）～Type-C（オス））

# 環境構築
## ボードマネージャ
まずArduinoIDEに環境を構築します。

Arduino Nano EveryはArduino Nanoから改良されているため、別途ボードを認識させる必要があります。
「ツール」→「ボード」→「ボードマネージャ」から「Arduino megaAVR Boards」をインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130771/136bebe8-12f1-8177-8e8c-5f55f53855e2.png)

インストール後、Ardiono Nano EveryをPCと繋ぎ、「ボード」「Registers emulation」「シリアルポート」を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130771/74e7e244-f241-48e2-d6fd-607a51d59440.png)

## ライブラリマネージャ
続いて、OLEDに文字を表示するため、ライブラリをインストールします。
今回使用するOLEDのICはSSD1306なので、「スケッチ」→「ライブラリをインクルード」→「ライブラリを管理」から「Adafruit GFX Library」と「Adafruit SSD1306」をインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130771/eb0417a3-fe38-f253-3025-3e75e51ab70a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130771/05e7095c-590a-2d35-00a7-afed59b21202.png)

# 結線
ブレッドボードにArdiono Nano EveryとOLEDを挿し、結線します。
とりあえず電圧は5Vを繋ぎ、あとはGNDとSCA、SCLをそれぞれ繋ぎます。

| Ardiono Nano Every | OLED |
|:---:|:---:|
| +5V | VCC |
| GND | GND |
| SCA | SCA |
| SCL | SCL |

![pin assign](https://content.arduino.cc/assets/Pinout-NANOevery_latest.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130771/5b749fe0-801e-c4ca-5b7f-480a536a87a9.png)

# サンプルプログラム
「Hello World!」と表示するプログラムを実行してみます。

```c
#include<Wire.h>
#include<Adafruit_GFX.h>
#include<Adafruit_SSD1306.h>

Adafruit_SSD1306 display(-1);

void setup() {
  // initialize
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
}

void loop() {
  // clear display
  display.clearDisplay();

  // set text parameter
  display.setTextSize(1);
  display.setTextColor(WHITE);

  // set text position
  display.setCursor(0, 0);

  // display text
  display.println("Hello");
  display.println("World!");

  // draw
  display.display();
  delay(1000);
}
```

これを実行すると、以下のように表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130771/6a5d55a9-780d-cfbe-db2e-36860048cf72.png)

# まとめ
非常に簡単に文字を表示することが出来ました。これで運用中（PCに繋いでいないとき）も値の確認が出来ます。
このOLEDは画像も表示できるのですが、その場合はちょっと工夫が必要になります。
それらもネット上に情報がありますので、そちらを参考にするのが良いかと思います。
Udemyメモ「データサイエンティストを目指すあなたへ〜データサイエンス25時間ブートキャンプ〜」

## 概要

[【世界で34万人が受講】データサイエンティストを目指すあなたへ〜データサイエンス25時間ブートキャンプ〜 \| Udemy](https://www.udemy.com/course/datascience365/)


## データサイエンスとは

### 分析と分析論の違い
- 分析
  - 過去に発生したデータについて、なぜ、どのように発生したかを説明
- 分析論
  - 過去の事象に対して、合理的な説明をすること
    - 定性分析: 直感やビジネス上の経験を通じて説明
    - 定量分析: 公式とアルゴリズムを通じて説明

## データサイエンスのテクニック

### 1: 従来データの扱い

1. 生データ
   - そのままの事実や初期データを示す処理前のデータ
   - 分析用のデータとして扱わない
   - サーバーに保存する前に加工してはいけない
   - データコレクションとも呼ばれる
2. データの前処理
    - ラベリング ( アクセス数等の量的、都道府県等のカテゴライズ )
    - クレンジング ( 入力ミス等の修正 )
    - 欠損データの決め ( レコードを削除？、平均値で代替え？ )
3. 特定ケース: データのバランシング
    - 属性に着目してデータのバラツキを 50:50 へ
    - ランダムに抽出 ( レコード全体から満遍なく )

### 2: ビッグデータの扱い

1. 生データ
    - 従来データに準じるが、画像やオーディオデータなどリッチなデータも含む
2. 特定ケース: データマイニング
 - excel,ブログ..様々なデータ形式からデータを抽出する技術
3. 特定ケース: 個人情報に触れず分析するデータマスキング
 - ランダム又はダミーデータで生データを隠蔽して分析
 - 重要な情報は安全な場所に保管

### 3: ビジネスインテリジェンスの取り扱い

1. 目的
   - ビジネス上において、経過や進捗を測定すること
   - 指標 <= 測定値 + ビジネス上の意味
2. 従来データとビッグデータから分析
   - 「データスキル + ビジネス上の知識経験」により過去のデータを解析
   - どれくらい商品販売できたか、どの地域で最も商品販売出来たか

### 4: 統計手法の取り扱い

1. 手法
   - 回帰分析 ( ２次元上にデータをプロットして、2次関数的に線形の傾向を導出 )
   - ロジスティック回帰 ( ２次元上にデータをプロットして、ロジスティック関数的に傾向を導出 )
   - クラスター分析 (２次元上にデータをプロットして、グループ毎の集合を導出 )
   - 因子分析 ( アンケート時において、類似質問を一つの変数にまとめる )

### 5: 機械学習の取り扱い

1. 基本
    - メリット: 人よりも効率的に目的に向けた手段を導出可能
    - 活用法: 複雑な数学モデルを改善
2. 種類 ( 教師あり学習 )
    - ターゲット: データの意味を事前に明瞭化されている
    - 目的関数: 正確性を測定する
    - 最適化アルゴリズム: 手段を改善可能である
3. 種類 ( 教師なし学習 )
    - データの意味がわからない場合に行われる
    - 教師あり学習前に、データのカテゴリ分けして意味を把握する
4. 種類 ( 強化学習 )
    - 損失を最小化し、報酬を最大化する
    - 教師あり学習に類似

## データ分析業界における職種
- データアーキテクト
  - データをどのように取得するかを構築する
  - データをどのように処理して、活用可能にする
- データエンジニア
  - 分析に活用可能とするためデータを処理する
- データベースアドミニストレーター
  - データを管理する
  - 主に従来のデータを担当
- BI アナリスト
  - データ分析してレポートを作成
- BI コンサルタント
  - 外部の BI アナリスト
- BI デベロッパー
  - プログラミングを通じて、会社特有の問題を解消
- データサイエンティスト
  - 従来の手法や、機械学習の手法を通じて将来を予測
- データアナリスト
  - より高度な分析を行う
- 機械学習エンジニア
  - 機械学習の高度なモデルを構築する
ERROR: Table has no partition for value from ...

## 概要
テーブルにレンジパーティションを貼る時、終端まで定義しないと、最後のレンジを超えた時に insert できなくてエラー発生する。

そのため、「キャッチオール」を定義して、パーティションの終端を用意する。

## 対策

```sql
PARTITION pmax VALUES LESS THAN MAXVALUE
```

- 参考URL
    - [mysql \- ERROR 1526 \(HY000\): Table has no partition for value 1426566990 \- Stack Overflow](https://stackoverflow.com/questions/29694539/error-1526-hy000-table-has-no-partition-for-value-1426566990/29695312)
    - [MySQLのパーティショニング \- 祈れ、そして働け ～ Ora et labora](https://tetsuyai.hatenablog.com/entry/20110308/1299569576)
    - [MySQL : 第15章 パーティショニング \- LANDHERE](https://landhere.jp/docs/manual/mysql/partitioning.html#partitioning-range)
    - [MySQL :: MySQL 5\.6 リファレンスマニュアル :: 19\.2\.1 RANGE パーティショニング](https://dev.mysql.com/doc/refman/5.6/ja/partitioning-range.html)
    - [pdf | 実践！パーティションの基本から実装例まで](https://www.oracle.com/technetwork/jp/ondemand/database/db-technique/d-12-disk-1484778-ja.pdf)
rsync --delete でサーバを壊した時の原因


## 概要
rsync --delete をシェルスクリプトに仕込んでサーバ壊滅した。

## 事象

bashCMS2 中の ./deploy コマンド実行で、サーバを吹っ飛ばした。
[ryuichiueda/bashcms2: a little CMS system written with bash](https://github.com/ryuichiueda/bashcms2)

原因は、コード手入力により不可視文字が入り込んだようで、 bin/conf ファイルを読み込めてなかったこと。

./deploy 中の rsync は、bin/conf ファイルで設定された変数を元にして、実行される。
そのため、引数が空になって、残った `/` が指定されてしまい、サーバを吹っ飛ばした。

## 対策

今から思えば、VSCode で ./deploy を開いていた時、txt ファイルのシンタックスカラーだったので、そこで違和感を持つべきだった。

rsync --delete で引数を使用する時は、気をつけるべき。
ドメインの初期設定とHTTPS化

## 概要
ドメイン初期設定と HTTPS 化 ( さくらの VPS　× Let's Encrypt )

## サーバの IP を確認

さくらの VPS は、デフォルトでドメインが割り当てられている。

そのため、デフォルト値を使用する。

なお、ドメインは、以下 URL の管理画面における `ホスト名` の箇所で確認できる。

https://secure.sakura.ad.jp/vps-beta/servers/:id/info

## サーバのドメイン設定

```bash
$ echo ${ホスト名} | sudo tee /etc/hostname
$ sudo reboot
```

## HTTPS 化 ( Let's Encrypt )

### 設定ファイルの調整

```bash
$ cd /etc/apache2/sites-available/
$ sudo cp 000-default.conf ${新設定ファイル}.conf
$ vim ${新設定ファイル}.conf
```

```diff:${新設定ファイル}.conf
- <VirtualHost *:80>
+ <VirtualHost ${ドメイン名}:80>
```

```bash
$ cd /etc/apache2/sites-enabled

$ sudo rm 000-default.conf

$ sudo ln -s ../sites-available/${新設定ファイル}.conf ./

$ sudo service apache2 restart
```

### Let's Encrypt のインストール

```bash
$ sudo apt install letsencrypt python-certbot-apache
```

### サーバ証明書を取得

```bash
$ sudo letsencrypt --apache
```

Question | Answer
---|---
Enter email address | 自分のメールアドレス ( 証明書更新時期に連絡あるかも？ )
Please read the Terms ... | 規約に同意できる場合は、Agree
Would you be willing to share your email address... | 任意
Which names would you like to activate https for ? | HTTPS 化したいドメインを選択
Please choose whether or not to redirect HTTP traffic to HTTPS | 2\. Redirect

### 終了

Let's Encrypt におけるサーバ証明書の有効期限は、`90 日間` である。

証明書の更新時は、以下のコマンドを実行すること。

```bash
sudo letsencrypt renew
```

- 参考 URL
    - [よくある質問 \(FAQ\) \- Let's Encrypt \- フリーな SSL/TLS 証明書](https://letsencrypt.org/ja/docs/faq/#:~:text=Let's%20Encrypt%20%E3%81%AE%E8%A8%BC%E6%98%8E%E6%9B%B8%E3%81%AE%E6%9C%9F%E9%99%90%E3%81%AF%E3%81%A9%E3%81%AE%E3%81%8F%E3%82%89%E3%81%84%E3%81%A7%E3%81%99,%E6%9C%9F%E9%99%90%E3%81%AF%2090%20%E6%97%A5%E9%96%93%E3%81%A7%E3%81%99%E3%80%82)


## メモ: 無料ドメインの取得

使用期限が 1 年未満となるが、無料ドメインの選択肢が存在する。

- 参考 URL
    - [Freenom](https://my.freenom.com/clientarea.php)
    - [freenomで無料ドメインを取得する｜ふじい｜note](https://note.com/dafujii/n/n406f385651e2)
    - [よくある質問 \- KAGOYA Internet Routing サポートサイト \- DNS設定が反映したか確認したい](https://support.kagoya.jp/kir/faq/index.php?action=artikel&cat=22&id=377&artlang=ja)
フロントエンド開発者のための刺激的なプロジェクト10選　1選目考察【後編】

https://qiita.com/nakada-web/items/25ff6287a04470afb1b3

前編に続き、

https://qiita.com/baby-degu/items/e720c2007716811c8b30

を、考察していきます。プロジェクト1選目は、下記リンクにて確認できます。

https://codepen.io/bnhovde/pen/OJLYGKx

#getBoundingClientRect()
任意の要素の大きさ(height,width)と、ビューポートに対する位置を返す。

#clientX clientY
イベント発生時のマウスの座標を返す。
このプロジェクトでは`mousemove`イベントが発生した時にカーソルの位置を取得しています。

```JS
// Mouse position
const useMousePosition = () => {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  useEffect(() => {
    const setFromEvent = e => setPosition({ x: e.clientX, y: e.clientY });
    window.addEventListener("mousemove", setFromEvent);

    return () => {
      window.removeEventListener("mousemove", setFromEvent);
    };
  }, []);

  return position;
};
```

#Math.atan2(y,x)
指定した座標を元に平面上の角度を取得できる。第1引数にy座標、第2引数にx座標を指定するのに注意。このプロジェクトでは上記の`getBoundingClientRect`と`clientX clientY`で取得した座標を元に、画面右下のマウスをキャッチしてくるおじさんから角度を計算しています。

```JS

const Grabber = ({ state, gameOver, extended, onCursorGrabbed }) => {
  const mousePos = useMousePosition();
  const [ref, position] = usePosition();
  const hasCursor = false;

  // Calculate rotation of armWrapper
  const x = position.left + position.width * 0.5;

  const y = position.top + position.height * 0.5; 

  const angle = gameOver ? 0 : Math.atan2(mousePos.x - x,-(mousePos.y - y)) * (180 / Math.PI);

  // Ensure value is within acceptable range (-75 to 75)
  const rotation = Math.min(Math.max(parseInt(angle), -79), 79);
  
  const grabberClass = `grabber grabber--${state} ${extended && "grabber--extended"}`;
  const wrapperStyle = { transform: `rotate(${rotation}deg)` };

  let handImageSrc = ASSETS[state];

  return (
      
    <div className={grabberClass}>
      <div className="grabber__body"></div>
      <img className="grabber__face" src={ASSETS.head} />
      <div className="grabber__arm-wrapper" ref={ref} style={wrapperStyle}>
        <div className="grabber__arm">
          <img
            className="grabber__hand"
            src={handImageSrc}
            onMouseEnter={onCursorGrabbed}
          />
        </div>
      </div>
    </div>
  );
};
```

Math.atan2で計算した角度はラジアンなので、度数法に変換するために、`(180 / Math.PI)`を乗じています。
ここまでは理解できたのですが、本来ならy座標を指定する第1引数にx座標、x座標を指定する第2引数にy座標を指定している点や、変数rotationの計算式で出てくる`79`と`-79`いう数字の意味が理解できませんでした。
どなたか解説頂けると幸いです。


#アウトプット
この前編、後編の考察で学んだことをアウトプットしてみました。
下のリンクをクリックすると柴犬をなでなでできると思うので、なでていってやってください。(スマホ対応してないです。)

https://daikidaiki1583.github.io/dogear/

https://github.com/daikidaiki1583/dogear
Web サーバの初期設定 ( Ubuntu × Apache )

## 概要
Web サーバの初期設定 ( Ubuntu × Apache )

## 手順
### インストール

```bash
$ sudo apt install apache2
```

### エラーにサーバ情報を隠蔽

エラー画面において、デフォルトでは、フッターに Apache の情報が表示される。

そのため、最低限の対策として、当該情報を隠蔽する。


```bash
$ sudo vim /etc/apache2/apache2.conf
```

Apache の設定ファイルの下部に以下の設定を追加する。

```diff:/etc/apache2/apache2.conf
+ ServerSignature Off
+ ServerTokens ProductOnly
```

```bash
$ sudo service apache2 restart
```

- 参考 URL
    - [たった2行でできるWebサーバ防御の「心理戦」 \(2/3\)：セキュリティ対策の「ある視点」（1） \- ＠IT](https://www.atmarkit.co.jp/ait/articles/0707/19/news141_2.html)
ubuntuの初期設定

## 概要

Ubuntu の手順

## 手順

### OS インストール後

#### Set up users and passwords

Question | Answer
---|---
Full name for the new user | ${自分の名前を入力}
Username for  your account | ${アカウントのユーザ名を入力}
Choose a password for the new user | ${パスワード入力}
Re-enter password to verify | ${パスワード再入力}


#### Partiton disks

Question | Answer
---|---
Partitioning method | Guided - use entire disk
Select disk to partition | Virtual disk 1 (vda)
Write the changes to disks? | Yes

### Finish the installation

1. `Continue` 選択
1. 再起動後に再接続


### 好みのサーバ設定

```bash
# 好みのテキストエディタ
$ sudo apt install vim

# 日本語設定
$ sudo apt install manpages-ja manpages-ja-dev language-pack-ja
$ sudo update-locale LANG=ja_JP.UTF-8
```

### SSH認証設定

id_rsa 生成が初回の場合、`ssh-keygen` のみでよし。

既存の id_rsa と別管理にしたい場合、以下の手順とする。

```bash
# ローカル
## 新サーバ用の SSH Key を生成
$ cd ~/.ssh/

$ ssh-keygen -t rsa -b 4096 -f id_rsa_${別名用の suffix}
> 全部リターンでも良い （ 強度高めたい場合は追加調査 ）

## 公開鍵を新サーバに送信
$ scp ./id_rsa_${別名用の suffix}.pub ${ユーザ名}@${IPアドレス}:~/
```

```bash
# リモートサーバ
## SSH接続元に対して接続を許可する公開鍵を設置する `.ssh/authorized_keys` 設定

$ mkdir .ssh

$ mv ${公開鍵} ./.ssh

$ chmod 700 .ssh/

$ cat ${公開鍵} >> .ssh/authorized_keys

$ chmod 600 .ssh/authorized_keys

$ rm ${公開鍵}
```

### SSH接続時の設定ファイル

ここまでの設定では、SSH接続時に `ssh ${ユーザ名}@${IPアドレス}:~/ -i ${秘密鍵のファイル名}` と入力する必要がある。

そのため、~/.ssh/config を設定することにより、入力を省略可能にする。

```bash
$ vim .ssh/config
```

```txt:~/.ssh/config
Host ${ssh コマンドで使用する任意のサーバ名}
  User ${接続先のユーザ名}
  Hostname ${接続先のIPアドレス}
  IdentityFile ~/.ssh/${生成した秘密鍵名}
```

- 参考URL
    - [ssh\-keygenでファイル名を指定して鍵を生成する \- Qiita](https://qiita.com/goldbook@github/items/575981f3ec0bc582ea24)
    - [SSH で複数の秘密鍵を使い分けるいくつかの方法 \- Ellinikonblue\.com Weblog](http://www.ellinikonblue.com/blosxom/UNIX/20150721SSH.html)
    - [インフラエンジニアじゃなくても押さえておきたいSSHの基礎知識 \- Qiita](https://qiita.com/tag1216/items/5d06bad7468f731f590e)
    - [~/\.ssh/configについて \- Qiita](https://qiita.com/passol78/items/2ad123e39efeb1a5286b)


### パスワードログインを無効化

```bash
$ sudo vim /etc/ssh/sshd_config
```

```diff:/etc/ssh/sshd_config
- #PasswordAuthentication yes
+ PasswordAuthentication no
```

```bash
$ sudo service ssh restart
```

## 断念したこと
### IP 制限

固定 IP が必要になるが、家庭用回線において、基本的に別途オプションが必要である。

nuro 光の場合は、ビジネス契約が必要になるから、設定不可だった。

- 参考 URL
    - [さくらのVPS パケットフィルタで「許可する送信元IPアドレス」設定追加のお知らせ – さくらのVPSニュース](https://vps.sakura.ad.jp/news/vps-pf-ph3/)
    - [NURO 光で固定IPアドレスを使う方法を解説！変動型との違いは？ \| NURO 光](https://www.nuro.jp/article/koteigata-ip/)
bashrcの環境変数が使えなくて困っていた件

# 3行でまとめると
- Bashのシェルスクリプトを実装した。
- ~/.bashrcに定義しておいた環境変数をシェルの中で使おうとしても存在していない。
- なるほど、~/.bashrcに`export`がいるのか！！

# 背景
こんなコードをつくった。
`$work_root`が~/.bashrcに記述してある環境変数。

```Bash:main.sh
#!/bin/sh

work_dir=${work_root}/yyy/ddd/mmm/work;

cp -r $HOME/work/* ${work_root};
```
動かした結果

```
cp: cannot create regular file `/yyy/ddd/mmm/work': No such file or directory
```
`$work_root`の部分がない・・・だと・・・
ちなみに対話型シェルでは

```
echo $work_root
```
で

```
/home/xxx/hoge
```
と出てくる。

# 改善点
`.bashrc`の中身の部分の記述がよろしくなかったようです。

```Bash:~/.bashrc（改善前）
work_root=/home/xxx/hoge
```

これを、こうする。

```Bash:~/.bashrc（改善後）
work_root=/home/xxx/hoge;
export work_root;
```

これでシェルスクリプト内で`$work_root`が使えるようになる。

# まとめ
- 対話型シェルを使うときは`export`なしでも環境変数が使える。
- シェルスクリプトでは`export`が必要。
REMOTE HOST IDENTIFICATION HAS CHANGED!

## 概要
ssh 接続時にエラー発生

## エラー内容

発生手順

1. サーバ吹っ飛ぶ
1. OS 再インストール
1. ssh 接続を試みる
1. 以下の通りエラーが発生

```bash
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
...snip...
```

## 原因

SSH接続先の情報について、接続元が以下のファイルに保存される。

そのため、OS再インストール等により接続先の情報が変わったため、不整合が生じた様子。

保存場所: `cat ~/.ssh/known_hosts`

> SSHでは、安全な接続を行うために接続先サーバの情報(RSA公開鍵のフィンガープリント)を、クライアントは保存する。SSH接続時には、以前保存したこの情報と、いままさに接続しようとしているサーバの情報が一致しているかを確認する。こうすることで、ユーザ（クライアント）が知らない間に、別のサーバへ接続してしまうことを防ぐ。よりセキュアになるってわけだ。
>> [SSH接続エラー回避方法：\.ssh/known\_hostsから特定のホストを削除する/削除しないで対処する3つの方法 \- Qiita](https://qiita.com/grgrjnjn/items/8ca33b64ea0406e12938)



## 対策

`vim ~/.ssh/known_hosts` により、以前の接続情報を削除した。