OmniAICreator/Qiita-1.07M huggingface dataset:
Nuxt3でvueファイルが「Cannot find module 'vue'. Did you mean to set the 'moduleResolution' option to 'node', or to add aliases to the 'paths' option?」となった時の対処法

# このようなエラーメッセージが表示された場合の対処法
開発をしている際に、`vue`ファイルに下記のメッセージエラーが表示されたときの対処方法について解説します。
```
Cannot find module 'vue'. Did you mean to set the 'moduleResolution' option to 'node', or to add aliases to the 'paths' option?
```

# ディレクトリ構成
`Nuxt3`のディレクトリ構成は下記のようになっています。
```
└── Project/
    ├── .nuxt
    ├── .output
    ├── components/
    │   └── navbar/
    │       └── navbar.vue
    ├── node_modules
    └── pages/
        ├── adminUsers
        ├── generalUsers/
        │   └── registration/
        │       └── registration.vue
        ├── index.vue
        ├── public/
        │   ├── favicon.ico
        │   └── robots.txt
        ├── server/
        │   └── tsconfig.json
        ├── app.vue
        ├── nuxtconfig.ts/
        │   ├── package.json
        │   └── package-lock.json
        ├── README
        └── tsconfig.json
```

# 対処方法
解決方法は、`tsconfig.json`に下記のコードを追加します。

```tsconfig.json
  "compilerOptions": {
    "moduleResolution": "node"
  }
```

全体のコードは、こちら↓
```tsconfig.json
{
  // https://nuxt.com/docs/guide/concepts/typescript
  "extends": "./.nuxt/tsconfig.json",
  "compilerOptions": {
    "moduleResolution": "node"
  }
}
```
javacだとエラーにならないが、ECJだとエラーになることがあるらしい

## この記事を書くに至った経緯

Java8 + Spring Bootで書かれたプログラムを、IntelliJ IDEAで開いて編集していた。
しかし、話題のAIエディタCursorを使用したくて、同じプログラムをCursor(VSCode)で開いてみた。
すると、なぜか大量のエラーが発生し、コンパイルできなくなった。
原因を探るのに1日溶かしてしまったので、戒めとして投稿する。

## エラーが起こったコード

要約すると、以下のようなコードである。

```java
package com.example;

import java.util.List;

public class ServiceImpl<V> implements IService<V> {
    // 他のメンバ

    // IntelliJでは警告になるが、Cursor(VSCode)だとコンパイルエラーになる個所
    public List<?> voList(List list) {
        return null;
    }
}

interface IService<V> {
    List<V> voList(List<V> list);
}
```

上記コメントの通り、問題は`public List<?> voList(List list)`の部分である。
IntelliJだと警告が出るだけで、問題なくビルドできるのだが、Cursorだとエラーになり、ビルドできない。
本来、上記コードの`List<?>`を`List<V>`か`List`とすれば問題ないのだが、上記コードはclassファイルとなっており、編集できなかった。
そのため、コードを編集することなく、エディタ側の何かしらの設定をいじって対応できないかと考えた。

## 原因

結論から言うと、この現象はどうやらコンパイラーの違いに起因するらしい。
IntelliJでは標準でjacacが使われているのに対し、Cursor（VSCode）ではEclipseと同じECJが使用される。
javacだと上記コードは警告で済むのに対し、ECJではエラーと判定される、ということらしい。
Cursor（VSCode）でもjavacを使えるようにできるが、JDK23以上でないといけないらしい。
そのため、Java8（JDK1.8）の今回のプロジェクトではCursor（VSCode）でjavacを使うことはできないようだ。

## 結局どうしたか

Cursorは使用したいが、Cursorからだとコンパイルはできない。
そのため、Cursorで編集しつつ、実行するときはIntelliJを使う、という方針に落ち着いた。
Cursorでファイルを編集するタイミングでビルドが走ってしまうので、IntelliJでリビルドをしてからでないと実行できないというのが面倒だが、現状だと他にどうしようもなさそうだ。

## 参考文献

- <https://github.com/redhat-developer/vscode-java/wiki/Javac%E2%80%90based-compilation-support>
Oracleインスタンス学習まとめ

# 挨拶
初めまして、日本システム開発株式会社の鈴木です。
技術者として更なる向上を目指すためQiitaアウトプットをする取り組みを行っています。
技術者としては経験が浅く発信内容はとにかく試したものの覚書になります。
今回は資格取得勉強中に苦戦したOracleデータベースのOracleインスタンスについて備忘録を書いていきます。

## Oracleインスタンス
OracleインスタンスとはOracleデータベースの処理の中心となる **SGA(システムグローバル領域)** というメモリ領域と **バックグラウンドプロセス** というデータベース管理に必要なプロセスの2つとなります。インスタンスは（Oracle Real Application Clustersを使用しないかぎり）データベースファイルと1:1で対応します。

### バックグランドプロセス
#### データベースライター(DBWn)
DBWnはデータベースバッファキャッシュ内の更新データをデータベースファイルに反映するプロセスです。高速化のためにディスク上のデータベースファイルではなくメモリ上のキャッシュを編集する際に、更新されたキャッシュ上のブロックをデータベースファイルに反映する役割を持ちます（キャッシュに読み込む処理はサーバプロセスが行います）。
#### チェックポイント（CKPT）
DBWnにデータファイルへの更新を指示するバックグランドプロセス
#### ログライター(LGWR)
復旧用REDOログをREDOログファイルへ書き込むプロセスです。キャッシュの更新履歴（REDOデータ）はメモリ上に保存されますがトランザクションがコミットしたタイミングでLGWRが書き込みを行います。
#### システムモニター(SMON)
 **インスタンス** 異常終了時に整合性復旧を行うプロセス
#### プロセスモニター(PMON)
**プロセス** 異常終了時にプロセスがロックしていたリソースの開放を行うバックグランドプロセス
#### 管理モニター(MMON)
性能分析で使用される統計情報を収集する
#### アーカイバ(ARCn)
REDOログファイルは多重化して破損に備えます。その際に多重化しているログファイルの一つを1グループとして、更にグループを切り替えてログファイルを保存していきます。このグループの切り替え（ログスイッチ）時にREDOログファイルをアーカイブログファイルとして指定ディレクトリに保存するバックグランドプロセス。
### SGA(システムグローバル領域)
#### データベースバッファキャッシュ
データベースのブロックを編集する際にディスク上のファイルを開くと処理が遅いため、キャッシュとしてメモリ上に読み込む際のメモリ領域。更新や読み込みは一度このデータベースバッファキャッシュにキャッシュされる。
#### 共有プール
解析済みのSQL情報やデータベースディクショナリ情報をキャッシュする領域
#### REDOログファイル
LGWRがREDOログファイルへ書き込む前のREDOログ履歴のキャッシュ。トランザクションがコミットされる前まで更新。
## まとめ
今回は、Oracleインスタンスの主要な構成要素であるSGAとバックグラウンドプロセスについて解説しました。SGAは高速なデータアクセスと処理効率化のために、バックグラウンドプロセスはデータベースの安定稼働とデータ保全のために、それぞれ重要な役割を担っています。
matminerでマテリアルズインフォマティックス(3) XgBoostで鋼材の強度予測

## 強度予測の方法は・・
強度予測した結果を`SHAP`を使って、結果の解釈をしたいので、決定木系のアンサンブルであるXgBoostで降伏強度を予測します。
データは前処理して、降伏強度と元素組成のデータフレームになっています。

|yield strength  |Fe |	C |	Mn |	Si	 |Cr |	Ni |
|------|------|------|------|------|------|------|
|2411.5  |0.62	|0.000953|	0.000521	|0.00102	|0.00011|	0.192|
|1736.3  |0.623|	0.00854	|0.000104	|0.000203	|0.147|9.71E-05|

## 生成AI(Gemini)で予測プログラムを作成する
Geminiで予測プログラムを作成しました。指示は、こんな感じのお手軽な命令です。
>yield strengthをyに、それ以外をxに入れて、yを予測する機械学習を行う。アルゴリズムはXgBoostです。ハイパーパラメーターはoptunaで最適化してください。結果をグラフに表してください。

この命令だけで、このプログラムが出来上がります。

```python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import xgboost as xgb
import optuna

# Prepare the data
X = df.drop(columns="yield strength")
y = df["yield strength"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Define the objective function for Optuna
def objective(trial):
    params = {
        "n_estimators": trial.suggest_int("n_estimators", 100, 1000),
        "max_depth": trial.suggest_int("max_depth", 3, 10),
        "learning_rate": trial.suggest_float("learning_rate", 0.01, 0.3),
        "subsample": trial.suggest_float("subsample", 0.5, 1.0),
        "colsample_bytree": trial.suggest_float("colsample_bytree", 0.5, 1.0),
        "min_child_weight": trial.suggest_int("min_child_weight", 1, 10),
        "objective": "reg:squarederror",  # Specify the objective function
        "random_state": 42
    }
    model = xgb.XGBRegressor(**params)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    rmse = np.sqrt(mean_squared_error(y_test, y_pred))
    return rmse

# Run Optuna optimization
study = optuna.create_study(direction="minimize")
study.optimize(objective, n_trials=200)  # Adjust n_trials as needed

# Train the model with the best hyperparameters
best_params = study.best_params
best_model = xgb.XGBRegressor(**best_params)
best_model.fit(X_train, y_train)

# Make predictions
y_pred_train = best_model.predict(X_train)
y_pred = best_model.predict(X_test)

# Evaluate the model
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
print(f"Best RMSE: {rmse}")
print(f"Best Hyperparameters: {best_params}")

# Plot the results
plt.figure(figsize=(8, 6))
plt.scatter(y_train, y_pred_train, alpha=0.5)
plt.scatter(y_test, y_pred, alpha=0.5)
plt.plot([min(y_test), max(y_test)], [min(y_test), max(y_test)], color='red', linestyle='--')  # Add a diagonal line
plt.xlabel("Actual Yield Strength")
plt.ylabel("Predicted Yield Strength")
plt.title("Actual vs. Predicted Yield Strength (XGBoost)")
plt.grid(True)
plt.show()
```

