OmniAICreator/Qiita-1.07M huggingface dataset:
統計学２級とPython



```python
# Program Name: pokemon_probability_analysis.py
# Creation Date: 20250530
# Overview: Solve conditional and Bayes probability problems using Pokémon-themed context
# Usage: Run in Google Colab to simulate and verify conditional probability results

# ライブラリのインポート / Import libraries
import numpy as np

# ---------- 問1: 条件付き確率 P(A ∩ B) = P(B) * P(A|B) ----------
# A: 合格 / Pass the test
# B: 対策講座を受けた / Took Pokémon battle prep course

P_A_given_B = 0.7        # P(A|B)
P_A_given_notB = 0.3     # P(A|¬B)
P_B = 0.2
P_notB = 1 - P_B

# P(A ∩ B) = P(B) * P(A|B)
P_A_and_B = P_B * P_A_given_B

# ---------- 問2: ベイズの定理 ----------
# A: 工場A, B: 工場B, C: カモノハシのポケモンがプリントされたクッキー
P_C_given_A = 0.02
P_C_given_B = 0.08
P_A_factory = 0.7
P_B_factory = 0.3

# P(C) = P(C|A)P(A) + P(C|B)P(B)
P_C = P_C_given_A * P_A_factory + P_C_given_B * P_B_factory

# P(A|C) = P(C|A)P(A) / P(C)
P_A_given_C = (P_C_given_A * P_A_factory) / P_C

# ---------- 問3: 条件付き期待値 ----------
# 袋A: 赤2 白3, 袋B: 赤1 白4, サイコロの出目で袋選択
# X: 赤が出る回数（2回引く、戻しあり）

P_dice_A = 2 / 6  # サイコロ1,2 → 袋A
P_dice_B = 4 / 6  # サイコロ3-6 → 袋B

# 袋A: 2/5 赤, 2回独立抽出の赤期待値
E_A = 2 * (2/5)
# 袋B: 1/5 赤, 2回独立抽出の赤期待値
E_B = 2 * (1/5)

# 全体期待値
E_X = P_dice_A * E_A + P_dice_B * E_B

# ---------- 結果表示 / Output ----------
def print_summary():
    print("=== 問1: 条件付き確率 P(A ∩ B) ===")
    print(f"P(A ∩ B) = {P_A_and_B:.4f}")

    print("\n=== 問2: ベイズの定理 P(A | C) ===")
    print(f"P(A | C) = {P_A_given_C:.4f}")

    print("\n=== 問3: 赤玉出現回数の期待値 E[X] ===")
    print(f"期待値 E[X] = {E_X:.4f}")

print_summary()
```
CursorでDockerのコンテナ一覧が消えた？原因と応急処置メモ

## はじめに

Cursorを開いてみると、**Dockerのコンテナ一覧のサイドバーが突然消えている**現象に遭遇しました。
調査したところ、**Docker拡張機能のアップデートが原因**だったので、自分用の備忘録として、原因と対処法をまとめておきます。

## 原因：Docker Extensionのアップデート

2025年5月に、**Docker Extensionがv2.0.0にアップデート**されました。

