OmniAICreator/Qiita-1.07M huggingface dataset:
チャットルームとユーザーのモデル化【O'Reilley/Golang/Webアプリケーション】

# 概要
[Go言語によるWebアプリケーション開発(O'Reilley)](https://www.oreilly.co.jp/books/9784873117522/)のChapter1.2.4までの内容をモデル図を書いて要約する
設計を書いてからコードを書くor 読むと納得しやすいので参考までに

# モデル化
## ユーザー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694714/1398c57b-ff08-8ddf-1c40-41761f4e19ae.png)

```go:client.go
type client struct {
	socket *websocket.Conn
	send chan []byte
	room *room
}
```

## チャットルーム
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694714/834a6123-29ae-e2b8-42b4-09189ea9defa.png)

### ソースコード
```go:room.go
type room struct {
	forward chan []byte
	join chan *client
	leave chan *client
	clients map[*client]bool
}
```

## メッセージの送受信

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694714/85befc45-6117-93a4-3996-1d4fa643f1e9.png)

当初client.read()およびclient.write()がサーバーサイドから見た読み書きであることがわからず困惑した。

### ソースコード

```go:client.go
func (c *client) read() {
	for {
		if _, msg, err := c.socket.ReadMessage(); err == nil {
			c.room.forward <- msg
		} else {
			break
		}
	}
	c.socket.Close()
}

func (c *client) write() {
	for msg := range c.send {
		if err := c.socket.WriteMessage(websocket.TextMessage, msg); err != nil {
			break
		}
	}
	c.socket.Close()
}
```

```go:room.go
func (r *room) run() {
	for {
		select {
		// caseが同時に実行されることはない
		case client := <-r.join:
			// 参加
			r.clients[client] = true
		case client := <-r.leave:
			// 退室
			delete(r.clients, client)
			close(client.send)
		case msg := <-r.forward:
			// すべてのクライアントにメッセージを転送
			for client := range r.clients {
				select {
				// メッセージを送信
				case client.send <- msg:
				default:
					// 送信に失敗
					delete(r.clients, client)
					close(client.send)
				}
			}
		}
	}
}
```

## ユーザーとの接続の確立
ついでに、送受信のモデルで説明しなかった最初にユーザーがチャットルームに入るときのフローをまとめておく

1. Websocketを使えるようにHTTP接続をアップグレードする
1. ユーザーがチャットルームに入室するHTTPリクエストを飛ばす
1. room.ServeHTTPメソッドが呼び出される
1. upgrader.UpgradeメソッドがWebSocketコネクションを取得
1. コネクション取得に成功したならば、clientを生成し、room.joinチャネルに渡す
1. クライアント終了時にルームから退出するように遅延処理
1. 並行処理でメッセージ受信を待機
1. メインスレッドでメッセージ送信を待機

### ソースコード

```room.go
const (
	socketBufferSize = 1024
	messageBuffuerSize = 256
)

// HTTP接続をアップグレードしてWebSocketを使えるようにする
var upgrader = &websocket.Upgrader{ReadBufferSize: socketBufferSize,WriteBufferSize: socketBufferSize}

func (r *room) ServeHTTP(w http.ResponseWriter, req *http.Request)  {
	// WebSocketコネクションを取得
	socket, err := upgrader.Upgrade(w,req,nil)
	if err != nil {
		log.Fatal("ServeHTTP:", err)
		return
	}
	client := &client{
		socket: socket,
		send: make(chan []byte,messageBuffuerSize),
		room: r,
	}
	r.join <- client
	defer func() {r.leave <- client}()
	go client.write()
	client.read()
}
```

# 参考
[Go言語によるWebアプリケーション開発(O'Reilley)](https://www.oreilly.co.jp/books/9784873117522/)
VSCode insiders venv activate時の「このシステムではスクリプトの実行が無効になっているため～」 エラーの解決

## 事象
PCを新調したのでPython開発環境を構築しようとvenv activate を実行しようとしたところ、
「このシステムではスクリプトの実行が無効になっているため、ファイル xxx .venv\Scripts\Activate.ps1 を読み込むことができません。」という
エラーになったので対処法を記載
別のPCではならなかったので調べるに至った

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515586/dfb9afee-c6df-612c-97a7-fdc93df7723b.png)

## 環境
Windows 10
Visual Studio Code insiders 1.64.0
(Visual Studio Codeでも同じだと思う)
Python 3.10.2

## 対処
Visual Studio Code insiders（以降、VSCode）の表示→コマンドパレットを押下し出てきた入力欄に「settings」と入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515586/9267d39e-35fc-a037-af1a-b0bca6a68def.png)
`Open Settings(JSON)`を選択。
この際、`Open xxx Settings(JSON)`がいくつかあるが、`Open Settings(JSON)`を選択する。

以下を追記する。

```python
    "terminal.integrated.env.windows": {
    "PSExecutionPolicyPreference": "RemoteSigned"
}
```

私の場合は以下の通り。
before

```python
{
    "workbench.colorTheme": "Default Dark+",
}
```

after

```python
{
    "workbench.colorTheme": "Default Dark+",
    "terminal.integrated.env.windows": {
        "PSExecutionPolicyPreference": "RemoteSigned"
    }
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515586/5c741d84-6229-925e-c938-91a02599f14b.png)

すでに何か記載がある場合は、最後に
`,`
を入力することを忘れないように。

JSONファイルを更新し保存をしたらVSCodeを再起動する。
再起動後、venv activate を実行し、activate されることを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515586/b9f547e7-8933-1338-bb01-b752a40c5daf.png)


## 参考
ほぼ参考どおりですがsetting.jsonなど場所がわからなかったのでより初心者向けに記載させていただきました
[VSCodeでActivate時に「このシステムではスクリプトの実行が無効になっているため、ファイルｘｘを読み込むことができません」とエラーが表示される時の対処法](https://manumaruscript.com/vscode-activate-error/)
Unity(Mac版)のファイル名に日本語入力ができないときの暫定対処方法


Mac版のUnityで日本語を入力をした際に、入力した文字が消えることがあります。
根本的な解決策が見つからなかったので、力技で解決する方法を紹介します。


## 暫定対処方法
#### 1. Unityのエディタ上で日本語を入力する(このときEnterを押してはいけない)
Spaceや↓↑キーで変換候補を選びます。Enterを押すと文字が消滅するので押さないように気をつけましょう。
![スクリーンショット 2022-01-23 18.13.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126388/96793f52-762d-6c9c-69d7-fe299bf22e8f.png)

#### 2. 入力中の文字欄をクリックして変換候補のウィンドウを閉じる
Enterを押さずに、マウスのクリックを使用して変換候補のウィンドウを閉じます。Enterを押していないので文字列を入力することができます。
![スクリーンショット 2022-01-23 18.13.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126388/7271e10e-08f0-cf33-a212-6814a42f4eb5.png)


## 環境
- macOS Mojave 10.14.6
- Unity 2021.1.3f1
【python selenium】find_elementsで取得した要素に対してfind_elementsを実行

find_elements_by_xpathで複数の要素が該当する場合、List型で変数を取得すると思います。
各要素に対して処理を行う場合、for文を活用するとき、実はfor文内でさらにfind_elements_by_xpathを使用することができました。
例えば、Amazonの商品リストごとに処理を行いたいといった場合に便利ですね。

下記のプログラムでは「class='list_5」で指定された「ulタグ」直下の「liタグ」をすべて取得し、
for文を回す中でさらに各「liタグ」に対して「find_elements_by_xpath」を実行し、画像を取得します。

サイトは 'https://www.min-inuzukan.com/' を参考にしました。

```py:getimg.py
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
import io
from urllib import request
from PIL import Image
from time import sleep

# driverを取得
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get("URLname")
print("サイトにアクセスしました")
sleep(5)

contents = driver.find_elements_by_xpath("//ul[@class='list_5']/li")
print("xpathにて要素を探しました")

n = 1
try:
    for content in contents:
        img = content.find_elements_by_xpath("a/img")
        imgurl = img[0].get_attribute('src')
        f = io.BytesIO(request.urlopen(imgurl).read())
        img = Image.open(f)
        img.save('img{}.jpg'.format(n))
        n += 1
        print("画像が保存されました")
        sleep(3)
except:
    print("エラー発生")
    