optunaの繰り返し回数のみ増やしていますが、他は基本的にデフォルトです。
実行すると、こういうグラフが出てきます。
![予測グラフ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/336017/be88021d-3cbf-4b4e-afbc-4c79511db740.png)

見事に予測できています。
R2 (Training Data): 0.971
R2 (Testing Data) : 0.845
Substance 3D Designerのコマンドラインツールについて

## 環境
* Windows
* Adobe Substance 3D Designer 14.1.1


## コマンドラインから実行できるツール

Substance 3D Designer単体でも [Substance 3D Automation Toolkit](https://helpx.adobe.com/substance-3d-sat.html) の [コマンドラインツール](https://helpx.adobe.com/substance-3d-sat/command-line-tools.html) の一部が使用できます。

### コマンドラインツール

Substance 3D Designerのインストールディレクトリには下記のツールが同梱されています。

* [sbsbaker.exe](https://helpx.adobe.com/substance-3d-sat/command-line-tools/sbsbaker.html)
    * テクスチャベイクのツール
* [sbscooker.exe](https://helpx.adobe.com/substance-3d-sat/command-line-tools/sbscooker.html)
  * .sbsファイルを.sbsar ファイルに変換するツール
* [sbsrender.exe](https://helpx.adobe.com/substance-3d-sat/command-line-tools/sbsrender.html)
  * .sbsarファイルからレンダリングするツール
* [sbsupdater.exe](https://helpx.adobe.com/substance-3d-sat/command-line-tools/sbsupdater.html)
  * .sbsファイルを現在のバージョンに更新するためのツール

また ```psdparse.exe``` というexeファイルも同梱されています。こちらはpsdファイルからpngファイルの書き出しなどができます。使用方法の詳細については下記のコマンドで確認できます。

```bat
Substance 3D Designerのディレクトリ>\psdparse.exe -h
```

## Substance 3D Designerで使用できる起動オプション

コマンドラインツール以外にも、Substance 3D Designerには起動オプションがあり、下記のコマンドで確認できます。

```bat
<Substance 3D Designerのディレクトリ>\Adobe Substance 3D Designer.exe -h
```

### デバッグユーティリティ

起動オプションにはデバッグ用オプション ```--debug``` があります。こちらを使用して起動すると、デバッグメニューが表示され、デバッグ用ユーティリティを使用できるようになります。

**Debugメニュー**
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3965005/a80cf2be-f283-4871-adb8-5e3413b7f698.jpeg">

**Data Explorer**
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3965005/605436a8-9de1-45c3-b441-dc12130b5eaa.jpeg">

**Dependency Viewer**
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3965005/4e86e538-6892-4e9c-b52f-03589d5ffd42.jpeg">

**Widget Picker**
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3965005/f5a690be-fb0d-4858-96ef-301a29490acc.jpeg">


## 参考

* [Substance 3D Automation Toolkit](https://helpx.adobe.com/substance-3d-sat.html)
* [Command Line Tools | Substance 3D Automation ToolKit](https://helpx.adobe.com/substance-3d-sat/command-line-tools.html)
* [sbsbaker](https://helpx.adobe.com/substance-3d-sat/command-line-tools/sbsbaker.html)
* [sbscooker](https://helpx.adobe.com/substance-3d-sat/command-line-tools/sbscooker.html)
* [sbsrender](https://helpx.adobe.com/substance-3d-sat/command-line-tools/sbsrender.html)
* [sbsupdater](https://helpx.adobe.com/substance-3d-sat/command-line-tools/sbsupdater.html)
PowerShellに最低限インストールすべきコマンドとエイリアス

### インストールするもの

lessコマンドとvimは必須。
vimはともかくlessがないとファイル読めないよね

```
winget install jftuga.less
winget install vim.vim
```

### 設定するエイリアス

```
PS C:\Users\yugoy> cat $PROFILE
Set-Alias vim 'C:\Program Files\Vim\vim91\vim.exe'
Set-Alias vi  'C:\Program Files\Vim\vim91\vim.exe'
function Show-HistoryFile {
    Get-Content (Get-PSReadLineOption).HistorySavePath
}
Remove-Item Alias:history -Force
Set-Alias history Show-HistoryFile
```

- wingetでvimを入れてもパスを通してくれるわけではなかったので、エイリアスで設定
- powershellのhistoryコマンドが、セッション開始以降しか表示してくれない仕組みだったので全件表示できるようにエイリスを切り直し
- 本当はgrepも欲しかったけど、lessコマンドの&でgrep的な絞り込みもできるのでよしとする

```
PS C:\Users\yugoy> history| less
```

こんな感じで全件ヒストリを眺めながら前回の仕事の続きをする。
Atcoder 競プロ典型 90 問 012 - Red Painting

# [Atcoder 競プロ典型 90 問 012 - Red Painting](https://atcoder.jp/contests/typical90/tasks/typical90_l)
問題文は👆を確認してください

# 導入
atcoderで精進してますが、  
どこかにアウトプットしたかったので、qiitaに書くことにしました。  
ACしてから載せるようにしてますが、考え方が至っていない点があればご指摘頂けると幸いです。  
また、誰かの参考になると嬉しいです。

# 使用しているアルゴリズム
- Union-Find（素集合データ構造）
- グリッドの2次元→1次元変換

# 解法のポイント
この問題は、グリッド上の赤マス同士が連結しているかどうかを、高速に判定する必要があります。  
そこで、以下の工夫をしています：

### 🔹グリッドのUnion-Find化
- 各マスを「2次元→1次元」へ `h*W + w` で変換し、Union-Findで管理。
- 初期状態ではすべて白（未訪問）とし、赤マスに変えた際に上下左右の赤マスと連結（merge）します。

### 🔹Union-Find実装の詳細
- `find(j)`：親を再帰的にたどりつつ、経路圧縮も実施
- `merge(i, j)`：根っこ同士を比較して連結
- `same(i, j)`：2つのマスが同じ連結成分にいるか判定

### 🔹クエリ処理
- **クエリ1**（赤く塗る）：該当マスを赤（visited=True）にし、上下左右の赤マスがあればUnion
- **クエリ2**（赤マス間連結判定）：両マスが赤で、かつUnion-Findで同じ親を持っていれば `Yes`

# ACサンプル
```python
class UnionFind:
  def __init__(self,n):
    self.parent = [-1] * n
  
  def find(self,j):
    if self.parent[j] == -1:
      return j
    self.parent[j] = self.find(self.parent[j])
    return self.parent[j]
  
  def merge(self,i,j):
    i_root = self.find(i)
    j_root = self.find(j)
    if not i_root == j_root:
      self.parent[i_root] = j_root
  
  def same(self,i,j):
    i_root = self.find(i)
    j_root = self.find(j)
    return i_root == j_root

H,W = map(int,input().split())
N = int(input())
visited = [[False]*(W+2) for _ in range(H+2)]
uf = UnionFind(H*W)

def query1(h,w):
  visited[h][w] = True
  dhs = [1,-1,0,0]
  dws = [0,0,1,-1]
  for dh,dw in zip(dhs,dws):
    fh = h + dh
    fw = w + dw
    if fh < 0 or fh >= H or fw < 0 or fw >= W:
      continue
    if visited[fh][fw]:
      uf.merge(h*W+w, fh*W+fw)

def query2(ah,aw,bh,bw):
  if visited[ah][aw] and visited[bh][bw]:
    return uf.same(ah*W+aw,bh*W+bw)
  return False
  
for _ in range(N):
  q = list(map(int,input().split()))
  if q[0] == 1:
    query1(q[1]-1,q[2]-1)
  else:
    if query2(q[1]-1,q[2]-1,q[3]-1,q[4]-1):
      print("Yes")
    else:
      print("No")
```

# リンク
[ACサンプル集(アルゴリズム逆引き)](https://www.notion.so/motonao/1cc8aca4381b80f39713ddb52fa85e8f?v=1cc8aca4381b80519654000c236bb8d6&pvs=4)
Launch関数の使い方色々(Outlook,Teams Chat,他Appを開く)

PowerApps内に表示されているメールアドレスに対してOutlookの新規メール作成画面を開いたり、Teamsの新規チャット画面を開いたり、別のAppsを立ち上げる方法に関しての共有です。

私は非ITエンジニアの市民開発者なので、おそらく難しい言葉を使ってないと(自分では)思っているので気軽に読んで頂ければと思います。

その上でどなたかのお役に立てば幸いです。

# 1. 環境
手元に下記のようなShareppoint List, PowerApps(キャンバス)がある状況とします。
で、これらAppsのボタンからそれぞれOutlookの新規メール作成画面、Teamsの新規チャット作成画面、別Appsの立ち上げる画面を実装したいとします。

**Sharepoint List** (データソース名 "DummyDB")
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343332/2bd0d3ac-94ba-49f8-8a9e-e0c2171bc253.png)


**PowerApps** (上記SharepointListを元に生成したものに少し手を加えたもの)
    **・機能**：左側カラム上部の「検索」にワード入れると人がソートされ、選択されたアイテムの詳細が画面の右側に表示されるApps。人材管理や資産管理などに使える想定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343332/4a510255-ee7b-4ac6-b2e4-11dce2c462da.png)



# 2. 実例
画面上部に"Teams", "Outlook", "Apps"のボタンがあり、それぞれをクリックすると下記が起こります。

- **Outlook:**
    - 画面に表示されている人への新規メールを送る画面が開く
    - タイトルには"Hello"とデフォルトで入力される
    - 本文には"It's me!"とデフォルトで入力される


**・ボタンのOnSelectプロパティ**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343332/72a0f724-335c-4dda-ad52-a1bcaa03b0aa.png)

**・押すと開く新規メール作成画面**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343332/60529749-52e8-4fb6-a608-e850f2daf56c.png)


- **Teams:** 
    - 画面に表示されている人へのTeams Chat画面が開く
    - Teams Chat画面の本文に"Hello it's me!"とデフォルトで入力される

**・ボタンのOnSelectプロパティ**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343332/7ea7a0b1-73b4-46c9-bcaa-ff241bad4379.png)

**・TeamsのChat開くと初期入力されているテキスト**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343332/38430f00-0f11-4790-ab2b-d2102f538797.png)


- **Apps**
    - 別のAppsが開く 
        - 本来はAppsの共有用URLをLaunchの"()"の中にペーストした状態ですが、サンプルなのでざっくりした記載のみを載せています

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343332/12dbb55c-47f4-45d2-9711-fdf694ddbb65.png)

# 3. 解説 - Outlookを開く
抽象化したコードは下記です。
```
# 一般化した実例のコード
OnSelect = Launch("mailto:メールアドレス", "subject", "タイトル文字列", "body", "本文")

# 最低限のコード
OnSelect = Launch("mailto:メールアドレス")
```

* Launch関数：ほかのサイトやアプリを立ち上げる時に使用する関数
* "mailto:"：Outlookで新規メール立ち上げる時のおまじない(呪文)という理解でOK
* メールアドレス：メールの宛先 (実例中では変数 "DataCardValue2.Text"を使用しています)
* "subject", "body": 任意のタイトル、本文のパラメータ (無くてもOK)

# 4. 解説 - Teams Chatを開く

抽象化したコードは下記です。

```
# 一般化した実例のコード
OnSelect = Launch("https://teams.microsoft.com/l/chat/0/0?users=メールアドレス", "message", "Hello it's me!!")

# 最低限のコード
OnSelect = Launch("https://teams.microsoft.com/l/chat/0/0?users=メールアドレス")
```

* Launch関数：前述
* 'https://teams.microsoft.com/l/chat/0/0?users=' ：Teamsで新規メール立ち上げる時のおまじない(呪文)という理解でOK。(Outlookでの"mailto:"に該当)
* メールアドレス：Chatの宛先 (実例中では変数 "DataCardValue2.Text"を使用しています)
* "message": 任意の本文のパラメータ (無くてもOK)


# 5. 解説 - 別Appsを開く
抽象化したコードは下記です。一番シンプルなので特に詳細解説無しです。
```
Launch("Appsの共有URL")
```

# 4. おわりに
Launch関数を使いことで他の機能との連携がスムーズになり操作性があがると思うので、是非やってみて下さい。
module "XXX" not foundの対策法

普通のmodule "XXX" not foundの記事は

```
flutter clean
flutter pub get
```

ですが私は
それでは治らなかったのでここに忘れない為に記載させていただきます。

これは
xcode上でおそらくRunnerだけでなくPodfileがなければならないのです。

その為には以下のようなコマンドをターミナルで打てばいいのだと思います。

```
flutter clean
flutter pub get

cd ios
rm -rf Pods Podfile.lock Runner.xcworkspace

[ -f Podfile ] || flutter create .

pod install --repo-update          
cd ..


open ios/Runner.xcworkspace

```
【SQL】IN句とNULLの怖さ

# はじめに
業務で最近SQLをよく読むことが多くなったのだが、その際にNULL関連で勉強になったことがあったので備忘と啓発のための記事です

## 要約
samplesテーブル
|id|name|
|----|----|
|1|SQL|
|2|Python|
|3|JavaScript|
|NULL|C#|

idが2でも3でもNULLでもないレコードを検索したい
今回の場合、ID=1であるレコードだけを出力したい
```sql
SELECT * FROM samples WHERE id NOT IN (2, 3, NULL);
```

↓出力結果(対象レコードなし)
|id|name|
|----|----|

NULLの比較によって検索条件が想定外のものになってしまうのだろう

+ [オンライン実行環境での動作確認](https://sqlfiddle.com/sql-server/online-compiler?id=6f0a3d79-5acd-478a-b87d-0ab6dff38faf)

## 原因
検索条件を式変形していくと原因らしいものを特定できた

`id NOT IN (2, 3, NULL)`
`=`(IN句をORに同値変換)
`NOT ((id = 2) OR (id = 3) OR (id = NULL))`
`=`(∵ドモルガンの法則)
`(id <> 2) AND (id <> 3) AND (id <> NULL)`
`=`(∵id <> NULLは常にunknownを返す)
`(id <> 2) AND (id <> 3) AND unknown`
`=`(∵true AND unknown = unknown, false AND unknown = false)
`false もしくは unknown`

よって必ずtrueになることはないので条件に合うレコードは存在しなくなる

## 暫定対応策
NULLを特別扱いするのが一番簡単
```sql
SELECT * FROM samples WHERE id NOT IN (2, 3) AND id IS NOT NULL;
```

+ [オンライン実行環境での動作確認](https://sqlfiddle.com/sql-server/online-compiler?id=cb0e71c2-2dc0-4bc7-bbba-1c3132bc6913)

## 考えられる問題
対策でNULLを特別扱いすればよいとは言ったが、例えば以下の場合に考慮しにくい。

名簿テーブル
|id|部署|役割|
|----|----|----|
|1|S|A|
|2|S|B|
|3|S|C|
|4|T|A|
|5|T|D|
|6|T|NULL|

**T部署に存在しないS部署の役割**を探す場合
今回の場合、S(A, B, C) でT(A, D, NULL)なので役割BとCを出力して欲しい
```sql
SELECT 役割 FROM 名簿
WHERE
    役割 NOT IN
        (SELECT 役割 FROM 名簿 WHERE 部署 = 'T')
    AND 部署 = 'S'
;
```
これで残念ながらIN句にNULLが入ってしまい出力は0レコードとなってしまう

+ [オンライン実行環境での動作確認](https://sqlfiddle.com/sql-server/online-compiler?id=470154c3-8ced-4d68-a13c-d48d2ce23fc2)

上記のSQLのように「存在する/しない」を判断するならば以下のようにEXISTSを使って書いた方が安全だろう
```sql
SELECT 役割 FROM 名簿 m1
WHERE
	NOT EXISTS (
		SELECT 1 FROM 名簿 m2
		WHERE m2.部署 = 'T' AND m2.役割 = m1.役割
	)
    AND s1.部署 = 'S'
;
```
+ [オンライン実行環境での動作確認](https://sqlfiddle.com/sql-server/online-compiler?id=1cb25f0b-ba97-4ef0-b297-046da01c9dee)

結論として、SQLを読み書きする際は常にNULLを意識した方が良いのだろう
はじめての技術書読書体験を振り返る：学び方の改善メモ

## はじめに

前回の記事では、初めて技術書を使って学習に取り組みました。実際に読んでみると、思っていた以上に時間がかかってしまったり、理解しきれない部分で立ち止まってしまったりと、試行錯誤の連続でした。

そこで今回は、自分の学び方を一度振り返ってみることにしました。
技術書をより効率的かつ効果的に活用するために、実際に試してみて気づいたことや、反省点、工夫したことなどをまとめてみます。

## 丁寧すぎる読み方の落とし穴

わからない箇所があると、理解できるまで粘ってしまい、気づけば同じページを30分、1時間と見続けていたこともありました。

ですが、概要だけつかんで一通り読み進め、後で戻ってくるという読み方でも良かったのではと思います。

実際、あとから読み返してみると、前には理解できなかったことが「全体像が見えたことで自然と理解できた」「実は後の章で詳しく説明されていた」といった経験が何度かありました。

最初の1周目は全体をざっくり掴む読み方にして、2周目で重点的に深掘りする読み方とするのが、バランスのよい進め方かもしれません。

## 学ぶべき内容の取捨選択

読み終わって振り返ってみると、ここは今の自分にはそこまで深掘りしなくてもよかったな、と思う箇所がいくつかありました。

「すべてをしっかり理解しておかないといけない」という気持ちで読んでいましたが、冷静に考えてみると、今の自分にはまだ必要のない知識もあったと気づきました。

技術書は、幅広く網羅的に書かれていることが多いですが、「自分はこの本を通じて何を得たいのか？」という目的意識を持つことで、内容を取捨選択しやすくなると感じました。

## 生成AIを使った理解の深め方

分からない部分があったとき、生成AIに質問できるのは今の時代ならではの強みだと感じました。
技術書を読んでいて「なんとなく分かったけど、本当に理解できているのか不安なとき」や「この部分、もっとイメージしやすい説明が欲しいとき」に、生成AIに頼ることで理解が一段深まりました。

私が実際に使っていたプロンプトは以下のようなものです：
- 自分の理解を文章にして書き出し、「どこが間違っているか」を指摘してもらう
    → 自分の頭の中を言語化することで、自然と整理もできる
    
- 難しい仕組みや抽象的な概念を、身近なものにたとえて説明してもらう
    → イメージしづらいものも、具体的な例があると理解しやすくなる

これからも生成AIを上手く活用していくことで、学習効率をさらに高めていきたいと考えています。

## 感想

今回の振り返りを通して、完璧主義に陥らず、目的意識を持って学習に取り組むことの重要性を再認識しました。この学びは、技術書に限らず、今後のあらゆる学習において活かせるものだと感じています。

そして、この経験を糧に、これからも技術書を効果的に活用し、スキルアップを目指していきたいと思います。
XIAO ESP32C6+SSD1306、クリアして豆腐を召喚する(スペルは、「40-FF」...)


参考
----

https://akizukidenshi.com/catalog/default.aspx

https://akizukidenshi.com/catalog/g/g112031/

https://akizukidenshi.com/goodsaffix/ssd1306.pdf


いろいろ、注意
----

- 過去ログを見ようね!!! おねがいします。
- 3.2.0
- SSD1306を直接操作
- いろいろ　昨日(0418)のガジェットメイドカフェでOLED一体型が「かわいい」と褒めて、頂きましたので、勘違いして、精進いたします。(すすむ　こころ　と　書く)


目的
----

OLEDのテスト
豆腐がどこかに表示される
(まだ、アドレスの事は、やってないので?)

結果
----

![image_original(21).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/17c170e6-eb78-4e08-a747-510f65392a01.jpeg)

イメージ

![image_original(22).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/d0f5b834-98ab-451c-979d-660ddc26b520.jpeg)

プログラム
----



```c++



//有機ELのSSD1306で豆腐を召喚
//秋月のOLEDとアイテンドウのOLEDのアドレスは3c
//SSD1306_int_cls_8x8box_XIAO_ESP32C6_1


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


//定義
#define COMMAND_MODE               0x80 // continuation bit is set!
#define DATA_MODE                  0x40

#define SET_MEMORY_ADDRESSING_MODE 0x20 // takes one byte as given above
#define HORIZONTAL_ADDRESSING_MODE 0x00


//I2Cに配列を転送する
void write_s(uint8_t *str1, uint8_t len1) {

  Wire.beginTransmission(  0x3c  );

  for (int icount = 0; icount < len1; icount++) {

    //一文字出力
    Wire.write(*str1 ++);

  }//for

  Wire.endTransmission();

}//write_s


//セットメモリーアドレシングモード
void setMemoryAddressingMode()
{
  uint8_t databytes[4] = {COMMAND_MODE, SET_MEMORY_ADDRESSING_MODE, COMMAND_MODE, HORIZONTAL_ADDRESSING_MODE};
  write_s(databytes, 4);
}//setMemoryAddressingMode


//初期化
void setup() {

  //I2Cの初期化
  Wire.begin(D9,D10); //XIAO ESP32C6+SSD1306
  //Wire.begin(D10,D9); //XIAO ESP32C6+GROVE
  delay(200);

  //SSD1306の初期化スペル(魔法)
  //0x80,0x8D,0x80,0x14,0x80,0xAF
  write_s( (uint8_t*) "\200\215\200\024\200\257", 6);
  delay(100);

  //セットメモリーアドレシングモード (画面の終端に来たら画面の先頭に)
  setMemoryAddressingMode();

  //データの配列の定義
  uint8_t databytes[2] = {DATA_MODE,0x00};

  //画面のクリア
  databytes[1] = 0x00;
  for (int icount = 0; icount < ((128/8)*64); icount++) {
    write_s(databytes, 2);
  }//for

  //8x8の豆腐の表画
  databytes[1] = 0xFF; // 1111-1111
  for (int icount = 0; icount < 8; icount++) { // x8
    write_s(databytes, 2);
  }//for

}//setup


//メインループ
void loop() {
  delay(3); //dummy
}//loop



```
remiリポジトリ導入について

## remiリポジトリについて
今回centos 8 streamにおいてphp72を入れようとしたときにremiリポジトリがうまく入らなかったためそちらについてメモ書きとして残してきます。

### 発生のerror
問題: 競合するリクエスト
  -- nothing provides redhat-release >= 8.10 needed by remi-release-8.10-2.el8.remi.noarch from @commandline
(インストール不可のパッケージをスキップするには、'--skip-broken' を追加してみてください または、'--nobest' を追加して、最適候補のパッケージのみを使用しないでください)

・上記の様にエラーが発生しており、検索してもいい感じの検索結果は出てきませんでした。
しかし唯一バージョンを指定してインストールすればいいのでは？という記事を見つけました。
①問題
・そもそもarchiveが見つからない
🌟公式のページに行ったときにarchiveが見つからず四苦八苦しました。
そして気づいたのはarchiveというURLではなく、enterpriceというURLだったことに！
今回試したコマンドは下記の内容です

**dnf install https://rpms.remirepo.net/enterprise/8/remi/x86_64/remi-release-8.5-3.el8.remi.noarch.rpm**

もともと使おうとしていたコマンド
**sudo dnf install https://rpms.remirepo.net/archive/enterprise/8/remi/x86_64/remi-release-8.5-3.el8.remi.noarch.rpm**
↓
archiveというURLが見つからない（404error）のコマンド

初めに使おうとしていたコマンド
**sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-8.rpm**
↓
さっきのエラーが出た時のコマンド

とりあえずインストールできたからよかったけど今後もコマンドを使うときにはURLから直接インストールするものはリンクの生き死にを確認してみようと思う。
自分専用、文字の並びを逆にする。4文字まで


- UNO での　予定は、未定
- 簡単な文字操作

プログラム
----

オンラインコンパイラpaiza


```c++

#include <iostream>
using namespace std;

void r(char *str){
    
    char c;
    
    if(str[0] == 0 ) return;
    if(str[1] == 0 ) return;
    if(str[2] == 0 ) {
        c = str[0];
        str[0] = str[1];
        str[1] = c;
        return;
    }
    if(str[3] == 0 ) {
        c = str[0];
        str[0] = str[2];
        str[2] = c;
        return;
    }
    if(str[4] == 0 ) {
        
        c = str[0];
        str[0] = str[3];
        str[3] = c;
        
        c = str[1];
        str[1] = str[2];
        str[2] = c;
        
        return;
    }
    
    
}

int main(void){
    // Your code here!
    
    char s0[32] = "";
    char s1[32] = "1";
    char s2[32] = "12";
    char s3[32] = "123";
    char s4[32] = "1234";

    
    printf("START\n");
    r(s0);printf("%s\n",s0);
    r(s1);printf("%s\n",s1);
    r(s2);printf("%s\n",s2);
    r(s3);printf("%s\n",s3);
    r(s4);printf("%s\n",s4);
}


```

```

START

1
21
321
4321



```
【廃止】Sales Opportunities Superbadge Unit



https://trailhead.salesforce.com/content/learn/superbadges/superbadge_sales_opps_sbu


+ 商談レコードを作成および更新します。
+ 販売プロセスを反映して機会を調整します。
+ 商談を関連レコードに関連付けます。
+ 商談相手とそれぞれの役割に関わります。



# 商談と関連レコードの操作

特別な設定でDeveloper Edition組織にサインアップし 、Solara、Greenwich Media、Sunshine Distributorsとの取引をサポートするレコードを管理します。

:::note alert
We can't find an account created for Solara.
:::

今回もただの英語の理解力の問題になりそうだ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/a8775be1-134a-4c28-ae47-0135eaeaa7e2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/53100e2a-2490-4bef-8dff-999e603533a6.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/624c9d82-1cc8-4c4a-b9b8-3b8901aa7af3.png)


:::note alert
We can't find a correct contact record for Ianeira Giana.
:::

:::note alert
We can't find any Solara opportunity that matches the specified criteria.
:::

どうやっても読み取れん

https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000J5qZJ0AZ


:::note alert
We can't find the correct relationship configuration for Ianeira Giana.
:::

:::note alert
We can't find the correct information for the Greenwich Media deal. Make sure you use lead conversion to create the opportunity, account, and contact, and that the opportunity name follows the UMS sales process.


Greenwich Mediaの取引に関する正しい情報が見つかりません。リードコンバージョンを使用して商談、取引先、取引先責任者を作成し、商談名がUMSの営業プロセスに準拠していることを確認してください
:::

:::note alert
We can't find the correct configuration for the Sunshine Distributors deal.


Sunshine Distributors 取引の正しい構成が見つかりません。
:::




# 営業チームとして働く
商談レコードを更新して、他のチーム メンバーと協力して販売プロセスをサポートします。

:::note alert
We can't find the correct order of the opportunity related list.
:::


:::note alert
We can't find the correct sharing settings for the Dickenson Mobile Generators deal.
:::

もしかして、こっち？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/4a705b64-cf38-49bc-9c64-b9aeedcfd7cd.png)


:::note alert
We can't find the correct account team setup for Second Industry LLC.
:::


:::note alert
We can't find the University of Arizona record associated with the correct records.


正しいレコードに関連付けられたアリゾナ大学のレコードが見つかりません。
:::

どうしたいんだろう？取引先名に変えてもエラーになりますね。

University of Arizona: An opportunity for 3 million should be managed by another team. Reassign this deal so that Alan Lin is responsible for it. Make sure to double check the associated account name.

取引先を変えろって！！意味が分からん


:::note alert
We can't find the opportunity split configured properly.


適切に設定された商談分割が見つかりません。
:::
一番安いGPUでも動くLLM bitnet-b1.58-2B-4T 

T4で動く。

# 使い方

```python
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

model_id = "microsoft/bitnet-b1.58-2B-4T"

# Load tokenizer and model
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    torch_dtype=torch.bfloat16
)

# Apply the chat template
messages = [
    {"role": "system", "content": "You are a helpful AI assistant."},
    {"role": "user", "content": "How are you?"},
]
prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
chat_input = tokenizer(prompt, return_tensors="pt").to(model.device)

# Generate response
chat_outputs = model.generate(**chat_input, max_new_tokens=50)
response = tokenizer.decode(chat_outputs[0][chat_input['input_ids'].shape[-1]:], skip_special_tokens=True) # Decode only the response part
print("\nAssistant Response:", response)
```

>以下の製品をみんなが買いたくなるクールなラップを作って
>
>製品名：Mac Studio (2025) M4 Max
SoC：M4 Max（最大16CPU＋40GPU＋Neural Engine）​
メモリ：36 GB〜128 GB ユニファイドメモリ
ストレージ：512 GB〜8 TB SSD
外部ポート：背面 Thunderbolt 5×4、USB‑A×2、HDMI、10 GbE／前面 USB‑C×2、SDXC​
サイズ／重量：7.7″×7.7″×3.7″・約2.8 kg
価格：$1,999〜（日本税込 約27万5千円〜）​
発売日：2025年3月12日出荷開始
主な強化点：M2 Max比で最大2倍超のCPU/GPU性能、Thunderbolt 5搭載、静音設計継続​

```
Assistant Response: (Verse 1)
Yo, it's the future, meet the Mac Studio (2025) M4 Max,
With 16 CPUs, 40 GPUs, and a Neural Engine that's a blast.
Unified memory, got 36 to 128 gigabytes,
So you can run all your games, without any inhibitions.

(Chorus)
Mac Studio (2025) M4 Max, it's the king of the scene,
Got the power, got the speed, it's the best machine.
From 512 gigabytes to 8 terabytes,
With Thunderbolt 5 and USB-C, you're ready to begin.

(Verse 2)
On the back, four Thunderbolt 5, for all your data needs,
Two USB-A, HDMI, 10 GbE, for a seamless blend.
On the front, two USB-C, for all your charging needs,
SDXC, it's the future, it's the best it can be.

(Chorus)
Mac Studio (2025) M4 Max, it's the king of the scene,
Got the power, got the speed, it's the best machine.
From 7.7 inches to 7.7 inches, it's got the size,
But don't let the size fool, it's got all you need.

(Bridge)
Up to twice the CPU and GPU, that's what it does best,
With quiet design, it's the perfect fit for the rest.
In Japan, it's 275,000 yen, but worldwide it's a steal,
Mac Studio (2025) M4 Max, it's the future, it's real.

(Chorus)
Mac Studio (2025) M4 Max, it's the king of the scene,
Got the power, got the speed, it's the best machine.
From 7.7 inches to 7.7 inches, it's got the size,
But don't let the size fool, it's got all you need.

(Outro)
So what are you waiting for, get your Mac Studio (2025) M4 Max,
It's the future, it's the best, it's the future, it's the past.
```

50秒かかった。

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
[GitHub](https://github.com/john-rocky)
あらゆるITエンジニアが身につけて損はない最強の言語を見つけた！

# はじめに

エンジニアを目指す皆さん、エンジニアになりたての皆さん、キャリアアップを考えているエンジニアの皆さん、どのような現場や環境においても役に立つ最強の言語を見つけました。

この言語を身につけて 損 は あ り ま せ ん。

# それは「英語」です

あ、待って、まだブラウザバックしないで。

これから理由を説明します。

# 理由① 「ほとんどのものは英語圏で作られている」

手元にあるパソコンを見てみましょう。ほとんど英語圏で作られているはずです。

* CPU → 英語圏
* OS → 英語圏
* プログラミング言語 → 英語圏
* フレームワーク → 英語圏
* IDE → 英語圏
* ネットワーク → 英語圏
* 生成AI → 英語圏

つまり、英語を読めると、早い！新鮮！正確！な情報ソースに辿り着けるわけです。

# 理由② 「プログラムはほぼ英語」

プログラムはほぼ英語です。

例えば、これはReactのソースコードの一部です。[^1]

[^1]: https://github.com/facebook/react/blob/main/packages/react-dom/src/server/ReactDOMFizzStaticBrowser.js

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59475/f7d243dd-e53f-4797-b136-c99655b40514.png)

英語が読めるひとにとっては、以下のように見えています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59475/670b8ea4-2117-4b70-8f01-d1437f9988fc.png)

つまり、英語を読めると、プログラムをすらすら読めるわけです。

# 理由③ 「メッセージはほとんど英語」

理由① を前提としまして、プログラミング言語やフレームワークが出力するメッセージは英語です。

例えば、これはTypeScriptが出力するメッセージです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59475/093aaeb8-b969-40da-bd39-65837e145445.png)

英語が読めるひとにとっては、以下のように見えています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59475/d1f56d70-5e41-4415-a7bb-32a3c15eab27.png)

つまり、英語を読めると、すばやく問題解決できるわけです。


# 理由④ 「圧倒的な情報格差」

「typescript ts2355」でググった時のヒット件数です。

言語指定なし: 174件

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59475/e10ab61a-f0c3-4723-96ad-af88d26a2259.png)

日本語ページ指定: 10件

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59475/a2246dc6-303b-4b60-9cfc-ca810fdf8af2.png)

つまり、英語を読めると、日本語では辿り着けない情報に辿り着けるわけす。

# 理由⑤ 「生成AIは英語がお好き」

英語プロンプトのほうが、日本語プロンプトより良い（主観）結果が返ってきませんか？

つまり、生成AI時代は英語が有利なのです。

# 理由⑥ 「サポートは英語で問い合わせた方が素早く解決する」

理由①を前提としまして、やはり相手に通じる言語でやりとりしたほうが、真摯に対応してもらえる気がします（主観）。

つまり、素早く問題解決するには、相手の言語を使うと都合がよいわけです。

# 理由⑦ 「ITエンジニアをやめても役に立つ」

もしあなたがなんらかの理由でITエンジニアから離れるとしても、英語はきっと役に立つはず。


# まとめ

あらゆるITエンジニアが身につけて損はない最強言語「英語」について、その理由を7つ紹介いたしました。

1. ITエンジニアが使うほとんどのものは英語圏で作られている
1. プログラムはほぼ英語である
1. プロゴラミング言語やフレームワークが出力するメッセージはほとんど英語である
1. 日本語と英語には圧倒的な情報格差がある
1. 生成AIは、英語プロンプトのほうが期待に沿う結果が返る
1. サポートは、英語で問い合わせた方が素早く解決する
1. ITエンジニアをやめても、英語はきっと役に立つ

エンジニアとしてのスキルアップ、まずは英語から、というのはどうでしょう？
書けなくたっていい、ましてやしゃべれなくたっていい、読めるだけで十分 :heart:
自分専用の整数を文字列に変換する。ただし、順番が逆


- UNO での　予定は、未定
- UNO に　itoaが無いので?
- 順番が逆


プログラム
----

```c++

#include <iostream>
using namespace std;

void myitoa(char *str,int num){
    
    int m = 0;
    if(num < 0){
        num = 0 - num;
        m = 1;
    }
    
    do{
        *str++ = num % 10 + '0';
        num /= 10;
    }while(num != 0);
    
    if(m == 1 ){
        *str++ = '-';
    }

    *str = 0;
    
}

int main(void){
    // Your code here!
    char s[32];
    myitoa(s,1234);
    printf("%s\n",s);
    myitoa(s,-1234);
    printf("%s\n",s);
}

```

```

4321
4321-

```
自分専用の文字列の数字を整数の数字に変換する(知っていると思うけど)


- UNO 等　小規模マイコンには、atoiがなぜか、無いので?
- UNO での　予定は、未定


プログラム
----

オンラインコンパイラpaiza

```c++

#include <iostream>
using namespace std;

int myatoi(char *str){
    int num = 0;
    while(*str != '\0'){
        num += *str - '0';
        num *= 10;
        str++;
    }
    num /= 10;
    return(num);
}

int main(void){
    // Your code here!
    printf("%d\n",myatoi("1234"));
}


```

```

1234

```
ベクトルの内積と三角形の余弦定理について

# はじめに
高校数学で習うベクトル内積の公式は、三角比で扱った余弦定理がもとになっている。しかし、そのことについて理解していない受験生や大学1,2年生は多い。したがって、今回は、余弦定理を用いることで、内積の公式を導出していき、それに関連した外積の公式と点と直線の距離の公式を証明する。

# 内積の公式
$\Delta OAB$に対して、余弦定理より以下のことが成立する。
```math
|\vec{AB}|^2=|\vec{OA}|^2+|\vec{OB}|^2-2|\vec{OA}||\vec{OB}|\cos \theta
```
ただし、$\angle AOB=\theta$とする。


ここで、直交座標より、A,Bの座標をそれぞれ、$(x_A,y_A),(x_B,y_B)$とすると、以下のことが成立する。

```math
|\vec{AB}|^2=(x_B-x_A)^2+(y_B-y_A)^2,|\vec{OA}|^2=x_A^2+y_A^2,|\vec{OB}|^2=x_B^2+y_B^2
```

したがって、これらを余弦定理の式に代入して整理する。

```math
(x_B-x_A)^2+(y_B-y_A)^2=(x_A^2+y_A^2)+(x_B^2+y_B^2)-2|\vec{OA}||\vec{OB}|\cos \theta
```

```math
2|\vec{OA}||\vec{OB}|\cos \theta=(x_B-x_A)^2+(y_B-y_A)^2-(x_A^2+y_A^2)-(x_B^2+y_B^2)
```

```math
|\vec{OA}||\vec{OB}|\cos \theta=x_Ax_B+y_Ay_B
```

したがって、$\vec{OA}\cdot\vec{OB}=x_Ax_B+y_Ay_B$と表記するといかのことが成立する。

```math
|\vec{OA}||\vec{OB}|\cos \theta=\vec{OA}\cdot\vec{OB}(=x_Ax_B+y_Ay_B)
```

# 外積の公式

$\Delta OAB$の面積を$S$とおくと、外積の大きさ$|\vec{OA}\times\vec{OB}|$は$2S$と定義される。

まずは、$S$について考察する。三角形の面積の公式を用いて、

```math
S=\frac{1}{2}|\vec{OA}||\vec{OB}|\sin \theta
```

これを余弦で書くと以下の通りである。($0<\theta<\pi$より)

```math
S=\frac{1}{2}|\vec{OA}||\vec{OB}|\sqrt{1-\cos^2 \theta}
```

ここで、内積の公式より、

```math
\cos \theta=\frac{\vec{OA}\cdot\vec{OB}}{|\vec{OA}||\vec{OB}|}
```

したがって、

```math
S=\frac{1}{2}|\vec{OA}||\vec{OB}|\sqrt{1-\cos^2 \theta}=\frac{1}{2}|\vec{OA}||\vec{OB}|\sqrt{1-(\frac{\vec{OA}\cdot\vec{OB}}{|\vec{OA}||\vec{OB}|})^2}
```

となり、

```math
S=\frac{1}{2}\sqrt{(|\vec{OA}||\vec{OB}|)^2-(\vec{OA}\cdot\vec{OB})^2}=\frac{1}{2}|x_Ay_B-x_By_A|
```
ただし、公式$\sqrt{p^2}=|p|$を用いた。


したがって、符号に関する議論は省略するが、$\vec{OA}\times\vec{OB}=x_Ay_B-x_By_A$と表すことができる。

# 点と直線の距離公式

さて、直線$AB$と原点$O$の距離$h$は、$\Delta OAB$の$AB$を底辺とみた、高さ$h$に対応するので、

```math
\Delta OAB =\frac{1}{2}|\vec{AB}| h
```

と表すことができる。

```math
h=\frac{2\Delta ABC}{ |\vec{AB}|}=\frac{|x_Ay_B-x_By_A|}{\sqrt{(x_B-x_A)^2+(y_B-y_A)^2}} 
```

ここで、$\Delta OAB$ を$x$軸方向に、$x_1$、$y$軸方向に$y_1$だけ平行移動すると$\Delta O' A' B' $と重なる。ただし、$O'(x_1,y_1),A'(x_A+x_1,y_A+y_1),B'(x_B+x_1,y_B+y_1)$

となる。ここで、直線$AB$の一般形の方程式は、

```math
-(y_B-y_A)x+(x_B-x_A)y+(-(y_B-y_A)(x_A+x_1)+(y_A+y_1)(x_B-x_A))=0 
```

ここで、$a=-(y_B-y_A),b=(x_B-x_A)(x_B-x_A),c=-(y_B-y_A)(x_A+x_1)+(y_A+y_1)(x_B-x_A)$とおくと、天下り的ではあるが、

```math
ax_1+bx_1+c=x_Ay_B-x_By_A
```

となることが分かる。したがって、

```math
h=\frac{|ax_1+by_1+c|}{\sqrt{a^2+b^2}} 
```

# まとめ
今回は、三角比で習う三角形の余弦定理を用いることで、ベクトルの内積の公式を導出した。つぎに、その三角形の面積に対応する外積を導出した。最後に、それを底辺で除することで、点と直線の距離の公式を導出した。このことは、大学入試数学では頻出な事項なのでしっかりと理解しておきたい。
【スッキリわかる！】Google Cloud 認証入門！

この記事では、Google Cloud における”認証”、”認可”の仕組みや
IAMの基本用語からOAuth2やサービスアカウントなど
よく使う用語をわかりやすく解説します。


### 簡単なまとめ
>  **認証**：本人確認を行うこと
>  **認可**：誰が何をできるかの権限管理  
>  **IAM（Identity and Access Management）**：
　リソースに対して”誰”が”何”をできるかを定義する仕組み
> **プリンシパル**：”誰”の部分（ユーザー、グループ、サービスアカウントなど）
> **サービスアカウント**：サーバー間通信や自動化処理で用いる「非人間ユーザー」
> **権限**：”何”の部分（閲覧、編集、管理など）
> **ロール**：関連する複数の権限をひとまとまりにしたもの
> **OAuth2**：エンドユーザーが自分のデータにアクセス権をアプリに与える仕組み
> **ADC（Application Default Credentials）**：
　認証方法は様々だけど、ADCはその環境が持っている情報（JSON キーやユーザー認証情報）を使って良い感じに認証してくれる
---

## 1. 認証（Authentication）と認可（Authorization）の違い

### 1.1 認証（Authentication）
認証とは「あなたは誰ですか？」を確かめるプロセスです
- **ユーザー認証**：ADCなどでユーザー認証情報を受け取り認証する
- **サービスアカウント認証**：サービスアカウントキーを使い認証する
- **OAuth2**：
　Webやモバイルのアプリで、ユーザーがGoogle Driveなどの自分のサービスへ
　アクセス許可を与える際に使います
　
 OAuth2の典型的なフローは以下のとおりです
  1. Google API Console で OAuth2 クライアント ID とシークレットを取得  
  2. 認可サーバーにリクエストを送り、承認画面を経て認可コードを取得  
  3. 認可コードでアクセストークンを交換し、API 呼び出し時にトークンを添付する


### 1.2 認可（Authorization）
認可とは「この主体がこのリソースに対して何をできるか」を管理する仕組みです

- **IAM ポリシー**：リソース階層（組織 > フォルダ > プロジェクト > リソース）ごとにポリシーを結びつけ、プリンシパル（ユーザーやサービスアカウント）と ロール（権限のまとまり）を紐づけます
- **権限**：API メソッドや操作などを行うための権限
- **ロールの種類**：
  - **基本ロール**：全権限、読み書き、読み取りのみなどの基本的な権限セット
  - **事前定義ロール**：BigQuery 管理者などのGoogle 提供の細かな権限セット
  - **カスタムロール**：権限をカスタムした自作ロール

## 2. 主な認証方法とその使いどころ
### 2.1 gcloud CLI を使ったユーザー認証
- `gcloud auth login`：個人ユーザーとして CLI を認証
- `gcloud auth application-default login`：ADC 用にユーザー認証トークンを設定

### 2.2 サービスアカウント認証（サーバー間通信向け）
- **長期認証**：ダウンロードした JSON キーを環境変数に設定（簡単、キー流出リスク大）  
- **短期認証**：トークン（一定期間有効なキーのようなもの）を取得し使用
- **Workload Identity Federation**：Kubernetes や他クラウド上の ID プロバイダー（OIDC/SAML）と連携し、サービスアカウントキー不要でトークンを発行

### 2.3 Application Default Credentials（ADC）
ADC はライブラリが実行環境に応じて以下の順序で認証情報を探索します 
1. 環境変数 `GOOGLE_APPLICATION_CREDENTIALS` が指す JSON キー
2. ローカルに `gcloud auth application-default login` で設定したユーザー情報
3. GCE／GKE 上で割り当てられたサービスアカウント
4. Cloud Shell や Cloud Functions／Cloud Run などのランタイム用自動付与アカウント


## 3. 権限の注意点

1. **最小権限の原則**（Least Privilege）
   ロールは必要最低限の権限に留める
2. **サービスアカウントキーの管理**
   可能な限りキーではなくトークンや Workload Identity を使う
3. **カスタムロールの活用**
   ロールの権限が余分な場合は必要な権限のみのカスタムロールを作成する
4. **監査ログの有効化**  
   Cloud Audit Logs で実際の認証・認可イベントを記録し、異常検知に役立てる
Google Agent Development Kit の adk コマンドが見つからない


# 結論から先に言うと
google-adkをpipインストール後、adkコマンドを実行しても command not foundになる。
```
~/.local/bin/
```
のパスが通っていなかった

パスを通す
```bash
export PATH="$HOME/.local/bin:$PATH"
```
ギャラリーコントロールの並び順をランダムにするItemsプロパティ

ギャラリーコントロールのItemをランダム表示する方法に関しての共有です。

私は非ITエンジニアの市民開発者なので、おそらく難しい言葉を使ってないと(自分では)思っているので気軽に読んで頂ければと思います。

その上でどなたかのお役に立てば幸いです。


# 1. 環境
手元に下記のようなShareppoint List, PowerApps(キャンバス)がある状況とします。
で、画面左側のギャラリーコントロールの並び順をランダムにしたいとします。

**Sharepoint List** (データソース名 "DummyDB")
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343332/3b2ea65b-e1ec-4f5b-879f-d69997e029c6.png)


**PowerApps** (上記SharepointListを元に生成したものに少し手を加えたもの)
・**機能**：左側カラム上部の「検索」にワード入れると人がソートされ、選択されたアイテムの詳細が画面の右側に表示されるApps。人材管理や資産管理などに使える想定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343332/12eb3f3e-301a-4bdb-9b42-471e372009c1.png)
...この機能で利用するのは黄色でハイライトしたボタンコントロールとギャラリーコントロールのみです。

