OmniAICreator/Qiita-1.07M huggingface dataset:
Ollama + Open WebUI でFugaku-LLMを利用する

# はじめに
本記事はFugaku-LLMのお試し環境を構築するために、主に以下の2つの記事を参考にさせていただきながら手順や個人的にハマったところを記録したものになります。参考になれば幸いです。

>①

https://zenn.dev/karaage0703/articles/c271ca65b91bdb

>②

https://zenn.dev/tos_kamiya/articles/9d8ce89bb933b1

## 環境構築に用いたマシンのスペック
2万円の再整備品でLLMを動かすには非常に低スペックです。

>【 Windows 11Pro】第六世代 Core i5 6200u/メモリー8GB/SSD256GB


# 手順
## Docker環境の整備
まず、①の記事の「Ollama + Open WebUIでGUI付きで動かす方法」によるとOpen Web UIはDockerを使うとのことだったので、Docker環境の整備から。
以下のページによるとDocker DesktopかRancher Desktopのどちらかを入れればよいとのことでした。

https://zenn.dev/mkj/articles/33befbaf38c693

前者は250人以上の会社等はライセンスが必要とのことだったので、Rancher Desktopを使うことに決定。公式ページからWindowsのインストーラをダウンロードしてインストール開始。
インストール自体は問題なく完了したが起動しませんでした。以下参考になれば参照ください。

:::note info
ハマったところ。
**Rancher Desktopの起動中に"error: wsl.exe exited with code 4294967295"がでて起動が完了しない。**
　→ Windowsで仮想化が有効になっていないことが原因でした。BIOSの画面から有効化することで問題解消。

 https://jp.minitool.com/news/enable-virtualization-windows-10.html
 
:::

## DockerからのOllamaの操作
本章の内容は基本的に①の記事の中ほどにあるコマンドを実行していくだけです。

まずはOllama環境を起動

```Ollama環境の起動.
docker run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama
```

llama3をダウンロード

```llama3のダウンロード.
docker exec -it ollama ollama pull llama3
```

llama3を実行し、コマンドプロンプトに対話画面が開き、チャットができればOK

```llama3の実行.
docker exec -it ollama ollama run llama3
```


### Fugaku LLM環境の設定
ここから②の記事の内容になります。
こちらも記事の以下の内容を実行すれば問題なく設定できるはずです。

>(2) Fugaku-LLMのGGUFファイルをダウンロードする
>(3) ollamaにFugaku-LLMを登録するためのモデルファイル（設定ファイル）を用意する
>(4) ollamaにFugaku-LLMを登録する

:::note info
**ハマったところ(その１)**

**GGUFファイルおよびモデルファイルをホストコンピュータからdocker環境に送付する方法** 
→(2),(3)の手順はホストPC側でファイルの取得＆作成を行い、Docker側にコピーしました。コピーは以下コマンドで実行。

```ホストPCとDockerコンテナ間のファイルコピー.
docker cp [ホスト側のファイルパス] ollama:[Docker側のファイルパス]
[具体例]
docker cp .\.ollama\Modelfile ollama:/tmp/Modelfile
```

:::

:::note
**ハマったところ(その２)**

**Dockerのコンテナ内のシェルへのアクセス**
→ 以下のコマンドを実行し、シェルからコマンドで(4)の作業を行いました。

```Dockerコンテナのシェルへのアクセス.
docker exec -it [コンテナ名] /bin/bash
[具体例]
docker exec -it ollama /bin/bash
```
 
:::

## 動作確認
Open WebUIを起動して動作確認をします。
以下コマンド実行後、http://localhost:3000/ にアクセスするとWebUIのログイン画面が見えるはずです。

```Open WebUIの起動
$ docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main
```

WebUIのログイン方法、詳細な操作方法は割愛しますが、モデル選択の画面にFugakuが表示されれば成功です。

![fig1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1426173/17caa4e8-5892-2a15-79ff-180258eb7c3e.png)


# 終わりに

余談ですが、ひ弱なノートPCで試したため、Fugakuを用いた場合、回答に1文字1分程度かかっていました💦でも一応動いていました！
データ処理方法と要件: クラウドでのストリーミング、イベント駆動、バッチ処理

## はじめに
データ処理の方法には、ストリーミング処理、イベント駆動処理、バッチ処理の3つがあり、それぞれ異なる要件に基づいて使用されます。本記事では、これらのデータ処理方法について説明し、Snowflake、Google Cloud、AWSの使用ツールと共に具体例を示します。

## データ処理方法と要件

| データの種類 | 処理の頻度 | 適切な処理 | 理由 | Snowflakeでのツール | Google Cloudでのツール | AWSでのツール |
| :--- | :---: | :--- | :--- | :--- | :--- | :--- |
| センサーデータ | 毎秒〜毎分 | ストリーミング処理 | リアルタイム解析が必要 | Snowpipe, Streams | Pub/Sub, Dataflow | Kinesis, Firehose |
| ログデータ | 毎分 | ストリーミング処理 | 継続的なモニタリングが必要 | Snowpipe, Streams | Pub/Sub, Dataflow | Kinesis, Firehose |
| 金融取引データ | 毎秒 | ストリーミング処理 | 即時処理と不正検知が必要 | Snowpipe, Streams | Pub/Sub, Dataflow | Kinesis, Firehose |
| ユーザーのクリックデータ | 毎秒〜毎分 | ストリーミング処理 | ユーザー行動のリアルタイム分析が必要 | Snowpipe, Streams | Pub/Sub, Dataflow | Kinesis, Firehose |
| ファイルアップロード | 不定期 | イベント駆動処理 | ファイルアップロードイベントがトリガー | Snowpipe, Tasks | Cloud Functions, Storage Triggers | Lambda, S3イベント |
| データベースの更新 | 不定期 | イベント駆動処理 | データ更新イベントがトリガー | Streams, Tasks | Cloud Functions, Firestore Triggers | Lambda, DynamoDB Streams |
| ユーザーのアクション（例：フォーム送信） | 不定期 | イベント駆動処理 | ユーザーアクションがトリガー | Streams, Tasks | Cloud Functions, App Engine | Lambda, API Gateway |
| バッチレポート生成 | 毎日/毎週 | バッチ処理 | 高頻度のリアルタイム性は不要 | Snowflake Tasks | Cloud Composer, Dataflow | Glue, Batch |
| ETLジョブ | 毎日/毎時間 | バッチ処理 | 定期的な大量データの処理が必要 | Snowflake Tasks | Cloud Composer, Dataflow | Glue, Batch |
| APIデータ収集 | 毎時間/毎日 | バッチ処理 | 定期的なデータ収集が必要 | Snowflake Tasks | Cloud Composer, Dataflow | Glue, Batch |

## ストリーミング処理

ストリーミング処理は、データが生成されると同時にリアルタイムで処理される方法です。継続的にデータが流れ込み、低遅延での処理が求められる場合に使用されます。

**使用ツール**:
- **Snowflake**: Snowpipe, Streams
- **Google Cloud**: Pub/Sub, Dataflow
- **AWS**: Kinesis, Firehose

## イベント駆動処理

イベント駆動処理は、特定のイベント（例：ファイルのアップロード、データベースの更新）がトリガーとなり処理が開始される方法です。イベントの迅速な検出と処理が求められます。

**使用ツール**:
- **Snowflake**: Streams, Tasks
- **Google Cloud**: Cloud Functions, Storage Triggers, Firestore Triggers
- **AWS**: Lambda, S3イベント, DynamoDB Streams, API Gateway

## バッチ処理

バッチ処理は、一定の間隔（例：毎日、毎週）でデータを取り込み処理する方法です。大量のデータを一度に処理し、リアルタイム性がそれほど重要でない場合に使用されます。

**使用ツール**:
- **Snowflake**: Tasks
- **Google Cloud**: Cloud Composer, Dataflow
- **AWS**: Glue, Batch

## 1. センサーデータのストリーミング処理

### **Snowflake**:
- **Snowpipe**を使用してリアルタイムでデータを取り込み、**Streams**を使ってデータの変更を監視します。

### **Google Cloud**:
- **Pub/Sub**でデータを受信し、**Dataflow**でリアルタイムにデータを処理します。

### **AWS**:
- **Kinesis**でデータを収集し、**Firehose**でリアルタイムにデータを処理します。

## 2. ファイルアップロードのイベント駆動処理

### **Snowflake**:
- S3にファイルがアップロードされると**Snowpipe**がトリガーされ、データを取り込みます。**Tasks**を使用して追加の処理を自動化します。

### **Google Cloud**:
- **Cloud Storage**のトリガーを設定し、ファイルアップロードイベントが発生すると**Cloud Functions**が実行されます。

### **AWS**:
- **S3イベント**をトリガーとして**Lambda関数**が実行され、ファイルがアップロードされたときに処理を開始します。

## 3. バッチレポート生成

### **Snowflake**:
- **Tasks**を使用して、毎日決まった時間にレポートを生成します。

### **Google Cloud**:
- **Cloud Composer**を使用して、定期的にDataflowジョブを実行し、レポートを生成します。

### **AWS**:
- **Glue**を使用して、定期的にETLジョブを実行し、**Batch**を使ってレポートを生成します。

# まとめ

