OmniAICreator/Qiita-1.07M huggingface dataset:
【Python】三項演算子（条件式）

Pythonの三項演算子（条件式）は、短い条件分岐を1行で書くための構文です。他の言語での「三項演算子」に相当し、`if`と`else`を使った条件式を簡潔に記述できます。これを使うと、条件に基づいて異なる値を返したり、設定したりすることができます。
# 基本構造
Pythonの三項演算子の構文は次の通りです：
```python
値1 if 条件 else 値2
```
- 条件: 評価される条件（`True`または`False`）
- 値1: 条件が`True`の場合に返される値
- 値2: 条件が`False`の場合に返される値
## サンプルコード
**サンプル1: 数の大小を比較**
```python
a = 10
b = 20

# 三項演算子を使って大きい方の数を選ぶ
max_value = a if a > b else b

print("The larger number is:", max_value)
```
説明: このコードは、`a`と`b`のどちらが大きいかを比較し、大きい方の値を`max_value`に代入します。

**サンプル2: 偶数か奇数かを判断**
```python
number = 7

# 三項演算子を使って偶数か奇数かを判定
result = "Even" if number % 2 == 0 else "Odd"

print("The number is:", result)
```
説明: `number`が偶数なら`"Even"`, 奇数なら`"Odd"`を`result`に代入します。

**サンプル3: 入力に基づいてメッセージを表示**
```python
user_input = input("Enter 'yes' or 'no': ")

# 三項演算子を使ってメッセージを決定
message = "You said yes!" if user_input.lower() == 'yes' else "You said no!"

print(message)
```
説明: ユーザーが`"yes"`と入力した場合、`"You said yes!"`を表示し、それ以外の場合は`"You said no!"`を表示します。

**サンプル4: 複数の条件で値を選択**
```python
score = 85

# 三項演算子をネストして複数の条件に対応
grade = "A" if score >= 90 else "B" if score >= 80 else "C" if score >= 70 else "D" if score >= 60 else "F"

print("Your grade is:", grade)
```
説明: `score`の値に基づいて成績を判定し、`grade`に代入します。この例では三項演算子をネストして使っています。
# if-elseとの比較
通常のif-else文と比較すると、三項演算子は次のようにより簡潔に書けます。
```python
# 通常のif-else文
if condition:
    result = value1
else:
    result = value2

# 三項演算子を使うと
result = value1 if condition else value2
```
# まとめ
- 三項演算子: 短い条件式を1行で書くことができる。可読性を保ちながらコードを簡潔に書くのに便利。
- 使い方: 値1 `if` 条件 `else` 値2 の形式で使う。

######
参考)　[東京工業大学情報理工学院 Python早見表](https://chokkan.github.io/python/index.html)
Goのbuiltinをサクッとリードしてみる。


builtin.goはGolangのリポジトリの`src/builtin/builtin.go`に書かれている。

このファイルにはGoで使われる定数、type、関数が定義されている。

当たり前に使っている定数や関数がどのように定義されているかをいくつか見てみましょう。


## bool

Goにおけるbool型は`true`と`false`の2つの値を持つ。


それぞれは`true`と`false`という定数で定義されている。


```go
const (
    true  = 0 == 0 // Untyped bool
    false = 0 != 0 // Untyped bool
)
```

（VSCodeのGoの拡張機能で`true`と`false`にホバーするとこの定義に飛べて、初めて見たときは驚いた）

## make

makeは以下のように定義されている。

```go
func make(t Type, size ...IntegerType) Type
```

makeはslice、map、channelに対しするメモリの確保を行う。

Typeがsliceの場合、sizeはlenとcapの両方を指定する。

```go
make([]int, 10, 100)
```

とすると、10個の要素を持つスライスを作成し、そのスライスの容量は100になる。

Typeがmapの場合はsizeはcapを指定する。

```go
make(map[string]int, 100)
```

とすると、100個の容量を持つマップを作成する。

Typeがchannelの場合はsizeはバッファの容量を指定する。

```go
make(chan int, 10)
```

とすると、10個のバッファを持つチャネルを作成する。


## new

newは以下のように定義されている。

```go
func new(Type) *Type
```

newはmakeとは異なり、Typeのゼロ値のポインタを返す。

## panic

panicは以下のように定義されている。

```go
func panic(v any)
```

panicはプログラムを停止させ、関数内でdeferされた関数を実行し、その後プログラムを終了させる。

panicをコールした関数がを呼び出す関数にもdeferされた関数があれば、それも実行される。

プログラムの終了時にはスタックトレースが表示され、0ではない終了コードが返される。

## recover

recoverは以下のように定義されている。

```go
func recover() any
```

recoverはpanicを呼び出した関数内でのみ使用できる。

recoverはpanicをコールした関数内でdeferされた関数内でのみ使用できる。

deferされていない関数の外でrecoverがコールされた場合panicはキャンセルされず、プログラムは停止する。panicしなかった場合はnilを返す。
Hyper-V上にProxmox VEをインストール 

# 概要
Proxmox VEのクラスタリング検証のために、Windows 11 Proの端末上のHyper-Vに、Proxmox VEをインストールしてみました。

### 手順

### ブリッジ用仮想スイッチの作成
Hyper-Vにデフォルトで作成されるDefault Switchは、**接続の種類**が**内部ネットワーク**となっており、ホストOSのネットワークから切り離されています。今回は同じセグメントに接続したいため、以下手順でブリッジ接続用のようにブリッジ用仮想スイッチを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3789581/7875c87c-74a2-7a91-b1b5-a85179566b1c.png)

参考: https://qiita.com/katz_engineer/items/a4693679c2dce84cd211

### 仮想マシンの作成
Proxmox VE 8.2のISOファイルを用意し、Hyper-Vマネージャでインストール元として選択します。また、Networkとして先ほど作成したブリッジ用仮想スイッチを選択します。さらに、**この仮想マシンではWindowsを実行します** をオフにして、**仮想マシン** の作成 をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3789581/f1a5a14b-80e7-da95-c2b8-88b7f9c7047f.png)

### 仮想化支援機能の有効化
仮想化支援機能を有効化するために、管理者権限でPowerShellを実行したうえで以下コマンドを実行します。（仮想マシン名はPVE）

```PowerShell
PS C:\Windows\System32> Set-VMProcessor -VMName PVE -ExposeVirtualizationExtensions $true
PS C:\Windows\System32> Get-VMProcessor -VMName PVE | Select ExposeVirtualizationExtensions
ExposeVirtualizationExtensions
------------------------------
                          True
```

### MACドレススプーフィングの有効化
Proxmox上の仮想マシンがネットワーク接続を行うために、MACアドレススプーフィングを有効化します。

MACアドレススプーフィングを有効にする手順は以下の通りです：

1. **Hyper-Vマネージャーを開く**:
    - 「スタート」メニューから「Hyper-Vマネージャー」を開きます。

2. **仮想マシンの設定を開く**:
    - 設定を変更したい仮想マシンを右クリックし、「設定」を選択します。

3. **ネットワークアダプターの設定**:
    - 左ペインから「ネットワークアダプター」を選択します。
    - 「高度な機能」タブを選択し、「MACアドレスのスプーフィングを有効にする」にチェックを入れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3789581/b2ca8fea-b35c-b994-cd89-ae31895f2439.png)

:::note warn
### 注意事項：Hyper-VでのMACアドレススプーフィングの設定

#### なぜこの設定が必要なのか？
Proxmox仮想マシン（VM）をHyper-V上で実行する際、仮想ネットワークインターフェースカード（NIC）に対してMACアドレススプーフィングを有効にすることが重要です。この設定を有効にする理由と必要性は以下の通りです：

1. **仮想ブリッジとLXCコンテナの通信**:
    - Proxmoxでは、仮想ブリッジ（vmbr0）を介して仮想マシンやLXCコンテナがネットワークに接続されます。この仮想ブリッジは、内部的には物理NICのMACアドレスを使用してパケットを転送します。
    - MACアドレススプーフィングを有効にしないと、Hyper-Vの仮想スイッチが予期しないMACアドレスからのパケットを拒否することがあります。これは、仮想ネットワーク内で動的にMACアドレスが変わるLXCコンテナや、複数の仮想マシンをホストする場合に特に重要です。

2. **セキュリティとフィルタリング**:
    - Hyper-Vでは、セキュリティの観点からMACアドレススプーフィングをデフォルトで無効にしていることがあります。これは、仮想マシンが他の仮想マシンのMACアドレスをなりすまし、ネットワークトラフィックを盗聴することを防ぐためです。
    - しかし、Proxmox環境では、LXCコンテナが独自のMACアドレスを使用するため、正当なネットワークトラフィックもフィルタリングされてしまう可能性があります。

#### 設定を有効にしないとどうなるか？

MACアドレススプーフィングを有効にしない場合、以下の問題が発生する可能性があります：

1. **外部ネットワークへの接続不可**:
    - LXCコンテナや仮想マシンが外部ネットワークにアクセスできなくなります。具体的には、インターネットへの接続や、他のネットワークサービスへのアクセスが阻害されます。
    - コンテナがIPアドレスを取得できない、もしくは既存のネットワーク設定を持っていても、パケットがドロップされることで通信が成立しません。