# 2. 実例
このサンプルの場合ではそれぞれのコントロールで下記の設定がなされてます。
これで"Random"のボタン押すとギャラリーコントロールの表示順がランダムになります。
以降の段落で詳細の解説します。

**ボタンコントロールの設定**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343332/96100fee-167d-4b4c-b222-db596ca74b28.png)
※"Shuffled"はコレクション名、"DummyDB"はSharepoint List名

**ギャラリーコントロールの設定** 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343332/95a5a3dd-2e9a-4af2-a797-29a75c078575.png)
※"SearchInput"は検索ボックスに使ってるテキスト入力コントロール名
※"Title", "emailAddress"はSharepoint Listのカラム名

**ランダム表示したギャラリーコントロール** 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343332/ca72dc20-f4e2-4e8e-ac08-6d49500c59f1.png)



# 3. 解説 - ボタンコントロールのOnSelectプロパティ
少し一般化して書くと下記のように設定するとOKです。

```PowerApps
OnSelect = ClearCollect('コレクション名', Shuffle('データソースのSharepoint List名'))
```
- **ClaerCollect関数：**
    - **機能**：指定したコレクションのデータを削除し新規データをコレクションに追加する
        - コレクション：テーブル型の値を格納する変数(ClearCollect関数で生成されます)
            - 実例中では"Shuffled"がコレクションです
    - **基本構文**：下記