データ処理方法の選択は、データの特性とビジネス要件に依存します。ストリーミング処理はリアルタイム性が重要なシナリオに、イベント駆動処理は特定のイベントに基づく迅速な対応が必要なシナリオに、バッチ処理は定期的な大量データの処理が必要なシナリオにそれぞれ適しています。Snowflake、Google Cloud、AWSのツールを活用して、効率的なデータ処理パイプラインを構築しましょう。
[初級] C++: 仮想関数

仮想関数を使った継承
継承、仮想関数

:::note info
本記事の前提条件は以下の通りです。
* 初心者向け
* とは言っても、何らかのプログラムはそれなりに書けるけど、C とか C++ はちょっと、という人向け
* ざっくり概要しか説明しないので細かいことは気にしないでいただきたい
* Visual Studio 2013 くらい～
* Windowsプログラム (CUI, GUI)
* コードの検証
    * 開発環境: Visual Studio 2022, x64, Release ビルド
    * 実行環境: Windows 10
:::

:::note info
* 本記事は上から順番に読む前提となっている
:::

:::note info
* 「Visual Studio 2013 くらい～」と書いてあるが、本記事の内容だと現在過去未来のどのバージョンでもほぼ同じ
* 「Windowsプログラム (CUI, GUI)」と書いてあるが、本記事の内容だとどの OS でもほぼ同じ
:::

:::note info
前提知識として必要と思われる情報
* [[初級] C++: クラスの基本 - 拙著](https://qiita.com/yasu62347/items/f544e486ea2cc1965c95)
* [[初級] C++: 機能の拡張とは - 拙著](https://qiita.com/yasu62347/items/54e8bbc63fb6a996ff88)
* [[初級] C++: 継承 - 拙著](https://qiita.com/yasu62347/items/8b7aa258fca08ea97c64)
:::

# 通常の継承と仮想関数の継承の違い

## 通常の継承
基底クラス
```cpp
class Cook
{
public:
    void Wash()
    {
        std::cout << "水道水で流し洗い\n";
    }
    void Cut()
    {
        std::cout << "包丁で切る\n";
    }
    void Grill()
    {
        std::cout << "コンロで焼く\n";
    }
};
```
派生クラス
```cpp
class Factory : public Cook
{
public:
    void Wash()
    {
        std::cout << "超高圧洗浄\n";
    }
    void Cut()
    {
        std::cout << "レーザーで切る\n";
    }
    void Grill()
    {
        std::cout << "1万℃で焼く\n";
    }
```

これを使ってみる。
```cpp
Factory factory;
factory.Wash();
// -> 超高圧洗浄
```
基底クラスにキャストして使うと...。
```cpp
Factory factory;
Cook& cook = static_cast<Cook&>(factory);
cook.Wash();
// -> 水道水で流し洗い
```
あくまでも基底クラスの処理が呼ばれる。

## 仮想関数で継承する
基底クラス
```cpp
class Cook
{
public:
    virtual void Wash()
    {
        std::cout << "水道水で流し洗い\n";
    }
    virtual void Cut()
    {
        std::cout << "包丁で切る\n";
    }
    virtual void Grill()
    {
        std::cout << "コンロで焼く\n";
    }
};
```
派生クラス
```cpp
class Factory : public Cook
{
public:
    virtual void Wash() override
    {
        std::cout << "超高圧洗浄\n";
    }
    virtual void Cut() override
    {
        std::cout << "レーザーで切る\n";
    }
    virtual void Grill() override
    {
        std::cout << "1万℃で焼く\n";
    }
```

同じように使ってみる。
```cpp
Factory factory;
factory.Wash();
// -> 超高圧洗浄
```
基底クラスにキャストして使うと、
```cpp
Factory factory;
Cook& cook = static_cast<Cook&>(factory);
cook.Wash();
// -> 超高圧洗浄
```
オブジェクトの実体であるクラスの処理が呼ばれる。

:::note info
なお、この場合でも明示的に基底クラスの関数を呼ぶと、
```cpp
Factory factory;
Cook& cook = static_cast<Cook&>(factory);
cook.Cook::Wash();
// -> 水道水で流し洗い
```
基底クラスの処理が呼ばれる。
:::

以上。
機械学習を応用して画像のポスタリゼーション

K-means法は教師なし学習の中でクラスタリングを行いますが、そのアルゴリズムの中でクラスタの重心を求めます。
ところで画像は配列にするとRGBが縦×横になっているわけですが、そのRGBのデータを取り出すことでデータセットにしてクラスタの数を8個にして各色の重心の色を使います。

※今回はGoogle Colabを使っているのでインデントが少し変ですがおおめに見てください。

# ライブラリのインポート
```Python3
from sklearn.cluster import KMeans
import cv2
import matplotlib.pyplot as plt
import numpy as np
```

# 画像の読み込み
```Python3
img = cv2.imread("/content/drive/MyDrive/lena_square.png")
plt.imshow(img)
plt.show()
```
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/bccd17b6-df8f-e4ba-1d93-0a0c3ce3b3ec.png)
なんかRGBがおかしいのはGoogle Colabの仕様なのかOpenCVの仕様なのか

# RGBのデータセットを作る
```Python3
arr = np.array(img).tolist()
data = []
for i in range(len(arr)):
  for j in range(len(arr[i])):
    data.append(arr[i][j])
```
これでRGBのテーブルデータが作れました。

# モデルの作成と重心の確認
```Python3
model = KMeans(n_clusters=8)
model.fit(data)
xyz = model.cluster_centers_
print(xyz)
```
```
[[172.18651769 194.6938175  231.58912477]
 [137.42536743 102.83654745 156.32401665]
 [ 65.31620059  23.47032448  93.80382301]
 [ 81.58072177  69.04411444 172.72797008]
 [135.19572287 156.5699912  225.06082865]
 [ 81.86449534  49.36292781 130.18762519]
 [ 95.78363064  96.39556654 205.78326798]
 [116.89396007 127.20808313 213.13809171]]
```
ポスタリゼーションした時にこの色が使われます。
# 色を重心に変換
```Python3
arr2 = []
for i in range(len(arr)):
  tmp2 = []
  for j in range(len(arr[i])):
    tmp = []
    for k in range(len(xyz)):
      dst = np.sqrt((xyz[k][0]-arr[i][j][0])**2+(xyz[k][1]-arr[i][j][1])**2+(xyz[k][2]-arr[i][j][2])**2)
      tmp.append(dst)
    tmp2.append(xyz[np.argmin(tmp)])
  arr2.append(tmp2)
```
8色の中で一番ユークリッド距離が近い色を採用します。
これで8色になりました。

# 画像を確認
```Python3
plt.imshow(np.array(arr2).astype("int"))
plt.show()
```
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/8fea8bc5-d4d9-a109-c527-693ace06020a.png)
こんな感じになりました。割と自然にポスタリゼーションできたんじゃないかと思います。
比較用↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/2a489271-3f29-50b5-a3ca-ea23b3e48e5e.png)


# まとめ
機械学習でこんなこともできるんですよ
【Docker】aptパッケージをキャッシュする方法

`Dockerfile`に以下のように記述するとaptパッケージをキャッシュできます。

```Dockerfile
# syntax=docker/dockerfile:1

# ...

# apt-get install実行後に/var/cache/apt内のdebファイルが削除されないようにする
RUN rm -f /etc/apt/apt.conf.d/docker-clean
# aptパッケージをキャッシュする
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
  --mount=type=cache,target=/var/lib/apt,sharing=locked \
  apt-get update && apt-get --no-install-recommends install -y gcc
```

`apt-get`を使用する場合には`echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache`は不要です。

https://arc.net/l/quote/kjnmfrnz

## 参考

- `rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache` について

https://vsupalov.com/buildkit-cache-mount-dockerfile/

https://stackoverflow.com/a/59285496

https://zenn.dev/thaim/articles/2023-08-apt-cache-mount#deb%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E8%87%AA%E5%8B%95%E5%89%8A%E9%99%A4%E3%82%92%E7%84%A1%E5%8A%B9%E5%8C%96%E3%81%99%E3%82%8B

https://arc.net/l/quote/flcedlab

- `--mount=type=cache`について

https://docs.docker.com/reference/dockerfile/#run---mounttypecache

https://docs.docker.com/build/cache/#use-the-dedicated-run-cache
JavaScript: utf8編

まずは**byte数計算速度**を比較。構成文字によって最適法は変わってきます。以下の例ではほぼ多byte文字となります。
```js
!function(){// utf8 size
var a=0,b=0,c,d,e,z=65536,A=[];
for(;a<0xd800;)A[a]=a++;
for(;a<z;A[a++]=0xdc00+(b++&0x3ff))A[a++]=0xd800|b>>10;//surrogate pair
A=String.fromCharCode(...A);//計算対象文字列

for(b=new Date,a=100;a--;)encodeURI(A).replace(/%../g,'i').length
console.log(new Date-b)

for(b=new Date,a=100;a--;)A.replace(/[\x80-\u07ff]/g,11).replace(/[\u0800-\ud7ff\ue000-\uffff]/g,111).replace(/[\ud800-\udbff][\udc00-\udfff]/g,1111).length
console.log(new Date-b)

for(b=new Date,a=100;a--;)for(c=e=0;c<z;e+=d<128?1:d<0x800?2:d<0xd800||d>0xdfff?3:(c++,4))d=A.charCodeAt(c++);
console.log(new Date-b)

for(b=new Date,a=100;a--;)new TextEncoder().encode(A).length;
console.log(new Date-b)
}()
```
`encodeURI`がぶっちぎりで遅いです。
TypeScript勉強してみた１０

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

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