2. **ネットワークトラフィックの不具合**:
    - 仮想マシン間やコンテナ間の通信に問題が発生し、ネットワークパフォーマンスが低下します。
    - ブリッジを介した通信が正しく機能しないため、内部ネットワークの疎通にも支障をきたします。
:::

### インストール
**接続** して **起動** クリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3789581/10e2e981-d4e5-6318-ef88-45c8b9f26eca.png)

画面の指示に従い、インストールを行ってください。

:::note warn
画面がブラックアウトしてインストール画面が表示されない場合、画面上でキーボードを入力すると表示されます。
:::

インストール完了後、再起動すると利用可能となります。

### データストアの追加
Windows 11端末上にはあまりディスクスペースがありません。
このため、CIFS領域を以下の通りデータストアとして追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3789581/69e82cbc-d7e8-e53b-abf4-21717c96cae8.png)
帰納法と演繹法　どっちがどっち問題について

# はじめに
日頃、データ分析をする中で大事にしているのが、
・仮説思考
・依頼内容に＋αを
という２点です。

こういった、付加価値を発揮していくために分析結果から**示唆だし**をするときに、上司から
**帰納法だけでなく演繹法でも考えてみて**や、その逆を指摘されることがあります。

しかし、、、

いつも、どっちがどっちかわからなくなるので、自分のために、整理・まとめてみます！

なお、今回説明は主に「データ分析の教科書 最前線のコンサルタントがマクロミルで培った知識と実践方法」という本を参考にさせて頂きました。

https://amzn.asia/d/0gFUjMbd


# 帰納法：目の前の事象から新しいものを想像する
複数の事実から共通点を発見し、全体に当てはめて結論を導き出す推論法

２種類ある
・観察的帰納法（主語、術後が同じ）
・洞察的帰納法（意味合いが同じ）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3091004/996494fd-acf0-3135-7842-3983789290bd.png)

とてもわかりやすい図ですね！
※引用：データ分析の教科書 最前線のコンサルタントがマクロミルで培った知識と実践方法

# 演繹法：既存の知識・ルールを活用する
前提となるルールに、物事をあてはめて、あてはまるか、あてはまらないかで結論を導き出す推論法

空・雨・傘　のイメージが強いですね💡

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3091004/53a02d87-0923-1327-e77a-00f4b7ec794e.png)

※引用：データ分析の教科書 最前線のコンサルタントがマクロミルで培った知識と実践方法

データ分析では、右側のパターンで考えることが多いですね🌴

# 最後に
どちらも、データ分析にはかかせない手法ですね！

帰納法で求めた結論を、ほかの事例に演繹法であてはめて確かめてみる・・・
という風に対になる考え方でもあるので、ややこしいのかもしれません。笑

私は、**空雨傘＝演繹法**　と覚えようと思います✨
プログラミングで必要な概念のまとめサイト

