OmniAICreator/Qiita-1.07M huggingface dataset:
AWS EC2へIAMロールを紐付け

# 概要

- AWS EC2へIAMロールを紐付ける方法をまとめる

# ご注意

- AWSは従量課金です。
- 本作業で料金が発生する可能性があります。
- 筆者は本作業で発生するいかなる料金も負担する事ができません。
- ご自身の責任の下作業をお願いいたします。

# 前提

- 下記に近い方法でIAMロールが作成されていること。
    - [AWS IAM ロールの作成](https://qiita.com/miriwo/items/e7308e8303527d45b9ff)
- EC2インスタンスが起動していること。

# 方法

1. AWSにログインしてEC2の画面を開く。
1. インスタンス一覧でIAMロールを割り当てるEC2を選択する。
1. 「アクション」→「セキュリティ」→「IAMロールを変更」をクリックする。

    ![インスタンス___EC2_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/48c4c1da-b2b8-bf74-d5c0-28eb98aee62a.png)

1. IAMロールを選択して「保存」をクリックする。
CircleCIで要dockerのcdk deployする

`cdk deploy` でdockerが必要になることがあります。(少なくともlambdaのpythonランタイムのデプロイでは必要だった)
CircleCIで要dockerの`cdk deploy`を実現しようとしてハマったので方法を共有します。

# Executor Type
Executor Typeは`machine`を選択します。
私は既存のデプロイ環境を元にExecutor Typeを`docker`として、実現方法を探し始めました。
以下の2つのアプローチをしましたが、どちらも中々うまく行かず断念しました。

## ダメ1
* Executor Typeは `docker` 
* setup_remote_dockerを使う
* AmazonLinuxベースのdockerを実行環境として、Docker in Docker(以下dind)できるようにしてトライ。

### だめな理由
setup_remote_dockerを使って立ち上がるdockerに、ディレクトリのマウントが出来ないことに起因するcdk deployの失敗。(たぶん)

## ダメ2
* ダメ1を元に、ディレクトリのマウントも自由にできるという ECRにdocker:dindベースのイメージを作りそれをexecutorとする方法。

### だめな理由
* このイメージを実行する時に`--privileged`しないと、dindが実現できないと思われる
* しかし`--previledged`を指定してコンテナ(CircleCIの実行環境)を起動する方法がわからなくてCircleCI上でdind出来なかった

# 具体的な実現方法
実際はもっと複雑ですが、要素だけ抜き出すとこんなconfig.ymlで実現できました。

```
version: 2.1
orbs:
  # cdkの実行に必要
  node: circleci/node@5.0.1
jobs:
  deploy:
    machine:
      image: ubuntu-2004:current
    steps:
      - checkout
      - node/install:
          install-yarn: true
          node-version: '16.13'
      # docker使えるか確認
      - run: docker info 
      - run: npm ci && cdk deploy
```

orbがあるので無理にカスタムdockerイメージを使う必要性がだいぶ少なくなっているのかもしれません。

# まとめ
そもそもmachineで調べ始めたらこんな苦労はなかったんだな :thinking:
GOPATH と go module を理解するためのメモ

この記事はほぼ自分用メモです。

### 概要
- GOPATH, GOROOT, go mod を理解できてなくていろんなところでつまずく
- goenv 使わない限り GOROOT は気にしなくてもよさそうだから、とにかく GOPATH と go mod を理解したい
- 以下の記述はこれらのページを参照して自分用に整理したものなので、不明点・曖昧箇所があった場合はこちらを参照すること
    - [Go のモジュール管理【バージョン 1\.17 改訂版】](https://zenn.dev/spiegel/articles/20210223-go-module-aware-mode)
    - [Go1\.16からの go get と go install について \- Qiita](https://qiita.com/eihigh/items/9fe52804610a8c4b7e41)
    - [go mod完全に理解した](https://zenn.dev/optimisuke/articles/105feac3f8e726830f8c)


### Go Module が導入された理由
Go 1.11 以前のモード（のちに `GOPATH mode` と呼ばれる）は、いろんなプロジェクトのコードを全部 `GOPATH` 以下で管理していたため、ソースコードを好きな場所に置けなかったり、プロジェクト毎に異なるバージョンのパッケージを使うことができない問題（GOPATH汚染問題）があったため、これを解消するために導入された。

### モジュールとパッケージの違い
- パッケージは特定の物理ディレクトリ内全部
- モジュールは go.mod ファイルのあるディレクトリ以下の全パッケージを内包し、バージョン毎に異なるモジュールと見なされる

### 歴史と経過
- GO 1.11 で導入された (`GO111MODULE` のデフォルトは `auto`）
- Go 1.16 で大幅変更
    - `go install` 動作変更（ビルド・インストール用となる）
    - `go get` は `go.mod` 編集用となる
    - `GO111MODULE` のデフォルトが　`on` に変更
    - `go build`, `go test` では `go.mod` が変更されなくなった
- Go 1.18 からは `go get`　からバイナリインストール機能が削除された

### Go Module と mode
- GOPATH mode: 全てのソースコードとバイナリが `GOPATH` 下に入り、パッケージは最新バージョンのみ使える。
- module-aware mode: バイナリのみ `GOPATH` 下に入り、ソースコードは任意のディレクトリに置ける。パッケージはバージョン指定して使える。

### GO111MODULE 環境変数による切り替え
- on: module-aware mode になる
- off: GOPATH mode になる
- auto: go.mod が存在するディレクトリでのみ module-aware mode になる

今更 GOPATH mode を使う理由はないので、`GO111MODULE` は `on` にするか、そもそも定義しなくてよい（Go 1.16 以降はデフォルト `on` になったため）。

### go.mod の役割
- モジュール名が記述される (`module github.com/tmishina/myapp`)
- 使う go バージョンと依存モジュール情報などを含む

### go install と go get
- `go install <package>@<version>` で任意のモジュールをインストールできる。このとき、go.mod は変更されない
    - 例: `go install golang.org/x/tools/gopls@latest`
- `go get` は、現時点では忘れてよい。Go 1.18 からダウンロードする機能はなくなる。


### 開発時の基本な流れ
1. `go mod init github.com/tmishina/myapp` を実行して `go.mod` 生成
1. ソースを書く（`import`記述がソースコード内に現れる）
1. `go mod tidy` 実行することで、不要モジュール削除・不足モジュール追加が自動的に行われる（よって通常の開発プロセスにおいては `go install` も `go get` も実行不要）
初心者ブロックチェーンに挑戦する　21

# のんびりしたゲーム

## 金は天下の回りもの

 [UNCHAIN](https://app.shiftbase.xyz)の課題も三つ目になって、ちょっとは慣れてきた。油断は禁物だし、次々新しい技術が組み込まれてくるので、イージーになるという意味ではない。ただ、種をまいて、発芽して、双葉が出て、本葉になる、ぐらいのところまでのセットアップは、スムーズにいきます、というていどのことだ。

　三つ目の課題はゲームづくりだ。この世界、ゲームは避けて通れないんだろうけれど、対戦ゲームに興味のない身に、格段に煩雑になる手順が襲いかかる。いわく、相手がどんなキャラクターを持っているか、アタック能力や、現在のHPはどれぐらいか、とかなんとか、読み込んだり、変更したりする情報量が、これまでの静的な課題とは段違いに多いのだ。

　テキストには有名なキャラクターが使われていたが、著作権の問題か、とちゅうで変わった。オンラインテキストはこれが簡単だからおもしろい。ときどき、変更し忘れて、昔のキャラが残っていたりする。新しいキャラクターも、いつまで使えるのかわからない。自分でつくるときはできるだけオリジナル画像を設定しましょうって言うから、iPadでお絵かきなんか始めて、けっきょくオープニング画面、敵キャラ、味方キャラ三体、計五枚も描いてしまいましたよ。それをアップロードして、onchainにして、importして、使う。こういう決まった手順が、やっぱり回を重ねるごとに楽になるわけだよね。

　しかし、できあがったゲームは、まあ、世に言うゲームとはほど遠い。

- サイトに着く。お財布持ってますか、と聞かれる。
- ウォレットを繋ぐ。
- どのキャラで遊びますか、と聞かれて選ぶと、ミントのためにガス代払いますか、と聞かれる。
- 支払いを承認する。
- 選んだキャラがミントされるのを待って、攻撃ボタンを押すと、攻撃のためにガス代払いますか、と聞かれる。
- 支払いを承認する。
- しばらくお待ちください･･････ボスのHPが○○、あなたのHPが××になりました。

　ゲーム中毒を治すにはバツグンの効果があるかもしれない笑　
　支払っているのは、ブロックチェーンで処理するためのガス代であって、サイトの運営者の収入になるわけではない。これがどういう経済で成り立っていくのか、私にはまだわからない。

　一方、「歩いて稼ぐ」系ゲームでは、まず現実のお金＞仮想通貨＞仮想のスニーカーを買わなければならない。元は取れる、というけれど、そのお金がどこから湧いてくるのか、見定める目も必要になるよね。
【Python3】tweepy.Streamでツイートを全文取得する(2022年3月時点)

tweepy v4からStream周りの仕様が色々と変わっており、紹介されている方が少ない気がしたので備忘録として書いておきます。

## 環境
- Python 3.9.10
- tweepy 4.6.0

## ソースコード
```python:timeline.py
import tweepy

class StreamListener(tweepy.Stream):
    # ツイート取得時の動作
    def on_status(self, status):
        # ツイートの全文を取得する
        if 'extended_tweet' in status._json:
            text = status._json['extended_tweet']['full_text']
        elif 'extended_tweet' not in status._json:
            text = status.text

        # ツイートを出力
        tw = '[@{username}] {text}\n'.format(username = status.user.screen_name, text = text)
        print(tw)

streamlistener = StreamListener('ConsumerKey', 'ConsumerSecret', 'AccessToken', 'AccessTokenSecret')

streamlistener.filter(track=['python'])
```

## 参考
- [twitter - Error when trying to get full_text for a Tweet using Tweepy and Python - Stack Overflow](https://stackoverflow.com/questions/71159646/error-when-trying-to-get-full-text-for-a-tweet-using-tweepy-and-python/71209546)
ハマりポイントから学ぶ ALB と NLB の違い

# はじめに
NLB を利用した構成でハマったポイントがあったため、ALB との違いを交えて紹介します。

構成図はこちらです。
![nlb-drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619762/08a3a8bc-fbb7-71d6-83f0-f36d089553ac.png)


NLB を選んだ理由は L4 でトラフィックルーティングしたかったからです。
ALB を挟んで SSL オフロードしたりせず、HTTPS のまま EC2 まで到達させます。

# ポイント
ポイントとなる ALB との相違点は下記になります。

* NLB は Security Group をアタッチできない
* NLB はクロスゾーン負荷分散はデフォルトで無効

# ハマリポイント1 ｜ NLB からのヘルスチェックに失敗する
### 事象
ターゲットグループで設定しているヘルスチェックが成功せず、`Unhealthy` 状態になっていました。
ヘルスチェックのプロトコルは `TCP` 、ポートは `Traffic port` となっており意図した通り設定されていました。
試しに外部からリクエストしたところ、正常なレスポンスが返っていました。
よって、ヘルスチェックにだけ問題がある状態でした。

### 原因と対応
原因は NLB が設置されているサブネットの IP アドレスを許可していないことでした。
NLB には Security Group をアタッチできないため、アドレス制限の観点では Client からのリクエストは直接 EC2 に到達します。
EC2 の Security Group は Client の IP アドレスのみ許可する設定になっていました。

Client からのアクセスの場合は、Client の IP アドレスが評価されるため問題なくリクエストが処理されます。
![traffic_client.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619762/002372de-b4d8-b40b-f179-559dfca3edc9.png)

一方で NLB からのヘルスチェックの場合は、
NLB が配置されているサブネットの CIDR を許可していないため Security Group によって弾かれてしまいます。
![traffic_healthcheck.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619762/b9366117-5ec3-b6f9-b288-3ae24c6b0f34.png)

EC2 の Security Group でサブネットの CIDR を許可することでヘルスチェックが通るようになりました。

ALB ではこのような事象は基本起きないです。
ALB は Security Group をアタッチ可能であるため、EC2 の Security Group で、
ALB にアタッチされた Security Group からのアクセスを許可するのが一般的です。
こうすると、「Client からのリクエスト」と「 ALB からのヘルスチェック」はネットワーク的に差分がありません。

# ハマリポイント2 ｜ クロス AZ でトラフィックルーティングされない
### 事象
NLB にアクセスしたとき、配下の EC2 に負荷分散されることが想定でした。
しかし、実際には、AZ1 の NLB にアクセスしたときには AZ1 の EC2 、
AZ2 の NLB にアクセスしたときには AZ2 の EC2 しかレスポンスを返しませんでした。

![nlb-3drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619762/b90da735-73ef-4205-9a6d-fcc40795b207.png)

つまり、片側の NLB から見た EC2 は実質1台になっており、フェイルオーバーが実現できないことになります。

### 原因と対応
原因は NLB の設定漏れでした。

>Application Load Balancer では、クロスゾーン負荷分散が常に有効になっています。
Network Load Balancer と Gateway Load Balancer では、クロスゾーン負荷分散はデフォルトで無効になっています。ロードバランサーの作成後は、いつでもクロスゾーン負荷分散を有効または無効にできます。
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/userguide/how-elastic-load-balancing-works.html

ロードバランサーの属性 `load_balancing.cross_zone.enabled` を True にすることで解決しました。

# 相違点まとめ

|     | ALB | NLB | 
| --- | --- | --- | 
|   レイヤ |  L7   |   L4  | 
|   Security Group |  アタッチ可   |  アタッチ不可   | 
|  クロスゾーン負荷分散 |  デフォルト有効 | デフォルト無効  | 
|  EIP |  アタッチ不可| アタッチ可 | 

↑ きっと他にもありますが、この記事で触れた部分だけになります。
安全なSQLの呼び出し方　SQLインジェクション対策【個人的なお勉強アウトプット】

## 参考記事
chrome-extension://efaidnbmnnnibpcajpcglclefindmkaj/viewer.html?pdfurl=https%3A%2F%2Fwww.ipa.go.jp%2Ffiles%2F000017320.pdf&clen=730235&chunk=true

## SQLインジェクション攻撃とは
SQL文のリテラル部分は変動するパラメータ化することが一般的。
リテラルとして文法的に正しく文を生成しないと、パラメーターに与えられた値がリテラルの外にはみ出した状態になり、リテラルの後ろに続く文として解釈されることになる。

### 例
`$q = "SELECT * FROM atable WHERE id='$id'"; `

`$id`に以下の値を与える場合、
`';DELETE FROM atable-- `

パラメータを展開した後の　SQLは以下になる。
`SELECT * FROM atable WHERE id='';DELETE FROM atable--' `

結果、データベースの内容がすべて削除される。

## 安全なSQLの呼び出し方
- 文字列連結によるSQL文の組み立て
- プレースホルダによるSQL文の組み立て
    - 静的プレースホルダ
    - 動的プレースホルダ

### 文字列連結によるSQL文の組み立て
パラメータ部分への値の埋め込みを文字列連結によって実現する。
ただし、以下のプログラムにはSQLインジェクションの脆弱性がある。
```
$name = $_POST['name']; //... $sql = "SELECT * FROM employee WHERE name='" . $name . "'"; 
```

PHPの式`$name`が「山田」の場合、以下のSQL文が生成される。
`SELECT * FROM employee WHERE name='山田' `
SQLインジェクションの脆弱性をなくすには`$name`をクォートとして文字列連携する際に、`$name`の値に対するエスケープ処理が必要。エスケープが必要な文字はデータベースエンジンの種類や設定によって異なる。

#### 文字列連結による安全なSQL文生成
以下の要件を満たす必要がある。
- 文字列リテラルに対しては、エスケープすべき文字をエスケープすること
- 数値リテラルに対しては数値以外の文字を混入させないこと

しかし、文字列リテラル生成時にエスケープが必要な文字は、データベースエンジンの種類によって異なったり、データベースの背rっていによって異なる場合がある。データベースの種類や設定に応じたエスケープ処理を行わないといけない。
なので、SQLにおけるリテラルを文字列として生成する専用のメソッドや関数を用意している場合がある
例えば、PHPのPear::MDB2、ODOなど。

##### PHPのPEar::MDB2におけるquateの呼び出し
```
//ライブラリのロード
require_once 'MDB2.php'; 

//DBへの接続（PostgreSQLの場合）
$db = MDB2::connect('pgsql://dbuser:password:hostname/dbname?charset-utf=8';)

//文字列型を指定して、文字列チレたるのクォート済み文字列を得る
$db->quote($s, 'text')

//数値を指定して、数値リテラルの文字列を得る
$db->quote($n, 'decimal')
```

上記のようにquoteメソッドの第2引数で生成するリテラルの型を指定する。
`text`で文字列型を指定すると、データベースエンジンの種類や設定に応じて適切なエスケープ処理を施し、それをシングルクォートでくくった文字列を返す。
`decimal`などの数値型を指定すると、数値リテラルとしてふさわしい文字列を返す。

### プレースホルダによるSQL文の組み立て 静的プレースホルダ
プレースホルダのままのSQL文をデータベースエンジン側にあらかじめ送信して、実行前にSQL分の構文解析などの準備をしておく。SQL実行の段階で、実際のパラメータの値をデータベースエンジン側に送信し、データベースエンジン側がバインド処理をする。
SQL文の構文がバインド前に確定することから、プレースホルダにわたす文字列はクォートして記述する必要がない。そのため、シングルクォートのエスケープ処理も必要ない。数値リテラルも適切にバインドされる。
このことから、セキュリティの観点で、静的プレースホルダはもっとも安全。静的プレースホルダでは、SQLを準備する段階でSQL文の構文が確定し、後からSQL構文が変化することがないため、パラメータの値がリテラルの外にはみ出す現象がおきない。結果、SQLインジェクションの脆弱性が生じない。

### プレースホルダによるSQL文の組み立て 動的プレースホルダ
プレスホルダを利用するものの、パラメータのバインド処理をデータベースエンジン側で行うのではなく、アプリケーション側のライブラリで実行する方式。セキュリティの観点では、プレースホルダを用いたバインド処理によってパラメータの値の埋め込みがライブラリで機械的に処理されることから、文字列連結による組み立てに比べてアプリケーション開発者のミスによるエスケープ漏れを防止を期待できる。
ただし、動的プレースホルダは静的プレースホルダとは異なり、バインド処理を実現するライブラリによってはSQL構文を変化させるようなSQLインジェクションを許してしまう脆弱な実装のものが存在する可能性を否定できない

動的プレースホルダでも安全な書き方があるみたいだが割愛。
AWS Elastic IP 固定化したグローバルIPアドレスを取得してEC2インスタンスに割り当てる

# 概要

- AWS Elastic IPを用いて固定化したグローバルIPアドレスを取得してEC2インスタンスに割り当てる方法をまとめる。

# ご注意

- AWSは従量課金です。
- 本作業で料金が発生する可能性があります。
- 筆者は本作業で発生するいかなる料金も負担する事ができません。
- ご自身の責任の下作業をお願いいたします。

# 前提

- EC2インスタンスが起動していること。

# 方法

1. AWSにログインしEC2の画面を開く。
1. サイドバーの「Elastic IP」をクリックする。
1. 「Elastic IPアドレスを割り当てる」をクリックする。
1. 任意のリージョンを選択する。
1. パブリックIPv4アドレスプールは「AmazonのIPv4アドレスプール」を選択する。
1. 「割り当て」をクリックする。
1. 作成されたElastic IPを一覧で選択して「アクション」をクリックする。

    ![EC2_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/e3b51071-c3f9-031f-2e84-aca2db5cd2c6.png)

1. 「Elastic IPアドレスの関連付け」をクリックする。

    ![EC2_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/2e43d74e-eab1-3757-bfca-5afa2693cbf1.png)

1. 下記の様に選択・入力して「関連付ける」をクリックする。
    - リソースタイプ：インスタンス
    - インスタンス：任意のEC2インスタンス

1. EC2インスタンスの「詳細タブ」にて「Elastic IPアドレス」が設定されていれば紐付け完了。
<script>のdefer属性もっと流行れ

## 初めに

HTMLの`<script>`要素には`defer`属性がある。これを使うことで、HTML・JavaScript両方のコーディングが改善されるので、開発者はもっと取り入れるべきだ。

`defer`のブラウザ対応は非常に良い、というか**すべての現行ブラウザで利用可能**なので、使わない手は無い。

https://caniuse.com/script-defer

## 利点その1：DOMを読み込む`<script>`でも`<head>`内に置ける！

よくある`<script>`の書き方として、`<body>`の末尾に置くというプラクティスが良く知られている。WebページのDOMを操作するメソッドなどでよく使われる手法だ。しかし、これでは`<head>`にある先読みしておきたい`<script>`と場所が分散されてしまうので、HTMLの見通しが悪くなるという欠点がある。それにただのスクリプトは文書で遭遇した際に逐次読込が発生するのでローディングタイムが遅くなってしまう。

それを解決してくれるのが`defer`だ。これは`<script>`を「[文書の解析完了後かつ DOMContentLoaded が発生する前に実行することをブラウザーに示](https://developer.mozilla.org/ja/docs/Web/HTML/Element/script#attr-defer)」すものである。つまり、`<head>`に置いた`<script>`でも、文書構造が分かった状態で読み込めることになる。それもただ文章構造が読み込まれていることを期待して`<script>`を`<body>`末尾に置くのとは違い、**仕様で確約されている**。実際の読み込みタイミングは「[\<script> タグに async / defer を付けた場合のタイミング](https://qiita.com/phanect/items/82c85ea4b8f9c373d684#%E8%AA%AD%E8%BE%BC%E3%81%AE%E6%96%B9%E6%B3%95)」を読んで欲しい。

なお、`<script type="module">`の読み込みも基本的には`defer`スクリプトと同じタイミングである。というより `import` や `export` を使うことで、読み込み順の問題を回避できるし、旧来のJavaScriptの書き方でカプセル化ができるようになるので、これからは書き捨てのテストスクリプトをHTMLファイルに書く場合（残念ながら `import` 出来ない。何故だ？[^1]）以外は `module` に移行すべきである。

[^1]: つまりこれからはJSは別ファイルに分けましょうねということなのに、いちいち閉じタグを付けなければならないので冗長極まりない。CSSはインラインは `<style>` 要素で記述し、外部ファイル読み出しは `<link>` 要素で読み込むのに、それが無い。そもそも本来はスクリプトの種類を表すはずだった `type` 属性をJS仕様の設定に使うなど、拡張性が無いのは実におかしい。自分は本来Java用だったJVMという土台を用いるScalaやKotlinのように、HTTPというプロトコルを使いつつもJSにおける `var` のような問題ある文法や `for (let a in b)` という誰得機能などの歴史的経緯の頸木から外れた新しいフォーマットを作るべきだと本気で思っている。

なお、`defer`スクリプト同士の実行順はソース順のままなので、別に今まで通り`<body>`末尾に置いてもいい。移行の初期段階はそうすることだろう。HTMLをリファクタリングする段階で、`<head>`に移せばいい。

**DOMに関係ない処理（特に早めに済ませたいもの）は`async`、そうでないものは`defer`と住み分ける**のが重要だ。我々はDIOではないので、時、もといレンダリング処理を止めてまで処理を進める必要は皆無だ。

## 利点その2：イベントリスナを設定しなくてよい

`<body>`末尾法の場合、スクリプトを動かす際に`document.addEventListener("DOMContentLoaded", doSomething)`（一般的には`"load"`の方を使うかな。あんまり良いことでないけど）という風にイベントを設定する必要がある。

しかし、`defer`スクリプトはそんなことをせずに**トップレベルでスクリプトを書ける**（というよりむしろ、`document.addEventListener("DOMContentLoaded", doSomething)`とすると動作しなくなる）。

```defer.js
// こういうふうにスクリプトに直に書かれた関数が、deferスクリプト実行時に読み出される。
// しかもそもそもHTMLに<p>要素が無い場合を除いて、見つからないという例外が発生しない！
const paragraphs = document.getElementsByTagName("p");
```

これで関数を書くのが飛躍的に楽になるので、`defer`の存在を知ってからは私は`<script>`に必ず`defer`を付けることにしている（`async`が必要な関数を書かないので…）。

これでいて、デメリットは特に存在しない。本当に使わなきゃ損！
AWS Certificate Managerでssl証明書を取得する

# 概要

- AWS Certificate Managerにてssl証明書を取得する方法をまとめる。

# ご注意

- AWSは従量課金です。
- 本作業で料金が発生する可能性があります。
- 筆者は本作業で発生するいかなる料金も負担する事ができません。
- ご自身の責任の下作業をお願いいたします。

# 前提

- 任意のドメインをお名前.comなどで購入していること。
- AWS Route53にて購入しているドメインを用いてホストゾーンを作成していること。

# 方法

1. AWSにログインしCertificate Managerの画面を開く。
1. サイドバーの「証明書をリクエスト」をクリックする。
1. 「証明書タイプ」は「パブリック証明書をリクエスト」を選択して「次へ」をクリックする。

    ![AWS_Certificate_Manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/927b5cbf-a9cb-8704-33f2-6d6e199e6c38.png)

1. 下記の内容を入力・選択して「リクエスト」をクリックする。
    1. 「ドメイン名」には購入しているドメインを入力する。
    1. 「検証方法を選択」は「DNS検証」を選択する。
1. ssl証明書が発行されると、当該のドメインを登録しているRoute53のホストゾーンにAレコードを追加するボタンが表示されるはずなので登録する。
【php】SplFileObjectでcsvを読み込む前に(SJIS-win → UTF-8)


SJIS-winからUTF-8にエンコードする時は注意が必要。

```php:before

public function convertCsv($filePath){
        $csv = new SplFileObject($filePath);
        $csv->setFlags(
            \SplFileObject::READ_CSV |           // CSV 列として行を読み込む
            \SplFileObject::READ_AHEAD |       // 先読み/巻き戻しで読み出す。
            \SplFileObject::SKIP_EMPTY |         // 空行は読み飛ばす
            \SplFileObject::DROP_NEW_LINE    // 行末の改行を読み飛ばす
        );

       $readData = collect($csv)->map(function($data,$key){
                    mb_convert_variables('UTF-8', 'SJIS-win', $data);
                    .
                    .
                    .
       }

```

上記の置換、SJIS-winをそのまま```mb_convert_variables```とすると、SJIS-win文字によっては「\」で終わることがあり、これが、置換区別後の「""」と作用して「"\\"」で読み込まれて「\\"」が文字認識される場合があります。

```
dump($data)
置換前
=> b"Ä®ô«òÈÉM,âüü[âïÆ╩Æm,ÿAîgï@ö\",https ~ "
                                  ↑これ
置換後
=> "連携機能",https:// ~ "

>> 期待値はこうでありたい
=> "連携機能",
=> "https:// ~ ",

```



なので、変換するときはSplFileObject読込み前に以下のように修正するとうまいこと区別して読み込んでくれます。

```php:after

public function convertCsv($filePath){
        $fileData = file_get_contents($filePath); 
        $fileData = preg_replace("/\r\n|\r/","\n",$fileData); // 読込み行ごとの改行パターンを置換
        $encode = mb_detect_encoding($fileData, ['SJIS-win','UTF-8']); // 文字コード判定
        if($encode == 'SJIS-win'){
            $fileData = mb_convert_encoding($fileData,'UTF-8','SJIS-win'); // 区別してエンコード
        }

        $tmpName = tempnam(sys_get_temp_dir(), "csv"); 
        file_put_contents($tmpName,$fileData); // $tmpNameにファイルデータを詰めてからSplFileObjectで読込む
        $csv = new SplFileObject($tmpName);
        $csv->setFlags(
            \SplFileObject::READ_CSV |         // CSV 列として行を読み込む
            \SplFileObject::READ_AHEAD |       // 先読み/巻き戻しで読み出す。
            \SplFileObject::SKIP_EMPTY |       // 空行は読み飛ばす
            \SplFileObject::DROP_NEW_LINE      // 行末の改行を読み飛ばす
        );
        unlink($tmpName); // お掃除

        $readData = collect($csv)->map(function($data,$key){
                    return ($key !== 0) ? $this->convertItemGroup($data) : [];
                    .
                    .
                    .
                })
```

SplFileObjectで読み込む前に一旦、file_get_contents() で内容を取得します。
ファイルによっては改行パターンが\r\nや\rの場合があるので\nで置換します。
あとはエンコードすると、「\\"」問題は解消されました。
お名前.com ネームサーバーをAWS Route53に変更する

## 概要

- お名前.comで購入したドメインのネームサーバーをRoute53に変更する方法をまとめる。

## 前提

- 任意のドメインをお名前.comで購入していること。
- AWS Route53にて購入しているドメインを用いてホストゾーンを作成していること。

## 方法

1. お名前.comにログインする。
1. ドメイン一覧から当該のドメイン名をクリックする。

    ![ドメインNavi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/379bd8b6-bcfd-8ef2-2eb5-b89c50bbc374.png)

1. 「ネームサーバー情報」の「ネームサーバーの変更」をクリックする。

    ![お名前_com_Navi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/da315e71-85cc-1e46-effc-123dc30ef453.png)

1. 「ネームサーバーの選択」の「その他のネームサーバーを利用」をクリックする。

    ![ドメインNavi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/feda8a9b-66a1-648e-46cc-2cf2d42c1632.png)

1. 「その他のネームサーバーを使う」の部分でAWSのRoute53のホストゾーンのNSレコードの「ルーティング先」に記載されている4個の値を順不同で記載して「確認」をクリックする。

    ![お名前_com_Navi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/a7cefde1-37bd-810b-5150-c2195b6d2a16.png)

1. ターミナルで下記コマンドを実行してNSレコードのネームサーバーがRoute53のものと一致している事を確認する。（ネームサーバーの切り替えには時間がかかる場合があります。お名前.comで作業後すぐにはRoute53のNSレコードのルーティング先の値が表示されないかもしれません。）

    ```terminal
    $ dig ドメイン NS +short
    ```
ターミナルから当該ドメインのNSレコードのネームサーバーを確認する

# 概要

- ドメインのNSレコードに紐づくネームサーバーをターミナルで確認する方法をまとめる。

# 方法

1. 下記コマンドを実行する。

    ```terminal
    $ dig ドメイン名 NS +short
    ```
簡単にCPUに負荷をかける

シングルスレッド性能を測りたくて、いいツールないかなと調べてたら、性能測定ではないんだけど、負荷をかけるツールとしてSysInternals ToolのCPU Stressというのがあったので試した

ここからDLする
https://docs.microsoft.com/ja-jp/sysinternals/downloads/cpustres

CPUSTRES64.EXEを管理者実行したらツールが起動するので、シングルスレッドで実施したい場合は以下のように設定して、Activate Threadsを実行する

- 4コアCPUの4番目のコアにだけ負荷をかけてみる。Ideal CPUが3のスレッドだけ残し、他のスレッドを削除する
- 残ったスレッドを選択して右クリック、AffinityをクリックしてSelect CPU Affinityダイアログを出し、CPU3以外のチェックを外す
- Activity Level -> Maximum(100%)にする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620712/cc5a66d2-c533-7e5a-75ce-bafc23ccf5f1.png)

Activate Threadsをクリックすると、4番目のコアの負荷だけみるみる100%で張り付く
(CPU弱めの古いマシンでやったので、負荷確認用のリソースモニター自体の負荷で全体的にCPU使用率が高いのでわかりづらいけど、CPU3だけCPU使用率が張り付いている)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620712/6ca42a10-5aaa-4bf6-2394-229f2efe8f10.png)

終了するときは、Active?列がActiveになってるスレッドを選択してDeactive Threadsをクリックする
止め忘れ注意.. 
一定時間で停止するとか設定が見当たらないので、1コアだけ実行とかだと、気づかないままずっと高負荷かけ続けるとかやらかしえる
CPUの製品寿命とか耐久面での品質的な意味でのストレステストに..
AWS Route53 ホストゾーンの作成

# 概要

- AWS Route53にて新規でホストゾーンを作成する方法をまとめる。

# ご注意

- AWSは従量課金です。
- 本作業で料金が発生する可能性があります。
- 筆者は本作業で発生するいかなる料金も負担する事ができません。
- ご自身の責任の下作業をお願いいたします。

# 方法

1. AWSにログインしてRoute53の画面を開く。
1. サイドバーの「ホストゾーン」をクリックする。
1. 「ホストゾーンの作成」をクリックする。
1. 下記の情報を入力する。
    - ドメイン名：使用するドメインを入力する。
    - タイプ：インターネットからのアクセスに対応したものなら「パブリックホストゾーン」を選択する。
gorm with PostgreSQL で Primary Key / ID を UUIDv4 にするには ( Docker 対応 )

# Motivation
- できるだけ gorm 標準の `gorm.Model` に準拠させた形にして、gorm の恩恵を受けたい

```go
import (
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

type Product struct {
	gorm.Model
	Code  string
	Price uint
}
// → このままだと PK が uint / auto_increment フィールドになる
```

# 結論
以下のサンプルコードをご覧ください。

```go
type UUIDBaseModel struct {
	// UUID が主キーになり、UUID は Postgres が勝手に生成する
	ID        string `gorm:"primaryKey;size:255;default:uuid_generate_v4()"`
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt gorm.DeletedAt `gorm:"index"`
}

type Product struct {
	// UUIDBaseModel を含む struct は全て UUID が主キーになる
	UUIDBaseModel
	Code  string
	Price uint
}

func migrate() {
	dsn := "host=localhost user=user password=password dbname=dbname port=5432 sslmode=disable TimeZone=Asia/Tokyo"
	db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
		if err != nil {
			panic(err)
		}

	// 追加: PostgreSQL に拡張機能 "uuid-ossp" を追加する
	db.Exec(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`)

	// マイグレーションを行なう
	err = db.AutoMigrate(&Product{})
	if err != nil {
		panic(err)
	}
}
```

ポイントは以下の3点です。

- **マイグレーションを行なう前に**、SQL句 `CREATE EXTENSION IF NOT EXISTS "uuid-ossp";` を実行する
  go ではなく実際に SQL のコンソールに入って実行しても構いませんが、go で実行することをおすすめします。
  ```go
  db.Exec(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`)
  ```

- UUID が主キーになるようなモデルをつくる
  この構造体が埋め込まれた構造体はすべてで、Primary Key が UUID になります。
  ```go
  type UUIDBaseModel struct {
	// UUID が主キーになり、UUID は Postgres が勝手に生成する
	ID        string `gorm:"primaryKey;size:255;default:uuid_generate_v4()"`
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt gorm.DeletedAt `gorm:"index"`
  }
  ```

- 実際にマイグレートするモデルの構造体にはすべて `UUIDBaseModel` を含める
  ```go
  type Product struct {
	// UUIDBaseModel を含む struct は全て UUID が主キーになる
	UUIDBaseModel
	Code  string
	Price uint
  }
  ```

# Docker の `postgres` 公式イメージを使用している場合
マイグレーションを行なう前に、SQL句 `CREATE EXTENSION IF NOT EXISTS "uuid-ossp";` を実行する方法以外に、環境変数で拡張機能 `uuid-ossp` を追加することができます。
これにより、  ```db.Exec(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`)``` の追記が不要になります。
環境変数 `POSTGRES_EXTENSIONS=uuid-ossp` を追記して下さい。
```Dockerfile:Dockerfile
FROM postgres:9.6.23
USER root

# 以下を追記
ENV POSTGRES_EXTENSIONS=uuid-ossp
```

```yml:docker-compose.yml
services:
  postgres:
    environment:
      # 以下を追記
      POSTGRES_EXTENSIONS: uuid-ossp
```

# 参考文献
- [Using UUIDs with Gorm and Postgres – Sam's space](https://samu.space/uuids-with-postgres-and-gorm/)
- [データ型のカスタマイズ | GORM - The fantastic ORM library for Golang, aims to be developer friendly.](https://gorm.io/ja_JP/docs/data_types.html)
（備忘メモ）Django + MySQL で大量データを insert しつつ ID を取得したい場合

Django + MySQL でバッチ的にデータの登録を行いたかったのですが、微妙にテクニカルだったので備忘メモ

# bulk_insert では ID が拾えない

* <https://docs.djangoproject.com/en/4.0/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create>
  * If the model’s primary key is an AutoField, the primary key attribute can only be retrieved on certain databases (currently PostgreSQL, MariaDB 10.5+, and SQLite 3.35+). On other databases, it will not be set.
* 要件にもよると思うが、自分は他のテーブルに登録したデータを紐付ける必要があったので、ID 取得できないのは NG

# 対応策：通常のインサートを行いつつ、トランザクションを広めに取る

* 通常、Django は一回の insert ごとにトランザクションを貼る。
* これをまとめることで、性能改善が望める。

# 検証

## 条件

* MacBook Pro (13-inch, 2020)
  * 1.4 GHz Quad-Core Intel Core i5
* MySQL 5.7
* Django 1.11.18

## サンプルコード

```sh
# ディレクトリ構成
├── tmp_multi_insert_test
│   ├── __init__.py
│   ├── models.py
│   └── script.py
├── manage.py
```

```python
# models.py
from django.db import models

class test_model(models.Model):
    name = models.CharField(max_length=60)
```

```python
# script.py
# 100 件ごとにテスト
import timeit

from django.db import transaction

from models import test_model

def insert_in_loop(repeat=100):
    ids = \[]
    for i in range(repeat):
        new_model = test_model(name='tmp_{}'.format(i))
        new_model.save()
        ids.append(new_model.id)
    return ids

def insert(repeat=100, with_transaction=True):
    if with_transaction:
        with transaction.atomic():
            ids = insert_in_loop(repeat)
    else:
        ids = insert_in_loop(repeat)

start = timeit.default_timer()
insert(with_transaction=False) # 引数を切り替えながらテストする
stop = timeit.default_timer()
print(stop - start) 
```

### 実行方法

```sh
$ ./manage.py shel
>>> exec(open('./tmp_multi_insert_test/script.py').read())
Time:  0.49636074993759394
```

## 結果

各 10 回ぐらいずつやった平均値

| トランザクションあり    | トランザクションなし   |
| ------------- | ------------ |
| 0.094 | 0.480 |

およそ 5 倍の速度差がありました。
横スクロールをなくす方法

**サイトの横スクロールをできないようにする方法** 

cssのbodyに「overflow-x: hidden;」を指定する。
```css
body{
 overflow-x: hidden;
}
```

レスポンシブ対応のサイトを作っている時に右側に余白ができて困っていたところ、上記で解決しました！


※追記(2022/6/15)
現役エンジニアの方に上記のやり方はあまり好ましくないというご指摘をいただきました。
左右に空白ができてしまう問題を根本的な原因として、

・画面サイズよりもサイズの大きい要素が存在すること

があるそうです。
私の場合、Chromeのデベロッパーツールを使い、どの要素がはみ出してしまっているかを確認、調整すると全く左右にブレなくなりました！
（視覚的にはみ出していなくても、実際のサイズを確認するとはみ出しているものが見つかりました。）
AWS IAM ロールの作成

# 概要

- AWS　IAMにてロールを新規作成する方法をまとめる。
- 今回はEC2に割り当てるS3FullAccessだけを設定しているロールを作成する。

# ご注意！！！

- AWSは従量課金です。
- 本作業で料金が発生する可能性があります。
- 筆者は本作業で発生するいかなる料金も負担する事ができません。
- ご自身の責任の下作業をお願いいたします。

# 方法

1. AWSにログインしてIAMの画面を開く。
1. サイドバーの「ロール」をクリックする。

    ![IAM_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/2ddf6fb4-d2fa-7b94-4714-f9b61d992f58.png)

1. 「ロールを作成」をクリックする。

    ![IAM_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/ab07ad0f-bf53-c92a-1437-2dc043229482.png)

1. 今回はEC2に割り当てるロールなので「AWSのサービス」を選択して「ユースケース」では「EC2」を選択して「次へ」をクリックする。

    ![IAM_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/70adda47-6352-f66b-4c15-dda4809459b0.png)

1. ポリシーの選択画面で検索ウインドウに「S3」と入力して「AmazonS3FullAccess」を選択して「次へ」をクリックする。

    ![IAM_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/56a91b32-450c-374c-2079-83e24942aae0.png)

1. 任意のロール名を入力して、その他は特にいじらず「ロールを作成」をクリックする。

    ![IAM_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/6c0705ab-b5a4-8d2c-6997-7b9a73eca4ee.png)

1. エラーなどが出なければロールの作成完了
Excelエビデンス作成用マクロ

### 用途
エクセルで、期待値と実施結果を比較するマクロ。
マクロを実行すると期待値と実施結果が異なる箇所のセルが赤くなる（条件付き書式を設定している）。  
- i：期待値のデータ開始行
- s：実施結果のデータ開始行
- e：実施結果のデータ終了行
- col_s：データ開始列
- col_e：データ終了列

下のようなイメージの使い方ができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167355/de9ec73c-e606-8096-bebc-79cad3404961.png)

### マクロ
```
Sub test_checker()

Dim i As Integer
Dim s As Integer
Dim e As Integer
i = 3
s = 246
e = 354
Dim col_s As String
Dim col_e As String
col_s = "B"
col_e = "OU"

Dim k As Integer

For k = s To e
    Dim c As Range
    Set c = Range(col_s  & k, col_e & k)
        
    Dim formla As String
    formla = "IF(TEXT(" & col_s & i & ",\""＠\"")<>TEXT(" & col_s & k & ",\""＠\""),1,0)"
    c.FormatConditions.Add Type:=xlExpression, Formula1:="=IF(TEXT(" & col_s & i & ",""＠"")<>TEXT(" & col_s & k & ",""＠""),1,0)"
    c.FormatConditions(1).Interior.Color = XlRgbColor.rgbRed
    i = i + 1
Next
End Sub
```
SQL Boilerでintで生成されるフィールドをint32にする

SQL BoilerはDBスキーマから構造体などを生成してくれる便利ORMです。
DBスキーマの型からGoの型にいい感じにマッピングしてくれるのですが、DB（ここではPostgresSQL）でintegerで定義したものはGo上ではintで表現されるようになります。
これでも特に困らないことは多いのですが、OpenAPIやProtocolBuffersなどから生成されるGoのコードではintはint32で定義されるので、これらと相互に変換する際にはint32になっていたほうが都合が良いです。
intとint32の変換であればそこまで大変ではないのですが、 null許可されたカラムはnull.Intと*intで表現されるため、これを*int32にキャストはとてもめんどうです（めんどうというかやり方がわからなかった。）
*intを避けるのであれば、DBスキーマでNULL許容しなければよいという話ではあるのですが、その話をすると長くなるのでここではやめ、*intと真剣に向き合うことにします。
とは言え方法は簡単で、SQL Boilerの設定ファイルに以下のように記載するだけです。
```toml
[[types]]
  [types.match]
    type = "null.Int"
    nullable = true

  [types.replace]
    type = "null.Int32"

  [types.imports]
    third_party = ['"github.com/volatiletech/null/v8"']

[[types]]
  [types.match]
    type = "int"

  [types.replace]
    type = "int32"

```

null.Intにmatchしたらnull.Int32にreplace、intにmatchしたらint32にreplaceというふうにするだけです。
tomlの文法に癖があってREADMEをパット見ただけではわかりにくかったのですが、tomlの文法さえ理解すればかんたんですね。
Laravelでvue-test-utilsを使ってVueのテストをやってみた

# はじめに
最近、Laravel + Vueをよく使うのでVueのテストをうまいことできないか調べて試してみた備忘録的なものになります。
Vueのテストをするのに[vue-test-utils](https://vue-test-utils.vuejs.org/ja/)というものがあるようなので、それを使ってテストの環境を作ってみた話です。
(テストランナはいくつかあるようですが、mochaを使ってみました)

# テストを行いたい環境
- Laravel 9.0
- vue 2.5.17
- webpack 5.52.17
- npm 8.5.3
 
# やってみた
[こちらのページ](https://vue-test-utils.vuejs.org/ja/installation/testing-single-file-components-with-mocha-webpack.html)を参考に以下を実行しました。
```
npm install --save-dev @vue/test-utils mocha mocha-webpack jsdom jsdom-global expect
```

**めっちゃエラーで怒られました**

なぜ？と思い[mocha-webpack](https://www.npmjs.com/package/mocha-webpack)についてよくよく見てみると

> mocha-webpack works with
> webpack in version 2.x.x & 3.x.x

webpackバージョン2または3までしか対応していないとのこと。
ここでハマってしまい(正直、mochaをやめてJestにしようか)と思いながらも、気を取り直してなんかないか探しました。
そして見つけました。

[instant-mocha](https://www.npmjs.com/package/instant-mocha)

FAQをみると、なんかよくわからんけれど良さそう！
> This project was created from scratch because mocha-webpack is no longer maintained and doesn't have Webpack 5 support (and neither does its fork, mochapack).

- instant-mochaのサポートしているmochaバージョンは8
- [@vue/test-utils](https://github.com/vuejs/vue-test-utils)もそのままでは何気にバージョンの問題が発生していた
ということで、以下のように修正。

```
npm install --save-dev @vue/test-utils@1 mocha@8 instant-mocha jsdom jsdom-global expect
```

エラーが出まくって怒られることもなく無事だったので、再び先ほどの[参考ページ](https://vue-test-utils.vuejs.org/ja/installation/testing-single-file-components-with-mocha-webpack.html)に倣って準備を進めます。
(パスとかちょいちょい変えてます)

package.jsonに以下追記
```package.json
{
  "scripts": {
    (中略)
    "test": "instant-mocha --webpack-config node_modules/laravel-mix/setup/webpack.config.js --require test/setup.js test/**/*.spec.js"
  }
}
```
test/setup.js作成
```test/setup.js
require('jsdom-global')()

global.expect = require('expect')
```
テスト対象ファイル(resources/js/Assets/Counter.vue)作成
```resources/js/Assets/Counter.vue
<template>
  <div>
    {{ count }}
    <button @click="increment">Increment</button>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        count: 0
      }
    },

    methods: {
      increment() {
        this.count++
      }
    }
  }