このアップデートにより、「[**Container Tools**](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-containers)」という新しい拡張機能に機能の一部が切り出されたことで、Dockerの拡張機能ではコンテナ一覧のUIが提供されなくなったようです。（参考：[DockerのChangelog](https://marketplace.visualstudio.com/items/ms-azuretools.vscode-docker/changelog)）

VS Codeではこの「Container Tools」拡張がすでにマーケットプレイスに存在していますが、**Cursorのマーケットプレイスではまだ提供されていません（※）**。

:::note warn

※2025年5月30日時点

![スクリーンショット 2025-05-30 19.54.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/780389/38b4fbd3-5e26-4a3a-9ab5-c41f990df047.png)
:::

## 対処法：Docker Extensionをダウングレード

マーケットプレイスに「Container Tools」が来るまでは、元の状態に戻したいです。
そこで、Docker Extensionを**ダウングレード**することで、コンテナ一覧のサイドバーを復活させました。

### 手順（Cursorでの操作）

1. `Docker` Extension を検索
2. `Uninstall` の横の矢印を展開して `Install Specific Version` を押下し、`2.0.0` 未満のバージョンを選択する
![スクリーンショット 2025-05-30 19.50.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/780389/e53a2109-9bad-4551-9611-3d487adb6bf4.png)
3. インストールが完了したら、拡張機能を再起動する

## 補足

Cursorは基本的にVS Codeと互換性があるものの、マーケットプレイスの提供タイミングなどに若干の差があるようです。  
今回はその差によって一時的に不便な状態になりましたが、いずれ「Container Tools」がCursorでも使えるようになると思われます。

## まとめ

- Docker拡張のアップデートで「Container Tools」への分離が行われた  
- Cursorのマーケットプレイスにはまだ「Container Tools」がない  
- Docker Extensionをダウングレードすることでコンテナ一覧を復活できた

もし同じ現象に悩んでいる方がいれば、参考になれば幸いです。  
当面はCursorのマーケットプレイスで「Container Tools」が利用可能になるのを待ちましょう。
Kali Linuxのaptコマンドがエラーになる件

# はじめに
ある日、私もKali Linuxのaptコマンドが動かなくなりました。

https://qiita.com/ettottooo/items/8e374eec4bc398e49a66

https://qiita.com/GenkaiChan/items/e041c36dc1b01c09d781
# やっちゃいました。テヘ!?
よく調べたら、4月28日に大本営発表されてました...
"This is not only you, this is for everyone, and this is entirely our fault. "

下記のBlogにある通り、新しい公開鍵を手動でインストールするか、新しい公開鍵を含むパッケージで再インストールすれば解決します。

https://www.kali.org/blog/new-kali-archive-signing-key/

Q&Aでは、2018年にもやっちゃいましたとゲロってますね(^_^;)
ひずみエネルギとそれを使った材料力学 基本例題8.34 P289 「材料力学演習(20221021)」をsympyでやってみた。

:::note info
[基本例題8.18](https://qiita.com/mrrclb48z/items/2ed82c3c6f53ccd7ee06)
基本例題8.34 本ページ
:::


# オリジナル
基本例題8.34 P289
~~http://zairikiweb.starfree.jp/zai_enshuh/zai_enshuh_ver.3.3.pdf#page=292~~

「材料力学演習(20221021)一括(ver.3.3)」を勉強したい。＞sympy
https://qiita.com/mrrclb48z/items/c3274daf5f7a99cfe027#%E4%BD%9C%E6%A5%AD%E4%B8%AD%E7%A7%81%E3%81%AE%E8%A7%A3%E7%AD%94sympy

# sympyで
```python
#  例題8.34 P289
from sympy import *
var('a,x3,δB,P,EIz,c')
mAB=-a+x3
print("#",(P/EIz*integrate((c-a+x3)*(-a+x3),(x3,0,a))).simplify())
# P*a**2*(2*a - 3*c)/(6*EIz)
```
ひずみエネルギとそれを使った材料力学 基本例題8.30 P287 「材料力学演習(20221021)」をsympyでやってみた。

・作図はありません。(I形)でイメージして下さい。


# オリジナル
基本例題8.30 P287
~~http://zairikiweb.starfree.jp/zai_enshuh/zai_enshuh_ver.3.3.pdf#page=292~~

「材料力学演習(20221021)一括(ver.3.3)」を勉強したい。＞sympy
https://qiita.com/mrrclb48z/items/c3274daf5f7a99cfe027#%E4%BD%9C%E6%A5%AD%E4%B8%AD%E7%A7%81%E3%81%AE%E8%A7%A3%E7%AD%94sympy

# sympyで
```python
# (I形) 例題8.30 P287 (参考 例題3.3 P37)
from sympy import *
var('ρg,A,E,l,x')
Nx=ρg*A*x;nx=1
print("#",1/(A*E)*integrate(Nx*nx,(x,0,l)))
# l**2*ρg/(2*E)
```
VS Code の Biome 自動保存設定

```json:.vscode/settings.json
{
	"editor.codeActionsOnSave": {
		"source.fixAll.biome": "explicit",
		"source.organizeImports.biome": "explicit"
	},
	"[javascript][typescript][typescriptreact][json][jsonc][css]": {
		"editor.defaultFormatter": "biomejs.biome",
		"editor.formatOnSave": true
	}
}
```

Biome の対象・対応ファイルのみ `defaultFormatter` と `formatOnSave` を設定しています。  
[→ Biome の対応言語](https://biomejs.dev/ja/internals/language-support/) / [対応コード](https://github.com/biomejs/biome-vscode/blob/main/src/constants.ts) ([v3.0.2](https://github.com/biomejs/biome-vscode/blob/v3.0.2/src/constants.ts))

Prettier を設定する際は言語ごとにブロックを分けないと動作しなかった記憶ですが、Biome の場合は纏めて指定できます。  
(Prettier の最新の設定方法は必要に応じてご確認ください)

<details>
<summary>対応言語など意識・指定せず乱暴めに指定する場合</summary>

```json:.vscode/settings.json
{
	"editor.defaultFormatter": "biomejs.biome",
	"editor.formatOnSave": true,
	"editor.codeActionsOnSave": {
		"source.fixAll.biome": "explicit",
		"source.organizeImports.biome": "explicit"
	}
}
```

TS 系の開発では特に悪さしないと思うので、この設定もアリかなと思います。
もし不具合の知見など有ればコメントなどで共有いただけると幸いです。
</details>

**参照ページ**

https://biomejs.dev/ja/reference/vscode/

## ワークスペースを利用している場合

ワークスペースを利用している場合、`folders` 配下のファイルでは `.vscode` 内の設定が効かない事が有りました。
その場合は `settings.json` の内容をワークスペースファイルの settings 貼り付ければ機能します。

```json:[project].code-workspace
{
	"folders": [
		{
			"path": "."
		},
		{
			"path": "src/app"
		},
		{
			"path": "src/components"
		}
	],
	"settings": {
		"editor.codeActionsOnSave": {
			"source.fixAll.biome": "explicit",
			"source.organizeImports.biome": "explicit"
		},
		"[javascript][typescript][typescriptreact][json][jsonc][css]": {
			"editor.defaultFormatter": "biomejs.biome",
			"editor.formatOnSave": true
		}
	}
}

```
`.vscode/settings.json` と `[project].code-workspace` の双方を git 管理するのは2重管理であまりお勧めできないので、ドチラかのみを管理の対象に、ルール化・ドキュメントでカバーするのが良いかと思います。

何度か Biome の設定など繰り返してるので、ナレッジ定着も兼ねて記事化してみました。
Biome の設定も `quickfix.biome` から `source.fixAll.biome` に変わるなど、微妙に更新されてたりするので、暫く設定を触ってない場合は改めて確認してみるのも良いかもしれません。
ひずみエネルギとそれを使った材料力学 基本例題8.28 P286 「材料力学演習(20221021)」をsympyのTrussでやってみた。

・sympyのTrussで作図しました。(2025-06-16)

(旧タイトル)ひずみエネルギとそれを使った材料力学 基本例題8.28 P286 「材料力学演習(20221021)」をsympyでやってみた。
~~・作図はありません。(＞形)でイメージして下さい。~~

# オリジナル
基本例題8.28 P287
~~http://zairikiweb.starfree.jp/zai_enshuh/zai_enshuh_ver.3.3.pdf#page=292~~

「材料力学演習(20221021)一括(ver.3.3)」を勉強したい。＞sympy
https://qiita.com/mrrclb48z/items/c3274daf5f7a99cfe027#%E4%BD%9C%E6%A5%AD%E4%B8%AD%E7%A7%81%E3%81%AE%E8%A7%A3%E7%AD%94sympy

# sympyで
```python
# (＞形) 例題8.28
from sympy import *
var('P,Q,δ,λ,θ,l,AE')
θ  =pi/4
NAC=P*cos(θ)                ;NBC=-P*cos(θ)
U  =1/(2*AE)*NAC**2*l/cos(θ)+1/(2*AE)*NBC**2*l/cos(θ)
print("#",diff(U,P))
rep={P:1}
nAC=NAC.subs(rep);nBC=-NBC.subs(rep)
print("#",1/AE*NAC*nAC*l*cos(θ)+1/AE*NBC*nBC*l*cos(θ))
# sqrt(2)*P*l/AE
# 0
```

# sympyのTrussで
#### ver1.1
```python
# ver1.1
from sympy.physics.continuum_mechanics.truss import Truss
from sympy import *
var('P,dummyQ')
var('l,AE',positive=True)  
def myTruss(l):
    def myAdd_member(*args):
        def make_triples(s):
            return (s,s[0],s[1])
        for s in args:
            t.add_member(make_triples(s))      
    t = Truss()
    t.add_node     (('A',0,l*2),('B',0,0),('C',l,l) ) 
    myAdd_member   ( 'AC','CB')  
    t.apply_support(('A' ,'pinned'),('B','pinned'))
    t.apply_load   (('C',P     ,270))   
    t.apply_load   (('C',dummyQ,0))   
    return t
# -------------------------------------------------------------------------------------
myTruss(1).draw().show()       # 作図のため(l=1)
t=myTruss(l);t.solve()         # 計算のみ
U=sum({k:1/(2*AE)*v1**2*v2  \
       for (k,v1),(_,v2) in zip(t.internal_forces.items(),t.member_lengths.items())} \
       .values())
print('#',diff(U,P).simplify())
print('#',diff(U,dummyQ).subs({dummyQ:0}))
# sqrt(2)*P*l/AE
# 0
```
・縦横比は1:1では、ありません。
![111.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109698/f855634a-8f8f-4edb-bbd0-5732b1886b38.png)
GitHub Copilotで利用可能なモデルのプレミアムリクエスト消費量と性能の一覧

GitHub Copilotで利用可能なモデルとプレミアムリクエストの消費量は[公式のドキュメント](https://docs.github.com/en/copilot/managing-copilot/monitoring-usage-and-entitlements/about-premium-requests)に記載がありますが、選択肢が多いのでどのモデルを使うべきなのかパッと見では判断できません。プレミアムリクエストの消費量の多さ＝性能の高さとは限りませんし…
というわけで公式のドキュメントに追加する形でSWE-bench(Verified)のスコアとコンテキストウィンドウの長さを調査しました。
各社ポジショントークなどもあるとは思いますので、参考程度までに。

| Model                   | 消費   | SWE-bench | コンテキストウィンドウ |
| :---------------------- | :----- | :-------- | :----------------- |
| GPT-4.1                 | 1      | 54.3%    | 1M                 |
| GPT-4o                  | 1      | 30.7%    | 128K               |
| GPT-4.5                 | 50     | 38.0%    | 128K               |
| Claude 3.5 Sonnet       | 1      | 50.8%    | 200K               |
| Claude 3.7 Sonnet       | 1      | 62.3%    | 200K               |
| Claude 3.7 Sonnet Thinking | 1.25   | 記載なし  | 200K               |
| Claude Sonnet 4         | 1      | 72.7%    | 200K               |
| Claude Opus 4           | 10     | 72.5%    | 200K               |
| Gemini 2.0 Flash        | 0.25   | 51.8%    | 1M                 |
| Gemini 2.5 Pro          | 1      | 63.2%    | 1M                 |
| o1                      | 10     | 48.9%    | 200K               |
| o3                      | 5      | 69.1%    | 200K               |
| o3-mini                 | 0.33   | 42.4%    | 200K               |
| o4-mini                 | 0.33   | 68.1%    | 200K               |

個人的にはClaude 4系がやはり性能が良い印象があります。
プレミアムリクエストの消費量とのバランスで、雑多なタスクはo4-mini、少し込み入ったタスクはSonnet 4、ロングコンテキストが必要なタスクはGemini 2.5 Pro、といった感じで併用していこうかなと考えています。
🛴ループ処理まとめ🔁❸ ー .timesメソッド

Ruby の反復処理でよく使う「整数限定」の繰り返し方法、`.times` メソッドについて、アウトプットします。  
返り値や `each` との違いも整理して、サンプルコードとともに見ていきたいと思います。


---

## `.times` メソッドとは

- **Integer** クラスに定義されているメソッドで、整数（レシーバーの値）回だけ繰り返し処理を実行する  
- 戻り値はレシーバー（メソッドを呼んだ整数そのもの）  

---

## 基本的な書き方

### 複数行ブロック

```ruby
n.times do |i|
  # i を使った処理
end
```
## 単一行ブロック
```ruby
n.times { |i| 処理 }
```
- ブロック引数 `i` には `0` から `n-1` までの整数が順に渡る

- メソッドの戻り値はレシーバーの整数 `n`
```ruby
3.times do |i|
  puts i
end

# 出力
# 0
# 1
# 2

# 戻り値
=> 3
```

---
## `.each` メソッドとの違い
| 項目           | `.each`                    | `.times`        |
| ------------ | -------------------------- | --------------- |
| 対象           | Enumerable（Array、Range など） | Integer         |
| 繰り返す回数       | Collection の要素数分           | レシーバーの値分        |
| ブロック引数に渡される値 | 各要素                        | 0 〜 n-1 の整数     |
| 返り値          | 元の Enumerable オブジェクト       | レシーバーの整数        |
| ブロック省略時の返り値  | Enumerator                 | Enumerator      |
| 主な用途         | 配列や範囲の各要素を順に処理する           | 同じ処理を指定回数だけ繰り返す |

```ruby
# .times を使った例
4.times do |i|
  puts i
end
# => 0, 1, 2, 3
#    戻り値: 4

# (0..3).each を使った例
(0..3).each do |j|
  puts j
end
# => 0, 1, 2, 3
#    戻り値: (0..3)
```
- `.each` は Array や Range など「要素を持つオブジェクト」の反復に

- `.times` は「整数を上限にした同一処理の繰り返し」に

- とはいえ、`(0..n-1).each` で整数回の繰り返しも可能です

---

## まとめてみて
- `n.times do |i|` で回すよりも、`(1..n).each do |i|` の方が自分としては見やすいから多用したい。
- `n.times` ： ０からｎ-1まで繰り返す
- `(1..n).each` ： １からｎまで繰り返す　👈包括的範囲
- `(1...n）.each` ： １からｎ-1まで繰り返す　👈排他的範囲
生成AIを試したい 3

よし、次はテストクラスだ。
こればっかりは、本気でどうにかしたかった。
Salesforceの開発は、テストクラスの作成に異様に時間を食う。
いや、テストは大事、当たり前だ。
しかし、品質を落とさずに時間を削れるなら、削るに越したことはない。

作り方は至って簡単、らしい。
コード画面を右クリックするか、右上のフラスコめいたボタンか、
あるいは左の・・・どうにも形容しがたいボタンでも押すか。
![テストクラス0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390179/d0253562-e539-4335-baf2-772971a0b869.png)

Apex Fileには、テストしたいクラスのファイルを選ぶ。当然だろう。

Apex Methodはテストしたいメソッド、とある。全部テストしてほしいので、メインとなるメソッドを選択した。

Test Fileは「Create a new file」を選ぶと、テスト対象のクラス名の後ろに「Test」を付けたファイルをこしらえてくれるという。

あとは「Generate」を押すだけ。

![テストクラス2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390179/ea54429e-69d6-4199-8317-e16248fa3e70.png)

すると、差分を見せる形で生成したコードを閲覧できる。問題なければ「Accept」を押す、とあるが……どうにも腑に落ちない。取り込みテスト用のデータとやらも、ヘッダ名やヘッダ数がまるで違うではないか。

![テストクラス4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390179/a57f0b19-8573-464b-998e-f4ff680a27c7.png)

テストクラス生成時に情報を追加することもできないのだから、これは困った。どうしたものか……。

調べてみれば、どうやら完璧なテストクラスを一発で作ってくれるわけではない、というのが世間の常識らしい。むしろ、テストしたいクラスをDev Assistantに丸ごと渡して「テストクラスを作れ」と依頼した方が、よほど賢明だという。

言われた通りにやってみた。

![テストクラス8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390179/04b7eda5-d501-45e5-8883-d90ed97c5775.png)

作ってくれた。今度のは、ぱっと見は問題なさそうだ。これをデプロイして、実行してみよう。

はい、エラーが出た。

![テストクラス7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390179/2804f9b9-777a-4b14-bd07-d18250681757.png)

仕方がない、こっからは手動でなおそう。

その後、ソースを修正し、テストを通すことができた。カバレッジ率も問題なし。
ただし、テスト対象のクラス自体にも問題があったりして、100%のものをポンと作ってくれるわけではないようだ。もっとも、AIは日々進化しているのだから、来月には修正されている、などということもあり得るのだろうが。

とはいえ、7〜8割は瞬時に作ってくれるのだから、使う価値は十分にある。
仮に5割しか作ってくれなかったとしても、コードを書く時間が半分になるのだ。
是非活用していきたい。
生成AIを試したい 2

生成AIはたしかにプログラムを生成してくれたが、どうにも一発で完璧な命令をプロンプトに書き下すのは難しいらしい。普段、友人や家族とすらまともにコミュニケーションをとれない私であれば、なおさらだ。それに、既存のファイルを修正することも、新規で作るよりも多いのが現実というもの。

というわけで、生成されたファイルに手を加えてみることにした。

### お題
CSVアップロード時に列の型チェックを追加する

#### 目的
CSVアップロード時にヘッダと各項目の型のチェックを追加する
#### 条件
ヘッダが「年月日」「仕入先コード」「商品コード」「単価」「数量」であるか確認する
各列の型が以下の通りであるか確認する
- 年月日：YYYY/MM/DD
- 仕入先コード：半角英数字10文字
- 商品コード：半角英数字15桁
- 単価：半角数字10桁以内
- 数量：半角数字5桁以内
- 確認で問題があれば、CSVの何行目に何の問題があるかをVisualforce画面のダイアログへ表示する
- 問題があった場合、オブジェクトへの登録処理は行わない
#### 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390179/ac9d632e-3b8b-477d-8750-eb2d594ceb63.png)

期待通り、画面と画面から呼び出すApexクラスを更新してくれた。
画面の方は全文だが、Apexクラスは変わらない部分は省略されている。

メソッド単位で区切っていれば良いのだが、これだとコピーが難しい。というわけで、以下のプロンプトを送って全文を生成してもらった。

#### 追加プロンプト
PurchaseUploadController.clsは全プログラムを生成して

お願いした通り、全部作ってくれた。これをそのままクラスへ移せばOKだ。
生成AIを試したい 1

今さらながら私も生成AIとやらを使い始めたいと思い立った。

要件定義だの設計だの、開発のあらゆる工程で使えるらしいが、まずは一番やってみたかったプログラムの生成を試してみることにする。

### 準備
生成AIと一口に言っても、実に様々な種類があるようで、どれを選べばいいのか逆に迷ってしまう。だが幸いなことに、私が業務で使っているSalesforceが生成AIを提供してくれているという。これを使わない手はない。しかも開発環境まで無料で提供してくれるというのだから、ありがたい話だ。

使い方を調べてみると、どうやらVisual Studio Codeから使えるらしい。
ていうか、もうそこにいた。
この「Dev Assistant」とやらを使えば、生成AIに依頼ができるらしい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390179/1ac5712d-ce14-4f66-9fde-55f2a699484a.png)


とりあえずPlaygroundを作って、早速試してみようではないか。

### お題
生成AIに指示を出すための内容は「プロンプト」と呼ぶらしい。
そして、これができるだけ分かりやすく書くことが肝要だという。

指示を出すにもお題が必要なので、以下の内容にしてみることにした。

#### 概要
Visualforceで仕入れ情報のCSVをアップロードする画面を作り、アップロードした内容をオブジェクトへ保存する。

#### 条件
- CSVは10,000行以上
- CSVの列は、「年月日」「仕入先コード」「商品コード」「単価」「数量」
- ガバナ制限は回避すること
- 例外処理を入れる
- 例外の内容を担当者へメール送信する
- 担当者のメールアドレスは、カスタム表示ラベル「ErrorToMail」を使用する
とりあえず、これで実行してみよう。

#### 結果
![生成結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390179/5d4035a8-fd6a-4091-b4ea-6ea3626bbd2b.png)

内容が少ないからか、1分もかからずに結果が返ってきた。画面用のVisualforce、そしてVisualforceから呼び出すためのApexクラス。プロンプトに「CSVが10,000行以上」「ガバナ制限を回避」と条件をつけたおかげか、取り込み処理はバッチにしてくれている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390179/b3d81ec7-abe1-4650-a623-76f45bafe228.png)

ファイル名も指定してくれているので、その名前でファイルを作り、右上のボタンを押せば内容をすべてファイルへ移してくれるという親切設計。

これからプログラムを確認するが、見た感じエラーはないし、少なくとも土台にはなりそうだ。これが1分ほどでできるというのであれば、かなりの実装時間を抑えられそうだ。

さて、これはもう、活用して楽ができるということで良いだろうか
Android端末でIKEv2/IPSec接続方式でVPN接続をできるようにする（RTX1300設定）

# 最初に

Android端末ではAndroidのバージョン12以降から、VPNの `L2TP/IPsec` 接続方式ができなくなった為、**ヤマハルーターRTX1300** で `IKEv2/IPSec` 接続できるように対応を行いました。
備忘録として残しておきます。

# IKEv2/IPSecとは
`IKEv2/IPSec`は、VPNを構築するためのセキュリティプロトコルの組み合わせです。
`IKEv2`は、VPN接続時の**鍵交換と認証**を担当し、`IPSec`は**データの暗号化と保護**を担当します。
この組み合わせにより、VPN接続の安全性と安定性が向上します。

#### IKEv2/IPSecの特徴
1. 高速で安定した接続
・IKEv2は、ネットワークの切断後も自動的に再接続する機能を持っており、モバイル環境に適しています。
2. 強固なセキュリティ
・IPSecを利用することで、データの暗号化と認証を行い、安全な通信を確保します。
3. 幅広いデバイス対応
・Windows、macOS、iOS、Androidなど、多くのOSでサポートされています。



# ルーター設定
`IKEv2/IPSec` の設定は**GUI**からは行えない為、 **「コマンドの実行」** から設定をしていきます。

#### 【トンネルの設定例】
gateway_id（セキュリティゲートウェイの識別子）： 99
pool_id（アドレスプール ID）： 1
```
tunnel select 99
description tunnel トンネル名
tunnel encapsulation ipsec
ipsec tunnel 99
ipsec sa policy 99 99 esp
ipsec ike version 99 2
ipsec ike keepalive log 99 off
ipsec ike keepalive use 99 on rfc4306 10 3
ipsec ike local name 99 (ルータのグローバルIPアドレス) ipv4-addr
ipsec ike pre-shared-key 99 text (IPsec事前共有鍵)
ipsec ike remote name 99 (ユーザー名) fqdn
ipsec ike mode-cfg address 99 1
ipsec auto refresh 99 off
tunnel enable 99


ipsec ike mode-cfg address pool 1 192.168.100.101-192.168.100.200
```

* IPsec事前共有鍵　⇒　任意の文字列
* ユーザー名　⇒　任意の文字列
* IKEv2クライアントへ配布するアドレス　⇒　192.168.100.101-192.168.100.200
* IKEv2キープアライブの方式　⇒　RFC4306(IKEv2 標準) 、ICMP Echo の2種類から選ぶことができる。第1書式は自動的にRFC4306方式となる
* キープアライブパケットの送信間隔秒数　⇒　10
* キープアライブパケットが届かないときに障害とみなすまでの試行回数　⇒　3


#### 公式サイト記載の重要事項

:::note warn
【重要】
・IKEv2リモートアクセスVPN接続では、ipsec auto refresh GATEWAY_ID off を設定してください。
・ipsec auto refresh on を設定した状態で、ipsec auto refresh GATEWAY_ID off を設定しても、
設定したトンネルのみ refresh sa されなくなるため問題なく使用可能です。
・端末のモバイル回線やWi-Fiが不慮に切断されたとき、
  ルーター側でセッションが残ってしまい次の接続をすぐ受けることができなくなります。
  対策としてルーター側で早期に切断を検知できるよう、
  TUNNELに対してキープアライブを有効にすることを薦めます。
:::

# クライアント側設定


|名前    |任意の名前           |
|----------|--------------------------|
|**タイプ**  |**IKEv2/IPsec PSK**         |
|**サーバーアドレス**  |**接続先のホスト名もしくはIPアドレス（ルータのグローバルIPアドレス）**         |
|**IPSec ID**  |**ルーターに設定した「ユーザー名」（任意の文字列）**         |
|**IPsecの事前共有鍵**  |**ルーターに設定した「IPsec事前共有鍵」（任意の文字列）**         |

# まとめ
`IKEv2/IPSec`接続方式は、`pptp`接続や`L2TP/IPsec`接続と比べて、セキュリティ面でより安全性が高い事や、利用してみた体感として速度も速くなっている印象を受けました。
これを機に積極的に`IKEv2/IPSec`接続方式を利用していくのが良いかと思います。

最後まで読んで頂きありがとうございました。

# 参考
https://www.rtpro.yamaha.co.jp/RT/docs/ipsec/ikev2_ras/index.html
TanStack Queryでハマった落とし穴

### 1. **queryKeyの設計が雑でキャッシュがバグる**
**問題**：`queryKey` にオブジェクトや関数をそのまま使うとキャッシュが効かなくなる
**例**：

  ```tsx
  useQuery({
    queryKey: ['user', { id }],
    queryFn: () => fetchUser(id),
  });
  ```
**原因**：
#### ①`queryKey` は**配列の中の値を「参照」で比較**してキャッシュを判断する

* JavaScriptではオブジェクトや配列は「値」ではなく「参照」で比較される。
* `['user', { id: 1 }]` の `{ id: 1 }` は毎回新しく生成されるため、
  → 同じように見えても毎回別物として扱われる。

#### ② そのため、**queryKeyが毎回「違うもの」として扱われ、キャッシュが使われない**

* TanStack Query は `queryKey` を元にキャッシュを探す。
* `['user', { id: 1 }] !== ['user', { id: 1 }]` → 毎回新しいクエリとして実行されてしまう。
* 本来ならキャッシュを使えるのに、**意図せず毎回APIを叩く羽目になる。**
  
**解決策**：オブジェクトを避けて、**プリミティブな値だけで構成する**

```tsx
queryKey: ['user', 1]; 
```
---


### 2. **mutation後にuseQueryが自動更新されないと思って焦る**

* **問題**：`useMutation` 後に `useQuery` の内容が古いまま
* **原因**：mutationを実行しても、それに関連するquerykeyは自動で更新されない。
* **解決策**：手動で `invalidateQueries` を呼ぶ

  ```tsx
  const queryClient = useQueryClient();

  useMutation({
    mutationFn: updateUser,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['user', userId] });
    },
  });
  ```
これで、['users'] クエリが再取得され、最新の一覧が表示されるようになります。
つまり、**「TanStack Queryは賢いけど、そこまでは自動でやってくれない」** という落とし穴の話です。

---

### 3. **loadingとfetchingの違いを知らずにバグる**

* **問題**：「初回の読み込み」だけでローディングUIを表示したいのに、再取得時にも同じローディングUIが表示されてしまい、画面が不自然にリセットされてしまう。
* **原因**： `useQuery` の状態フラグ `isFetching` は「再取得中」でも `true` になる。

* **初回のデータ取得中かどうか**を判断するには、`isLoading` を使う。

具体例：

```tsx
const { data, isLoading, isFetching } = useQuery({ ... });

if (isLoading) {
  return <Skeleton />;
}

return (
  <div>
    {isFetching && <SmallSpinner />}
    <UserList data={data} />
  </div>
);
```
---
### 4. **refetchのタイミングが思ったより多くてパフォーマンスが悪化**

* **問題**：意図していない場面でクエリが自動的に再取得されてしまい、APIの呼び出しが増えたり、画面のパフォーマンスが低下してしまう。
* **原因**：予期せぬタイミングで「データが古い」と判断されて、再取得が走っている
* **解決策①**：`staleTime` を設定する
    デフォルトでは `staleTime = 0` なので、データは**取得した瞬間に stale（古い）扱い**になります。


```tsx
useQuery({
  queryKey: ['users'],
  queryFn: fetchUsers,
  staleTime: 1000 * 60 * 5, // 5分間は再取得しない
});
```
* **解決策②**：`refetchOnWindowFocus` を `false` にする
React Query はユーザーがタブを切り替えて戻ってきた時に、最新の情報を自動で再取得する。
`refetchOnWindowFocus`でデフォルトの再取得を`false`にして、必要なタイミングで`true`にして再取得をする。
```tsx
useQuery({
  queryKey: ['user'],
  queryFn: fetchUser,
  refetchOnWindowFocus: false,
});
```
* **解決策③**：クエリキーを安定させる（外から渡された props / state が不安定）
useQuery の中で queryKey をしっかり制御しているつもりでも、
外から渡された props や state の参照が毎回変わっていたら、意図せず再取得が発生する。

**❌ 具体例：親コンポーネントから渡されたオブジェクト**
```tsx
// 親コンポーネント
<MyComponent filters={{ status: 'done', sort: 'desc' }} />
```

```tsx
// 子コンポーネント
const { data } = useQuery({
  queryKey: ['items', filters], // ← filters は props で渡されたオブジェクト
  queryFn: fetchItems,
});
```

**✅ 具体例：`useMemo` を使って props を安定化させる**

```tsx
const memoizedFilters = useMemo(() => ({ status: 'done', sort: 'desc' }), []);
<MyComponent filters={memoizedFilters} />
```
**「useQuery 内の制御だけでは不十分」**
なぜなら queryKey に使っている値が「外から来ている」なら、その安定性は親側に依存するから。
【脱Docker】Podmanを使ってみた！コンテナ時代の新たな選択肢を実例で解説

# 【脱Docker】Podmanを使ってみた！コンテナ時代の新たな選択肢を実例で解説

![images.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125746/e8d93e08-7d76-4510-8ca8-5d3f30c349a6.png)

コンテナ技術といえば真っ先に思い浮かぶのが**Docker**ですが、最近話題の**Podman**というツールをご存知でしょうか？

今回は、Dockerと同じように使えるけど実はそれ以上に「良いところがある」Podmanについて、実際の使用例を交えて紹介します！

---

## ✅ Podmanとは？

PodmanはRed Hat主導で開発されている**OCI（Open Container Initiative）準拠**のコンテナエンジンです。最大の特徴は以下の点です：

* **デーモンレス（Daemonless）**：root権限不要で動作可能
* **Docker互換CLI**：`alias docker=podman` でそのまま使える
* **セキュリティ重視**：Rootlessコンテナが標準対応
* **シンプルなアーキテクチャ**：systemdとの親和性が高い

---

## 🆚 DockerとPodmanの比較

| 特徴            | Docker            | Podman                          |
| ------------- | ----------------- | ------------------------------- |
| デーモン          | 常駐デーモンが必要         | デーモンレス（CLIが直接操作）                |
| Rootless対応    | 一部対応              | フル対応（完全な非root運用）                |
| CLI互換性        | -                 | ほぼ完全互換（Docker CLIそのまま）          |
| systemd統合     | 手動対応              | 標準対応（`podman generate systemd`） |
| Windows/Mac対応 | Docker Desktopが必要 | WSL経由で可能                        |

---

## 🔧 実例：PodmanでNginxを立ち上げる

以下、Dockerと同様のコマンドでNginxコンテナを立ち上げてみます。

### ① Podmanインストール（Ubuntuの場合）

```bash
sudo apt update
sudo apt install podman
```

### ② Nginxを実行してみる

```bash
podman run -d -p 8080:80 nginx
```

ブラウザで `http://localhost:8080` にアクセスすると、NginxのWelcomeページが表示されます。

### ③ Rootless動作確認

```bash
whoami   # 通常ユーザー
podman ps
```

rootユーザーではなくても、Podmanは普通に動作しています。これはDockerではできなかった点です。

---

## ⚙️ systemdサービス化の例（コンテナ自動起動）

Podmanの面白い機能の一つが「systemdユニットの自動生成」です。

```bash
podman generate systemd --name nginx -f
```

このコマンドで作成された `.service` ファイルを systemd に登録するだけで、コンテナが自動起動するようになります。

---

## 💬 使ってみた感想

**良かった点：**

* Dockerとほぼ同じコマンド体系で学習コストが低い
* セキュリティ的に安心（非rootで運用できる）
* デーモン不要なので軽量＆トラブルが少ない
* systemdとの親和性が非常に高い

**惜しい点：**

* GUIツールやエコシステムがDockerに比べるとまだ少なめ
* WindowsやMacでの体験はWSLや仮想環境に依存する（Docker Desktopほど簡単ではない）

---

## 📌 まとめ

Podmanは「Dockerの完全な代替」ではなく、「よりセキュアで柔軟な代替手段」です。

開発・テスト・本番環境において、**デーモンレス、非root運用、systemd統合**という魅力を活かして、より軽快でセキュアなコンテナ運用が実現できます。

特に次のような方におすすめです：

* セキュリティ重視の環境構築をしたい人
* Dockerを使いたいがroot権限がない環境
* systemdでサービスとしてコンテナを管理したい人
統計検定2級のための線形回帰



```python
# Program Name: simple_linear_regression.py
# Creation Date: 20250530
# Overview: Perform simple linear regression and compute 95% confidence interval and hypothesis test for the slope
# Usage: Run in Google Colab to evaluate simple regression coefficients and intervals

# ライブラリのインストール / Install required libraries
!pip install numpy pandas matplotlib scipy statsmodels

# ライブラリのインポート / Import libraries
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import stats
import statsmodels.api as sm
from statsmodels.stats.outliers_influence import variance_inflation_factor
from scipy.stats import shapiro

# データ定義 / Define data
x = np.array([12, 12, 11, 7, 8, 9, 14, 11])
y = np.array([22, 24, 21, 19, 19, 22, 24, 23])
n = len(x)

# 平均・分散などの統計量 / Compute basic statistics
x_bar = np.mean(x)
y_bar = np.mean(y)
Txx = np.sum((x - x_bar) ** 2)
Txy = np.sum((x - x_bar) * (y - y_bar))

# 回帰係数の計算 / Estimate regression coefficients
b2 = Txy / Txx
b1 = y_bar - b2 * x_bar

# 予測値・残差の計算 / Compute fitted values and residuals
y_hat = b1 + b2 * x
e = y - y_hat

# 残差平方和と誤差分散 / Residual sum of squares and variance estimate
SSE = np.sum(e ** 2)
sigma_hat2 = SSE / (n - 2)
sigma_hat = np.sqrt(sigma_hat2)

# 信頼区間の計算 / Compute 95% confidence interval for b2
t_crit = stats.t.ppf(1 - 0.025, df=n - 2)
se_b2 = sigma_hat / np.sqrt(Txx)
CI_lower = b2 - t_crit * se_b2
CI_upper = b2 + t_crit * se_b2

# 仮説検定統計量 / Hypothesis test for b2 = 0
T = b2 / se_b2
p_value = 2 * (1 - stats.t.cdf(np.abs(T), df=n - 2))

# Shapiro-Wilk検定 / Shapiro-Wilk test for normality of residuals
shapiro_stat, shapiro_p = shapiro(e)

# statsmodelsによる回帰分析 / Regression analysis using statsmodels
X = sm.add_constant(x)
model = sm.OLS(y, X).fit()

# VIFの計算 / Calculate VIF
vif_data = pd.DataFrame()
vif_data['feature'] = ['const', 'x']
vif_data['VIF'] = [variance_inflation_factor(X, i) for i in range(X.shape[1])]

# 結果の出力 / Print results
print(f"Regression Line: y = {b1:.3f} + {b2:.3f}x")
print(f"95% CI for slope: [{CI_lower:.3f}, {CI_upper:.3f}]")
print(f"T-statistic: {T:.3f}, p-value: {p_value:.4f}")
print(f"Shapiro-Wilk Test: W = {shapiro_stat:.4f}, p = {shapiro_p:.4f}")
print(model.summary())
print("\nVIF Table:")
print(vif_data)

# 散布図と回帰直線のプロット / Plot scatter and regression line
plt.scatter(x, y, color='blue', label='Observed data')
plt.plot(x, y_hat, color='red', label='Regression line')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Simple Linear Regression')
plt.legend()
plt.grid(True)
plt.show()

# 残差プロット / Residual plot
plt.scatter(x, e, color='green')
plt.axhline(0, color='black', linestyle='--')
plt.xlabel('x')
plt.ylabel('Residuals')
plt.title('Residual Plot')
plt.grid(True)
plt.show()

```



* 単回帰＋重回帰のモデル構築
* 回帰係数、t値、p値、信頼区間の表示
* 残差のプロットとQ-Qプロット
* Shapiro-Wilkによる残差の正規性検定
* VIFによる多重共線性診断
* 散布図＋回帰直線可視化（X1とY）
Reactを使った入力時にラベルをフロートで移動させる方法

この記事はプログラミング学習者がアプリ開発中に躓いた内容を備忘録として記事におこしたものです。内容に不備などあればご指摘頂けると助かります。

今回はRails(API) x ReactでX(旧Twitter)のクローンサイトを作る際に本家のデザインの一部を模倣したので、備忘録を兼ねて記事に起こしたいと思います。

## 1. 記事の趣旨について
本家(X - 旧Twitter)を模倣する際、inputタグにフォーカスすることで起こるラベルのフロートを実装しました。
通常、inputタグに備わっているplaceholderで名前をつけておくとフォーカスされていない時はinputタグの対象が別できますが、フォーカスしてしまうとplaceholderは消えてしまうので、何のinputタグかを判別することができません。
ラベルをフロート(移動)させることで、入力内容とラベルが重なることを避けつつ、入力しているinputタグは何のラベルが付いているかを確認することができるようになりました。
ここではinputタグのplaceholderは使わずに他の要素で代用することで機能を実現しています。

下のGif画像はフロート化したラベルがついたinputタグにフォーカスした時の動画です。

![インプットタグ ラベルフロート移動.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3508918/f7b3ff23-10a5-4fff-9290-56f5da145b75.gif)


## 2. 実装したコード
```JavaScript:FloatingInput.jsx
import React, { useState, useEffect } from "react";
import styled, { css } from "styled-components";

const InputBox = styled.div`
  position: relative; // InputとPlaceholderに対する親要素として指定
  font-size: 14px;
  padding-top: 20px;
  width: 75%;
`;

const Input = styled.input`
  width: 100%;
  height: 60px;
  margin-bottom: 10px;
  border-radius: 5px;
  background-color: black;
  color: white;
  border: solid 1px #3b3b3b;
  outline: none;
  padding-left: 12px;
  padding-top: 15px;
  padding-bottom: 0;
  font-size: 16px;
  &:focus {
    border: solid 2px #1d9bf0;
  }
`;

const PlaceHolder = styled.span`
  position: absolute; // 親要素のInputBoxに対して子要素として指定
  left: 10px;
  top: 70%;
  transform: translateY(-50%); // 上方向に移動させる
  color: #aaa;
  pointer-events: none; // カーソルフォーカス時にポインターに変わらないように
  background: black;
  font-size: 20px;
  transition: top 0.3s, font-size 0.3s, color 0.3s; // 要素の変わる速度
  ${({ $isActive }) =>
    $isActive &&
    css`
      top: 40px;
      font-size: 12px;
      color: #1d9bf0;
    `}
`;

export const FloatingInput = ({ label, value, onChange, type, name }) => {
  const [isFocused, setIsFocused] = useState(false);

  return (
    <InputBox>
      <Input
        type={type}
        value={value}
        name={name}
        onChange={onChange}
        onFocus={() => setIsFocused(true)}
        onBlur={() => setIsFocused(false)}
      />
      <PlaceHolder $isActive={isFocused || value}>{label}</PlaceHolder>
    </InputBox>
  );
};

```

機能実装する際に肝となるのは親要素のInputBoxコンポーネントと子要素であるPlaceholderコンポーネントです。
InputBoxに`position: relative`を置いて、親要素としての機能を追加します。
子要素のPlaceholderに`position: absolute`を置いて親要素の位置から子要素をどれくらい動かすかという移動機能を追加できます。
通常時は下記の位置設定になっており、親要素InpuBoxから移動した位置を記述しています。
```CSS
left: 10px;
top: 70%;
transform: translateY(-50%);
```
そして、変数`&isActive`がtrueになった場合、下記の状態に変更します。
`top: 40px;`の部分で移動させるように実装しています。
```CSS
top: 40px;
font-size: 12px;
color: #1d9bf0;
```

## 3. 参考にしたサイト
[コピペで簡単！ CSSのみで、フォームの入力時にフロートする入力欄のラベルを実装するテクニック](https://coliss.com/articles/build-websites/operation/css/css-only-floating-input-labels.html)
[placeholderを消さずにCSSで見出しに活用する方法](https://lpeg.info/html/css_placeholder.html#m3)
Adobe IllustratorのAIGeneratorで画像の色を変更してみました

皆さん、こんにちは。

最近、Adobeの動画作業を勉強している途中で、Adobe IllustratorのAI Generator機能を知って、この機能で写真を編集してみました。

今回は経験談として、Adobe Illustrator AI Generatorを使って、写真の色を変更するステップをシェアします。

## Adobe IllustratorのAI Generatorとは
Adobe IllustratorのAI Generatorは2023年10月10日に発表された機能です。初代のベータ版の機能は主にテキストからベクター画像生成であり、その後の二回のアップデートで塗りつぶしとパターン生成が追加されました。

この文章は、初代ベータ版の「Generative Recolor」機能で画像の色を変更する手順について紹介します。

## Adobe IllustratorのAI Generatorで画像の色を変更する方法

### Step1.ベクター画像を作成
ここで、Illustratorのライブトレース機能を使えば、JPEGやPNGなどの画像をベクター化できます。画像をベクター画像にする理由は、ベクター画像はサイズ、形状と色を編集しても、画質が落とさないという特徴があるからです。

:::note warn
編集作業を始まる前に確認しておきたいこと：
**1\.** 画像の形式は**TIFF**であれば、画像を「Image Trace」で画像の形式に変換してから、色の編集作業を始めてください。
**2\.** ベクター画像のカラー形式は**RGB**または**CMYK**であること。もし「Grayscale」になっている場合、変更してください。
:::

![Adobe Illustrator step1](https://images.hitpaw.com/topics/photo-ai/adobe-illustrator-ai-generator.jpg "Adobe Illustrator step1")

### Step2.Generative Recolorを起動
ベクター画像をIllustratorにアップロードすれば、色を変更したい画像を選びます。
色を変更したい画像を確認できましたら、「Edit」→「Edit Colors」→「Generative Recoloer」を起動します。
![Adobe Illustrator step2](https://images.hitpaw.com/topics/photo-ai/adobe-illustrator-generative-ai.jpg "Adobe Illustrator step2")

### Step3.Generative Recolorで色を変更
1.Generative Recolorの画面で、「Prompt」にテキストを入力し、テーマまたはスタイルを選んで、「Generate」をクリックします。これで、生成した結果を確認できます。
2.テキストで画像を生成する以外に、下にある「Variations」のところから、表示される9つのサンプルを選択します。各プロンプトには視覚化用のサンプル画像が付いているので、お好みに応じて選んでください。
![Adobe Illustrator step3](https://images.hitpaw.com/topics/photo-ai/adobe-ai-illustration-generator.jpg "Adobe Illustrator step3")

### Step4.色を変更した画像を確認
結果を生成できたら、 4つのバリエーションからいずれかを選んで、ベクター画像に適用できます。
一方、もし結果に満足しない場合、「もう一度生成」で結果を再びレビュできるので、満足できるまでお試しください。
![Adobe Illustrator step4](https://images.hitpaw.com/topics/photo-ai/generative-ai-in-adobe-illustrator.jpg "Adobe Illustrator step4")

## まとめ
以上は今回の内容となります。
Adobe IllustratorのAI Generatorは色を変更する以外に、「下絵作成やアイデア出し」と「絵のスタイル選択」などの機能もあります。
このツールの使用感想として、とてもデザイナーにとって非常に強力なパートナーとなるAIツールですが、日本語プロンプトの精度は英語に比べて若干劣る場合があるというデメリットもあります。
Excelグラフを画像として保存する方法（C# および VBA）

Excelでのレポート自動生成や、グラフを他のドキュメントで再利用する場面では、グラフを画像として保存するニーズがよくあります。たとえば、PowerPointレポートへの埋め込み、メールでの共有、Webでの可視化表示などに活用されます。**C# を使って複数のグラフを一括で画像として出力することも、VBA を使って Excel 内からワンクリックで画像化することも可能です。**

本記事では、**C# および VBA を使って Excel 内のグラフを画像として保存する方法**について、コード例と操作手順を交えて詳しく解説します。

---

## C# を使って Excel グラフを画像として保存する

.NET 環境では、[Free Spire.XLS for .NET](https://jp.e-iceblue.com/introduce/free-spire-xls-for-net.html) を使用することで、Excel ファイル内のグラフを `.jpg` 形式の画像として簡単に出力できます。

### Spire.XLS のインストール

NuGet パッケージマネージャーで以下のコマンドを実行します：

```bash
Install-Package FreeSpire.XLS
````

### C# のサンプルコード

```csharp
using Spire.Xls;
using System.Drawing;

Workbook workbook = new Workbook();
workbook.LoadFromFile("Sample.xlsx");

// すべてのワークシートとグラフを走査し、画像として保存
foreach (Worksheet sheet in workbook.Worksheets)
{
    foreach (Chart chart in sheet.Charts)
    {
        Bitmap chartImage = chart.SaveToImage();
        chartImage.Save($"output/{sheet.Name} - {chart.ChartTitle}.jpg");
    }
}
workbook.Dispose();
```

### 操作の流れ

1. 既存の Excel ファイルを読み込む
2. すべてのワークシートをループ処理
3. 各ワークシート内の `Chart` オブジェクトを取得
4. `SaveToImage()` メソッドで画像化
5. `.jpg` ファイルとして保存

**利用シーン例**：C# でのバッチ処理や、レポート生成システムへの組み込みなど

---

## VBA を使って Excel グラフを画像として保存する

**Excel の UI から直接グラフを画像として保存したい場合**は、VBA マクロを使うと簡単に実現できます。外部ライブラリやアドインの導入は不要です。

### VBA のコード例

```vba
Sub SaveAllChartsAsImages()
    Dim ws As Worksheet
    Dim chartObj As ChartObject
    Dim folderPath As String
    Dim chartIndex As Integer
    Dim fileName As String

    ' 保存先フォルダの設定
    folderPath = ThisWorkbook.Path & "\Charts"
    If Dir(folderPath, vbDirectory) = "" Then MkDir folderPath

    chartIndex = 1 ' ファイル名用の番号付け

    ' すべてのワークシートを走査
    For Each ws In ThisWorkbook.Worksheets
        ' 各ワークシート内のグラフオブジェクトを取得
        For Each chartObj In ws.ChartObjects
            fileName = folderPath & "\" & ws.Name & "_Chart" & chartIndex & ".jpg"
            chartObj.Chart.Export Filename:=fileName, FilterName:="JPG"
            chartIndex = chartIndex + 1
        Next chartObj
    Next ws

    MsgBox "すべてのグラフを画像として保存しました。", vbInformation
End Sub
```

### 実行手順

1. **Excel ファイルを開く**
2. **`Alt + F11` キーで VBA エディタを起動**
3. **\[挿入] > \[標準モジュール] を選択し、新規モジュールを追加**
4. **上記コードを貼り付ける**
5. **`F5` キーでマクロを実行**
6. 現在の Excel ファイルと同じディレクトリに `Charts` フォルダが作成され、すべてのグラフが `.jpg` 形式で保存されます

**利用シーン例**：開発不要で Excel 内から手軽にグラフ画像を取得したい一般ユーザー向け

---

## 出力例

以下は C# を使って出力したグラフ画像の一例です：

![Excelのグラフを画像として保存する効果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/5c49fc09-2144-423a-9578-abd744657c07.png)


---

## まとめ

| 方法                 | メリット                      | 想定ユーザー        |
| ------------------ | ------------------------- | ------------- |
| **C# + Spire.XLS** | バッチ処理対応、システム組み込み可能、自動化に最適 | 開発者、業務システム運用者 |
| **Excel VBA マクロ**  | 追加インストール不要、操作が直感的         | 一般ユーザー、非エンジニア |

グラフを自動で画像化したい場合でも、手動で素早く保存したい場合でも、これら2つの方法で多様なニーズに対応可能です。

さらに Excel ファイル処理の詳細を知りたい方は、以下のリソースも参考にしてください：

* [Spire.XLS チュートリアルセンター（公式）](https://jp.e-iceblue.com/tutorials/net/spire-xls-net/xls-net-program-guide-content.html)
* [Microsoft Docs - Excel VBA によるグラフ操作](https://learn.microsoft.com/ja-jp/office/vba/api/overview/excel)
📘 Vol.14：画面遷移図詳細（管理者側）

本記事では、Struts2を用いて作成した掲示板システムにおける***管理者向けの画面遷移フロー***について説明します。

「📘 Vol.13」では、ユーザー・管理者を含めた***全体の遷移図***を掲載しましたが、本記事ではそのうち「***管理者機能***」に特化して詳しく解説します。


### 🗂️ 管理者が操作可能な項目

管理者は、以下の項目を管理・操作することができます：

- 掲示板管理（作成・編集・削除）

- ユーザー管理（作成・編集・削除）

- スレッド管理（編集・削除）

- 投稿管理（削除）


---

### 🔄 画面遷移図（管理者側）
以下が管理者側の画面遷移フロー図です。

```text
[1. ログイン画面]
   ↓
[2. 管理メニュー画面]
   ├─→ [3. 掲示板管理画面]
   │       ├─→ [4. 掲示板作成画面]
   │       └─→ [5. 掲示板編集画面]
   │
   ├─→ [6. ユーザー管理画面]
   │       ├─→ [7. ユーザー作成画面]
   │       └─→ [8. ユーザー編集画面]
   │
   ├─→ [9. スレッド管理画面]
   │       ├─→ [9-1. スレッド編集画面（管理者用）]
   │       └─→ [9-2. スレッド削除確認画面（管理者用）]
   │
   └─→ [10. 投稿管理画面]
           └─→ [10-1. 投稿削除確認画面（管理者用）]
```

---

### 🔢 各画面の詳細説明

---

### [1. ログイン画面]
- 管理者・ユーザー共通のログイン画面。

- 認証後、管理者は[2. 管理メニュー画面]へ遷移。

---

### [2. 管理メニュー画面]
- 管理機能のハブ画面。

- 以下の管理機能へのリンクを表示：

  - 掲示板管理

  - ユーザー管理

  - スレッド管理

  - 投稿管理


---


### [3. 掲示板管理画面]
- 既存の掲示板一覧を表示。

- 各掲示板に対して「編集」「削除」操作が可能。

- 「新規作成」ボタンから[4]へ遷移可能。

---

### [4. 掲示板作成画面]
- 新しい掲示板のタイトルや説明を入力して作成。

---

### [5. 掲示板編集画面]
- 既存の掲示板の情報を編集。

- タイトル・説明文の修正が可能。

---

### [6. ユーザー管理画面]
- 登録済みユーザーの一覧を表示。

- 各ユーザーの「編集」「削除」操作が可能。

- 「新規ユーザー作成」から[7]へ遷移。

---

### [7. ユーザー作成画面]
- ユーザー名、パスワード、権限（管理者/一般）を入力して登録。

---


### [8. ユーザー編集画面]
- ユーザー情報の更新が可能。

- 権限の変更もここで行う。

---

### [9. スレッド管理画面]
- すべてのスレッドを一覧表示。

- 各スレッドごとに「編集」「削除」ボタンあり。

---

### [9-1. スレッド編集画面（管理者用）]
- タイトルや説明文を修正。

- 必要に応じて運営側の注釈を加えることも可能。

---

### [9-2. スレッド削除確認画面（管理者用）]
- スレッド削除前の確認画面。

- 関連投稿が存在する場合、削除をブロックまたは注意表示。

---

### [10. 投稿管理画面]
- 全投稿の一覧を表示。

- 通報や違反内容に応じて投稿を削除可能。

----


### [10-1. 投稿削除確認画面（管理者用）]
- 投稿内容を確認し、削除するかを選択。

- 削除理由の記録や通知機能の追加も検討可能。

---

### 🔍 今後の検討事項（運用面）
- 投稿やスレッドの「非表示対応」機能の導入。

- 投稿削除時の理由記録や通知処理の実装。

- 監査ログの導入による「誰がいつ何をしたか」の記録。

---

### 🧩 まとめ
本記事では、掲示板システムにおける***管理者側の画面遷移図***とその詳細を紹介しました。

ユーザー側と同様に、画面ごとの操作内容を明確にすることで、設計段階での***機能整理や責務の分離***にも役立ちます。

次回 Vol.15 では、***ユーザー側の画面遷移詳細***を改めて確認していきます。

---
ポテンシャルを保つための自分の個人開発

# 💻 金なしエンジニア、個人開発に挑戦中

個人開発に勤しんでいる金無しエンジニアです。

現在、0→1でサービスを立ち上げる真っ最中なのですが、そのハードルの高さや難しさを日々痛感しています。

昔から「ちょっと変なもの」を作るのは好きで、色々と手を動かしてきました。
でも今回は、本気で“使ってもらえる”ちゃんとしたサービスをつくるつもりです。

---

## 🧠 頭フル回転の日々

ロードマップ、将来的な展開、サービスの方向性、市場の動き、資金調達のことまで…。

考えることは山ほどあって「これは長い道のりになりそうだな……」と感じることもありますが、  
**コツコツ積み上げていくこと、継続することが一番大事**だと思っています。

今は、開発を“習慣”として取り入れるように意識して、  
**毎日ある程度の時間を決めて開発に取り組む**ようにしています。

---

## 🏗 現在の構成と方針

- **技術スタック**：Laravel + Vue（いわゆるフルスタック構成）
- **現在のフェーズ**：土台構築中
- **開始形態**：Webサービス（アプリは余裕ができたら……）

将来的にはアプリ開発にもチャレンジしたい気持ちはありますが、  
現時点では、ユーザー導線や運用コスト的にもWebのほうがベターと判断しています。

---

## 🛠 自分の進め方

### 1. 全体像を描く（＝メモ書きまくる）
- 必要な構成や機能をざっくり洗い出す
- GitHubに思いついたものをどんどんメモ
- 書き出すうちに要件が膨らむ → 構成が見えてくる

### 2. 外側だけHTMLで先に作る
- モックではなく、実際のHTMLで“見た目”だけ先に組む
- 動きがなくてもOK。まずは“見える化”が重要

### 3. デザインやUIは「参考＋アレンジ」
- 優れたサイトを参考にして取り入れる（パクる）
- 完全コピーではなく、**自分の世界観やテーマに合わせて調整**

※ピカソも最初は模倣から。真似は悪じゃない！

---

## 📱 スマホ最適化を最優先

アクセスの大半がスマホからという現実を踏まえて、  
**UIやデザインはスマホファーストで考えています。**

---

## 👀 実装できなくても「見せる」ことが大事

技術的にまだ実装できない or 今は必要ない機能でも、  
**UIだけでも見せておくように意識**しています。

なぜなら、ユーザーにとって：

> 「このサービス、これから機能がどんどん増えていくんだ！」  
という期待感が持てることは大きな価値。

サービスに継続的に触れてもらえるように、“未来”もUIで伝えるようにしています。

---

## ✔ ポイントまとめ

- ✅ 思いついたら GitHub にメモ
- ✅ 機能はまず洗い出し
- ✅ HTMLで外観を先に作って雰囲気をつかむ
- ✅ 優れたデザインは参考に（ただしアレンジはする）

---

## ✅ 現在の開発状況（2025/05/30時点）

- [🔨] 主要なページ構成：**約7割完成**
- [🔧] サブページの整理中
- [🧩] Vueのコンポーネント化を進行中
- [🗂] フロントとバックを統合
- [📊] 最小構成かつパフォーマンス重視のテーブル設計を模索中

---

## 🏁 最後に

地道に積み重ねて、**いつかリリースできる日を目指して**がんばっています。

同じように個人開発を頑張っている方、  
**一緒にがんばりましょう！🔥**

また進捗があれば書いていこうと思いますー！
IntelliJで複数行同時編集する方法(Windows)

## TL;DR

Ctrl を2回押して、2回目を押しっぱなしにしてから、上/下矢印キー

## 誰向けか？

- Windows環境のIntelliJで複数行同時編集をしたい人
- マルチカーソルしたい人
- VScodeの ctrl+alt + 上/下矢印キー のような操作をしたい人
  - 人によってショーカットは違うかも
終了判定



今日も条件分岐がテーマの問題で、「終了判定」を解いた！問題文に “Σ” が出てきてびっくりしたけど、やることはシンプル！

<br><br>

## 問題概要

- 長さ `N` の数列Aが与えれらる。
- 数列の中で最初に出てくる奇数の手前までの合計を出す。

<br>

入力例：

    5
    2 4 6 8 1

出力例1：

    20

<br>

https://paiza.jp/works/mondai/conditions_branch/conditions_branch__complex_step4

<br><br>

## ✅OKコード例：
```js
const rl = require('readline').createInterface({ input: process.stdin });
const lines = [];

rl.on('line', (input) => {
    lines.push(input);
});



rl.on('close', () => {
    const N = Number(lines[0]); // 数列の長さ
    const arrA = lines[1].split(' ').map(Number); 



    let even = []; // 最初の奇数までの偶数を格納する配列

    for (let i = 0; i < N; i++) {

        if (arrA[i] % 2 !== 0) {
            break; // 奇数が出たらループ終了
        } 
        
        else {
            even.push(arrA[i]); // 偶数なら追加
        }
    }


    // 偶数たちの合計を計算
    const result = even.reduce((sum, element) => sum + element, 0);
    
    console.log(result); // 結果を出力

});
```
- `A[i] % 2 !== 0`：奇数かどうかのチェック。
- `break`：最初の奇数が出た時点でそれ以降は無視。
- `reduce` を使ってその合計を計算。

<br><br>

## ✨ さらにスッキリ書くなら？
```js
    let sum = 0;
    for (let i = 0; i < A.length; i++) {
        
        // 奇数が出たらループ終了
        if (A[i] % 2 !== 0) break; 
        
        // 偶数なら加算
        sum += A[i]; 
    }

    console.log(sum);
```
<br><br>

## 💡メモ
- 奇数チェックは `% 2 !== 0`
- `break`　→　`for` 文を終了
- `reduce()` で合計を出すとき、初期値0を忘れずに

<br><br><br>[僕の失敗談(´;ω;｀)と解決法🐈](https://paizabeginner.wordpress.com/2025/05/30/paiza%e3%81%a7%e5%9f%ba%e6%9c%ac%e3%83%9e%e3%82%b9%e3%82%bf%e3%83%bc%ef%bc%9a%e7%b5%82%e4%ba%86%e5%88%a4%e5%ae%9a/)
【Laravel】依存性注入（DI）のなんとなくざっくり理解

## 背景
laravelでポートフォリオ作成中。
講座等でたくさん出てくる「依存性注入」が本当になんとなくわかってきたから自分の言葉でまとめておく。
## 依存性注入とは
DI（Dependency Injection）ともいう。
必要な部品（依存？）を「外からもらう」こと。

「依存」を他のところから「注入」してもらう。
→これがまだあんまりイメージできないんだけど。
「自分でnewしない」のがポイント。

この設計で、クラス間の依存度を下げる（疎結合にする）ことができる。

##  Laravelでの例
### DIじゃない設計 （密結合）
```
public function index()
{
    $request = new Request();
}
```
自分でRequestクラスのインスタンスを作っている。
これはクラス間の依存度が高い。
毎回newしないといけないし、テストしたり、拡張したりしにくい。

### DIに基づく設計 （疎結合）
```
public function index(Request $request)
{
    
}
```
これはLaravelのサービスコンテナが自動でインスタンスを作ってくれる。
自分でnewしなくていい。

Laravelはサービスコンテナを使って、依存性注入が自動でできるから、
責務分離やテストがしやすいフレームワーク。


## サービス層やリポジトリ層も同じ考え方
Controller ⇄ Service ⇄ Repository
コントローラの責務を分散させるのも、依存性注入の考え方に基づいている。

## まとめ
* 依存性注入＝依存するクラスを自分で作らず、外からもらう（注入される）設計思想
* Laravelではサービスコンテナが自動でやってくれる
* コードが疎結合になって、テストや拡張がやりやすくなる
* コントローラをサービス・レポジトリ層に分けるのも、同じ考え方
📘 Vol.13：画面遷移図紹介（管理者・ユーザー共通）

はじめに
本記事では、掲示板アプリケーションにおける***画面遷移の全体像***を紹介します。
このアプリは「ユーザー側」と「管理者側」の機能を持つため、双方の画面遷移を一枚の図で俯瞰できるよう設計しています。

>✅ 遷移図はこちら：
[🔗 画面遷移図（PDF）](https://github.com/juehara-crypto/Portfolio_Bulletinboard/blob/master/01.%E5%9F%BA%E6%9C%AC%E8%A8%AD%E8%A8%88%E6%9B%B8/%E7%94%BB%E9%9D%A2%E9%81%B7%E7%A7%BB%E5%9B%B3.pdf)

---

### 🎯 遷移図の目的
- アプリケーション全体の***画面構成と遷移関係***を把握しやすくする

- 各画面がどのアクター ***（ユーザー／管理者）によって利用される*** かを明示する

- 各種仕様書（機能仕様・詳細設計）やブログ記事との***位置づけを明確化***する


---

### 🧭 画面区分の概要
***👤 ユーザー側（利用者ポータル）***
掲示板一覧・詳細表示

- スレッド一覧／詳細／投稿作成

- 自分が作成したスレッド／投稿の一覧・編集

- ログイン／ログアウト機能

※ユーザーによるスレッド削除は不可。編集・投稿は可能です。

---

### 🛠️ 管理者側（管理メニュー）
- 掲示板の作成・編集・削除

- スレッドの削除（ユーザーが作成したものも含む）

- 投稿の削除

- ユーザー管理（ユーザー登録・編集・削除）

管理者は、掲示板の運営を行うための一連の機能を専用メニューから操作します。

---

🧱 設計方針との関係
本遷移図は、[設計書](https://github.com/juehara-crypto/Portfolio_Bulletinboard/blob/master/%E6%8E%B2%E7%A4%BA%E6%9D%BF%E3%82%A2%E3%83%97%E3%83%AA%E4%BB%95%E6%A7%98%E6%9B%B8.pdf)における以下のセクションと対応しています：

📄 「4. 機能カテゴリ一覧」
機能のカテゴリ（共通基盤機能、ユーザーポータル機能、管理機能など）

📄 「5. 機能詳細仕様（カテゴリ別）」
上記カテゴリごとの具体的な画面と機能の記述

📄 「Vol.14」・「Vol.15」シリーズ
遷移図の詳細解説記事として、以下のように役割を分担しています：


| 記事                                                                             | 内容                         |
| ------------------------------------------------------------------------------ | -------------------------- |
| Vol.13（本記事）                                                                    | 全体の構成・画面マップの提示             |
| Vol.14（管理者側詳細）                                                                 | 管理者が操作する画面の構成と遷移解説（今後公開予定） |
| [Vol.15（ユーザー側詳細）](https://qiita.com/juehara-crypto/items/0b786ff983dcb101cead) | ユーザーが操作する画面の構成と遷移解説        |

---

### 📌 注意点・補足
本記事では***個別画面の仕様やボタンアクションの詳細説明***は行いません。

それらは今後の Vol.14／Vol.15 で画面単位に深掘りします。

遷移図の色分けやラベルにより、***ユーザー／管理者の操作範囲が明確に識別できる構成***としています。


### おわりに
今後、各機能カテゴリや画面の詳細を扱った記事を順次公開していく予定です。
本記事と遷移図をベースにすることで、全体像を見失わずに設計・実装・テストが進められます。

---

### 🔗 関連リンク
[🎨 画面遷移図（全体）PDF](https://github.com/juehara-crypto/Portfolio_Bulletinboard/blob/master/01.%E5%9F%BA%E6%9C%AC%E8%A8%AD%E8%A8%88%E6%9B%B8/%E7%94%BB%E9%9D%A2%E9%81%B7%E7%A7%BB%E5%9B%B3.pdf)

📘 Vol.14：画面遷移図詳細（管理者側）※作成中

📘 Vol.15：画面遷移図詳細（ユーザー側）
Log4j2でサンプルコード通り、書くとエラーになってしまった

<h1>log4j2でサンプルコード通り、書くとエラーになってしまった</h1>

興味があったため、Log4jの学習をしていてサンプルコード通りに入力したが、何故かエラーになってしまった。インポートに必要なjarファイルをビルドパスで正しく設定している。

<h3>書いたコード</h3>
<pre>
package practice;<br>
<br>
import org.apache.log4j.Logger;
<br>
public class Practice {
	public static void main(String[] args) {
		Logger logger = org.apache.log4j.LogManager.getLogger("ログ出力");
		
		    logger.info("プログラム実行中");
	    }
    }
</pre>

<h3>発生した現象</h3>
<pre>log4j:WARN No appenders could be found for logger (practice.Practice).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
</pre>

<h3>解決するために何をしたか</h3>
まず右の検索ワード＜java log4j2 上記のエラーメッセージ1行目＞でググると様々なサイトが表示
され、上のサイトから順に書かれていることを試していった。結局、どういう理由わからないが
上手くいかなかった。上から何番目かに表示されていたStackOverFlowでようやく解決できた。

org.apache.log4j.BasicConfigurator.configure();

Log4j.propertiesを書かない場合は、上記をソースコード内に書くことに<br>よって、Appender と Layoutを自動設定してくれる。

<h3>改善後のソースコード</h3>
<pre>
package practice;
<br>
import org.apache.log4j.Logger;
<br>
public class Practice {
	public static void main(String[] args) {
        org.apache.log4j.BasicConfigurator.configure();
		Logger logger = org.apache.log4j.LogManager.getLogger("ログ出力");
	    logger.info("プログラム実行中");
    }
}
TypeScript の asとはなにかを掘り下げて考えてみた

## `as` は何をするのか

TypeScript に対して、「この値はこの型ですよ」と明示的に伝えるために使います。これを **型アサーション（type assertion）** と呼びます。

```ts
const value = { name: "apple" } as Fruit;
```

このように書くと、TypeScript は `value` を `Fruit` 型として扱ってくれます。


### 型アサーション（type assertion）とは

「この値は絶対にこの型ですよ」と TypeScript に教えること


```ts
const value = "hello" as string;
```
この場合、TypeScript に「この値は string 型で扱っていい」と開発者が責任を持って宣言しています。


### アサーションの言葉の意味
「アサーション（assertion）」は日本語でいうと 「断言」や「主張」 のことです。

プログラミングでは、「これは絶対に○○であるべきだ」と自分で保証することを「アサーション」と呼びます。

## なぜ `as` が必要なのか

TypeScript は安全性の高い型チェックを行うため、"undefinedかもしれない" や "型が合ってないかもしれない" という不安があると、エラーを出します。

そんなときに「これはこの型で合ってる」と教えるために `as` を使います。



## 実際の使用例

React + Supabase で作った英単語帳アプリの中で、APIから返ってきた JSON を使って複数の単語カードを表示したい場面がありました。

### `as` を使わないとき
```ts
setWordList([
  { ...parsed.main, label: "main" },
  parsed.synonyms ? { ...parsed.synonyms, label: "synonym" } : undefined,
  parsed.antonyms ? { ...parsed.antonyms, label: "antonym" } : undefined,
]);
```
TypeScript は `label` プロパティの存在を認識できず、「label なんてプロパティ知らない」と型エラーになり怒られました。


### `as` を導入してみた
```ts
setWordList([
  { ...parsed.main, label: "main" } as LabeledWord,
  parsed.synonyms
    ? { ...parsed.synonyms, label: "synonym" } as LabeledWord
    : undefined,
  parsed.antonyms
    ? { ...parsed.antonyms, label: "antonym" } as LabeledWord
    : undefined,
].filter(isLabeledWord));
```

ここでの as LabeledWord は、
・Gemini から返ってきたデータ（WordInfo）に label を追加した
・その結果、TypeScript に「これは LabeledWord 型だよ」と教える必要がある

という背景で使われています。

filter() の部分では、**型ガード関数**を使って undefined を取り除いています。

```ts
function isLabeledWord(word: LabeledWord | undefined): word is LabeledWord {
  return word !== undefined;
}
```
この関数は「この値は LabeledWord です」と TypeScript に確実に伝える手段で、as の補助的な役割を果たします。



## まとめ

* `as` は型を明示するためのもの
* 「何型として扱いたいのか」を意識したい時に `as` を使う
* 型ガード関数と併用して使う

https://typescriptbook.jp/reference/values-types-variables/type-assertion-as
【Vue.js】コンポーザブルでトーストの表示処理を再利用

# はじめに
REST APIのエラー時、ステータスコード及びエラーメッセージをユーザーにトーストで通知したい。
トーストをコンポーネント化し、呼び出し処理を各ページに実装していたが、冗長であることに気づいた。
<br>

▼トーストの親コンポーネント（変更前）
``` vue
<template>
  // propsでステータスコード、エラーメッセージをトーストに渡す
  <Toast v-if="isToastVisible" :message="errorMessage" :status="errorStatus"></SpToast>
</template>

<script setup lang="ts">
import Toast from '@/components/Toast.vue'

// ステータスコード
const errorStatus = ref<number>(0)
// エラーメッセージ
const errorMessage = ref<string | null>(null)
// トースト表示/非表示のフラグ
const isToastVisible = ref<boolean>(false)

.
.
.
// トースト表示処理
errorStatus.value = res.status
errorMessage.value = res.error.message
isToastVisible.value = true
```

トーストの呼び出し処理をコンポーザブル(Composable)で再利用可能にする。


# コンポーザブル(Composable)とは？
Vue3のComposition APIにおいて状態を持つロジックをカプセル化してまとめた関数。コンポーネント間で共通するロジックを使いまわすことができる。
Reactでは似た機能をカスタムフックと呼ぶらしい。

https://ja.vuejs.org/guide/reusability/composables


# トーストの呼び出し処理のコンポーザブル化
上記に書いたコードをコンポーザブルとして外部に切り出してみる。
<br>

▼コンポーザブル
``` ts
import { ref } from 'vue'

// 慣習としてコンポーザブル関数の名前は"use"で始める
export function useToast() {
  // コンポーザブルによってカプセル化および管理される状態
  const errorStatus = ref<number>(0)
  const errorMessage = ref<string | null>(null)
  const isToastVisible = ref<boolean>(false)

  // トースト表示処理
  const showToast = (status: number, message: string) => {
    errorStatus.value = status
    errorMessage.value = message
    isToastVisible.value = true
  }

  // 提供する値と関数を返す
  return {
    errorStatus,
    errorMessage,
    isToastVisible,
    showToast,
  }
}
```

コンポーザブルを呼び出し元のページから呼び出す
<br>

▼トーストの親コンポーネント（変更後）

``` vue
<template>
  // propsでステータスコード、エラーメッセージをトーストに渡す
  <Toast v-if="isToastVisible" :message="errorMessage" :status="errorStatus"></SpToast>
</template>

<script setup lang="ts">
import useToast from './useToast.ts'

const { errorStatus, errorMessage, isToastVisible, showToast } = useToast()

showToast(res.status, res.error.message)
```

元のコードよりだいぶスッキリして再利用性・可読性・保守性が向上したと考えられる。