# 今回の目的
TypeScriptがわからなくてやばたにえんなので、ハンドブックで学んでみました。
（前回）

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

# 主に参考にさせていただいた記事

https://www.typescriptlang.org/docs/handbook/intro.html

# Keyof型演算子
### keyによる警告
key情報で型を制限します。
```ts
type Point = { x: number; y: number };
type P = keyof Point;
//OK
const ok:P = "x";
//NG
const ng:P = "a";
```

# Typeof 型演算子
### 型情報の返還
typeofの後に記述した内容から型を返還します。
```ts
// string
console.log(typeof "Hello world");
```

# インデックスアクセスタイプ
### オブジェクト内から型情報を取得
```ts
type Person = { age: number; name: string; alive: boolean };
// number
type Age = Person["age"];
// UnionType
type I1 = Person["age" | "name"];
// keyofによる取得
type I2 = Person[keyof Person];
```

# 最後に
後半はまだ実用できてないからイメージできませんでしたが一通り見ることができました。:writing_hand:
TypeScript勉強してみた⑨

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

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


# 今回の目的
TypeScriptがわからなくてやばたにえんなので、ハンドブックで学んでみました。
（前回）

https://qiita.com/mr_noppo/items/57fe7b35b047b1535f41

# 主に参考にさせていただいた記事

https://www.typescriptlang.org/docs/handbook/intro.html

# オブジェクトの種類
### readOnly
propertyへ再代入した時に警告することができます。実行エラーにはなりません。
```ts
type SomeType = {
  readonly prop: string;
}
 
function doSomething(obj: SomeType) {
  console.log(`prop has the value '${obj.prop}'.`);
 
  // 警告
  obj.prop = "hello";
  // helloは表示されます
  console.log(obj.prop)
}

const obj:SomeType = {
  prop:'test'
}

doSomething(obj)
```

### ReadonlyArray
pushプロパティを使用すると警告されます。
letを使用して上書きした場合は警告が出ないので注意。
```ts
const roArray: ReadonlyArray<string> = ["red", "green", "blue"];
// 警告
roArray.push('a');
```

### タプル型
配列の型をインデックス単位で指定できます。
```ts
type StringNumberBooleans = [string, number, ...boolean[]];
type StringBooleansNumber = [string, ...boolean[], number];
type BooleansStringNumber = [...boolean[], string, number];

const a: StringNumberBooleans = ["hello", 1];
const b: StringNumberBooleans = ["beautiful", 2, true];
const c: StringNumberBooleans = ["world", 3, true, false, true, false, true];
```

# 型操作
## ジェネリック
<>で型の注入が可能です。中の名称はType以外でも統一されていれば問題ありません。
```ts
function identity<Type>(arg: Type): Type {
  return arg;
}
// 返り値もstringで定義されます。
let output = identity<string>("myString");
```
### 引数の型とメソッド
Typeの場合でも呼び出せるプロパティを絞り込まないといけません。
```ts
function loggingIdentity<Type>(arg: Array<Type> | string): Array<Type> | string {
  console.log(arg.length); // Array has a .length, so no more error
  return arg;
}
```
### 定義部分の切り出し
下記のように切り出し、ジェネリックで型を定義する記述も可能です。
```ts
type GenericIdentityFn<Type> = {
  (arg: Type): Type;
}
 
function identity<Type>(arg: Type): Type {
  return arg;
}
 
let myIdentity: GenericIdentityFn<number> = identity;
```

### propertyによる制限
下記の例の場合は、propertyにlengthがないと警告されます。
```ts
type Lengthwise = {
  length: number;
}
 
function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {
  console.log(arg.length); // Now we know it has a .length property, so no more error
  return arg;
}

loggingIdentity({ length: 10, value: 3 });
```

### keyofによる制限
```ts
function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
  return obj[key];
}
 
let x = { a: 1, b: 2, c: 3, d: 4 };
 
getProperty(x, "a");
// keyにない為警告
getProperty(x, "m");
```

# 次回の予定
Keyof型演算子
【Proxmox 7.x】ハードウェアパススルーで NVMe の Windows 10 を起動したい！

# はじめに
[この素晴らしい記事](https://qiita.com/stLuciano/items/49652543192f2402e7c8)を発見し、私も過去の Windows が入ってるディスクを接続しながら Proxmox を起動していたので、実際にやってみた。


# VM を作る！
Create VM を選択して VM を作る

### General
ご自由に `VM ID` とか `Name` 決めてください

### OS 
今回はすでにインストールされている OS を使用するので、`Do not use any media` を選択。
`Guest OS` は `Windows 10` を使用するので、 
`Type: Microsoft Windows, Version: 10/2016/2019` を選択する。

### System
こんな感じに設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348896/00dd361f-5066-66ee-81af-2f2c66b53f55.png)

### Disks
今回は NVMe をパススルーするのでゴミ箱を押して**何もない状態**で進む。

### CPU
好きなコア数を割り当てましょう。

### Memory
好きなメモリ数を割り当てましょう。4 GiB だと起動はできるけどちょっと足りなそう。

### Network
好きな設定にしましょう。

:::note warn
Firewall をオンにすると、VM 内でネットワークがつながらない可能性があるので、
もしつながらなかったらオフにすると改善するかも？
:::


### Confirm
最終的にはこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348896/7c8a2808-25a4-e443-9f8e-a6bf428c874b.png)


# NVMe をパススルーする！
VM が作成出来たら Hardware タブを開く。
左上の `Add` から `PCI Device` を選択。(NVMe は PCI デバイスなので GPU とかと同じように PCI の中にある)

`Device` タブから `NVMe コントローラー` であろうものを選択する
(私の環境だとこれでした。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348896/427939d5-c397-73f0-a643-99e86506d792.png)

`All Functions` にチェックを入れて Add を押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348896/8dfd93e9-471d-0892-fc96-6f3ef61ab343.png)

:::note warn
No IOMMU detected, please activate it. See Documentation for further information.
というエラーが出ていたら、↓ を参考に設定してみてください (宣伝)
:::
https://qiita.com/waigoma/items/738cea38d4e18097c1e2

# OS 起動ディスクとして登録する！
`Hardware` タブと同じように `Options` タブがあると思うのでそれを開く
`Boot Order` を選択し、先ほど追加した NVMe デバイスの `Enabled` にチェックを入れ、起動順序を上げておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348896/85fb1b5f-c165-3bd5-ab8c-dddfa74368f9.png)

# 起動！
起動するとこんなエラーが出るかも？(おま環説は大いにありますが)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348896/7f75f9fc-b1ca-2c71-7feb-2bb4d78a1fee.png)

`F9` を押して、他の OS を使うとすることで NVMe から起動できた！
(もしかしたら Win11 を一瞬入れてしまい、OS が 2 つあるみたいな状態になってたせいかも？)


# 余談とかメモ
余談ですが、ネットワークデバイスが `VirtIO` になっていると自環境ではネットに繋がらなかったので、`Intel E1000` に変更することで解決した

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348896/cde07ac3-4235-3cde-25e5-eb3c5f7eb07c.png)

リモートデスクトップ接続できるように設定すると便利かも？
設定するときは IP の固定を忘れずに。

SATA 接続デバイスもパススルーしたいときは、こちらのサイトがすごく参考になった。

https://blog.hitsujin.jp/entry/2023/05/17/proxmoxrdm

```shell
# Proxmox 起動しているシェルで実行
# 接続ディスク確認
ls -l /dev/disk/by-id/

# VM にパススルー
qm set [VMのID] -[virtio,sata,scsi][数値] /dev/disk/by-id/[ストレージの情報]
# ex.) qm set 100 -sata0 /dev/disk/by-id/ata-Crucial_CT275MX300SSD1_164914EE5EA1
```


# おわり
過去の PC で Linux とか入れて遊びたい、
でも Windows の設定を残して使えるようにしたい、って人にすごくおすすめ！

気になった方はぜひやってみてください！


# 参考

https://qiita.com/stLuciano/items/49652543192f2402e7c8

https://blog.hitsujin.jp/entry/2023/05/17/proxmoxrdm

https://www.youtube.com/watch?v=IUb8FTON5w4

https://forum.proxmox.com/threads/what-is-the-best-way-to-add-nvme-m-2-ssd-to-a-vm-via-qm-set-command-or-by-adding-a-pcie-device-in-guis-vm-hardware-page.127929/
Power Automate クラウドフローのトリガーで複数チャネルを指定するには

## こんな人にお勧め
チームに複数のチャネルがあり、どのチャネルに投稿された場合もトリガーしたいけれど、「チャネルに新しいメッセージが追加されたとき」では複数のチャネルを指定できず。別々にトリガーを作るのは大変で困っている方のための記事です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285141/ef173af9-d32d-990b-0c2e-899809c6c84f.png)