</script>
```
テストファイル(test/Assets/Counter.spec.js)作成
```test/Assets/Counter.spec.js
import { shallowMount } from '@vue/test-utils'
import Counter from '../../resources/js/Assets/Counter.vue'

describe('Counter.vue', () => {
  it('increments count when button is clicked', async () => {
    const wrapper = shallowMount(Counter)
    await wrapper.find('button').trigger('click')
    expect(wrapper.find('div').text()).toMatch('1')
  })
})
```
これで　` npm run test ` を実行。
```
  Counter.vue
    ✓ increments count when button is clicked


  1 passing (39ms)
```

# まとめ
- webpack5 の環境では `mocha-webpack` ではなく `instant-mocha` を使う。
Laravel EC2 公開時に composer install できない

## 遭遇したエラー
~~~
composer install
~~~

error...

~~~bash
Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi

In Finder.php line 603:
                                    
  The "" directory does not exist.  
                                    

Script @php artisan package:discover --ansi handling the post-autoload-dump event returned with error code 1
~~~
## 環境
- EC2:ubuntu
- dockerコンテナ
 - app:php7.4系
    - Laravel(api)+React(ui)
 - web:nginx
 - db:mysql8.0


## 解決策
.gitignoreが起因してclone時に作成されなファイルまたはフォルダーを作成する
自分の環境で必要となったこと
~~~
mkdir -p storage/framework/cache/data/
mkdir -p storage/framework/app/cache
mkdir -p storage/framework/sessions
mkdir -p storage/framework/views
~~~

## 経緯
docker+Laravel(API)+React+mySQlで実装

local環境では問題なくうごいていたものが

aws EC2上に公開しようとして下記の流れで実装

1. git clone
1. ルートディレクトリー .env 作成 + 編集
1. docker-compose up -d --build
1. docker-compose exec app composer install



## 試したこと
ここから先はlogのようなものなので参考程度に御覧ください

1. 試したこと1
    1. .envファイル見確認
        - スペースが入っていないか
        - APP_ENV=production になっている
    1. .gitignoreみなおし
        - /configの記述を発見 しらべてみると.envより先によまれるものでプロダクトによっては記述がひちようになるがcnfigファイルはとくに目立った編集をしていないため公開することに
        - 別のエラー発生
~~~bash
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi

   InvalidArgumentException  : Please provide a valid cache path.

  at /work/backend/vendor/laravel/framework/src/Illuminate/View/Compilers/Compiler.php:36
    32|      */
    33|     public function __construct(Filesystem $files, $cachePath)
    34|     {
    35|         if (! $cachePath) {
  > 36|             throw new InvalidArgumentException('Please provide a valid cache path.');
    37|         }
    38| 
    39|         $this->files = $files;
    40|         $this->cachePath = $cachePath;

  Exception trace:

  1   Illuminate\View\Compilers\Compiler::__construct(Object(Illuminate\Filesystem\Filesystem))
      /work/backend/vendor/laravel/framework/src/Illuminate/View/ViewServiceProvider.php:92

  2   Illuminate\View\ViewServiceProvider::Illuminate\View\{closure}(Object(Illuminate\Foundation\Application), [])
      /work/backend/vendor/laravel/framework/src/Illuminate/Container/Container.php:799

  Please use the argument -v to see more details.
Script @php artisan package:discover --ansi handling the post-autoload-dump event returned with error code 1
~~~
MACアドレスはなぜ世界で一意でなければならないのか

表題を見て「そんな疑問をもつこと自体が理解できない」と思う人もいるでしょう。  
また、「実は一意とは限らないんだぞ」と言いたくてうずうずする人もいるでしょう。
そういう人は分かっている人だと思うので、特に読んでも得るところはないかもしれません。
（が、ご指摘やご質問があればいただきたく思います）

#### 疑問の背景
何となくの理解で済ませてきたインフラ知識をしっかり勉強しようと、
[佐野裕『インフラエンジニアの教科書２』（C＆R研究所, 2016年）](https://www.amazon.co.jp/dp/B01KSUGP28/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)をめくっていたところ、
OSI参照モデルのデータリンク層の説明に行き当たりました。（同書16-17頁）
この層の役割は
> 直接的（隣接的）に接続されている通信機器間の信号の受け渡し

受け渡し先の決定に用いる情報は
> MACアドレス

これを見て思ったのです。
MACアドレスは世界で一意（globally unique）だと新人研修で教わった記憶があります。しかし、近くの機器を識別するのが用途であるなら、近くの機器同士の間で一意であれば十分なのではないでしょうか？


#### 改めてMACアドレスとは

MACアドレスに関しては、
- @cironaga [MACアドレスとIPアドレスの違い](https://qiita.com/cironaga/items/6a0c909e31f986c9f825)（直観的に分かりやすい）
-  @s_oshima [ネットワークって何①](https://qiita.com/s_oshima/items/3d7832e595b859a25908)（情報量が多い割にコンパクト）
-  その他多数

の解説記事がQiita内外に存在しますが、屋上屋を架すことになるのを承知で簡単にまとめます。

##### MACアドレス
MACアドレス（Medium Access Control Address）はネットワークに参加する機器（PC、ルータ、スマホなど）に予め割り振られている識別番号です。フォーマットはIEEE（Institute of Electrical and Electronics Engineers, アイ・トリプル・イー）という団体が管理する規格[^1]に従います。

##### アドレスの管理
アドレス自体は、IEEEが払い出す組織識別子（OUI: Organizationally Unique Identifier）を受け取った各組織（機器のベンダーなど）が、さらに組織の中で一意になるような識別子をOUIに付加して発番されることになっています。理論上は上位ビットのOUIが全世界で一意（IEEEが管理）・下位ビットが組織内で一意（各組織が管理）なのでMACアドレス全体は世界で一意になることになります。

##### 何に使われているのか
主な用途としては、上述の通りOSI参照モデルでいうデータリンク層で、通信相手となる隣接機器を特定するのに使われています。
隣り合った機器同士はネットワークの区分としてはLAN（Local Area Network）を構成していますので、LANの通信規格であるIEEE802.X(802.3 Ethernetや802.11 Wi-Fi）でMACアドレスが活用されています。

#### 冒頭の疑問に戻る
LANでの使用なのだから、ローカルに一意であれば十分では？　というのが私の疑問でした。

具体的な使用の局面に限って言えば、それで十分だと考えられます。今いるLANの外部に、MACアドレスの重複する機器が仮に存在していたとして、それがLANの通信に何の支障があるでしょうか？
（上で言及した@s_oshima氏の記事にも「L2セグメント内で一意であれば、通信するうえで特に支障はありません」とあり、「そうだよね！」と思いました。）

しかしそれでも、世界で一意になるように管理する必要があります。
「今いるLAN」を構成するネットワーク機器は、理論的に言えば、世界中で流通している機器の中の任意の組み合わせでありうるからです。
どのベンダーからどのPCを買い、どのベンダーからどのルータを買い、それらをどう組み合わせようともLANが成立するようにするためには、そもそもそれらのベンダーが製造するすべてのPC、ルータに一意な番号を振っておかなければなりません。
ベンダーは世界で展開していますので、それは結局、世界で一意であるということです。

少し考えれば分かることですが、解答に思い至ってスッキリしました。

#### しかし一意ではない
本稿は、原則論としてなぜ一意性の保証が必要なのかを考察していますのでテーマから外れますが、実際には重複が発生することがあり、ネットワークエンジニアリング界隈では少し悩ましい問題であるようです。[Wikipedia](https://ja.wikipedia.org/wiki/MAC%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9#%E5%A4%89%E6%9B%B4%E3%81%A8%E9%87%8D%E8%A4%87)やWikipediaの参考文献に詳細な解説がありますのでご興味のある方は当たってみてください。

[^1]: [IEEEのアーカイブ](https://ieeexplore.ieee.org/Xplore/home.jsp)でMACアドレスの仕様書を探しましたが、ダウンロードが有料ということもあり、結局これというドキュメントの特定に至りませんでした。
セル関数のSUMIFSの使い方の応用（複数項目でのVLOOKUP的な使い方）　

# はじめに
EXCELのセル関数のSUMIFS関数を使って、
<font color=RED>**複数列でVLOOKUPを実行する**</font>ようなイメージ
あるいは別の表現では
<font color=RED>**SQLの LEFT JOIN を実現する**</font>ようなイメージ
または <font color=RED>**MATCH + INDEX関数の代替方法**</font>　
を実現する方法を思いついたので紹介します。


# サンプル
C列に該当する値をG列から取得する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411106/67fc49f2-9edb-3c6e-c969-ff690ed0686c.png)

# 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411106/e0b89ffd-fa87-e094-64fe-949d89650efe.png)

# セル関数
SUMIFS関数を使って実現する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411106/9a3bb108-9cc3-ecce-008f-7a91495c0d37.png)


# 問題点
・該当の列の属性が文字列の場合は使えない
・該当する行がなかった場合は、0となる（サンプルの10行目）
　※ただしCOUNTIFS関数をあわせて使えばエラーにすることも出来ます。
　例：```=IF(COUNTIFS(E:E,A2,F:F,B2)<>1, NA(), SUMIFS(G:G,E:E,A2,F:F,B2))```

2022/4/9 
文字列にも対応できる方法を思いつきましたので、以下の記事で紹介しています。
https://qiita.com/takahasinaoki/items/bfb104f7575ebb356ba9

# 関連記事

https://qiita.com/takahasinaoki/items/dc6834ea24d820446718

https://qiita.com/takahasinaoki/items/bfb104f7575ebb356ba9
Symfony6で突然zipコマンドが動かなくなった問題

## Symfony3.4では動いてたんや

[Symfony\Process](https://github.com/symfony/process)を用いて、複数ファイルをワイルドカード（＊）を使用して
１つのZIPファイルにまとめるコマンドを実行していました。

Processクラスに渡したコマンドは以下の通りです

```php
new Process(['zip', '-jrq', '-P', 'password', 'path/to/test.zip', 'path/to/test*.csv']);
```

```bash
# コマンド実行前
path
└── to
    ├── test_1.csv
    ├── test_2.csv
    └── test_3.csv