driver.close()
```

#注意
本プログラムを実行する場合は、自己責任にてお願いいたします。
また、サイト運営者への配慮をお願いいたします。
PowerAutomateDesktopを使って少しでも楽したい！PC立上げ後に使用するアプリを自動で開く。

私は小売業の本社スタッフとしてシステム関連の部署に所属しています。
と言っても自分でプログラムを書けるわけではないので、色々なツールを勉強中です。
Power Automate Desktopを初めて使い、これは便利と思い作成してみました。

#PCを起動した後に必要なアプリやWEBを自動で開きたい
PCを起動した後に必ず使用する「Outlook」「Teams」「社内イントラ」。
その他、私の会社では在宅勤務用の打刻、体調管理用のWEBページなど、
開く画面が多く面倒だと思っていました。
これをPowerAutomateDesktopを使って自動化したいと考えました。

#使用したツール
Power Automate Desktop

#作成の流れ
###・Power Automate Desktopのレコーダー機能を利用
「社内イントラ」→「打刻ページ」→「体調管理ページ」→「Outlook」→「Teams」
の順にレコードを進めました。
###・レコード失敗
最初の社内イントラへのアクセスでエラーになりました。
ユーザーIDとPWを入力するページで、「UI要素を取得出来ません」とエラーが表示され、
文字入力が反映しませんでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2476728/2078966f-57c7-3db3-f85b-7d4ba77b8842.png)


Edgeで開いたのが原因かと思い、Google Chromeで同じ様に進めたところ、
「Chromeを制御することが出来ませんでした」というエラーコメントが表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2476728/273f3aa5-d9b9-892a-9b8e-35574770e3e6.png)

###UI要素を取得する方法を色々調べましたが答えが見つからず・・
今回は社内イントラとSingle Sign Onで開く打刻ページは諦めその他を自動化しました。

#Power Automate Desktopのフロー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2476728/9565549d-67a6-3884-cdcc-8c7655d2b0c2.png)

「体調管理ページ」→「Outlook」→「Teams」は自動で開ける事が出来ました！

#感想
Power Automate Desktopを利用する事で日常行っている操作を自動化出来るので、
便利と感じました。3つ自動化出来たので少し楽になった。
身近な事を少しずつ自動化する事で効率改善出来ればと思います。
レコード機能を利用したUI要素を取得する方法を見つけ出す事が出来ず、
社内イントラを開く事が出来なかったので、更に挑戦したいと思いました。
【Project Euler】Problem 50: 連続した素数の和で表される素数

* 本記事は[ProjectEuler](https://projecteuler.net/about)の「100番以下の問題の説明は記載可能」という規定に基づいて回答のヒントが書かれていますので、自分である程度考えてみてから読まれることをお勧めします。

### 問題 50. 連続した素数の和

原文 [Problem 50: Consecutive prime sum](https://projecteuler.net/problem=50)

**問題の要約：連続した素数の和で表される$10^6$以下の素数の中で、連続した素数が最も長いものを求めよ**

連続した素数の和を求めるのにちょうど良い**numpy**の**cumsum**という関数があったので使って見ました。

まずどんな関数か試してみます。20以下の素数のリストで見てみると**cumsum**の結果の大きい方から素数を探せば2から始まる一番長い連続した素数の和が見つかります（この場合は41）。

```python
import numpy as np
l = [2,3,5,7,11,13,17,19]
print(np.cumsum(l))
#[ 2  5 10 17 28 41 58 77]
```

これをもとにしたプログラムです。

```python
import numpy as np
from sympy import primerange, isprime
plist = [p for p in primerange(1,10000)]
maxCon = 0
for st in range(0,100):                # Shifting the starting position
  priSum = np.cumsum(plist[st:])       # cumulative sum of the primes
  for n in range(len(priSum)-1, maxCon,-1): # Seach max prime in priSum
    if priSum[n] < 10**6 and isprime(priSum[n]): 
      maxCon, startP, lastP, maxConPrime = n, plist[st], plist[st+n], priSum[n]
      break

print(f"Answer : {maxConPrime}, {maxCon+1} consecutive primes ({startP}-{lastP})")
```

（開発環境：Google Colab）
【Project Euler】Problem 49: 並び替え素数

* 本記事は[ProjectEuler](https://projecteuler.net/about)の「100番以下の問題の説明は記載可能」という規定に基づいて回答のヒントが書かれていますので、自分である程度考えてみてから読まれることをお勧めします。

### 問題 49. 並び替え素数

原文 [Problem 49: Prime permutations](https://projecteuler.net/problem=49)

**問題の要約：4桁の素数を並べ替えた2つの数も素数で、かつ3つの数が等差数列になっているとき、その順番に連結した12桁の数を求めよ**

関数**isPermSame**で2つの数が並び替えで同じになるかチェックしています。

```python
from sympy import nextprime, isprime
def isPermSame(n1, n2):
  return ("".join(sorted(str(n1)))) == ("".join(sorted(str(n2))))

p, ans = nextprime(1000), 0
while p < 10000:
  for inc in range(2,5000):
    p1, p2 = p+inc, p+inc+inc
    if p2 < 10000 and p != 1487 and \
       isprime(p1) and isprime(p2) and \
       isPermSame(p, p1) and isPermSame(p, p2):
      ans = "".join([str(p),str(p+inc), str(p+inc+inc)])
  p = nextprime(p)

print(f"Answer: {ans}")
```

（開発環境：Google Colab）
【Project Euler】Problem 48: NのN乗の和

* 本記事は[ProjectEuler](https://projecteuler.net/about)の「100番以下の問題の説明は記載可能」という規定に基づいて回答のヒントが書かれていますので、自分である程度考えてみてから読まれることをお勧めします。

### 問題 48. NのN乗の和

原文 [Problem 48: Self powers](https://projecteuler.net/problem=48)

**問題の要約：$n=1000$の時$1^1+2^2+3^3 \dots n^n$の値の下10桁を答えよ**

下10桁ということなので$pow$関数のmodを指定して数が大きくならないようにします。

```python
m = 10**10
print(f"Amswer: {sum([pow(n, n, m) for n in range(1,1001)]) % m}")
```

（開発環境：Google Colab）
-bash: php: command not found 解決方法

##初めに
作成中のポートフォリオでPHPのバージョンを確認したいと思い、`php -v`をターミナルで叩いたところ、`-bash: php: command not found`と表示されてバージョン確認できなかったので、その解決方法についてご紹介していきます。

##エラー原因
```
アプリディレクトリ $ php -v
-bash: php: command not found
```
`-bash: php: command not found`で「そんなコマンド無いよ！」と指摘された時は、パスが通ってないことが原因です。
なので、`.bash_profile`ファイルにパスを通す設定をしてあげることで解決できます！


##1.パスを通す

###`.bash_profile`の確認
先ずそもそも自身のホームディレクトリに`.bash_profile`が存在しているのか確認してみます。

```
アプリディレクトリ $ cd #ホームディレクトリに戻る

ホームディレクトリ　$ ls #ホームディレクトリ下に配置されているファイルを確認
Applications		OneDrive		getting-started
Creative Cloud Files	Pictures		index.html
Desktop			Public			mysite
```

上記コマンドで確認してみると、`Applications`等はありますが、`.bash_profile`は存在していないことがわかります。

###`.bash_profile`作成
`.bash_profile`がないので新規で作成します。
ついでに、`~/.bashrc`も作成しておきす。

```
$ touch ~/.bash_profile
$ touch ~/.bashrc
```

###編集
.bash_profileにパスを通す設定を書き込みます。

```
$ vi ~/.bash_profile
```

```
# User specific environment and startup programs

PATH=$PATH:$HOME/bin:/usr/local/php5/bin

export PATH
```

###反映
sourceコマンドで変更を即時反映させます。

```
$ source ~/.bash_profile
```

###確認
では、もう一度phpのバージョン確認をしてみます。

```
アプリディレクトリ $ php -v
-bash: php: command not found
```

？？？　何故かまだパスが通ってないようです。

##2.Homebrewをアップデート
いくつか参考記事を見て、HomebrewでPHPをインストールしてみることに。
その前に一様Homebrewをアップデートしておきます。

```
ホームディレクトリ　$ brew upgrade
```

これで再度バージョン確認をしてみます。
おっと、アップデートのみでバージョン確認できるようになりました！

```
$ php -v
PHP 8.1.2 (cli) (built: Jan 21 2022 04:47:46) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
    with Zend OPcache v8.1.2, Copyright (c), by Zend Technologies