```PowerApps
ClearCollect('空にして更新するコレクション', 'コレクションに入れるデータ(Sharepoint List)')
```

- **Shuffle関数：**
    - **機能**： テーブル型のデータの並び順をランダムにシャッフルする
    - **基本構文**：下記

```
Shuffle('データソースのSharepoint List名')
```


# 4. 解説 - ギャラリーコントロールのItemsプロパティ
こちらも少し一般化して書くと下記のように設定するとOKです。
簡単にまとめると**コレクションが空ならSharepoint Listのままで表示、そうでなければコレクションを表示**ということをしています。

```
Items = If(IsEmpty('コレクション名'), Search('データソースのSharepoint List', '検索用テキスト入力コントロール名'.Text, 検索対象カラム1, 検索対象カラム2), Search('コレクション名', '検索用テキスト入力コントロール'.Text, 検索対象カラム1, 検索対象カラム1))
```

- **IsEmpty関数 (≠ IsBlank関数)**
    - **機能**：コレクションが空かを判断する。空ならTrue、そうでなければFalse。
    - **補足**：IsBlankは"値"に対する判断、IsEmptyは"テーブル"に対する判断で別物です。
    - **基本構文**：下記

```
IsEmpty('データソースのSharepoint List名')
```
- **Search関数**
    - **機能**：データソースをフィルタする
    - **基本構文**：下記

