OmniAICreator/Qiita-1.07M huggingface dataset:
アニメーションの特定フレームの状態に追加パーツを追従させる

３Dのアニメーションを作っていて
カットの途中からの破損等で「このフレームから既存のオブジェクトに追加部分が追従してほしい」といったことはないでしょうか？

これまでも ある程度は可能でしたが、ジオメトリノードで比較的扱いやすい状態にできたので書き残しておきたいと思います。
![24031901.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/26a67375-e6b0-2f29-62b3-f0145d50f836.gif)
今回はこのモデルを使用します
レストポーズは左側に映っているモデルのような状態で
選択オブジェクトが脚の動きに追従させている追加パーツで　動画の15フレームの脚の位置でメッシュを作成しています。
## ベイクノード
まずはベイクノードについて触れておきます。
「ベイク」ノードは　Blender 4.1から搭載された機能です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/e98b7a7d-b87a-a072-c1bf-e81e4b94f272.png)
追加＞ジオメトリ＞処理＞ベイクから追加できるノードで

.blendファイルを保存した状態でノード上の「ベイク」のボタンを押すと
ノードに入力されているジオメトリの情報が ファイルと同一パスに保存されるようです。
（blendcache_bakenode というフォルダが自動生成されましたが"_"の後ろ側は.blendファイル名です）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/062922cb-6891-b147-e187-c58273793821.png)
一旦保存したジオメトリの情報は　ファイルを開きなおしても利用されます。
つまり特定のフレームの変形状態を再利用可能な状態で保存しておけるということです。

## ノードとベイク
今回のノードの設定です　ベイク設定前の状態でベイクを行うのとは別のフレームの状態で表示しています
モディファイアパネルで指定しているのが　動きを取得するオブジェクトです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/ec1daa3d-a0e6-e120-b140-6007f970e4c1.png)
少ないノードですが
- ベイクしたジオメトリの頂点IDを元に　動きを取得したいオブジェクトの頂点の現在位置を取得
- ベイクデータのジオメトリに「diff」の名前付き属性で頂点の移動量を格納
- 最近接表面サンプルで変形するオブジェクトの移動量を取得して移動

という手順を踏んでいます
後は目的のフレームに現在のフレームを移動した後　ベイクのノードの　ベイクボタンを押すだけです
![24032101.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/a7ba4c3c-b174-3217-709b-c45aeb65de15.gif)
有機的な形状でもある程度利用できるようです

:::note
このままではシーンの中でしか利用できませんが
一旦アニメーションを付けているオブジェクトをレスト位置に持って行ってジオメトリノードのモディファイアを適用してしてしまえば
他で再利用可能な状態に再セットアップも可能かと思います
:::

## Bleder 3.3での場合
実はこの手法自体は　ベイクのノードは必須ではなく
過去のバージョンのジオメトリーノードでも利用可能です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/88e87dff-f2f0-3ed5-d53a-2768173adcb7.png)
ただし　ベイクデータから計算していた移動量を他の方法で取得する必要があります
移動対象のオブジェクトを複製して　移動に関わるモディファイアを適用してしまえば　同様のデータは作れます
ただし　複製オブジェクトをレンダリング対象外にしたりと色々手間がかかります。

::: note
いずれの場合も　頂点のIDを元に移動を計算しているので
調点数が変わってしまうようなモディファイアを使っている場合には利用できない手法なのも注意が必要です
:::
データ解析用ライブラリ

# はじめに
皆さん、データ解析やデータ処理にどのライブラリを使用していますか？
恐らく、ほとんどの人が`pandas`を使用していると思います。
今回は、その他のデータ解析用ライブラリやデータ処理ライブラリについて紹介したいと思います(/・ω・)/

# Pandas
言わずと知れたデータ解析用ライブラリですね。
データフレームとシリーズという2つの主要なデータ構造が提供されており、データの読み込みやフィルタリングなど、様々なデータ解析/処理に適しています。
中小規模のデータセットに適しており、大規模なデータの処理はメモリ不足や処理速度の問題からあまり向いていません。

# Numpy
こちらも言わずと知れたライブラリです。
高速な多次元配列の処理とベクトル化演算のためのライブラリであり、配列の生成やブロードキャスティングなどの多彩な操作を提供しています。
線形代数や乱数生成、フーリエ変換などの科学技術計算に必要な機能も備えており、`Pandas`を含む多くの化学計算ライブラリの基盤となっています。

# Dask
大規模のデータセットにを並列処理するためのライブラリです。
`Pandas`と似たデータフレームのAPIを提供しており、既存の`Pandas`のコードを最小限の変更で分散処理することができます。
データを複数のチャンクに分割し、クラスターやマルチコアCPUで並列処理を行い、メモリに収まらない大規模なデータセットを処理することができます。
スケジューラを用いて並列処理を管理するそうです。

# Polars
よく`Pandas`と比較されるライブラリですね。
Rust言語で書かれているため、かなり早いとの噂です。
遅延評価とベクトル化演算を利用して、メモリ効率とCPU使用率を最適化しています。
比較的新しいライブラリなので、`Pandas`ほどの機能はありませんが、十分実用的なライブラリだと思います。
以下に100本ノックの記事を参照しておきますので興味のある方は是非！

https://qiita.com/_jinta/items/28442d25bba067c13bb7

https://qiita.com/_jinta/items/394b1682893e5991d592

https://qiita.com/kunishou/items/1386d14a136f585e504e

# Vaex
こちらも大規模なデータセットを高速に処理するためのライブラリです。
データをメモリにロードせず、遅延評価とアウトオブコア処理を使用しているようです。
可視化機能も備えており、大規模なデータセットを対話的に探索することができるそうです。
また、GPUアクセラレーションをサポートしているとのこと。

# Xarray
ラベル付きの多次元配列を処理するためのライブラリです。
NetCDF、HDF5、Zarr、OPeNDAPなどの多次元データフォーマットを読み書きすることができます。
`Pandas`のデータフレームと似た操作が可能で、データの結合、グループ化、リサンプリングなどができます。
気象学や海洋学、地球科学などの分野で使用されることが多いようですね。

# Bottleneck
`Numpy`の配列操作を高速化するためのライブラリです。
`Cython`で実装された高速な関数を提供することで高速化を図っています。
欠損値を含む配列の集約操作に特に効果的で、移動窓関数（または窓関数）も提供しています。

# PyTables
HDF5ファイルフォーマットを使用した階層的なデータセットの管理ライブラリです。
大規模な多次元配列や表形式データ、時系列データなどを効率的に保存・読み込みできます。
`Numpy`や`Pandas`と緊密に結合されており、高速なI/Oが可能です。
データの圧縮やチャンク化、クエリなどの多彩な機能を提供しています。

# Blaze
大規模データの処理と分析のためのライブラリです。
`Numpy`や`Pandas`と似たインターフェースを提供し、分散コンピューティングにも対応しています。
CSV、JSON、HDF5、SQLなど様々なデータソースを抽象化し、同じAPIで扱うことができます。
`Dask`をバックエンドとして使用し、並列処理と分散処理を実現します。

# Numba
`Numpy`とPythonコードを高速化するJITコンパイラです。
でこれーたを使用して関数を最適化し、C言語に匹敵する速度を実現します。
CPUとGPUのどちらでも動作し、並列処理もサポートしています。
数行追加するだけで高速処理が可能なので個人的にかなり推しています！

# Swifter
`Python`のデータフレームに対する処理を高速化するためのライブラリです。
`apply`、`applymap`、`map`などの関数は大規模なデータセットに対して適用する際に非常に遅くなることがありますが、`swifter`はこれらの関数の処理を自動的に最適化し、コードの変更を最小限に抑えながら、処理速度を大幅に向上させることができます。
また、処理をマルチスレッドまたはマルチプロセスで並列化し、CPUリソースを最大限に利用しています。
ベクトル化演算やチャンク処理にも対応しています。

# Modin
`Pandas`と互換性のある高速なデータ処理ライブラリです。
`Pandas`のAPIを維持しながら、並列処理とデータ分割を利用してパフォーマンスを大幅に向上させています。
また、バックエンドを選択することができ、`Pandas`の他にも、`Dask`や`Ray`を選択することもできます。

# まとめ
いかがだったでしょうか。
私の知る限りのデータ解析用ライブラリでした。
個人的には`Polars`、`Numba`、`Swifter`あたりの学習を進めようと思っていますね！
皆様の参考になれば幸いです！
また良さげなライブラリがあれば紹介したいと思います(/・ω・)/
それでは！
docker-minecraft-bedrock-server のバージョンを1.20.62に戻す方法

2024/03/20現在、Minecraft 統合版 1.20.70/71 の不具合でクライアントのアップデートが停止されていますが、 https://github.com/itzg/docker-minecraft-bedrock-server を使ってホストしているサーバ側がアップデートされてしまい、バージョン不一致でプレイできなくなってしまったため、サーバ側のバージョンを戻す方法を共有しておきます。

ドキュメントの通り、Environment Variablesの `VERSION` を指定してあげればよいのですが、 `1.20.62` だけでは不十分で、 `1.20.62.03` まで指定する必要があります。

compose.yml例