1. [アルゴリズムの代表的な種類一覧｜それぞれの特徴を徹底的に解説
](https://web-camp.io/magazine/archives/110411)

1. [プログラミング用語一覧
](https://ja.wikipedia.org/wiki/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E7%94%A8%E8%AA%9E%E4%B8%80%E8%A6%A7)
水力発電の比速度について

# はじめに
電験の電力科目の水力発電に、水車の比速度という概念がある。これは、落差1[m]で1[kW]の相似な仮想水車が存在していると仮定したときの回転速度という意味である。一般に、水車を設置する落差や規模は環境に依存する。したがって、比速度を用いれば、すべての水車を同じ基準で比較することができるようになる。今回は、比速度について簡潔に紹介した後に、落差と出力と比速度の関係を水車の回転数を一定という条件のもとグラフ化してみる。これにより、3つのパラメーターの関係性について調査する。

![hisokudo_phns.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/f5650e15-a111-2181-6cca-78f1654e3c84.png)

# 比速度の定義
前述するとおり、ある水車について落差1[m]で1[kW]の相似な仮想水車が存在すると仮定したときの回転速度を比速度と定める。
導出は以下の記事を参考にされたい。エネルギー保存の法則と流量と速度の関係を使用するようである。

https://kenshoku-bank.com/column/3423/

さて、比速度は以下の式で表すことができる。

```math
N_s=N \frac{\sqrt{P}}{H^{5/4}}
```

ただし、水車の出力は$P[kW]$であり回転速度は$N[min^{-1}]$であるとする。

# 公式の導出

水車の出力P[kW]は流量Q[$m^3/s$]を用いると以下のように表すことができる。

```math
P=gQH\eta
```
ただし、$g,\eta$は重力加速度と水力発電の効率とする。

また、水路は半径rの円筒管であるとすると、

```math
Q=Av=(\pi r^2)v
```

ただし、$v$は流速[m/s]として円筒管の断面積は$A=\pi r^2$であるとする。

次に下図のような水車においてrと回転数Nの積は流速に比例するので、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/998b809a-616b-2e26-03b0-fc52cecba6c4.png)

```math
v=r\omega =  K_1 r (2 \pi N/60)=K_2 (rN)
```

と表すことができる。したがって、エネルギー保存の法則より$v=K_3 \sqrt{2gH}[m/s]$であることを考慮して、

```math
r=\frac{v}{K_2 N}=\frac{K_3\sqrt{2gH}}{K_2N}
```
となる。これらを用いて水力発電出力Pを計算すると以下のようになる。

```math
P=gQH\eta=g(v \pi r^2)\eta=g(K_3 \pi \sqrt{2gH}  r^2)H\eta=K_4 H^{3/2}r^2=K_5 H^{3/2}(\frac{\sqrt{H}}{N})^2
```

つまり、

```math
P=K_6 \frac{H^{\frac{5}{2}}}{N^2}
```

と表すことができる。ただし、K郡は定数である。

ゆえに、

```math
N=\sqrt{K_6} \frac{H^{\frac{5}{4}}}{P^{\frac{1}{2}}}=k \frac{H^{\frac{5}{4}}}{P^{\frac{1}{2}}}
```

ここで、H=1[m],P=1[kW]である仮想的な相似水車における回転速度つまり比速度を求めると以下のようになる。

```math
N_s=k \frac{1^{\frac{5}{4}}}{1^{\frac{1}{2}}}=k
```
したがって、

```math
N=　N_s  \frac{H^{\frac{5}{4}}}{P^{\frac{1}{2}}}
```

ゆえに、

```math
N_s=N \frac{\sqrt{P}}{H^{5/4}}
```

この式の導出は『風車出力は風速の3乗に比例する』の証明と同じ考え方で、具体的にPはHやNの何乗に比例するかと考えると上手くいく。








# グラフ化
さて、横軸を比速度、縦軸を有効落差、高さを水車の有効電力出力としたときのグラフを描写するために以下のプログラムを書いた。

```python hisokudo.py
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
import math 

n=1000
P=np.linspace(100,1000,n)
H=np.linspace(100,600,n)

P,H = np.meshgrid(P,H)

#電源周波数
f=50
#極数
p=20
#水車の回転数（発電機と直結）
N=120*f/p

N_s=N*(P**0.5)/H**(1.25)



plt.xlabel("N_s[m・kW]")
plt.ylabel("H[m]")

plt.contourf(N_s,H,P)
plt.colorbar(label="P[kW]")
plt.savefig("hisokudo_phns.png")
plt.show()
```

これを実行すると以下のようなグラフになる。

![hisokudo_phns.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/f5650e15-a111-2181-6cca-78f1654e3c84.png)

前提条件として、水車の回転速度は固定とした。
このグラフより、実際の水車の有効落差が高いほど比速度は遅くなるようである。また、出力を大きくするためには、有効落差と比速度の両方を向上させなければならないため、効率の良い水車を建設するためには、できるだけ最新の技術を用いたほうが良いかもしれない。しかし、低落差から中落差に対応するフランシス水車を高落差で運用すると、キャビテーションが発生してしまうため、あまり実用的ではない。

# まとめ
今回は、水車の比速度について関連するパラメータと比較するためにグラフ化をした。すると、比速度は水車の落差が大きくなると低下するということが分かった。さらに、大きな出力を得るためには、背反する有効落差と比速度の両方を上昇させないといけないということも分かった。なので、出力の大きな水車を建築するためには、最新の技術を用いるべきである。

# 参考文献
https://denken-ou.com/c2/denryokukanrir2-1/
OpenAIのEval Frameworkについて


# はじめに

- OpenAIのEval Frameworkは、大規模言語モデル(LLM)を評価するためのツールである
  - LLMの評価は難しい課題であり、信頼性の高い比較方法の開発が必要とされている
  - OpenAIがLLMの性能を確保するために内部で使用していたフレームワークをオープンソース化した

## Evalの仕組み

- Evalとは、言語モデルの特定の領域におけるパフォーマンスを測定するための評価タスク
  - 質問応答や感情分析などの標準化されたベンチマークである
  - 異なる言語モデルの比較を可能にする
- EvalはYAMLファイルでデータセットとEvalクラスを定義することで構成される
- Evalを実行するには、oaieval CLIを使用し、完了関数とEvalの名前を指定する

https://github.com/openai/evals

## カスタムEvalの作成方法

- 既存のテンプレートを使用してカスタムEvalを構築する手順は以下の通りである
  1. サンプルデータをJSONL形式で用意する
  2. evals/registry/evals/.yamlファイルにEvalを登録する
- 完了関数を構築することで、モデルが正確に答えるために必要な操作を定義できる
  - 完了関数はCompletionFn URLsまたはOpenAI APIのモデル名で指定する
  - すべてのEvalと互換性を持つには、いくつかのインターフェースを実装する必要がある



## Eval Frameworkの利点

- 標準化された評価指標とベンチマークを提供する
- 使いやすく、わずかなコードですぐに使用できる
- 柔軟性があり、幅広いタスクやベンチマークでモデルを評価できる
- オープンソースであり、研特定のニーズに合わせて使用・修正できる
ファイルの最終更新日を確認してyyyyMMのフォルダを作成し、そこにファイルを移動するPowerShell

## やりたいこと
 - フォルダ内のファイルの最終更新日を確認し、yyyyMMのフォルダを作成
 - ファイルをそのフォルダに移動する

## 環境
 - Windows 10 Pro 22H2
 - Windows PowerShell 5.1

## ソース
```movefiles.ps1
###############################################################################
### ファイルの最終更新日を確認してyyyyMMのフォルダを作成し、そこにファイルを移動する。
###############################################################################

#このファイルの名前を取得
$myname = $MyInvocation.MyCommand.Name.ToString()

Get-ChildItem -File | foreach{
    
    #このファイルを除く
    if($_.Name.ToString() -ne $myname){
    
        #ファイルの最終更新日から年月yyyyMMを取得
        $yyyyMM = $_.LastWriteTime.ToString('yyyyMM')

        #フォルダの作成
        New-Item -Path . -Name $yyyyMM -ItemType 'directory' -Force

        #ファイルの移動
        Move-Item -Path $_ -Destination $yyyyMM
    }
}

```

## 参考
 - [PowerShellの実行ポリシー変更](https://qiita.com/earthdiver1/items/b3f529c81f5892972a72)
 - [とほほのPowerShell入門](https://www.tohoho-web.com/ex/power-shell.html)
 - [Get-ChildItem](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.management/get-childitem?view=powershell-7.4)
 - [New-Item](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.management/new-item?view=powershell-7.4)
 - [Move-Item](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.management/move-item?view=powershell-7.4)
 - [about_Automatic_Variables](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_automatic_variables?view=powershell-7.2)
このシステムをお前に預ける　いつかきっと返しに来い　自動テストを導入してな

# はじめに
システム担当を引き継いだ際に学んだことをまとめてみたいと思います。


# システムに関する前提情報
- 当時の開発者は一人
- スピード優先で開発されていて、引継ぎ時にはほぼ完成していた
- 私(ともう一人)に引き継ぐと同時に開発者は別プロジェクトを担当することに

# もし自分がゼロから開発するならテスト駆動開発を導入したい

当時はスピード優先だったらしく、自動テストまでは対応できなかったようでした。
自動テストを入れるまでは、開発環境にデプロイして動作確認をしていました。
また、システムがサーバレス構成であるためバックエンドに関しては毎回デプロイしないと動作確認ができませんでした。引継ぎ時はデータの受け渡しや型周りの理解が出来ていなかったため、デプロイ→Cloud Watchでログ確認→エラー対応→デプロイを繰り返していました。

最終的に自動テストを入れることはできたのですが、コードをリファクタリングするところから始める必要がありました:cry:

テスト駆動開発はテストを満たすようにコードを実装していくので、小規模に綺麗なコードを実装できます。短期的にはスピード優先の開発より時間がかかりますが、運用保守を見据えた中長期的には時間を抑えることが期待できます。

プロトタイプレベルであればスピード優先で良いと私は考えていますが、
気づいたらプロトタイプレベルで運用を始めることになってしまった。そして改修や機能追加要望の対応を進めることになってしまった。ということにならないように注意が必要だと思います。


# おわりに
現在はバックエンドをテスト駆動開発で実装しています。
最低限綺麗にコードを実装し、サポートに入ってくれた開発者や引き継いだ開発者が開発しやすいようにしておきたいですね。もちろん自分やチームのためにも。
【React】レンダリングについて学習してみた

# ReactのUIの描画

Reactでは、UI（コンポーネント）が描画（画面に表示）されるまでに以下の3つの工程を経る必要がある。


### 1. レンダーのトリガ
コンポーネントがレンダーされる理由には 2 つ。
- コンポーネントの初回レンダー。

- コンポーネント（またはその祖先のいずれか）の state の更新

### 2. React がコンポーネントをレンダー
コンポーネントがレンダーされる理由には 2 つ。
- 初回レンダー時、React はルート (root) コンポーネントを呼び出す。
- 次回以降のレンダーでは、state の更新によってレンダーがトリガされた関数コンポーネントを、React が呼び出す。

### 3. React が DOM への変更をコミットする
コンポーネントをレンダー（関数として呼び出し）した後、React は DOM を変更する。

- 初回レンダー時には、React は appendChild() DOM API を使用して、作成したすべての DOM ノードを画面に表示する。
- 再レンダー時には、React は最新のレンダー出力に合わせて DOM を変更するため、必要な最小限の操作（レンダー中に計算されたもの）を適用する。

※Reactはレンダリングの差分が発生した場合のみDOMの更新を行う。

```App.js
import React, { useState } from 'react'

const App = () => {
  const [number, setNumber] = useState(0);
  //呼ばれる度にコンソールを出力させてみる
  console.count('レンダリングしました。')
  return (
    <div>
      <button onClick={()=>setNumber((num)=>num + 1)}>+</button>
      <p>{number}</p>
    </div>
  )
}
export default App
```
![無題の動画 ‐ Clipchampで作成 (5).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/96a35e92-8c7c-cf80-152d-34b78443e8f1.gif)

:::note info
**レンダリングはいつ起きる？**
・リロードした時(初回も含む)
・ステートが更新された時

:::


## useEffectについて
```App.js
import React, { useEffect, useState } from 'react'

const App = () => {
  const [number, setNumber] = useState(0);
  
  //呼ばれる度にコンソールを出力させてみる
  useEffect(() => {
    console.count('useEffectです。')
  })
  
  //呼ばれる度にコンソールを出力させてみる
  console.count('レンダリングしました。')
  
  return (
    <div>
      <button onClick={()=>setNumber((num)=>num + 1)}>+</button>
      <p>{number}</p>
    </div>
  )
}
export default App
```

![無題の動画 ‐ Clipchampで作成 (4).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/83ff3d83-0007-96b2-f898-620b8f14b188.gif)

:::note info
**UseEffectはいつ実行される？**
・レンダリングの後に実行される
:::




```App.js
import React, { useEffect, useState } from 'react'

const App = () => {
  const [number, setNumber] = useState(0);
  
  //呼ばれる度にコンソールを出力させてみる
  //第二引数に空文字列を設定してみる(初期値が空の場合のみuseEffectを実行する)
  useEffect(() => {
    console.count('useEffectです。');
  },[]);
  
  //呼ばれる度にコンソールを出力させてみる
  console.count('レンダリングしました。')
  
  return (
    <div>
      <button onClick={()=>setNumber((num)=>num + 1)}>+</button>
      <p>{number}</p>
    </div>
  )
}
export default App

```

![無題の動画 ‐ Clipchampで作成 (6).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/37bea400-0a99-4182-19d5-4c5c9f305df5.gif)



useEffect の依存配列として空の配列 ([]) を渡すことで、useEffect はコンポーネントのマウント時に一度だけ実行される。
その後、依存配列が変化しない限り再実行されない。
ITパスポート 表計算（相対参照と絶対参照）

・ワークシート
表計算ソフトの作業領域
・セル
行と列によって仕切られた各マス目

・算術演算子
加算（+）、減算（-）、乗算（*）、除算（/）、べき乗（^）

・相対参照
複写元を基準として、複写元からどの方向にどれだけ離れているかで、計算式のセル番地が自動調節される
横方向に複写
列のみ自動調節される
縦方向に複写
行のみ自動調節される
両方向に複写
列と行が自動調節される

・絶対参照
列または行の前に「$」を付けると、計算式のセル番地を複写しても自動調節はされず固定される
列の前に「$」
列が固定される
行の前に「$」
行が固定される
列と行の前に「$」
列と行の両方が固定される

・csv
データの各項目がカンマ（,）で区切られた形式
flutter_dotenvを使って.envファイルから環境変数を読み込む

# はじめに
外部に公開したくないAPIキーなどの情報はgit管理の対象から外し、.envファイルに記載した環境変数として使用したいです。



# 環境
Flutter 3.22.1


# パッケージのインストール

flutter_dotenvのインストールします。

```
flutter pub add flutter_dotenv
```

https://pub.dev/packages/flutter_dotenv/install


# envファイルの準備

サンプルとして次のようにSAMPLE_KEYを記載した.envファイルを準備します。

```:.env
SAMPLE_KEY='hello_test_key'
```

# .envファイルをgit管理の対象から外す

```.gitignore
.env
```

# pubspec.yamlの修正

envファイルの記述を追加します。

```yaml:pubspec.yaml
～～～
flutter:
  ～～～
  assets:
    - .env
　～～～
```

# envファイルの読み込み

envファイルから環境変数を読み込みその値をログに出力します。

```dart:main.dart
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';

void main() async {
  // .envファイルの読み込み
  await dotenv.load(fileName: ".env");
  // 環境変数の値をログに出力する
  print('SAMPLE_KEY: ${dotenv.env['SAMPLE_KEY']}');
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flutter Dotenv Example'),
        ),
        body: const Center(
          child: Text('Hello world'),
        ),
      ),
    );
  }
}
```

# 実行結果

プロジェクトを起動すると `print()` で取得した環境変数が出力されている事を確認。

```
I/flutter ～～: SAMPLE_KEY: hello_test_key
```

# 参考

https://pub.dev/packages/flutter_dotenv/example
C++におけるVSCode上の設定メモ

### 目標
Ctrl+Shift+B でコンパイル作業を行い、Ctrl+Shift+R でコンパイルされたファイルを実行できるようにする。


## tasks.jsonの設定
コンパイルや実行の設定
```tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build active file",
            "type": "shell",
            "command": "g++",
            "args": [
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "group": "build",
            "problemMatcher": [
                "$gcc"
            ],
            "detail": "Compiles the active C++ source file and creates an executable."
        },
        {
            "label": "run active file",
            "type": "shell",
            "command": "${fileDirname}/${fileBasenameNoExtension}",
            "group": {
                "kind": "test",
                "isDefault": true
            },
            "problemMatcher": [],
            "detail": "Runs the executable of the active C++ source file."
        },
        {
            "type": "cppbuild",
            "label": "C/C++: gcc アクティブなファイルのビルド",
            "command": "/usr/bin/gcc",
            "args": [
                "-fdiagnostics-color=always",
                "-g",
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "detail": "デバッガーによって生成されたタスク。"
        }
    ]
}
```

## keybindings.jsonの設定
tasks.jsonに記述されたタスクをもとに、Ctrl+Shift+B でコンパイル作業を行い、Ctrl+Shift+R でコンパイルされたファイルを実行する。
```keybindings.json
[
    {
        "key": "ctrl+shift+b",
        "command": "workbench.action.tasks.runTask",
        "args": "build active file"
    },
    {
        "key": "ctrl+shift+r",
        "command": "workbench.action.tasks.runTask",
        "args": "run active file"
    }
]

```
prisma × kyselyを使えるように準備しておく

# 利用するまでの手順
1. 必要なパッケージをインストールする。

    ```bash
    $ npm install prisma --save-dev
    $ npm install @prisma/client
    $ npm install kysely
    ```

2. Prismaの初期設定を行う。
    - プロジェクトディレクトリに`prismaディレクトリ`と`prisma/schema.prisma`が作成される。

    ```bash
    $ npx prisma init
    ```

3. Prismaスキーマの定義を行う。

    ```prisma/schema.prisma
    generator client {
      provider = "prisma-client-js"
    }
    
    generator kysely {
      provider = "prisma-kysely"
      output       = "../src/db"
      fileName     = "types.ts"
      enumFileName = "enums.ts"
    }
    
    datasource db {
      provider = "postgresql"
      url      = env("DATABASE_URL")
    }
    
    model User {
      id    Int    @id @default(autoincrement())
      name  String
      email String @unique
      posts Post[]
    }
    
    model Post {
      id       Int    @id @default(autoincrement())
      title    String
      content  String?
      authorId Int
      author   User   @relation(fields: [authorId], references: [id])
    }
    ```

4. `.env`に環境変数DATABASE_URLを定義する。

    ```.env
    DATABASE_URL="postgresql://user:password@localhost:5432/mydatabase"
    ```

5. マイグレーションを行う。

    ```bash
    $ npx prisma migrate dev --name init
    ```

6. Prismaクライアントを生成する。
    - 型ファイルが生成される。

    ```bash
    $ npx prisma generate
    ```

7. prisma-kyselyの設定を行う。

    ```kysely.ts
    import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
    import { PrismaClient } from '@prisma/client';
    import { Kysely, MysqlDialect } from 'kysely';
    import { createPool } from 'mysql2';
    import { ConfigService } from './config.service';
    import { DB } from './types';
    
    @Injectable()
    export class KyselyService implements OnModuleInit, OnModuleDestroy {
      constructor(private config: ConfigService) {}
    
      private readonly prisma = new PrismaClient();
      private readonly kysely = new Kysely<DB>({
        dialect: new MysqlDialect({
          pool: {
            min: 0,
            max: 10,
          },
        }),
      });
    
      async onModuleInit() {
        await this.prisma.$connect();
      }
    
      async onModuleDestroy() {
        await this.prisma.$disconnect();
      }
    
      getKysely(): Kysely<DB> {
        return this.kysely;
      }
    }
    ```

# 参考
[Kysely | Kysely](https://kysely.dev/)
[TypeScriptのSQLビルダー Kysely をさわってみた](https://zenn.dev/zat/articles/f2670ad0bafab3)
[TypescriptのSQLクエリビルダーのkyselyが快適](https://qiita.com/mont_blanc/items/0564a946b0d6919ad3a0)
[TypeScript用クエリービルダー「Kysely」でトランザクション、UPSERT、JOINを使ってみた](https://qiita.com/kanedaq/items/2202b700533e9ca15f9e)
【Swift】最もシンプルに実行時間を計測する

```swift
let start = Date()
try? await Task.sleep(for: .milliseconds(1234))
let end = -start.timeIntervalSinceNow
print(String(format: "%.3f", end))
// 1.246
```

# 🙆🏻‍♂️ 引用

https://android.benigumo.com/20240622/mesure-execution-time/

https://android.benigumo.com/20240521/common-string-format/
ChatGPT-3.5先生へ「正規表現を教えて下さい。」揖保乃糸4970180611000

**パイソニスタの方へ**
・リスト(表)から正規表現を作るオススメの方法を教えて下さい。

```
^[a-zA-Z]+ -?\d+$
```

# ChatGPT-3.5先生へ(1回目)
User
```
揖保乃糸4970180611000
半田手延べそうめん4904563000011
三輪素麺4902766000417
商品名とJANコードでMarkdown表を作ってください
```
| 商品名               | JANコード       |
|----------------------|-----------------|
| 揖保乃糸             | 4970180611000   |
| 半田手延べそうめん   | 4904563000011   |
| 三輪素麺             | 4902766000417   |


# ChatGPT-3.5先生へ(2回目)
User
```
揖保乃糸4970180611000
半田手延べそうめん4904563000011
三輪素麺4902766000417
商品名とJANコードです。正規表現で表して下さい。
```

# ChatGPT-3.5先生へ(3回目)
User
```
揖保乃糸4970180611000
半田手延べそうめん4904563000011
三輪素麺4902766000417
共通する正規表現で表して下さい。
```
```
商品名もお願いします
```
```
.*\d{13}
```
```
それぞれの商品名とJANコードをカバーできます。
```


# ChatGPT-3.5先生へ(4回目)
User
```
揖保乃糸4970180611000
半田手延べそうめん4904563000011
三輪素麺4902766000417
共通する商品名とJANコードの正規表現で表して下さい。
```
？？？
```
(揖保乃糸|半田手延べそうめん|三輪素麺) (4970180611000|4904563000011|4902766000417)
```

# ChatGPT-3.5先生へ(5回目)
User
```
文字列数字を正規表現で表して下さい。
```

# ChatGPT-3.5先生へ(6回目)
User
```
文字と整数の行を正規表現で表して下さい。
```

```
^[a-zA-Z]+ -?\d+$
```


# 参考

https://qiita.com/mrrclb48z/items/7b75eec56ff947561088

私のコメントより

https://qiita.com/toyokky/items/881e1d55a4a11969ebf3#:~:text=28%2007%3A56-,more_horiz,-%EF%BC%88%E5%8F%82%E8%80%83%EF%BC%89%E8%B3%AA%E5%95%8F%EF%BC%9A%E4%BB%A5%E5%89%8D
Java 16で登場した「recordクラス」について

# 導入

Java 16では新しい言語機能として「レコードクラス」というものが導入されました。
私自身、ほとんどJava8か11のプロジェクトばかりしか触れてこなかったので、きちんと触ったことがなかったのですが、この機能が便利そうでしたので、記事にまとめてみました。
ですので、本記事では、レコードクラスの概要と使用例を紹介していきます。

# レコードクラスの概要
レコードクラスは、簡潔にイミュータブルなデータキャリアを定義するための機能です。
古くから利用されているJavaBeansのようなゲッターのみを持つシンプルなクラスを簡潔に定義できます。

これにより、不要なコード（getterメソッド、`toString()`、`equals()`、`hashCode()`メソッドの定義）の明示的な実装を削減することができ、コードの可読性と保守性が向上します。

## レコードクラスの定義

レコードクラスは、`record`キーワードを使用して定義します。
例は以下のようになります。

```java
record レコードクラス名(型1 引数名1, 型2 引数名2, ...) {}
```

例えば、`Animal`というレコードクラスを作成する場合は、次のようになります。

```java
public record Animal(String species, String habitat, int size) {}
```

これにより、`Animal`クラスは次のようなフィールドを持つイミュータブルクラスとして定義されます。

## レコードクラスを使用した場合と使用しなかった場合の比較

`Animal`クラスを例にして、レコードクラスを使用した場合と使用しなかった場合のコードを比較します。

### レコードクラスを使用した場合
※上記で紹介したものと同じソースです。
レコードクラスを使用すると、`Animal`クラスは次のように簡潔に定義できます。

```java
public record Animal(String species, String habitat, int size) {}
```

### レコードクラスを使用しなかった場合

同じ`Animal`クラスを通常のJavaクラスとして定義すると、次のようなコードになります。

```java
public final class Animal {
    // フィールド
    private final String species;
    private final String habitat;
    private final int size;

    // コンストラクタ
    public Animal(String species, String habitat, int size) {
        this.species = species;
        this.habitat = habitat;
        this.size = size;
    }
    
    // 注: イミュータブル(不変)であるためsetterは存在しません。

    // アクセサメソッド(getter)
    public String species() {
        return species;
    }
    
    public String habitat() {
        return habitat;
    }
    
    public int size() {
        return size;
    }

    @Override
    public String toString() {
        return "Animal [species=" + species + ", habitat=" + habitat + ", size=" + size + "]";
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Animal animal = (Animal) obj;
        return size == animal.size &&
                species.equals(animal.species) &&
                habitat.equals(animal.habitat);
    }

    @Override
    public int hashCode() {
        return Objects.hash(species, habitat, size);
    }
}
```

使用した場合、使用しなかった場合に比べてかなり冗長なコードを削減し、コードの見通しが良くなることが理解できたかと思います。

### メソッドのオーバーライドと追加

レコードクラスでも、`toString()`や`equals()`などのメソッドをオーバーライドしたり、新しいメソッドを追加することができます。

以下の例では、`toString()`メソッドをオーバーライドして出力形式をカスタマイズし、`printInfo()`メソッドを追加しています。

```java
public record Animal(String species, String habitat, int size) {
    @Override
    public String toString() {
        return "[ 種別 => " + species + ", 生息地 => " + habitat + ", 大きさ => " + size + " ]";
    }

    public void printInfo() {
        String message = "この動物は「" + species + "」です。" + habitat + "に生息しており、大きさは" + size + " cm あるとされています。";
        System.out.println(message);
    }
}
```

# 終わりに

Java 16で導入されたレコードクラスは、イミュータブルなデータキャリアを簡潔に定義するための強力な機能です。
レコードクラスは、特にデータの一貫性を保つ必要がある場合や、シンプルなデータ構造を扱う場面で非常に役立ちます。

ぜひこの機能を活用してみてください。
gazeboの初回起動時に真っ暗なままでなかなか起動しないときは、とりあえず待つ

お疲れ様です。秋並です。
<br>  

gazeboを初めて起動するときに、なかなか起動せずに「インストール方法間違ったかな？」となることがあると思いますが、初回起動時はモデルなどのデータを読み込むため起動に時間がかかります。

そのため、**しばらく待って入れば普通に起動する**ので気長に待ちましょう。
<br>

少し厄介なのが、モデルの生成なども同時に行うlaunchファイルをgazeboの初回起動時に実行した場合、モデル生成の**タイムアウトの時間がすぎるとエラーが発生する**ので、余計にインストールを間違えたのかと疑いたくなることがあります。

その場合、初回起動時はモデルが生成されていない状態でgazeboが起動されますが、**再起動すれば、大抵は正しくモデルが生成された状態で起動されます。**

# まとめ
- gazeboの初回起動は時間がかかるのでとりあえず待とう
- 初回起動時にモデルとかがうまく生成されなかった場合は、一度gazeboを終了して再度起動してみよう
C_TS422_2021 SAP Certified Application Associate SAP S/4HANA Production Planning and Manufacturing対策（14/100）

【14日目】
トピック 3：SAPS/4HANAのマスタデータ（3/22）

≪問題14≫
SAPS/4HANAの部品表/配合表（BOM）では、どの代替明細方針を使用できますか。
（２つ選択）
□マニュアル更新
□100%チェック
□即時
□FIFO（先入先出）

≪解答≫
■マニュアル更新
■100%チェック
□即時
□FIFO（先入先出）

≪解説≫
◆代替明細は、次の状況で更新することができます。
（1）使用頻度が指定された代替明細：これらの代替明細は一定の使用頻度を持ちます。グループ内の各代替明細の使用頻度を登録し、所要量計画で従属所要量を設定し、製造指図の入出庫予定に反映させます。
（2）情報としての代替明細：情報目的で代替明細を登録することも可能です（たとえば、部品不足状況でのみ参照される場合など）。この明細に対しては、従属所要量や入出庫予定に使用頻度は生成されません。
◆代替明細に対する方針は、以下の2種類から選択できます。
（1）マニュアル更新（使用頻度別）
（2）100%チェック
[NestJS] ライフサイクルイベントについて理解を深めてみる

# ライフサイクルイベントとは
で起動時や終了時の初期化や終了処理などのことをライフサイクルという。
それらのタイミングで任意の処理をライフサイクルイベントという。
コントローラーや、モジュール、サービスなど基本的にどこでも使うことができます。

# onModuleInit()
## 実行トリガー
モジュールが初期化されたときに呼び出されます。

## 用途
サービス内で必要な初期設定や依存関係の初期化などを行う。

## 実装例

```typescript
import { Injectable, OnModuleInit } from '@nestjs/common';

@Injectable()
export class MyService implements OnModuleInit {
  onModuleInit() {
    console.log('MyServiceが初期化されました');
  }
}
```

# onApplicationBootstrap()
## 実行トリガー
アプリケーション全体がブートストラップされたときに呼び出される。

## 用途
アプリケーションが完全に初期化された後に実行したい処理を定義する。

## 実装例

```typescript
import { OnApplicationBootstrap } from '@nestjs/common';

@Injectable()
export class MyService implements OnApplicationBootstrap {
  onApplicationBootstrap() {
    console.log('アプリケーションがブートストラップされました');
  }
}
```

# onModuleDestroy()
## 実行トリガー
モジュールが破棄されるときに呼び出される。
アプリケーションがシャットダウンされるときに、各モジュールのonModuleDestroyが順次呼び出される。

## 用途
モジュールのクリーンアップ処理を行うために使用する。

## 実装例

```typescript
import { OnModuleDestroy } from '@nestjs/common';

@Injectable()
export class MyService implements OnModuleDestroy {
  onModuleDestroy() {
    console.log('モジュールが破棄されます');
  }
}
```

# beforeApplicationShutdown()
## 実行トリガー
アプリケーションがシャットダウンされる直前に呼び出される。

## 用途
シャットダウン前の最後の処理を実行するために使用する。

## 実装例

```typescript
import { BeforeApplicationShutdown } from '@nestjs/common';

@Injectable()
export class MyService implements BeforeApplicationShutdown {
  beforeApplicationShutdown(signal?: string) {
    console.log(`アプリケーションがシャットダウンされます: ${signal}`);
  }
}
```

# onApplicationShutdown()
## 実行トリガー
アプリケーションがシャットダウンされた後に呼び出される。

## 用途
シャットダウン後の処理を実行するために使用する。

## 実装例

```typescript
import { OnApplicationShutdown } from '@nestjs/common';

@Injectable()
export class MyService implements OnApplicationShutdown {
  onApplicationShutdown(signal?: string) {
    console.log(`アプリケーションがシャットダウンされました: ${signal}`);
  }
}
```


# 参考
[Lifecycle Events](https://docs.nestjs.com/fundamentals/lifecycle-events)
[NestJSのリクエストライフサイクルを理解する](https://blog.shgnkn.io/nestjs-request-lifecycle/)
[fundamentals-lifecycleevents](https://zenn.dev/kisihara_c/books/nest-officialdoc-jp/viewer/fundamentals-lifecycleevents)
いいねしたユーザーの一覧表示

# はじめに
ポートフォリオ制作中です！
いいね数をクリックするといいねしたユーザーの一覧を表示
できるように実装したためアウトプットします✍️

※旅行やデートのプランを共有するアプリなので、投稿機能はPostではなくPlanを使用しています！

# 前提
いいね機能は実装済み、いいねボタンの非同期化済みです
ご留意ください！

# モデル

```plan.rb
class Plan < ApplicationRecord

  # アソシエーション
  belongs_to :user
  has_many :likes, dependent: :destroy
  # この行を追加
  has_many :liked_users, through: :likes, source: :user
  #throughで、likesを通してuserのカラムを使用できる
:
end
```

# ルーティング
```routes.rb
Rails.application.routes.draw do
  scope module: :public do
    resources :plans do
      resource :like, only: [:create, :destroy]
      # 以下を追加
      member do
        get :liked_users
      end
    end
:
end
```

作成されたルーティング↓
```
liked_users_plan GET    /plans/:id/liked_users(.:format) public/plans#liked_users
```

# コントローラー
```plans_controller.rb
class Public::PlansController < ApplicationController
:
  def liked_users
    @plan = Plan.find(params[:id])
    @liked_users = @plan.liked_users
  end
:
end
```

# ビュー

#### いいねボタン修正

いいねカウントのコードに`liked_users_plan_path(plan)`を追加
```_like.html.erb
<% if user_signed_in? %>

  <% if plan.liked_by?(current_user) %>
    <%= link_to plan_like_path(plan), method: :delete, remote: true do %>
      <i class="fa-solid fa-star"></i>
    <% end %>
    <!--リンク追加-->
    <%= link_to plan.likes.count, liked_users_plan_path(plan) %>
  <% else %>
    <%= link_to plan_like_path(plan), method: :post, remote: true do %>
      <i class="fa-regular fa-star"></i>
    <% end %>
    <!--リンク追加-->
    <%= link_to plan.likes.count, liked_users_plan_path(plan) %>
  <% end %>

<% else %>
  <i class="fa-regular fa-star"></i><%= plan.likes.count %>
<% end %>
```

#### いいねしたユーザー一覧作成
user一覧はテンプレートを使用します

```liked_users.html.erb
<%= render 'public/users/index', users: @liked_users %>
```

#### ユーザー一覧のテンプレートの中身
レイアウトの部分は省略しています！

```_index.html.erb
<% if users.present? %>
  <% users.each do |user| %>
    <%= image_tag user.get_profile_image(100, 100) %>
    <%= link_to  user.name, user_path(user) %>
    フォロー：<%= link_to user.followings.count, user_followings_path(user) %>
    フォロワー：<%= link_to user.followers.count, user_followers_path(user) %>
  <% end %>
<% else %>
  ユーザーがいません
<% end %>
```

# さいごに
ポートフォリオ制作も終盤です
細かいところを詰めていけるようがんばります！

# 参照記事
参考にさせていただきました！
ありがとうございます！

https://zenn.dev/goldsaya/articles/026eabf0b4c645
スクラム開発を成功に導く！ユーザーストーリーマッピングの極意

## はじめに

スクラム開発において、ユーザーストーリーマッピングは非常に重要な手法の一つです。ユーザーストーリーマッピングを適切に活用することで、プロダクトの全体像を把握しやすくなり、開発チーム全体の理解を深め、効果的なスプリント計画を立てることができます。本稿では、ユーザーストーリーマッピングの概要、実施方法、その利点について解説します。

## ユーザーストーリーマッピングの概要

ユーザーストーリーマッピングは、プロダクトの全体像を視覚的に把握するためのツールです。具体的には、ユーザーストーリー（ユーザーがプロダクトを使って達成したいこと）を時系列や優先度に沿って配置し、全体の流れや必要な機能を視覚的に整理します。これにより、チーム全体が同じ目標を共有し、プロダクトの開発に集中できます。

## ユーザーストーリーマッピングの実施方法

1. **目標設定**:
   プロダクトの最終目標やユーザーが達成したいことを明確にします。これにより、ユーザーストーリーマッピングの方向性が定まります。

2. **ユーザーストーリーの洗い出し**:
   ユーザーの観点から考え、プロダクトを利用する際の具体的な行動や目的をリストアップします。これにはユーザーペルソナの設定が役立ちます。

3. **ストーリーの配置**:
   洗い出したユーザーストーリーを、時系列や重要度に基づいて配置します。上部にユーザーの大まかな行動（アクティビティ）を配置し、下部に詳細なタスクや機能を配置します。

4. **優先順位の決定**:
   各ユーザーストーリーの優先順位を決定し、どのストーリーを先に実装すべきかを明確にします。これにより、スプリントの計画が立てやすくなります。

5. **フィードバックの収集と改善**:
   ユーザーストーリーマッピングは一度作成して終わりではなく、継続的にフィードバックを収集し、改善していくことが重要です。チーム全体で定期的に見直し、必要に応じて更新します。

## ユーザーストーリーマッピングの利点

1. **視覚的な把握**:
   プロダクト全体の流れや必要な機能を視覚的に把握できるため、チーム全体の理解が深まります。これにより、プロダクトの一貫性を保ちながら開発を進めることができます。

2. **優先順位の明確化**:
   各ユーザーストーリーの優先順位を明確にすることで、スプリント計画が立てやすくなります。また、重要な機能から順に開発を進めることで、ユーザーにとって価値の高いプロダクトを早期に提供することが可能です。

3. **チームの連携強化**:
   ユーザーストーリーマッピングは、チーム全体で議論しながら作成するため、コミュニケーションが活発になります。これにより、チームメンバー間の連携が強化され、一体感が生まれます。

4. **柔軟な対応**:
   開発中に変更が発生した場合でも、ユーザーストーリーマッピングを見直すことで、迅速かつ柔軟に対応することができます。これにより、プロダクトの方向性を大きく逸脱することなく、適応的な開発が可能となります。

## まとめ

ユーザーストーリーマッピングは、スクラム開発において非常に有効な手法です。プロダクトの全体像を視覚的に整理し、チーム全体の理解を深め、スプリント計画を立てる上で大いに役立ちます。適切に実施することで、ユーザーにとって価値の高いプロダクトを効率的に開発することができ、チームの連携も強化されます。継続的なフィードバックと改善を行いながら、効果的なユーザーストーリーマッピングを実現しましょう。
ITパスポート ファイル管理

・階層構造
HDDなどの記憶装置に保存したファイルは、ディレクトリを用いて階層構造で管理されている
階層構造のうち最上位にあるディレクトリが、ルートディレクトリである

・カレントディレクトリ
現在、操作の対象となっているディレクトリ

・ファイルパス
目的のファイルにたどり着くまでの経路
・絶対パス指定
ルートディレクトリから目的のファイルまでの経路
例： /next/index.html
・相対パス指定
カレントディレクトリから目的のファイルまでの経路
カレントディレクトリは、「.」で表す
１階層上のディレクトリは、「..」で表す
例： ../index.html
NestJSで良い感じに例外を捌いていく

# 概要
NestJSで例外処理を実装する際に個人的に良い感じに実装して、フロント側にエラーレスポンスを返す備忘録。

# 手順
1. 例外レスポンス用のInterfaceを用意する。

    ```src/common/exceptions/exception.interface.ts
    export interface Exception {
      statusCode: number
      message: string
      timestamp: Date
      path: string
    }
    ```

2. グローバルで使えるExceptionFilterを実装する。

    ```src/common/exceptions/exception.filter.ts
    import {
      ArgumentsHost,
      Catch,
      ExceptionFilter,
      HttpException,
      HttpStatus,
    } from '@nestjs/common';
    import { Exception } from './exception.interface';
    
    @Catch()
    export class HttpExceptionFilter implements ExceptionFilter {
      catch(exception: HttpException, host: ArgumentsHost): Exception {
        const ctx = host.switchToHttp();
        const response = ctx.getResponse();
        const request = ctx.getRequest();

        const statusCode =
          exception instanceof HttpException
            ? exception.getStatus()
            : HttpStatus.INTERNAL_SERVER_ERROR;
        const message =
          exception instanceof HttpException
            ? exception.getResponse()
            : 'Internal server error'
    
        response
          .status(status)
          .json({
            statusCode: statusCode,
            message: message,
            timestamp: new Date().toISOString(),
            path: request.url
          });
      }
    }
    ```

3. ExceptionFilterをグローバルに適用されるようにする。

    ```src/main.ts
    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';
    import { HttpExceptionFilter } from '../../exceptions/exception.filter';
    
    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
    
      // グローバルフィルターとしてHttpExceptionFilterを適用
      app.useGlobalFilters(new HttpExceptionFilter());
    
      await app.listen(3000);
    }

    bootstrap();
    ```

# 参考
[overview-exceptionfilters](https://zenn.dev/kisihara_c/books/nest-officialdoc-jp/viewer/overview-excepitonfilters)
[NestJS の Exception Filter を使って例外ベースで異常系の処理を行う](https://qiita.com/potato4d/items/350b72746b644d4b8238)
[NestJSのExceptionFiltersでいい感じに例外処理とログ出力を実現する方法](https://zenn.dev/ampersand/articles/9b1623e5860b57)
[【NestJS】例外処理を共通化する方法](https://tsukurue.com/archives/127)
Python for 鬼の100本ノック in range(31, 40)

日記

40【クラスの継承】まで1週目

https://www.youtube.com/watch?v=Gh0qRBHbnVs&t=2392s

疲れたからちょっと休憩

![2024.6.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812230/b17ca9ab-7672-bfc8-64c9-b50bf25c63d4.png)
【初心者向け】VSCodeの便利なショートカット10選

## はじめに
VSCodeの便利なショートカットキーを紹介する記事は既に多く投稿されています。幅広くショートカットキーを網羅している記事も多いので、VSCodeを始めたばかりの方がすぐに開発に取り入れられるよう、ショートカットキーを絞り込んでまとめた記事もあると便利だと考え、本記事を投稿しました。
本記事では、開発にすぐに取り入れられるVSCodeの便利なショートカットキーを10個紹介します。

※本記事でのVSCodeのキー設定はデフォルトのままの設定です。

**開発環境**
・WSL2/Ubuntu環境
・Python: 3.10.12

※WSL2/Ubuntu環境で以下codeコマンドを実行することで、VSCodeを起動しています。

```
code .
```

## VSCodeの便利なショートカットキー10選

#### ①右端での折り返し：「ALT + z 」
1行が長いデータを確認する際に、デフォルトの設定だと右端のデータが隠れてしまうことがありますが、右端での折り返しを行うことで見やすくなります。

#### ②タブ内での検索：「CTRL + f 」
VSCodeのタブの中だけでの単語検索。
正規表現を使用したり、大文字と小文字を区別するなどの複雑な検索にも対応しています。

#### ③タブ内での置換：「CTRL + h 」
VSCodeのタブの中だけでの単語置換。
1つ1つ単語置換を行っていくだけでなく、全て一気に単語置換を行うことにも対応しています。

#### ④ワークスペース全体での検索：「CTRL + SHIFT + f 」
VSCodeのタブではなくワークスペース全体での検索なため、ある関数やデータをどのファイルで使用していたかを特定することなどに使用します。

#### ⑤矩形選択：「ALT + SHIFT + マウス操作でドラッグ」
縦のラインが揃っているデータやプログラムを一気に修正したい場合などに使用します。

#### ⑥タブ内の先頭に移動：「CTRL + HOME 」
マウスのスクロールや十字キーでタブ内の先頭に移動してしまいがちですが、このショートカットキーを使用すると、すぐに先頭に移動出来るので作業が早くなります。

#### ⑦タブ内の末尾に移動：「CTRL + END 」
マウスのスクロールや十字キーでタブ内の末尾に移動してしまいがちですが、このショートカットキーを使用すると、すぐに末尾に移動出来るので作業が早くなります。

#### ⑧ファイルを開く：「CTRL + o 」
「ファイル」メニューから「ファイルを開く」操作も出来ますが、このショートカットキーを使うとより早く作業が出来ます。

#### ⑨コマンドパレットを開く：「CTRL + SHIFT + p 」
VSCodeのリロードなど多様な機能を持つコマンドパレットを、このショートカットキーを使用するとすぐに呼び出せるので便利です。

#### ⑩設定を開く：「CTRL + , 」
設定からsettings.jsonを開く流れはよく使用します。


## おわりに
本記事では、開発にすぐに取り入れられるVSCodeの便利なショートカットキーを10個紹介しました。
本記事の内容が少しでも何かの役に立てば幸いです。

## 参考文献
本記事は以下情報を参考にして執筆しました。

https://qiita.com/12345/items/64f4372fbca041e949d0
WSUSで少し複雑な自動承認

## WSUSで少し複雑な自動承認

WSUSには自動承認機能がありますが、
製品別とかでさらに細かい所までは出来ない。

例えば下記のスクリプトは
Edgeの中のStableチャネルと WebView2 Runtimeを承認して、
他(Devチャネルとか)は承認しない、
みたいな事も出来る。

```powershell
$WSUS = Get-WsusServer
$updates = $WSUS.GetUpdates()
$TgtGrps = $WSUS.GetComputerTargetGroups().where({$_.Name -like 'Group*'}) #対象グループを探す

foreach ($Grp in $TgtGrps){
Write-Host ($Grp.Name+':'+$Grp.Id)
}
foreach($update in ($updates | Where-Object({$_.ProductTitles.Contains('Microsoft Edge') -and $_.IsDeclined -ne $true}))){
    if($update.LegacyName.IndexOf('-Stable-RTM-MicrosoftEdge-') -ge 0 -or $update.LegacyName.IndexOf('-MicrosoftEdge-WV2-Client-') -ge 0){
        Write-Host ($update.Title + 'is approve')
        foreach ($Grp in $TgtGrps){
            $_apprs = $update.GetUpdateApprovals()
            $_appcnt = ($_apprs | ForEach-Object{if(($_.ComputerTargetGroupId -eq $Grp.Id) -and ($_.Action -eq [Microsoft.UpdateServices.Administration.UpdateApprovalAction]::Install)){$_}}).Length
            if($_appcnt -eq 0){
                Write-Output ("「"+($update.Title)+"」を"+$Grp.Name+"に承認しました。")
                $update.Approve([Microsoft.UpdateServices.Administration.UpdateApprovalAction]::Install,$Grp) | Out-Null
            }
        }
    }
}
```
Amazon VPCをIPv6で構成する

VPC内部をIPv6で構成してみたときのメモ
主要なことはIPv6でだいたい完結できるけれども、まだかゆいところに手が届くところまでには至らないと感じた

## Amazon VPCをIPv4で構成する場合との主な違い

- インターネット側からのアクセスをIPv6のみで受け付ける場合、Elastic IPは不要(IPv６アドレスは既にグローバルIPアドレスのため)
- privateサブネットからインターネットとのIPv6通信にはEgress-Onlyインターネットゲートウェイを使用する

## AWSのIPv6対応状況

AWSの中でまだ対応していないサービスや、一部制約のあるサービスがある
対応状況は変化するため、IPv6対応状況の詳細は一次情報を参照
- [IPv6 をサポートする AWS サービス(docs.aws.amazon.com/)](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/aws-ipv6-support.html)
- [IPv6 - IPv6 でアプリケーションのスケールを実現する(aws.amazon.com)](https://aws.amazon.com/jp/vpc/ipv6/)


## 設定ポイント

### VPC作成

- 「VPCの設定」->「IPv6 CIDRブロック」において、「Amazon提供のIPv6 CIDRブロック」を有効にする

### publicサブネット

- 「IPv4 CIDRブロック」にて、「IPv4 CIDRがありません」を有効にする
- 「IPv6 CIDRブロック」にて、「手動入力」を有効にする
- 「IPv6 VPC CIDRブロック」にて、VPCに割り当てられたCIDRブロックを選択する
- 「IPv6サブネットCIDRブロック」にて、VPCに割り当てられたCIDRブロックから、適当に割り当てる

### privateサブネット

- publicサブネットと同様に作成する

### isolatedサブネット

- 他のサブネットと同様に作成する

### インターネットゲートウェイ

- 普通に作る

### Egress-Onlyインターネットゲートウェイ

- privateサブネットから外のインターネットにIPv6でアクセスしたい場合は、NATゲートウェイの代わりにEgress-Onlyインターネットゲートウェイを作成する
- [Egress-Only インターネットゲートウェイを使用してアウトバウンド IPv6 トラフィックを有効にする(docs.aws.amazon.com)](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/egress-only-internet-gateway.html)

### ルートテーブル

#### 1. publicサブネット用のルートテーブル

- 「::/0」宛のターゲットをインターネットゲートウェイに向ける

#### 2. privateサブネット用のルートテーブル

- 「::/0」宛のターゲットをEgress-Onlyインターネットゲートウェイに向ける

#### 3. isolatedサブネット用のルートテーブル

- IPv4の場合と特別な違いはない

### NACL

- IPv4とIPv6とで特別な違いはない

### セキュリティグループ

- IPv4とIPv6とで特別な違いはない

### DNS64/NAT64

- privateサブネットからVPC外のネットワークとIPv4で通信をする場合にはDNS64/NAT64を有効にする
- [DNS64 と NAT64(docs.aws.amazon.com)](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/nat-gateway-nat64-dns64.html)
　
- DNS64を有効にする
    - サブネットの設定から、「アクション」->「サブネットの設定を編集する」で画面遷移し、DNS64を有効にする
　
- NAT64を使う
    - NAT64機能そのものは、NATゲートウェイの機能で、デフォルトで最初から有効になっており、無効にすることはできない
    - NATゲートウェイを、通信したいIPv4ネットワークと疎通できるサブネットに置く
    - IPv6専門のサブネットに関連づけるルートテーブルで、通信対象のIPv4 CIDRブロック宛のルーティング先をNATゲートウェイに向ける

## VPC内に設置するもの

### EC2

- EC2作成時にIPv6アドレスを割り当てることができる

### ロードバランサー

- ロードバランサーのうち、ALBとELBは、IPv6に対応している

### RDS

- RDS作成時にネットワークタイプとして、デュアルスタックモードを有効にし、IPv4とIPv6の両方と通信できるようにする

## その他

### インスタンスメタデータ

インスタンスメタデータのIPv6アドレスは、[fd00:ec2::254]

[インスタンスメタデータの取得(docs.aws.amazon.com/)](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html)

### DNSサーバ

Route 53 ResolverのIPv6アドレスは、[fd00:ec2::253]

### NTP

Amazon Time Sync ServiceのIPv6アドレスは、[fd00:ec2::123]


### CloudFront

クライアントとCloudFrontとの通信はIPv6対応
CloudFrontとオリジンとの通信はIPv4のみ
どっちのtypeof？

:::note
本記事はZennに投稿している記事の再投稿になります。
https://zenn.dev/axoloto210/articles/advent-calender-2023-day16
:::
## 2種類の`typeof`
値の型情報を取得するための演算子として`typeof`という演算子があります。この`typeof`にはJavaScriptで使用されている`typeof`とTypeScriptの型演算子としての`typeof`があります。
## JavaScriptの`typeof`演算子
JavaScriptにおける`typeof`演算子は、値の型を文字列で返す演算子です。
JavaScriptの型について、`typeof`は以下のような値を返します。
| Type | `typeof`の返り値 |
| ---- | ---- |
| Null | `"object"`|
| Undifined | `"undefined"` |
| Boolean | `"boolean"` |
| Number | `"number"` |
| String | `"string"` |
| Bigint | `"bigint"` |
| Symbol | `"symbol"` |
| 関数オブジェクト | `"function"` |
| その他のオブジェクト | `"object"` |

以下のコードのようにオブジェクトの型をプロパティを含めて詳しく見たいと思っても、`"object"`しか返ってきません。これは、JavaScriptの`typeof`演算子が文字列を返しているからというわけですね。
```ts
const obj = {
  num: 1,
  str: 'one'
}

console.log(typeof obj)// "object" 
```
`typeof`は`null`に対しても`"object"`を返すという点にも注意が必要です。
```ts
console.log(typeof {num: 1} === typeof null) //true 
```
この挙動はJavaScriptのバグなのですが、`"null"`を返すよう修正を行なってしまうと既存のコードが破壊されることが懸念されるため、修正はされない方針となっているようです。
>In JavaScript, typeof null is 'object', which incorrectly suggests that null is an object (it isn’t, it’s a primitive value, consult my blog post on categorizing values for details). This is a bug and one that unfortunately can’t be fixed, because it would break existing code. Let’s explore the history of this bug.

https://2ality.com/2013/10/typeof-null.html

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof#typeof_null

## TypeScriptの`typeof`型演算子
TypeScriptにも値の型情報を得るための演算子として`typeof`があります。
こちらは`typeof`型演算子（Typeof Type Operator）と呼ばれ、`typeof`演算子と区別されています。

https://www.typescriptlang.org/docs/handbook/2/typeof-types.html
```ts
const obj : {
  num: number
  str: string
} = {num: 1, str: 'one'}

// type T = {
//     num: number;
//     str: string;
// }
type T = typeof obj

//const t: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
const t = typeof obj
```
このコード例では、型`T`はオブジェクトのプロパティを含めて詳細な型情報を`typeof`型演算子で取得できています。
一方、`typeof`演算子によって`obj`の型に関する文字列を代入されている変数`t`は`typeof`演算子が返しうる文字列のユニオン型であると型推論がされています。
`typeof obj`がどのような文字列を返すかはJavaScriptの`typeof`が実行されるまでわからないため、このような型推論がされているわけですね。
## `typeof`演算子と`typeof`型演算子の見分け方
同じ綴りの演算子があると混乱してしまいそうですが、`typeof`型演算子はリテラル型の`"foo"`や`123`と同様に、型注釈などの型を記述する場面でのみ使用することが可能ですので、どこに記述されているかに着目することで見分けられます。
```ts
const obj = {str: 'foo'}

//const obj2: { str: string; }
const obj2: typeof obj = {str: typeof obj}

console.log(obj2.str) //"object" 
```
上のコード例で出てくる1つ目の`typeof`は型注釈として使用されていますので、型演算子の方の`typeof`であるとわかります。
2つ目の`typeof`については、オブジェクトリテラルに含まれる`str`プロパティの値として記述されていますので、`typeof`演算子の方であるとわかります。
TypeScriptには`typeof`の他にもリテラル型など、JavaScriptでは別の意味をもつが同じ書き方がされる機能がいくつかあります。
どちらの機能なのかわからなくなった時には、記述位置が型が期待される箇所なのか、値が期待される箇所なのかを考えてみると見分けがつくはずです。
文字列はプリミティブ値なのにlengthプロパティをもつ？

:::note
本記事はZennに投稿している記事の再投稿になります。
https://zenn.dev/axoloto210/articles/advent-calender-2023-day03
:::
## 文字列がもつ`length`プロパティ

文字列に含まれる文字数を取得したいとき、`length`プロパティにアクセスすることで取得することができます。

```ts
const str = "foobarbaz";
console.log(str.length); //9
```


文字列はプリミティブな値なので、プロパティを持たないはず。
しかし`length`プロパティを参照できているのは、一時的にオブジェクトが作成されて、そのオブジェクトが持つプロパティを参照しているためです。

> 文字列プリミティブに対してメソッドを呼び出したり、プロパティを参照したりするコンテキストでは、JavaScript は自動的に文字列プリミティブをラップし、ラッパーオブジェクトに対してメソッドを呼び出したり、プロパティを参照したりします。

 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String

## `length` プロパティと型

文字列が`length`というプロパティを実質的にもっているような記述となるため、TypeScript では`{length: number}`など、Stringのプロパティやメソッドのみをもつ型のオブジェクトに文字列を代入してもコンパイルエラーが発生しないようになっています。

```ts
type T = { length: number; includes: (searchString: string) => boolean };
const obj: T = "foobarbaz"; //コンパイルエラーは発生しない
```
```length```の型がStringオブジェクトの持つ```length```の型と一致しない場合などにはコンパイルエラーを出してくれます。
```ts
type U = { length: string; includes: (searchString: number) => boolean };
const obj2: U = 'foobarbaz' //Type 'string' is not assignable to type 'U'.2322)
```
## `{}`型
文字列が```{length: number}```型のオブジェクトに代入可能であることから、部分型である```{}```型のオブジェクトにも代入可能です。
```ts
const obj:{} = 'foobarbaz' //コンパイルエラーは発生しない
```

`{}`は、`null`と`undefined`以外の値は全て代入可能な型となっています。
```ts
const obj:{} = 234
const obj2:{} = false
const obj3:{} = Symbol
const obj4:{} = undefined  //Type 'undefined' is not assignable to type '{}'.(2322)
const obj5:{} = null       //Type 'null' is not assignable to type '{}'.(2322)

const obj6:{} = Math.random() > 0.5 ? 1 : undefined
//Type 'number | undefined' is not assignable to type '{}'.
//Type 'undefined' is not assignable to type '{}'.(2322)
```

## サロゲートペア文字に注意
`length`プロパティは文字数をあらわしているのではなく、コードユニットの数をあらわしています。
そのため、サロゲートペア文字（𩸽や𠮷）は長さ2としてカウントされてしまいます。（もっと大きな数値でカウントされる文字も存在します👨‍👩‍👧‍👧）
文字列を一度スプレッド構文で配列に入れてから配列の要素数を数えることで、見た目の文字数を数えることができます（スプレッド構文はコードポイントごとに文字列を分けてくれます）。
```ts
const str = '𩸽と𠮷'
console.log(str.length) //5
console.log([...str].length) //3

console.log([...str]) //["𩸽", "と", "𠮷"] 
```

この方法でも絵文字などは直感に反する数値が返ってくるのでご注意を。
```ts
console.log([...'👨‍👩‍👧‍👧']) //["👨", "‍", "👩", "‍", "👧", "‍", "👧"] 
console.log([...'👨‍👩‍👧‍👧'].length) //7
```
4人と数えられるわけでもないんですね。👨👩👧👧
storybookを使ってinput(text)タグをテストしてみた

# はじめに
初めまして！
エンジニアになって数年、今まで本を読むだけでしたが、もっとプライベートで楽しみながら成長したい！自分が学んだ足跡を残していきたい！と思い記事を書きました！
最終的には自在に開発できるようになりたいと思っています。:triumph:
いろいろな記事を参考にさせてもらっています。:bow_tone2:

**「いいね」か「ブックマーク」**
を頂けると僕のモチベーションアップになります！:thumbsup:
少しでも気に入っていただけたらよろしくお願いいたします！:thumbsup:

# 今回の目的
storybookでUIテストをしたかった中でhoverのようなイベントでスタイルが適用されているか？を確認したかったため

# バージョン
React:18
storybook: 8.1.10

# ボタンの作りについて
単純なtextを作成しました。最大７文字まで入力できます。

```jsx
...
<input
  type="text"
  data-testid='text'
  maxLength={7}
/>
...
```

# テストはこちら
storiesファイルはこちらです。
7桁までで入力されているかテストしています。
```tsx
export const Default: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    await userEvent.type(canvas.getByTestId('text'),'12345678');
    await expect(canvas.getByTestId('text')).toHaveValue('1234567');
  },
};
````

# 結果はこちら
![スクリーンショット 2024-06-22 18.04.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/943982/85ef2536-6ca1-33d1-ca2b-54b4884b39f5.png)


# 参考
expect

https://github.com/testing-library/jest-dom

userEvent

https://testing-library.com/docs/user-event/v13

# 最後に
閲覧いただきありがとうございました！