OmniAICreator/Qiita-1.07M huggingface dataset:
Pythonで実装するStateパターン：状態によって振る舞いを動的に切り替える



## 概要

**State（ステート）パターン**は、  
オブジェクトの内部状態によって**振る舞い（メソッドの挙動）を動的に切り替える**ことを目的とした振る舞い系のデザインパターンである。

各状態をクラスとして定義することで、  
**状態ごとの責務分離と状態遷移の可視化・制御を実現できる**。

---

## 1. なぜStateパターンが必要か？

### ❌ 条件分岐で状態を管理しようとする設計

```python
if state == "locked":
    ...
elif state == "unlocked":
    ...
```

→ 条件が増えるたびに**メソッドが肥大化し、保守困難になる**

---

### ✅ 状態ごとに専用のクラスを用意し、振る舞いを分離

```python
context.set_state(LockedState())
context.press_button()  # 状態に応じた処理を実行
```

→ **状態クラスに応じた処理をカプセル化し、切り替えを直感的に**

---

## 2. 基本構造

### ✅ State（共通インターフェース）

```python
class State:
    def handle(self, context):
        raise NotImplementedError
```

---

### ✅ ConcreteStates（具体的な状態）

```python
class LockedState(State):
    def handle(self, context):
        print("🔒 ドアはロックされています。開けられません。")
        context.set_state(UnlockedState())

class UnlockedState(State):
    def handle(self, context):
        print("🔓 ドアが開きました。ロックします。")
        context.set_state(LockedState())
```

---

### ✅ Context（状態管理本体）

```python
class Door:
    def __init__(self):
        self._state = LockedState()

    def set_state(self, state: State):
        self._state = state

    def press_button(self):
        self._state.handle(self)
```

---

### ✅ 使用例

```python
door = Door()
door.press_button()  # 🔒 → 🔓
door.press_button()  # 🔓 → 🔒
door.press_button()  # 🔒 → 🔓
```

---

## 3. Python的応用：動的に戦略を切り替えるオブジェクト設計

```python
class Player:
    def __init__(self):
        self._state = NormalState()

    def change_state(self, state):
        self._state = state

    def move(self):
        self._state.move()

class NormalState:
    def move(self):
        print("通常移動（速度1x）")

class SpeedUpState:
    def move(self):
        print("加速移動（速度2x）")
```

```python
player = Player()
player.move()
player.change_state(SpeedUpState())
player.move()
```

→ **振る舞いを状態インスタンスで切り替える柔軟な実装**

---

## 4. 実務ユースケース

### ✅ ゲーム内のキャラクター挙動制御（通常 / 無敵 / 麻痺）

→ **状態によって移動・攻撃の挙動を切り替え**

---

### ✅ フォームウィザードの状態管理（入力 → 確認 → 完了）

→ **状態ごとの画面/バリデーションロジックを分離**

---

### ✅ ネットワーク接続状態（未接続 / 接続中 / 切断中）

→ **接続処理の流れとUI反映を状態に応じて制御**

---

### ✅ チケットライフサイクル管理（発行 / 使用中 / 完了）

→ **ステータス遷移に応じて処理内容を変更**

---

## 5. よくある誤用と対策

### ❌ Contextが状態ごとの処理を知りすぎてしまう

→ ✅ **処理はState側に委譲し、Contextは状態の保持と切り替えに限定**

---

### ❌ 状態クラスが過剰に肥大化

→ ✅ 状態ごとの責務を**明確かつシンプルに分割**

---

### ❌ 状態が1つしか存在しない用途に適用

→ ✅ Stateパターンは**状態と振る舞いが複数存在し、動的に切り替える必要がある場合に有効**

---

## 結語

**Stateパターンとは、“振る舞いを状態に委ね、コードに動的な表現力を与える構造設計”である。**

- 状態に応じた振る舞いの切り替えを**責務分離とカプセル化で明示的に管理**  
- 条件分岐の塊を**状態クラスとして独立させ、拡張性と保守性を向上**  
- Pythonではクラスの柔軟性とシンプルな構造により、**状態遷移を明快に実装可能**

**Pythonicとは、“現在の文脈に応じて振る舞いを変える柔軟さ”を保つこと。  
Stateパターンはそのコンテキストの動的変化を、構造で美しく捉える設計技法である。**
Pythonで実装するVisitorパターン：構造と処理の分離による柔軟な拡張



## 概要

**Visitor（ビジター）パターン**は、  
オブジェクト構造に対する操作を、構造クラスから分離して**「訪問者」として外部に定義する**ことで、  
**構造を変えずに新しい操作（振る舞い）を追加可能にするパターン**である。

複雑な構文木やオブジェクトの階層構造に対し、  
**共通インターフェースを介して柔軟に処理を切り替える**ことが可能になる。

---

## 1. なぜVisitorが必要か？

### ❌ 構造オブジェクト自身が処理ロジックを持ちすぎて肥大化

```python
class Node:
    def evaluate(self): ...
    def print_tree(self): ...
    def optimize(): ...
```

→ 各処理が構造の中に密結合し、**拡張のたびに修正が必要**

---

### ✅ Visitorを導入し、処理ロジックを外部クラスに分離

```python
node.accept(Evaluator())
node.accept(Printer())
```

→ **構造をそのままに、処理を訪問者クラスとして外部化・追加可能に**

---

## 2. 基本構造

### ✅ Element（構造側の抽象）

```python
class Node:
    def accept(self, visitor):
        raise NotImplementedError
```

---

### ✅ ConcreteElements（構造定義）

```python
class NumberNode(Node):
    def __init__(self, value):
        self.value = value

    def accept(self, visitor):
        return visitor.visit_number(self)

class AddNode(Node):
    def __init__(self, left: Node, right: Node):
        self.left = left
        self.right = right

    def accept(self, visitor):
        return visitor.visit_add(self)
```

---

### ✅ Visitor（処理の抽象）

```python
class Visitor:
    def visit_number(self, node): pass
    def visit_add(self, node): pass
```

---

### ✅ ConcreteVisitor（処理定義）

```python
class Evaluator(Visitor):
    def visit_number(self, node):
        return node.value

    def visit_add(self, node):
        return node.left.accept(self) + node.right.accept(self)
```

---

### ✅ 使用例

```python
tree = AddNode(NumberNode(3), AddNode(NumberNode(2), NumberNode(1)))
evaluator = Evaluator()
result = tree.accept(evaluator)

print(result)  # 6
```

---

## 3. Python的応用：`@singledispatchmethod` を使った動的ディスパッチ

```python
from functools import singledispatchmethod

class DynamicVisitor:
    @singledispatchmethod
    def visit(self, node):
        raise NotImplementedError

    @visit.register
    def _(self, node: NumberNode):
        return node.value

    @visit.register
    def _(self, node: AddNode):
        return self.visit(node.left) + self.visit(node.right)
```

→ **マルチメソッド的な構造により、Pythonらしく実装可能**

---

## 4. 実務ユースケース

### ✅ 抽象構文木の評価・最適化

→ パーサ/インタプリタにおける**式の評価・表示・変換**の切り替え

---

### ✅ ファイルシステム構造の走査とレポート生成

→ ファイル・ディレクトリに対して**サイズ集計/表示/圧縮**などを分離実装

---

### ✅ UIコンポーネント構造へのイベント処理適用

→ ボタン/入力欄/パネルなどの**描画/検証/保存処理をVisitor化**

---

### ✅ ビジネスルールの外部定義・適用

→ 各ドメインオブジェクトに対する**検証・計算・集計処理を注入**

---

## 5. よくある誤用と対策

### ❌ Visitorクラスが全ての構造型を知ってしまう

→ ✅ Visitorの拡張は必要に応じて分割し、**単一責務を守る**

---

### ❌ Element側のacceptに処理が入りすぎる

→ ✅ `accept` は**Visitorの呼び出しに限定**すべき

---

### ❌ 構造が頻繁に変更されるプロジェクトに無理に適用

→ ✅ Visitorは**構造が安定していて、処理が頻繁に追加される場面に適す**

---

## 結語

**Visitorパターンとは、“構造に手を加えず、処理だけを拡張するための訪問設計”である。**

- 処理の拡張をクラス外に独立させ、**構造との疎結合を実現**  
- 複数の処理（表示/最適化/検証/計算など）を、**構造の再利用性を保ったまま外部化**  
- Pythonではダックタイピングやマルチディスパッチを活用し、**柔軟かつ簡潔にVisitor設計を実現できる**

**Pythonicとは、“構造と責務を分離して洗練させる”ことであり、  
Visitorパターンはその責務の訪問者として、コードの中に拡張性を宿す技法である。**
Pythonで実装するMementoパターン：状態のスナップショットを安全に保存・復元する



## 概要

**Memento（メメント）パターン**は、  
オブジェクトの内部状態をスナップショットとして記録・保存し、  
**その状態を後から安全に復元できるようにするための設計パターン**である。

**Undo/Redo、タイムトラベル、履歴管理**などの実装に非常に適しており、  
「内部状態のカプセル化を保持したまま復元する」ことが最大の特徴。

---

## 1. なぜMementoが必要か？

### ❌ 状態の変更に対応したUndo処理が複雑すぎる

```python
# 状態の保存なしにロールバック不能
editor.content = "新しい内容"
```

→ 状態の復元を実現するには、**状態スナップショットの保存が必要**

---

### ✅ 状態を外部に記録し、任意のタイミングで復元可能に

```python
snapshot = editor.save()
# ...
editor.restore(snapshot)
```