```

他の参考記事ではアップデートのみで解決した事象はなかったので、今回の記事が少しでも参考になればと思います!

##参考記事
https://qiita.com/takutoki/items/021b804b9957fe65e093

https://neos21.net/blog/2017/02/12-02.html

https://web-guided.com/1874/

https://qiita.com/5ryo_ryo5/items/f38edd2b5ed3e30e7760

https://mifooooo.hatenablog.com/entry/2014/03/31/143131
リーダブルコードのまとめ。　1/2

リーダブルコードを読み終わったので、内容をまとめます。

## 【第一部-表面上の改善】
### 2章-名前に情報を詰め込む

- 変数名には、その目的が分かるような明確な単語を選ぶ。例えば、get~という変数をもっと具体的に、fetch~やdownload~とする。
- tmpやnumなどの汎用的な名前はできるだけ避ける。
- メソッド名やクラス名は短いコメントのようなものである。このクラスやメソッドは何をするクラスなのか、一目でわかるような名前にする。
- 変数名に大切な情報を追加する。例えば、ミリ秒を表す変数名には _msをつける。
- 変数名のスコープが大きい場合、長い名前を付ける。1単語や2単語だと、その変数が何を表しているのかとても分かりづらくなってしまう。
- ローカル変数とグローバル変数を区別できるよう、変数に印をつける。例えば、グローバル変数には一番最初に_(アンダーバー)をつけるなど。


### 3章-誤解されない名前

- 意図が伝わるような名前を選ぶ。例えば、filterという名前は「選択する」という意味にも解釈できるし、「除外する」という意味にもとれる。「選択する」であればselectを、「除外する」であればexcludeにするのがよい。
- 上下の限界値を決めるときはmax_やmin_を前につけるとよい。ブール値ならisやhasを前につけ、包含的範囲であればfirstやlastを使うとよい。
- get()やsize()は軽量メソッドの時に使うことが期待されている。


### 4章-美しさ

- 複数のコードブロックで同じような処理があったなら、その処理のコードのシルエット(見た目)は同じようにする。
- インデントを使い、縦の列をそろえる。
- 処理の順番がある場所でA,B,Cの順番で並んでいたならば、他の場所でB,C,Aのように並べるのは良くない。最初にどのような順番にするかを決め、一貫してその順番を守る。
- コードの中で、処理や似ている考えごとに空行を使って段落に分ける。


### 5章-コメントすべきことを知る

- コメントすべきでは「ない」こと・・・コードを見ればすぐに分かってしまうようなことはコメントすべきでない。また、汚いコードがどのような処理をしているかを補助的にコメントするのも良くない。補助的なコメントを書くのではなく、コードそのものを修正する。
- 自分の考えを記録する・・・定数がなぜその値を持っているのか、何を行うのかという「背景」を記録する。なぜほかの方法ではなくそのような処理の書き方にしたのかという「背景」を記録する。
- コードの欠陥をTodoやXXXなどをつけて示す。
TODO⇒あとで手を付ける
FIXME⇒既知の不具合があるコード
HACK⇒あまり綺麗じゃない解決策
XXX⇒大きな問題がある

- コードやクラスの全体像を書く。クラスはどのように連携しているのか、データはどのように流れるのか、等を記録する。
- 平均的な読み手が迷うような処理は予想して文書化しておく。
- 読み手が細部にとらわれないように、コードブロックにコメントをつけて概要をまとめる。


### 6章-コメントは正確で簡潔に

- コメントは簡潔に！長々と書かないようにする。
- 入出力の処理のコメントには実例をつける。例えば、入力[5,4] 出力[9,2]など。
- よくわからない引数にはインラインコメントを使う。
インラインコメントは、関数の呼び出し時、引数の横にコメントをつける手法である。例えば、
Connect(/*timeout_ms=*/ 10, /*use_encription=*/ false); など。
- 低レベルの詳細ではなく、高レベルの処理内容を書く。
関数の中の「計算の内容」の説明をするのではなく、その関数は「何を行うのか」を説明する。


## 【ループとロジックの単純化】

### 7章-制御フローを読みやすくする

- 比較 if(a < b)等を書くときは、変化する値を左に、より安定した値を右に配置する。
- if/else文のブロックは適切に並び替える。肯定系、目立つもの、単純なものを先に処理する。
- 三項演算子(? :)やdo-whileループを単純な処理以外に使用する場合、コードが読みにくくなる場合が多いので使わない方がよい。
- 深いネストを避ける。分離できそうな処理は先にreturnして処理を終わらせておく。直線的なコードを書く。


今回は以上です。後半は次回で書きます。
Vim基本操作入門

# はじめに
サービスを運用していく中で障害が発生した時は
ログを確認することで原因調査に役立てることができるのですが
自分の場合、Vimの使い方がままならずログを追うのに苦戦していたので
今回改めて、ログを追うのに必要となる基本操作をピックアップして整理してみました。

他にもVimを覚えたらファイルの編集だったり、OSに依存せずコードを書けたりと
覚えておくと便利らしいです。


# 「Vi」と「Vim」の違い
「Vi」＝「Vim」で問題ないそうです。
Vimは2000年以降で普及し始めたviの進化版だそうです。
（vimは「Visual editor IMproved」の略で、viの改良版という意味）

# Vimコマンド
## vimの起動

|コマンド名|説明|
----+-----
|vim filename|ファイルを開くまたは新規作成する|
|view filename|読み取り専用でファイルを開く|

## カーソル移動

|コマンド名|説明|
----+-----
|h|左に移動|
|j|下の行の先頭文字 (空白ではない) に移動 |
|k|上の行の先頭文字 (空白ではない) に移動 |
|l|右に移動|
|Returnキー|下の行の先頭文字 (空白ではない) に移動 |
|Sfift + g|ファイル内の最終行に移動する|
|Ctrl-F|1 画面先のページを表示 |
|Ctrl-D|半画面先にスクロール  |
|Ctrl-B|1 画面前のページを表示 |
|Ctrl-U|半画面前にスクロール |


## 検索

|コマンド名|説明|
----+-----
|/string|文字列を検索|
|?string|文字列を逆方向に検索|
|n|検索方向の前方にある文字列を検索|
|N|検索方向の後方にある文字列を検索|

## 挿入

|コマンド名|説明|
----+-----
|i|インサートモードになる。次から打つ文字が挿入されていく。終えるときはESCキー|

## 削除
|コマンド名|説明|
----+-----
|x|カーソルのある場所の文字を削除する|
|dd|カーソルのある行を削除する|

## コピーペースト
|コマンド名|説明|
----+-----
|yy|行をバッファにコピーする|
|p|バッファの内容を貼り付ける|

## 変更を戻す
|コマンド名|説明|
----+-----
|u|変更を元に戻す|


## 保存と終了

|コマンド名|説明|
----+-----
|:w Returnキー|変更を保存|
|:q Returnキー|vimの終了(変更していた場合、:wなどで保存しないと終了できない)|
|:wq Returnキー|変更を保存してvimを終了|
|:q! Returnキー|変更を保存しないでvimを終了|

## その他
|コマンド名|説明|
----+-----
|esc|（様々なモードを）キャンセルする。|

## タブ移動
|コマンド名|説明|
----+-----
|gt|1つ次のタブへ|
|gT|1つ前のタブへ|
|ctrl + w|スプリットされたタブ間の移動|


# 最後に
Vimのことを少しだけ知れました。
実際にコマンドを動かしながら学習すると楽しいです。
トランザクションと実行制御



## トランザクション分離レベル
- RR(Repeatable Read)
    - 複数回のクエリの間に他トランザクションがコミットしていてもその内容を反映されない
    - ファントムリードが起きる。ただしInnoDBではMVCCのため発生しない。
    - MySQLのデフォルトのトランザクション分離レベル
- RC(Read Commited)
    - クエリ実行時点でCommitされたデータを読み込む。
    - ファントムリードと、ファジーリードが発生する
    - Oracle、PostgreSQL、SQL Serverのデフォルトのトランザクション分離レベル




## ロックタイムアウトとデッドロック

### ロックタイムアウト
- ロック状態：更新処理が同時に行われたときに、先に行われる更新を待っている状態のこと。
- ロックタイムアウト：ロック待ち状態で設定のロック待ち時間を超えること。システム変数 `innodb_rollback_onn_timeout` で待ち時間を設定できる。
- タイムアウトエラー時は、エラーが出たクエリのみロールバックされる。トランザクション全体をロールバックしたい場合は、明示的に `ROLLBACK` を発行する必要がある。

### デッドロック
- デッドロック：互いにテーブルのロックを保持したまま、もう一方のテーブルに対してロックが必要な処理が行われるとき、ロックが解除されない状態

#### デッドロックが起きたら
- 上限を決めたリトライ処理を行う。


#### デッドロックを起こさないために
- トランザクションを小さくコミットする。
- 処理を行うテーブルの順序を決める。
- 必要がない場合にロック読み取りの利用を避ける。
- トランザクションの分離レベルを `READ COMMITTED` にする
- テーブル単位のロックを取得して更新を直列化する。（並列に処理が行えなくなるデメリットあり）
- インデックスを利用する。（インデックスがないと、スキャンした行全体にロックが掛かる）



# 参考
- 『おうちで学べる　データベースんの基本』 ミックら著
- [MySQLのMVCC - Qiita](https://qiita.com/nkriskeeic/items/24b7714b749d38bba87b)
- [トランザクション分離レベルについてのまとめ - Qiita](https://qiita.com/song_ss/items/38e514b05e9dabae3bdb)
Railsで全てのレコードを検索する

##全てのテーブルの全てのレコードの中から特定の単語を検索する方法 

以下のコードをコピーして、検索したい文字列を入力して、コンソールで実行するだけで検索できます。

```search_word.rb
ActiveRecord::Base.connection.tables.each do |table|
  model_name = "#{table.camelize.chop}".constantize rescue next
  model_name.column_names.each do |column_name|
    if model_name.columns_hash["#{column_name}"].type.to_s == ("string" || "text")
      pp table_model.where("#{column_name} like ?", '%ここに検索したい文字を入力%') rescue next
    end
  end