# コマンド実行後
path
└── to
    ├── test_1.csv
    ├── test_2.csv
    ├── test_3.csv
    └── test.zip # test_1.csv, test_2.csv, test_3.csvが全て入っている
```

このコマンドを**Symfony3.4**で実行すると、問題なく動作します。

## なぜかSymfony6では動かない...

しかし、**Symfony6**でそのコマンドを走らせると下記のようなエラーが出るようになりました。
もちろんZIPファイルも作成されていません。

```
zip error: Notiong to do ! (try: zip -jrq -P password /path/to/test.zip . -i  /path/to/test*.csv)
```

`zip -jrq -P password /path/to/test.zip . -i /path/to/test*.csv`を
代わりに試してくれよなと言われてしまいました。

## 原因

Symfonyの[github discussion](https://github.com/symfony/symfony/discussions/45877)にて、このエラーの原因について教えていただきました。

エラーの原因は、Processクラスのコンストラクタに渡されたコマンドの取り扱い方法が
Symfony3.4と6で変わっていたことでした。
その変更に伴い、圧縮対象のファイル名に含まれているワイルドカード（＊）の解釈の仕方も変わりました。

- **Symfony3.4**
    - コンストラクタに渡されたコマンドは一度シェルでプリプロセッシングされてから実行される
    - ワイルドカード（＊）は、[glob](https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%AD%E3%83%96)として扱われる
    - `test_1.csv` `test_2.csv` `test_3.csv`が圧縮対象のファイルになる

- **Symfony6**
    - コンストラクタに渡されたコマンドはシェルでラップされることなく直接実行される
    - ワイルドカード（＊）は、そのまま文字列として扱われる
    - `test*.csv`というファイル名は存在しないのでエラーが出る

## 解決策

解決策は、エラーメッセージが既に教えてくれていました。

```
(try: zip -jrq -P password /path/to/test.zip . -i  /path/to/test*.csv)
```

これをそのままProcessクラスのコンストラクタに渡せば無事実行することができました。
`-i`オプションを用いることで、ワイルドカード（＊)を[glob](https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%AD%E3%83%96)として認識させることができるようです。

```php
new Process(['zip', '-jrq', '-P', 'password', 'path/to/test.zip', '.', '-i' ,'path/to/test*.csv']);
```

## 後書き

普段はLaravelばかり触っており、Symfonyやシェルについてはまだまだ勉強中です。
もし、間違っているところなどありましたらコメント欄にて教えていただけると幸いです。

シェルのプリプロセッシングって厳密には何しているんでしょうか・・・？
詳しい方教えてください。

最後まで読んでいただきありがとうございました。
B - Collatz Problem 解説


## 問題
https://atcoder.jp/contests/abc116/tasks/abc116_b


## 考え方

nとaiは関数f(n)の項数となっている。
従ってn にaiを代入していく。


iが2、3、4、、、の時はai = f(ai -1)となる。
つまり、

```
i = 1の時　a1 = 8
i = 2の時　a2 = f(a1) = f(8) = 4 
i = 3の時　a3 = f(a2) = f(4) = 2 
i = 4の時　a4 = f(a3) = f(2) = 1 
i = 5の時　a5 = f(a4) = f(1) = 4 
```

となり、初項sがどんな値であれ4→2→1が繰り返される。

mは項数であり、

nよりも大きいmかつ、最小の項数を求める。

am = an （ m > n ）、つまり最初に要素の重複が起こる項数を答えとすればよい。

要素の重複が起こる項数を求めるという発想に辿り着けなかった。

答え
```python
s = int(input())