→ **内部構造に立ち入らず、安全に状態を復元可能にする**

---

## 2. 基本構造

### ✅ Memento（スナップショット）

```python
class Memento:
    def __init__(self, state):
        self._state = state

    def get_state(self):
        return self._state
```

---

### ✅ Originator（状態を持つ本体）

```python
class Editor:
    def __init__(self):
        self._content = ""

    def type(self, words):
        self._content += words

    def save(self):
        return Memento(self._content)

    def restore(self, memento):
        self._content = memento.get_state()

    def show(self):
        print(f"内容: {self._content}")
```

---

### ✅ Caretaker（履歴の管理）

```python
class History:
    def __init__(self):
        self._mementos = []

    def push(self, memento):
        self._mementos.append(memento)

    def pop(self):
        return self._mementos.pop() if self._mementos else None
```

---

### ✅ 使用例

```python
editor = Editor()
history = History()

editor.type("Hello ")
history.push(editor.save())

editor.type("World!")
history.push(editor.save())

editor.show()  # → 内容: Hello World!

# Undo
editor.restore(history.pop())
editor.show()  # → 内容: Hello 

# Undo again
editor.restore(history.pop())
editor.show()  # → 内容: 
```

---

## 3. Python的応用：deepcopyベースの汎用Memento実装

```python
import copy

class GenericMemento:
    def __init__(self, obj):
        self._snapshot = copy.deepcopy(obj)

    def restore(self):
        return copy.deepcopy(self._snapshot)
```

→ **どんなオブジェクトでも状態を保持・復元できる汎用ツールとして応用可能**

---

## 4. 実務ユースケース

### ✅ テキストエディタのUndo/Redo機能

→ 入力内容を時系列で保存し、**任意の時点へロールバック**

---

### ✅ ゲームのセーブポイント・チェックポイント

→ キャラクターの状態やフィールド情報などを**安全に巻き戻し**

---

### ✅ データベーストランザクションのローカルロールバック

→ 書き込み前の状態を保持し、**整合性のある巻き戻し**

---

### ✅ スプレッドシート・フォームの編集履歴追跡

→ 入力状態を保持して、**元の状態へ簡単に戻せる**

---

## 5. よくある誤用と対策

### ❌ Mementoに処理ロジックを含めてしまう

→ ✅ **Mementoは状態の保存・復元に限定すべき**

---

### ❌ CaretakerがOriginatorの内部状態を操作する

→ ✅ **Originatorだけが状態の保存・復元を行うべきであり、他者は介入不可**

---

### ❌ Mementoの量が肥大化してパフォーマンスに影響

→ ✅ **定期保存・差分保存・容量制限などの設計的対処が必要**

---

## 結語

**Mementoパターンとは、“変化を記録し、過去へ戻るための設計的タイムマシン”である。**

- 状態を外部に安全に保存し、**任意のタイミングで復元可能にする構造**  
- Undo/Redo、履歴、復元処理を**カプセル化と責務分離の原則に基づいて構築**  
- Pythonでは柔軟なオブジェクト操作と`deepcopy`の活用により、**明快かつ強力な状態復元が可能**

**Pythonicとは、“変化を記録し、戻る自由を与える”こと。  
Mementoパターンはその自由な復元性を、構造の中に安全に埋め込む技法である。**
Pythonで実装するChain of Responsibilityパターン：責任の流れを連鎖で設計する



## 概要

**Chain of Responsibility（責任の連鎖）パターン**は、  
複数のオブジェクトに順に処理を委譲し、**ある条件を満たすものが責任を引き受けて処理を完了する**ための設計パターンである。

この構造により、**送信者（リクエスト元）と受信者（処理実体）の結合を疎に保ちながら、柔軟で拡張可能な処理フローを実現**する。

---

## 1. なぜChain of Responsibilityが必要か？

### ❌ 条件分岐が集中した処理ロジック

```python
if request.type == "auth":
    ...
elif request.type == "log":
    ...
```

→ 新しい責任の追加で、**if-elseの嵐が発生し、拡張性が低下**

---

### ✅ 各処理単位を責任としてチェーンで接続し、順に評価する

```python
auth.set_next(logger).set_next(handler)
auth.handle(request)
```

→ **各処理が責任を持って処理・パスを判断。拡張も容易**

---

## 2. 基本構造

### ✅ Handler（共通インターフェース）

```python
class Handler:
    def set_next(self, handler):
        self._next = handler
        return handler

    def handle(self, request):
        if hasattr(self, '_next'):
            return self._next.handle(request)
```

---

### ✅ ConcreteHandler（実処理）

```python
class AuthHandler(Handler):
    def handle(self, request):
        if request.get("auth"):
            print("認証成功")
        else:
            print("認証失敗 → 次へ")
            return super().handle(request)

class LogHandler(Handler):
    def handle(self, request):
        print("ログ記録中...")
        return super().handle(request)

class FinalHandler(Handler):
    def handle(self, request):
        print("最終処理を実行")
```

---

### ✅ 使用例

```python
auth = AuthHandler()
log = LogHandler()
final = FinalHandler()

auth.set_next(log).set_next(final)

request = {"auth": True}
auth.handle(request)
```

出力:
```
認証成功
ログ記録中...
最終処理を実行
```

---

## 3. Python的応用：デコレータ的連鎖処理にも適用可能

```python
class Middleware:
    def __init__(self, next=None):
        self.next = next

    def handle(self, request):
        if self.next:
            self.next.handle(request)

class RateLimiter(Middleware):
    def handle(self, request):
        if request.get("rate_limit_ok", True):
            print("レート制限クリア")
            super().handle(request)
        else:
            print("レート制限ブロック")

class Validator(Middleware):
    def handle(self, request):
        if "user" in request:
            print("入力バリデーション成功")
            super().handle(request)
        else:
            print("バリデーション失敗")
```

```python
chain = RateLimiter(Validator(FinalHandler()))
chain.handle({"user": "alice", "rate_limit_ok": True})
```

---

## 4. 実務ユースケース

### ✅ Webアプリケーションのリクエスト処理パイプライン

→ 認証 → ログ → バリデーション → ビジネスロジック などを**責任の連鎖で構築**

---

### ✅ ロガー・監視・セキュリティなどの横断的処理

→ 事前処理・後処理を**独立した責任単位として組み込む**

---

### ✅ イベント処理・UIイベントチェーン

→ 特定のコンポーネントがイベントを処理しなければ、**次のコンポーネントへ委譲**

---

### ✅ フィルタチェーン設計（例：セキュリティチェック → XSS → トークン検証）

→ **中間層で責任を逐次消化し、柔軟に拡張可能**

---

## 5. よくある誤用と対策

### ❌ 全ての処理が責任を持ってしまう

→ ✅ **各ハンドラーは「処理する/しない」を明確に判断すべき**

---

### ❌ チェーン構成がハードコードされている

→ ✅ **柔軟にハンドラーを組み替えられるように設計すべき**

---

### ❌ 次のハンドラーへの委譲が必須になっている

→ ✅ 最終処理やエラーストップなど**連鎖を止める設計も組み込むべき**

---

## 結語

**Chain of Responsibilityパターンとは、“責任の流れを構造として連鎖させ、柔軟に制御を渡す”ためのデザイン技法である。**

- 処理の流れをモジュール化・分離し、**拡張性と順応性を両立**  
- 各責任単位が、**受ける/渡すの判断を担うことで柔軟な制御が実現**  
- Pythonではオブジェクト指向構造に加え、**動的なハンドラー構成・関数型設計との親和性も高い**

**Pythonicとは、“制御構造を流れのようにしなやかに構築する”ことであり、  
Chain of Responsibilityパターンはその制御の意志を、連鎖する責任という形で表現する設計技法である。**
ファイルの内容が同じか確認する方法（ハッシュ値を比較）

Linux環境でファイル内容の正しさを比較するときどうしてますか？

diffコマンド使うのが多いかと思います。
ですが、
・バイナリファイル同士の同一性を確認できない
・行のわずかな変更や行の順序の差分を検知してしまう（内容が一致してても、順序が異なれば差分としてでてしまう）
という課題がある。

単純にデータの内容の一致を確認したい場合、
sha1sumコマンドを使うことで、
引数に指定したファイルの、SHA1アルゴリズムでの計算されたハッシュ値を表示することができるので、
そのハッシュ値を比較して一致すればファイルの中身は同一であることを保証できる。

#### コマンド概要
```
sha1sum ファイル名
```

*** 

#### コマンド実行例
```
# sha1sum sample_1.txt
384a8a9f6c477b7be4999dd5118558c32a8ce1b8 sample_1.txt
```
比較対象のもう一つのファイル
```
# sha1sum sample_2.txt
384a8a9f6c477b7be4999dd5118558c32a8ce1b8 sample_2.txt
```
384a8a9f6c477b7be4999dd5118558c32a8ce1b8
が一致するため、ファイル内のデータが同一であると判断できる

※参考サイト
https://eng-entrance.com/linux-command-sha1sum#MD
黄昏酒場スコアボード作成①〜背景と要件

## はじめに

初めてqiitaに投稿するゑふまいかというものです。
私は今、黄昏酒場スコアボードというものを作成しています。
今回は備忘録としてこのスコアボードを作成するにあたって使用した技術や学んだことを書いていきます。

## 背景、及び動機