```
Search('データソースのSharepoint List','検索ボックスのTextプロパティ','検索対象カラム1','検索対象カラム2'...) 
```

# 5.おわりに
こんな感じでした。どなたかのお役に立てば幸いです。
ちなみにランダム表示した後にアルファベット順に戻す場合にはSortByColumns関数を組み合わせればできます。余裕があれば別途記事を作るかもしれません。
ProxmoxのWebUIをApacheでリバプロしたい

# ProxmoxのWebUIをApacheでリバプロしたい
ホスト名関係とWebsocketでちょっと詰まった……
※hosts回り間違えるとWebUI死ぬので、コンソールへのSSH接続確認をしてから作業推奨

## 環境
以下環境で構築しています
```
Proxmox導入済み
ドメイン取得済み

Proxmox:
# pveversion
pve-manager/8.4.1/2a5fa54a8503f96d (running kernel: 6.8.12-9-pve)

リバプロ用Apache(別ホスト)
SSL証明書導入済
```



## Proxmox側Hosts追記（最初からドメイン名で構築していれば不要）
Originヘッダーの整合性を取らないとWebsocketが通らない為ドメインを追記
```
XXX.XXX.XXX.XXX   prox hogehoge.com servername.local servername
```


## Apachリバプロ
WebUIは通常通りProxyPassとReverseでOK
WS用は通常のProxyPassより前に記載で確実に動作する(ハズ)
```
<VirtualHost *:443>
    ServerName hogehoge.com

    SSLEngine on
    SSLProxyEngine On
    SSLProxyVerify none
    SSLProxyCheckPeerName off

    SSLCertificateFile /path/to/key/fullchain.pem
    SSLCertificateKeyFile /path/to/key/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

    ProxyPreserveHost On

    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-Host "hogehoge.com"
    RequestHeader set X-Forwarded-For %{REMOTE_ADDR}s

    ProxyPassMatch ^/api2/json/.*/vncwebsocket wss://XXX.XXX.XXX.XXX:8006

    ProxyPass / https://XXX.XXX.XXX.XXX:8006/ retry=0
    ProxyPassReverse / https://XXX.XXX.XXX.XXX:8006/
</VirtualHost>
```