a = []
i = 1

while True:
    if s not in a: ##初稿が配列aにない間.sは8,4,2,1,4と繰り返し、4が出たので1に4をたした５が出力される。
        a.append(s)
        i += 1
        if s % 2 == 0:
            s //= 2
        else:
            s = 3 * s + 1
    else:
        print(i)
        break

```

## 参考
https://onecheese.com/2021/12/06/atcoder-abc-116-b/
バージョン指定してRails6環境を構築する方法

バージョン指定してRails6環境を構築する方法

Gemfile
```Gemfile
source "https://rubygems.org"
gem 'rails', '~> 6.0'
```

ターミナルから下記コマンドを実行
```
$ bundle install
$ gem install -v 6.0.4.7 rails
$ rails new . 
```
ssh-copy-idがデフォルトで選択する鍵ファイル

久しぶりに`ssh-copy-id`で鍵を配置しようとしたら、うまくいかなかったので調べてみました。

## 何が起きたか

`ssh-copy-id my-server`を実行したら、
`id_rsa.pub`ではなく、全然違う鍵ファイル`id_boot2docker.pub`をコピーしようとした。

## 原因と`ssh-copy-id`の仕組み

`ssh-copy-id`で`-i <鍵ファイル>`オプションを指定しない場合、デフォルトでどの鍵ファイルが選択されるかというと、次のような実装によって決定されます（`ssh-copy-id`ってシェルスクリプトなんですね）。

```bash
most_recent_id="$(cd "$HOME" ; ls -t .ssh/id*.pub 2>/dev/null | grep -v -- '-cert.pub$' | head -n 1)"
DEFAULT_PUB_ID_FILE="${most_recent_id:+$HOME/}$most_recent_id"
```

つまり、`id*.pub`（`id*-cert.pub`を除く）にマッチするファイルのうち、タイムスタンプが最新のものが使われるわけですね。

自分の環境では、Docker Machineを入れたときに生成された`id_boot2docker.pub`が`id_rsa.pub`よりも新しかったため、そちらが選択されたということだったようです。

## 明示的に鍵を指定しよう

`ssh-copy-id`するときは`-i`で明示的に鍵を指定したほうがよいでしょう。

## （おまけ）秘密鍵しかない場合

ちなみに秘密鍵しかない場合は、自動的に公開鍵を生成してくれるなどという気の利いたことはしてくれず、エラーになります。

```console
$ ssh-copy-id -i ~/.ssh/test_rsa my-server