end
```


##よくわかる解説

大まかな方針としては、``(モデル名).where("カラム名 like ?", "検索したい文字列") ``を全てのモデルに対して実行します。


そのためには、全てのモデル名と全てのカラム名を取得する必要があります。


1. ``ActiveRecord::Base.connection.tables``で全てのテーブルの名前を抽出できます。ただし、この時点だとテーブル名がtable_namesのように複数形のスネークケースになっているのでモデル名にはなりません。


2. そこで、``table.camelize.chop``で取得したテーブル名をキャメルケースに変換していきます。``(テーブル名).camelize``でテーブル名が複数形のキャメルケースになります(例：TableNames)。また、``chop``で単語の末尾の一字を削除できるので``TableNames``が``TableName``のように変換されます。

3. 取得したモデル名はただのStringで、クラスではありません。そこで、``constantize``メソッドで文字列をクラスにしていきます。 

4. モデル名は取得できました。次はモデルにある全てのカラムを抽出していきます。カラムは``(モデル名).column_names``で取得可能です。


5. テーブル名とカラム名は取得できたので、``(モデル名).where("カラム名 like ?", "検索したい文字列") ``を実行すれば検索したい文字列は取得できます。ただし、booleanやintegerなどは検索対象外です。データ型がstringとtextの場合のみ検索を行います。モデルからカラム名を取得する方法は``(モデル名).columns_hash["カラム名"].type``で取得できます。


6. 最後は定番のwhere~like?で検索すれば完了です！consoleで実行することが多いかと思います。ぜひご活用ください！

##参考文献一覧
- https://qiita.com/jkr_2255/items/7e6b98b95976d76ad435
- https://railsdoc.com/page/camelize
- https://qiita.com/kenzan100/items/299018704269951e5ca7
- https://qiita.com/yonsuke/items/da74c00d55e0bed43930
- https://reasonable-code.com/rails-column-type/
自動微分を自作したい

#背景
単なる学習の記録です。
自作モジュールを作っていて、init関数も分かるようになってきました。ただ、まだまだPythonのクラスの機能を引き出せている気がしません。現代の高度な技術（？）なように思える自動微分を実装出来たらある程度使いこなせてる感が出るような気がしています。
#目的
自動微分の実装を通して、深層学習の理解を深めます。
#方法
まずは簡単な実装から行いたいです。PyTorchのチュートリアルにそれっぽい動画がありましたので、これを基に理解を深めます。

https://youtu.be/E-I2DNVzQLg
#結果
自動微分を自作してみる.ipynb(単に動画からGitHubに飛んだ先のコードをコピペしただけです。動画の概要欄にあるリンクの方が参考になると思います。)

https://colab.research.google.com/drive/19yvx5nZck5Q_LbGm2_w_qJnjszeD9Hme?usp=sharing

#考察
微分を解析的な方法で実装出来ました。numpyを使って実装しています。複数の入力を一気に計算する為だと思いますが、表記してある記号とその意味を一致させるのに時間がかかりました。例えば、xと表記してある物にも一つのデータを表しているのか複数のデータを表しているのか考えることがあります。
#課題
正直、課題は書ききれない程あるのですが、次はこれを基に「[Colab：ニューラルネットワークでANDゲートを解く.ipynb](https://colab.research.google.com/drive/1HyYvulakETtZgVWiibYoAICY8A6V2epX?usp=sharing)」のTensorFlowの部分を普通のPythonで書き換えようと思います。
#関連
nginx公式イメージのポートとドキュメントルートを変更する

nginxを初めて触った時のメモです。
動作はlocalhostで「Hello, World!」するだけです。

初めにデフォルトの状態でコンテナを起動し、ポートとドキュメントルートの設定がどこで行われているか確認します。

その後設定を変更し、再起動後のコンテナで独自の設定が反映されていればOKです。

# nginxの公式イメージ

https://hub.docker.com/_/nginx

# デフォルトの状態でコンテナを起動する
## 構成
```bash
.
├── docker-compose.yaml
└── nginx
    └── html
        └── index.html
```

### docker-compose.yamlを作成
```docker-compose.yaml
version: '3'
services:
  web:
    image: nginx:1.20.2
    volumes:
      # コンテナはデフォルトのドキュメントルートを指定
      - ./nginx/html:/usr/share/nginx/html
    ports:
      # コンテナはデフォルトのポートを指定
      - "8080:80"