## 「キーワードが言及された場合」トリガーを使いましょう
こちらのトリガーならば、チームを選んだあと、そのチームにぶら下がっている複数のチャネルを追加することができます。
ポイントは、検索キーワードに「"?"」と入力すること。こうすることで、どんな文字が入力されていてもトリガーとして反応させることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285141/05e2cc2c-c585-c2b8-c43c-6caa0a77e0b9.png)

"?" を使ってどんなキーワードにも反応させるテクニックは、おいしみさんのこちらの記事を参考にしました。

https://qiita.com/ksgiksg/items/f9e1ce9f8df8403d607f

## そのままでは使えない。詳細で深く掘るのだ

ただし、トリガーの中にはメッセージの内容までは含まれていません。その代わりに、チームID、チャネルID、メッセージIDがJSONとして含まれています。

これらを取り出して、「メッセージ詳細を取得する」に渡してやれば、メッセージの中身が取り出せます。トリガーからそれぞれの値を抜き出すには、下記の式を使ってください。

```
triggerOutputs()?['body/value'][0]?['teamId']
```
```
triggerOutputs()?['body/value'][0]?['messageId']
```
```
triggerOutputs()?['body/value'][0]?['channelId']
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285141/4e299e36-dca0-3cdb-f28f-a01840714833.png)

メッセージの詳細のなかには、投稿の内容が含まれていますね！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285141/c42a1fa6-16b3-6f99-b7b8-8f800ad28945.png)
【イベント】JAWS-UG山梨  第0回

## はじめに
・Qiita初投稿
・情シス2年目
・AWSとc#勉強中

## 目次
1.JAWS-UGとは
2.参加のきっかけ
3.参加してみて

## JAWS-UGとは
エリア、地域を拠点とした地域支部と、勉強会のテーマ、目的別に組織化された専門支部がある。主にAWSの勉強会(アウトプットの場)、コミュニティを広げる、インスパイアを目的としている。

## 参加のきっかけ
上司と1on1をしていた時に、もっと外の世界を知った方がいいとアドバイスいただき、巡り合わせもあり参加してきました。

## 参加してみて
なんと、AWS Ambassadorsの方が3名も参加くださいました。
会自体は初心者でもわかりやすいような内容でしたが周りのレベルが高かった😅
AWS Ambassadorsの方のお話「RAGの研究から予測する、これからのエンジニアに求められるスキル」の中でおしゃっていたことを少し抜粋させていただきます。
これからのエンジニアに求められるスキルは
・検索に関するスキル
・プロンプトエンジニアリング
・既存の技術
の3点である。

私自身全てに関してまだまだスキル足りてないと感じています。これからQiitaへの投稿(アウトプット？)も含め日々精進したいと思います。

![IMG_7442.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806000/12ff2807-bc80-210b-bf4f-81e9a240d9a0.jpeg)
【powershell】特定のフォルダに格納されているファイル一覧を取得

## 特定のフォルダに格納されているファイル一覧を取得
```
Get-ChildItem -Path C:filepath\* -Recurse -File |Select-Object  FullName,Name,LastWriteTime | Export-csv -Path .\filelist.csv -Encoding UTF8
```

## ポイント1.ファイルを取得
```
Get-ChildItem -Path C:filepath\* -Recurse -File
```
パワーシェルでファイルを出力するときは

## ポイント2.CSVで出力
```
Export-csv -Path .\filelist.csv -Encoding UTF8
```
出力をエクスポートする場合はExport‐CSVを使用します
日本語はCSVで文字化けが発生するのでEncoding　UTF8は忘れずに

## ポイント3.CSVの出力を制限
```
Select-Object  FullName,Name,LastWriteTime
```
ほしい情報だけ出力する場合は下記を実施
Ubuntu24.04LTSで起動音を鳴らす方法

最近のUbuntuは、デフォルトの設定で起動音（ログイン音）が鳴らないようになっています
今回は、起動音を鳴るようにする方法をご紹介します

## 環境
バージョン - Ubuntu24.04LTS
カーネル - 6.8.0-31-generic

## 起動音を鳴らすようにする
実は、デフォルトの設定で鳴らないようになっているだけで、ファイル自体は残っています
「Startup Applications Preferences」を開いてください
すると、画像のようなものが起動します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691296/91ab1e91-6f33-897e-f40e-30b08a456ee9.png)

そしたら、右にある「追加(A)」を押して、
以下のようなダイアログが出ます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691296/59418568-6d16-b9f0-d65b-9c45b998371e.png)

コマンドの欄に、以下のように入力してください
```
/usr/bin/canberra-gtk-play --id="desktop-login" --description="GNOME Login sound"
```
名前欄や説明欄は自分のわかりやすいように設定して、追加を押します

これで完了です！
個人的に便利だと思うVSCodeショートカット

## ctrl + D
検索＆選択
## ctrl + Shift + R
リファクタ

## 組み合わせるとこんなことができる
![無題の動画 ‐ Clipchampで作成 (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2221375/50d5657b-daa5-0155-1108-d6eb573afc83.gif)
ABC356をPythonで（A～D）

AtCoder Beginner Contest 356の解答等をまとめました

https://atcoder.jp/contests/abc356

# A問題
https://atcoder.jp/contests/abc356/tasks/abc356_a

言われたとおりにする
```python:A
n, l, r = map(int, input().split())

ans = [i for i in range(1, l)] + [i for i in range(r, l - 1, -1)] + [i for i in range(r + 1, n + 1)]

print(*ans)
```
# B問題
https://atcoder.jp/contests/abc356/tasks/abc356_b

forループで計算する
```python:B
n, m = map(int, input().split())

a = list(map(int, input().split()))

for _ in range(n):
    b = list(map(int, input().split()))
    for i in range(m):
        a[i] -= b[i]

print("Yes" if all(a_i <= 0 for a_i in a) else "No")
```
# C問題
https://atcoder.jp/contests/abc356/tasks/abc356_c

bitを使って正しい鍵のパターンを全通り用意し、シミュレーションする
```python:C
n, m, k = map(int, input().split())
ok, ng = [], []
for _ in range(m):
    c, *a, r = input().split()
    if r == "o":
        ok.append(list(map(lambda x: int(x) - 1, a)))
    else:
        ng.append(list(map(lambda x: int(x) - 1, a)))

ans = 0
for bit in range(1 << n):
    flag = True
    for ok_i in ok:
        cnt = 0
        for i in ok_i:
            if bit >> i & 1:
                cnt += 1
        if cnt < k:
            flag = False
    for ng_i in ng:
        cnt = 0
        for i in ng_i:
            if bit >> i & 1:
                cnt += 1
        if cnt >= k:
            flag = False

    if flag:
        ans += 1
    
print(ans)
```
# D問題
https://atcoder.jp/contests/abc356/tasks/abc356_d

2進数の桁ごとに考える
[公式解説](https://atcoder.jp/contests/abc356/editorial/10126)と同じような解法なので貼り付けときます
```python:D
n, m = map(int, input().split())
mod = 998244353
ans = 0

for i in range(59, -1, -1):
    if m >> i & 1:
        if n >> i & 1:
            ans += n % (2 ** (i + 1)) - (2 ** i) + 1

        ans += n // (2 ** (i + 1)) * (2 ** i) % mod
        ans %= mod

print(ans)
```
VirtualBoxの「内部ネットワーク」にDHCPサーバ(備忘録)

DHCP使ってゲストOSのIPをホストOS群のIPを別セグメントにしたい。
でも、ホストPCのメモリが８GBしかないので、DHCPサーバ用のゲストは上げたくない。
VirtualBoxの機能に、DHCPサーバがあるようなので設定してみました。

# ホストPC環境
- Windows10 22H2
- VirtualBox 7.0.10

# ゲストPC環境
- ゲスト1(CentOS8)
- ゲスト2(WindowsServer 2019)
ゲスト2からTeratermで、CentOS8へSSHができれば良い

# 注意点
　内部ネットワークの設定であるため、内部ネットワークだけ設定した場合、
　ホストPCからの接続は不可
　内部ネットワークに接続したゲストPC間の接続は可能

# 内部ネットワークにDHCPサーバを設定する手順
　ホストPCにインストールされている「VBoxManage.exe」コマンドで設定します。

VirtualBoxをインストールしたフォルダに「VBoxManage.exe」があります。
こいつで、内部ネットワークにDHCPサーバを設定します。

因みに、「vboxmanage dhcpserver」だけで実行するとコマンドヘルプが参照できます。
```
vboxmanage dhcpserver
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246395/7fffceda-4e91-ae55-8c16-e099bcb26309.png)


# 具体的な手順
ホストPCでコマンドプロンプトを起動します。
VirtualBoxをインストールしたフォルダに移動します。

デフォルトでインストールしたなら以下になります
```
cd C:\Program Files\Oracle\VirtualBox
```

今回のDHCPは、こんな感じで割り当てていきます。
- ネットワーク名：intnet
- DHCPサーバアドレス：128.10.10.254/24
- IPアドレス範囲：128.10.10.1～128.10.10.16

**DHCPサーバ有効化**コマンドは、以下のようになります。

```
vboxmanage dhcpserver add --network=intnet --server-ip=128.10.10.254 --netmask=255.255.255.0 --lower-ip=128.10.10.1 --upper-ip=128.10.10.16 --enable
```