黄昏酒場とは東方projectと同じエンジンが使われているゲームである。
昔は待宵という方がroyalflare netというドメインで東方projectシリーズのスコアボード(以降旧ロイヤルフレアと呼ぶ)を管理しており、その中に黄昏酒場のスコアボードもあった。
しかし突如待宵氏は運用を取りやめた。
東方界隈は大混乱に陥った。そこで正規東方シリーズに関しては海外ニキたちが新東方projectスコアボード、silentsalane netを立ち上げた。
だが黄昏酒場に関しては何故かスコアボードが作られなかった。
最近になって黄昏酒場のスコア狙いをする人が自分以外に現れたこと、及び自宅サーバPCを購入したこともあり、黄昏酒場スコアボードを立ち上げることにした。
特に今回の開発において気をつけるポイントとして、『旧ロイヤルフレアをモダンにしたものを作る』というのを意識した。
何故なら今更東方STGを触る人間は保守的な人間であることが予想され、あまりに違うものを作ると近寄らないと考えられるからである。
よって以降でも『旧ロイヤルフレアはどういう実装をしていたか』という点に言及しながら記述していく。


## 旧ロイヤルフレアの移植と失敗

実は待宵氏は旧ロイヤルフレアのコードを公開しており、サーバに置くだけの構成を作っていた。
いざ載せようとしたところ問題が起きた。
どうやらcgiという技術を使っていたようだ。
cgiとは動的にhtmlを生成する技術である。
旧ロイヤルフレアでは、①ユーザはalcostg.cgiに向かってHTTPリクエストを行い、②cgiサーバがPythonで書かれたalcostg.cgiを動かし、③alcostg.cgiはHTTPリクエストの種類によってランキング画面などのHTMLページを生成、という手順を踏んでいたようだ。
下記にざっくりとしたイメージを示す[^1]

![スクリーンショット 2025-04-08 223118.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3659726/5e17ead0-ee9b-4cf1-a9ec-9f38316e0777.png)



しかし自分の環境ではうまくcgiが動作しなかった。
cgiを勉強しろという話なのだが、正直この技術は枯れていて今更勉強しても役に立たないことが知られている。
(そもそも旧ロイヤルフレアは2006年頃に作成されたものなので当然古い)
そこで旧ロイヤルフレアをなぞりながらモダンにスコアボードを作成することにした


## 要件の整理

ざっくり旧ロイヤルフレアのユースケースについてまとめると以下のようになる

- ユーザはユーザ名、削除パスワード、リプレイファイルをサーバに投げる
- サーバはリプレイファイルを解析しスコアなどのメタデータを得る
- 削除したいときはリプレイidに紐付く削除パスワードを入力して削除する
- リプレイファイルのメタデータを元に記述された新着順一覧とスコア順一覧が見られる
- 新着順一覧やスコア順一覧のダウンロードボタンを押すとリプレイファイルがダウンロードされる

ここでリプレイファイルとは黄昏酒場が出力する、自機の動作やプレイ結果などが入ったバイナリファイルのことである。
最初は旧ロイヤルフレアに倣ってJavaScriptを使わずにHTMLのみで作成しようとしていたが、削除確認の具合が悪いということで以下のような3層構造にすることにした

![スクリーンショット 2025-04-08 225006_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3659726/78ad54a2-8d5f-4f07-a62b-0400ec9093e0.png)


また、本来ユーザ認証機能などを付けて、ユーザに紐付く削除パスワードを入力させるべきである。
しかし今回は旧ロイヤルフレアに倣い、リプレイidに紐付く削除パスワードで削除することにしている。
これはユーザ認証まで作ると開発規模が膨大になるという点、及びユーザ認証はなりすまし防止に効果があるがスコアボードは一人一つしか上げないことが予想できるためなりすましの識別が容易という点からである。


## 次回

いよいよバックエンドから開発を行っていく。

[^1]:上述した通り詳しくは勉強できていないので図が間違っている可能性がある。また投稿したい人は投稿.html、削除したい人はスコア順一覧.htmlか新着順一覧.htmlを介してからalcoscore.cgiに向かってリクエストを投げるが、ここでは省略している。
話題のパスキーやFIDOを使ってみた

先月（2025年3月）頃から、証券会社のオンラインサービスに不正アクセスをされたという報道が目立つようになりました。

参考ニュース
https://www3.nhk.or.jp/news/html/20250406/k10014771571000.html

私も他人事ではないなと思い、お金に関連するサービス（証券会社や銀行、ネットショッピング等）のセキュリティを改めて見直してみました。
そんな中、最近はパスキーやFIDO等のデバイスの生体認証を使ったログインに対応しているサービスも増えてきたので、使い勝手を確かめるため導入してみることにしました。

## 何それ？

従来のパスワードに代わる認証の方式として、サービスごとに自動生成される暗号鍵を使ってログインをする方式です。
スマホなら顔認証、指紋認証などの生体認証の他、端末のパスコードなど、要は端末のロックを解除する方法を様々なサービスのログイン認証にも使おうという発想です。

端末のOSとサービス側の両方が対応している必要があり、2022年頃から大手サービスを中心に対応が進んでいるもののまだ一般的とまでは言えないと思います。
対応していれば、パスキーを作成することで普段の端末ロック解除に近い感覚でサービスにログインすることができ、別途パスワードを覚えたりする必要もありません。

仕組み上正規のサービス以外にログインできないため、フィッシング耐性があります。
秘密鍵データはパスキー登録をした端末に保存されますが、通常はユーザーに直接見えないように設計されているようで、漏洩に対しても強いようです。

このことから、従来のパスワード方式より優れた認証方式だと言われています。

## 世のサービスの現状

冒頭で「パスキーやFIDO」と書きましたが、パスキーはFIDOアライアンスという団体が定めた認証技術です。
では何でこんな書き方をしたかと言うと、現状パスキーに対応したサービスもあれば「FIDO準拠を謳いつつ独自に実装したと思われる」方式も多く提供されているからです。

パスキー自体は決まった規格なので、OSとサービスが対応していれば同じ使い勝手で使うことができます。
私はiPhoneを使用していますが、対応サービスにログインしようとするとiOSからFace IDの認証が求められるので、それをクリアすればログインできます。

しかしながら似たようなログイン方式でありながら独自の方式というのが、現状多い印象を受けました。（サービス名は出しませんが大手の金融機関等）
ややこしいのは各社がそのログイン方式に独自の名前をつけていること、そしてその使い勝手に微妙な差異があることです。

パスキーの場合、手持ちのスマホに秘密鍵を作成し、PCからのログインの際にスマホの生体認証でログインするということも可能です。
PCのブラウザからサービスにログインする場合はPCに表示されるQRコードをスマホで読み取るとパスキー認証に移行できるような仕組みとなっています。

パスキーであればその操作感は統一されており、iOSであればカメラアプリでQRコードを読み取ればそのまま生体認証にスムーズに移行できます。

ただ独自方式の場合必ずしもそうではなく、某金融機関の「FIDO準拠方式」ではPCからのログイン時にQRコードを表示するところまでは同じですが、それを読み取るとその金融機関のアプリが立ち上がり、アプリ内で生体認証をして・・・と一手、二手操作が多くなっています。
似ているようで、微妙に違う操作感というのが僅かにストレスがありますし、分かりづらいと感じます。

一方で、パスキーであっても現時点ではどうもサービスによる微妙な仕様の違い、特に従来のパスワード周りの挙動が違うような印象があります。
パスキーを設定しても従来のパスワードでもログインできるサービスもあれば、必ずパスキーによる認証が必要なサービスもあるようで、このあたりは規格で決まっているわけではなくサービス側に委ねられている部分なのかもしれません。

## 今後に期待すること

今のところパスキー（と類似サービス）を導入して大きな問題は発生していません。
場合によっては少し手間が増えてしまうことは否めませんが、不正アクセスの話題を目にしない日が無いような昨今、新しい技術を取り入れた対策はもはや必須なのかなと思います。
今後もサービス側が対応されれば取り入れていくつもりです。

ただ、現状はやはり過渡期であるからなのか、サービスにより名称や操作感が異なるなど、混乱する部分がありました。
例えばあるサービスのヘルプページではパスキーを「生体認証とも呼ばれます」と説明していましたが、パスコードでも構わないことを思うと、正確な表現ではないと感じました。
もちろんサービス側もそれを分かったうえで、一般ユーザーに伝わりやすい説明をしているのでしょうが、やはり混乱する人もいるのではないかと思います。

慣れてしまえば顔認証や指紋認証でログインできるのは便利ですし、ログイン情報の管理も楽（iOSであれば自動的に端末とクラウドに鍵が保存される）ではあるのですが、やはり運用がこれまでのパスワードとは大きく異なるため、もっと仕様がシンプルに整理されていく必要があると感じています。

特に金融関連の重要なサービスは慣れていない人だとログイン自体に問題が発生することも十分考えられ、今後普及していく上での課題の1つになるかもしれません。
新人研修

　４月に入社してから早一週間がたちました。
本日は今私が受けている研修のことについて書こうと思います。
研修内容は、プログラミングの学習で、スライドを読んで知識をインプットして、実際に課題を解いていきコードの解説を講師にしてOKがもらえたら次の単元に進むという内容です。
　驚いたのはそのペースで、JavaScriptを三日でＤＯＭ操作まで理解したり、数日でSpringBootでCrud処理を行ったりなど、かなりのスピードで進めています。
　私は、事前に勉強していたので理解しながら進めれていますが、ほとんど触ってない人はきちんと頭に入っているのだろうかと思っています。
　プログラミングの学習はこのようなペースで進むのが普通なら、私はとても効率の悪い学習をしてたのだろうかと思いつつ、きちんと理解しながら進めれているのでいいかと思って楽しめています。
 　もし、研修時代のことなど覚えれいる方がいらしたら、どのような内容だったか教えてもらいたいです。