/usr/bin/ssh-copy-id: ERROR: failed to open ID file '/Users/username/.ssh/test_rsa.pub': No such file or directory
```
Zabbix6.0にアップグレードしたらDatabase errorに遭遇した

# 環境
・Ubuntu 20.04
・MariaDB 10.3
Zabbix 4.2 -> 6.0 にアップグレード

# Zabbix6.0にアップグレード
公式手順も用意されてるのでその通りにアップグレードしていきます。

https://www.zabbix.com/documentation/6.0/jp/manual/installation/upgrade/packages/debian_ubuntu

# トラブル

zabbixのアップグレードは問題なく完了したが、フロントエンドでDatabase errorが表示

```
The Zabbix database version does not match current requirements. 
Your database version: 4020000. Required version: 6000000. Please contact your system administrator.
```

`/var/log/zabbix/zabbix_server.log` にログが何も出力されず原因不明。

そもそもデータベースの[サポートバージョン](https://www.zabbix.com/documentation/current/en/manual/installation/requirements#database-management-system)はMariaDBの場合10.5以上なので、
MariaDBも10.3->10.5にアップグレードを実施。

```
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 53948
Server version: 10.5.15-MariaDB-1:10.5.15+maria~focal mariadb.org binary distribution
```

MariaDBのアップグレード後も、フロントエンドでは上記のDatabase errorが表示されたが
`/var/log/zabbix/zabbix_server.log`にはログが出力されるようになった。
```
  4859:20220329:010905.627 Starting Zabbix Server. Zabbix 6.0.1 (revision a80cb13868).