エラーになる場合はどこかコマンドが間違っているので、コマンドヘルプを見て直しましょう。

**DHCPサーバ**を開始します。
```
vboxmanage dhcpserver start --network=intnet
```

ゲストOSのネットワーク設定は、内部ネットワークになっていますか？
それでは、ゲストOSを起動しましょう。

ゲストOSが起動したら、IPアドレスを確認してください。
設定範囲のIPアドレスが払い出されていると思います。

払い出し状況確認は、以下のコマンドで確認できます。
macアドレスは、VirtualBoxのゲストOS、ネットワーク設定で確認できます。
```
vboxmanage dhcpserver findlease --network=intnet --mac-address=0800279b1c4c
```
結果は、こんな感じで出力されます。
```
IP Address:  128.10.10.1
MAC Address: 08:00:27:9b:1c:4c
State:       acked
Issued:      2024-06-01T11:37:13Z (1717241833)
Expire:      2024-06-01T11:47:13Z (1717242433)
TTL:         600 sec, currently 593 sec left
```

DHCPサーバの停止や無効化はコマンドヘルプを確認してください。
考えてプログラミングを作ること

## 初めに
開発者日記を始めます。
この前は自分が好きな勉強をやり続けようと思って、やりたい勉強の全てをudemyで動画を見ながら勉強し、アプリを作ろうと思いました。
reactやswift, C++まで当時で出来ると思い、日を分けて勉強に頑張ったが失敗でした。
失敗の理由はどこにも集中できず、自分が分けた時間内でコード作成を終わらせることはできなかったです。一番辛かった理由は何も学んでいる気がしなかったです。
仕事でもできないことはできないままだし、２週間だけだが辛かったです。やっぱり自分は向いてないかなって思ったこともあるけど、やっぱり何かを作ることが楽しいから辞めることは考えないです。

## 優秀な開発者になる為には？
たくさんの言語を知ったら、役に立つと思いました。
でも、開発者になることは問題を解決する能力かも知らないです。周りの先輩とか本から沢山聞いたが気づくのが遅かったです。
### なぜ、プログラミングの本をたくさん読んでも、実際バグをあった時に考えを繋げないんだろ
隣で一番コードを書ける師匠に聞いたら、やっぱり考える力だと話をしてくれました。
考えれば、コードを書く時はいつも答えがあると思って考えるより、ネットで答えを探してあれを覚えましょうの気持ちが強かったです。

## ゼロイチに戻す
Vanilla JSとReactでToDoリストを自分の考えだけで作り始めることに戻そうと思いました。
開発の初めをReactから始めたのでVanilla JSのシンタックスから壁にぶつかったり、edit機能が動かなくってイライラする日々です。

## 師匠の言葉を信じてイライラしない
ことを一番にしようと思います。
考えたことより時間は何倍掛かってるが、自分の力で作りながら、本当に色々勉強になっています。
JSの動きについてちゃんと勉強する時間になっています。

## 自分を信じて楽しく成長すること
始まったばかりで、なんとも言えないが一応楽しくやっています。
結論がなんともないことになりましたが、毎週自分の成長を記録しようと思っています。
【PHPフレームワークFlow】FlowのソースにPHPunitを試す

# 初めに
Flowでソースを書いてきましたが、UnitTestはまだ書いたことがありませんでした。
今回は、PHPフレームワークFlowでUnitTestを書く方法をまとめます。

# PHPunit
PHPUnitとは、PHPのUnitテストツールです。
豊富なAssertメソッドを有しているのが特徴です。

https://phpunit.de/index.html

# PHPUnit使ってみる
ということで、さっそく使ってみましょう。
今回UnitTestを作成するのはこちらのUsersクラスです。
getName()のUnitTestを作成したいと思います。

```Users.php
<?php
namespace Neos\Welcome\Domain\Model;

use Neos\Flow\Annotations as Flow;
use Doctrine\ORM\Mapping as ORM;

/**
 * @Flow\Entity
 * @ORM\Table(name="users")
 */
class Users
{

    /**
     * @ORM\Column(length=80)
     * @var string
     */
    protected $name;

    public function __construct(string $name, string $email, string $password)
    {
        $this->name = $name;
    }

    /**
     * テスト対象
     */
    public function getName(): string
    {
        if (empty($this->name)) {
            return "unknown";
        }
        return $this->name;
    }

}
```

## 作成手順
ということで作成します。

### 1. インストールは不要
まずはインストール！と言いたいところですが、Flowのプロジェクトには最初からPHPUnitが入っているので、インストールは不要です。
プロジェクト直下のbinディレクトリを見ると、すでにphpunitの実行ファイルが入っていることが確認できると思います。

```
Project
  └ bin
      ├ phpunit
      └ phpunit.bat
```

## Testファイル作成
続いてテストファイルを作成します。

```php: UsersTest.php
<?php
namespace Neos\Welcome\Tests\Unit\Domain\Model;

use Neos\Welcome\Domain\Model\Users;

class UsersTest extends \PHPUnit\Framework\TestCase
{

    /**
     * @test
     */
    public function testGetName_unknown()
    {
        // Arrange
        $sut = new Users("", "test@example.com", "pass");

        // Act
        $result = $sut->getName();

        // Assert
        $this->assertSame("unknown", $result);
    }
    
    /**
     * @test
     */
    public function testGetName_known()
    {
        // Arrange
        $sut = new Users("a", "test@example.com", "pass");

        // Act
        $result = $sut->getName();

        // Assert
        $this->assertSame("a", $result);
    }
}
```

ポイントは以下です。
* `\PHPUnit\Framework\TestCase`クラスを継承
* TestCaseクラスのassertメソッドを使って結果を確認
  * 今回はassertSameを使用
* `@test`アノテーションがついているか、`test`から始まるメソッドがテスト対象になる

## 実行
ここまで出来たら実行しましょう。
先ほど確認したphpunitの実行ファイルを実行します。

```sh
$ .\bin\phpunit .\Packages\Application\Neos.Welcome\Tests\Unit\Domain\Model\UsersTest.php
PHPUnit 9.6.19 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 00:00.008, Memory: 4.00 MB

OK (2 tests, 2 assertions)
```

無事に実行できました！


# 終わりに
Flowでは、`\PHPUnit\Framework\TestCase`クラスを継承した`UnitTestCase`というクラスが用意されており、それを利用しても試験ができるようになっています。が、現状そのクラスを利用したUnitTestの実行でハマっています。解決したらまた記事にしようと思います。

ご覧いただきありがとうございました！
Next.jsのTailwindCSS入門


シリーズのトップは↓こちら

https://qiita.com/every-month/items/a6a9f481ac31eb695d25

前回の記事は↓こちら

https://qiita.com/every-month/items/1da2de989732fe721055

たまたまプライベートで人にNext.jsと一緒にTailwindCSSを叩き込む機会がありまして、せっかくなので再びこの場をお借りしていっしょに復習します。

## 前回のポイント（再掲）（抜粋）

- `npm run dev`
    - （作ってる途中の）Next.jsを動かす
    - だいたい`http://localhost:3000`で見れる

## 今回のポイント

- `src/app/globals.css`の基本はたった３行
    - `@tailwind base;`
    - `@tailwind components;`
    - `@tailwind utilities;`
- `src/app/layout.tsx`
    - HTMLの比較的外側の部分を生成するのがこのファイル
- HTMLの`class`はTSXでは`className`
- TailwindCSSでは`class`がいっぱい準備されている
    - `class`を指定するだけでOK

## 今回の目標

### しましまを消す

前回一部の（ダークモードでない）方はこんな画面になったのではないでしょうか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782801/93b85519-112a-f145-447b-4340139770c1.png)

この意図しないしましまを取り除きます。

### 色をつける

今回は背景と文字の色を選んでみます。

## 色を選ぶ

お好みの色をこれらのページから選びます。上のほうの表から文字の色と背景の色をお好みで選んでClass欄の名前を控えておきます。

見づらい色の組み合わせに気をつけましょう。文字が消えてびっくりします。

背景の色は↓こちらから

https://tailwindcss.com/docs/background-color

文字の色は↓こちらから

https://tailwindcss.com/docs/text-color

私ははこんな色を選んでみました。

| 背景 | 文字 |
|:---:|:---:|
| bg-blue-500 | text-white |

## やってみよう

まずは`src/app/layout.tsx`を開きます。

```tsx:src/app/layout.tsx（抜粋）
  return (
    <html lang="en">
      <body className="bg-blue-500 text-white">{children}</body>
    </html>
  );
```

この`<body`の行の`className=`の後を書き換えます。

私は↓この色を選んだので、

| 背景 | 文字 |
|:---:|:---:|
| bg-blue-500 | text-white |

`<body className="bg-blue-500 text-white">{children}</body>`←こうしました。

次に、`src/app/globals.css`です。