【Git】main以外の任意のブランチから新しいブランチを切る方法

## はじめに
developブランチからfeatureブランチを派生させたいときに意外と手間取ったので、備忘録を兼ねて記事にします。

## 方法1：`git checkout -b`コマンドを使用する方法
1\. 派生元になるブランチへ移動する
まずは、`checkout`コマンドで起点となるブランチに移動します。

```bash
git checkout {起点となるブランチ名}
```

2\. 新しいブランチを作成し、移動する
`checkout -b`コマンドを使用すると、起点となるブランチから新たなブランチを作成し、そのまま新たなブランチにチェックアウトします。

```bash
git checkout -b {新しいブランチ}
```

### 1行で書く方法
```bash
git checkout -b {新しいブランチ} {起点となるブランチ}
```
この方法だと、現在どのブランチにいるかに関わらず、派生ブランチの作成と移動が行えます。

## 方法2：`git branch`コマンドを使う方法
こちらの方法でも、現在どのブランチにいるかに関わらず、派生ブランチの作成と移動が行えます。
`checkout -b`を使う方法との違いは、こちらの場合はコマンドを実行しても、チェックアウトしているブランチは移動しない点です。

```bash
git branch {新しいブランチ} {起点となるブランチ}
```

## 補足
`feature`ブランチが存在する状態で`feature/hoge`ブランチを作成するなど、既存ブランチと同じ階層で同じ名前を含むブランチを作成する場合は、先に既存ブランチをリネームか削除しておかないと、`fatal: cannot lock ref～`というエラーが出ます。
Githubなど、リモートリポジトリにプッシュする際も同様の注意が必要です。
CP932とShift_JISの違いを徹底解説！

# CP932とShift_JISの違いを徹底解説！

## はじめに

日本語環境でよく目にする文字コード「Shift_JIS」と「CP932」。

「名前が違うだけで同じじゃないの？」と思っている方も多いかもしれません。

実はこの2つ、**よく似ているけれど決定的な違いがある**んです。

本記事では、実際の使用例や文字セットの違いを交えて、**Shift_JISとCP932の違いをわかりやすく解説**していきます！

---

## ざっくり結論

| 項目         | Shift_JIS        | CP932（Windows-31J） |
|--------------|------------------|------------------------|
| 標準規格     | JIS X 0208       | Microsoft独自拡張     |
| 互換性       | 古いシステムで使用 | Windowsで主に使用     |
| 追加文字     | なし             | NEC特殊文字、IBM拡張文字など多数（約360文字以上） |
| 実際の使用例 | ワープロソフト、レガシーなデバイス | Excel/メモ帳などWindows標準環境 |

→ **CP932はShift_JISの拡張版（上位互換）** だが、互換性に注意が必要！

---

## Shift_JISとは？

Shift_JIS（シフトJIS）は、1980年代に日本語を扱うために広く使われた文字コード。

- JIS X 0201（半角カナ）
- JIS X 0208（全角ひらがな・漢字）

これらを組み合わせて構成されており、2バイト文字と1バイト文字が混在する特徴を持っています。

### 特徴
- 日本語環境での黎明期に広く使われた
- ワープロ、FAX、組み込み機器などで活用
- 現代では非推奨（UTF-8が主流）

---

## CP932とは？

CP932は、MicrosoftがShift_JISをベースに拡張したWindows用の文字コードで、**Windows-31J**とも呼ばれます。

一般的にはCP932とWindows-31Jは同一とされますが、コードポイントの扱いや割り当てに微細な違いがあるとされる事例も存在します（例：U+005Cが円記号とバックスラッシュで見え方が異なるなど）。

### 特徴
- Shift_JISの全文字を含む（互換あり）
- さらに多くの記号や漢字、異体字、丸付き文字などを追加
- Windowsで「Shift_JIS」として指定しても、実際にはこのCP932で処理される

---

## 違いの具体例

### CP932にしか存在しない文字（一部）

| 文字 | 説明 |
|------|------|
| 髙   | はしご高（「高」の異体字） |
| 﨑   | たつさき（「崎」の異体字） |
| ①②③ | 丸付き数字 |
| 彅   | 草彅剛の「彅」など、JIS未収録漢字 |

これらの文字は、**Shift_JISでは未定義（表示・保存できない）**です。

---

## 落とし穴：Shift_JIS互換と見せかけて…

### Shift_JIS ⊂ CP932 であるが、逆は成り立たない！

CP932にはShift_JISにない文字が多数含まれているため（約360文字以上）、

- CP932で作成したファイル → Shift_JIS対応ソフトで開くと文字化けする可能性
- 特に `nkf`, `iconv`, POS端末など、Shift_JISベースで動作している環境では要注意

### 実際のトラブル例

- CP932で保存したファイルをレガシーシステムに渡したら「髙」が文字化けした

---

## まとめ

- Shift_JISはJIS規格に基づいた日本語文字コード
- CP932はその拡張版で、Windowsに最適化された仕様
- 両者は互換性があるようで、完全ではない（特に出力・保存・比較時）

> ✅ **Shift_JISを使っているつもりでも、実はCP932を使っているかも？**

ファイルを扱うときは、**明示的に文字コードを指定**する or **Unicode（UTF-8）へ移行**していくのが今後のベストプラクティスです。

---

## おまけ：確認コマンド例（Windows）

```powershell
# PowerShellでファイルの文字コード確認
Get-Content sample.txt
# エディタで保存時に"Shift_JIS"と書いてあっても、中身はCP932かも？
```
「9 - 3 ÷ ⅓ + 1」の答えが別れるらしいので白黒つけてみる

参考動画

https://www.youtube.com/shorts/0tFok9Dbv60

# 二つの答え

#### 答え1
　$9 - 3 \div ⅓ + 1$　→$\div ⅓$を$\times 3$にする→　$9 - 3 \times 3 + 1$

　よって、$1$。私はこれに賛成。

#### 答え2
　$9 - 3 \div ⅓ + 1$　→$⅓$を$1 \div 3$にする→　$9 - 3 \div 1 \div 3 + 1$

　よって、$9$。は？

# 解説
　答えは一つしかない、つまりは、**どちらかは間違っている**。
 
　ここで、答え2に注目しよう。何か変だ。

　最初の式は同じなので、変更を加えたところをみる。

　$3 \div ⅓$　→　$3 \div 1 \div 3$

　となっている。ここで、プログラムの話になるが、$3$と$⅓$はオペランド（この場合、分数は有理数を整数同士の除算で表現するため）に相当する。評価としては

　**3を⅓で割る**となる。つまりは、**3を1を3で割った値で割る**ということだ。

　しかし、**3を1で割って3で割る**となっているため、答え2の考え方は誤っている。つまりは、答え2は間違っている。

　そうすると、残るは答え1のみなので、答え1の答え$1$が正しい。
jqコマンドラインツールの誕生背景

## はじめに

APIレスポンス、構成ファイル、ログ…。
JSONは現代開発に欠かせないデータフォーマットです。

でも、CLIから扱うのが面倒くさいと感じたことはありませんか？

* `grep` や `awk` ではネスト構造に太刀打ちできない
* PythonやNode.jsでちょっとした抽出に毎回スクリプトを書くのもだるい

そんな問題を解決してくれるのが `jq`。
本記事では、なぜjqが生まれたのか？ 誕生背景を紹介します(^ ^)

## 目次