　・・・(略)
  4859:20220329:010905.628 using configuration file: /etc/zabbix/zabbix_server.conf
  4859:20220329:010905.664 Zabbix supports only "utf8,utf8mb3,utf8mb4" character set(s). Database "zabbix" has default character set "latin1"
  4859:20220329:010905.664 Zabbix supports only "utf8_bin,utf8mb3_bin,utf8mb4_bin" collation(s). Database "zabbix" has default collation "latin1_swedish_ci"
  4859:20220329:010905.690 character set name or collation name that is not supported by Zabbix found in 392 column(s) of database "zabbix"
  4859:20220329:010905.694 only character set(s) "utf8,utf8mb3,utf8mb4" and corresponding collation(s) "utf8_bin,utf8mb3_bin,utf8mb4_bin" should be used in database
  4859:20220329:010905.696 current database version (mandatory/optional): 04030004/04030004
  4859:20220329:010905.696 required mandatory version: 06000000
  4859:20220329:010905.696 starting automatic database upgrade
  4859:20220329:010906.335 [Z3005] query failed: [1366] Incorrect string value: '\xE3\x81\x9D\xE3\x81\xAE...' for column `zabbix`.`item_rtdata`.`error` at row 68 [insert into item_rtdata (itemid,lastlogsize,state,mtime,error) select i.itemid,i.lastlogsize,i.state,i.mtime,i.error from items i join hosts h on i.hostid=h.hostid where h.status in (0,1) and i.flags<>2]
  4859:20220329:010906.378 database upgrade failed