```
version: '3.4'

services:
  bds:
    container_name: bds
    restart: always
    image: itzg/minecraft-bedrock-server
    environment:
      EULA: "TRUE"
      VERSION: "1.20.62.03"
(略)
```

ちなみに、この1.20.62の最新バージョンの情報が見つけられなかったため、ダウンロードURLを総当たりすることで調べました。
[Azure]AZ-104***不***合格体験記

# はじめに
どうも、SobaNyakuです。蕎麦と蒟蒻が大好きです。
なんとなんと、AZ-104落ちました。ちょっと予想外でしたが、仕方ありません。
反省会を始めます。


# 結果発表
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3659255/2c14c196-2455-5828-eda0-8f6e35ecf73c.png)

低すぎる。というか、どのセクションでも7割いってないんだが。。。


# 反省会
以下は持っているのと、AZ-900が簡単に取得できたので、完全に油断していました。
* SAA([AWS Certified Solutions Architect - Associate](https://aws.amazon.com/jp/certification/certified-solutions-architect-associate/))
* SAP([AWS Certified Solutions Architect - Professional](https://aws.amazon.com/jp/certification/certified-solutions-architect-professional/))
* Azure Fundamentals([AZ-900](https://learn.microsoft.com/ja-jp/credentials/certifications/exams/az-900/))

https://qiita.com/SobaNyaku/items/c21c4fd5e89b92f8221f#%E5%89%8D%E6%8F%90

次はしっかり勉強して挑みます。

# 次に向けて
### 1. プラクティス評価を受けます

これは受けるべき。そして、不明点を調べる。

https://learn.microsoft.com/ja-jp/credentials/certifications/practice-assessments-for-microsoft-certifications

### 2.Learn の AZ-104 試験準備ビデオを視聴する
試験準備ビデオが存在する。
AZ-104 は5 つあるので、視聴する。

https://learn.microsoft.com/ja-jp/shows/exam-readiness-zone/preparing-for-az-104-manage-azure-identities-and-governance-1-of-5

### 3. 予約
1,2が終わったら、試験日を予約する

### 4. 再受験の準備で優先すべきスキル領域トップ 3 を勉強する
ScoreReport をよく見ると、以下のように書いてあります。定型文しか書いてないと思ったら、色々ヒントくれているのでよく見た方がいいです。
>スキル習得の優先順位を決める際に、この情報をご活用ください。この一覧では、この試験に合格するため
に改善が必要なスキルすべてを提示するのではなく、3 つのスキルのみを記載しています。以下は、試験で最も成績の低かったスキル領域です。この 3 スキルは、最もスキルの向上を期待でき、試験全体の成績向上につながる可能性があるものです。
>* ストレージ アカウントを構成および管理する
>* Azure Files と Azure Blob Storage を構成する
>* Azure で仮想ネットワークを構成および管理する

### 5. あとは試験日ぎりぎりまでラーニング パスを受講する

https://learn.microsoft.com/ja-jp/credentials/certifications/exams/az-104/#two-ways-to-prepare


これでいけるだろう。次は合格体験記でお会いしましょう！！
やるぞーーー

# おわりに
最後まで見ていただき、ありがとうございます。
少しでも読んでいただいた方の役に立てたら幸いです。
よかったらチャンネル登録（フォロー）、高評価（いいね:heart_decoration:）、コメント:pen_fountain:などなど何でもお願いします:pray:

週一で投稿目指しています。もし何かリアクションをしてくれるとやる気が出るので、次週は投稿することを約束します。今のところ約束は履行されています（投稿なかった週はリアクションが前週になかったのだからと正当化して休んでます:grimacing:）
スニペットで超効率的にコードを書く方法【VSCode】

## タイピングが面倒ならスニペット
スニペットとは、**自分でカスタマイズ** できるショートカットのようなもの。

例えば、cと打ったら `console.log();` が表示される、ということができる。

ファイルの種類ごとに管理できるので、上の例だと c と打ったときにPythonだと `cv2` と表示させたいということもできる。



## 普段使っているスニペットを紹介
僕がVSCodeで使っているスニペットを紹介します。

ちなみにスニペットのjsonファイルを呼び出すには、以下のようにすればよい。
- `command` + `^control` + `p` でEnter
- 呼び出したい言語 (pythonなど) を選択するか入力する

![snippet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899381/af9e9360-8495-f33a-3018-d086ee56c003.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899381/87b3a9f6-a862-51f4-0742-775bd7560168.png)


### JavaScript
```json
"Print to console": {
	"prefix": "c",
	"body": [
		"console.log($1);",
	],
	"description": "Log output to console"
}
```

JavaScriptの基本言語サポートに`log`って打ったら候補として`console.log`が出てくるのですが、logと３文字打って、候補を選ぶために下矢印押して、Enterって5回作業あります。
しかも、下矢印は難易度高くてすぐ打てない。

だから、上の方法で `c` 打ってEnterで2回の作業で出るようにしています。

### HTML

```json
	"<link rel=\"stylesheet\" href=\"css/reset.css\">": {
		"prefix": "css",
		"body": [
			"<link rel=\"stylesheet\" href=\"css/reset.css\">",
    		"<link rel=\"stylesheet\" href=\"css/style.css\">"
		],
		"description": "link css"
	}
```

これは、HTMLの< head >タグの中に毎回CSSを組み込むリンクを書くのが面倒だと思ったので作りました。

全体のフォーマットはデフォルトのEmmet (スニペットみたいな楽できるやつ) で `!` を打ってEnterで表示できます。

HTMLでテンプレが決まっている人は全体をスニペットにして一発でテンプレが出せるようにするのもいいかもしれません。



### Python

業務ではありませんが、競プロの時短のために、入力でint型の `input()` と `map()` がすぐ出るようにしています。 
```json
	"n = int(input())": {
		"prefix": "n=i",
		"body": [
			"n = int(input())",
			"$2"
		],
		"description": "n=int"
	}
```

```json
	"map(int, input().split())": {
		"prefix": "map(",
		"body": [
			"map(int, input().split())",
			"$2"
		],
		"description": "map int"
	}
```

## スニペット生成に便利なサイト

スニペットを作るときは大体これを使ってる。このサイトはとても便利です。


https://migi.me/vsc_snippet/



## 最後に

誰かの役に立ったら嬉しいです。
もっと便利になる方法あったらぜひ教えてください。
pyenvでPythonのversion切り替えをする方法 (M1 Mac)


まず、現在のバージョンを確認する。
```
python --version
```

次に、pyenvを用いてインストール可能なバージョンを確認。
```
pyenv install --list
```
pyenvがそもそも入っていない場合は以下の方法でインストールする。
```
brew install pyenv
```

インストール可能なバージョンから選び、インストール。
```
pyenv install 3.7.2
```

pythonのバージョンを変更。
```
pyenv global 3.7.2
```

さらに以下のコマンドで情報を更新。
```
eval "$(pyenv init -)"
```

pythonのバージョンが更新されていることを確認。
```
python --version
```


## 参考記事

https://qiita.com/Kohey222/items/19eb9b3cbcec9b176625

https://yu-nix.com/archives/python-change-version/
Raspberry Pi 4のファン(PoE+ HAT)がうるさいので閾値を調節した

:::note info
[こちらの記事](https://zenn.dev/matoruru/scraps/97ad8c96a50c81)で作っているおうちKubernetesのRaspberry Piに設定を加えていきます。
:::

## 環境

**機器**
- Raspberry Pi 4 Model B
- PoE+ HAT

**OS**

- Ubuntu Server 22.04.3

## ファンの動作音について

PoE+ HATのファンの動作には5段階あり、

1. 停止
1. 起動 (poe_fan_temp0)
1. 速く回転 (poe_fan_temp1)
1. さらに速く回転 (poe_fan_temp2)
1. 最高速で回転 (poe_fan_temp3)

の順でCPUの温度に応じて推移していきます。

私の聴力ではpoe_fan_temp2のあたりから音が聞こえ始め、poe_fan_temp3ではとても耳障りになります。

## デフォルト設定

40度でファンが起動し、55度で最高速になります。

冬に電源を入れただけでも45度前後にはなっているため、適当に`yes`コマンドでも実行すれば即座に最高速で回りだします。

## おすすめ設定

:::note warn
冷却ファンの動作を制限するため、CPUやボードの温度が高くなります。これはパフォーマンスへの影響や**寿命を縮める**ことにつながる可能性があります。本設定を適用する際は自己責任で実施ください
:::

設定ファイルは`/boot/firmware/config.txt`にあります。編集にはルート権限が必要なため`sudo vim`などで開きましょう。

以下の設定を追記します。

```:/boot/firmware/config.txt
dtoverlay=rpi-poe-plus
dtparam=poe_fan_temp0=60000,poe_fan_temp0_hyst=2000
dtparam=poe_fan_temp1=70000,poe_fan_temp1_hyst=2000
dtparam=poe_fan_temp2=80000,poe_fan_temp2_hyst=2000
dtparam=poe_fan_temp3=85000,poe_fan_temp3_hyst=5000
```

再起動して完了です。

```
sudo reboot
```

動作音が静かになっていることに気づいたら成功です！

## CPU温度の確認方法

`sensors`コマンドで確認できます。

```
> sensors
cpu_thermal-virtual-0
Adapter: Virtual device
temp1:        +78.9°C
```

`sensors`コマンドが見つからなければ`sudo apt install lm-sensors`でインストールしてください。

## まとめ

静かで快適なラズパイライフを！

## 参考

- デフォルト設定 https://github.com/raspberrypi/firmware/blob/40ac9ca411ba2a0947061712a379a43579a33c0c/boot/overlays/README#L3950-L3970
Cisco ルーター基本コマンド01

## 作業内容
1. ルーターのホスト名を設定する
1. IPアドレスを設定する
1. インターフェースを有効化する

### 基本コマンド　初期設定
```bash
##特権モードへの移行
Router>enable

##グローバルコンフィギュレーションモードへ移行
Router#configure terminal 

##ルータのホスト名登録
Router(config)#hostname hoge-router

##インターフェースコンフィギュレーションモードへ移行
hoge-router(config)#interface fastEthernet 0/0

##IPアドレスの登録
hoge-router(config-if)#ip address 192.xxx.xxx.1 255.255.255.0 

##インターフェースの有効化、デフォルトはshutodown状態（無効）
hoge-router(config-if)#no shutdown 

##特権モードへ移行
hoge-router(config-if)#exit
hoge-router(config)#exit

##設定内容の表示、変更点の確認
hoge-router#show running-config
```


### 変更前-確認コマンド結果
```bash

hoge-router#show running-config 
Building configuration...
(省略)
!
hostname hoge-router
!
(省略)
!
interface FastEthernet0/0
 no ip address
 duplex auto
 speed auto
 shutdown
!
(省略)
end
```


### 変更後-確認コマンド結果
変更された点
- IPアドレスが設定された
- shutdown の表示が消えた

```bash

hoge-router#show running-config 
Building configuration...
(省略)
!
hostname hoge-router
!
(省略)
!
interface FastEthernet0/0
 ip address 192.168.1.1 255.255.255.0
 duplex auto
 speed auto
!
(省略)
end
```
AWS勉強備忘録13 - S3

Amazon S3は、AWSが提供するオブジェクトストレージサービスです。これは、インターネット上で大量のデータを保存、取得するための耐久性に優れたプラットフォームを提供します。S3は「Simple Storage Service」の略で、その名の通りシンプルで強力なデータストレージソリューションを提供します。

## オブジェクトストレージサービスとは

オブジェクトストレージサービスは、データをファイルとしてではなく、オブジェクトとして管理します。各オブジェクトにはデータ本体、メタデータ、グローバルにユニークなIDが含まれます。この設計により、スケーラビリティと管理のしやすさが大幅に向上します。

## S3の特徴と主な機能

### WEBサーバー機能

S3は静的コンテンツのホスティングに利用でき、HTML、CSS、JavaScriptファイルなどを直接S3バケットに保存して、ウェブサイトとして公開することができます。EC2インスタンスをWebサーバーとして利用することも可能ですが、S3を使用することで、サーバーの管理やスケーリングの手間を省くことができます。

### クエリ機能

S3 SelectやAmazon Athenaの使用により、S3に保存されたデータに対して直接クエリを実行できます（CSVやJSONのような構造化されたテキスト形式のデータに対してSQLのSELECT文を実行可能）。これにより、大規模なデータセットから必要なデータのみを効率的に抽出し、アプリケーションのパフォーマンス、データの抽出・分析のパフォーマンスを向上させることができます。

## S3の主要な利点

### スケーラビリティ

S3は自動的にスケールし、どんな量のデータも保存できます。ユーザーはストレージ容量を気にすることなく、任意の量のデータをS3に保存できます。

### 可用性と耐久性

[可用性](https://ja.wikipedia.org/wiki/%E5%8F%AF%E7%94%A8%E6%80%A7)は、システムが稼働し続ける能力を意味し、S3は99.99%の稼働率を保証しています。耐久性は、データが失われるリスクを低減する能力を指し、S3は99.999999999%（11 9's）の耐久性を提供します。

### 信頼性

AWSの広範なインフラストラクチャにより、S3は高い信頼性を持っています。データは複数の物理的なロケーションに自動的に複製されるため、災害時でもデータの安全性が確保されます。

### 管理機能とインテリジェントな機能

S3は、ストレージクラス分析、ライフサイクルポリシー設定など、豊富なデータ管理機能を提供します。

### AWS Lambdaとの連携

S3とAWS Lambdaの連携により、データがS3にアップロードされた際に自動的にコードが実行されるイベント駆動型のアーキテクチャを構築できます

## 補足1: RailsアプリをAWSデプロイする場合
Railsで開発されたアプリケーションをデプロイする際には、一般的にAmazon EC2（Elastic Compute Cloud）がよく利用される。EC2インスタンス上でRailsアプリケーションを実行することにより、アプリケーションのサーバーサイドのロジックを処理し、ユーザーリクエストに応じて動的なコンテンツを生成して提供できます。

一方、Amazon S3（Simple Storage Service）は、オブジェクトストレージサービスであり、静的ファイルやメディアファイル、バックアップなど、大量のデータを保存・配信するために設計されています。S3はデータベースとしては使用されず、主に静的コンテンツのホスティングやデータのバックアップ、アーカイブ用途に適しています。

したがって、Railsアプリケーションのデプロイにおいて、EC2はアプリケーションの実行環境として、S3は静的アセット（画像、CSSファイル、JavaScriptファイルなど）の保存や配信、バックアップの保管場所としてそれぞれ異なる役割を担います。

データベースについては、Railsアプリケーションでは通常、Amazon RDS（Relational Database Service）やAmazon DynamoDBのようなAWSのマネージドデータベースサービス、またはEC2インスタンス上に自らデータベースサーバー（例：PostgreSQL、MySQL）を設定して使用することが一般的です。これらのデータベースサービスは、アプリケーションのデータを管理し、高いパフォーマンスとスケーラビリティ、簡単な管理を提供します。

## 補足2: EC2上にPostgreSQLを設置する場合と、Amazon RDSを使用する場合の比較

### EC2上のPostgreSQLのスケーラビリティ

EC2インスタンス上に直接PostgreSQLを設置する場合、スケーラビリティの管理は全て手動で行う必要があります。これには、インスタンスのサイズ変更、レプリケーションの設定、ロードバランサーの設定、バックアップの管理などが含まれます。データベースが成長するにつれて、これらの作業はより複雑になり、運用の負担が増大します。自動スケーリングの設定や運用は可能ですが、そのための設定や管理は自己責任となり、専門知識が必要です。

### AWS RDSの利点

Amazon RDSを使用すると、これらのスケーラビリティと管理の課題が大幅に軽減されます。RDSはマネージドサービスであり、データベースのセットアップ、パッチ適用、バックアップ、スケーリングなどの管理タスクを自動化します。具体的には、数クリックでデータベースのレプリケーションやリードレプリカの設定が可能で、負荷に応じて自動的にストレージをスケールアップする機能も提供します。また、RDSは高可用性のためのマルチAZデプロイメントを簡単に構成でき、故障時の自動フェイルオーバー機能を持っています。
結論として、EC2上に自分でデータベースを設定することも可能ですが、スケーラビリティや運用の簡便さを考慮すると、AWS RDSの利用が推奨されます。

## 補足3: S3の代替品としてのWasabi

Amazon S3の代替品としてWasabiは、コストパフォーマンスや特定の機能面で異なる選択肢を提供します。Wasabiは低コストで高速なオブジェクトストレージサービスを標榜しており、データ転送費用が無料である点や、よりシンプルな料金設定が特徴です。S3と同様に、Wasabiも耐久性と可用性が高いストレージサービスを提供しますが、AWSの豊富な追加サービスやエコシステム、地理的なリージョンの広がりといった点では差があります。
結論として、WasabiがS3の有効な代替品になり得ますが、選択にあたってはコスト、パフォーマンス、サービス連携の要件を総合的に評価する必要があります。
Cypressを使って, APIで取得したデータが表示されているかどうかを確かめる

CypressでE2Eテスト自動化を行ったので、備忘録として書きます。
### やりたかったこと
DBから取得したAPIのレスポンスが、狙った位置に表示されているかをCypressで確認したい


### 具体的な状況
vue.jsファイル↓
```
<template>
<p>動的に値が変わるデータ↓<p>
<p> {{ items.data.key1 }} </p>
</template>

<script>
export default {
  data() {
    return {
      items: ""
    };
  },
  // 画面表示した時にgetItems関数が走る
  async created() {
      this.items = await getItems();
  },
  methods: {
      getItems(){
          // API Gatewayを叩いてlambdaを呼び出しし、DBからデータを取得する処理
      }
  },
}
</script>
```

このgetItem関数が画面表示時に、叩かれると、レスポンスボディの中は↓のようになっています。
レスポンスボディは、開発者ツール(Ctr + Option + I)のネットワークを開いた状態で、画面表示(リロード）し、表示されたAPIの中からレスポンスを見たいAPIを押して、「レスポンス」を押すと、見ることができます。
![スクリーンショット 2024-03-19 23.37.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3747635/10c02723-6eb1-07de-429d-11b744a69ce5.png)
（上の例では、今この記事を編集している最中に、叩かれたAPIのレスポンスを見てみました)
今回中身は↓のようになっているとします。

```
{
    "data":{
        "key1":"value1"
        "key2":"value2"
        "key3":"value3"
    }
}
```


フロントでDBから取得した値が表示されるまでの流れとしては、
① 画面に遷移する
② データ取得APIはまだ叩かれていないため、　items = ""　（欲しいデータがまだ入っていない）　
③ DBからデータを取得するAPIが叩かれる
④ items に③のレスポンスで帰ってきた値が入る

となっています。
そのためCypressでフロント④のテストを行うためには、
1️⃣ APIを叩いてレスポンスが帰ってくるのを待つ
2️⃣ APIのレスポンスの値を変数に持つ
3️⃣ 2️⃣で作った変数の値と、<p>タグの中身が同じであることを確認する
の流れになります。

### 自分がハマった落とし穴
1️⃣でAPIを叩いてレスポンスを叩く前に、itemsのデータを読み取ろうとすると、中身が""なので、エラーで落ちる。特にitemsにデータが入っている＝データ取得APIが叩かれることの証明だと思っていたので、
```
cy.get('p').should('not.have.text', "");
```
としていたら、APIが叩かれる前のitems = ""の状態で,pセレクタの内のテキストが""ですといったエラーに落ちていました。



### 解決策

1️⃣ データ取得APIのレスポンスが変えるまで待つ
```
cy.intercept('①GETもしくはPOST', '②http://example.com/settings')as('③getItems')
cy.wait('④@getItems')
```
①　確認したいAPIの種類によってGETもしくはPOSTを選ぶ（これも開発者ツールの「ネットワーク」から、今回処理を待ちたいAPIを選んで、ヘッダーを見ると、GETかPOSTかを確認できる。
② 叩くAPIのエンドポイント
③ このレスポンスをなんと定義するか、④でinterceptで定義したものが返ってくるまで待つのに使う。
④ ③と同様の値（③で定義したもののレスポンスが変えるまで待つ）。※ @をつける

2️⃣ APIのレスポンスの値を変数に持つ
上記のコードのwaitのところに繋げて書きます。
```
cy.wait('@parametersReq').then(interception => {
  const items = interception.response.body.data ⭐️データの構造に合わせて適宜変更
  if(interception.response.statusCode == 200){
      // ここの中で、itemsの変数が使えるため3️⃣の処理をここに追記
  }
}
```
3️⃣ 2️⃣で作った変数の値と、<p>タグの中身が同じであることを確認する
先ほど2️⃣で作ったコードの中で、<p>タグの中身がitemsの該当するデータと同じなのかを確認します。
```
cy.wait('@parametersReq').then(interception => {
  const items = interception.response.body.data ⭐️データの構造に合わせて適宜変更
  if(interception.response.statusCode == 200){
      cy.get('p').should('have.text', "items.key1");
  }
}
```
これでDBから取得した値の、特定の値が狙ったところに表示されているかを確認できます。
APIエンドポイントは例として直書きで書きましたが、実際には環境で分けています。


### 結論
cy.intercept　と cy.waitを使って、APIのレスポンスが帰ってくるのを待つことが重要。


### 感想
vue.jsのv-modelを使っている入力フィールドの中身が、DBから取得しているかを一致しているかの確認の記事があまり見つからなかったので、記事にしてみました。

もっと効率のいい方法知っている人いれば、教えてください。
Nodeのビルドインオブジェクトを拡張する


## 目的
配列の`remove`メソッドなど、JSのビルトインオブジェクトには存在しないメソッドを拡張して定義したい

## 問題点
こんな感じで関数を定義してもいいけど、
```typescript
function remove<T>(array: T[], removeElement: T): T[] {
    return array.filter(element => element !== removeElement)
}

remove(['a', 'b', 'c'], 'b') // ['a', 'c']
```
やっぱり配列のメソッドとして拡張ができた方が、使いやすいし読みやすい。
swiftなら`extension`で、Kotlinなら関数の前にレシーバータイプを記述することで拡張関数を定義できる。
しかしTypescriptにはそのような文法はない。

## 解決策
まず配列のアンビエント宣言を追加し、型チェックができるようにする。
その後配列のprototypeオブジェクトに任意の名前で関数を代入する。
```typescript
export {}

declare global {
    interface Array<T> {
        remove<T>(removeElement: T): T[];
    }
}

Array.prototype.remove = function<T>(removeElement: T): T[] {
    return this.filter(element => element !== removeElement)
}
```

あとはviteのReactプロジェクトの場合であれば、ルートである`main.tsx`でインポートすることで、
グローバルに使えるようになる。
```tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './ArrayExtensions.ts' // 追加


ReactDOM.createRoot(document.getElementById('root')!).render(
    <React.StrictMode>
        <App/>
    </React.StrictMode>,
)
```

テスト実行時も動作するように、`setupTests`でもインポートしておく
```typescript
import '@testing-library/jest-dom/vitest'
import userEvent from '@testing-library/user-event'
import { render } from '@testing-library/react'
import '../ArrayExtensions.ts' // 追加

export default function setup(jsx: JSX.Element) {
    return {
        user: userEvent.setup(),
        ...render(jsx)
    }
}
```

完成
```typescript
['a', 'b', 'c'].remove('b') // ['a', 'c']
```
WSLのインストール：Linux未経験者がWindows内環境でできること①

### きっかけ
卒業した専門学校も職歴も開発系で、インフラ周りはほとんど触ったことはありませんが
LPI-Japan様のオープンコミュニティに参加させて頂いているので、せっかくなのでやってみようと思ったことです。

### WSLとは
Linux用Windowsシステムのこと。WSLを使用することにより、WindowsでLinuxが使用できるようになります。

### インストール方法(再インストールの場合)
かなり前にUbuntuをインストールしたPCに再インストールしたためその場合の手順を記載させて頂きます。

①PowerShellを管理者権限で開き、
「Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux」コマンドを実行する。実行後PCの再起動を求められるため、再起動。

![インストール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533750/28e06f22-7add-982e-b8b3-3e46f8fae123.png)


②Windowsのスタートボタンからメニューを開き、ストアアプリを起動。Ubuntuアプリをインストール

![ストアアプリ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533750/dcdc0b3e-1824-7552-afe5-80cf038096c9.png)

③インストールしたUbuntuを起動してみると、カーネルコンポーネントの更新を求められたため、一旦Ubuntuを閉じる。

![開いた直後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533750/06961a43-1c0a-66ce-9681-bd588cbd5125.png)

④PowerShellを管理者権限で開き、「wsl.exe --install」コマンドでLinux用Windowsサブシステムが既にインストールされていることを確認後、「wsl.exe --update」でサブシステムを更新。
![アップデート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533750/88535980-aff4-3b8c-1b01-c467a8e3d4bf.png)

⑤更新終了後、不足しているコンポーネントをインストールするよう求められたためインストール
![不足コンポーネント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533750/f8e6d8bb-b9dc-8592-c6ed-c304cb8da85a.png)

⑥再度Ubuntuを開いてみると「指定されたファイルが見つかりません」というエラーが出る。以前Ubuntuをインストールした時の登録情報が残っているため、初期化処理ができないことが原因なので登録をPowerShellで解除。

![再インストールエラー対策.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533750/e0760dc8-8fb6-8b75-8f73-88cd706b07fa.png)

⑦登録解除後、再びUbuntuを開くと自動的に初期化処理が始まる。

![Ubuntuのアカウント作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533750/b777aaa4-929f-2eda-c2f2-04a4f773d8c3.png)

⑧usernameとpasswordを設定するとログイン成功！
![ログイン成功.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533750/4e8c339f-599f-607b-e799-f75912cd8c82.png)

再インストールのため、登録解除などの作業が増えましたが
WSLを使用すればLinuxの経験がない私のような者でも、簡単にLinux環境をWindowsの中に作成できます。


以上です。ここまで読んで頂きありがとうございました。
【Railsチュートリアル】第11-14章　まとめ

## 第11章
### コンソールの改行
```ruby:ターミナル

rails generate migration add_activation_to_users \
> activation_digest:string activated:boolean activated_at:datetime

```

### メーラーの生成
```ruby:ターミナル

rails generate mailer UserMailer account_activation password_reset

```

### メールを即時送信
```ruby:app/controllers/users_controller.rb

UserMailer.account_activation(@user).deliver_now

```

### メッセージを渡し、動作させる
```ruby:app/models/user.rb


digest = self.send("#{attribute}_digest")

```

### コントローラのアクション内で定義された変数をテストで使う
```ruby:app/models/user.rb


@user = assigns(:user)

```

### メールの宛先と件名を決める
```ruby:app/mailers/user_mailer.rb

mail to: user.email, subject: "Account activation"

```

## 第12章
### コンソールの改行
```ruby:ターミナル

rails generate migration add_activation_to_users \
> activation_digest:string activated:boolean activated_at:datetime

```

### 隠しフィールドとしてページ内に保存する
```ruby:app/views/password_resets/edit.html.erb

<%= hidden_field_tag :email, @user.email %>

```

## 第13章
### データベースに反映させず、オブジェクトを返す
```ruby:test/models/micropost_test.rb

@micropost = @user.microposts.build(content: "Lorem ipsum")

```

### スコープを設定する
```ruby:app/models/micropost.rb

default_scope -> { order(created_at: :desc) }

```

### Procをの処理を評価する
```ruby:ターミナル

>> -> { puts "foo" }
=> #<Proc:0x007fab938d0108@(irb):1 (lambda)>
>> -> { puts "foo" }.call
foo

```

### 紐づいたデータもあわせて削除する
```ruby:app/models/user.rb

has_many :microposts, dependent: :destroy

```

### アップロードファイルを関連づける
```ruby:app/models/micropost.rb

has_one_attached :image

```

## 第14章
### ユーザーidを指定してメンバーを表示
```ruby:app/models/micropost.rb

resources :users do
  member do
    get :following, :followers
  end
end

```

### ユーザーidを指定せずメンバーを表示
```ruby:app/models/micropost.rb

resources :users do
  collection do
    get :tigers
  end
end

```
laravel factoryはcreateOneとかcreateでDBにレコードを作るだけじゃない

## 概要

Unitテスト中にモデルのインスタンスを作りたくなって、どうしようか困っていたときにfactoryを使えば簡単にモデルのインスタンスを作れることを思い出して活用したので簡単に活用方法をまとめる。

## 経緯

laravelのfactoryというと、自分は「Featureテストのときに、テストメソッド前のお膳立てでDBの状態を作るときに使うやつでしょ」というイメージが有る。
多分これは自分があまりUnitテストを書いてこなかったからかもしれない。

今回「モデルのインスタンスを引数に動作するメソッドのUnitテスト」を書く必要があった。

モデルを直接newしてインスタンスを作っても良かったがスマートな方法があるはずだと考えた。そして、factoryを使うとDB永続化せずに、指定の値でモデルのインスタンスを作れたはずだということを思い出した。

## createOneやcreate

その前にFeatureテストでよく使う`Foo::factory->createOne();`や`Foo::factory->create();`について簡単にまとめてみる。

このメソッドたちは「テスト用DBに実際にレコードを追加して、追加したレコードのモデル（`createOne()`の場合）やモデル郡のコレクションを返す（`create()`の場合）」という動作をしている。

簡単に言うと実際にテスト用データをモデルに紐づくテーブルに突っ込んで、突っ込んだ情報のモデル情報を返してくれるすごく便利なメソッドだ。Featureテストのときはかなりお世話になっている。いつもありがとう。

## モデルのインスタンスだけを返すメソッド

本題だが、今回お世話になったメソッドが`Foo::factory->make();`である。
この`make()`は **DBへの永続化は行わず、モデルインスタンスのみを返す**のだ。

「DBにレコードは作ってほしくないけど、簡単にモデルのインスタンスを作りたい」というニーズに答えるメソッドだ。

なので今回のような「モデルクラスのインスタンスを引数にするメソッドのUnitテスト」にはピッタリだった。
更に`createOne()`と同様にキーを指定し値を渡すと、渡したキーと値でモデルのインスタンスを作ってくれる。

下記のように指定すると`$piyo`には値がセットされたモデルのインスタンスが入る。

```php
$piyo = Piyo::factory()->make([
    'id' => 100,
    'hoge_token' => 'test_token',
    'is_fuga' => true,
        ]);
```

Unitテストで結構使えそうなのでこれは活用していきたい。

あとは下記のように`count()`と併用すれば複数のモデルのインスタンスを作る事もできるらしい。（10と指定しているので10個のインスタンスができる。）

```php
$piyos = Piyo::factory()->count(10)->make();
```

## 注意

外部キー制約がしっかり貼られている場合あるあるのファクトリの中で子テーブルのファクトリ（`createOne()`）を更に呼んでいる場合、`make()`で指定したモデルに関してはインスタンスだけを作るが、もちろんファクトリの中で呼ばれているファクトリのメソッドが`createOne()`なら、もちろんのことその呼出はインスタンスを作るにとどまらずレコードのインサートまでしてしまう。
こういった予想外のレコード作成はその先の関連テーブルとの整合性エラーが発生する場合がある。
ファクトリの`make()`を使った際に外部キー制約の整合性エラーが出る場合は「呼び出しているファクトリが更にファクトリを呼んでいないか」などを確認してみよう。

## 参考文献

https://readouble.com/laravel/10.x/ja/eloquent-factories.html#instantiating-models
Promiseコード解説（Vue）

・<ag-list-footer＞など他のファイルはインポートしないで使えるのはなぜ？

import SettingDialog from './SettingDialog.vue';これ書かないとエラーになる

 （解）components: {}の中にも定義していたから

　　app.jsの中で設定されているのでファイルはインポート書かなくてもタグで使える

```
<user-save-component ref="SaveDialog" :auth="this.auth" :const="this.const" @onListReload="onGetList"></user-save-component>
        <loading-overlay :loading="loading"></loading-overlay>
        <message-dialog ref="msgDialog"></message-dialog>
```

- beforeMountなど、Vueの**ライフサイクルについて**

### **`Promise`には3つの状態がある**

処理の順序に

**お約束**を取り付けることができるもの、

**処理を待機することや、その結果に応じて次の処理をすることお約束するもの**

だと思っています。

`Promise`には、`PromiseStatus`というstatusがあり、3つのstatusがあります。

- `pending`: **未解決** (処理が終わるのを待っている状態)
- `resolved`: **解決済み** (処理が終わり、無事成功した状態)
- `rejected`: **拒否** (処理が失敗に終わってしまった状態)

https://qiita.com/cheez921/items/41b744e4e002b966391a

```
 getData(sid) {
            // データ取得のPromiseを返す関数
            return new Promise(function(resolve, reject) {
                const axios_class = axios.get(constants.url.endpoint.setting.list + "/" + Number(false));
                const axios_edit_data = axios.get(constants.url.endpoint.setting.data + "/" + sid);
                Promise.all([axios_class, axios_edit_data])
                    .then(response => resolve(response))
                    .catch(error => reject(error));
            });
        },
```

[axios_class, axios_edit_data]の配列の

追加の時は0番目axios_class→分類で選択肢出すためにlistでデータの一覧を取得する

編集の時はの配列の1番目axios_edit_data→編集する行のsidで１個選んでその行のデータを取ってくる

```
<!-- 分類 -->
                        <v-col class="pt-0" cols="12" xs="12" sm="12" md="12" lg="12" xl="12">
                            <v-autocomplete
                                :items="classList"
                                item-value="class_cd"
                                item-text="class_name"
                                v-model="classValue"
                                label="分類*"
                                **return-object**
                                :rules="isNewClass ? [] : [inputRules.requiredSel]"
                                :disabled="isEditMode"
                            >
                            <template v-slot:append-outer v-if="!isEditMode">
                                    <v-icon @click="isNewClass = !isNewClass">mdi-plus</v-icon>
                                </template>
                            </v-autocomplete>
                        </v-col>
```

**:disabled**="isEditMode"　触れなくする

**return-object**

が書いてあるときはデータ１個（nameとか）じゃなくて、全部(１件丸ごと)渡す。

使うのは何を基準に決める？

:rules="isNewClass ? [] : [inputRules.requiredSel]"

ルールの条件　**`isNewClass`**が**`true`**の場合、**`:rules`**には空の配列**`[]`**が指定されます

```

        <!-- 一覧 -->
        <div>
            <ag-grid-vue class="ag-theme-alpine" style="height: calc(100vh - 200px);min-height: 340px;"
                :gridOptions="gridOptions"
                :rowData="rowData"
                :modules="modules"
                :context="context"
                :frameworkComponents="frameworkComponents"
            />
        </div>
```
LaTeXの数式を画像で保存する方法

## 概要
- LaTeXで書いた数式をpngで保存する方法です
- スクショと異なり背景透過もされているため扱いやすいです
- 複数の数式を一度に出力できます
- パワポなどに貼るときに便利です

## 環境
- TexLive 2023
- Inkscape 1.3.2
- Ubuntu 22.04（Windowsにも方法は転用可能）

## 方法
### 大雑把な流れ
1. LaTeXで数式のみのpdfを出力（ページ番号なども無し）
1. `pdfcrop`で余白を削除
1. `rungs`でフォントをパスに変換（文字化け防止）
1. `pdfseparate`でpdfをページごとに分離
1. inkscapeでpdfをpngに変換

:::note
`pdfcrop`，`rungs`と`pdfseparate`は，TexLiveに同梱されています．
:::

### ビルド用のshellスクリプト
```bash: texbuild.sh
# ファイルパスの処理
filepath=$(readlink -m $1)
dir="$(dirname "$filepath")"
file="$(basename "$filepath")"
file="${file%.*}"
echo "[${dir}] [${file}]"

# ファイル名の生成
texname=$file".tex"
pdfname=$file".pdf"
pdf_tmp=$file"_tmp"
pdf_sep=$file"_%02d.pdf"

# カレントディレクトリの移動
OLDPWD=$PWD; cd $dir
echo $PWD

# すでにあるpdfとpngを削除
find -regex ".*png"
rm *pdf *png

# メインの処理（lualatex使用バージョン）
lualatex -interaction=nonstopmode --jobname=$pdf_tmp $texname
pdfcrop $pdf_tmp".pdf" $pdf_tmp".pdf"
rungs -o $pdfname -dNoOutputFonts -sDEVICE=pdfwrite $pdf_tmp".pdf"
pdfseparate $pdfname $pdf_sep
rm $pdf_tmp*
eqs=$(find -regex ".*[1-9]\.pdf" -type f )
for eq in $eqs; do
  echo $eq
  inkscape --pages=1 $eq --export-dpi=600 --export-type="png"
done

# 作業前のディレクトリに戻る
cd $OLDPWD

```

## 実行例
以下のtexファイルを例に実行例を示す（`\clearpage`ごとに別々の画像が出力されます）．
```tex: eq.tex
\documentclass[a4paper,10pt]{ltjsarticle}
\usepackage[deluxe,haranoaji]{luatexja-preset}
\usepackage{amsmath,mathtools,amssymb}
\pagestyle{empty}
\begin{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{align*}
  e^{j\theta} = \cos(\theta) + j\sin(\theta)
\end{align*}
\clearpage
\begin{align*}
  _{\it n}\mathrm{C}_{\it r} = \frac{n!}{(n-r)!r!}
\end{align*}
\clearpage
\begin{align*}
  \int f(x)dx, \ g(x)=\int^{x} f(x')dx'
\end{align*}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\end{document}
```
上記のtexファイルに対して，以下のコマンドを実行する．
```bash
source texbuild.sh eq.tex
```
出力後のディレクトリ構造と出力された画像：
```tree
.
├── eq_01.pdf
├── eq_01.png
├── eq_02.pdf
├── eq_02.png
├── eq_03.pdf
├── eq_03.png
├── eq.pdf
├── eq.tex
└── texbuild.sh
```
- `eq_01.png`：
<img width="400" alt="eq_01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529141/11c2cd6a-6a6a-88af-ebd1-033af8bdd07c.png">

- `eq_02.png`：
<img width="400" alt="eq_02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529141/54a01cf7-bf3b-17a9-3f2c-b214d3c368b3.png">

- `eq_03.png`：
<img width="400" alt="eq_03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529141/4ab87a38-dbbb-7bb5-8400-409c303d9b9a.png">

## ソースコード
https://github.com/m13yama/Eq
MacでPDFの文字起こし（OCR）

Macで簡単にPDFの文字起こし，OCR（光学文字認識）ができるのでその方法を共有します．

1. PDFをプレビューで開く．
（PDFを右クリック→このアプリケーションで開く→プレビュー.app）

2. サイドバーで適当なページを右クリック→別名で書き出す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583007/54e0b425-ee13-dc6d-31fd-33b92e97addb.png)

3. 「テキストを埋め込む」にチェックを入れた状態で保存を押す．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583007/b1d2747b-cbd3-dc9b-c5fa-346114bb778d.png)

4.完了！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583007/7774a160-48f1-c858-e11a-1dfc9ce0edd5.png)
[Laravel]Handler.phpを初めて知った際のメモ

## これはなに
- 業務上で得た知識をメモるだけ
- 他人が読む前提で書いていません

## Handlerとは？
- Laravelプロジェクト作ると最初から入ってるクラス
- ログ出力・アラート通知・レンダリングなどを行う

## なぜ知ったのか
- 特定のアラートのみエラー通知から除外する対応を行ったが、エラー通知を行っている箇所がHandler.php
    - renderJsonメソッドでログを出力していたため除外対応を行ったが、reportメソッドでも出力を行っていた
        - 結果、reportメソッド側でも同様の除外対応を実施する事となった

## renderとは？
- 例外をHTTPレスポンスに変換したり
- 例外毎に出力するメッセージを変えたり
- 特定の例外を詰め替えたり
~~~
$e instanceof BackedEnumCaseNotFoundException => new NotFoundHttpException($e->getMessage(), $e)
~~~

## reportとは？
- ログに書いたり
- メールやSlackへ通知を行ったり
- dontreportに設定すればレポートされない
    - セキュリティ上報告したくない例外を除外するため
~~~
A list of the internal exception types that should not be reported.
protected $internalDontReport = [
        AuthenticationException::class,
        AuthorizationException::class,
        ~~~
~~~

## まとめ
- renderでレンダリングしてreportで通知
- 役割が違うのでそれぞれ適した実装をする
React公式ページで学んでみた④（備忘録）

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

# 今回の目的
前回の続きです。今回は「インタラクティビティの追加」。被る部分もあると思いますが、後で振りかえって深掘りするきっかけになるのが理想です。細かく書くと大変なのであっさりめ。

https://qiita.com/mr_noppo/items/f817e2941470a1082f28

# 使用したものや事前準備
・Macbook Pro
・Visual Studio Code

# 主に参考にさせていただいた記事
https://ja.react.dev/learn/state-a-components-memory

https://ja.react.dev/learn/render-and-commit
# コンポーネントのメモリ（State)
Stateとは、コンポーネント固有のメモリ

### ローカル変数はレンダー間で保持されない、変更に気づけない
下記のような処理を書いてもレンダリングはされない。
```js
let count = 0; // 再レンダリングされると初期化される
function handleClick() {
    count = count + 1;
}
```
```js
<button onClick={handleClick}>
    next
<button/>
```
```js
{/* 値の変更に気づけないから更新されない */}
<div>{count + 1}<div/>
```

（参考ページ参照）下記のようにボタンをクリックしてカウントを上げていっても表示は変わらなかった。また、修正して再レンダーが始まるとカウントは０からに戻った。

![スクリーンショット 2024-03-19 22.04.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/943982/98ebe868-eacc-a1c9-1a47-bab1c9a4111b.png)


![スクリーンショット 2024-03-19 22.08.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/943982/3ea35242-b336-1a57-e431-ed33f0cbafb1.png)

### useState
・レンダー間でデータを保持するstate変数（count)
・変数の更新が再レンダーのトリガになる(setCount)

```react
const [count, setCount] = useState(0); // レンダーされてもデータを保持できる
function handleClick() {
    setCount(count + 1);
}
```
```react
<button onClick={handleClick}>
    next
</button>
```
```react
{/*値が変更されたことを検知再レンダリングされる*/}
<div>{count + 1}</div>
```

### フック
useStateと頭文字に「use」が付く関数はフックという。フックはレンダーされる時に利用可能な特別な関数。
コンポーネントの最上位でしか記述することができないため、コンポーネントで何を使うか宣言するような解釈で捉えると良さそう。

# レンダーとコミット
### レンダー
レンダーの意味は画面を再描画することではない。Reactでコンポーネントの状態やプロパティによって実際のDOM要素に変換するプロセス。レンダー結果が同じならReactはDOMを変換しない。

### レンダリングタイミング
主に下記で覚える。
・Stateの変更
・Propsの変更（react.memoでpropsのプリミティブは抑制可能、関数の場合はuseCallback関数で抑制）
・親コンポーネントが再レンダリングされた時
・Contextの値が変更された時

# 終わりに
少し本質的な部分を知れたと思います。

# 次
https://qiita.com/mr_noppo/items/5648128c5de10c40f12a
pythonで雑に実行引数の処理をする

# 雑に実行時引数の処理をする
雑に引数処理します、辞書型のある言語なら同じロジックが使えます
引数の解説だとかヘルプだとかバリデーションとか無いですが機能します
一般的な引数パースのライブラリがあるので使う機会あまり無いと思いますが

``` python

# argparse.py
import sys

def argparse(arguments, options):
    keyValue = ""
    keyReaded = False
    for argument in arguments:
        trimedArgument = argument.strip()
        if keyReaded == False:
            if trimedArgument in options:
                keyValue = trimedArgument
                keyReaded = True
        else:
            options[keyValue] = trimedArgument
            keyReaded = False
    return options

def test():
    options = {
        "-a": "a-default-value",
        "-b": "b-default-value",
        "-c": "c-default-value",
    }
    parsedOptions = argparse(sys.argv, options)
    print("parsedOptions", parsedOptions)
    

if __name__ == "__main__":
    test()

```
HTTPS-PORTALで接続元を日本に制限する

## 概要

- 小さな範囲で使用するWebサイトを簡単にHTTPS化する場合、[HTTPS-PORTAL](https://github.com/SteveLTN/https-portal)は簡単、便利です
- インターネットに公開する場合、公開したサイトにアクセスできる国を限定しておきたい場合があると思います
- 今回は[HTTPS-PORTAL](https://github.com/SteveLTN/https-portal)を使って公開したサイトを国別に限定する方法を試してみたいと思います

## 原理

[HTTPS-PORTAL](https://github.com/SteveLTN/https-portal)には[アクセス制限機能](https://github.com/SteveLTN/https-portal/blob/master/README-ja.md#%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%88%B6%E9%99%90)があります。
この機能は環境変数「ACCESS_RESTRICTION」に許可するIPアドレスを指定する事で、それ以外のアドレスからのアクセスを排除する事ができるというものです。

問題は日本国に割り付けられるIPアドレスは定期的に変化しているため、
制限対象として指定するIPアドレスも定期的に変化させる必用がります。

実は、HTTPS-PORTALには[動的に設定を変更する](https://github.com/SteveLTN/https-portal/blob/master/README-ja.md#%E5%8B%95%E7%9A%84%E3%81%AB%E8%A8%AD%E5%AE%9A%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B)方法があります。
これは、HTTPS-PORTAL内部の指定されたパス`/var/lib/https-portal/dynamic-env`に存在する環境変数名のファイル内容を定期的にチェックしてシステムの設定に反映してくれるというものです。

つまり、HTTPS-PORTAL内部の

`/var/lib/https-portal/dynamic-env`

に

`ACCESS_RESTRICTION`

というファイル作成して、その中に接続するIPアドレスを記述し、そのファイルを定期的に更新していけば良いという事です。

```:ACCESS_RESTRICTIONの内容例
1.2.3.4/24 4.3.2.1
```

## 日本国のIPアドレス情報
IPアドレス情報は[ipv4.fetus.jp](https://ipv4.fetus.jp/)を参考とさせていただきます。
ここのサイトから毎日のIPv4割り付け情報を取得する事が出来ます。

まず始めに[自動化されたアクセスについて](https://ipv4.fetus.jp/about#automation)を確認しましょう。
特に重要なポイントとして接続元が分かるようにしてほしいのと事です。
これは、高負荷など何らかの対応をお願いする可能性があるからとの事です。
以下スクリプトでは、`-A`でユーザーエージェントを指定して接続元を明記していますのでご自分の設定に合わせてください。

このスクリプトはdockerのホスト側でクーロン駆動する事を想定しています。

```bash
#!/bin/bash

# ダウンロードするファイルのURL
url="https://ipv4.fetus.jp/jp.txt"

# 引数から出力ディレクトリとファイル名を取得、もしくはデフォルト値を使用
output_dir=${1:-"/hoge/docker-path/dynamic-env"}
output_file_name=${2:-"ACCESS_RESTRICTION"}

# 出力パスの組み立て
output_file="${output_dir}/${output_file_name}"

# 一時ディレクトリを作成（mktempを使用）
temp_dir=$(mktemp -d /tmp/my_temp_dir.XXXXXX)

# 一時ディレクトリ内の一時ファイル名
temp_file="$temp_dir/original_file.txt"

# curlを使用してファイルをダウンロード
curl -o $temp_file $url -A examplebot (contact@example.com)

# '#'を削除して新しいファイルに書き出す
sed '/^#/d' $temp_file > "$temp_dir/$output_file_name"
#改行はスペースに変換する
sed -i ':a;N;$!ba;s/\n/ /g' "$temp_dir/$output_file_name"

# 処理後のファイルを最終的な場所に移動
mv "$temp_dir/$output_file_name" "$output_file"

# 一時ディレクトリを削除
rm -r $temp_dir

echo "ファイルが処理され、${output_file}に書き出されました。一時ディレクトリは削除されました。"

```

スクリプトが作成出来たら、クーロンに登録します。
[ipv4.fetus.jp](https://ipv4.fetus.jp/)の情報更新か1日1回との事なので、スクリプトの更新も1日1回で良いです。
また、0時頃は接続が集中するとの事ですので、適当に散らしましょう。

```:crontab
0 3 * * * /bin/bash /*** path ***/update_ip_filter.sh
```

最後に生成結果をdocker環境に対してマウントします。
設定例は以下となります。

```yaml
#HTTP-Potal用の設定
services:
  https-portal:
 ・・・　いろいろ　・・・
    volumes:
      # IPアドレス制限用
      - ./dynamic-env:/var/lib/https-portal/dynamic-env

```
Reactのreducerによる状態管理

### リデューサとは
useStateでは状態の更新処理が複雑になる時のソリューションである。

### リデューサは何を解決するか
#### 「何を」「どのように」変更するか管理する必要がある 
`useState`では値を更新する際に「何を」「どのように」更新するかを記述する必要がある。
しかし状態するときは「何を」更新するかを考えるだけにしたい。
例えば簡単なTODOリストでは下記のようになる。

```jsx
const [tasks, setTasks] = useState(initialTasks);
...
// どのように更新するかを記述
function handleAddTask(text) {
  // setTasks()の前後に任意の処理を入れることもある。
  setTasks([
    ...tasks,
    {
      id: nextId++,
      text: text,
      done: false,
    },
  ]);
}

...

return (
  <>
  ...
  <!-- AddTaskでは一つのタスクの状態を管理している -->
  <AddTask onAddTask = { handleAddTask }>
  ...
  </>
)
```

これにタスクを加えたときに配列全体にソート処理をかけたり、他のコンポーネントへ値を渡したりといった処理が発生し複雑な処理になることもある。

「どのように」変更するかを分割した方がそのコンポーネントに適しているのであれば、ここに`setTasks()`の処理を書くべきではない。
`reducer`を使うことで「どのように」変更するかの処理だけ別のコンポーネントに移譲することができる。

```jsx
const [tasks, dispatch] = useReducer(taskReducer, initialTasks);
const taskReducer = (tasks, action) => {
  switch (action.type) {
  // 任意のキー（ここでは'added'）に対して処理を書く
  // このキーのことをアクションと呼ぶ
    case 'added':{
      return [
        ...tasks,
        {
          id: action.id,
          text: action.text,
          done: false,
        }
      ]
    }
    // その他のパターン
    case 'changed': { }
    case 'deleted': { }
    default:
      throw Error('Unkonwn action: ' + action.type);
  }
}

// useStateの場合と比べ処理が少なくなる
function handleAddTask(text) {
  dispatch({
    // typeは何でもいい　added_taskなどでもOK 何が起こったかを説明するもの
    type: 'added',
    id: nextId++,
    text: text 
  });
}

```

上記のように「何を（tasksを）」更新することだけ考えればよくなる。
つまり処理を適切に分割し、[関心の分離](https://www.amazon.co.jp/Clean-Architecture-達人に学ぶソフトウェアの構造と設計-Robert-C-Martin/dp/4048930656)を行うことができる。

### 参考
https://ja.react.dev/learn/extracting-state-logic-into-a-reducer
Spring Data JPAをAutonomous Databaseで使う

Google Cloud PlatformからOracle Cloud Infrastructureに乗り換えつつありますが、RDBもCloud SQLのPostgreSQLからAutonomous Databaseに移行しています。Spring Data JPAでちょっと苦労したので書き残しておきます。

## PostgreSQL

PostgreSQLではシリアルデータ型を列に指定することで、データインサート時にテーブル作成時自動的に作成されたシーケンスから採番した値をシリアルデータ型の列に格納してくれる機能があります。

```
CREATE TABLE user (
    id SERIAL NOT NULL,
    ...
);
```

Spring Data JPAのEntityクラスでは

```
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;
    ...
}
```
のようにIdアノテーションとGeneratedValueアノテーションを指定することでシーケンスから採番した値をidに設定することができます。

## Autonomous Database
Autonomous Databaseにはシリアルデータ型と同様のものはないので別の方法に変更しますが、使い勝手が変わらないようにデータベースのシーケンスから採番する方法とします。
```
CREATE TABLE user (
    id NUMBER NOT NULL,
    ...
);
```
自動的には作成されないのでシーケンスを作成します。
```
CREATE SEQUENCE user_id_seq;
```

Spring Data JPAのEntityクラスは

```
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_id_generator")
    @SequenceGenerator(name = "user_id_generator", sequenceName = "user_id_seq", allocationSize = 1)
    @Column(name = "id")
    private Long id;
    ...
}
```
のようにstrategyにGenerationType.SEQUENCEを、SequenceGeneratorアノテーションのsequenceNameに上記で作成したシーケンスを指定します。
シーケンスを指定しない場合はhibernate_sequenceが作成され使われます。採番が必要なテーブルが少なければhibernate_sequenceを使うのでも良いでしょう。
「asshuku」フロントエンドで画像を圧縮する！

# はじめに

初めまして、KouKinです。
フロントエンド開発歴5年。

出身は中国、日本の文化が大好きです。前は約2年ぐらい東京のIT会社で働きました。いろんな原因で2021年に帰国しました。今は中国の会社で働いています。

このような文章を作るのは初めてなんですが、多分何か文法的な間違いがあると思ういます。この原因で読みづらい、理解できない部分があれば、ご了承いただけますと幸いです。

今回はみなさんに共有したいことは「asshuku」です。
「asshuku」はフロントエンドで画像を圧縮することをできるnpmのpackageです。

# 「asshuku」 作成原因

ある日僕と上司のやり取り：

上司「コウ君、フロントエンドで画像を圧縮できるの？サーバー側の原因で圧縮しないとエラーが発生する可能性が高くになるそう。」

僕　「アップロードする画像の最大ファイルサイズを制限することは一般的な処理方ですが、圧縮の方は試してみます。」

上司「おお、頼むぞ。」

大体2、3日ぐらい、画像を圧縮に関するコードが書き終わりました。その時は偶然に、別のグループの業務システムもこの機能を求めているということを聞きました。

「意外と人気があるね。でも毎回違うシステムでこの似たような機能を書くのは時間の無駄だ（多分コードもほぼ同じ）。npm の package がつくってみよう！」

さて、「asshuku」が完成しました。

# インストール

好きなパッケージマネージャーを使って、asshukuをインポートする。

```
npm install asshuku
```
or
```
yarn add asshuku
```

# 例

### 必要なところにasshukuをインポートする。

```js
import { asshukuImage } from "asshuku";
s
... // other codes

const _file = await asshukuImage(file, {
    quality : 50,
    multAsshukuOptions : {
        targetSize: 500 * 1024, // 500KB
        maxRetryNum: 5, // 綜合六回を圧縮する
        qualityChangeFn : (quality) => quality / 3
    }
});
```

# オプション

### 基礎オプション

| Property | Description | Type | Default | Required |
| --- | --- | --- | --- | --- |
| file | 圧縮したい画像ファイル | File |  | true |
| asshukuOptions | オプション | AsshukuOptions | - | false |

### AsshukuOptions

| Property | Description | Type | Default | Required |
| --- | --- | --- | --- | --- |
| quality | 圧縮質 (0 ~ 100) | Number | 80 | true |
| multAsshukuOptions | 複数回圧縮する場合のオプション | MultAsshukuOptions | - | false |

### MultAsshukuOptions

| Property | Description | Type | Default | Required |
| --- | --- | --- | --- | --- |
| targetSize | 希望する圧縮後のファイルサイズ | Number | - | true |
| maxRetryNum | 最大再試行回数（ファイルが大きすぎると、何度圧縮しても目標サイズに到達できませんのため、このパラメーターを設置する） | Number | - | true |
| qualityChangeFn | quality減らす方法、qualityはマイナスには減らない。（マイナスの場合は0をリターン） | Function | (quality) => quality / 2 | false |

# サポート

✅　ES2015とその以後のバージョン。
✅　Typescript。
✅　すべてのコードをオープンソース化しました、ご必要があればご自由にお使いください。

# 最後

最後までお読みいただきありがとうございます。
[asshuku]があなたのお仕事に少しでもお役に立てれば光栄です。

# リンク

:file_folder: [npm](https://www.npmjs.com/package/asshuku)
:computer: [github](https://github.com/GumieHX/asshuku)
laravel uuidの形式チェックを行うバリデーションルール

## 概要

laravelのバリデーションルールにて、正規表現を用いてuuidの形式をチェックするバリデーションルールを考えたので簡単にまとめておく。

## 内容

regexのルールを使って正規表現を用いて文字列形式のチェックを行う。

```php
$request->validate([
    'uuid' => ['required', 'regex:/([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})/'],
]);
```

uuidは`8桁-4桁-4桁-4桁-12桁`の形式のため、それぞれ取りうる値を正規表現で表してみた。

## 参考文献

https://qiita.com/miriwo/items/8ea80aebd113edafebb0
複数の画像をタイル状に敷き詰めた画像を作る方法

# これは何？
こういう画像を作るための方法をまとめました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200471/b7e0336a-8876-2d54-2ae3-430edb7111c0.png)

# 背景

オープンデータスゴイというオープンデータの可視化ハッカソンを運営しており、その応募作品を一覧としてまとめたかったので、色々ググった末、chrome-extensionとfigmaを使えば結構簡単にできるということがわかった。その方法を備忘録も兼ねてまとめておきます。

# まずは画像ファイルを用意する

オープンデータスゴイに寄せられた作品は自分のQiita記事にまとめていたので、chrome-extensionを使ってそこから画像ファイルを抽出しました。

使ったchrome-extensionは「Image Downloader」というもの。

https://chrome.google.com/webstore/detail/cnpniohnfphhjihaiiggeabnkjhpaldj

使い方は簡単。

1. まずは[こちらのまとめ記事](https://qiita.com/unbosoms/items/7967d2408d03e9815491)を開いて、Image Downloderを起動。
1. するとページ内の画像の一覧が表示されるのでダウンロードしたい画像を選択
1. 保存するフォルダの名前やファイル名を指定してDownloadをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200471/6b45142d-b97b-974e-8ac7-173fc46ebd28.png)

フォルダ名とファイル名は設定した方が良いです。でないとデフォルトのダウンロードフォルダに全ての画像がファイルサーバー状のファイル名で保存されるのでどれがどれかわからなくなります。

ファイル名を指定すると「指定して文字列」＋「数字2桁」で保存してくれます。

＃ つぎにfigmaでタイル状に敷き詰める

こちらの記事を参考にしています。

https://www.wantedly.com/companies/seesaw/post_articles/477334

まずは貼りたい画像の分だけ四角形を並べます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200471/a9041277-380d-4111-29b3-b41c5130525d.png)

上記のように綺麗に６ｘ６=36個なら楽ですが例えば35個並べたい場合は、以下の様に何らかの調整が必要です（一番下の段だけ横５列にしています）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200471/7f803b96-f51f-7f56-1df2-c684e8c5d057.png)

そしたらMacだと「Cｍｄ＋Shift+K」、Windowsだと多分「Ctrl+Alt+K」を押すとファイルを選ぶ画面になります。ここで入れたい画像を全部選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200471/156be65a-86f3-a82f-d496-609e678ee832.png)

すると以下の動画のように四角形のボックスを順番にクリックすることで画像を埋め込むことができます。

![figma.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200471/cc9df090-18cd-f9b2-e691-15766b63645b.gif)


完成したらフレームを選択して、右のメニュー下部にあるエクスポートボタンから画像に吐き出すことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200471/6ed357a5-20b4-290b-0615-233e2e9655f4.png)

# 最後に

最初はパワポでやれるんじゃ...と思ってこちらの動画の内容をやろうとしたのですが、私のMacに入ってるPowerPointには当該メニューがなかったので上記の方法で実現しました。

https://www.youtube.com/watch?v=2iP0uSfROwQ

他にもいいやり方があれば是非教えてください！
CSVダウンロード（サーバからクライアント側へ）

1. **エラーチェック**:
    - 最初に、選択されたセンサーが存在しないかどうかを確認します。**`selectedSensors`**という配列が空であれば、選択されたセンサーがないということです。その場合、エラーメッセージが表示され、関数はそこで終了します。
2. **リクエストの準備**:
    - 選択されたセンサーが存在する場合は、リクエストのパラメータを準備します。これは、選択されたセンサーの情報を含むオブジェクトです。
3. **ダウンロードリクエストの送信**:
    - ダウンロードを実行するために、HTTP POSTリクエストが行われます。リクエストのURLは**`/admin/sensor/download`**です。
    - レスポンスの形式はBlob形式で、これはファイルデータをバイナリ形式で表します。
4. **リクエストの成功とファイルのダウンロード**:
    - リクエストが成功すると、サーバーからの応答データがBlobとして返されます。
    - このBlobデータから、ダウンロードするファイルの種類（MIMEタイプ）とファイル名を取得します。
    - 最後に、ブラウザがBlobデータをファイルとしてダウンロードします。
5. **エラーハンドリング**:
    - もしリクエストがエラーを返した場合、**`catch`**ブロックが実行されます。この場合、エラーメッセージが表示されます。
6. **最後の処理**:
    - ダウンロード処理の成否にかかわらず、最後にローディング状態を解除します。
    
    ```jsx
    public function download(Request $request)
        {
            // 選択中のセンサー情報のSIDをリクエストから取得
            $selectedSensorSids = $request->input('sid');
    
            // 選択中のセンサー情報をデータベースから取得
            $selectedSensors = MtSensor::whereIn('sid', $selectedSensorSids)->get();
    
            // CSVデータを生成
            $csvData = $this->createCsvData($selectedSensors);
    
            // CSVデータをレスポンスとして返す
            return Response::make($csvData, 200, [
                'Content-Type' => 'text/csv',
                'Content-Disposition' => 'attachment; filename="selected_sensors.csv"',
            ]);
        }
    
        /**
         * 選択されたセンサー情報からCSVデータを生成するメソッド
         *
         * @param  \Illuminate\Database\Eloquent\Collection  $selectedSensors
         * @return string
         */
        private function createCsvData($selectedSensors)
        {
            // CSVのヘッダー行を作成
            $csvData = "Sensor ID, ID, Temperature Lower, Temperature Upper, Humidity Lower, Humidity Upper, Battery Level, No Signal Time, Group SID, Remarks, Receive Interval, Is Enabled\n";
    
            // 選択されたセンサー情報をループしてCSVデータを追加
            foreach ($selectedSensors as $sensor) {
                // 各センサーの情報をCSV行に追加
                $csvData .= "{$sensor->sensor_id}, {$sensor->id}, {$sensor->temperature_lower}, {$sensor->temperature_upper}, {$sensor->humidity_lower}, {$sensor->humidity_upper}, {$sensor->battery_level}, {$sensor->no_signal_time}, {$sensor->group_sid}, {$sensor->remarks}, {$sensor->receive_interval}, {$sensor->is_enabled}\n";
            }
    
            return $csvData;
        }
    }
    ```
    
    **`download` メソッドの解説:**
    1. **リクエストの処理**: 選択中のセンサー情報のSIDをリクエストから取得します。
    2. **データベースからの取得**: 取得したSIDを使って、選択中のセンサー情報をデータベースから取得します。
    3. **CSVデータの生成**: 取得したセンサー情報からCSVデータを生成する **`createCsvData`** メソッドを呼び出します。
    4. **レスポンスの作成**: 生成したCSVデータをレスポンスとして返し、ダウンロードさせます。
    **`createCsvData` メソッドの解説:**
    1. **CSVヘッダーの作成**: CSVファイルの最初の行に、各列のヘッダー情報を追加します。
    2. **センサー情報の追加**: データベースから取得した各センサーの情報をループして、CSVデータに追加します。