## ドメインでWebUIアクセス
通ったやったー！
【React】chakraUIのSelectタグのmultiple設定の時、クリックで一気に選択される


React×Chakra UI を使用してフロントエンドを作成した際に、指定の要素から複数を選択できるような UI を`Select`を利用して実装していました。

https://www.chakra-ui.com/docs/components/select#multiple

その際にタイトルにも記載したように、１つ選択するとすべての要素にチェックが入ってしまうバグが発生し、解決に長い時間がかかってしまったため共有します。

## 修正前と修正後の動作

言葉だけではどのようなバグか伝わりずらいと思うので修正前後の違いを示します。

**修正前**
![修正前.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3783169/6aa071eb-bdce-4f73-86ed-0fc9aa7b4ce5.gif)

**修正後**
![修正後.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3783169/0bf58018-ea52-4514-b488-5329549f7894.gif)

ご覧の通り修正前は１つ選択するとすべての項目が選択状態になっています。

## 原因

`Select`に渡している値を`createListCollection`を用いて作成する際に`item`に設定する値の型が`Temp[]`(Temp は自分のコードで定義したデータクラス)になっていました。。正しくは下記の型で渡す必要がありました。

```typescript
{
  label: any;
  value: any;
}
[];
```

## 修正方法

```diff_typescript
  // 表示用ダミーの元データ
  const tempSkills: Skill[] = [
    { id: 1, name: "JavaScript", displaySkillInfo: () => "JavaScript" },
    { id: 2, name: "TypeScript", displaySkillInfo: () => "TypeScript" },
    { id: 3, name: "React", displaySkillInfo: () => "React" },
    { id: 4, name: "Node.js", displaySkillInfo: () => "Node.js" },
    { id: 5, name: "Python", displaySkillInfo: () => "Python" },
  ];

  // 実際にSelectタグに渡すデータ
- const skills = createListCollection({ items: tempSkills });
+  const skills = createListCollection({
+    items: tempSkills.map((skill) => ({
+     label: skill.name,
+     value: skill.id.toString(),
+   })),
+  });

```