```

# 解決
ログの通り`item_rtdata`カラムを確認するとCollationが`latin1_swedish_ci`になっていたので下記コマンドを実行した。
```
ALTER TABLE zabbix.item_rtdata CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;
```

これでzabbixが起動してフロントエンドのエラーも消えて無事にアップグレードが完了しました。
Excelで覚えておくといつか役に立つ関数


# TEXT関数

TEXT関数では、セルの表示形式を変更出来ます。
例えば、見積書などで年月日を表示したい場合や、時間を表示したい場合などに使用出来ます。

`
　=TEXT(値,"yyyy年mm月dd日")　
`
![年月日.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2102213/2b89080f-b24a-beea-017f-86b95bba3820.png)
`
　=TEXT(値,"h時mm分ss秒")
`
![時間.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2102213/0bc40944-c724-c34c-47d6-7782d4999419.png)


# SUBSTITUTE関数

SUBSTITUTE関数では、指定の文字の置換が行えます。
いつも置換している文字があれば、この関数がおすすめです。

`
=SUBSTITUTE(値,置換前の文字,置換後の文字,置換対象)
`
![置換.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2102213/7fd7e788-ecc9-f45f-a61b-465484dc3312.png)


# XLOOKUP関数
VLOOKUP関数を使う際に検索値より前にある情報を取ってきたいみたいな場面に遭遇した場合はこの関数がおすすめです。

`
=XLOOKUP(検索値,検索範囲,戻り範囲,見つからない場合,一致モード)
`
![Xlookup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2102213/f3af6430-6d77-df94-c5dd-19f1d82f1906.png)
commitせずにブランチを移動する方法。

作業中に別ブランチに移動してやりたいことがあるという時に作業をスムーズにする方法です。
commitしていない変更がある状態でブランチを移動しようとすると以下のようなエラーが出ます。
```
error: Your local changes to the following files would be overwritten by checkout:
        src/app/Http/Controllers/BicycleController.php
