OmniAICreator/Qiita-1.07M huggingface dataset:
ろうとるがPythonを扱う、、（その28：glob+おまけ）

# 正規表現あり引数を扱ったときに気がついたこと
かなりの小ネタであるが、引数に正規表現を含めて、それをglobを使った時の話である。

## glob
globは、ワイルドカードなどの正規表現を展開してくれるもの。下記説明がわかりやすい。
- [Pythonで条件を満たすパスの一覧を再帰的に取得するglobの使い方](https://note.nkmk.me/python-glob-usage/)
-  [［解決！Python］globモジュールを使って特定のパターンにマッチするパス名を取得するには](https://atmarkit.itmedia.co.jp/ait/articles/2310/03/news016.html)

本家はこちら。
- [glob --- Unix 形式のパス名のパターン展開](https://docs.python.org/ja/3/library/glob.html)

## 内容
### Windows上にてコマンドプロンプトでの実行とWSLとの実行で差があったため気が付く（後述するが、理由は単純）
ここでのプログラムは、正規表現にマッチするファイルを表示する単純なものである。

### 環境
あるティレクトリに下記ファイルが存在、これらをターゲットとする。

```shell
$ ls *.txt
f0.txt  f1.txt  f12.txt  f13.txt  g1.txt  g12.txt  h.txt
```

### 最初に作成したコード
```python:p1.py
import sys
import glob

# For Windows     ' ' is necessary for Linux
all_files = glob.glob(sys.argv[1])
for file in all_files:
    print(file)
```

第１引数をglob()に渡すだけである。

#### Windowsでの実行（期待どおり）
拡張子txtで、"1"を含むファイルを表示する。

```shell
> python p1.py *1*.txt
f1.txt
f12.txt
f13.txt
g1.txt
g12.txt
```
#### Linuxでの実行（期待どおりでない）
```shell
$ python3 p1.py *1*.txt
f1.txt
```

Linuxでは、シェルで正規表現を展開してしまうため、シェルで最初にマッチしたファイルしか表示されない。そこで、下記のように、シングルクオーテーションにて、正規表現の展開を防ぐと、期待どおりとなった。

```shell
$ python3 p1.py '*1*.txt'
f1.txt
f12.txt
f13.txt
g1.txt
g12.txt
```

### 次に作成したコード（正確にはどこかで見つけたコード）
引数を表示するもの。

```python:q1.py
import sys

# For Linux
args = sys.argv
for i in range(len(args)):
    print("args[", i, "] = ", args[i])
```

#### Linuxでの実行
```shell
$ python3 q1.py *1*.txt
args[ 0 ] =  q1.py
args[ 1 ] =  f1.txt
args[ 2 ] =  f12.txt
args[ 3 ] =  f13.txt
args[ 4 ] =  g1.txt
args[ 5 ] =  g12.txt
```
シェルで展開された内容が表示される。

#### Windowsでの実行
```shell
> python q1.py *1*.txt
args[ 0 ] =  q1.py
args[ 1 ] =  *1*.txt
```

globを用いていないので、当然の結果。

### 共通化？
引数を表示するプログラムを、WindowsとLinuxで判別したものが下記。

```python:r1.py
import sys
import glob
import platform

os = platform.system()
args = sys.argv

if os == "Linux":
    for i in range(1, len(args)):
        print(args[i])
elif os == "Windows":
    all_files = glob.glob(args[1])
    for file in all_files:
        print(file)
```

#### Windowsでの実行
```shell
> python r1.py *1*.txt
f1.txt
f12.txt
f13.txt
g1.txt
g12.txt
```
#### Linuxでの実行
```shell
$ python3 r1.py *1*.txt
f1.txt
f12.txt
f13.txt
g1.txt
g12.txt
```

環境（ここではOS）に合わせて、コードを変える、、、よくある話。

## おまけ
今回のトライ＆エラーで気がついた「おまけ」も記録。Linuxのシェルスクリプトの話である。

```shell:x2.sh, x3.sh
for file in `ls -1 *`
do    
  echo $file
done
```

Windows上で作成したコードを、Linux（WSL）で実行した。
```
$ bash x2.sh
x2.sh: line 5: syntax error: unexpected end of file
```

コードCR（0x0d）が余計らしい。そこで、下記を実行し、CRを取り除く。

``` shell
$ tr -d '\r' < x2.sh > x3.sh
```

```shell
$ bash x3.sh

....

x1.py
x2.py
x2.sh
x3.sh
x4.sh
```

異なる環境では動作しないこともある、、、という教訓。

EOF
Javaで「ラベルの前景色/背景色の設定と背景の透明/非透明の切り替え」の動作を確認してみた。

# 概要

Javaで「ラベルの前景色/背景色の設定と背景の透明/非透明の切り替え」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/tutorial/jlabel/index2.html

# 実装

以下のファイルを作成しました。

```Sample.java
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import java.awt.Color;
import java.awt.BorderLayout;

class Sample extends JFrame{
  public static void main(String args[]){
    Sample frame = new Sample("MyTitle");
    frame.setVisible(true);
  }

  Sample(String title){
    setTitle(title);
    setBounds(100, 100, 728, 400);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JLabel label1 = new JLabel("Hello!");
    label1.setForeground(Color.BLUE);

    JLabel label2 = new JLabel("Bye!");
    label2.setForeground(Color.RED);

    JPanel p = new JPanel();
    p.add(label1);
    p.add(label2);

    add(p, BorderLayout.CENTER);
  }
}
```

以下のコマンドを実行しました。

```
$ javac Sample.java 
$ java Sample
```

# まとめ

何かの役に立てばと。
paizaラーニングレベルアップ問題集の「3行のデータの入力」をやってみた。

paizaラーニングレベルアップ問題集の[3行のデータの入力](https://paiza.jp/works/mondai/stdin/stdin_3_line)をやってみました。
- - -
###### 問題
https://paiza.jp/works/mondai/stdin/stdin_3_line
- - -
###### 方針
[1行のデータの入力](https://qiita.com/anonymously115/items/50ed25f7748f1cb1b426)を3回繰り返します。
- - -
###### C
```c
#include <stdio.h>

int main() {
	for (int i = 0; i < 3; i++) {
		char s[102];
		printf("%s", fgets(s, sizeof(s), stdin));
	}
	return 0;
}
```
- - -
###### C++
```cpp
#include <iostream>
using namespace std;

int main() {
	for (int i = 0; i < 3; i++) {
		string s;
		getline(cin, s);
		cout << s << endl;
	}
	return 0;
}
```
- - -
###### C#
```cs
using System;

class Program
{
	public static void Main()
	{
		for (int i = 0; i < 3; i++) Console.WriteLine(Console.ReadLine());
	}
}
```
- - -
###### Go
```go
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	for i := 0; i < 3; i++ {
		if scanner.Scan() {
			fmt.Println(scanner.Text())
		}
	}
}
```
- - -
###### Java
```java
import java.util.*;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		for (int i = 0; i < 3; i++)
			System.out.println(sc.nextLine());
		sc.close();
	}
}
```
- - -
###### JavaScript
```js
const lines = require("fs").readFileSync("/dev/stdin", "utf8").split('\n');
for (var i = 0; i < 3; i++) console.log(lines[i]);
```
- - -
###### Kotlin
```kotlin
fun main() {
	repeat(3) {
		println(readLine())
	}
}
```
- - -
###### PHP
```php
<?php
	for ($i = 0; $i < 3; $i++)
		echo trim(fgets(STDIN)) . PHP_EOL;
?>
```
- - -
###### Perl
```pl
for (my $i = 0; $i < 3; $i++) {
	chomp(my $s = <STDIN>);
	print "$s\n";
}
```
- - -
###### Python3
```py
for _ in range(3):
	print(input())
```
- - -
###### Ruby
```rb
3.times do puts gets end
```
- - -
###### Scala
```scala
import scala.io.StdIn._

object Main extends App{
	for (_ <- 1 to 3) println(readLine())
}
```
- - -
###### Swift
```swift
for _ in 1...3 {
	print(readLine()!)
}
```
【Salesforce】「PermissionSetAssignment」オブジェクトを解説

今回はSalesforceでマニアックなオブジェクトである**PermissionSetAssignment**を解説します。  
このオブジェクトは、ユーザーと権限セット（Permission Set）や権限セットグループ（Permission Set Group）の関連付けを管理するために使用されます。  
多数のユーザーの「誰がどの権限を持っているのか？」を管理するうえで、便利なオブジェクトなので、ぜひ押さえておきましょう。

---

## 1. PermissionSetAssignmentとは？

`PermissionSetAssignment（権限セットの割り当て）`オブジェクトは、**ユーザー**と**権限セット/権限セットグループ**の関係を表現する中間オブジェクトです。

例えば、以下のような場面で利用されます：
- 特定のユーザーがどの権限セットを持っているかを確認する。
- 新しい権限セットを割り当てる。
- 不要な権限セットを削除する。

公式ドキュメント：[PermissionSetAssignment - Object Reference](https://developer.salesforce.com/docs/atlas.ja-jp.object_reference.meta/object_reference/sforce_api_objects_permissionsetassignment.htm)


データローダーからも確認できます。

![01権限セットの割り当て.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/789516/18c561cb-9aff-2c05-ad34-94f71eb68378.png)


---

## 2. 主なフィールド

PermissionSetAssignmentオブジェクトの主要なフィールドを以下にまとめました。

| フィールド名        | 型            | 説明                                                                 |
|---------------------|---------------|----------------------------------------------------------------------|
| `Id`               | ID            | レコードの一意識別子                                                |
| `PermissionSetId`  | ID            | 割り当てられた権限セットのID                                         |
| `PermissionSetGroupId` | ID        | 割り当てられた権限セットグループのID                                 |
| `AssigneeId`       | ID            | 権限セットを割り当てられたユーザーのID                               |
| `CreatedDate`      | DateTime      | レコードが作成された日時                                             |
| `LastModifiedDate` | DateTime      | レコードが最後に更新された日時                                       |

これらのフィールドを使うことで、権限セットや権限セットグループの割り当て状況を詳細に追跡できます。

---


## 3. 使用例

### 3.1 SOQLで権限セットを確認する

以下のSOQLクエリで、特定ユーザーの割り当てられた権限セットを取得できます。

```sql
SELECT Id, PermissionSet.Name, Assignee.Name 
FROM PermissionSetAssignment 
WHERE AssigneeId = '005XXXXXXXXXXXX'
```

- **AssigneeId**：ユーザーのIDを指定します。
- **PermissionSet.Name**：関連付けられた権限セットの名前を取得できます。

### 3.2 権限セットを割り当てる

開発者コンソールから、特定のユーザーに権限セットを割り当てることも可能です。

```apex
Id userId = '005XXXXXXXXXXXX'; // ユーザーID
Id permissionSetId = '0PSXXXXXXXXXXXX'; // 権限セットID

PermissionSetAssignment psa = new PermissionSetAssignment();
psa.AssigneeId = userId;
psa.PermissionSetId = permissionSetId;

insert psa;
System.debug('Permission Set Assigned: ' + psa.Id);
```
---

## 4. 注意点

- **一意性制約**  
  同一ユーザーに同一の権限セットを複数回割り当てることはできません。

- **削除制限**  
  権限セットの割り当てを削除する際は、Sandboxなどで十分に検証を行い、影響範囲に注意してください。基本的に件数が少ない場合には設定から手動で行っていきましょう。

---

## 5. 終わりに

`PermissionSetAssignment`は、普段は見ることがないオブジェクトかと思います。  
本記事で紹介した内容が少しでも参考になりましたら幸いです。
LambdaとContainerとJavaとM2 Macbook。

## はじめに

コンテナを使ったLambda関数を作ったことなかったなー。と思い、業務でも活かせそうなjavaで試してみました。

どハマりしたので、情報共有です。

## その１：The image manifest or layer media type for the source image〜

まず、デプロイ時に出るこのエラーです。

![スクリーンショット 2025-01-11 6.03.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894042/4ca6af20-ba94-578c-7a4f-b964bba04dc0.png)

> The image manifest or layer media type for the source image xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/batch-demo-lambda@sha256:0aa7422dadc5f760ad4ac164fda2ff7219d97daac3264abc5ce690f070ea3f36 is not supported.

### `--provenance=false`の付与が必要。

`docker build`に以下のオプションが必要でした。

この件は多くの記事で紹介されていました。

```
docker build --provenance=false -t batch-demo-lambda .
```

https://zenn.dev/c_hero/scraps/cbf8ccb7e3ec96

## その２：Error: fork/exec /lambda-entrypoint.sh: exec format error

次にこのエラーです。

![スクリーンショット 2025-01-11 6.13.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894042/dca48dbb-f692-0dc2-1989-f014dce6dffb.png)

### `--platform linux/amd64 `

ややこしいのですが、まずAppleシリコンのMacBookでは、`--platform linux/amd64`を明示しないとだめだよ！って記事を見かけたので、以下でビルドするようにしました。

```
docker build --provenance=false --platform linux/amd64 -t batch-demo-lambda 
```

そして、ランタイムも`arm64`側を選んでたのですが、どうしてもエラーが取れませんでした。

ただ、`x86_64`側だとエラーが出なくなり、不思議な感じでした。

![スクリーンショット 2025-01-11 6.14.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894042/f52b4c05-6655-961f-a6fc-464f835ccedc.png)

### arm64とamd64の違いに気づけず。。

この記事を書いていて、ようやく原因に気づいたのですが、私が`arm64`と`amd64`の違いに気づけてませんでした。。

Appleシリコン版はarm64なので、Lambdaのランタイムarm64で動かす場合は、`--platform`の明示的な指定は不要でした。

```
docker build --provenance=false -t batch-demo-lambda .
```

## java.lang.ClassNotFoundException

![スクリーンショット 2025-01-11 6.26.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894042/df1940e3-0157-e13a-e901-a3635b173c46.png)

### `${LAMBDA_TASK_ROOT}/lib/`にJARファイルを置く。

JARファイルは`${LAMBDA_TASK_ROOT}`直下ではなく、`lib`に配置する必要がありました。

> COPY target/batch_demo-1.0.jar ${LAMBDA_TASK_ROOT}/lib/

また、ここらの調査でも`Java21`と`Java27`の違いに気づけず、時間を無駄に消費しました。。

## 余談：imagesが更新されない！

今回はコンソール上からの操作でしたが、ここの更新ボタンでイメージが更新されないのは地味にストレスでした。。

![スクリーンショット 2025-01-11 6.38.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894042/6651860f-42f1-e463-8498-28f9b03996ba.png)

## まとめ

javaをコンテナに乗せて、Lambdaで動かすケースなんてないと思いますが、ネタ記事として公開してみます！

なお、log4jを使って以下のログを出すだけのサンプルにおける性能ですが、12秒くらいでした。（遅い）

```
21:40:22.749 [main] INFO  org.example.Main - Hello and welcome!
21:40:22.809 [main] INFO  org.example.Main - i = 1
21:40:22.809 [main] INFO  org.example.Main - i = 2
21:40:22.809 [main] INFO  org.example.Main - i = 3
21:40:22.809 [main] INFO  org.example.Main - i = 4
21:40:22.809 [main] INFO  org.example.Main - i = 5

REPORT Duration: 11618.42 ms	Billed Duration: 12085 ms	Memory Size: 128 MB	Max Memory Used: 115 MB	Init Duration: 466.01 ms	
```
Dockerを用いてpi holeの環境を整える方法

Pi-HoleはAd Block機能付きのDNSサーバとDHCPサーバを持つツールである．本ページではそれをDockerを用いてUbuntu上に導入する方法を記述する．
## 前提条件
- DNS，DHCPなどのネットワークの知識を有していること
- Dockerの知識をある程度有していること
- Pi-Holeについてある程度知識を有していること

## 準備

`$ ip a`を使用して，listenするネットワークインタフェース名を調べる
例
```
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever
2: enp0s31f6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 34:97:f6:8d:6a:68 brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.102/24 brd 192.168.10.255 scope global noprefixroute enp0s31f6
       valid_lft forever preferred_lft forever
    inet6 fe80::3697:f6ff:fe8d:6a68/64 scope link
       valid_lft forever preferred_lft forever
3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 52:54:00:7a:85:3c brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:29:6a:19:15 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
```
この場合「enp0s31f6」である．

## /opt/pi-holeディレクトリの作成

設定ファイルなどをDocker上で保持するため「/opt/pi-hole」ディレクトリを作成する．そしてその中に，「etc-dnsmasq.d」と「etc-pihole」というディレクトリを作成する．

## compose.yamlの作成

先ほど作成した/opt/pi-holeにcompose.yamlを次のように作成する
```
services:
  pihole:
    image: pihole/pihole
    network_mode: host # DHCPを機能させるために必須
    environment:
      TZ: 'Asia/Tokyo'
      WEBPASSWORD: hogehoge #好きなパスワードに設定してください
      WEB_PORT: 8080 #好きなポートに設定してください
      PIHOLE_INTERFACE: enp0s31f6 #「準備」で調べたネットワークインタフェース名
      INTERFACE: enp0s31f6 #「準備」で調べたネットワークインタフェース名
    volumes:
      - './etc-pihole:/etc/pihole' # 先ほど作成したディレクトリをコンテナ内から見えるようにする
      - './etc-dnsmasq.d:/etc/dnsmasq.d'# 先ほど作成したディレクトリをコンテナ内から見えるようにする
    cap_add:
      - NET_ADMIN
    restart: unless-stopped
```

最後に`$ docker-compose up -d --build`すればOK

## 筆者がハマったポイント

PIHOLE_INTERFACE: enp0s31f6 #「準備」で調べたネットワークインタフェース名
      INTERFACE: enp0s31f6 #「準備」で調べたネットワークインタフェース名
の両方の環境変数を設定しないとリッスンするインタフェースが勝手にeth0になって困っておりました．ChatGPTに助けてもらって解決しました．
NVIDIAドライバのせいでPCがクラッシュして絶望した話

# 背景
Isaac SimというNVIDIA社が提供するシミュレーションプラットフォームを使用しているときにプログラムのエラーが起き，NVIDIAドライバのバージョンのせいだと早とちりして安易にドライバをバージョンアップしてしまった．その結果，設定を開こうとしたり，GPUを使おうとするとPCがクラッシュするようになってしまった; ;
タスクマネージャーを見ると，CPUの使用率が100%になっており，まともに操作できない．

## 実行環境
OS: Ubuntu 22.04
GPU: Geforce RTX4070
CPU: 13th Gen Intel® Core™ i9-13900HX  
メモリ: 32GB

# NVIDIAドライバのインストール方法
NVIDIAドライバのインストール方法として，
- aptからインストール
- 公式サイトからデータを取ってくる

の２通りあると思う．

## aptでインストール
aptでインストールする際は，`ubuntu-drivers devices`で推奨ドライバを確認し，ppaなどからインストールすることになる．
```
// 既存のドライバのアンインストール
sudo apt --purge remove nvidia-*

// 推奨ドライバの確認
ubuntu-drivers devices

// インストール
sudo add-apt-repository ppa:graphics-drivers/ppa
sudo apt update
sudo apt install nvidia-driver-<バージョン>

// 再起動
sudo reboot now
```

## 公式サイトからインストール
公式サイトからインストールする際は`.run`ファイルを落としてきてダウンロードする．自分の環境を入力すると，公式オススメのドライバを取得できる．

https://www.nvidia.com/ja-jp/drivers/


```
// 既存のドライバのアンインストール
sudo apt --purge remove nvidia-*

// .runファイルに実行権限を付与
sudo chmod +x <ファイル名>.run

// インストール
sudo <ファイル名>.run

// 再起動
sudo reboot now
```

# 解決するまでにやったこと
本来であれば，上記の手順を踏めば適切なドライバがインストールされてGPUを使用できるようになるが，ここでクラッシュする問題が発生した．  
解決するまでに色々と調べながら行ったこととして，
- 他のバージョンを試す
`ubuntu-drivers devices`を実行すると，以下のように出力される．
```
== /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0 ==
modalias : pci:v000010DEd00002860sv00001028sd00000BF9bc03sc00i00
vendor   : NVIDIA Corporation
driver   : nvidia-driver-555-open - third-party non-free
driver   : nvidia-driver-535-server-open - distro non-free
driver   : nvidia-driver-560-open - third-party non-free
driver   : nvidia-driver-550 - third-party non-free
driver   : nvidia-driver-525 - third-party non-free
driver   : nvidia-driver-545 - third-party non-free
driver   : nvidia-driver-535-server - distro non-free
driver   : nvidia-driver-535-open - distro non-free
driver   : nvidia-driver-535 - third-party non-free
driver   : nvidia-driver-555 - third-party non-free
driver   : nvidia-driver-565 - third-party non-free recommended
driver   : nvidia-driver-545-open - distro non-free
driver   : nvidia-driver-560 - third-party non-free
driver   : nvidia-driver-565-open - third-party non-free
driver   : nvidia-driver-550-open - third-party non-free
driver   : xserver-xorg-video-nouveau - distro free builtin
```
ここで，`recommended`が推奨されるらしいが，場合によっては他のものがいいときもあるようだ．`open`がついているものはダメといったコメントもあったので，`third-party`のものを極力選ばないようにしながらいくつかのバージョンを試してみたがダメだった; ;  

他に行ったこととして，
- Nouveau の無効化
- Secure Bootの無効化
- Toolkitのアンインストール/バージョン変更
- カーネルのバージョン更新
- OSの初期化
- BIOSの初期化
- PCの初期化

など，他にも試行錯誤したがダメだった．Secure Bootを無効化したときにはUbuntuを立ち上げられなくなった．しかし，ドライバをアンインストールするとクラッシュしなくなるので原因はやはりドライバだろう．

# どうやって解決したのか
PCの初期化までやっても直ることなく，絶望して放心していたとき，ふとこれまで避けてきた`third-party`で`open`な最新のドライバを入れてみた．すると，

<b>動いた!!!!!!!!!!!!</b>

実際に使用したドライバは，
`nvidia-driver-565-open - third-party non-free`
です．

# まとめ
今回は違うバージョンを入れることで解決できましたが，調べていた感じだと問題は多岐にわたるようです(この仕様はなんとかなんないのかなぁ)．  
今回得た教訓として，
- ネットの内容を安易に信じない
- アップデートする際などはバックアップをちゃんととる(めんどくさくてサボりがち)
- 安易にアップデートやアップグレードをしない
- AIの言うことも鵜呑みにしない(結構ハルシネーションがある)

同じトラブルに見舞われている人にこの記事が役に立ってくれると嬉しいです！！！
(温度)M5NanoC6、MCP9700で遊ぶ。(MCP9700-E/TO)


x 過去ログを見ょ!!!
x 3.1.1
x なぜか、M5NanoC6は、電圧の値が入力される

目的
MCP9700の電圧を測って500引いた値の温度を
内蔵シリアルからパソコンで表示する。
printfは、esp32 arduinoでは、使えるが
ここは、あえて、


無意味に
●軽量
●高速化
●見やすさ重視
(M5NanoC6にハードウェア除算ある為?積極的に割り算を使う)
(M5NanoC6には、浮動小数点演算装置は、なさそう
(ラインナップ上、コスト重視ため?、中学の情報の授業では、
浮動小数点演算装置の面積は、CPUより大きいとされている?
(ようは、同じ面積からCPUが2個以上とれるため)))

MCP9700は、温度のアナログ出力ICで内部にオペアンプと
基準電圧?を持ち、多少、補正された値が出力される
リニアティー(値の直線性は、良い)
2Vぐらいから5Vぐらいの電源で使える
mVに対して1℃当たり10mVで10で割った値で温度(整数)になる
オフセット(0℃の中心点)は、500mVで単に500を引けばよい


![o_coq776.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/62fdf89c-39b7-d185-b7e3-fc221075d6ca.jpeg)


![image_original (26).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/d5f7e830-9c1a-b0b7-9509-004870fe5397.jpeg)

(画像は、使い回し)


・

プログラム

```c++




//mcp9700_1_M5NanoC6_1


//ヘッダー
#include <Arduino.h>


//初期化
void setup(void) {

  //シリアルの初期化
  Serial.begin(9600);
  Serial.println("");

  //シリアルの待ちが0.5*9
  for (int i = 0; i < 9; i++) {
    delay(500); //接続待ち
    Serial.print(".");
  }//for

  Serial.println("");

}//setup


//メインループ
void loop(void) {

  char data[16];//出力用文字列

  //MCP9700の電圧を読み取り500引く事で固定小数点1個
  int temperature = analogRead(1) - 500; // x10
  //Serial.println(temperature); //debug

  data[4] = 0;//終端記号
  data[3] = '0' + temperature % 10; //小数点の値
  temperature = temperature / 10;
  data[2] = '.'; //小数点の区切り
  data[1] = '0' + temperature % 10; //整数1桁目(1の位)
  temperature = temperature / 10;
  data[0] = '0' + temperature;      //整数2桁目(10の位)

  //MCP9700の温度を小数点1桁で表示 ex 23.4
  Serial.println(data); //debug

  delay(1000);//1秒待つ

}//loop




```
Docker入門以前：仮想化への理解から

# これは何？
長い間`Docker`の名前は聞き及んでいたものの、公式ドキュメントの難解さからなかなか手が出せずい、今回重い腰を上げてその習得に勤しんだんですね。

そういうわけで、本稿は、私が`Docker`に対して抱いていた誤解を含めその勉強をメモしたものです。間違っている可能性は悪しからず、むしろ指摘してくれたらうれしいです。

# そもそも仮想化技術とは
> 仮想化とは、一般的に物理的なコンピュータリソースを抽象化し、複数の独立した環境を作り出す技術のことを指します。
> 『図解まるわかり仮想化の仕組み』翔泳社、2024年 p16。

とにかく目の前にあるコンピュータをソフトウェアの力でさも複数のコンピュータがあるように見せかける技術、と理解して始めました。割とこの理解で何とかなります。

仮想化技術の何がうれしいかといえば、
1. 実行環境を独立させてお互いの干渉を抑えたり、
1. 複数のハードをソフトのレベルで一つのハードのように見せかけることができたり
1. 持っていないOSを差もそこにあるかのように模倣できたり

してとにかく管理が楽になり、限りあるリソースを効率よく割くことができるようになったりすることです。

# サーバー仮想化の種類、Dockerとは何者？
仮想化を使ってできることは幅広いので、とりあえず「どうサーバーを仮想化するの？」という方法論の観点から分類してやると、主に次の三種類に分かれます。
* Host型
* Hypervisor型
* Container型

上二つについては省略して、ここで取り上げるのがContainer型仮想化です。Container型は、アプリの実行環境や依存関係を詰め込んだ「小さなコンピュータ」である"Container"を作り上げる仮想化技術です。

さて、DockerはこのContainerを管理するアプリです。何ができるかといえば、先ほど述べた「もろもろを詰め込んだContainer」を作るということに加え、これを配布、実行までしてくれます。すごい（感嘆）

# Dockerの強み
いろいろ言いましたが、その上Dockerならではの強みがさらにあります。
その強みとは、可搬性と収縮性です。

まず可搬性（いろいろな環境で使える）についてです。DockerではどのようにContainerを生成するかといえば、それはDockerfileというファイルに**どのような環境を作るかをテキストとして記述**し、これをDockerに食わせることで実現します。
これが革新的で、実際このDockerfileさえ共有してしまえば、いつでもどこで環境を再現、実行できるわけですね。これが可搬性です。

次に収縮性（設定の調整のしやすさ）についてです。DockerではそのContainerを管理するための機能がいくらか用意されており、例を挙げればネットワーク通信の統制、ストレージの手配、セキュリティの保障などがあります。これらの機能により利用者は仮想的なContainerという抽象的で扱いずらい存在を簡単に扱うことができるようになり、各種の設定、調整などが手軽になります。これが収縮性です。

# 仕組み
Container仮想化の仕組みです。
TODO

# で、実際どうやるのさ
ここまで書いといてなんですが実際の使い方なんかは有用な記事がごろごろ転がってるのでそちらに任せた方がいいかな…

* [【図解】Dockerの全体像を理解する -前編-](https://qiita.com/etaroid/items/b1024c7d200a75b992fc#-%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A)

これあれじゃん、この記事いらないね

まあ書いてるうちに理解してくることもあるから....
Functionsにカスタムメトリックを送信する

## ライブラリ
`@opentelemetry/api`を使って、カスタムメトリックを送信する
AzureMonitorとの統合には`@azure/monitor-opentelemetry`の`useAzureMonitor`を使う

> ※似た方法として、Application Insights SDKがMSから提供されていますが、去年の夏ごろに廃止していく方針を発表しています。
> ここでは、方針に則ってOpenTelemetry Distroで実装していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956153/d592a59b-f169-4f47-9a79-2c4adbd6604e.png)
> [Application Insights を使用して Node.js サービスとアプリを監視する](https://learn.microsoft.com/ja-jp/azure/azure-monitor/app/nodejs)

## Opentelemetryのカスタムメトリックについて
アプリケーションやシステムの状態を数値として測定し監視するため、大きく以下３種類が用意されています。

メトリクス種類|データの方向性|主な用途|更新方法
--|--|--|--
Counter|増加のみ|イベント数、リクエスト数などの累積値を追跡|明示的に add メソッドを呼び出す
Histogram|分布を記録|応答時間やデータサイズの分布測定|明示的に record メソッドを呼び出す
Observable|Metrics|増減可能	メモリ使用量、CPU使用率などの動的な値を監視|コールバック関数内で値を観測

ここでは、最も汎用的なヒストグラムでの送信を考えます。

## ヒストグラム
送信方法は以下。
やり方はシンプルで`createHistogram`でヒストグラムを作成して、`record`で送信。
引数に2つ目にJSONを追加して、ディメンション分割することも可能。
```typescript
useAzureMonitor({
  azureMonitorExporterOptions: {
    connectionString: APPINSIGHTS_CONNECTION_STRING,
  },
  enableLiveMetrics: true,
});

export const opentelemetry = {
  async sendHistogram(args: { metricName: string; customMetric: CustomMetric[]; logger: Logger }) {
    const { metricName, customMetric, logger } = args;

    logger.info(`CustomMetric send start. metricName: ${metricName} count: ${customMetric.length}`);

    // Get the meter for the "metricName" namespace
    const meter = metrics.getMeter(metricName);

    // Create a histogram metric
    const histogram = meter.createHistogram(metricName);

    customMetric.map((cm) => histogram.record(cm.value, { [cm.dimensionName]: cm.dimensionValue }));

    logger.info(`CustomMetric send end. metricName: ${metricName}`);
  },
};
```

## 実際に送信してみる
テストデータとして、以下のような`Metric1`,`Metric2`のデータを用意した。
```typescript
  const metricName = 'testMetric';
  const customMetric: CustomMetric[] = [
    {
      dimensionName: 'Metric',
      dimensionValue: 'Metric1',
      value: 30,
    },
    {
      dimensionName: 'Metric',
      dimensionValue: 'Metric2',
      value: 60,
    },
  ];
```
10分ほどデータを流して、ApplicationInsightsで確認する。
`testMetric`というメトリック名で、ディメンション別にグラフ表示できていることを確認できた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956153/efc8c684-81b7-cf0d-dc66-d1f9c3f80e1a.png)
【個人用】AWS Solution Architect Associate対策ノート(セキュリティ＆コンプライアンス編)

## 扱う内容

・WAF
・Shield
・KMS
・CloudHSM


# 【KMS】

## KMSで使う２種類の鍵

### データキー
データを暗号化する鍵
暗号化するデータの分作らなければならない

### KMSキー
**データキー**を暗号化する鍵

2段階で鍵を保護する方式を**エンベロープ暗号化**という

## KMSキーの管理体制

### AWSマネージド型
鍵の生成、管理はAWSが行う
ユーザーは鍵の削除はできない

### カスタマーマネージド型
鍵の生成、管理、削除はユーザーが行う
(CloudHSMと違い、多少はAWS側も手伝ってくれる)
鍵の**自動ローテーション**機能がついている

## KMSのキーポリシー

**KMSキーポリシー**は、KMSキーに適用するリソースベースのポリシー
鍵に対して、IAMユーザーまたはIAMロール、他のAWSアカウントに対して操作可能な権限を設定する

鍵の作成者とは異なるIAMユーザーやIAMロールが複合したい場合、**キーユーザー**に追加することで複合できるようになる

# 【CloudHSM】

## CloudHSMとは

**専用のハードウェアデバイス**を用いて、暗号化鍵を生成、管理する
鍵の生成や保管、削除などは何から何まで完全にユーザー側で行わなければならない

# 【Shield】

## Shieldの種類

### Shield Standard
普通のShield
DDoS攻撃から守ってくれる

### Shield Advanced
ちょっと高級なShield
高度な保護サービスを利用できる
EC2インスタンス、CloudFront、NLBを守ってくれる

# 【WAF】

## WAFの保護対象

・API Gateway
・ALB
・CloudFront
ConstraintLayoutで割合幅を指定する

ConstraintLayoutで親の幅に対して子の幅を割合で指定できるようにする。
Guidelineを使用します。`orientation`に`vertical`、`layout_constraintGuide_percent`に決めた割合値を入力する。幅を決めたいTextViewはGuidelineの位置に従い制約をつける。そうすることで割合幅を指定できる。3等分、4等分したい場合は、その数だけGuidelineを追加して、3つ目、4つ目の制約場所を決める。
下記コードは3等分した場合のサンプルコード

``` xml
<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#fff"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="parent">

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.25" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.85" />
 
    <TextView
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:background="#ff3"
        android:text="左側"
        app:layout_constraintEnd_toEndOf="@id/guideline"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:background="#f3f"
        android:text="真ん中"
        app:layout_constraintEnd_toStartOf="@id/guideline2"
        app:layout_constraintStart_toStartOf="@+id/guideline"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:background="#33f"
        android:text="右側"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/guideline2"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
```
#### 参考
https://qiita.com/devnokiyo/items/59d72bf285ee378ef637#%E7%B8%A6%E6%96%B9%E5%90%91%E3%81%AB%E5%88%86%E5%89%B2%E3%81%97%E3%81%9Fguideline
早寝促進システム HotaruNoHikari を作った

## はじめに
遅く起きると、1日が無為に終わってしまうことが多い。
早く起きるために一番大事なことは早く寝ることなので、
早寝のためのシステムを作った。


Webアプリでアラームを設定しておき、
設定した時間になると[蛍の光](https://ja.wikipedia.org/wiki/%E8%9B%8D%E3%81%AE%E5%85%89)が流れ、一定時間が経過すると強制的に消灯する。

#### デモ
アプリ操作画面（スマホ）
<iframe width="560" height="315" src="https://www.youtube.com/embed/LX52D042yXo?si=GjLCckaqRGvXi4t_" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

アラームシステム
<iframe width="560" height="315" src="https://www.youtube.com/embed/bSePok_vbEg?si=OJ4lKKxQ-cQtlS47" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

## システム構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581044/6eec5daf-dfc0-329f-b9fa-3f0673bcb34b.png)

使用機器
- [Raspberry Pi 3 Model B+](https://www.raspberrypi.com/products/raspberry-pi-3-model-b-plus/)
- [Apqfw PC スピーカー](https://www.amazon.co.jp/dp/B0CR5WQ2PZ?ref=ppx_yo2ov_dt_b_fed_asin_title)
- [SwitchBot](https://www.switchbot.jp/products/switchbot-bot)

### Webアプリ
#### 使用技術
- フロントエンド：React
- バックエンド：C# ASP.NET
- データベース：MySQL(RaspiではMySQLが使えなかったためMariaDBで代替)
#### 機能
- 新規アラーム設定の追加
- アラーム設定の編集
    - 有効・無効
    - アラーム時間
    - 再生する音楽の選択
    - スイッチのON・OFF
    - スイッチが作動するまでの時間
- アラーム設定の削除


### アラート（音楽再生＆SwitchBot操作）アプリ
#### 使用技術
- コンソールアプリ：C#
- スクリプト
    - SwitchBot操作：Python
    - 音楽再生：Python
- データベース：MySQL(RaspiではMySQLが使えなかったためMariaDBで代替)

#### 機能
- 有効なアラーム設定がないか監視する
- 音楽をスピーカーで再生する
- Bluetooth通信でSwitchBotを制御する

## GitHub

https://github.com/ikenohotori/HotarunoHikari

※ フォルダ構成をミスして上手くGitに公開できないため、Webアプリのソースのみ。

## 感想
#### ラズパイでASP.NETアプリを動かせるようになった
ここが一番苦労した。WindowsPC上で動かしていたものをラズパイ（Linux）上で動かすのに試行錯誤した。
Linuxでdotnetコマンドを動かすのと、PCからラズパイにアクセスするためのルーティング設定に時間がかかったが、先人のおかげで動かせた。感謝。

自分が動かした時の方法は以下にまとめた。
[Raspberry PiでC#（ASP.NET）のWebアプリを動かす](https://qiita.com/ikenohotori/items/22b75d401cf7fe09d2d0)

#### はじめてReactでアプリを作った
初めてReactでアプリを作成した。最初は全部の実装をApp.tsxに書いていたが、コンポーネントを分割し、CSSを別ファイルに分けて、と徐々に細かくしていくのが楽しかった。また、MUIを使うだけでまあまあのデザインで出来てしまうので、モチベーションが保持できて嬉しかった。

#### 続けることは難しい
せっかく機器まで購入してシステムを作ったが、動作確認の日以外で一度も使ってない。スマホのアラームは必ず使うので、それ以外でブラウザを起動して何かを設定するのが煩わしい。普段の生活で使えるものを作りたい。
GASの値をスプレットシートに送る

## 概要

GASで生成した値を任意のスプレットシートに送って保存する方法を簡単にまとめる。

## 前提

- 中身が記載されていない「make_graph」というGASのプロジェクトが作られていること
- 任意のスプレットシートが作られていること

※今回はGASで生成した1~30までのランダムな数字をGASの実行毎にスプレットシートに記入していってみる。

## 内容

1. 下記のコードをGASに記載（スプレットシートのIDはブラウザでスプレットシートを開いたときのURLの`https://docs.google.com/spreadsheets/d/xxxxxxxxxxxxxxxxxxx/edit?`のxxxxxxxxxxxxxxxxxxxの部分のはず）

    ```js
    function makeGraph() {
      // スプレッドシートIDを指定
      var spreadsheetId = '1dEx9lyqlLIJbrepQvmJM7V4T0QuKPGkOJ25mJ9OsVkY';
      
      // スプレッドシートを開く
      var sheet = SpreadsheetApp.openById(spreadsheetId).getActiveSheet();
      
      const min = 0;
      const max = 31; // 上限が除かれるためあえて31を指定、本来ならgetRandomInt()の中を修正すべき
      const value = getRandomInt(min, max);
    
      // スプレッドシートに追加
      sheet.appendRow([value]);
    }
    
    function getRandomInt(min, max) {
      const minCeiled = Math.ceil(min);
      const maxFloored = Math.floor(max);
      return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled); // 上限は除き、下限は含む
    }
    ```

1. 上記のコードを保存しGASの「実行」をクリック

    ![CleanShot 2025-01-11 at 01.35.45@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/d334bc46-9791-7adb-7082-27b5dc0f5690.png)

1. 認証が必要な旨のポップアップが初回のみ出るはずなので「権限を確認」をクリック

    ![CleanShot 2025-01-11 at 01.19.31@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/bf468918-f557-13d6-0f79-e3ffcd86cb2a.png)

1. 別画面が開くはずなのでGoogleアカウントでログイン後、下記の様な画面が出ることがあるのでご自身の責任において「詳細」→「make_graph（安全ではないページ）に移動」をクリック

    ![CleanShot 2025-01-11 at 01.20.49@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/8eb554cd-86b3-2791-f4d9-7572d5dc09bb.png)
    ![CleanShot 2025-01-11 at 01.21.50@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/a096f69a-12a6-b96f-d0a9-2aa11fa71da2.png)

1. ご自身の判断で「許可」をクリック

    ![CleanShot 2025-01-11 at 01.22.52@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/b71f4f98-caf6-b8db-c09b-ed3966228a8c.png)

1. 実行が完了し、指定したスプレットシートにデータが記載されていれば完了（実行のたびにA列に数値が追加され続ける）

    ![CleanShot 2025-01-11 at 01.36.54@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/eb4680e1-6ff3-f535-a054-880789106cf1.png)

## 参考文献

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/random#2_%E3%81%A4%E3%81%AE%E5%80%A4%E3%81%AE%E9%96%93%E3%81%AE%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E3%81%AA%E6%95%B4%E6%95%B0%E3%82%92%E5%BE%97%E3%82%8B
Linuxでもmacみたいなライブ変換がしたい！

Linuxを使っていると感じる不便ポイントの一つに、変換がだるいというのがあると思います。
（macOSのライブ変換機能は素晴らしいです）
これをLinux上で行えるようにしていこうと思います。

# fcitx5-hazkey
[fcitx5-hazkey](https://github.com/7ka-Hiira/fcitx5-hazkey)はAzooKeyKanaKanjiConverterを利用したIME、だそうです。
もちろん依存関係としてFcitx5が必要です。

# インストール
AURからインストールすることができます。
```
yay -S fcitx5-hazkey-bin
```

ニューラル漢字変換システムZenzaiを利用するともっと制度の良い変換ができるそうですが、個人的にはなくても困っていません。

# Post installation
ログアウト/ログイン後、fcitx 5設定を起動して、右のリストからhazkeyを選択し左側に追加します。

これでライブ変換が使用できるようになったはずです。
さくらのVPSで複数のVPSをスイッチで繋ぎ、スイッチ経由で通信しようとしてつまずいた話

## 前提・注意事項

- さくらのVPSを同一リージョンで複数契約している
- VPS同士をスイッチで繋いでいる
- OSはUbuntu
- ポート開放の話は省略します

## 単語についての説明

#### 公開サーバー
インターネットに対して直接アクセスすることができるサーバー

#### 内部サーバー
公開サーバーを経由しないとインターネットに接続できないサーバー

## つまずいた点１　プライベートIPアドレスの割り当て

これについてはそこまで厄介な話ではなく、`/etc/netplan/01-netcfg.yaml`スイッチを設定しているイーサネットアダプターに対してIPアドレスを割り当ててあげるだけのシンプルなお話でした

```yaml: /etc/netplan/01-netcfg.yaml（公開サーバー）
(前略)
"ens4":
      dhcp4: false
      addresses:
        - 192.168.1.1/24
      nameservers:
        addresses:
          - 127.0.0.1
```

```yaml: /etc/netplan/01-netcfg.yaml（内部サーバー（例））
(前略)
"ens3":
      dhcp4: false
      addresses:
        - 192.168.1.2/24
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses:
          - 192.168.1.1
```

私の場合は公開サーバーで内部サーバーに対してDNSを提供して通信を行うようにしている関係上、ネームサーバーが公開サーバーのIPアドレスになっていますが、ここはご自身の環境に合わせて変えて下さい。

最後に`sudo netplan apply`でIPアドレスの割り当ては完了となります。

## つまずいた点２　内部サーバーがインターネットにアクセスできない

これはただ公開サーバーでこれ叩いただけ。正直解説いらんような気もする

```bash
sudo apt-get install iptables-persistent
sudo iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE
sudo iptables -A FORWARD -i ens4 -o ens3 -j ACCEPT
sudo iptables -A FORWARD -i ens3 -o ens4 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo netfilter-persistent save
sudo netfilter-persistent reload
```

## つまずいた点３　プロキシジャンプで内部サーバーへSSH接続できない

実はこれがものすごく解決に時間かかりまして、原因が分からないまま３日も作業してしまいました。
そもそも公開サーバーからダイレクトにSSHもできなかったので…。

まあこれについてもすっごくばかばかしい話でした。

```ssh: sshd_config
ListenAddress 192.168.1.2
```

sshd_config見たらこのListenAddressに、このVPSに割り当てられたグローバルIPアドレスが書かれていて、それに気づいた時は「あ、こいつが原因だったのかよ…」って思いましたね。
そして最後に`sudo reboot`で完了です。
`sudo systemctl restart ssh.service`で良いんじゃないかと思う人もいるかと思うんですけど、それだとListenAddressが更新されなかった＋他にもやってたから一括でアップデートしちゃえ精神で再起動しました。

## 最後に

まあそもそもこんな面倒なこと、個人レベルでやるほどのことって何やってんだって思うかもしれないんですが、これ実はゲームのサービス用サーバーとデータベースサーバーを分離したくてこんな面倒な作業してたわけでして、そうでもなければこんなくそめんどくさいことしたいなんて考えません。
もし私と同じようなことをしようと思って同じことでつまずいた人がいたらこれを参考にしてもらえればと思います。
ラズパイ　赤外線でエアコンの消し忘れを自動で消す、人がいる時にエアコンの暖房自動ONを実現　ジャンプ

# １号機で設定
１．人が居る時にエアコンの暖房自動ONを実現。　heater_on_check.pyを作成。
2号機での人感センサーで人が検知されたら、1号機で情報を取得して、エアコンをオンにする。heater_on.pyで起動。（11度未満であればエアコンをオンにする。）
```
!/usr/bin/ python3
from datetime import datetime
import time
import subprocess
import mysql.connector

print(datetime.now().strftime('%Y/%m/%d %H:%M:%S'))

cmd = "sudo python3 /home/pi/heater_on.py"

# db connect
def main():     
# mysql connect 
    cnt = mysql.connector.connect(
    host='miyamodb',
    port='3306',
    db='miyamodb',
    user='miyamo',
    password='miyamoXXXX',
    charset='utf8'
    )

    db = cnt.cursor(buffered=True)   

#room_env select
#    sql = 'select kenchisw from jinkan_kenchi where id = 1'

    db.execute('select kenchisw from jinkan_kenchi where id = 1')

# display & check
    for record in db:
        print('kenchisw=', record[0])
    if record[0] == '1':
        print("heater_ON")
        subprocess.check_call(cmd, shell=True) 

# db.close
    db.close()
# cnt.close
    cnt.close()

if __name__ == "__main__":
    main()
```
２．仕上げ　crontab登録
```
sudo crontab -e
```
中身は以下
0 7 * * * cd /home/pi/ && /usr/bin/python3 /home/pi/heater_on_check.py > /tmp/cronh.log 2>&1

# 完成
せっかく図書館で借りた、動画編集の本、読んでいないので、明日から勉強しよう。
[🔰初心者向け]Dockerを初歩から学びたい方へ🐋 ~全9回~

## はじめに
こんにちは！ITスクールRareTECHにてCS（Customer Support）を担当している池村です。好きな技術はシェル周り全般、Go、Pythonはある程度書けます。最近はRust🦀の勉強もしています。

今回の記事は、今まで投稿してきた**Docker連続記事をまとめた記事**になります。

これは完全に初めてDockerを触る人向けであり、エンジニアの方の軽い復習用でもあります。Docker興味あるけど、どうやって勉強したらいいんだろう？という方はぜひ読んでみて下さい。

:::note info
ただ、Dockerをやる前にLinuxの基礎コマンドくらいは叩けるようになっている方、を対象にしていますのでご注意ください。
:::



![ccbfa902-1ef0-4466-a63e-2d6428512466_720.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/117af4d8-3fee-1609-56af-4272875ea7cd.png)


## ①コンテナのライフサイクル編 🐳
何をいってもまずはここから。
コンテナがどういった手順でできているのか？コンテナがイメージから作られて、動き出し、止まるまでの間を解説しています。

https://qiita.com/ikemura-ren/items/dae9f599254b90167b06


## ②コンテナの中に入ってみよう編 🐳
コンテナが動いている時、その中に入ってLinuxコマンドで色々なことが出来ます。コンテナの中に入ることは必須技術であり、初学者はしっかり押さえておきたいですね。

https://qiita.com/ikemura-ren/items/3b5667eee6e83a63d0b2

## ③コンテナとイメージの削除編 🐳
コンテナを動かしたら、消すまでが一連の流れです。
コンテナだけでなく、その土台になっているイメージも消すことが出来ます。コンテナのお片付け編といっても過言ではないですね。

https://qiita.com/ikemura-ren/items/8bad27179b09cd507e2c

## ④コンテナのボリューム編 🐳
ここから少し難しくなってきます。コンテナの中のデータはコンテナを削除するともちろん消えてしまうので、どう永続化していくのだろう？というお話です。こちらもコンテナ運用には必須知識です。

https://qiita.com/ikemura-ren/items/221cf630ad03fb4b41b3

## ⑤バインドマウント編 🐳
こちらはボリュームの記事の続きになっています。Webアプリ制作などでは必須の知識になっており、コンテナとホスト（自分のPCとかサーバーとか）のデータをどう繋げるのか？という部分です。アプリ作れるようになるには必須知識です。

https://qiita.com/ikemura-ren/items/d9de3d767bdeca3bf089

## ⑥Dockerのネットワーク編 🐳
コンテナの中にどうやって外からの通信を送るのか？コンテナ間の通信はどうするの？といった内容になっています。かいつまんで解説していますのでぜひ読んでみて下さい。

https://qiita.com/ikemura-ren/items/0e6071f26a847366e585

## ⑦Dockerfileについて 🐳
基礎的な部分は⑥まで。ここからコンテナ作成をどう楽にしていくのかを考えていきます。Dockerfileはその手段のひとつであり、Dockerの鬼門のひとつだと思っています。なるべく初学者にも分かるように解説していますのでご覧ください。

https://qiita.com/ikemura-ren/items/3debbe2ba8997a95e6b5

## ⑧Docker Composeの基礎 🐳
Docker Composeはコンテナを一元管理してくれる便利な技術です。しかしここまでの基本的な概念知識を理解していないと、必ず詰まります。難しいです。でもここまでの記事の内容を押さえた方なら大丈夫。頑張って学んでいきましょう。

https://qiita.com/ikemura-ren/items/7296576db5b5ce5c60e5

## ⑨Docker Composeによる複数コンテナの運用 🐳
前回の⑧の記事ではDocker Composeで単一コンテナを作ってみましたが、これだけなわけがありません。複数コンテナを運用してこそComposeの本領発揮です。Dockerを初歩から学んできた方は一旦ここがラストです。しっかり知識を見につけていきましょう！

https://qiita.com/ikemura-ren/items/2140694831149324b258

## おわりに
今回は今まで書いてきた初心者向けのDocker基本記事、全9回分をまとめました。
あくまで初心者用です。今後は中級者向けの記事も書いていきますので、よかったらまた見ていって下さい。


## 宣伝
ITスクールRareTECHを運営しています！スクール受講生の皆さんがたくさん記事を投稿しているので、よかったらみていってください！
Organizationはこちら👇

https://qiita.com/organizations/raretech
React 18のSuspenseについて

こんばんは。

今日は「React 18のSuspenseについて」について説明します。

Suspenseは、Reactコンポーネントが非同期のデータを必要とする際に、そのコンポーネントが「読み込み中」であることをReactに伝える仕組みです。これにより、データの取得が完了するまでコンポーネントのレンダリングを遅延させたり、ローディングインディケーターを表示することができます。

# React 18でのSuspenseの主な改良

## React Server Components

React 18では、Server Componentsが追加され、サーバーサイドで非同期データを直接フェッチしてクライアントに渡すという新しいパターンが可能になりました。Suspenseはこれをサポートしており、サーバーからのデータ取得を待機してからUIを描画することができます。

## データフェッチのための`Suspense`

React 18では、`Suspense`を使って非同期のデータ取得をサポートするために、`React Suspense Data Fetching`という新しいAPIが導入されました。このAPIを使用すると、`Suspense`のコンポーネントが非同期のデータを待機している間に、Reactがローディング状態やエラーハンドリングを簡単に行うことができます。

## 並列非同期処理

React 18では、複数の非同期操作が並列で実行される際の処理が改善されました。これにより、データ取得が複数のコンポーネント間で分散している場合でも、効率的に並行して読み込むことができます。

# `Suspense`の使い方

通常、`Suspense`を使用する際には、fallbackプロパティを指定して、データが読み込まれていない間に表示されるコンテンツ（例えば、ローディングインジケーター）を定義します。以下は、React 18での基本的な例です。

## 例 1: Suspenseを使った非同期データのフェッチ

```React
import React, { Suspense } from 'react';

// 非同期データをフェッチするコンポーネント
function MyComponent() {
  const data = fetchData(); // 非同期データ取得
  return <div>{data}</div>;
}

// Suspenseを使ってローディングインジケーターを表示
function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <MyComponent />
    </Suspense>
  );
}

export default App;
```

## 例 2: React QueryとSuspenseの統合

React Queryのような外部ライブラリと組み合わせることで、より強力な非同期データ管理が可能です。React Queryは`Suspense`をサポートしており、データがローディング中の間にUIを遅延させることができます。

```React
import React, { Suspense } from 'react';
import { useQuery } from 'react-query';

// 非同期データをフェッチするフック
function fetchData() {
  return fetch('https://api.example.com/data')
    .then(res => res.json());
}

function MyComponent() {
  const { data } = useQuery('data', fetchData, { suspense: true });
  return <div>{data}</div>;
}

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <MyComponent />
    </Suspense>
  );
}

export default App;
```

## 注意点

### エラーバウンダリ

`Suspense`は非同期処理が失敗した場合、エラーを表示する方法を提供しません。そのため、`ErrorBoundary`を使用して、エラーが発生した場合に適切に処理することが推奨されます。

### 並行レンダリングの有効化

React 18では、並行レンダリング（Concurrent Rendering）がデフォルトで有効になり、Suspenseがより強力に動作します。非同期の操作が行われている間に他の作業を並行して行うことができます。

# 結論

React 18の`Suspense`は、コード分割やデータフェッチの待機など、非同期処理をより効率的に扱うための重要なツールです。これにより、ユーザー体験が大幅に向上し、より滑らかなUIの遷移が可能になります。また、React QueryやGraphQLといったデータ管理ライブラリと組み合わせることで、さらに強力な非同期処理が実現できます。

今日は以上です。

ありがとうございました。
よろしくお願いいたします。
JetBrains IDEが重い時の設定見直しポイント【IntelliJ/PyCharm/PhpStorm/GoLand】

## 1. メモリ設定
- `idea.vmoptions`ファイルで設定
- `-Xms`: 初期ヒープサイズ（メモリの25%）
- `-Xmx`: 最大ヒープサイズ（メモリの50%）

例）16GBメモリの場合：
```
-Xms2048m
-Xmx8192m
```

## 2. プラグイン
- Settings > Plugins から不要なプラグインを無効化
- 特に未使用の言語サポートやバージョン管理系を確認

## 3. インデックス
- File > Invalidate Caches でインデックスを再構築
- Settings > Project Structure で不要なディレクトリを除外
  - build出力
  - 依存関係キャッシュ
  - ログディレクトリ

## 4. エディタ設定
- Settings > Editor > Inspections で不要な検査を無効化

## 5. キャッシュ管理
- Settings > System Settings でキャッシュサイズを調整
- 定期的なキャッシュクリアと IDE の再起動

## 改善されない場合の最終手段
Power Save Mode（省電力モード） の活用
以下の機能が無効化されるので効果は高いがデメリットも大きい
- 無効化される主な機能：
    - コードの自動補完
    - エラーチェックやコード解析
    - 自動バックグラウンドコンパイル
    - VCS（Git等）の自動更新
    - 外部ファイルの自動同期
    - プラグインの自動更新チェック
普段はPower Save Modeをオンにしておき、コードの補完・エラーチェックなどをしたい時だけオフにするという使い方をするのがよい
AIとの協業による効率的な開発 - Overview Firstアプローチの実践

## はじめに
AIアシスタントとの協業が一般的になってきた今日、より効率的な開発プロセスを確立することが重要になっています。本記事では、**Overview First**アプローチを中心に、AIとの効果的な協業方法について、実践から得られた知見を共有します。

## 本記事で得られること
- AIアシスタントと協業する際の具体的な手順
- 効率的な開発を実現するためのプロジェクト構造化の方法
- 知識を継続的に蓄積・活用するためのドキュメント管理手法
- トラブルを未然に防ぐためのテスト戦略

## Overview Firstアプローチとは
Overview Firstとは、「実装を始める前に必ず概要の確認から始める」というアプローチです。

```mermaid
sequenceDiagram
    participant D as 開発者
    participant AI as AIアシスタント

    Note over D,AI: フェーズ1: 概要設計
    D->>AI: 機能要件を説明
    AI->>D: 実装概要の提案
    D->>D: 内容確認と課題特定
    D->>AI: 要件の詳細化
    AI->>D: 更新された概要
```

このアプローチには以下のような利点があります：

1. 実装前に不明点や欠落を発見できる
2. 自身の要件の曖昧さに気づける
3. AIとの認識齟齬を早期に解消できる
4. 全体の見通しを立ててから実装に入れる

## プロジェクト構造の整理

### 1. 明確なディレクトリ構造
プロジェクトの開始時に、以下のような点に注意してディレクトリ構造を確立します：

```
project/
├── src/           # ソースコード
│   ├── components/  # 再利用可能なコンポーネント
│   ├── modules/    # 機能モジュール
│   └── utils/      # ユーティリティ関数
├── tests/         # テストコード
├── docs/          # ドキュメント
│   └── adr/       # アーキテクチャ決定記録
└── config/        # 設定ファイル
```

### 2. モジュール分割のポイント
- 機能ごとに適切な単位でファイルを分割
- 1ファイルは400行程度に抑える
- 依存関係を明確にし、循環参照を防ぐ
- インターフェースを明確に定義

## AIとの効果的な協業プロセス

### 1. 設計フェーズ
Overview Firstアプローチに基づき、以下の手順で進めます：

```mermaid
sequenceDiagram
    participant D as 開発者
    participant AI as AIアシスタント
    participant ADR as ADR/文書
    participant Code as コード/テスト

    Note over D,AI: 概要確認
    D->>AI: 機能要件を説明
    AI->>D: 実装概要の提案
    D->>ADR: 設計決定を記録

    Note over D,AI: 実装
    D->>AI: コード生成依頼
    AI->>Code: コード生成
    D->>Code: レビューと修正
```

### 2. 実装フェーズ
AIの得意分野を活かしつつ、以下の点に注意して進めます：

- 単体機能の実装はAIに任せる
- 複雑な統合部分は人間が主導
- コードレビューはAIに依頼
- 継続的な改善サイクルを回す

## 知識の継続的な記録

### 1. ADR（Architecture Decision Record）の活用
重要な設計決定を以下の形式で記録します：

```markdown
# ADR 1: Overview Firstアプローチの採用

## 状況
- AIとの協業において、実装前の認識合わせが不足
- 要件の曖昧さによる手戻りが発生

## 決定
- 実装前に必ずAIに概要説明を求める
- 概要の確認後にコード生成を行う

## 結果
- 実装前の課題発見が可能に
- AIとの協業がスムーズに
```

### 2. ドキュメント管理のコツ
- プロジェクトの文脈を常に文書化
- 長いチャットは適宜マークダウンに保存
- APIドキュメントなど仕様書を整備
- テスト仕様も文書として管理

## トラブルを防ぐためのテスト戦略

### 1. テスト設計のポイント
1. テスト駆動開発を基本とする
2. AIを活用してテストケースを生成
3. カバレッジ目標を設定
4. エラーケースの網羅的なテスト

### 2. 安全性の確保
1. GETなど安全な操作から着手
2. データ変更操作は慎重にテスト
3. 本番データへの影響を防止
4. テストの分離と独立性を確保

## AIの限界を理解する

### AIの得意分野
- 単体機能の実装
- テストコードの生成
- コードレビュー
- ドキュメント作成支援

### 人間が主導すべき領域
- アーキテクチャの決定
- 複雑な状態管理
- セキュリティ要件の判断
- ビジネスロジックの実装

## 効率的な開発の実現

### 1. 開発速度の向上
- AIによる定型作業の自動化
- テンプレートとボイラープレートの活用
- 再利用可能なコンポーネントの蓄積
- レビュープロセスの効率化

### 2. 品質の確保
- 一貫した命名規則の適用
- コードスタイルの統一
- 適切なエラー処理
- パフォーマンスの考慮

### 3. コミュニケーション
- 設計意図の明確な文書化
- チーム内での知識共有
- レビューコメントの活用
- 問題点の早期発見

## まとめ

1. **構造化された設計**: 明確なプロジェクト構造と設計方針を確立
2. **AIの適切な活用**: AIの得意分野を理解し、効果的に活用
3. **継続的な文書化**: ADRとドキュメントによる知識の蓄積
4. **安全なテスト**: 段階的なテストと安全性の確保
5. **役割の明確化**: AIと人間の適切な役割分担
6. **効率的な開発**: 自動化と再利用による生産性向上
7. **品質の重視**: 一貫性のある高品質なコードの維持
8. **知識の共有**: チーム全体での設計知識の活用

## 参考資料
- [AIエージェントを使って10倍早く工場OTデータシミュレータを開発してしまった記録と旧来型開発ビジネスの終焉](https://note.com/amatatsuk/n/n88ba32723a3d)
- [LLMによるADRの自動更新：設計知識の継続的な記録と活用](https://tech.jugoya.ai/blog/adr-with-llm)
- [This Simple Prompt Saved Me Hours of Debugging (Reddit Post)](https://www.reddit.com/r/cursor/comments/1hwt5nx/this_simple_prompt_saved_me_hours_of_debugging/)
【Zed】ファイルファインダーの幅を変更する方法

`settings.json`に以下の設定を追加することでファイルファインダーの幅を変更できます。

```settings.json
{
  "file_finder": {
    "modal_max_width": "xlarge"
  },
}
```

- 変更前

![スクリーンショット 2025-01-10 23.55.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/1ff37ced-c5bb-e2d0-a8b7-7d2a65e80503.png)

- 変更後

![スクリーンショット 2025-01-10 23.56.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/9cc29932-3593-688b-43be-1fdc2862d961.png)
(DAY17) 俺と学ぶRust言語~ジェネリクス~

# 今日の内容
- ジェネリクス

# はじめに
[前回](https://qiita.com/FUKAch/items/d0fc6e96dcd400fa3f87)は、BlackJackを完成させました。しかしながら、このシリーズの軌道が少しずれてきていた気がしたので、いったん戻ります！
今回は **ジェネリクス** について学びます。

# ジェネリクスとは
**ジェネリクス** は、「特定の型に依存しないコードを書く」ための仕組みです。
Rustでは、ジェネリクスはプレースホルダのように使われ、コードを書くときには型を指定せず、コンパイル時に具体的な型が決まります。

この機能はどのような場面で使えるでしょうか？
関数で異なる型の引数を処理したり、構造体や列挙型で任意の型を格納する時などに使えます。

# 関数でのジェネリクス
ジェネリクスを使うと、異なる型の引数でも処理できる汎用的な関数を作成できます。
```rust
fn get_larger<T: PartialOrd>(a: T, b: T) -> T {
    if a > b {
        a
    } else {
        b
    }
}

fn main() {
    println!("{}", get_larger(10, 20));
    println!("{}", get_larger(1.2, 3.4));
}
```
- <T>: ジェネリック型を定義
- T: PartialOrd: トレイトを実装してTが比較可能であることを指定

ここでのポイントは、ジェネリクスは **型安全** で、どの型にも対応するわけではありません。
必要に応じて **トレイト境界** を追加して型の制約を設定できます。

# 構造体でのジェネリクス
ジェネリクスを使って、構造体のフィールドに複数の型を持たせることができます。
```rust
struct Point<T> {
    x: T,
    y: T,
}

fn main() {
    let integer_point = Point { x: 1, y: 2};
    let float_point = Point { x: 3.0, y: 4.0};

    println!("Integer Point: ({}, {})", integer_point.x, integer_point.y);
    println!("float Point: ({}, {})", float_point.x, float_point.y);
}
/******** 実行結果 ********
Integer Point: (1, 2)
float Point: (3, 4)
*************************/
```
- `<T>`は任意の型を表す
- `Point<T>`はどの型でも扱える汎用的な構造体

# 列挙型でのジェネリクス
列挙型もジェネリクスを使って柔軟に設計できます。
```rust
fn main() {
    let some_number = Some(5);
    let some_string = Some("Hello");

    println!("{:?}", some_number);
    println!("{:?}", some_string);
}
/******** 実行結果 ********
Some(5)
Some("Hello")
*************************/
```
Rust標準ライブラリの **Option型** はジェネリクスを活用した代表的な例です。
Option型は次回学びます。

# トレイト境界
ジェネリクスを使う場合、ある特定のトレイトを実装した型だけを許可することができます。これを **トレイト境界** と呼びます。
```rust
fn print_display<T: std::fmt::Display>(value: T) {
    println!("{}", value);
}

fn main() {
    print_display(123);
    print_display("Hello");
    // print_display(vec![1, 2, 3]);
}
/******** 実行結果 ********
123
Hello
*************************/
```
「123」という整数や「Hello」というような文字列は`Display`を実装していますが、Vecは実装してないので、`print_display(vec![1, 2, 3]);`はエラーになります。

# おわりに
今回はRustでのジェネリクスについて学びました。
次回は、Option型について学ぼうと思います。
ご精読ありがとうございました。
WordとPowerPointのCopilotでの画像認識活用アイデア

# WordとPowerPointのCopilotでの画像認識のアップデートがきているよ～
12月度の更新で、Copilotの右側のペインから画像をアップロードまたはペーストして、画像つきでプロンプトが入力できるようになっています。どんな感じでつかえるかちょいと見ていこうと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/aa0a0675-aa1e-2a22-beba-32b757873f2d.png)

https://techcommunity.microsoft.com/blog/Microsoft365InsiderBlog/add-images-to-your-copilot-prompts-in-word-and-powerpoint/4359423 

## 文字認識
キャプチャの文字起こしをOCR的にしてもらいました。いいかんじ。翻訳とか要約もついでにできそう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/4a562542-3317-def7-8bbd-959f33792f05.png)

画像内の表をもう一度表形式にしてもらう
これ、地味に元ファイルがないときとかに使えそう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/a758b3eb-7d4b-e41f-4fac-48e5aa3300b8.png)

ちょっとやってないですが、手書きのメモの文字起こしや
キャプチャした申込書から特定の項目の文字取り出しとかもできそうですね。

## フロー図説明
フロー図の意図がわからないときに補助的に聞いたり、
パワポで作ったフロー図をそのままマニュアル化するときに使えるかも
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/bd65cb45-b9b7-0051-0c12-c98f27f1c227.png)

フロー図のコンサルもしてくれます。
ここではざっくり改善点と聞いてますが、フロー図の書き方あるいはフロー自体のコメントもしてくれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/41c548a4-da19-f087-f4f9-c5ac32c68628.png)

## パワポコンサル
自分が作ったスライドについてキャプチャすれば、そのままCopilot先生に意見をもらうこともできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/5db6c7f1-bfbe-8ba5-22e0-2f3a12ec7c41.png)

より詳細に聞きたいときは「具体的な改善例は？」などときいてみるといいかも。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/0729b0d2-882c-01e2-21a5-d3809d19903e.png)

パワポに自信がない方にはけっこうよさげじゃないでしょうか。
あと理解しにくいパワポについて「一番言いたいことは？」と聞くのもありかもですね。

## 手作業系コメントの集約
以下はMicrosoft Whiteboardで出し合った意見のまとめですがめっちゃありがたい。物理的なホワイトボードも文字が汚すぎなければうまくできると思います。
WhiteboardでもCopilotを使って要約（Loop）ができますが、まだまだいまいちなのでこっちのが実用的。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/2e1ba8b1-e5a2-d098-12b0-c3555ed95865.png)

## 説明が難しい画像の説明
高尚な画像もパワポやWodで表現したいとき用にうまく説明してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/7419a80a-09ca-2488-69cd-f9b00442a28e.png)

## スライドに合った挿絵づくり
うーんこれは、プロンプトをちゃんと打ったほうがいいかもしれない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/8c1017d0-7c97-64d6-4c24-f2ca3e036c44.png)

## おわりに
Word、PowerPointあんま関係ない使い方もありますが、、
作成中の資料の中で、すぐに調べたり使いたいときに右で作業できるのがめっちゃいい。
画像認識、意外と使えそう！！これが今後PowerPoint等でオブジェクトつくってくれるようになれば、資料作成も楽になりそうですね。
【Volta】zsh: command not found: nodeの解決方法

#  はじめに
`Volta`を使用して`node`を再インストールした際に、想定外のエラーが発生しました。本記事ではその解決方法を共有します。

:::note warn
***この記事は<font color="Red">個人的なアウトプット</font>を目的として作成したものです。そのため、誤った情報や不足している内容が含まれている可能性があります。もし間違いや気になる点がございましたら、ぜひご指摘いただけますと幸いです***。
:::

# 問題
`Volta`で`node`をインストールした後、`node`のバージョンを確認しようとしたところ、以下のエラーが出力されました。

```bash
node -v
zsh: command not found: node
```

このエラーは、`node`がインストールされていないか、正しく認識されていない場合に発生します。

# 解決方法
ターミナルに以下のコマンドを入力して、`Volta`のパスを環境変数に追加します。

```bash
export VOLTA_HOME="$HOME/.volta"
export PATH="$VOLTA_HOME/bin:$PATH"
```
再度`node`が正しくインストールされているか確認します。

```bash
node -v
v22.13.0
```
これでエラーは解消され、`node`が正しく動作するようになりました。

# 終わりに
環境構築時にはパス設定が重要であると再認識しました。今後もエラーに直面した際には丁寧に原因を調査し、解決策を学んでいきます。

# 参考

『あれ？ Voltaを使ってるんだけど「node」にPATHが通ってないぞ？』　Qiita

https://qiita.com/YOS0602/items/c694780773b091b4218c

『Node.jsのバージョン管理にVoltaを推したい』　Zenn

https://zenn.dev/taichifukumoto/articles/how-to-use-volta#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%95%E3%82%8C%E3%81%9F%E3%81%93%E3%81%A8%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B