1. [JSONと既存ツールのギャップ](#-jsonと既存ツールのギャップ)
2. [jqとは何か？なぜ生まれたのか？](#-jqとは何かなぜ生まれたのか)
3. [設計思想：jqは「関数型JSONクエリエンジン」 ](#-設計思想jqは関数型jsonクエリエンジン)
4. [他ツールとの比較](#-他ツールとの比較)
5. [エコシステムの進化](#-エコシステムの進化)
6. [まとめ](#-まとめ)
7. [参考文献](#-参考文献)

## 🧷 JSONと既存ツールのギャップ
2010年代、JSONはXMLに代わる軽量なデータ形式として普及しました。
しかし、CLIの世界ではこんな課題が。

| ツール | JSON処理との相性 |
|-----------|-----------------|
| `grep` | 構造に非対応（ネスト不能）|
| `awk` / `sed` | テキスト前提、構文に弱い |
| Python/Node.js | 強力だが、ワンライナーには不向き |

💡 「軽く抽出・変換したいだけなのに面倒」というニーズに対し、決定打がなかった..


## 🧷 jqとは何か？なぜ生まれたのか？
`jq` は2012年、Stephen Dolan によって開発されました。
モチベーションは明確で、 **「sedのようにJSONを処理したい」** という欲求からです。

```bash
# APIレスポンスからアクティブなユーザーのメールだけ抽出
curl -s https://api.example.com/users | jq '.[] | select(.active) | .email'
```

* C言語製で高速・軽量
* 単一バイナリでどこでも動く
* パイプ構文で直感的に書ける
* ストリーム処理で大規模JSONにも対応

💡 jqはJSONの抽出・変換・整形がサクッとできる最強のCLIツールとして登場。
💡 その実用性が、CLI愛好家・SRE・データエンジニアたちに刺さり、一気に普及。

## 🧷 設計思想：jqは「関数型JSONクエリエンジン」 
`jq`の本質は **「関数型プログラミング × JSON処理」**。

特徴的な技術要素
* レキシカルスコープとクロージャ
* ポイントフリースタイル（関数合成）
* 全ての式は“値”として扱える
* --stream によるイベントストリーム処理

初期の実装はHaskellで行われ、Haskellの `lens` や `モナドバインド` に近い構文も見られます。

```bash
# 名前のリストをカンマ区切りで出力
jq -r '[.users[].name] | join(", ")' input.json
```
💡 「簡潔かつ表現力が高い」クエリ記述が可能です。

## 🧷 他ツールとの比較
| ツール | 特徴 |
|-----------|-----------------|
| `gron` | JSONをフラットな行に展開（diffしやすい） |
| `jid` | インタラクティブに探索できるTUI |
| `yq` | YAML版のjq（jqと同じ構文） |
| `JSON.sh` | BashフレンドリーにJSONをパース |

💡 `jq`は、構造理解・抽出・整形・変換 を一手に担える汎用ツール。

## 🧷 エコシステムの進化
* jq 1.5 で正規表現対応
* gojq：Go実装。軽量でWASM対応も進行中
* yq：YAML対応（内部的にjqをラップ）
* jaq：Rust実装。高速で並列処理志向

💡 いまや、`jq`は単なるツールではなくJSON処理のプラットフォーム。

## 🎉 まとめ
* jq はCLIでのJSON処理を根本から変えたツール
* sed/awkのように「手軽」で、関数型言語のように「強力」
* JSONが関わるあらゆる現場で使える汎用性あり

## 💫 参考文献 
* [公式ドキュメント](https://stedolan.github.io/jq/manual/)
* [jq play ブラウザでjqg試せる](https://jqplay.org/)
* [gojq](https://github.com/itchyny/gojq)
整数・非負・最小最大値制限を確認（シェルスクリプト）

こんにちは。
整数（非負）および最小最大値制限を確認するシェルスクリプトを書きました。

下記のように使う想定です。

```console
$ ./is_integer.sh $N $N_MIN $N_MAX || echo "error"
```

#### source code

```is_integer.sh
#!/bin/sh

is_integer_f_() {
  case "$1" in ''|*[!0-9]*) return 1; esac  # it isn't a non-negative integer
  return 0
}

n="$1"; min="$2"; max="$3"
is_integer_f_ "$n" || exit 1
is_integer_f_ "$min" && [ "$n" -lt "$min" ] && exit 1
is_integer_f_ "$max" && [ "$n" -gt "$max" ] && exit 1
exit 0
```
Nova_Observer β - Web脆弱性スキャナをPythonで構築

## はじめに

`Nova_Observer β` は、Webアプリケーションの診断・調査を自動化するPython製の脆弱性スキャナです。セキュリティ初心者でも簡単に使えるよう、コマンド一発で以下のような診断を実行できます。

- コマンドインジェクションの可能性をチェック
- 不正アクセス可能なファイル・パスを列挙（トラバーサル）
- ポートスキャンによるサービス調査
- Shodan APIを用いた脅威情報の収集
- Markdown形式で自動的にレポートを出力

簡易的なセキュリティチェックやCTF前のリコンツールとして活用できます。

---

## 機能概要

| 機能                   | 内容                                                         |
|------------------------|--------------------------------------------------------------|
| Payload Injection      | GET/POSTリクエストでペイロードを送信し、応答の中に脆弱性の兆候を検出         |
| Directory Traversal    | パス列挙用ワードリストを使い、アクセス可能な隠しファイルや設定を探索         |
| Port Scan              | TCPポート範囲を指定してスキャン。サービス名も自動判別                     |
| Shodan InternetDB連携 | ターゲットIPのCPE、ポート、脆弱性情報をShodanの無料API経由で取得            |
| Markdownレポート出力  | スキャン結果を`Report_Logs/`内に日時付きで保存。報告用途にも活用可能        |

---

## 使用方法

### コマンド例

```bash
python3 nova_observer.py -url https://example.com -m POST \
  -payw payloads.txt -traw paths.txt -ps 20 100 -t 6
```

### 基本コマンド

```bash
python3 nova_observer.py -url <ターゲットURL> [オプション]
```

---

## オプション一覧

| オプション   | 内容                                      |
|-------------|-------------------------------------------|
| `-url`      | スキャン対象のURL（必須）                         |
| `-p`        | 任意のポート番号（デフォルト: 80/443）               |
| `-m`        | HTTPメソッド（GETまたはPOST）                    |
| `-s`        | 有効とみなす追加のステータスコード（例: 403 500）       |
| `-payw`     | ペイロードワードリストファイル（コマンドインジェクション用） |
| `-traw`     | ディレクトリトラバーサル用ワードリストファイル           |
| `-cua`      | カスタムUser-Agentリスト                          |
| `-ps`       | ポートスキャン範囲（開始ポートと終了ポート）              |
| `-t`        | スレッド数（並列スキャンに使用。デフォルトは4）         |

---

## 出力ディレクトリ構成

```
Nova_Observer/
├── Payload_logs/        # ペイロードの応答ログ
├── Traversal_Logs/      # トラバーサル成功時のログ
├── Port_Scan_Logs/      # ポートスキャン結果
├── Err_Checked_logs/    # エラーログ（例外や失敗した通信など）
└── Report_Logs/         # Markdown形式の最終レポート
```

---

## Markdownレポート例（抜粋）

```
date : 2025_4-08_15-44
Scan_Targets : https://example.com

Used_Modules : Payload_Checkers / Multi_Traversal / Port_Scan / Shodan API
Method : POST

Payload_Detections:
- cat /etc/passwd
- ; ls -la /etc

Traversal Hits:
- [GET/200] ../../../../etc/passwd
- [GET/200] /.git/config

Open Ports:
- http/80
- ssh/22

Shodan:
- IP : 93.184.216.34
- Ports : [80, 443]
- Vulns : ['CVE-2021-41773']
```

---

## インストール方法

### 必要な依存パッケージをインストール

```bash
pip install -r requirements.txt
```

requirements.txt:
```
requests
```

---

## GitHub リンク

ソースコード・更新情報はこちら：
[https://github.com/Alecto-Fsociety/Nova_Observer-Beta](https://github.com/Alecto-Fsociety/Nova_Observer-Beta.git)

---

## さいごに

Nova_Observer はセキュリティ調査の第一歩として使える軽量スキャナです。
現状β版ではありますが、シンプルかつ直感的な操作性で、初学者から実務者まで役立てる設計にしています。

Pull Request / Issue / Fork 大歓迎です。
Next.js  15で「Next.js＋ヘッドレスCMSではじめる！ かんたんモダンWebサイト制作入門」を進めた場合のデプロイエラーの対処方法

## はじめに

chapter8で、さあいざVercelへデプロイだ！となったところでエラーが出てデプロイが失敗する場合の対処方法です。
そういえばNext.js 15で進めていたんだった！

## エラー内容

Vercelでは、以下のようなエラーが表示されデプロイが失敗します。

```
Type error: Type 'Props' does not satisfy the constraint 'PageProps'.
Types of property 'params' are incompatible.
Type '{ slug: string; }' is missing the following properties from type 'Promise<any>': then, catch, finally, [Symbol.toStringTag]
Next.js build worker exited with code: 1 and signal: null
Error: Command "npm run build" exited with 1
```

ターミナルでは、以下のようなエラーが続きます。

```
Error: Route "/news/[slug]" used `searchParams.dk`. `searchParams` should be awaited before using its properties
```

## 原因

Next.js 15からparamsやsearchParamsが非同期化されました。
そのため型定義（type Props）をPromise型に修正する必要があり、
また、paramsやsearchParamsはawaitを使って値を取得する必要があります。

## 対処方法

以下のように、該当するページのコードをすべて修正します。
- params, searchParamsをPromise型に修正
- params, searchParamsをawaitで取得する

例）
/src/app/news/[slug]/page.tsx

修正前
```javascript
type Props = {
  params: {
    slug: string;
  };
  searchParams: {
    dk?: string;
  };
};

export default async function Page({ params, searchParams }: Props) {
  const data = await getNewsDetail(params.slug, {
    draftKey: searchParams.dk,
  }).catch(notFound);

  return (
    <>
      <Article data={data} />
      <div className={styles.footer}>
        <ButtonLink href="/news">ニュース一覧へ</ButtonLink>
      </div>
    </>
  );
}
```

修正後
```javascript
type Props = {
  params: Promise<{
    slug: string;
  }>;
  searchParams: Promise<{
    dk?: string;
  }>;
};

export default async function Page({ params, searchParams }: Props) {
  const { slug } = await params;
  const { dk } = await searchParams;
  const data = await getNewsDetail(slug, {
    draftKey: dk,
  }).catch(notFound);

  return (
    <>
      <Article data={data} />
      <div className={styles.footer}>
        <ButtonLink href="/news">ニュース一覧へ</ButtonLink>
      </div>
    </>
  );
}
```

## 参照リンク
[Next.js 公式ドキュメント](https://nextjs.org/docs/messages/sync-dynamic-apis#why-this-warning-occurred)
WinMergeで文字化け!? 半角中点と文字コード誤判定の罠

# WinMergeで文字化け!? 半角中点と文字コード誤判定の罠

## はじめに

Shift_JIS（CP932）で保存されたはずのテキストファイルをWinMergeで比較しようとしたとき、

> 「エンコーディングエラーにより情報が失われています」

というエラーが表示され、文字化けが発生したことはありませんか？

今回のケースでは、その原因が **"半角中点"（0xA5）** によるものでした。この記事では、この現象の原因を追いながら、文字コードとツールの仕様の落とし穴について紹介します。

---

## 事象の概要

1. CP932で保存されたテキストファイルに、半角中点（0xA5）を含む
2. WinMergeでファイルを比較しようとしたところ、エンコーディングエラーが発生
3. 該当ファイルを編集し、半角中点を削除して再度読み込ませたところ、文字化けが解消

---

## 原因の正体

一見、CP932でも0xA5はちゃんと「半角中点」として定義されています。

| バイト列 | 文字 | 備考 |
|-----------|--------|--------|
| `0xA5`    | `･`   | 半角カタカナの中点 |

では、なぜエラーになるのか？

その答えは、**WinMergeの文字コード自動判定ロジックにあります**。

### キーポイント：`0xA5`の後続バイト

WinMergeは、ファイルのエンコーディングを自動判別する際に、バイト列のパターンを元にUTF-16などと誤認識することがあります。

例：A5 83


この2バイトが並ぶと、UTF-16BEで見たときは `0xA583` というコードポイントになります。

`0xA583` は Unicode の私用領域（PUA）に属しており、環境によっては表示できなかったり、不正扱いされたりします。

その結果、WinMergeは

- UTF-16BEとして解釈 → 不正なコードポイントと判断
- 「エンコーディングエラー」として処理を中断、または文字化け

という挙動をしていたわけです。

---

## 検証と再現性

実際に以下のような処理で再現できました：

1. 半角中点を含むCP932ファイルを作成（例：`A5 83`）
2. WinMerge（特定バージョン）で比較
3. エラー発生
4. 半角中点（0xA5）だけ削除 → 正常に比較可能に

つまり、**問題は半角中点そのものではなく、その後続バイトとの組み合わせによるUTF-16BE誤判定**が原因だったのです。

---

## 回避策

- ファイルの先頭にASCIIコメント等を追加し、誤判定を避ける
- 半角中点（`･`）を全角中点（`・`）に置き換える
- UTF-8（BOM付き）へ一時変換してから比較する
- 他の比較ツール（例：Beyond Compare、Meld）を使用する

---

## おわりに

文字コードの問題は、一見ただの文字化けに見えても、

- ツールの仕様
- 自動エンコーディング判定のアルゴリズム
- バイト列の偶然の並び

など、複雑な要因が絡んでいることが多いです。

今回のように、**一見普通の文字（中点）**が原因でツールが誤動作するケースもあるので、

> 「エンコーディングエラーが出たら、ファイルの中身（バイト列）を疑う」

という視点を持っておくと、トラブル対応が格段に楽になります。

この記事が、同じような問題で悩んでいる方の助けになれば幸いです！
分類モデルの域値設定と精度検証

分類モデルで閾値を0.5に設定するのは、多くの場合、**慣習的な初期設定**であり、必ずしも最適な値であるとは限りません。その背景にはいくつかの理由があります。

**閾値を0.5に設定する理由**

* **直感的な解釈:** 確率が0.5を超えれば「陽性」、下回れば「陰性」と判断するのは、二値分類において最もシンプルで直感的な解釈です。
* **デフォルト設定:** 多くの機械学習ライブラリやツールキットで、二値分類モデルのデフォルトの閾値として0.5が設定されているため、特に理由がない場合にそのまま使用されることが多いです。
* **バランスの取れた初期点:** 特にクラスの分布が均衡している場合、0.5は偽陽性（実際は陰性なのに陽性と予測）と偽陰性（実際は陽性なのに陰性と予測）のバランスが取れた初期点となる可能性があります。

**0.5以外の閾値を設定する場合の検討**

0.5以外の閾値を設定するのは、多くの場合、**ビジネス上の要件やデータ特性、そしてモデルの目的に応じて**より適切な判断を行うためです。検討を進める上では、以下の点を考慮する必要があります。

1. **ビジネス目標とコスト:**
   * **偽陽性のコストが高い場合:** 例えば、医療診断で実際は健康な人を病気と診断してしまう（偽陽性）ことによる精神的負担や追加検査のコストが高い場合、閾値を高く設定して偽陽性を減らすことを検討します。
   * **偽陰性のコストが高い場合:** 例えば、不正検知で実際は不正な取引を見逃してしまう（偽陰性）ことによる経済的損失が大きい場合、閾値を低く設定して偽陰性を減らすことを検討します。
   * **再現率（Recall）を重視する場合:** 全ての陽性事例をなるべく捉えたい場合（例：病気の早期発見）、閾値を低く設定します。
   * **適合率（Precision）を重視する場合:** 陽性と予測した事例の正しさ（信頼性）を高めたい場合（例：スパムメールフィルタリングで重要なメールを誤ってスパム判定しない）、閾値を高く設定します。

2. **クラス分布の偏り:**
   * **陽性クラスが非常に少ない場合:** 閾値を0.5に設定すると、ほとんどの事例が陰性と予測されてしまい、陽性事例を全く捉えられない可能性があります。この場合、閾値を低く設定することを検討します。
   * **陰性クラスが非常に少ない場合:** 逆に閾値を高く設定することを検討します。

3. **モデルの出力特性:**
   * モデルが出力する確率値の分布を確認します。確率が0.5付近に集中している場合、わずかな閾値の変更で予測結果が大きく変動する可能性があります。
   * ROC曲線（Receiver Operating Characteristic curve）やPrecision-Recall曲線などを分析し、異なる閾値における性能の変化を把握します。

4. **評価指標の最適化:**
   * 単に正解率だけでなく、適合率、再現率、F値（適合率と再現率の調和平均）、AUC（Area Under the ROC Curve）など、目的に合った評価指標を最適化する閾値を探します。

**閾値を0.01刻みで動かし、基本指標を追う精度検証方法**

閾値を0.01刻みで動かし、正解率、再現率、適合率などの基本指標を追う精度検証方法は、**一般的であり、非常に有効な手法**です。これは、**閾値を変えることによってモデルの性能がどのように変化するかを詳細に把握する**ために行われます。

このプロセスを通じて、以下のことが分かります。

* **最適な閾値の候補:** 目的とする評価指標（例えば、特定の再現率を達成しつつ、可能な限り高い適合率を得るなど）を最も満たす閾値を見つけることができます。
* **トレードオフの可視化:** 適合率と再現率の間にはトレードオフの関係があることが多く、閾値を動かすことでこの関係性を具体的に確認できます。
* **モデルの特性理解:** モデルがどのような場合に陽性と予測しやすいか、あるいは陰性と予測しやすいかの傾向を理解するのに役立ちます。

**具体的な検証手順の例:**

1. **データを学習用、検証用、テスト用に分割します。**
2. **学習用データでモデルを学習させます。**
3. **検証用データに対して、閾値を0.01刻み（またはより細かい刻み幅）で変化させながら予測を行います。**
4. **各閾値における正解率、適合率、再現率、F値などの評価指標を計算します。**
5. **これらの評価指標を閾値に対してプロットし、性能の変化を視覚的に確認します。**
6. **ビジネス目標やデータ特性に基づいて、最適な閾値を決定します。**
7. **最後に、テストデータを用いて決定した閾値でのモデルの最終的な性能を評価します。**

このように、閾値を細かく動かしながら評価指標を追跡する手法は、分類モデルの性能を深く理解し、より適切な運用につなげるために重要なステップと言えます。
Visual Studio Codeの個人的なおすすめ機能

仕事で多用していたテクニック（？）集。誰かの役に立てればと思い記事にしました。

はじめてのアウトプット記事ですので、誤字脱字は大目に見てもらえたらと...

## VSCodeのマルチカーソル機能で編集効率アップ！  
プログラミングや文章編集、さっと行えるコマンドの一括作成時に活躍する便利テクニックを紹介

### はじめに  
Visual Studio Code（以下、VSCode）は多機能で軽量なエディターとして、多くの開発者に愛用されています。


中でも「マルチカーソル機能」は、知っているかどうかで編集効率が大きく変わる強力な機能の一つです。本記事では、VSCodeのマルチカーソル機能の使い方や活用例を紹介します。

---

### マルチカーソル機能とは？  
マルチカーソル機能を使うと、**複数の位置に同時にカーソルを配置して同時編集**が可能になります。これにより、同じ構文や文字列を複数行にわたって一括で修正したり、同様の入力作業を効率化することができます。

---

### 基本の操作方法

#### 1. `Alt + クリック`（Windows/Linux）または `Option + クリック`（Mac）  
任意の位置に複数のカーソルを追加。

#### 2. `Ctrl + Alt + ↑ / ↓`（Windows/Linux）または `Option + Cmd + ↑ / ↓`（Mac）  
**上下にカーソルを追加**して、複数行にわたって同時編集が可能。

#### 3. `Ctrl + D`（Windows/Linux）または `Cmd + D`（Mac）  
選択している単語と同じ次の単語を選択して、マルチカーソルで編集。

#### 4. `Ctrl + Shift + L`（Windows/Linux）または `Cmd + Shift + L`（Mac）  
**選択している文字列と一致するすべての単語を一括選択**して編集。

---

### 活用例

#### 1. 複数の変数名の一括変更  
```js
let item1 = 'A';
let item2 = 'B';
let item3 = 'C';
```
→「item」をまとめて「product」に変更。

- 変更前

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261493/c527f278-3d60-4ce6-b2c3-2e262083d134.png)

- 変更後

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261493/0a9de8c4-d613-44b9-85dd-7153f67ed223.png)

#### 2. CSVやテキストの整形  
複数行のデータに同じ接頭辞や接尾辞を追加したいときなどに便利。

#### 3. テンプレートやHTMLの一括編集  
同じタグやクラス名の一括編集が瞬時にでき、ミスも減らせます。

---

### より便利に使うためのTips

- **マルチカーソルのキャンセル**：`Esc`キー
- **矩形選択（ボックス選択）**：`Alt + Shift + ドラッグ`（Windows）または `Option + Shift + ドラッグ`（Mac）
- **ショートカットのカスタマイズ**：`keybindings.json` で自分好みに設定可能

筆者は`Ctrl + Shift + c s`で愛用しています。

---

### おわりに  
マルチカーソル機能は、一度覚えると手放せない機能です。ちょっとした修正から大規模な置換まで、作業の効率を格段に向上させてくれます。ぜひ日々の作業に取り入れて一つ一つ直していく地獄から脱却してくれればと思います。

なお、正規表現でやれば？と思う方はそちらでも構いません。筆者は考えるのがめんどくさくて、、こちらのほうが好みです。

### 注意

マルチカーソルモードで複数行を範囲選択していく際、行数が多い少ないにかかわらず、下ボタンキーで範囲選択をしていくともっさりとした感じで動作が鈍くなっていくので、下記の手順でマルチカーソルモードにすれば軽めの動作で済みます。

1. マルチカーソルモードOFFの状態にしたまま範囲選択
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261493/d6e3688f-d05d-4de8-b065-c7a1bfd292ee.png)
1. マルチカーソルモードをONにする
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261493/25d93535-dd19-4f2b-95f1-d2968134051e.png)
vuejs/core に css nesting した scoped style にて :deep() を使うと 無効なスタイルが生成される問題について報告した話


vuejs に scoped style というものがあります。

https://ja.vuejs.org/api/sfc-css-features

それは コンポーネント内に 一意の属性を付けて周りスタイルをそこに閉じ込めるものです。

具体的には 

```vue
<style scoped>
.hoge {
    color:red;
}
</style>
```

と書くことで

```vue
<style>
[identity].hoge {
    color: red;
}
</style>
```

の様な変換がされます。
ただ、上記 の変換ルールに不備があります。
具体的には css nesting と `:deep()` (`::v-deep()`) を併用した時に問題となります。

https://developer.mozilla.org/ja/docs/Web/CSS/CSS_nesting/Using_CSS_nesting

https://ja.vuejs.org/api/sfc-css-features#deep-selectors

```vue
<style scoped>
.hoge {
    :deep(.fuga) {
        color:red;
    }
}
</style>
```

これだと下記の様なスタイルが生成されます。

```vue
<style>
.hoge {
    [identity] .fuga {
        color: red;
    }
}
</style>
```

つまり、`.hoge .fuga` の意が `.hoge [identity] .fuga` になってしまい セレクタが壊れてしまうということです。
この不具合がある状態で正しいセレクターを生成させるにはこう書く必要があります。

```vue
<style scoped>
.hoge {
    &  :deep(.fuga) {
        color:red;
    }
}
</style>
```

これだと下記の様な生成になります。

```vue
<style>
.hoge {
    &[identity] .fuga {
        color: red;
    }
}
</style>
```

つまりこれなら `.hoge &[identity] .fuga` となり 最終的な解釈は `.hoge[identity] .fuga` となりますので想定されたスタイルとなります。

でそれを vuejs/core にて issues で 報告したのが下記となります。

[CSS nesting and `:deep()` in scoped styles not working · Issue #13159 · vuejs/core](https://github.com/vuejs/core/issues/13159)

やはり play.vuejs.org が 状態をURLに保存する構造をしているので共有が楽でよいですね。

これの対応の pull request は下記となります。

[fix(compiler-sfc): auto add nesting selector for nesting ::v-deep by edison1105 · Pull Request #13163 · vuejs/core]
(https://github.com/vuejs/core/pull/13163)

以上。
WindowsでHyper-Vを使用して、Linux環境を構築する

## 1. `Hyper-V マネージャー`を起動する
![{C17D6A02-9C18-447F-BCA3-72BAACA7BE42}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686561/e404f723-3cac-433b-86f6-2c32c32cea55.png)

## 2. 仮想スイッチマネージャーをクリックする
![{6EF8F066-143A-418B-B6B3-256807AA8155}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686561/eb6eed5b-832b-4667-bded-a76c759cd356.png)

## 3. 外部/内部それぞれ選んで、仮想スイッチの作成を押下
- 外部
    インターネットに接続できる
- 内部
    ホストOSと接続できる
- プライベート
    仮想マシン同士でしか接続できない
![{BB8435EC-FFE4-4EA1-926E-661EB9295608}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686561/5321ab71-5772-4dc1-87f7-ef21064ea610.png)

## 4. 名前を入力して、適用 > OKを押下
![{BFA47FE3-2FC3-4341-8E69-45B57B03BB3B}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686561/26b229a1-ef79-47a9-865c-4a13ea27c49c.png)

## 5. 右側の操作から新規 > 仮想マシンをクリック
![{9D5E3B02-354B-468A-BF02-B5BD2171EA94}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686561/c55df566-9d69-4aca-a0bc-ad3e9cd4750a.png)

## 6. 名前を入力して、次へ
![{F5C5E986-3423-484D-A4FF-7BFCC90A3200}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686561/07a5f334-d10d-45b5-88d9-c44216e59ac8.png)

## 7. 起動メモリに2048MB(2GB)を指定する
今回は、LinuxディストリビューションにDebianを使用するためこのサイズで指定します。

![{F399024B-4DE0-4656-9690-7CBBDAD84BD0}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686561/42d8c30e-427b-466b-8a98-8f0157f16f54.png)

## 8. 先ほど指定したネットワークスイッチを指定します
![{9076C14C-85B9-4B50-873A-885354804859}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686561/0be08b21-ce78-4523-853f-283893067f63.png)

## 9. 仮想ハードディスクは20GBを指定します
![{391FA8D7-ADD9-4CEF-85A2-AAB865F719C1}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686561/271613ee-1197-4710-9efb-8a4785cb0ebc.png)

## 10. 対象のイメージファイルを指定して、完了
![{479A8146-75FA-4FB6-951B-F0A7FA72AFE2}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686561/bceb71b1-bfe0-47c1-9a66-7106c0c064fc.png)

## 11. セキュアブートを有効にするのチェックを外す
![{B782B827-6F6D-44EB-A0EE-8E9D3CB2E239}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686561/cbc156d9-fd6a-4957-8368-1aa0b97cb974.png)

## 12. 仮想マシンを起動して、接続
![{D0CC0A2A-1F85-4C9F-A5F9-23A3FD552F40}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686561/bee0b6b1-e392-4cf6-9544-657f180d10f9.png)

## まとめ
次回は、linuxでwebサーバーを立てるにチャレンジします。
【遠隔可能】ペアプログラミングを簡単に実施する方法（VSCode）

※この記事は[KANGEN](https://kangen-holdings.co.jp/)の梅ぼしとにらめっこがお送りします。
※この記事は、5分程度で読めます。

## :hatching_chick:はじめに
今回は **VSCodeで、ペアプログラミングを行う方法をご連携します！**
梅干しとにらめっこも、フルリモートで仕事しているので遠隔の方と一緒に勉強／タスクの解決等に使用していきたいなと思っております。

## 準備物
①VSCode
②インターネット
③[GitHub](https://github.co.jp/)のアカウント（持ってない方へ：アカウントは無料で作成できます）
④（音声は届かないので）できれば、相手と会話できるツール（LINE通話、ハドル、Teamsなんでも可）

## **手順(共有する側の方）**
#### ①VSCodeを開く

#### ②拡張機能「Live Share」をインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3089043/452c0051-3152-4c55-a3db-af077ad207d8.png)

#### ③インストールが完了すると、VSCodeの左側にアイコンができますのでクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3089043/e084398a-32df-4eb4-9fd3-a1bd0941fa10.png)

#### ④（共有する側）オプションを選択
A.**Share（Read/Write）** 　⇒共有された人も編集が可能 
B.**Share（Read Only）** 　⇒共有された人は閲覧のみ可能
C.**Join**　※共有された人用なので、後で説明します

#### ⑤今回は「Share（Read/Write）」を選択しました。
上の検索窓にGitHubアカウントを使用するか、Microsoftアカウントを使用するか表示されます。
※任意の方を選択してください（自身はGitHubアカウントを使用します。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3089043/bbffae83-f0a8-4596-afc2-1e391863ebf4.png)

#### ⑥GitHubを選択した場合、ログイン画面＋VSCodeでアカウントを使用しても良いかの確認画面が出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3089043/b24a8ec7-746b-476e-a308-8abecdbb96ba.png)

OKな場合は、以下を押下してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3089043/fdeca396-659a-41de-ac56-59bdda09e7bb.png)

#### ⑦共有リンクがクリップボードに登録されますので、リンクを共有したい方へCtrl＋Vで貼りつけて教えます。


## **手順（ここからは共有される側の方）**

#### ①VSCodeを開く

#### ②拡張機能「Live Share」をインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3089043/452c0051-3152-4c55-a3db-af077ad207d8.png)

#### ③インストールが完了すると、VSCodeの左側にアイコンができますのでクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3089043/e084398a-32df-4eb4-9fd3-a1bd0941fa10.png)

#### ④「Join」を選択します。
#### ⑤VSCodeの検索窓に、共有してもらったリンクを貼りつけ、Enterを押します。

#### ⑥共有者のソースコードを閲覧（設定によっては編集も）できるようになります！
 

:::note info
作業中の相手の位置は、マーカーのように光って表示されます。
**誤って相手の修正を消さないようにだけ気をつけましょう。**
:::

## 終わりに:hatching_chick:
本日は、遠隔でペアプログラミングを行う方法をご紹介しました。

素敵なITライフをお過ごしください！

以上、**梅干しとにらめっこ** でした！
Firebase認証エラーメッセージ表示の問題解決

# エラーメッセージの不具合

# Firebase認証エラーメッセージ表示の問題解決まとめ

## エラーのに対して

1.　`firebaseauth`を使用して、`auth.ts`では元の`Firebase`エラーを捕捉し、新しい`Error`オブジェクトを生成していたことについて理解ができていなかったことが原因である。
2.　`auth.ts`で`throw new Error("メッセージ")`と書いた場合、そのメッセージが`error.message`となり新しい`Error`オブジェクトを生成していた。これについて理解ができていなくて、`CreateAccount`コンポーネントでは元の`Firebase`エラーコードを期待していたため、予想していたエラーメッセージを受け取ることができなかった。

## エラーの原因

問題の根本は**エラーオブジェクトの取り扱いの不整合**でした：

1. **二重のエラーハンドリング構造**:
    - `auth.ts`では元のFirebaseエラーを捕捉し、新しいErrorオブジェクトを生成
    - `CreateAccount`コンポーネントでは元のFirebaseエラーコードを期待していた
2. **プロパティの喪失**:
    - 標準の`new Error()`では`message`プロパティだけが設定され、元の`code`プロパティが失われた
    - 結果として、コンポーネント側の`error.code`による条件分岐が機能しなかった

## エラーメッセージの出所

画面に表示されるエラーメッセージには2つの可能性がありました：

1. **auth.tsのカスタムエラーメッセージ**:
    ```tsx
    typescript
    コピー
    if (error.code === 'auth/email-already-in-use') {
      throw new Error("このメールアドレスは既に使用されています。別のメールアドレスを使用するか、ログインしてください。");
    }
    
    ```

    
2. **コンポーネント側で設定したメッセージ**:
    ```tsx
    typescript
    コピー
    if (error.code === 'auth/email-already-in-use') {
      setError('このメールアドレスは既に使用されています。別のメールアドレスを使用するか、ログインしてください。')
    }
    
    ```
    

修正前は条件分岐の問題でコンポーネント側のメッセージが表示されず、修正後はいずれかが適切に表示されるようになりました。

## 解決策

コンポーネント側のエラーハンドリングを改善：

```tsx
typescript
コピー
catch (error: any) {
  // エラーメッセージがある場合はそれを使用
  if (error.message) {
    setError(error.message)
  }
  // FirebaseのエラーコードがあればFirebaseエラーとして処理
  else if (error.code) {
    if (error.code === 'auth/email-already-in-use') {
      setError('このメールアドレスは既に使用されています。別のメールアドレスを使用するか、ログインしてください。')
    }
    // その他のエラーコード処理...
  }
  // それ以外のエラー
  else {
    setError('アカウント作成に失敗しました。入力内容を確認してください。')
  }
}

```

## `error.message`を優先使用する理由

条件`if (error.message)`が重要な理由：

1. JavaScriptのErrorオブジェクトには必ず`message`プロパティがある
2. `auth.ts`で`throw new Error("メッセージ")`と書いた場合、そのメッセージが`error.message`として取得できる
3. このプロパティをチェックすることで、カスタムエラーメッセージを優先的に表示できる

## 実際の動作フロー

1. `auth.ts`でFirebaseエラーを捕捉し、カスタムエラーを投げる
2. コンポーネントのcatchブロックでそのエラーを捕捉
3. `if (error.message)`条件が`true`となり、カスタムエラーメッセージが表示される
4. もし元のFirebaseエラーだった場合は`error.code`で条件分岐する

## 学んだこと

1. **エラーオブジェクトの構造理解**が重要
2. **複数の条件によるエラー検出**で堅牢性が向上
3. **標準とカスタムエラーの統一的処理**が効果的
4. **優先順位を明確にした条件分岐**でユーザーに適切なフィードバックを提供
爆速でChrome拡張機能を作る

Google Chromeの拡張機能を作り方の概要です。

「とりあえず作ってとりあえず動かしてみる」を目的としているので、詳細を知りたい方は[Chrome Developers](https://developer.chrome.com/docs/extensions?hl=ja) のページをご覧ください。

Chromeの拡張機能はHTML、CSS、JavaScriptで作ります。

## フォルダ構成

フォルダ構成は下記になります。

sample/
┝manifest.json
┝index.html
┝index.js
┝index.css

## manifest.json

manifest.jsonには拡張機能の名前や概要、バージョンなどを記述します。
このファイルがないとChromeの拡張機能に追加できません。

```json-doc
{
    "name": "Sample", // 拡張機能の名前
    "description": "Sample Extension. Show alert!", // 拡張機能の概要
    "version": "1.0.0", // 拡張機能のバージョン
    "manifest_version": 3, // マニフェストのバージョン。2020年11月9日以降に新規作成する場合は「3」にする(2021年11月28日時点)
    "action": {
        "default_popup":"index.html" // デフォルトで表示されるHTML
    }
}
```

manifest.jsonのその他の項目については[こちら](https://developer.chrome.com/docs/extensions/reference/manifest?hl=ja)をご覧ください。

## index.html

Chromeの拡張機能のアイコンをクリックしたときに表示されるHTMLで、JavaScriptとCSSを読み込んでいます。
ファイル名はmanifest.jsonの「default_popup」と同じ必要があります。

このhtmlに直接JavaScriptを記述すると拡張機能をChromeで読み込んだ際にエラーとなるので記述しないようにしてください。

```index.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" href="./index.css">
    </head>
    <body>
        <div class="wrapper">
            <button class='.botton' onclick="sampleClick()">クリック！</button>
        </div>
        <script src="./index.js"></script>
    </body>
</html>
```

## index.js

index.htmlで読み込んでいるJSです。
今回は「クリック！」ボタンが押されたらアラートを表示するだけです。
htmlでjQueryを読み込めばjQueryも記述できます。

```index.js
document.getElementById('sampleButton').onclick = function sampleButtonClick() {
    alert(12345);
}
```

## index.css

```index.css
.wrapper {
    text-align: center;
    width: 100px;
}
```

## Chromeで拡張機能を動かす

Chromeで拡張機能を動かす方法です。
Chromeで右上の3点リーダ > その他のツール > 拡張機能と進み拡張機能の画面を開きます。
画面右上の「デベロッパーモード」がオフの場合はオンにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382613/43bf4a30-4f3f-45c2-82a4-1e1c741dddb0.png)

画面左上の「パッケージ化されていない拡張機能を読み込む」から、「manifest.json」が存在するディレクトリ(今回の場合は「sample」)を読み込みます。
エラーがなければ以下のように表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382613/9f152150-a7bb-404a-9670-7cb29dfac53e.png)

このままだと拡張機能のアイコンが表示されていないのでChrome右上の拡張機能のマーク(パズルのピースみたいなマーク)をクリックし、拡張機能をタスクバーにピン留めします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382613/f35d57a6-813f-4dff-8b36-9acb5e88b235.png)

拡張機能のアイコン（今回の場合は「S」と書かれているマーク）をクリックすると下記のようなウィンドウが表示され、「クリック！」ボタンをクリックするとアラートが表示されました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382613/b8087a2a-829a-4757-bdfa-36a485ee7b2f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382613/f7c61e2a-d7a3-4d9d-a30b-bc12cfea4210.png)
【Unity】コンパイルの成功・失敗を画像で通知させる機能

# はじめに
個人的にUnityでやっておいたほうがいい設定があります。
それは**再生中にソースを更新しても停止するまではコンパイルしないようにすること**です。
Preferencesで設定できます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820411/2b7dae54-1a50-4221-831e-b382a26f2f5a.png" width=70%>

# EditorCompileNotification
**コンパイルの成功や失敗を指定の画像で通知してもらいたい！** という自己満機能です。
好きなキャラを表示させてモチベ上げたいですよねわかります！

## 機能
・コンパイル成功時に指定の画像を表示
・コンパイル失敗時に指定の画像を表示する
・コンパイル時間をログで表示する

画像の指定はソース（EditorCompileNotification.cs）側で改変可能（以下デフォルト）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820411/09f8d91b-1e3b-4784-b02f-43dffefe5bbd.png)

## サンプル
### 停止時にソースを更新してコンパイル
| コンパイル成功  | コンパイル失敗 |
| ------------- | ------------- |
|![Demo1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820411/2907e2fb-4830-4877-abfc-da05228c4eb0.gif)| ![Demo2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820411/e87c7718-0b67-43f0-9431-de3020161f9b.gif)|
### 再生時にソースを更新して停止した際のコンパイル
| コンパイル成功  | コンパイル失敗 |
| ------------- | ------------- |
| ![Demo3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820411/9001f928-7e2b-4b00-9eb2-79216c8692dd.gif)| ![Demo4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820411/bc54f546-f43e-444c-8923-b61518b5c277.gif)|

## GitHubで公開
https://github.com/Isshi-777/EditorCompileNotification

## 備考
・最初に書いた**コンパイルタイミングの設定**をした時のみしか動作確認してません。
・会社のプロジェクトなどでの導入は**控えるべき**ですし、確実に却下されると思います。
・１人でニヤニヤしながら開発したい際に使用するのがよいと思っています。