Please commit your changes or stash them before you switch branches.
Aborting
```
ブランチを切り替える前にcommitかstashをしてくださいと言われるのですが(Google翻訳)、まだ作業途中なのでcommitしたくないという時があると思います。
その場合、$ git stachで修正を一旦退避させることができます。

変更をstashした後、$ git stash list で退避した作業を確認します。
```
$ git stash list
stash@{0}: WIP on issue-6: 1a3ae7f bicyclesページの作成
```

別ブランチでの作業が終わった後、元いたブランチに戻り作業を$ git stash applyで復元させます。
```
$ git stash apply stash@{0}
```
stash@{0}の作業を戻したい場合はこのように指定すると、退避させた修正が元通りになります。

作業時に参考にさせていただいた記事:
[【git stash】コミットはせずに変更を退避したいとき](https://qiita.com/chihiro/items/f373873d5c2dfbd03250)
[コミットせずに他のブランチで作業したい](https://qiita.com/maru53/items/316ed237a48e02c4711a)

# ちなみに
PowerShellで$ git stash apply stash@を実行しようとした時にエラーになってしまったのですが、
以下のようにシングルクォートで囲むと実行できました。

```
git stash apply 'stash@{0}'
```
PowerShellの場合中括弧内の文字列がコマンドとして実行されるらしいです。

こちらの記事より:
https://crieit.net/posts/PowerShell-Git-reset-stash
【要件定義編】開発未経験がクラウドを企業に導入するプロジェクトごっこをしてみた~その2~【明日から社会人】

# はじめに
２２年度文系学部卒のたいきです。この記事では、システムの開発経験もないのに、見よう見まねで「プロジェクトごっこ」をしていきます。
・保有資格 : 応用情報技術者・AWS-SAP
・プログラミング言語:軽くPython
# 本記事について
　前回記事で定めた前提をもとにして、今回は本プロジェクトごっこの要件を定めていきたいと思います。下記が前回記事です、よかったら読んでみてください。
[【前回記事】開発未経験がクラウドを企業に導入するプロジェクトごっこをしてみた~その１~](https://qiita.com/Ishii_Taiki/items/e3035c12b31385f8156b)
本記事は、下記のサイトを参考にして要件定義を行わせていただきました。
> 要件定義における成果物一覧と書き方（要件定義書サンプルあり）
>> https://pm-rasinban.com/rd-write
何か修正したほうがいい箇所、アドバイスを頂けると嬉しいです！
# 前提からの要件の抽出
　<a href=”https://qiita.com/Ishii_Taiki/items/e3035c12b31385f8156b” target=”_blank”>前回記事</a>で定めた前提となるストーリーから本プロジェクトの要件を抽出していきます。
以下に大まかな顧客の要望を抽出してみました。
・きのこの山とたけのこの里を判別、カウントする機能を有するアプリを開発すること
・クラウド環境を用いること
・中断が許されないこと
・必要キャパシティが予測不能なこと
・顧客はこれを機に完全にクラウドへ移行すること
・オンプレミスADを利用すること
# 要件定義書
こちらでは、システムの要件とクラウド環境の構築の要件の二つを定義していきます。
# システム要件
システムの要件に対して定義していきます。
## システム概要
アップロードした画像を基に、「きのこの山とたけのこの里」のどちらかを判別。また、その個数をカウントするシステム
## 当システムの目的・背景・狙い
### 当プロジェクトの目的
・画像をアップロードし、きのこの山とたけのこの里のそれぞれの個数をカウントするアプリケーションの開発
・最低限のコスト及び労力による開発・保守運用
### 当プロジェクトの背景
・きのこの山とたけのこの里の数をカウントしなければいけない法律の施行
・上記に伴うアプリケーション需要の急激な増大が予測されていること
### 当プロジェクトの狙い
・低コストで、高セキュリティ・高可用性・運用上の優秀性を確保する。
・膨大で不規則なアクセス数への対応。
## 機能要件
![機能一覧表.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2608302/eb929138-21bc-d706-9f96-6cdafa29bde9.png)
## 非機能要件
### インフラ構成
　　　・AWS
　　　　　　・Webサーバー
　　　　　　　　　サーバレス設計
　　　　　　・DB
　　　　　　　　　２つの地域(東京・バージニア北部)に冗長化された構造化DB
　　　　　　・Storage
　　　　　　　　　２つの地域に冗長化された非構造化DB
### 主要５非機能要件
![機能要件1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2608302/d701a6eb-116a-2103-99b9-4970a3c0ebcf.png)
![機能要件2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2608302/27d473a6-c4ff-3e97-6298-3475608fbc76.png)

# クラウド環境の構築に関する要件定義
## 当クラウド環境の目的・背景・狙い
### 目的
・今後、顧客がクラウドを利用する土台として拡張性にすぐれベストプラクティスに沿った将来性のあるクラウド環境の実装
・必要最低限のコスト及び労力によるAWSでの内部組織の管理及び統制
### 背景
・将来的なコスト削減のため
・クラウド技術の発展
・顧客企業のAWS技術者不足

### 狙い
・企業の要望に沿ったクラウド環境の構築
・AWSのベストプラクティスにそった組織の管理及び監視

## クラウド環境要件
・クラウド環境内の脆弱性の自動検知
・検知後の自動復旧
・自動復旧できない脆弱性の場合、人的介入を促す通知の仕組み
・企業内のクラウド内での作業者の統制および監視
・アクセスログ・操作ログ・イベントログの一元管理
・既存のアクティブディレクトリを利用した認証システムの構築

# おわりに
今回は、文系未経験クラウドエンジニア志望がみようみまねで要件定義をやってみました。見るに堪えないような要件定義書だとは思いますが、温かい目で見ていただけると嬉しいです。何かアドバイスなどをいただけますと嬉しいです。引き続き精進していきます。次は、「基本設計編」になりそうです。楽しみにしていただければなと思います。
ちなみに、明日から僕の社会人としての生活が始まります。一流に一刻も早くなれるよう頑張ります。
続編はこちらです！[【基本設計編part1】開発未経験がクラウドを企業に導入するプロジェクトごっこをしてみた~その3~](https://qiita.com/Ishii_Taiki/items/244308ef3bd925f4f253)
ConsoleアプリケーションでSystem.Windows.Formsを使う

# 移転します

https://ymd65536.hatenablog.com/entry/2023/10/30/001656

## はじめに

Visual Studio Code で コンソールプログラムを作成するときですが
フォームアプリケーションを操作したいなと思ったときに`using`が足りなくて困ったのでそのTipsです。

## 動作環境

- Windows10 Pro 21H2
- Visual Studio Code
- dotNET Core 6.0.101

## 結論

`.csproj` ファイルに追記するだけでOKです。

## 方法

これがデフォルトの`.csproj` ファイルの中身です。

```xml
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>
```

上記の記載を以下のように変更します。

```xml
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0-windows</TargetFramework>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>
```

これで`Consoleアプリケーション` から `Sysmtem.Windows.Forms` を利用できます。

## おわり