```css:src/app/globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

TailwindCSSにおいて大事な↑この３行***だけ***にします。あと全部消します。
（見た感じですが、しましまはこの消した部分に記述されているようです）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782801/e33e6d80-c568-c3ae-75e1-318fc49b76ed.png)

するとこうなりました。
背景の色も文字の色も意図したとおりです！🎉

今回はここまでにしました✨


## 今回のポイント（再掲）

- `src/app/globals.css`の基本はたった３行
    - `@tailwind base;`
    - `@tailwind components;`
    - `@tailwind utilities;`
- `src/app/layout.tsx`
    - HTMLの比較的外側の部分を生成するのがこのファイル
- HTMLの`class`はTSXでは`className`
- TailwindCSSでは`class`がいっぱい準備されている
    - `class`を指定するだけでOK
【AWS】検証用にIAM Identity Centerを使用したらミスったのでIAMユーザを作り直した

# 経緯
検証用にIAM Identity Centerを経由してIAMユーザを作成したらなんか思ったとおりにいかなかったので。
# 現状
IAM Identity Centerを経由してユーザ作成して、そのユーザでコンソールにログインしてみたら以下画像のようになんの権限もなかった。そういえば権限割り当て画面とかなかったもんな…。
ということで作ったばかりのユーザではあるけれど、ステータスを無効化してIAMユーザの作り直しを始める。
※私のゴールはIAM Identity Centerを理解することではなく、自分が使えるIAMユーザを作ることなのでここでは前者の理解とかいったんすっ飛ばしてます。今度ちゃんと勉強します。

![e8c32228d500-20240117.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3804761/dd03914a-6886-4d94-5974-3eaf815b7965.png)

# やり直し
ユーザ作成画面に戻る。
思えば以下画面で「IAM Identity Centerでユーザーを指定する」のボタンを選択してホイホイ進んだらそちらでユーザ作成することになったので、今回は下の「IAMユーザーを作成します」を選択して次に進む。

![8bb285fcccdb-20240117.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3804761/89803b7e-a4b8-b662-b0f5-70c7b09655b0.png)

![669f25564c96-20240117.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3804761/0213322e-2dec-88d3-3246-0741b838b66e.png)

キャプチャを取得し忘れたが、この後無事に権限割り当ての画面に遷移し、とりあえず今の自分に必要そうなAdmin（管理）系の権限を適当にピックアップして作成完了。
作成したばかりのIAMユーザでログインしてみたら、無事にマネジメントコンソールが表示された。

![5cd465cb979c-20240117.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3804761/4ad5699d-6aca-8f17-6f27-687aaef9115e.png)

# 最後に
失敗は多いが、少しずつ成長…。
Vue3で星のレーティング機能を作りたい！

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">

</head>
<body>
  <h1>Vue3で星のレーティング機能を作りたい！</h1>
  <p>と思ったので早速Vue3でTypescript実装してみようと調べてみると...</p>
  <p>Vuetify3という便利なライブラリがあるのでそれで実装しましょう！</p>
  <p><a href="https://vuetifyjs.com/en/components/ratings/">https://vuetifyjs.com/en/components/ratings/</a></p>
  <p>その前にインストールする必要があるよねということでChatGPTに聞くと</p>
  
  <pre><code>
vue add vuetify
  </code></pre>
  
  <p>これでインストール完了！</p>
  
  <p>後は</p>
  <pre><code>
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import vuetify from './plugins/vuetify';

createApp(App).use(vuetify).mount('#app');
  </code></pre>
  <p>これを書けばいいのね</p>
  
  <p>簡単に実装のところのサンプルをGPTに書いてもらうと？</p>
  
  <pre><code>
&lt;template&gt;
  &lt;v-app&gt;
    &lt;v-main&gt;
      &lt;v-container&gt;
        &lt;v-rating
          v-model="rating"
          background-color="yellow"
          color="blue"
          half-increments
          length="5"
          size="32"
        &gt;&lt;/v-rating&gt;
        &lt;p&gt;Rating: {{ rating }}&lt;/p&gt;
      &lt;/v-container&gt;
    &lt;/v-main&gt;
  &lt;/v-app&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data() {
    return {
      rating: 3.5,
    };
  },
};
&lt;/script&gt;

&lt;style&gt;
@import 'vuetify/styles';
&lt;/style&gt;
  </code></pre>
  
  <p>よし！これで表示されるはず！</p>
  <br>
  
  <b>は？何も表示されんのだが...</b>
  
  <h2>解決方法</h2>
  
  <p>結論から言うと、<b>MDIが必要でした</b></p>
  
  <pre><code>
npm install @mdi/font
  </code></pre>
  
  <p>これでインストールして、インポートに</p>
  
  <pre><code>
import '@mdi/font/css/materialdesignicons.css';  // 追加
  </code></pre>
  
  <p>を追加すると</p>
  
  <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758876/0ee1cf03-18b2-0671-aec1-bcefe9a3941d.png" alt="スクリーンショット 2024-06-01 215402.png"></p>
  
  <p>表示出来た！</p>
  
  <p>これ先ほどのRatingComponentのサイトに載ってませんでした。いきなりRating機能実装しようとして見えなかったうえ、MDIが必要であることにすぐに到達できなかったのでこちらに記述しておきます。</p>
</body>
</html>
アジャイルソフトウェア開発の奥義 ~依存関係の逆転~をかみ砕いてみる

# 初めに
ロバート・C・マーチン氏の「アジャイルソフトウェア開発の奥義」が大変面白かったのでまとめる。
＊本書とは順番が異なります。

## 依存性逆転の法則
SOLID原則のD、英語でDependency Inversion。
これは以下の2文で説明できる。

- 上位のモジュールは下位のモジュールに依存してはならない。どちらのモジュールも「抽象」に依存すべきである
- 「抽象」は実装の詳細に依存してはならない。実装の詳細が「抽象」に依存すべきである

### 今までの誤解。
自分はJava,Springをやってきたので、「あーDIのことか」と思っていた。
まず、これは間違い。逆転(Inversion)であって、注入(Injection)じゃない。
だが、自分はDIを利用すればDはクリアした気になっていた…
だが、一番の勘違いはDIするときのInterface設計だった。
多分多くのSpring経験者は書籍の中で「ServiceInterafceを作る」というようなサンプルコードを見てきただろう。例えば、こんなの。
```java
//Userの実装は略。
public interface UserInterface {
  public void login(User user);
}

@Service
public class UserService implememnts UserInterface{
/*(中略)*/
}