```
### index.htmlを作成
```index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>index</title>
</head>
<body>
<p>Hello, World!</p>
</body>
</html>
```

## コンテナを起動
```bash
$ docker compose up -d
```

``http://localhost:8080/``へアクセスすると、ブラウザに「Hello, World!」が表示されます。

## デフォルトの設定を確認
nginxの設定ファイルは``/etc/nginx/nginx.conf``です。
コンテナ内で確認します。

```bash
% docker compose exec web cat /etc/nginx/nginx.conf
```

nginx.confから``conf.d/``のconfファイルがincludeされていることが分かります。

```nginx.conf
# 一部抜粋
include /etc/nginx/conf.d/*.conf;
```

今回使用したイメージでは、conf.d/配下のconfファイルは``default.conf``のみです。
内容を確認します。

```
$ docker compose exec web cat /etc/nginx/conf.d/default.conf
```

やはりdefault.confの設定がデフォルトとして反映されているようです。
``listenディレクティブ``でポート、``locationディレクティブ``でドキュメントルートが指定されています。

```default.conf
# コメント部分は削除
server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
```

# 設定変更後にコンテナを起動する
ポートとドキュメントルートの設定を変更します。
ホスト側でdefault.confを作成し、コンテナ起動時にコンテナ側のdefault.confへ上書きして設定を反映させます。

## 構成

```bash
.
├── docker-compose.yaml
└── nginx
    ├── default.conf         # 追加 
    └── html
        ├── index.html
        └── test_index.html  # 追加
```

### default.confを作成
独自のポートとドキュメントルートを指定します。
動作検証が目的なので、設定は最低限の内容にとどめています。

```default.conf
server {
    # 10080番ポートを使用
    listen       10080;

    # パスに対応したドキュメントルートを設定
    location / {
        # ディレクトリ
        root   /usr/share/nginx/test_html;
        # トップページ
        index  test_index.html;
    }
}
```

### test_index.htmlを作成

```test_index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>test index</title>
</head>
<body>
<p>test Hello, World!</p>
</body>
</html>
```

### docker-compose.yamlの設定を変更

```docker-compose.yaml
version: '3'
services:
  web:
    image: nginx:1.20.2
    volumes:
      # コンテナのdefault.confを上書き
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
      # コンテナのドキュメントルートを変更
      - ./nginx/html:/usr/share/nginx/test_html
    ports:
      # コンテナのポートを変更
      - "8080:10080"
```

## コンテナを再起動
```
$ docker compose down
$ docker compose up -d
```

``localhost:8080``へアクセスすると、ブラウザに「test Hello, World!」が表示されます。
コンテナのdefault.confもホストの設定で上書きされていることが確認できます。

```bash
$ docker compose exec web cat /etc/nginx/conf.d/default.conf
```

初歩的な部分ですが、設定を反映するまでの仕組みを知ることができました。
参考にしてください。

# 採用PR
弊社で一緒に働く仲間を募集しています。
全てのオタクを幸せにしたい方、是非ご覧ください！

https://hrmos.co/pages/vivion/jobs/0000191
Angular Update 10 → 12のあれこれ事件簿

とあるPRJにて、Angular 10 → 12のUpdateの際にいくつかハマったので備忘録として残しておきます。

# ざっくり環境
Angular 10 → 12
Node.js 12.10 → 12.22
TypeScript 3 → 4
<font color="red">webpack 4 → 5</font>
...その他もろもろ

# 前提
・Angularのビルダーを変更
```angular-devkit/build-angular → angular-builders/custom-webpack
```

# 地道なバージョンアップ対応
Angularのバージョンアップに伴いNode.jsのバージョンも最低限上げないといけないなどその辺りの依存関係の調整を地道に行い、TypeScriptのバージョンアップに伴う既存ソースの微修正など対応した。そこまではよかったのですが。。。

# webpack 5系の罠
今回のAngularプロジェクトでは直接的にwebpackは使用していませんでしたが、custom-webpackなどAngularで使うパッケージにwebpackへの依存があり、webpack 4系から5系にアップデートされていました。
結果、画面が真っ白！？！！？！！

# polyfillの調整
これまでの開発でwebpackの存在など一ミリも気にしていなかっただけに、原因特定にハマってしまいました。。
下記の記事には大変お世話になりました本当にありがとうございます🙇‍♂️
https://blog.hiroppy.me/entry/webpack5

> Node.jsのpolyfillの自動挿入が廃止

はい、Node.jsさんこれまでお手数をおかけし申し訳ございません。
下記を参考に、既存ソースで使っているpolyfillを特定しました。
https://github.com/webpack/node-libs-browser
どうやらutil、processあたりでエラーとなっているみたいだったので、`polifills.ts`に追加して無事解決、、、**Chromeでは**

# 闇のIE 11対応
（心の声） ------------------------------------------------------------
<font color="gray">いや〜、あと先短いIE 11ですがまだ使っているのですね、
そもそもAngular 12ってIE非推奨になっているのですが。。
これまでもIEのAngular部品（nz-zorroとか）に対する描画レスポンスの悪さは露呈してたじゃないですか、もう不毛な争いはやめましょうよ。。</font>
------------------------------------------------------------ここまで
とか思いながら、健気に調査・対応しました。
結論として（運良く）、`polifills.ts`に`core-js`を追加するだけでうまく動いてくれました。
（`polifills.ts`の書き方が悪くて（`import`するところを`require`してたりして）zone.jsとコンフリクトしたりもしましたが、無事解消できました）
angular 13へのアップデートでIE対応させるのは（本当に）厳しい！！！！と思います。

# 結論
IEはもう安らかに眠らせてあげましょう。

読みにくい長文を最後まで閲覧いただき、ありがとうございました🙇‍♂️
良い開発を😄
Bar-Chart-Raceで歴代最多本塁打数を表示してみた

Bar-Chart-Raceを試してみたいと思ったので、プロ野球の歴代本塁打数で作ってみました。
データは[こちら](https://npb.jp/)からお借りしました。

# データの収集・加工
- 使うデータ：1946年～2021年までの本塁打数。
- 抽出した選手：2021年時点で歴代本塁打数上位の選手と各年度本塁打数が多い選手（特に1940年代～1960年代のデータ用）。

元データは各年度の本塁打データなので、それを累積に変換する。
Excelにデータを収集し、累積データへ変換
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683664/ec80e1e6-8c0b-2d18-fa2b-a6fa1ef74a6e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683664/8d027b15-ee89-b204-355a-7ecbb08219f4.png)

pandasで取り込むために累積データをCSVへ変換。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683664/2034e9b5-4705-b307-95bf-9a5ff3b47f3f.png)

累積データのCSVファイルをGoogle Colabへアップロード

# 実装
Google Colabで実装

```python:
import numpy as np
import pandas as pd
import csv
import matplotlib.pyplot as plt

%matplotlib inline

# グラフに日本語フォントで出力するため、japanize-matplotlib が必要．
!pip install bar-chart-race
!pip install japanize-matplotlib

import bar_chart_race as bcr
import japanize_matplotlib


# 時間軸を設定
year = 2021
csvファイルの読み込み
df = pd.read_csv('ファイルパス', encoding='shift-jis',header=0, index_col=0)
# 欠損値を除外
df.dropna(inplace=True)
# 1946～yearで設定した年までのデータを取得
df = df.iloc[df.index.get_loc(1946):df.index.get_loc(year+1) ,:]

# 上位20件を表示
# period_lengthで再生時間を調整（大きくするとゆっくりになる）
bcr.bar_chart_race(df=df, n_bars=20, period_length=500)
```

# 出力!
![BCR_NPB_HR_500.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683664/212cc2ee-1b4e-b254-ce85-f69434b7e0bf.gif)

※ゴジラは日米通算と日本のみの2つデータを用意したので、区別するため（メジャー）としてます。


# 参考資料
[日本プロ野球機構](https://npb.jp/)
[【簡単/無料】「動くグラフ」の作り方を解説](https://kino-code.com/bar-chart-race/)
[Matplotlibを使って「ぬるぬる動く棒グラフ」を作ってみた](https://life100create.com/bar-chart-race-matplotlib/)
lsofとfuserのやっていることが同じに見えて仕方がない件

# はじめに
Linuc201の勉強して気づいたけど、
普段、特定のファイルをつかんでいるプロセスを把握するためにlsofを使っていたけど
fuserでも同じことができるそうだ。
「あれ？同じことできるコマンドが２つあるの？」って思って調べることにした。

# fuser＝ファイルが主、lsof＝プロセスが主

実際に比較してみたらよくわかった。
↓↓は、/var/log/audit/audit.log　を参照しているプロセスはなんだろな？って
お題でそれぞれ実行したときの結果の比較。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/042996a8-d661-b717-5e0e-54f4719028f4.png)

fuserの見せ方は「"audit.log"を参照しているプロセスは”auditd”です。」って感じだけど
lsofは、「"auditd"は"audit.log"を参照しています」ってなってる。

なので、「誰かがファイルをつかんでいるから削除できない、ってときに使うのが"fuser"」で
「特定のプロセスがつかんでいるファイルはなんだろな？ってときに使うのが"lsof"」。

仕事ではlsofを使うのは、「とりあえず何らかの理由でつかまれているファイル全部リストアップして怪しいプロセスを探そう」って感じで
いつもまるっと棚卸的な感じで進めてるのでオプションも考えずにlsofを実行するだけで結果が出るので何も考えずに済んで楽だから使っていることに気づいた。

fuserの場合は「このファイルなんで削除できないのー？みたいなとき」なので、バグ探しとかに向いている気がする。

結局、使い方の問題なんだなってことはわかった。（当たり前だけど…）

～おしまい～
PortainerでDockerコンテナの一元管理を行う

Dockeのコンテナ管理のため、WebUIを導入することに。
調べてみると色々なUIツールが存在し、今回はPortainerをインストールしてみたいと思う。
取り急ぎ構築備忘のため、簡単に手順をメモ。

# インストール
次のように`docker-compose.yaml`を作成。

```yaml:docker-compose.yaml
version: '3.2'
services:
  portainer:
    image: portainer/portainer-ce
    ports:
      - "127.0.0.1:9000:9000"
      - "8000:8000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - data:/data
    restart: always

volumes:
  data:
```

# nginxリバースプロキシ設定
```conf:nginx.conf
location /portainer/ {
    proxy_pass http://localhost:9000/;
}
```

# nginxのpermission denied対応
`http://xx.xx.xx.xx/portainer/`でアクセスするとpermission deniedが表示された。
SElinuxのログをチェックしてみると、deniedログが存在。


```
$ tail -f /var/log/audit/audit.log
```

下記のように`httpd_can_network_connect`のパラメータを変更したら解決した。

```sh
$ setsebool -P httpd_can_network_connect 1
```

# 参考
https://docs.portainer.io/v/ce-2.11/
https://github.com/portainer/portainer
https://tech.mktime.com/entry/447
NeurIPS2021の枝刈り論文 (1)

# 概要
この記事では、NeurIPS2021の枝刈り論文をまとめます。[^1]

[^1]: 画像や数式は論文から引用しています。


# Learning Compact Representations of Neural Networks using DiscriminAtive Masking (DAM)

https://arxiv.org/abs/2110.00684

概要：DAM。コンパクトな表現学習やstructured pruning用の1-stage pruning
新規性：Structured pruningでSOTA。従来は、L1ノルムでの最適化(NetSlim等)など、L0ノルムの連続近似で最適化していたが、DAMはL0ノルム最適化に等価。
キモ：
ChipNetやNetSlimと同様、マスクパラメータ$g_i$を学習する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/7ee2fcb3-ef36-185b-6aa3-85fd748d95b7.png)
マスクの非ゼロの個数$\beta_i$をロスに加えて学習する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/59f6afe1-a079-25be-e842-bb31826649b6.png)
評価：ChipNet, NetSlimとPreResnet-164、Cifarで実験した。


# DynamicViT: Efficient Vision Transformers with Dynamic Token Sparsification

https://arxiv.org/abs/2106.02034

概要：DynamicViT。ViTのトークンを刈る。
新規性：ViTのトークンの枝刈りを提案。CNNのアーキテクチャで時々ダウンサンプリングすると同じ発想で、ViTでも特定レイヤでトークン数を減らす。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/8d60439f-c4b4-b5b0-d864-e890e292674f.png)
キモ：枝刈りをマスクで表現する。マスク$\mathbf{D}$は、Gumbel-Softmaxで微分可能として学習する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/fdce5ab6-e330-cb0b-16db-3d2e6b235641.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/e028e6be-0ca8-93a4-d3cf-b878dbd10c68.png)
評価：DeiT、ImageNet等に適用した。FLOPsを30%くらいに削減、精度0.5%悪化。


# The Elastic Lottery Ticket Hypothesis

https://arxiv.org/abs/2103.16547

概要：E-LTH。宝くじ仮説で、当たりくじを同じアーキテクチャのファミリで大きくしたり小さくしたりできる。
研究機関：Microsoft
新規性：当たりくじを見つける方法は反復法(IMP)が多い。データセットやオプティマイザを変えても有効な方法(One ticket to win them all)はあったが、ネットワークを変えて当たりくじを変化させるものは初。
キモ：複製するレイヤはなるべくかぶらせないようにする、レイヤを落とすときは序盤を残す(3.1章)などのルールを考えて実験で確認した。
評価：ResNet, VGG, Cifar, ImageNetで先行手法と比較した。従来のOne-Shot系よりは良い。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/a8e4a168-1242-8585-188e-60995ce4afce.png)


# Validating the Lottery Ticket Hypothesis with Inertial Manifold Theory 

https://openreview.net/forum?id=h6EWbx5xTj7

概要：宝くじ仮説の理論面の考察
新規性：当たりくじの存在を、力学的理論から証明した。
キモ：勾配法の解のうち、一部によって作られるinertial manifoldが存在し、そこに解が収束することを示した(定理5)。その解の上界を求める((23)式)ことがで刈るアルゴリズムIMCを提案した。
評価：ResNet, CIFAR, ImageNetで枝刈り実験した。


# Only Train Once: A One-Shot Neural Network Training And Pruning Framework

https://arxiv.org/abs/2107.07467

概要：Only Train Once (OTO)。One-shot trainingしながら枝刈りできる。
研究機関：Microsoft
新規性：従来の枝刈りの課題である、(i)ヒューリスティックなパラメータを設定する必要がある (ii)Fine-tuningが必要 (iii)特定アーキテクチャしか使えない を解決する、Fine-tuning不要なOne-shot学習を提案した。
キモ：ZIG (Zero-不変なチャネル) 同士に分けるように最適化するオプティマイザ HSPG
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/f11d1302-274d-8f78-7ead-4ba8aa9d3079.png)
評価：VGG, ResNet, Cifarで枝刈り実験した。
client_loop: send disconnect: Broken pipeでつまづいた話

#はじめに
SSHでサーバーにログインできず、3時間作業が止まったため備忘録として置いておきます。

##エラー内容

```
.ssh % ssh ec2-user@<IPアドレス> -i <Pemファイル>
client_loop: send disconnect: Broken pipe
```

##解決方法
.ssh/configを開きます。

```
Host *
  IPQoS lowdelay throughput
  Port 22
  HostName <ポート番号>
  User ec2-user
  IdentityFile ~/.ssh/<入りたいPemファイル>
```

これだけでログインできました。

同じところで詰まっている方がいらっしゃいましたら、
ぜひ参考にしてください。
【AWS】SAA合格体験記 - 2020年9月1日 -

# SAAについて
SAAはAWSの資格だとちょうど中間のレベルの資格になります。
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512673/b92e754d-59fa-cea7-4e9f-099d5f64d2f2.png)

私は1回目は不合格(646点)、2回目で合格(746点)できました。
1回目はSAA-C01、2回目はSAA-C02です。
01→02で結構な内容変更を感じたので、2022年8月にSAA-C03に変更された場合は、
また試験内容は更新が入ると思います。

# 推奨されるAWSの知識
・AWS のコンピューティング、ネットワーキング、ストレージ、管理、
　データベースサービスを使用した実務経験
・AWS のテクノロジーを利用したソリューションの技術要件を特定し、定義する能力
・提示された技術要件を満たす AWS のサービスを特定する能力
・適切に設計されたソリューションを AWS で構築するためのベストプラクティスに
　関する理解
・AWS のグローバルインフラストラクチャに関する理解
・従来のサービスに関連する AWS のセキュリティサービスと機能に関する理解

# 勉強方法①
Amazonにて下記テキストを購入、少し時間をあけつつ3周ほどやりました。
[(模擬問題付き)改訂新版 徹底攻略 AWS認定 ソリューションアーキテクト − アソシエイト教科書[SAA-C02]対応](https://www.amazon.co.jp/%E6%A8%A1%E6%93%AC%E5%95%8F%E9%A1%8C%E4%BB%98%E3%81%8D-AWS%E8%AA%8D%E5%AE%9A-%E3%82%BD%E3%83%AA%E3%83%A5%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%88-%E3%82%A2%E3%82%BD%E3%82%B7%E3%82%A8%E3%82%A4%E3%83%88%E6%95%99%E7%A7%91%E6%9B%B8-SAA-C02/dp/4295010650/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=YH6ONZDF0WY1&keywords=AWS+SAA+%E9%BB%92%E6%9C%AC&qid=1642925293&sprefix=aws+saa+%E9%BB%92%E6%9C%AC%2Caps%2C274&sr=8-1)

# 勉強方法②
下記の有料会員になり、SAA#100～最新までを2週ほど実施しつつ、解説を読み、
わからない箇所はQiitaや個人ブログを参照して勉強をしました。
[AWS WEB問題集で学習しよう](https://aws.koiwaclub.com/)

# 勉強方法③
Udemyの下記問題集も実施しました。
高難易度と書いているだけあり、結構難しかった記憶があります。
[【2022年版】AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集（6回分390問）](https://www.udemy.com/course/aws-knan/)

# 総評
上記のテキスト、問題集を実施すれば受かることが可能だと思います。
SAAの勉強をすることで、実際の現場でも有用な知識が得られますので役に立ちます。
私はだいたい2か月ほどがっつり勉強していたと思います。
SAAは特に幅広く知識が求められるため結構難易度が高めだと感じました。

ただAWSを使う職場で働いていれば、自分のふれたことがないサービスを中心に
勉強すれば取得難易度がさがるかなという印象です。
【React】親コンポーネントのuseStateから子コンポーネントの値を管理する

子コンポーネントから`onChange`イベントを検知し、値を取得して親コンポーネントに渡します。

子コンポーネント名: `Input.tsx`
親コンポーネント名: `Parent.tsx`
この二つのコンポーネントを使用して解説を行なっていきます。

# Parent.tsx

```react:Parent.tsx
import Input from '...'

const Parent = () => {
  const [password, setPassword] = useState('')

  return <Input onChange={setPassword} />
}
```

`Input`コンポーネントに対して、`onChange`という関数をPropとして渡しています。


# Input.tsx

```react:Input.tsx
interface Props {
  onChange: (arg: string) => void
}

const Input<Props> = ({
  onChange
}) => {
 
  return (
    <input
      type="text"
      onChange={(e) => onChange(e.target.value)}
    />
  )
}
```

`Parent.tsx`からPropで渡ってきた`onChange`イベントを受け取り、`input`要素で使用します。
`input`要素で`onChange`イベントを捕捉したら、親から`Prop`で渡ってきた`onChange`を発火させます。
消費額推移をTableauで可視化

e-statの家計調査データを使って、消費額の推移を可視化します。
完成版は[Tableau Public](https://public.tableau.com/shared/TTQCPCHHZ?:display_count=n&:origin=viz_share_link)参照。


![年末年始の消費動向 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2114658/65ff5046-0e34-2a18-ea84-6f588da31353.png)

#作成方針
家計の消費項目は、季節によって大きく異なるので、それを可視化できると興味を引くものができます。今回のダッシュボードでは、特定の月に消費金額が跳ね上がるものをランキング化して可視化しました。また、月ごとだけでなく、日毎のグラフも合わせて表示することで、月の中でも特定の期間に偏ってのかどうかを見ることができます。

#データのダウンロード

[家計調査（家計収支編）　時系列データ（二人以上の世帯）](https://www.stat.go.jp/data/kakei/longtime/index.html)から、[月別の全品目支出金額](https://www.stat.go.jp/data/kakei/longtime/csv/h-mon-2015.csv)と
[家計調査の表番号6−16の品目分類による日別支出](https://www.e-stat.go.jp/stat-search/files?page=1&layout=datalist&toukei=00200561&tstat=000000330001&cycle=1&tclass1=000000330001&tclass2=000000330004&tclass3=000000330005&tclass4val=0)から年末年始分のデータをダウンロードします。

#データ整形
月別の全品目支出金額データは、データベース形式で提供されていないので、整形する必要があります。
まずは、Tableauでデータインタープリターを使用して読み込みます。

使用前
![Screenshot 2022-01-23 15.31.45 - Display 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2114658/cc5212ad-e026-2fdc-ea08-cb50e434548a.png "そのまま読み込み")

使用後
![Screenshot 2022-01-23 15.34.06 - Display 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2114658/a792377e-54e3-0e03-a0c8-3fd40b417453.png "データインタープリター使用後")

項目名「１」〜「６０」は、各月の値が入っているので、ピボット解除します。
![Screenshot 2022-01-23 15.40.54 - Display 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2114658/c7d23f01-b62c-bed2-9c9c-7c53c620478a.png)

#消費額が年末に跳ね上がる品目の特定
とりあえず折れ線グラフにしてみると、品目が多すぎてよくわかりませんね。
![Screenshot 2022-01-23 15.49.26 - Display 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2114658/083f3522-5a0d-411f-62da-4a161814ac0b.png)

なので、「年末に跳ね上がる」を（12月の割合）=　(12月の消費額合計)/(年間の消費額合計)と定義して、TOP１０のみ表示していきます。
折れ線グラフで表現してもいいのですが、TOP10を見せるのであれば、項目数がやや多すぎる気がするので、今回はハイライト表を使って可視化します。

まず、TOP10にフィルターするために、セットフィルターを設定していきます。
![Screenshot 2022-01-23 16.15.41 - Display 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2114658/f280747b-5093-2fb3-11db-78a6fe93228b.png)


```:式指定
sum(iif(DATEPART('month',[年月])=12,[消費額],null))/sum([消費額])
```

![Screenshot 2022-01-23 17.01.55 - Display 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2114658/4c53931d-61b9-5b71-b3fb-b5419077a94b.png)

TOP10を12月の割合順に並べるために、EXCLUDEを使います。以下の式を不連続にして、行の先頭に持ってきます。

```:12月の割合
{exclude DATEPART('month',[年月]):
    sum(iif(DATEPART('month',[年月])=12,[消費額],null))/sum([消費額])
}
```

あとは、日別の消費額を棒グラフで表現し、ダッシュボードに配置して完成です。
【Docker】DockerfileにてRUN 、 CMD 、 ENTRYPOINTの違い

皆さん、こんにちは。
私は最近Dockerを学んでいますので、勉強したものとか、分からないものとか記事をしてみんなに共有したいんです。

Dockerでimageを作成するため、よくDockerfile経由で行われます。
RUN 、 CMD 、 ENTRYPOINTなどのコマンドをよく使われていますが迷っている人がいるはずでしょうか。

これからDockerfileにてRUN 、 CMD 、 ENTRYPOINTの違いところをそれぞれまとめて説明いたします。


## 一、RUN 
RUNコマンドを使うと新しい層を作ります。通常としては、パッケージ、プラグインなどのソフトウェアをインストールする際に、RUN　コマンドを使います。
例：

```
RUN apt-get install python3
```

## 二、CMD
CMDコマンドを使うと、デフォルトのコマンド、引数などを設定できます。
あと、コマンドラインで新コマンド、引数を渡すと、デフォルトのコマンド、引数をカバーできます。
また、CMDコマンドを使ってENTRYPOINTの引数を設定することも可能です。
ただ、CMDコマンドは最後の一個だけのCMDコマンドを実行されます。ほかのCMDコマンドを無視されます。

例：

```
CMD echo "Hello world" 
```

## 三、ENTRYPOINT
ENTRYPOINTとは、Dockerのcontainerを起動する際に、必ず実行されるコマンドです。
ENTRYPOINT使うとDockerのcontainerの起動コマンドを設定できます。
このコマンドは原則として無視されないです。
例：

```
ENTRYPOINT ["/bin/echo", "Hello"]  
```



## 最後に
最後まで読んでいただき、ありがとうございました。
React Native Expo利用時にAndroidエミュレータでエラーになるときの対処法

React NativeのExpoでAndroidエミュレータを開いたときエラーが出たため、その解決方法を備忘録として残しておきます。

## 環境
MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) OS Monterey12.1
expo --version：5.0.3
端末：Pixel_2_API_30:

# エラーが起こったエミュレータ起動手順
①ターミナルで以下のコマンドでExpoの管理画面をブラウザ表示

```
expo start
```

②サイドメニューのRun on Android　/device/emulatorからエミュレータを起動する

![スクリーンショット 2022-01-23 17.00.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360790/6e3008cd-60aa-9d01-fec9-03aa788dd019.png)

# エラー内容

上記の方法でExpoでアプリを開くと以下のエラーになってしまう。

```
Something went wrong.
Sorry about. You can go back to Expo home or try reload the project.
```

![スクリーンショット 2022-01-23 17.03.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360790/1348de0d-25d7-9092-46aa-5dcf16777988.png)


View error logをみてみると、以下のようなエラーが出ている。


```
Uncaught Error: java.net.UnknownHost.Exception: Unable to resolve host "exp.host":No address associated with hostname
```

![スクリーンショット 2022-01-23 16.54.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360790/b33249a6-737c-ab4d-7483-64875f5e81a5.png)


調べてみると端末がネットワークに繋がっていないらしい。


# 解決方法
ブラウザのExpoからではなく、ターミナル上からエミュレータを起動する
※下の参考文献を参考にしてください。

```
cd /Users/xxx/Library/Android/sdk/emulator

# 端末一覧を表示
./emulator -list-avds

# ↓Pixel_2_API_30の部分は端末一覧の中から的かつ変えてください
./emulator -avd Pixel_2_API_30 -dns-server 8.8.8.8

```

これでアプリが表示されるようになった！
![スクリーンショット 2022-01-23 17.09.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360790/a0f5a6c3-ba4d-b3ea-edb1-15940f721af7.png)


後々、私の環境ではPixel_2_API_30だとSystemエラーが出て安定しなかったのでPixel_5_API_30変えました。。


#参考記事
[Android エミュレーターでネットワークに繋がらない時](https://qiita.com/maaaaaiiiisan/items/fdcf1c370fc381bb9dd2)
ローカルでCircleCIを使う

# はじめに

この記事は、CircleCIをローカルで動かすために行なったことを記事にしています。間違っている箇所などがございましたら、指摘していただけると幸いです。

# 前提

- Mac
- Docker導入済み
- GitHubのアカウント作成済み

# homebrewでインストール

homebrewを使用している場合は、以下のコマンドを使用して CLI をインストールできる。

```bash
brew install circleci
```

# CLI の構成

[パーソナルAPIトークンタブ](https://app.circleci.com/settings/user/tokens)にアクセスをして、「Create New Token」をクリックして、トークンを発行します。

![スクリーンショット 2022-01-23 16.39.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880196/82063fe0-f56e-3b4c-4de4-cd745ab35e64.png)

![スクリーンショット 2022-01-23 16.41.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880196/9d78cb8e-e2b5-4728-e5b5-5eb5235028fc.png)

自分の好きな名前で「Add API Token」をクリックします。

![3yyjo9tnzs83vzku9w4j9ji5hltt.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880196/2f9d42d5-309e-f067-b18e-52d9044fc5cf.jpeg)

トークンをコピーします。

# トークンの設定
```bash
circleci setup
```

上記コマンドを実行したら、先ほど取得したトークンを入力します。
次にCircleCIを使用するホストを聞かれるので、そのままEnterでOKです。
ホストはデフォルトで設定されています。(https://circleci.com)

```bash
? CircleCI API Token ****************************************
API token has been set.
? CircleCI Host https://circleci.com
CircleCI host has been set.
Setup complete.
Your configuration has been saved to /Users/name/.circleci/cli.yml.

Trying an introspection query on API to verify your setup... Ok.
Trying to query our API for your profile name... Hello, name.

```

これで設定は完了しました。


# 実際にローカルで動かしてみる

### 設定ファイルのバリデーション
設定ファイルをバリデーションするには、.circleci/config.yml ファイルがあるディレクトリに移動し、以下を実行します。

```bash
circleci config validate
```

### ジョブを実行する
※CircleCI の設定ファイルをバージョン 2.1 以上に設定している場合、ジョブを実行するには、設定ファイルを process.yml にエクスポートしてから、そのファイルを指定する必要があります。

```bash
circleci config process .circleci/config.yml > process.yml
```

エクスポートが完了したら、下記コマンドでジョブを実行します。

```bash
circleci local execute -c process.yml --job JOB_NAME
```

# 参考
https://circleci.com/docs/ja/2.0/local-cli/#
.Net6 EFCore6 seedデータ


# はじめに
環境

```
C#
.Net6
EFCore6
Blazor
```


Seed は公式があるのですが
どのファイルに追加するかがわかりずらいです。
https://docs.microsoft.com/ja-jp/ef/core/modeling/data-seeding


# 実装
```c#:/Server/Data/AppDbContext.cs

namespace BlazorApp.Server.Data
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions options) : base(options)
        {}

        public DbSet<Building> Buildings => Set<Building>();


        // エラーを表示するのに必要だとか
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.EnableSensitiveDataLogging();
        }

       // 
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Building>().HasData(
                new { BuildingId = 1, OwnerId = 2, BuildingName = "集合住宅A", BuildingType = BuildingTypeEnum.HousingComplex, BuildingDetail = "駅近です" }
            );
        }
   }
}
```



# Enumをつかっているケース
```
BuildingType = BuildingTypeEnum.HousingComplex  のように代入するのですが


他のEnumでは
 RoomStaus = 0  こんな感じでも代入できます
```

命名規則の関係かもしれませんが、よくわかってないです。


# Dataの反映
```
dotbet ef migration add SeedData
database ef database update
```

これでOK
.NetではSeedはMigrationの一部なんですね
またローカルと本番でSeed有無を分けたりしないのが基本のようです。

他のフレームワークとの違いですね



次はAPI作成ですが、こちらは簡単そうなので
ようやくBlazorに取り掛かれそう。
2022_0123.0.1 Opnessl

環境：
         Icon name: computer-vm
           Chassis: vm
        Machine ID: 6d12c80cd2cb0c409f7a3e4b8c6b71dc
           Boot ID: c26be545d2d449f985a3263d896f6d8d
    Virtualization: kvm
  Operating System: CentOS Linux 7 (Core)
       CPE OS Name: cpe:/o:centos:centos:7
            Kernel: Linux 3.10.0-1160.49.1.el7.x86_64
      Architecture: x86-64

確認
$ yum list | grep openssl
openssl.x86_64                              1:1.0.2k-22.el7_9          @updates 
openssl-libs.x86_64                         1:1.0.2k-22.el7_9          @updates 

秘密鍵生成
$ openssl genrsa -des3 -out genrsa-des3.key 2048
Generating RSA private key, 2048 bit long modulus
..............+++
...................................................+++
e is 65537 (0x10001)
Enter pass phrase for sin-rsa-des3.key:
Verifying - Enter pass phrase for sin-rsa-des3.key:

秘密鍵から公開鍵を生成
$ openssl rsa -in genrsa-rsa-des3.key -pubout > pubkey.key
Enter pass phrase for sin-rsa-des3.key:
writing RSA key

RSA形式の公開鍵の内容を確認
$ openssl rsa -puboutin -in sin-rsa-pubkey.key -text
Public-Key: (2048 bit)
Modulus:
    00:a6:df:27:3d:5d:c4:e0:85:2e:df:56:ef:f7:85:
<<秘密鍵内容>>
    dd:df
Exponent: 65537 (0x10001)
writing RSA key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApt8nPV3E4IUu31bv94U8
<<公開鍵内容>>
lrhe8xxh+c/oolAoIHk7AVww1p70e4Z4MTmHz9fnf8y5haUM/b0AueRJosS5tUjd
3wIDAQAB
-----END PUBLIC KEY-----

公開鍵を用いて暗号化
$ openssl rsautl -encrypt -pubin -inkey rsa-pubkey.key -in test -out test-rsa.txt

秘密鍵を用いて復号化
$ openssl rsautl -decrypt -inkey genrsa-des3.key  -in test-rsa.txt -out test-decrypt.txt
Enter pass phrase for genrsa-des3.key:
【設計】スケジュールへの不安が止まらない私へ【備忘録】

論理的思考とは、事実を正しく認知し、そこから正しく演繹すること。
ところがそれは意外と難しい。

※事実と意見は混同されやすいし、判断は感情の影響を受けやすい。



#◆経験主義
経験主義とは実験・行動することによって不確実性を減らす考え方。
つまり「未来のことは分からない」ので、行動することで未来を現在にする。
これは具体的な事象の観察から結論を導き出すという意味で、帰納法的である。
スクラムは経験主義に基づいている。


>経験主義の対極は理性主義で、理性的に考えれば正しい結論に到れるという考え方。
ウォーターフォール型開発プロセスは理性主義を前提にしていると言える。


経験主義で重要なのは、<b>行動によって新たな知識を獲得する</b>こと。

そのためには

```
1.コントロールできるものとできないものを区別し、
2.コントロールできるものを操作すると同時に、
3.その結果を観測する
```

必要がある。



#◆仮説思考
仮説思考とは、演繹的(理性主義)でもなく、帰納的(経験主義)でもない考え方。
少ない情報で大胆な仮説を立て、それを検証していくアプローチ。
つまり、必ずしも事実・データに立脚しない。
仮説思考では、何をどのように検証するのかが重要となる。

仮説思考をうまく利用すると、意思決定を遅延することができる(リアルオプション戦略)。
つまり、まずは小さな投資で仮説の検証を行い、その結果を元に最終的な判断を行うことで、期待値を最大化する。
プロダクト開発におけるMVP (Minimum Viable Product) はその具体例




#『不確実性』で不安にならないためには？？
いずれにせよ不確実性に対処するには、
<b>「行動を通じて新たな情報を生み出す」</b>という、
<b>経験主義と仮説思考に共通する考え方が重要</b>となる。


理想に向けて、事業を最速かつ生産性高く成長させるには、
「未来」と「他人」という2つの不確実性をマネジメントすることで、成し遂げられる

※プロジェクトは初め不確実性の大きなものであり、
徐々に不確実性が下がっていく（想定納期は実際の2倍〜1/4と大きな幅がある）


https://qiita.com/kamesennin/items/89d479112554a6f9d038

https://qiita.com/yebihara/items/88c311a754a7ac953db6



#スケジュール不安と方法不確実性への対処
目的の機能・プロダクトが「いつリリースされるのか」という問いになるべく早期に答えるために行うのがスケジュールマネジメントで、3つの要素から成る。

>個別タスクの見積り
制約スラック
プロジェクトバッファ

制約スラックとはタスク同士の依存関係に起因する無駄のこと。
属人化したタスクがあると、特定の人の生産性が全体のボトルネックになる(リソース制約)。
タスク間に前後関係があると、それらのタスクを並行処理することができない(依存制約)。
属人性を減らし、作業を分解して並行実施できるようにすることで、制約スラックを減らすことができる。

プロジェクトバッファは見積りの不確実性を吸収するために設ける時間的余裕。
バッファはタスクごとに設けるのではなく、プロジェクト全体で設ける。

不確実性を吸収するのに十分なバッファが残っているかどうかは、プロジェクト全体の「不安量」から判断する。
不安量は各タスクの多点見積りから算出する。

不安量が大きいタスクから先に着手すること。
これによりスケジュール後半になってリスクの大きなタスクが残っている状況を避けることができる。
また、不安量の大きなタスクを分解し、不安量を小さくすることも重要。

そもそもタスクに要する時間を見積もることは難しい。
相対見積りを行い、小さなスプリントをいくつか実施してベロシティを計測すると、実績ベースでバッファの過不足を判断できるようになる。
SAMBAの実装①（概念編）

本日の投稿はSAMBAです。

＜概念＞
SAMBAを使うと、Linuxに対してWindowsNetwork内へのclient / Server機能を実装する事ができます。
client機能としては、WindowsNetwork内のリソースにアクセスできます。
server機能としては、
・ファイルサーバ
・プリンタサーバ
・ドメインメンバ
・ドメインコントローラ
をLinuxに実装し、WindowsNetwork内のclientに各サービスを提供できます。
SAMBAを実装していないLinuxはWindowsNetworkに接続できません。

☆図を作成しましたので、ご覧ください。
　上部は、Client機能を持ったSAMBA　　　下部は、Server機能を持ったSAMBA
![20210122_SAMBA - ページ 1 (1).jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2498823/c6b7ca6b-367f-6b42-3139-4c8c6170ca47.jpeg)


主に、ユースケースとしては、ファイル共有を実現する為に用いられ事が多いでしょうが、
WindowsNWでプリントサーバーやドメインコントローラ等のサーバーの機能を実装することも実現できます。



実装編では、
・ファイルサーバ
・プリンタサーバ
・ドメインメンバ
・ドメインコントローラ
を構築します。

次回をお楽しみに～～～～～:sunny:
【正規表現】PHPで郵便番号をIF文で条件定義

```php:test.php
<?php
$code = '0011-0012';

if(preg_match("/\A\d{3}[-]\d{4}\z/",$code)){
    echo('郵便番号：〒'.$code);
}else {
    echo('※郵便番号は000-0000の形式でご記入ください');
}

?>
```

<h1>説明

<p>
①preg_match — 正規表現によるマッチングを行う
https://www.php.net/manual/ja/function.preg-match.php

②/\A　←ここまでの意味・・・文字列の先頭を意味します。

③\d{3}　←これの意味・・・「d」が数字指定、{3}数。数字で3文字入力しなさい。

④[-]　←これの意味・・・郵便番号のハイフンです。ハイフン無し入力をユーザーにした正規表現を記述したい場合はこれは不要です。

⑤\d{4}　←これの意味・・・「d」が数字指定、{4}数。数字で4文字入力しなさい。

⑥\z/ ←これの意味・・・文字列の末尾を意味します。

```php:test.php
preg_match("/\A\d{3}[-]\d{4}\z/");
//000-0000の形式で入力するよう正規表現を定義。
```
既存の IPv4 CIDR ルールに 1 つの 参照先のグループ ID を指定することはできません。

# セキュリティグループ設定時にエラーが
セキュリティグループのルールの設定を変更をしようとした際に、以下のエラーが発生しました。
![スクリーンショット 2022-01-23 16.22.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1514023/1ce2f568-5bf7-3da6-89eb-0f3c36d17af8.png)

# 対策
- 右側にある「削除」をクリックし、対象ルールを一度削除する。
- 「ルール追加」をクリックし、新規ルールを追加することで設定をアップデートできます。
![スクリーンショット 2022-01-23 16.36.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1514023/5412f1a0-4ea8-cd11-0606-1a87aebcfb3e.png)
静的コード解析とは何かを勉強する

# 静的コード解析ってなに？

- ソフトウェアの欠陥につながる書き方を存在しないかどうか解析すること

# 静的コード解析のメリット

- 開発の早い段階でエラー検出できる
    - バグ修正コストを抑制できる
- プロジェクト共通のコーディング規約を推進できる
    - コードの可読性、保守性が向上する
- ツールによって自動化しやすい
    - 導入が簡単

# 静的コード解析のデメリット

- パフォーマンスや仕様の欠陥の検出は難しい
    - 実際にアプリケーションを動かさないと検出しにくい問題には不向き
- 機械的にチェックをするため、指摘事項が膨大になりやすい
    - チェックレベルやルールの設定をしたり、エラーの解析に時間がかかる場合がある

# ソフトウェアの品質向上する手段

- 最初から優れたソフトウェア設計
- ユニットテスト
- インテグレーションテスト
- E2Eテスト

# パターンベース解析

- ルールセットに照らして問題のある記述があるかどうかを確認
  - コード内の該当パターンを検出し、エラーの可能性がある箇所を特定できる
- 開発者が以下に従っていることを保証できる
    - コーディング規約
    - 単体テストのベストプラクティス
    - 組織の開発ポリシー

# フロー解析

- パターンベース解析と同じく、ルールセットに照らして問題のある記述があるかどうかを確認
  - 複雑なパスを特定してトレースするため、人間によるテストや検査では発見が難しいバグを検出できる
- 検出できるバグは
    - 未初期化メモリ
    - null ポインターの間接参照
    - ゼロによる除算
    - メモリリークなど
- コードの実行順序やパスに起因する問題、実行時の例外を検出できる

# 重複コード解析

- その名の通り重複コードがないかチェックする
    - アプリケーションの設計の向上とメンテナンス コストの削減を支援

# メトリクス解析

- オブジェクト間の結合や継承の深さなど、コードの保守性や再利用性の指標となるメトリクスを計測
- メトリクスを使って、潜在的な不具合を特定する
- 誤検知することもある

# Unity で使える静的コード解析

- .NET Compiler Platform (Roslyn) 
    - https://docs.microsoft.com/ja-jp/visualstudio/code-quality/roslyn-analyzers-overview?view=vs-2019
    - Unity 2020.2以降、Unityエディタ上でRoslynアナライザによる静的解析が実行可能になったとのこと
- UnityEngineAnalyzer
    - https://github.com/vad710/UnityEngineAnalyzer




# 参考文献
https://baba-s.hatenablog.com/entry/2017/11/06/090000

https://parasoft.techmatrix.jp/how-does-static-analysis-prevent-defects-and-accelerate-delivery

https://docs.parasoft.com/display/DOTTESTJP1043/Analysis+Types+1

https://www.fujitsu.com/downloads/JP/archive/imgjp/group/fct/v4/events/exhibit/esec2014-17-01.pdf

https://swet.dena.com/entry/2021/05/25/100000

https://hldc.co.jp/blog/2018/03/29/1211/