## おわりに

この間違いについて JavaScript だったら一生気づけなかったと思います。TypeScript の恩恵を感じました。

この記事が皆様のコーディングライフの助けになれば幸いです。

## 参考

https://www.chakra-ui.com/docs/components/select#multiple
Quickstartやって気づいたDocker Composeのアップデート備忘録（version廃止 / include / watch）

# はじめに
久しぶりのDockerなので、Quickstartからやってみたところ、いくつか目新しい点がありました。
この記事では、その中でも特に目に止まったポイントを **備忘録＋共有** という形でまとめます。

📚 参考: [Docker Compose Quickstart](https://docs.docker.com/compose/gettingstarted/)

# 対象読者
- しばらく Docker を触っていなかった方  
- 英語のリファレンスを細かく読んでいない方  
- **Docker Compose の最近の書き方**をざっくり知りたい方  

※ この記事で紹介するのは、主に **2023年までに追加された機能**です。2025年現在でもバリバリ使えます。

# `compose.yaml` を推奨（`docker-compose.yaml`は旧スタイル）
`docker-compose.yaml` も依然としてサポートされていますが、  
現在は **`compose.yaml` が推奨** です。

# `version` はもう書かなくてOK！
Compose V2 以降では `version` の記述は非推奨になりました。

昔はこんな風に書いていましたよね：

```
version: "3.8"  
services:  
  ...
```

versionを書かなくても、最新Compose仕様を優先するため、不要になったみたいです。

https://docs.docker.com/reference/compose-file/version-and-name/

# `include`: Composeファイルを分割できる
:::note info
Docker Compose 2.20.3 以降
:::

外部yamlファイルを組み込むことができます。
これにより可読性を向上させることができます。

``` yaml
include:
   - infra.yaml
services:
  web:
    build: .
    ports:
      - "8000:5000"
```

https://docs.docker.com/compose/how-tos/multiple-compose-files/include/

# `watch`: ファイル変更を自動反映！
:::note info
Docker Compose 2.22.0 以降
:::

コードを編集すると、実行中のconposeが自動的に更新される機能です。

``` bash
docker compose watch
# または
docker compose up --watch
```

``` yaml
services:
  web:
    build: .
    ports:
      - "8000:5000"
    develop:
      watch:
        - action: sync
          path: .
          target: /code
```

📘 解説：  
- `path`: ローカルのパス（compose.yamlからの相対）  
- `target`: コンテナ内のパス


https://docs.docker.com/reference/cli/docker/compose/watch/

https://docs.docker.com/compose/how-tos/file-watch/

# おわりに
今回、Quickstartをベースに最新のCompose機能を調べ直してみました。

2025年にも新機能（OCI artifacts）が追加されていたので、
興味がある方は公式リファレンスもぜひチェックしてみてください👇

https://docs.docker.com/compose/how-tos/oci-artifact/

ちなみに、記事作成にあたってChatGPTに添削してもらって今時な感じにしてもらいました。
絵文字を使ったり太字にしたり、見やすくなる工夫がされたなーと感じました。
機敏な方は、あ、ChatGPT使ったな？とすぐわかるんですかね。

ここまでお読みいただき、ありがとうございました。
最近のプラットフォームアップデート

リリース2025.3.27には、アップデートと改善点が含まれています。主な改善点は、(1) Wave.jsで特定の原子の原子座標を表示する機能、(2) Wave.js内で構造可視化画像からGIF画像を作成する機能、(3) プラットフォームの共有アイテムをWeb上の誰でも閲覧できる「外部共有」ページのデザイン刷新です。

機能:
- [Wave.js] 3Dビューアで座標を表示
- [Wave.js] 3D構造可視化用のGIF作成機能を追加

改善点:
- 「外部共有」の実装を更新
- Windows向けSSHガイドを更新

バグ修正:
- [API例] 画像URLを修正

開発者向け:
- [AX/Webapp] WebアプリでJLのすべてのAPI例のテストを追加
- [AX, MD] GHAでノートブックをテスト
- [AX] ノートブックのヘルスチェックテスト

無料でお試しください: https://www.mat3ra.com/?utm_source=qiita&utm_medium=newsletter

#materialsscience
#mat3ra

![Post-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4022238/f6f49f17-136f-4192-a499-14894bc15fab.png)
ネットワークスペシャリストに頻出するIEEE802.X

ネットワークスペシャリスト試験に頻出するIEEE802.Xを一覧化

|名称|詳細|
|---|---|
|IEEE 802.3af|PoE(Power over Ethernet): イーサネット配線で利用されるツイストペアケーブルを介してデータと電力を同時に供給する技術(最大給電15.40W)|
|IEEE 802.3at|PoE+(最大給電30.0W)|
|IEEE 802.3bt|PoE++(最大給電60W, 99W)
|IEEE 802.11a|無線LANの規格(周波数帯5GHz帯, 最大伝送速度54Mbps)|
|IEEE 802.11b|無線LANの規格(周波数帯2.4GHz帯, 最大伝送速度11Mbps)|
|IEEE 802.11g|無線LANの規格(周波数帯2.4GHz帯, 最大伝送速度54Mbps)|
|IEEE 802.11n|無線LANの規格(周波数帯2.4/5GHz帯, 最大伝送速度600Mbps)|
|IEEE 802.11ac|無線LANの規格(周波数帯5GHz帯, 最大伝送速度6.9Gbps)|
|IEEE 802.11ax|無線LANの規格(周波数帯2.4/5GHz帯, 最大伝送速度9.6Gbps)|
|IEEE 802.11be|無線LANの規格(周波数帯2.4/5/6GHz帯, 最大伝送速度46Gbps)|
|IEEE 802.11i|暗号化アルゴリズムにAESを初めて採用したWPA2が準拠する方式|
|IEEE 802.1Q|VLANタグの標準フォーマットを策定|
|IEEE 802.1X認証|イーサネットや無線LANで使用される認証プロトコルの規格であり, 以下の三要素から成る<br>サプリカント: クライアント(PC)<br>オーセンティケータ: 認証スイッチ, アクセスポイント等<br>認証サーバ: RADIUSサーバ等|
WSLのUbuntuに最速でDockerを導入する方法（公式スクリプト使用・軽量構成）

:::note warn
 本記事の手順は **WSL環境上のUbuntu** を前提としています。macOSの場合、Lima などでWSL相当のUbuntu環境を用意していれば、同じ手順で動作するはずです。
:::

Dockerをインストールしたり、完全に削除したりする機会が時々あるので、自分用の最小手順をまとめておきます。
**面倒な手順は一切なし。インストールも削除もわずか1分でできます。**

---

### Dockerのインストール（公式スクリプト準拠）

まずはインストールです。以下の1行を実行すれば、必要なパッケージがすべてインストールされます。

```bash
sudo wget -O- https://get.docker.com | sudo sh
```


公式サイトでは `curl` を使う方法が紹介されていますが、WSLのUbuntuはデフォルトでは `curl` をインストールしていないと思うので（たぶん）、ほぼインストールされているはずの `wget` を使う方法で説明します。

:::note
WSL環境で実行した場合、インストール冒頭で20秒ほど停止しますが、これはDocker Desktopの利用を促すためです。そのまま待ちましょう。
:::


### sudo なしで使えるようにする

```bash
sudo usermod -aG docker $USER
```

実行後は一度 **ログアウト** またはターミナルを閉じて、 **グループ変更を反映** します。

### 動作確認

```bash
docker --version
docker run hello-world
```

`Hello from Docker!`が表示されれば成功です！

### 何がどのようにインストールされたか確認したいとき

```bash
dpkg -l | grep docker
less /var/log/apt/history.log
```

Dockerだけではなく依存ライブラリなどもインストールされます。不要になった場合は、上記で得られる情報を参考に削除するとよいです。

### Dockerを完全に削除する方法

上記の手順で調べるのが面倒な場合、以下の手順でまとめて削除できます：

```bash
sudo apt purge -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```

これだけでも基本的なアンインストールは完了しますが、**痕跡を残さず削除したい場合は以下も実行**するとよいです：

```bash
sudo apt autoremove -y
sudo rm -rf /var/lib/docker /var/lib/containerd /etc/docker /run/docker* \
            /usr/local/bin/docker* /usr/local/lib/docker
```

### Docker Desktopとの比較

「Docker Desktopが起動しないと `docker` コマンドは使えない」のが前提なので、デーモンや仮想マシンの起動が完了するまで、しばらく待つ必要があります。

`get.docker.com` 経由でDockerをインストールすると、**WSLを起動した時点でDockerが使えるようになっています。**

| 項目              | Docker Desktop              | CLIインストール（WSL）        |
|-------------------|-----------------------------|-------------------------------|
| 起動時間          | 数十秒              | なし（WSL起動と同時）         |
| 必要なサービス     | Hyper-V / WSL2 / GUIなど     | なし                    |
| リソース使用量     | 多め（自前の仮想マシン）         | 少ない（仮想マシンなし）            |
| メリット           | GUIで直感操作、学習用途にも | 軽い・速い・シンプル           |

GUIが必要な場合は、VSCodeの拡張機能を使うほうが使い勝手がよいと感じています。


## まとめ

| 操作      | コマンド例                                               |
| ------- | --------------------------------------------------- |
| インストール  | `sudo wget -O- https://get.docker.com \| sudo sh`     |
| 動作確認    | `docker run hello-world`                            |
| sudo不要化 | `sudo usermod -aG docker $USER` → `再ログイン or WSL再起動` |
| 削除      | `apt purge .....` + `rm -rf .....`（必要に応じて）                        |


ネット上の記事では「GPG鍵の追加」「APTリポジトリの設定」「デーモンの起動設定」などの手順が紹介されているのを見かけることがありますが、  今回紹介した `get.docker.com` スクリプトでは、**これらの作業はすべて内部で自動実行されます**。

GUIによる管理が不要で、純粋に「軽くて早く使える」ことを重視するなら、CLIインストールはとてもおすすめです！