@Controller
public class LoginController{
  @AutoWired
  private final UserInteface user;
  /*RequestParamなどは省略 */
  public void Login(String userId,String password){
    user.login(new User(userId,password));
  }
}
```
そして、パッケージ構成はこうではなかっただろうか。
```plantuml
@Startuml
package sample{
  package controller{
    class LoginController
  }
  package service{
    interface UserInterface{
        + login(User)
    }
    class UserService implements UserInterface
  }
  package dto {
    class User
  }
}
```
これに違和感を覚えず、丸呑みして使っていた。だが、依存性逆転の法則にしたがうと、この`UserInreface`は`controller`パッケージにあるべきなのである。

本書の中では「影響が伝達しやすい依存関係」だと指摘している。
Controllerを直せば、Serviceが、そして恐らくあるであろうRepositoryにまで影響すると。
最初は理解できなかったが、アジャイルソフトウェア開発の本なので
「テストファースト」で考えるとよくわかる。

### テストが意味をなさなくなる依存関係

まず、どういう変更が考えられるか。
実はこの`UserInterface`には（意図的に）足りないものが一つある。そう、logoutだ。

では、UserInterfaceにlogoutを実装しよう。大体のＷＥＢサービスではログアウトはセッションにあるユーザー情報のリセットだろう。これをコード上で書く場所はUserServiceに他ならない。
セッションならcontollerだろと書いてしまうと大変危うい。もしかしたらSpring SessionでDBも使うかもしれない。たとえ今はそうでなかったとしても。

そして、テストはserviceプロジェクトにかかれる。
修正漏れがないようにこの仕事ではカバレッジが90%だったとしよう。
他に修正はなくてもガバレッジはクリアしているので、serviceプロジェクトの修正が終わればリリースできてしまう。
そして、多分１日目にしてこういうクレームが来る。
**「ログアウトしてない」**
なぜか、画面から呼び出されるはずのcontrollerにlogoutがないからだ。

「いやいや、そんなのテストでわかるよ」
もちろん、そうであるはずだ。大事なのは、こう言った初歩的なミスはテストコード、いわば「単体テスト」を書いてる時点で気づくべきだ。
もしかしたら、「こんなの半日で終わりますよ」と高を括っていってしまったがために、テストは行われてないかもしれない。このプロジェクトにはガバレッジが設定されているから大丈夫だと。
だがそうはならなかった。


これがこのパッケージの依存関係が生む大きな弊害である。

### どうすべきか

簡単である。UserInterfaceをcontrollerパッケージに書けばいい。
そうすればcontrollerプロジェクト担当者はcontrollerにlogoutを書き忘れることはない。
そして、このインターフェースはserviceプロジェクトが実装しているので、ガバレッジをクリアしても最終的なプロジェクトのコンパイルでエラーになる。なので、実は実装されてないなんてこともなくなる。
controllerとservice、両方が修正され初めてリリースできるという望ましい形になる。
これで、PMもお客さんもニッコリ(\*´ω｀\*)
あなたの仕事は多分しばらくは安泰だろう。

## まとめ
依存性逆転の法則に従うなら、インターフェースは「実装する側」ではなく「**依存している**」側に書くべき。
ポート(PORT)について

## ポートとは？
ポートとは、ネットワークからサーバー（コンピューター）に接続するための入り口または通信経路のことです。それぞれのポートには識別番号が割り当てられており、ネットワーク通信のプロトコルに応じてどのポートを使用して通信を行うかが定められます。

## ポートの役割
サーバー側では、前述の通り、通信方法に応じてどの番号のポートを介してアクセスを許可するかを設定します。

この設定を一般に「ポートを開放する」と表現します。たとえば、通信方法がHTTPアクセスであれば、80番ポートを介してサーバーにアクセスできます。ポートの主な役割は、ネットワーク通信を適切にルーティングすることです。

同じポートを同時に複数のアプリケーションが使用することはできません。したがって、一つのアプリケーションが特定のポートを使用している場合、他のアプリケーションはそのポートを使用できなくなります。
このため、ポートを分けて競合を回避します。

## 一般的に使われるポート番号とその役割
HTTP通信：80番
HTTPS通信：443番
FTPデータ通信：20番（FTPサーバーからクライアントへの送信）
FTP制御通信：21番（クライアントからFTPサーバーへの送信）
SSH：22番

※ポート番号はサーバー側で独自に設定し、役割を割り当てることもできます。
httpとhttpsについて

HTTP（HyperText Transfer Protocol）とHTTPS（HyperText Transfer Protocol Secure）は、ウェブ通信に使われるプロトコルであり、それぞれ異なる役割と特徴を持っています。
HTTPとHTTPSの違い、メリット・デメリット、そして使用例について説明します。


## httpについて
HTTPは、ウェブブラウザとサーバー間で情報をやり取りするためのプロトコルです。
プロトコルとはデータ(テキスト・画像etc)を転送するための手順などのルールを定めています。

### 特徴
#### <ステートレスであること>
HTTPはステートレスプロトコルです。
これは、各リクエストが独立しており、サーバーは前回のリクエストの状態を保持しないことを意味します。

#### <ポート番号>
デフォルトで80番ポートを使用します。

### メリット
シンプルで軽量: 簡単に実装でき、通信オーバーヘッドが少ない。
広く普及: ほとんどのウェブサイトで使用されています。

### デメリット
セキュリティの欠如: データが暗号化されていないため、盗聴や改ざんされるリスクがあります。



## httpsについて
HTTPSは、HTTPにSSL/TLS（Secure Sockets Layer / Transport Layer Security）を組み合わせたプロトコルです。
これは、通信内容を暗号化することでhttpに比べて、セキュリティが強化しています。

### 特徴
#### <暗号化>
通信内容が暗号化されるため、盗聴や改ざんから保護されます。

#### <認証>
サーバーの身元を証明するために、デジタル証明書が使用されます。

#### <ポート番号>
デフォルトで443番ポートを使用します。

### メリット
セキュリティ: 通信内容が保護されるため、安全なデータ転送が可能です。
信頼性の向上: SEO的にもhttps通信を使っているサイトの方が優先されるようです。

### デメリット
証明書が必要: SSL/TLS証明書の取得したり、期限が切れると更新する必要がある。
パフォーマンス: 暗号化と復号化の処理が追加されるため、若干ですがパフォーマンス低下を発生させる可能性があります。

## 使用例と選択基準

### HTTPの使用例
一般的なウェブページ: 個人情報などを扱わず、それほどセキュリティが重要でないデータを扱う場合。
ローカルネットワーク内の通信: 内部ネットワークでのみアクセス可能なシステムなどに使う。


### HTTPSの使用例
フォームや管理画面: 個人情報など重要な情報を扱うサイト。

## まとめ
基本的にはHTTPSを使うのがセキュリティ的にもよいが、システムなどを作る場合は、外部通信を受けるところだけHTTPS通信でやりとりし、内部からはHTTPを使ってデータのやり取りをするなどの方法を使うとパフォーマンスがよく、証明書も一枚で済みます。
EC2のキーペアの作り方（秘密鍵・公開鍵）

## やりたかったこと
複数人で同じEC2にアクセスして作業を行うときに、全員が「ec2-user」として同じ.pemを使ってアクセスするのではなく、作業用にそれぞれユーザーを作成し、それぞれに別々の.pemファイルを割り当てたかった。

## 作業手順

### EC2にssh接続
まずは「ec2-user」としてEC2にSSH接続します。
```
ssh ec2-user@【IPアドレス】 -i 【pemのパス】
```

### 作業をするためにユーザーをroot権限に変更
EC2内で様々な作業を行うため、あらかじめroot権限に切り替えておきます。
毎回sudoでコマンドを実行するのが面倒なので。
```
sudo su
```

### ユーザーを追加
作業用のユーザーを作成します。
```
useradd 【ユーザー名】
```

### 追加したユーザーをwheelグループに所属させる
作成したユーザーをsudoを使えるwheelグループに入れます。
wheelグループはsuやsudoコマンドを使えるユーザーグループです。ここに所属していないと、作業に必要なsuやsudoコマンドが使えません。
```
usermod -G wheel 【ユーザー名】
```

### sudoコマンドを使用する際のパスワード入力を省略可させる
下記のコマンドを実行し、sudo設定の編集モードにします。
```
visudo
```
次に、「Same thing without a password」の下の行のコメントアウト（#）を削除します。
```
## Same thing without a password
# %wheel  ALL=(ALL)       NOPASSWD: ALL
```
以下のように編集します。
```
## Same thing without a password
%wheel  ALL=(ALL)       NOPASSWD: ALL
```
「:wq!」で保存します。

### 作成したユーザーに切り替えて、キーペアを作成する
```
su - 【ユーザー名】
ssh-keygen -t rsa
```

### キーペアが作られているか確認する
キーペアが無事作成されているか確認するため、下記のコマンドを実行します。
「id_rsa」と「id_rsa.pub」が作成されていれば成功です。
```
cd ~/.ssh
ls
```

### 公開鍵の設定
クライアント側で生成された公開鍵 id_rsa.pub をサーバー側の authorized_keys ファイルに追加することで、そのクライアントがパスワードなしでSSHを使ってサーバーへログインできるようにします。
```
cat id_rsa.pub >> authorized_keys
chmod 600 authorized_keys
```

### 秘密鍵（id_rsa）をローカルにコピー
下記のコマンドでid_rsaの中身をコピーして、ローカル環境で任意の場所に秘密鍵を作成します。
ファイル名は「【任意の名前】.pem」で作成します。
```
vi ~/.ssh/id_rsa
```
または
```
cat ~/.ssh/id_rsa
```

作成したファイルのパーミッションを読み取り権限のみに変更します。
```
chmod 400 【秘密鍵のディレクトリ】/【秘密鍵の名前】.pem
```

### 接続の確認
ローカルから下記のコマンドを実行して、EC2に接続できれば成功です。
```
ssh 【ユーザー名】@【IPアドレス】 -i 【秘密鍵のパス】
```
AWSのCloudFrontについてのまとめ

## CloudFrontとは
CloudFrontは、AWSが提供するコンテンツ配信ネットワーク（CDN）サービスです。CloudFrontは、ウェブサイト、API、画像、動画などのコンテンツを、ユーザーに迅速かつ安全に配信するためのもので、通信の遅延時間（レイテンシー）を最小化し、高速にコンテンツを配信します。

※CDNとは、インターネット上でウェブコンテンツを効率的に配信するための分散型ネットワークです。CDNは、地理的に分散したサーバー群から構成されており、ユーザーに最も近いサーバーからコンテンツを提供することで、ウェブページの読み込み時間を短縮します。

## できること
### コンテンツ配信の最適化
ユーザーに近いエッジロケーションからコンテンツを配信することで、データ転送の距離と時間を短縮します。これにより、ユーザーエクスペリエンスの向上とサーバー負荷の軽減が図れます。

### キャッシュと配信方法の制御
ビヘイビアを設定し、コンテンツのキャッシュと配信の方法を制御することが可能です。特定のパスパターンやリクエストに対してどのように応答するかを詳細に定義できるため、パスパターンごとにEC2やS3など、どこにリクエストを送るか分けたり、通信方法の制限をかけるなどの使い方ができます。

### セキュリティの強化
CloudFrontは、分散型サービス拒否（DDoS）攻撃からの保護を提供します。また、データ転送時の暗号化を提供し、ユーザーとサーバー間のセキュアな通信を確保します。AWS ShieldやAWS WAF（Web Application Firewall）との統合により、さらなるセキュリティ強化が可能です。

### スケーラビリティ
CloudFrontは、トラフィックの増加に対応するため自動的にスケールアップし、需要に応じて適切なリソースを確保します。これにより、突然のトラフィック増加にも対応でき、安定したサービス提供が可能です。
MacのWineSkinServerで起動するゲームのCPU優先度を簡単に変更するやつを作った

# Macで東方原作のシューティングやってるんですけど、処理落ちするんです

経緯は、以下を参照してください。

https://qiita.com/ykmns/items/f9840ef498a905ce7e0c

# 処理落ちはreniceコマンドで解消できることが分かった、が、毎回やるのが面倒

せめてシェルスクリプトの実行はLaunchPadからやりたい。いちいちコマンドの名前を手打ちもしたくない。

# Macでは、シェルスクリプトの拡張子を.commandにすると、自動でterminal.appを起動して、うまいことやってくれるらしい

# 成果物

ファイル名 mac-game-renice.bash.command

* コマンドをわざわざ変数に入れてevalする手間かけてるのは趣味です。直接書いたほうがいいスクリプトだと思います。
* ※awkの `$2` にバックスラッシュ入れてるのはevalのせいです

```bash
#!/bin/bash

CMD_SHOW_MOST_HIGH_CPU='ps alwxxr | head -n 2'
CMD_GET_PID_OF_HIGHEST_CPU="ps alwxxr | head -n 2 | tail -n 1 | awk '{print \$2}'"
CMD_RENICE='sudo renice -10 '

echo "[INFO] Target Process:"
eval $CMD_SHOW_MOST_HIGH_CPU

VAR_TARGET_PID=$(eval $CMD_GET_PID_OF_HIGHEST_CPU)
CMD_RENICE="$CMD_RENICE $VAR_TARGET_PID"

echo "[INFO] Execute renice command:"
echo $CMD_RENICE
eval $CMD_RENICE

echo "[INFO] Check the result of ReNice:"
eval $CMD_SHOW_MOST_HIGH_CPU

```

これを適当な場所に保存し、Finderでダブルクリックして開く。
Terminal.appが起動し、sudoのパスワードを聞いてくる。
認証に成功したら、reniceした結果のpsを出力して終了。

# 動作イメージ

![スクショ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403229/c1f7d49f-3e3c-4a39-9c72-1218a952965c.png)

# 宿題

…と、ここまではいいんだ。
問題は、LaunchPadは `.command` ファイルをアプリケーションと認識してくれないらしい。なんだよそれは。意味ねえじゃん。
と、とりあえずreniceがワンクリックになったからよしとしよう。

# 成果物その2

ゲーム起動するたびにイチイチこれ実行すんのも面倒くさい。
nice値は親プロセスに指定した値を継承するらしいので、東方ゲームexeを実行する元のexplorerのnice値を変更してやれば、あとはゲームを起動するだけでうまく行くでしょ。

ということで作ったのがこれ
使い方は同じ。wineskinserverの.appを起動して最初に上がってくるexplorerのnice値を下げる。
explorerを終了せずに起動しっぱなしにしておけば、あとはゲームを起動するだけ。

```bash
#!/bin/bash

PID_EXPLORER=$(ps alwxxr | grep [e]xplorer | grep -v '/desktop' | grep -v bash  | awk '{print $2}')
echo ''
ps alwxxr | grep [e]xplorer | grep -v '/desktop' | grep -v bash
echo ''
echo "PID is: $PID_EXPLORER"

sudo renice -19 $PID_EXPLORER

echo ''
ps alwxxr | grep [e]xplorer | grep -v '/desktop' | grep -v bash
echo ''
```
GPT-4oにスクショだけでデバッグを頼んだメモ

![03_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951879/d6c92898-76dd-914b-9b3b-df7e87bf7c38.png)

# 趣旨
プロンプト書くのが面倒なのでスクショだけでデバッグしてもらいたい。

# デバッグしてもらうアプリの環境
- Windows 11
- Ruby 3.3.1
- Ruby on Rails 7.1.3

# デバッグをお願いしてみた
### お願いするエラー内容
ルーティングの設定が誤ってる場合に出力されるエラー。このエラー画面のスクショをGPT-4oに入力します。

![001＿ディレクトリ黒塗り.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951879/19b1068e-4823-be5c-4e68-9d80d110114f.png)

### 結果
エラー原因を特定して修正方法まで詳しく教えてくれました。内容も正しいです。

![GPT回答.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951879/1cf75cd5-dde3-2f01-ed25-bfe02b9072e7.png)

### なぜRailsアプリだと分かったのか
ChatGPTから良質な回答を引き出すには、ロールの設定や目的を詳細に記述するなど、プロンプト入力のコツがいくつかあり、その例も広く知られています。
セオリーに沿えば、Railsアプリであることを最初に入力して然るべきですが、それをせずとも言語やフレームワークを特定しています。
なので、なぜRailsアプリだと分かったのか聞いてみました。

![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951879/97713192-8489-77f8-b05c-97d8c21fe1b1.png)

エラー画面に「Rails」という文字列があるので、そこから判断したのかと思いましたが（それも要因のひとつかも知れませんが）、エラー画面のデザインの特徴からも判断しているようです。これには少し驚きました。

# 文字通りスクショだけでお願いしてみる
先程の例は申し訳程度に「このエラーを解決して」とメッセージを添えましたが、今度は文字通りスクショだけ入力します。
これまでのチャット履歴が影響するかもしれないので、メモリを全部削除して新しいチャットを作成し、先程の例とは別のエラー画面のスクショを入力しました。
何も言われずとも空気を読んでデバッグを進め、指示待ちAIではないことの証明を待ちます。

### お願いするエラー内容
定義されていないメソッドを呼び出したエラー。

![スクリーンショット 2024-06-01 172432.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951879/4221d465-4c94-1bdb-696f-22aa1a120754.png)

### 結果
![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951879/27fb8c21-892c-d6ba-81ff-5071d01c637e.png)

回答が英語になりましたが、原因と解決方法は正しく導き出せています。

# これならメッセージがコピペ出来ないエラーもサクッとお任せできる
以下の様にダイアログで表示されてメッセージがコピペ出来ない、遭遇するとイライラするタイプのエラーも、スクショを貼り付けるだけなので捗りますね。

![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951879/db68396b-5bc6-0a2f-ac34-e8423d325e66.png)
ランダムフォレストでワインの品質判定してみた【ワインの品質判定②】

#### はじめに
ランダムフォレストでワインの品質判定をやってみたので、紹介します。

#### そもそもランダムフォレストとは何なのか？
ランダムフォレストは、多数の決定木を使って予測を行うアンサンブル学習アルゴリズムである。
それぞれの決定木は、訓練データからランダムにサンプルを抽出したデータセットで学習する。（ブートストラップサンプリング）


#### プログラム
基本的には[前回記事](https://qiita.com/yamo1116/items/85b2d9d3f169d63789ca)と同じです。
ワインの特徴量と品質が記されたデータセットをURLから持ってきて、
特徴量からワインの品質を求めるようなプログラムになってます。
ランダムフォレストという機械学習の手法を使っております。

```Python
# 必要なライブラリのインポート
import numpy as np  # 数値計算を効率的に行うためのライブラリ
import pandas as pd  # データ分析を容易にするためのライブラリ
from sklearn.ensemble import RandomForestClassifier  # ランダムフォレストモデルを使用するためのライブラリ
from sklearn.model_selection import train_test_split  # データを訓練用とテスト用に分割するためのライブラリ
from sklearn.preprocessing import StandardScaler  # データの標準化を行うためのライブラリ
from sklearn.metrics import accuracy_score  # 正解率を計算するためのライブラリ

# データセットの読み込み
df = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv', sep=';')  # ウェブ上のデータセットを読み込む

# データの前処理
df = df.replace('?', np.nan).dropna()  # '?'を欠損値として扱い、欠損値を含む行を削除
for column in df.columns:
    df[column] = df[column].astype(float)  # 全ての列のデータタイプを浮動小数点数に変換

# 品質をカテゴリ変数に変換
df['quality'] = pd.Categorical(df['quality'])  # 'quality'列のデータをカテゴリ変数に変換

# 特徴量と目的変数の指定
X = df.drop('quality', axis=1)  # 'quality'列を除いたデータを特徴量として指定
y = df['quality'].cat.codes  # 'quality'列のカテゴリコードを目的変数として指定

# データの標準化
scaler = StandardScaler()  # 標準化を行うためのインスタンスを作成
X_scaled = scaler.fit_transform(X)  # 特徴量データを標準化

# 訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=0)  # データを訓練用とテスト用に分割

# ランダムフォレストモデルの構築
rf_model = RandomForestClassifier(n_estimators=100, random_state=0)  # ランダムフォレストモデルのインスタンスを作成

# モデルの訓練
rf_model.fit(X_train, y_train)  # 訓練データを使ってモデルを訓練

# モデルの評価
train_predictions = rf_model.predict(X_train)  # 訓練データに対する予測
test_predictions = rf_model.predict(X_test)  # テストデータに対する予測

# 正解率の計算
train_accuracy = accuracy_score(y_train, train_predictions)  # 訓練データの正解率を計算
test_accuracy = accuracy_score(y_test, test_predictions)  # テストデータの正解率を計算

# 結果の表示
print(f'正解率(train): {train_accuracy:.3f}')  # 訓練データの正解率を表示
print(f'正解率(test): {test_accuracy:.3f}')  # テストデータの正解率を表示
```

#### 実行結果
実行結果は以下のような感じでした。
正解率70.9%っすね。

```
C:\Python\wine\rf>python rf1.py
正解率(train): 1.000
正解率(test): 0.709
```

#### Q. なんで70%しか出ないのか・・・？

<font color="red">どうやらワインのデータに原因があるらしい。</font>

ワインのデータ内に、品質の偏りがあるらしい。。。

（↓の記事に分かりやすく書いてありました。）

https://note.com/keisuke_funabiki/n/n244a3b154e51