OmniAICreator/Qiita-1.07M huggingface dataset:
【Rails初学者】Railsのenumってstringとintegerどっち使えばいいの？通知モデルで迷った話

# enum設計で迷った話：string型 or integer型、どちらがいいのか。

こんにちは。
Railsを学習中の者です。
私が「通知モデル」を設計する際に`enum`の型で迷った経緯と、調べてわかったことを備忘録としてまとめます。
通知機能の設計でこの問題に直面したので、**実際の実装・調査・判断の流れ**をまとめてみました。

## そもそもenumってどういう仕組みなのか

Railsの`enum`は、モデル上でシンボルを定義することで、DBには数値や文字列を保存しつつ、コード上では人間が読みやすい形で扱える便利な機能です。


## 背景として通知の「種類」をenumで管理したいと思った

通知モデルに「通知の種類（kind）」という属性を追加しようとしたとき、以下のようなenumを使いたくなりました。

```ruby
enum kind: { reminder: "reminder", warning: "warning" }
```
このとき悩んだのが、マイグレーションで kind カラムを string にするか、integer にするかという点です。

## 最初string型にしていた

私自身、もともと `integer型` を使うつもりはありませんでした。
- 文字列のまま保存したほうが意味が直感的にわかる。
- enumを使い慣れていない初心者として扱いやすかった。
という初学者なりの理由から`string型 + enum`という構成を自然と選んでいました。

## 今回の実装（string型）
モデル
```ruby
class Notification < ApplicationRecord
  belongs_to :user

  enum kind: {
    reminder: "reminder",
    warning: "warning"
  }

  validates :user_id, presence: true
  validates :kind, presence: true, inclusion: { in: kinds.keys }
  validates :active, inclusion: { in: [true, false] }
end
```
マイグレーション
```ruby
class CreateNotifications < ActiveRecord::Migration[8.0]
  def change
    create_table :notifications do |t|
      t.references :user, null: false, foreign_key: true
      t.string :kind, null: false
      t.boolean :active, default: true, null: false  # 通知はデフォルトONで作成される

      t.timestamps
    end
  end
end
```

## string型かinteger型かで迷った点
通知の種類（kind）をenumで管理する際、以下の2パターンが存在します。
 ## ①integer型を使う場合
```ruby
# モデル（Rails 7以降の新構文）
enum :kind, [:reminder, :warning]

# マイグレーション
t.integer :kind
```
- 保存される値は 0（reminder）や 1（warning）
- Rails 7以降の enum :kind, [:a, :b] 構文はこの形式が前提
- DB上では数字だけなので、内容を理解するにはコードを確認する必要あり

 ## ② string型を使う場合（今回採用）
 ```ruby
 # モデル
enum kind: {
  reminder: "reminder",
  warning: "warning"
}

# マイグレーション
t.string :kind
```
- `reminder`や`warning`といった文字列がそのままデータベースに保存されるため、内容を直接見て意味を理解しやすいという利点
- 一方で、`enum`で定義していない値が保存されるのを防ぐために、
`inclusion: { in: kinds.keys }`のようなバリデーションを追加しておくといいらしい

## 最終的な判断：string型で採用
| 観点 | 理由 |
|------|------|
| 可読性 | DBを見たときに意味がすぐわかる（"reminder" など） |
| 開発・運用のしやすさ | SQLやログで確認する場面でも直感的 |
| 初学者としての安心感 | enum定義と保存値が一致していて混乱が少ない |
| パフォーマンス | 差はほぼ気にしなくてOK（今回のスケールでは問題にならない） |

## 学んだこと
- Railsでは`enum`に`string`も`integer`も使えるが、新構文（配列形式)は`integer`前提のようです
- `string`型を使う場合は、旧来のハッシュ形式`（{ name: "name" }`を使う
- 可読性や運用面も含めて、状況に応じて設計判断することが大切


初学者として悩んだ末の選択でしたが、「なぜこの設計にしたのか」を言語化する経験がとても勉強になりました。
色々と書きましたが、間違えていましたら、申し訳ありません

## 参考

[Railsガイド - Active Record Enum（公式）](https://railsguides.jp/active_record_querying.html)
[Railsのenumをstringで使う方法](https://qiita.com/Qiita/items/c686397e4a0f4f11683d)
[Railsのenumを使いこなす方法](https://techracho.bpsinc.jp/hachi8833/2022_02_18/115735)
[VEChat] SOM2.0 でフェイスミラー以外の選択肢を作る

## ⭐️目的

- フェイスミラー以外の選択肢がほしくて

### ☂️公式

https://docs.google.com/document/d/1wSGMh6i_HiaNhW3uUnvSWAJh3cINA8dsDvEsjmjCbHI/edit?tab=t.0

https://childwitch.booth.pm/items/5911762

## ⭐️インストール

https://booth.pm/ja/items/5911762

- フォルダからファイルをクリック

::: note info
旧バージョンもダウンロードする必要がある. そこにあるファイルを新しい方に入れる
:::

## ⭐️使い方

### ☂️導入

![スクリーンショット 2025-05-02 4.17.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/a602659a-b17d-45b8-82ba-6f7985217516.png)

- ここにあるSOMをヒエラルキーに移動

![スクリーンショット 2025-05-02 4.20.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/36c54a77-9b2c-4d83-b986-174e8cd23c57.png)

- これで使えるようになる

### ☂️初期設定で最初から出すようにする

![スクリーンショット 2025-05-02 4.29.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/8f589107-4826-41de-94dc-042e97aebc4f.png)

- このファイルをクリックする

![スクリーンショット 2025-05-02 4.31.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/9332dfa0-1944-48e7-8c83-d0913f23ad3c.png)


- 設定画面が出てくるので一番上の行のDefaultにチェックを入れる
競プロ日記#25/05/01

# アルゴ式-[かたよったくじ (1)](https://algo-method.com/tasks/795)
- 絶対誤差の出力をそのうちしっかり理解せねばと思っている
```
int main() {
    int N;
    cin >> N;
    int sum = 0;
    for (int i = 0; i < N; i++) {
        int a;
        cin >> a;
        sum += a;
    }
    // 絶対誤差10-6以下の精度で出力する
    cout << fixed << setprecision(15) << (double)sum / N << endl;
}
```

# アルゴ式-[かたよったくじ (2)](https://algo-method.com/tasks/796)
```
int main() {
    int M;
    cin >> M;
    int sum = 0;
    int countSum = 0;
    for (int i = 0; i < M; i++) {
        int A,c;
        cin >> A >> c;
        sum += A * c;
        countSum += c;
    }

    cout << fixed << setprecision(15) << (double)sum / countSum << endl;
}
```
[VRChat] なでなでExを使えるようにする

## ⭐️目的

頭や頬を撫でると表情が切り替わるアバターギミックを使えるようにする

## ⭐️参考

https://ravii.booth.pm/items/5068109

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

### ☂️公式

https://ravii.booth.pm/items/5068109

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


## ⭐️インストール

https://ravii.booth.pm/items/5068109

- 購入してファイルをクリック


## ⭐️使い方

![スクリーンショット 2025-05-02 3.48.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/04dffbe3-089f-4b5b-bef1-426c7f0f290a.png)

- assetsの中の画像の部分を選択する

![スクリーンショット 2025-05-02 3.48.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/e0d451f2-cf71-45f4-b8c8-ba2093c7104e.png)

- これをヒエラルキーに入れる

> Modular avatarを導入した後に
nadeEx/Avatars/各アバター名のフォルダに入っているNadenadeEx variantをアバター内に置いて下さい。
それだけです！
NadenadeExを出来るだけ下側に配置して下さい。

サイトからの引用
[VRChat] 可愛い座りツールを使えるようにする

## ⭐️目的

座り方や寝転び方にアレンジを加える

## ⭐️参考

https://qiita.com/YukiLulu0229/items/a5783334146c371db525

https://yunisaki.booth.pm/items/3611536

### ☂️公式

https://yunisaki.booth.pm/items/3611536



## ⭐️インストール

https://yunisaki.booth.pm/items/3611536

![スクリーンショット 2025-05-02 3.18.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/1b726487-d9cb-4d46-865f-a9977ea28bfa.png)


- 購入してファイルをクリック


## ⭐️使い方

![スクリーンショット 2025-05-02 3.26.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/dec77669-e6e0-460c-8969-8a9e69196875.png)

- 本体選択してこの画面の部分をクリック

![スクリーンショット 2025-05-02 3.26.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/91e4869b-2153-4488-9e33-71509af7107a.png)

- 初期設定を開始する

![スクリーンショット 2025-05-02 3.27.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/288cb472-5b1e-427b-a4bf-abb91bc8d5e8.png)

- 追加されてる
[VRChat] アバターの軽量化(AAOの基本以外の部分)

## ⭐️目的

アバターを軽量化して読み込みやすくする


### ⭐️lilAvatarUtils

## ☂️できること

- ポリゴンの数や容量などの重さなどがわかる

### ☂️インストール

lilAvatarUtils

- liltoonと同時ダウンロードされている

![スクリーンショット 2025-05-02 3.14.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/2b42603d-9e48-4d95-9fe8-f76c8db71dcb.png)

### ☂️方法

![スクリーンショット 2025-05-02 3.15.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/fdd3d18d-24bb-44a1-8797-79334962c60a.png)


- ツールから選択する

### ⭐️TexTransTool 

::: note warn
アイテクスチャーがこれで調子悪くなったかもだから今はやめとく
:::

https://ttt.rs64.net/

## ☂️できること

- アトラス化でテクスチャーメモリを削減する
- VRAMの使用料削減

### ☂️インストール

https://ttt.rs64.net/docs/Tutorial/ReductionTextureMemoryByAtlasing

![スクリーンショット 2025-05-01 23.59.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/8cfb7909-3918-4da3-a955-335a811649ec.png)

### ☂️方法

![スクリーンショット 2025-05-01 23.56.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/b790274f-c302-406a-babf-5666d4eb9f77.png)

- 本体を選択してここを押す

![スクリーンショット 2025-05-02 0.01.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/4aa2aa0b-e734-401a-95b0-e2a333fd55ee.png)

- このオブジェクトが生成される

![スクリーンショット 2025-05-02 0.02.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/63565536-19b5-46d9-bd9f-ec25a487bdf6.png)

- アクセサリーや衣類にチェックを入れる


### ⭐️lilNDMFMeshSimplifier

https://github.com/lilxyzw/lilNDMFMeshSimplifier?tab=readme-ov-file

## ☂️できること

- ポリゴンの削減

### ☂️インストール

https://github.com/lilxyzw/lilNDMFMeshSimplifier?tab=readme-ov-file

- liltoonと同時ダウンロードされている

![スクリーンショット 2025-05-02 3.06.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/783416c0-fbb5-46cc-9bd2-f7e715cfa6d1.png)

### ☂️方法

![スクリーンショット 2025-05-02 3.10.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610706/9cd702c8-2d82-412a-8795-f53707ab6b66.png)

- 削減したいオブジェクトにコンポネントを追加して倍率を下げる
最近読んで良かった技術書をお勧めしたい

今年の４月で社会人３年目になるエンジニアです。
この２年間で４０冊前後の技術書を読んできました。
（もちろん軽くなぞっただけの本も頭数に含まれています）

せっかくなので特に勉強になった本を紹介します。
新人エンジニアの参考になれば嬉しいです。

# １．ソフトウェアアーキテクチャの基礎 ―エンジニアリングに基づく体系的アプローチ
https://amzn.asia/d/6geEQTm

各論的な技術の解説書ではなく、アーキテクチャという巨視的観点について記された書籍です。
いち開発者から、より高い視座を持ったアーキテクトに進化させてくれるでしょう。
単なる作業要員ではなく、プロダクトの技術的方向性や開発プロセスの選定といった意思決定を根拠を持って行えるようになるため、組織内でのプレゼンス向上につながると思います。

# ２．AWS認定ソリューションアーキテクト-プロフェッショナル ~試験特性から導き出した演習問題と詳細解説
https://www.amazon.co.jp/AWS%E8%AA%8D%E5%AE%9A%E3%82%BD%E3%83%AA%E3%83%A5%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%88-%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB-%E8%A9%A6%E9%A8%93%E7%89%B9%E6%80%A7%E3%81%8B%E3%82%89%E5%B0%8E%E3%81%8D%E5%87%BA%E3%81%97%E3%81%9F%E6%BC%94%E7%BF%92%E5%95%8F%E9%A1%8C%E3%81%A8%E8%A9%B3%E7%B4%B0%E8%A7%A3%E8%AA%AC-%E5%B9%B3%E5%B1%B1-%E6%AF%85/dp/4865942483

AWS認定の最上位「SAP」の参考書です。
SAPの日本語書籍はこの他にもう一冊あったかと思いますが、私はこの本をお勧めします。
その理由は、「試験ガイド（AWSが提供する試験要綱）に非常に忠実であるから」です。
（書籍の構成自体が、試験ガイドの構成をなぞったものになっています）

公式の試験要綱を分析し、学習することは全ての資格試験の基礎です。
試験要綱という地図を持たずして、合格というゴールにたどり着くことは至難の業なのです。

この本はそういった試験への向き合い方を非常に「分かっている」本であり、今後一生役に立つ「資格試験の取り組み方」も学ぶことができる優れた参考書です。

# ３．Kaggleで勝つデータ分析の技術
https://amzn.asia/d/9hOYulV

世界最大のデータ分析コンペ「Kaggle」の入門書です。
データ分析の流れ、一般的な分析手法、Tipsやテクニックなどが網羅的に記されています。
そのためKagglerだけでなく、データ分析に興味のある全ての方にお勧めです。

また書籍の構成が整然としており、初めてデータ分析を学ぶ人でもとても分かりやすく記載されています。
まずデータ分析の全体像を示し、その後に具体的な方法論を説明しています。
このような「抽象→具体」は、新しい知識をキャッチアップする際にも有効でしょう。
新しい技術の概要や全体像を学び、その後に具体的な仕様の理解を深めるという学習プロセスについても改めて意識しながら読んでみてください。
AWS SAA合格体験記

# AWS SAAとは
Amazon Web Services（AWS）が提供するクラウド資格の一つで、主にAWS上でのシステム設計・構築に関する知識とスキルを問う中級（アソシエイト）レベルの認定試験

# なぜ受験しようと思ったか
* AWSのハンズオンをしていて、ある程度知識がついたと感じたため
* 何か資格を取得しておきたいと思ったため

# 学習期間および時間
期間：2025年2月〜3月の1ヶ月間（短期集中）

平日：2時間

休日：5時間

# 使用教材
ping-tの「AWS SAA 最強WEB問題集」のみ

# 工夫したこと・意識したこと
1. 問題集の「AWSクラウドの基本」や「主要なサービス」、「コンピューティング」などを一通り間違えなくなってから「試験レベル」の問題に取り組んだ

2. 「試験レベル」の問題はAWS Well-Architected Frameworkに沿って作成されており、繰り返し解いた（計10周ほど）

3. 4周目くらいで問題を見ただけで答えが思い浮かぶようになったが、気にせず進めた

4. 5周目以降は、正解の選択肢以外がなぜ不正解なのか、解説をよく読むようにした

# 受験方法
* 試験センター

# 結果
788点（合格基準：720点）

# 感想
* ping-tのみで合格できたが、知らないサービスも出てきたため、他の教材も使うとより安心かもしれない

* 試験センターのパソコンで表示される文字が読みづらかった

* 当日鼻水がひどく、あまり集中できなかった（体調管理は大事）
猿でもわかるAIの倫理・リスクシリーズ 🐵⚠️AIと子供：教育現場での課題



# 🐵⚠️AIと子供：教育現場での課題【猿でもわかるAIの倫理・リスクシリーズ #5】

## 🧩 はじめに：AIが子どもたちに教える時代がやってきた

近年、ChatGPTやAI教材などの登場により、教育現場でのAI活用が加速しています。自動採点、個別最適化学習、AI先生――これらは教育の質を飛躍的に高める可能性を秘めています。

しかし、**「本当にAIに子どもを任せて大丈夫か？」**という問いは、技術者として避けては通れません。本記事では、現場での活用例からリスク、実装の工夫まで、技術者の視点から深掘りしていきます。

---

## 🔍 テクノロジー概要：教育分野で活用されるAIとは？

教育現場で使われるAIは大きく分けて以下のタイプに分類できます：

| 種類 | 用途 | 代表技術 |
|------|------|----------|
| 教材推薦AI | 学習進捗に応じた問題出題 | レコメンドエンジン |
| 自動添削AI | 作文・記述式問題の採点 | 自然言語処理（NLP） |
| 対話型AIチューター | 質疑応答型学習サポート | LLM（大規模言語モデル） |
| 学習分析AI | 成績や傾向の可視化 | 機械学習＋統計分析 |

その中でも注目されているのが、**GPTベースのAIチューター**です。

---

## 💻 実装例：ChatGPT APIを使った「AI先生」のプロトタイプ

以下は、OpenAIのChatGPT APIを使った簡単な**算数チューター**の例です。

```python
import openai

openai.api_key = "YOUR_API_KEY"

def ask_ai_tutor(question: str):
    response = openai.ChatCompletion.create(
        model="gpt-4",
        messages=[
            {"role": "system", "content": "あなたは小学生向けの優しい算数の先生です。"},
            {"role": "user", "content": question}
        ]
    )
    return response['choices'][0]['message']['content']

# 例: 子どもが質問
print(ask_ai_tutor("かけ算ってどういうこと？"))
```

このプロトタイプは、子どもが疑問を持ったときに、AIがやさしく説明してくれるチューターとして機能します。

---

## 🛠️ 現場での工夫・注意点・よくある失敗

### ✅ 現場で役立つTips

| 工夫 | 内容 |
|------|------|
| 年齢別プロンプト最適化 | 小学1年と中学3年では言葉選びを変える |
| 事前フィルター処理 | AIに渡す入力をフィルターして不適切ワード除去 |
| ログ保存・レビュー機能 | AIの返答を教師が後から確認できるようにする |

### ⚠️ よくある失敗パターン

1. **倫理的に不適切な返答**  
   → 対策：プロンプトでロール設定＋出力監視フィルター  
2. **学習指導要領とズレる内容**  
   → 対策：公式教材を元にファインチューニング  
3. **子どもがAI依存になる**  
   → 対策：AIは補助、主体は教師・家庭という設計思想

---

## 🔄 発展的な応用：カリキュラム全体との連携

より実践的な応用としては、**LMS（学習管理システム）とAIの連携**があります。

例えば、以下のような構成です：

```
[生徒の学習履歴] → [分析AI] → [苦手分野の特定] → [GPTチューターによる個別解説] → [教師にフィードバック]
```

このようにすることで、「AIが教えて、教師が導く」理想的な連携が可能になります。

---

## 🔚 まとめ：AI教育の未来をどうつくるか？

### ✅ メリット
- 学習の個別最適化
- 反復学習の自動化
- 教師の負担軽減

### ❌ デメリット・リスク
- 倫理的制御の難しさ
- 教育方針との不一致
- 子どものAI依存・人格形成への影響

### 🔮 今後の展望
- 文科省ガイドラインに準拠したAI設計
- 透明性の高い出力ログと教師レビュー連携
- 保護者との連携によるトライアングル教育支援

---

## 🎓最後に

AIは強力な教育支援ツールですが、「便利」だけでなく「責任」を伴います。だからこそ、我々エンジニアが**倫理的に安全で、現場に根ざしたAI教育システム**を実装する責任があるのです。

子どもたちの未来のために、AIを「道具」として、正しく設計していきましょう。

---

🖼️ *図や用語解説（例）を挿入する場所（Qiita/Zennでの投稿時）：*

1. 教育AIの分類マップ
2. GPTによる回答例比較（良い例・悪い例）
3. 年齢別プロンプト例（図解）
4. LMS＋AIの連携図
5. 不適切発言検出フロー図
6. 子どもの反応例グラフ（AI対教師）
7. 倫理リスク評価マトリクス
猿でもわかるAIの倫理・リスクシリーズ 🐵⚠️ AIと人間の境界線は曖昧になるか？



## 🧩 1. はじめに：AIと人間の違いはどこにある？

近年のAI技術の進展により、私たちは「AIは人間に近づいているのか？」という問いを避けられなくなっています。生成AI、音声アシスタント、自律エージェント……その振る舞いはどんどん人間的になり、「これは人？AI？」と見分けがつかなくなる場面も珍しくありません。

本記事では、**AIと人間の境界線が曖昧になる現象**に焦点を当て、その技術的・倫理的リスクと、現場でどう向き合うべきかを、コード・実例付きで解説します。

---

## 📚 2. AIの“人間らしさ”を生む仕組みとは？

人間らしさを感じる要素には、主に次の3点があります：

- **自然言語処理の進化**：GPTやClaudeなどのLLMにより、文脈を理解した会話が可能に。
- **音声・表情生成**：TTS（Text-to-Speech）＋音声合成＋表情生成で、会話ロボットのリアルさが増加。
- **行動予測・意思決定**：強化学習や模倣学習により、人間のように環境に適応して意思決定する。

### ✅ 例：OpenAIのChatGPT APIを使って人格を持つチャットボットを構築
```python
import openai

openai.api_key = "YOUR_API_KEY"

response = openai.ChatCompletion.create(
  model="gpt-4",
  messages=[
    {"role": "system", "content": "あなたは親切で共感的な心理カウンセラーです。"},
    {"role": "user", "content": "最近、仕事のストレスがすごくて…"}
  ]
)

print(response['choices'][0]['message']['content'])
```

このように**"人格"のプロンプト設計**次第で、まるで人間のように応答するAIが簡単に作れてしまいます。

---

## 🔧 3. 実践：企業向けAIチャットボットの倫理的設計ポイント

あなたが企業で顧客対応AIチャットボットを開発しているとしましょう。以下のポイントを考慮しなければ、"人間のような振る舞い"はかえってリスクになりえます。

### ☠️ 倫理的リスク例：
- 顧客がAIを「人間の担当」と誤解し、重要な相談をAIにしてしまう
- AIの応答が一見共感的だが、実際は誤情報を含んでいる

### 🧠 対策コード例：人格開示の自動挿入
```python
def inject_identity(message):
    intro = "※この応答はAIによるものであり、医療・法律の助言には対応していません。"
    return intro + "\n\n" + message

ai_response = get_ai_response(user_input)
print(inject_identity(ai_response))
```

### 🪛 設計TIPS：
- プロンプトに「AIであることを毎回明示」と指示を加える
- UI上にAIアシスタントの役割や制限を常に表示
- 会話ログにAI応答の信頼スコアを付加（例：temperatureの値）

---

## ⚠️ 4. よくある落とし穴と現場TIPS

### ❌ よくある失敗
- 開発段階でAIの応答に感心しすぎて、検証・テストが甘くなる
- 法務チェックを後回しにしてリリース
- ユーザーとの境界線が曖昧なUI/UX設計

### 💡 現場の工夫
- ユーザーテスト時に「AIと気づいたか」のアンケートを実施
- モデルの応答ログを週次レビューし、リスクワードを抽出
- 開発者チームに倫理レビュー担当を置く（"倫理のPull Request"）

---

## 🚀 5. 応用編：AIと人間が協調する設計へ

曖昧な境界を「危険」とみなすだけでなく、**協調的AI設計**というアプローチもあります。

### 例：人間の判断をサポートするAI設計
- 医療：医師の判断を補強する診断補助AI
- 教育：教師のフィードバックを補足する自習支援AI
- コールセンター：担当者の横にAIがリアルタイム提案

これらはすべて、「AI ≠ 人間」であることを前提にしつつ、**役割の補完関係**を築いています。

---

## 🧭 6. まとめ：AIと人間の共存に向けて

| 項目 | 内容 |
|------|------|
| ✅ メリット | 共感的なUX、人手不足の補完、対話の自動化 |
| ⚠️ デメリット | 境界の曖昧化、誤認リスク、過信リスク |

未来のAI社会において、境界線はますます曖昧になるでしょう。しかし、それを**曖昧に設計してよい**わけではありません。むしろ、「どこを曖昧にしてよいか／いけないか」を見極める設計力こそが、これからのAIエンジニアに求められる実践知なのです。

---

本記事が、現場でAIを設計・運用するエンジニアの皆さんにとって、「すぐ試したくなる」知見となれば幸いです 🛠️💡
JavaScript学習ログ　ダブルクリックの禁止処理

## ダブルクリック禁止の処理
業務でダブルクリックを禁止する処理が必要となり、自分なりに調べたうえで、練習として実装を行いました。

練習では要素の取得をタグ名で行っていますが、実際の案件では対象の要素が多くなりすぎるため、クラス名で取得するように変更する予定です。

また、今回の案件はスマートフォン端末がメインとなるため、挙動を安定させる目的でdblclickイベントではなく、1回目のクリックから1秒間は2回目のクリックを受け付けない処理を採用しました。

```html
  <a href="https://example.com">アンカー</a>
  <form action="https://example.com">
    <button type="submit">ボタン</button>
  </form>
```

```css
    .disabled {
      pointer-events: none;
    }
```

```js

    document.addEventListener('DOMContentLoaded', function () {
      const btnAnchors = document.querySelectorAll('a');
      const btnButtons = document.querySelectorAll('button');

      let isClicked = false; // クリック未実行と定義

      // リンクのクリックイベント
      btnAnchors.forEach((btnAnchor) => {
        btnAnchor.addEventListener('click', function (event) {
          if (isClicked) {
            event.preventDefault(); // デフォルトの挙動を阻止→リンク無効化
            return; // これ以上処理を行わない
          }

          isClicked = true; // クリック時のデフォルトの挙動を行う
          btnAnchor.classList.add('disabled'); // 2回目のクリック禁止

          // 1秒後に再度クリックできるように
          setTimeout(() => {
            isClicked = false;
            btnButton.classList.remove('disabled'); // 無効化解除
          }, 1000);
        });
      });

      // ボタンのクリックイベント
      btnButtons.forEach((btnButton) => {
        btnButton.addEventListener('click', function (event) {
          if (isClicked) {
            event.preventDefault(); // デフォルトの挙動を阻止→リンク無効化
            return; // これ以上処理を行わない
          }

          isClicked = true; // クリック時のデフォルトの挙動を行う
          btnButton.disabled = true; // ボタンを無効化（disabled属性）

          // 1秒後に再度クリックできるように
          setTimeout(() => {
            isClicked = false;
            btnButton.disabled = false; // ボタンの無効化解除
          }, 1000);
        });
      });
    });
```

aタグの場合は.disabledクラスを付与し、buttonタグの場合はdisabled属性を設定することで、2回目のクリックを防止しています。

現在はその違いによって処理を分けていますが、共通部分を関数にまとめて引数で制御すれば、記述量を減らせるのではないかと考えました。

ただし今回は、まだそのような実装を行うだけの理解が十分ではないため、チャットGPTに相談しつつコードの簡略化を試みようと思っています。



## ❗最初に詰まった部分
- loadイベントを設定していなかったため、要素の取得に失敗していました。

- 実装練習時にボタンが複数存在していたため、意図した要素すべてに対して処理が適用されず、aタグやbuttonタグのクリック禁止処理が1つの要素にしか反映されていませんでした。背景の色を赤く変えることで確認していたのですが、1つしか反応しませんでした。

## 今回新しく出会ったメソッド
- Event: preventDefault() メソッド
ブラウザがそのイベントに対して行う「デフォルトの動作」をキャンセルする。

https://developer.mozilla.org/ja/docs/Web/API/Event/preventDefault

- Window: setTimeout() メソッド
指定した時間（ミリ秒）経ったあとに、1回だけ関数を実行する。

https://developer.mozilla.org/ja/docs/Web/API/Window/setTimeout
猿でもわかるAIの倫理・リスクシリーズ 🐵⚠️ AI兵器の倫理的リスクとは？



### 1. はじめに 〜なぜ今「AI兵器の倫理」を語るのか？

近年、AI技術の発展により、「自律型兵器（Lethal Autonomous Weapon Systems：LAWS）」の実現可能性が現実のものとなりつつあります。これらは人間の判断を介さず、AIがターゲットを識別し攻撃する能力を持ちます。

私たちエンジニアは「それは軍事の話でしょ？」と無関係に思いがちですが、実際にはAIモデルの精度・データバイアス・意思決定の透明性といった倫理課題は、私たちの日常的なシステム開発にも深く関わっています。

本記事では、「AI兵器の倫理的リスク」を切り口に、技術者の立場から具体例やコードを交えてこの問題を掘り下げ、実務にも活かせる知見を提供します。

---

### 2. AI兵器とは何か？概要と技術構成

#### ▶️ 定義と分類

| 種類 | 内容 |
|------|------|
| 半自律型兵器 | 人間が指示、AIが実行（例：ドローン爆撃） |
| 完全自律型兵器 | 人間の介入なしにAIがターゲット選定・攻撃 |
| 群知能型兵器 | 多数のAIユニットが群れとして自律行動 |

#### ▶️ 技術スタックの例

- 物体検出：YOLOv5 / Detectron2
- 追跡アルゴリズム：Deep SORT
- 経路計画：A* / D* Lite / Reinforcement Learning
- 決定アルゴリズム：Rule-based + Neural Network

---

### 3. リスク例：物体検出の「誤認識」問題を体験する

#### 💥 実装例：YOLOv5によるターゲット誤認識のシミュレーション

```python
import torch
from PIL import Image
from matplotlib import pyplot as plt

# YOLOv5モデルをロード
model = torch.hub.load('ultralytics/yolov5', 'yolov5s')

# 対象画像（例えば一般人が写る写真）
img = Image.open('civilian.jpg')
results = model(img)

# 結果の可視化
results.print()
results.show()
```

#### 🧪 結果と考察
画像に含まれる一般人が「武器を持った人物」と誤検出された場合、AI兵器にとっては「合法なターゲット」として扱われる可能性があります。

こうした誤検出が“命に関わる”という現実は、私たちが普段扱うAIでも決して他人事ではありません。

---

### 4. 実務で使える知見と注意点

#### ✅ 現場で応用可能な教訓
- **AIの判断は常に確率的**：誤検出はゼロにできない。必ず人間のレビュー工程を残すべし。
- **学習データのバイアス除去**：軍事系プロジェクトに限らず、医療や採用領域でも重要。
- **Explainable AIの導入**：ブラックボックスなモデルは倫理的説明責任を果たせない。

#### ❌ よくある失敗
- 精度99%のモデルを「完璧」と勘違い
- テストケースが現実のユースケースに偏りすぎ
- 責任主体を明確にしていない

---

### 5. さらに深掘り：AI倫理をコードレベルでどう担保するか？

#### 🔐 応用編：Fairnessチェックの自動化（例：`fairlearn`の導入）

```python
from fairlearn.metrics import demographic_parity_difference
from sklearn.metrics import accuracy_score

# 予測結果と属性情報を利用
dpd = demographic_parity_difference(y_true, y_pred, sensitive_features=gender_list)
print(f"Demographic parity difference: {dpd}")
```

- **用途**：兵器だけでなく、ローン審査や就職マッチングのAIでも利用可能。
- **利点**：差別的判断を数値で検出できる。

---

### 6. まとめ：私たちエンジニアにできること

#### 🟢 メリット
- 精度の向上で誤射の減少
- 負傷リスクを低減する「非人間戦闘」の可能性

#### 🔴 デメリット・リスク
- 誤認識による無辜の犠牲者
- 国際法の未整備による責任の曖昧さ

#### 🚀 今後の展望
- Explainable AIと倫理設計の融合
- 「AI設計倫理士」など新しい職種の登場

---

> ⚠️ **倫理的な判断をコードだけに委ねてはいけない。エンジニア自身の意識が最終防衛線である。**

---

### 📌 補足図解一覧（希望があれば画像も作成します）：
1. AI兵器の構成図
2. 誤認識例のビフォーアフター
3. Explainable AIのフロー
4. フェアネスチェックの仕組み
5. 人間とAIの意思決定比較
6. 誤検出による結果の分岐図
7. AI兵器の技術系譜ツリー

---

このような記事で問題ないでしょうか？必要であれば、図の作成やコード補足も可能です。どの部分を詳しく掘り下げたいですか？
猿でもわかるAIの倫理・リスクシリーズ 🐵⚠️ 自律型AIは制御できるのか？


## 自律型AIは制御できるのか？実装から見た現実と課題

### 🧩 1. はじめに：自律型AIの"制御不能問題"とは

近年、ChatGPTやAuto-GPTのような"自律型AI（エージェンティックAI）"が注目されています。こうしたAIは単なるツールではなく、目標を与えると自ら行動計画を立て、外部環境とやり取りしながらタスクを遂行します。

この進化は驚異的ですが、同時に次のような疑問が浮かびます：
- 「本当に制御できるのか？」
- 「勝手に行動したらどうするのか？」

本記事では、こうした倫理的・技術的リスクを、**実装の現場視点から**解き明かします。具体的なコードや設計例を通じて、現場のエンジニアにとってのリアルな知見を共有します。

---

### 🧠 2. 自律型AIとは？概要と誤解を解く

自律型AI（Autonomous AI, Agentic AI）とは、以下の3点がポイントです：
1. **目的駆動型（Goal-Driven）**
2. **環境とのインタラクション（Perception-Action Loop）**
3. **継続的な学習・最適化**

🔍 よくある誤解：
- ✅ ×「自律型AIは意識を持っている」 → ❌ それは幻想。
- ✅ ×「1回の指示で完璧な判断ができる」 → ❌ 試行錯誤と制御が必要。

---

### 🔧 3. 実例：LangChain + OpenAI APIで構築する自律型エージェント

以下は、LangChainベースで簡単なエージェントを実装した例です。
```python
from langchain.agents import initialize_agent, Tool
from langchain.llms import OpenAI
from langchain.utilities import SerpAPIWrapper

llm = OpenAI(temperature=0)
search = SerpAPIWrapper()
tools = [
    Tool(
        name="Search",
        func=search.run,
        description="最新情報を検索するためのツール"
    )
]

agent = initialize_agent(
    tools, llm, agent="zero-shot-react-description", verbose=True
)

agent.run("明日の東京の天気を調べて")
```
🧪 **ポイント：** ツールを組み合わせ、動的に行動するエージェントの骨格。

---

### 🛠️ 4. 実践の知恵：制御の工夫とよくある落とし穴

#### ✅ 制御のための実践的Tips
- **プロンプト設計：** 明確な制約と目標を書く
- **ツール制限：** 許可された操作のみ実行可能に
- **ログ出力とモニタリング：** 全実行ステップを記録

#### ⚠️ よくある失敗例
- "agent.run()" でAPIが暴走 → 対策：**timeoutやretryの設定**
- 情報検索エージェントが誤情報を採用 → **信頼性スコア導入**

---

### 🚀 5. 発展例：人間の介在によるハイブリッド制御

以下のような構成で、制御性と柔軟性を両立できます：
- ⛑️ 人間の承認ステップを挿入（例：ActionConfirmation）
- 🧭 意図のチェック機能（例："is_this_action_reasonable" モジュール）

```python
def is_this_action_reasonable(action):
    # ユースケースに応じたルールやブラックリストチェック
    return "削除" not in action.lower()
```

このような関所を設けることで、完全な自動化にブレーキをかけることができます。

---

### 📌 6. まとめ：制御可能性の限界と今後の展望

#### ✅ メリット
- 複雑なタスクを自動化できる
- 人的リソースを削減できる

#### ❌ デメリット・課題
- 行動予測の困難さ
- セキュリティや悪用リスク
- 倫理判断のブラックボックス化

#### 🔮 展望
- "責任あるAI（Responsible AI）"設計の必要性
- 説明可能性（XAI）とトレース性の重視

---

### 📚 用語解説
- **自律型AI：** 自分で目標を追求し行動を選択するAI。
- **LangChain：** エージェント型アーキテクチャの構築フレームワーク。
- **ツール呼び出し：** LLMが外部ツール（API等）を使って処理を進める仕組み。

---

このシリーズでは次回、"AI兵器の倫理的リスクとは？"を予定しています。

ぜひフォローして、実践知を深めていきましょう 💪✨
猿でもわかるAIの倫理・リスクシリーズ 🐵⚠️AIによる社会的不平等の拡大リスク


## AIによる社会的不平等の拡大リスクをどう防ぐ？

### 1. はじめに：AIが加速する“不平等”とは？

近年、AI技術の急速な進化により、企業や組織の業務効率は飛躍的に向上しています。しかし、その一方で、アルゴリズムによる意思決定が新たな“社会的不平等”を引き起こすリスクが浮き彫りになっています。例えば、採用システムでのバイアス、ローン審査での差別的判断、自動化による雇用格差などが現実に起きています。

このような問題を、単なる倫理問題としてではなく「エンジニアが実装段階で向き合うべき技術課題」として扱うことが、本記事の目的です。

---

### 2. AI倫理の基礎と不平等が生まれる構造

#### 🔍 なぜAIは“不公平”になるのか？
- **バイアスのある学習データ**：過去の差別的な傾向がそのままAIに学習されてしまう。
- **特徴量の選定ミス**：性別や人種に強く相関する特徴を安易に使用。
- **最適化目的のズレ**：例えば "精度" のみを最適化してしまうと公平性が損なわれることも。

#### 🧠 用語解説：Fairness（公平性）とは？
- **Demographic Parity**：予測結果に人種や性別などの偏りがない状態
- **Equal Opportunity**：本来対象となるべき人に平等にポジティブな判断がされる

---

### 3. 実例：バイアスのある採用AIをどのように修正するか

#### 🏢 ケース：採用推薦モデルの構築
```python
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report

# データの読み込み
candidates = pd.read_csv("candidates.csv")

# 問題点：性別が結果に強く影響してしまっている
X = candidates.drop(columns=["hired", "gender"])
y = candidates["hired"]

model = LogisticRegression()
model.fit(X, y)
print(classification_report(y, model.predict(X)))
```

#### ✅ 対策1：Fairlearnでバイアスを可視化・軽減
```python
from fairlearn.metrics import MetricFrame, selection_rate
from fairlearn.reductions import ExponentiatedGradient, DemographicParity

# Demographic Parityの強制
constraint = DemographicParity()
mitigator = ExponentiatedGradient(LogisticRegression(), constraint)
mitigator.fit(X, y, sensitive_features=candidates["gender"])

print(MetricFrame(metrics=selection_rate,
                  y_true=y,
                  y_pred=mitigator.predict(X),
                  sensitive_features=candidates["gender"]))
```

📌 **解説図1**：Demographic Parityによる修正前後の比較チャート

---

### 4. 現場で役立つTipsと陥りがちな落とし穴

#### 💡 Tips
- データ収集段階からバイアス検出を意識する
- KPIは「精度+公平性」の両方を設計する
- モデル監査のためのダッシュボード導入を検討する（例：What-If Tool）

#### ⚠️ よくある失敗
- 「性別・人種などを除けば公平」と誤解する
- テストデータでも不均衡があると意味がない
- ビジネス要求（売上等）と公平性要件のバランスを無視する

---

### 5. 応用編：Fairness-aware MLOpsの実践

本番環境で公平性を維持し続けるためには、MLOpsのプロセスに以下を組み込む必要があります：

- **定期的な再学習とバイアス評価**
- **ドリフト検出 + フェアネスモニタリング**
- **CI/CDパイプライン内にバイアスチェックステップを追加**

📌 **解説図2**：Fairness-awareなMLOpsパイプライン構成図

---

### 6. まとめ：AIの公平性はエンジニアの責任でもある

AIによる社会的不平等のリスクは、決して他人事ではなく、日々コードを書く私たちエンジニアの設計・実装の選択にかかっています。精度だけを追求するのではなく、社会に与える影響も視野に入れた開発が求められています。

#### ✅ 本記事のまとめ
- バイアスはデータ・モデル両方から生まれる
- Fairlearnなどのライブラリで可視化と修正が可能
- 実装段階から公平性を設計に組み込むことが重要
SeaArt小技メモ：NSFWワードで弾かれる時の対処法

最近、SeaArtでチャットキャラクターを編集している際に**「NSFW」「女性」などの単語が使えない**という現象に遭遇しました。

実はこれ、**スマホアプリ版特有の仕様**のようです。

---

### ■ 結論

**SeaArtのスマホアプリでは、NSFWや性別表記（女性・男性）などが自動的に弾かれる**仕様があります。

しかし、**PCまたはスマホのブラウザ版から編集すれば、問題なく設定可能**です。

---

### スクショで比較！

**● スマホアプリで設定 → エラー**  
![Screenshot_2025-05-01-16-26-20-90_a0e26d757392a1b1efd05b077e48a69c.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4035371/76abdc31-e178-4955-b98d-8dd9eda949c9.jpeg)
![Screenshot_2025-05-01-16-26-49-41_a0e26d757392a1b1efd05b077e48a69c.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4035371/03834bc8-aff4-4a65-99c2-dd70bd435101.jpeg)
**不適切なワードですとエラーになりました。** 

**● Webブラウザから設定 → 成功！**  
（スクリーンショット）
![Screenshot_2025-05-01-16-31-57-76_40deb401b9ffe8e1df2f1cc5ba480b12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4035371/b7629c37-3a1a-4794-87fa-bc16ac53e4ae.jpeg)
![Screenshot_2025-05-01-16-32-46-11_40deb401b9ffe8e1df2f1cc5ba480b12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4035371/a6b724f6-3ac8-4b07-bea4-3804f934e296.jpeg)　
**エラーは発生せず無事に変更されてチャット画面に戻りました。** 

---

### ■ 対策まとめ

- キャラ説明にNSFW系ワードを入れる時は「Web版から」アクセス  
- スマホでも**ChromeやSafariでSeaArtを開けばOK！**  
- アプリでは投稿前に保存内容が消えることもあるので要注意！
[seaartのweb page](https://www.seaart.ai/ja)

---

### ■ 補足

SeaArtのアプリ側では、Google Play や Apple App Store のガイドライン対策として、より厳しいフィルターが設けられていると考えられます。

---

ちなみに私が  seaart  で作成しているチャットキャラクターへはこちらからアクセスできます。

https://www.seaart.ai/ja/aiChat/c8858c050a72d4ac9d73434807597fda

https://www.seaart.ai/ja/aiChat/d009thde878c73e5dgv0?s_id=a119f1441b95d3d5a0b1de8214bf37f7

https://www.seaart.ai/ja/aiChat/d06avkte878c739tfieg?s_id=e6111a2b9d3bede9373a74e29f8595e6
JavaScriptの仕様を活用した難読化ツールを作った話

JavaScriptの仕様を活用した難読化ツールを作りました。
Webフロントエンドを想定しています。本体はこちらです。

https://gist.github.com/TNTSuperMan/4d50716403f3d2df0bc3156fe942e332

## そのJavaScriptの仕様とは？
それは、「関数の巻き上げ」です。

https://developer.mozilla.org/ja/docs/Glossary/Hoisting

巻き上げというのは総称で正式名称ではないのですが、このような機能があります。
この機能についてはこう書かれています。
> JavaScript の巻き上げ (Hoisting) は、インタープリターがコードの実行前に、関数、変数、クラス、インポートの宣言をそのスコープの先頭に移動するように見えるプロセスを指します。

これをわかりやすく言うと、実行時に宣言が全て上に行くということです。

## それを用いてどう難読化するのか？
実行時に宣言が全て上に行くということは、スコープ内の関数宣言はスコープ内のどこに書いてもいいということです。

ということで、関数宣言位置をランダムにすることで難読化します。

## なぜ難読になるのか？
JavaScriptプログラムは、最小化されていてもある程度の傾向が読めます。
例えばWebフレームワークではスクリプトの最後に、DOMにマウントするコードがあるなど。
Vueであれば`kl(ql).mount("#app")`という構文から
`createApp(App).mount("#app")`という構文が見えるはずです。
それらを関数として包んでどこかコードの果てに飛ばせば、解析も多少は困難になるはずです。

## その程度で難読になるのか？
Webフロントエンドにおいて、"解析できない"というのは無いです。
見られる前提で作るべきなんです。

今回作ったのは、一発見て「あ、これVueだ」とならないようにするだけの難読化です。

そして、[これ](https://obfuscator.io/)のような本格的な難読化は、最終的なコード量が超肥大化してしまい、速度も犠牲になってしまいます。
そのため、少し程度であるべきなんです

## 実装はどうなの？
acornというJavaScriptパーサーでASTにして、それを操作して関数をシャッフルした後にescodegenで元に戻します。

## 余計なことしてない？
クレジットコメントがへばりついてたので、ついでにAST化→escodegenを使って戻すことですべてのコメントを排除できるようにしました。

## 使うには？
acornとescodegenをインストールする必要があります。
```bash
$ npm i -D acorn escodegen
# or
$ bun i -D acorn escodegen
```
そしてTypeScriptで出来ているため、もしJavaScript環境で使いたいなら型宣言を頑張って消してください。
HSSとBDFDoor：今回のSKテレコムハッキング事件の核心技術とは？

# HSSとBDFDoor：今回のSKテレコムハッキング事件の核心技術とは？

韓国大手通信事業者であるSKテレコム（SKT）に対する最近のサイバー攻撃は、単なるネットワーク侵入事件ではなく、モバイル通信インフラの中枢を狙った精密な攻撃であると分析されています。本稿では、この事件の鍵を握る2つの技術的キーワード――**HSS（Home Subscriber Server）** と **BDFDoor** ――に注目し、それらが何であり、なぜ今回の事態で決定的な役割を果たしたのかを解説します。

---

## HSSとは何か：通信サービスの“心臓部”

**HSS（Home Subscriber Server）**は、4G LTEや5Gコアネットワークにおいて中心的な役割を担うデータベースサーバで、加入者の認証、接続制御、セッション管理を担当しています。

### 📌 HSSの主な機能

- **加入者認証（Authentication）**  
  ユーザーがスマートフォンにUSIMを挿入し、ネットワークに接続しようとする際、HSSはそのUSIMが登録済みの正当なものであるかを確認します。

- **接続制御（Authorization）**  
  ユーザーに許可されたQoS（サービス品質）やローミング可否などに基づき、ネットワークへのアクセス権限を設定します。

- **セッション情報管理**  
  通話やデータ通信時のセッション情報を管理・保持します。

- **USIMの発行・交換・履歴管理などの業務支援**

### 📌 HSSの侵害が意味するもの

HSSが侵害されたということは、数千万単位の通信契約者に関する認証情報や接続記録が外部に漏洩した可能性があることを意味します。これは単なる個人情報の流出ではなく、USIMの複製による**なりすまし通信**や**盗聴**など、国家的安全保障にも関わる深刻な事態です。

---

## BDFDoorとは何か：執拗かつステルスなバックドア

**BDFDoor**は、ここ数年、政府機関や重要インフラ、軍需産業を標的とするAPT（高度持続的脅威）攻撃に使われてきたとされるマルウェア（バックドア型）です。

### 📌 BDFDoorの主な特徴

- **多段階の隠蔽**  
  正規プロセス（例：svchost.exe）を装い、検出を回避。コードは暗号化・難読化されており、静的解析を困難にします。

- **C2（Command & Control）サーバとの通信**  
  外部の攻撃者が命令を送るC2サーバと定期的に通信し、ファイルのダウンロード、コマンド実行、情報収集などを行います。

- **永続性の確保**  
  再起動後も自動的に再実行されるよう、レジストリやタスクスケジューラに埋め込まれます。

- **高レベル権限の取得**  
  管理者権限を取得してファイアウォール無効化やログ削除などを実行可能にします。

### 📌 SKTへの侵入手口

現在までの分析によれば、内部システムの特定機器にBDFDoorが侵入し、それを足がかりにネットワーク内部へと拡散。最終的にHSSサーバへ到達したと推定されています。SKTの発表では**4種類のBDFDoor亜種**が確認されており、これは単一の侵入ではなく、**組織的かつ計画的なAPT攻撃**であることを強く示唆しています。

---

## 私たちは何を学ぶべきか

この事件は「単なる情報漏洩」ではありません。**HSSが攻撃されたという事実は“通信主権の侵害”であり、BDFDoorの存在はサイバーセキュリティが単なるITの問題ではない**ことを明確に示しています。

技術者として、以下の点を再確認する必要があります：

- 基幹インフラの物理・論理的分離とアクセス制御の徹底  
- 定期的な内部セキュリティ診断と脆弱性テスト  
- 異常トラフィックの早期検知と即時対応体制  
- APT攻撃に対応可能な専門人材とツールの整備

---

## APT攻撃への総合的な対応策：技術・プロセス・組織の3軸で防御を構築

### 1. 可視性と早期検知  
- EDR/XDRソリューションによるリアルタイム監視  
- SIEMによるログの集中分析  
- UEBAでユーザーの異常行動を識別

### 2. 24時間体制の監視と対応  
- SOC（Security Operation Center）の構築  
- グローバルな脅威インテリジェンスの活用  
- IR（インシデント対応）プロセスの確立と訓練

### 3. 権限とアクセス制御の強化  
- 最小権限の原則  
- MFA（多要素認証）の徹底  
- 外部ネットと内部重要系のネットワーク分離

### 4. 脆弱性管理とパッチ適用  
- 定期的な脆弱性スキャンと仮想パッチ適用  
- 自動アップデート体制の構築

### 5. 社員教育とシミュレーション訓練  
- フィッシング対策訓練  
- Red Team/Blue Team演習  
- Table-top訓練による意思決定模擬

### 6. データ保護と多重防御  
- 全データの暗号化とアクセスログの記録  
- オフラインバックアップ体制の強化

---

## 結論：本物のセキュリティは“技術＋誠実な企業文化”から

HSSとBDFDoorは、今回の事件における技術的な中心であると同時に、**企業の透明性不足、責任の所在不明、顧客保護意識の低さ**といった問題の象徴でもあります。

真のセキュリティとは、ファイアウォールやアンチウイルスだけで成り立つものではありません。**ユーザーの信頼を守る覚悟、問題発生時に責任を取る文化、そしてそれらを支える技術**が必要です。それこそが「信頼される企業」となるための唯一の道であり、最も重要な競争力なのです。
SKTハッキング事件、セキュリティの失敗と信頼の崩壊

# SKTの大規模情報流出事件：セキュリティの失敗と信頼の崩壊

2025年4月、韓国史上最悪とも言えるハッキング事件が発生しました。被害に遭ったのは、韓国最大手の通信会社 **SKテレコム（以下、SKT）**。その規模と影響力を考えると、今回の事件は単なる情報流出では済まされません。

SKTの重要なシステムである**ホーム加入者サーバ（HSS: Home Subscriber Server）**が不正アクセスを受け、**約9.7GBに及ぶUSIM（加入者識別モジュール）関連データ**が外部に流出しました。これにより、**約2,500万人分の個人情報**が漏洩した可能性が高く、**事実上、韓国の人口の半分近くに影響する事件**となっています。

## 何が問題だったのか？

USIMはモバイル端末のネットワーク認証を担う重要なコンポーネントです。今回流出した情報には、**電話番号、IMSI（国際加入者識別番号）、ICCID（USIMカード識別番号）、認証キー（Ki）**など、USIMの複製に関わる4種のデータが含まれています。さらに、**USIM発行・管理に使用される内部情報21種類**も外部に流出しました。ただし、端末固有識別番号（IMEI）の漏洩は確認されていません。

攻撃手段は**バックドア型のマルウェア**と推定されており、**BDFDoor系のマルウェア4種**が検出されました。これは一般的な攻撃ではなく、システム内部に潜伏し、長期間にわたり情報を外部へ送信する **高度な持続型標的型攻撃（APT）** であると考えられます。

しかしながら、SKTの対応はこうした脅威に見合うものではありませんでした。

### SKTの対応タイムライン

- **4月18日 午後6時9分**：ネットワークインフラセンターで異常なトラフィックを初検知  
- **4月19日**：マルウェアを確認し、問題の機器を隔離。HSSサーバからの流出の痕跡を発見  
- **4月22日**：KISA（韓国インターネット振興院）に正式通報  
- **4月25日**：SKT CEOが公式謝罪、USIMの無償交換を発表  
- **4月28日**：無償交換を本格開始、全国の店舗で混乱が発生  

初期検出から正式通報まで**4日間**の空白があったことは深刻です。また、**個別通知やアラートを加入者に送信しなかった**ことで、情報弱者や非アクティブユーザーの多くは未だに被害の事実を知らない可能性があります。

## 開発者として、この事態から何を学ぶべきか？

今回の事件は単なるセキュリティの欠陥ではなく、**企業文化や情報管理体制の不備**が浮き彫りになった出来事です。私たちは開発者として、**「どう守るか」だけでなく、「問題が起きた時にどう責任を取るか」**という姿勢を持たなければなりません。

以下のような点が改めて重要であることが明らかになりました：

- **APT攻撃を想定した常時監視体制の構築**  
- **重要インフラ（HSS、認証サーバ等）のネットワーク分離とアクセス制限**  
- **管理者権限やログへのリアルタイム監視とアラートシステム**  
- **情報漏洩発生時の迅速なユーザー通知と対応プロトコルの整備**

セキュリティは技術だけでなく、**意識と責任感**が問われる時代です。透明性ある報告、そして迅速な対応こそが信頼を守る唯一の方法です。

## 誠実義務は企業にも適用されるべき

企業は法的には“法人格”を持ち、人と人との契約と同じく、**信義誠実の原則** に基づいて行動すべきです。

ところがSKTの対応はその原則から逸脱しています。USIMの供給不足が発生し、既存ユーザーの交換すら追いついていないにも関わらず、**新規加入者向けのキャンペーンは継続・拡大**されました。さらに、**契約解除時の違約金免除に関しても明確な案内がされていない**状況です。「USIM保護サービスに加入していれば100％補償」といった表現は、**加入していないユーザーには補償がないのか** という不安を与えます。

加えて注目すべきなのは、**SKTのセキュリティ投資額の低さ**です。

- **KT：約1,200億ウォン**  
- **LG U+：約620億ウォン**  
- **SKT：わずか600億ウォン**

**業界1位でありながら、セキュリティ投資は最下位**。最も多くの顧客情報を保有しているにもかかわらず、最も少ない予算しか投じてこなかったという事実は、今回の事件が偶然の産物ではなく、**構造的な軽視**の結果であることを示しています。

## 信頼、それ自体がブランドである

技術者として、また企業人として、私たちが目指すべきは単なるシステムの構築ではありません。**顧客との信頼を築くこと、問題が発生した際に正直に報告し、誠実に対応する姿勢**こそが、企業の長期的な成長につながると信じます。

**信頼は一朝一夕では得られず、一瞬で失われるものです。** 今回のような危機を、単なる失敗で終わらせず、**信頼回復への転換点**とすることができるかどうか。それこそが、真に持続可能な企業の証ではないでしょうか。
React Router テストでパラメータが取れないときの解決法

## はじめに
React Router を使用したのコンポーネントのテストで、以下のエラーが発生しました。

```terminal
 ● UserCard › ユーザー名が表示されていること

    URLパラメータのIDが見つかりません

      40 |         try {
      41 |           if (!id) {
    > 42 |             reject(new Error('URLパラメータのIDが見つかりません'));
         |                    ^
      43 |             return;
      44 |           }
      45 |           console.log(`${id}のユーザー情報を取得します`);
```

これは、ユーザー名が表示されていることをテストした際に表示されたエラー内容です。
今回は、コンポーネントが適切にルートを認識できない場合の対処法をまとめます。

## 問題点
最初、レンダリングでは以下のようにテストを書きました

```tsx:Usercard.test.tsx
render(
  <MemoryRouter initialEntries={['/cards/testuser']}>
    <ChakraProvider>
      <UserCard />
    </ChakraProvider>
  </MemoryRouter>
);
```

このコードでテストを実行すると、useParamsがパラメータを取得できず、コンポーネント内で期待するid変数がundefinedになり、テストが失敗してしまいました。

## 解決策
実際のルーティング構造を再現する必要があるため、`Routes` と `Route` を追加しました。

```tsx
render(
<MemoryRouter initialEntries={['/cards/testuser']}>
  <Routes> // ← この部分
    <Route 
      path="/cards/:id"
      element={
        <ChakraProvider>
          <UserCard />
        </ChakraProvider>
      }
    />
  </Routes>
</MemoryRouter>
);
```
この変更を加えたところ、テストが成功するようになりました！

---

<details><summary><font color="skyblue">コード全体を見る</font>
</summary>

```tsx:Usercard.test.tsx
describe('UserCard', () => {
  beforeEach(async () => {
    // テスト用データの準備
    mockGetUserSkillById.mockResolvedValue({
      user_id: 'testuser',
      name: 'テストユーザー',
      description: '<p>これはテスト用の自己紹介です</p>',
      skills: [
        { id: '1', name: 'React' },
        { id: '2', name: 'TypeScript' },
      ],
      github_id: 'https://github.com/testuser',
      qiita_id: 'https://qiita.com/testuser',
      x_id: 'https://x.com/testuser',
      created_at: '2025-01-01 12:00:00',
    });

    render(
      <MemoryRouter initialEntries={['/cards/testuser']}>
        <Routes>
          <Route
            path="/cards/:id"
            element={
              <ChakraProvider>
                <UserCard />
              </ChakraProvider>
            }
          />
        </Routes>
      </MemoryRouter>
    );
  });

  it('ユーザー名が表示されていること', async () => {
    const userName = await screen.findByTestId('user-name');
    expect(userName).toBeInTheDocument();
    expect(userName).toHaveTextContent('テストユーザー');
  });
  
  // 他のテストケース...
});
```
</details>


## さいごに
`React Router` でURLパラメータを使用するコンポーネントをテストする場合、単に `MemoryRouter` を使用するだけでなく、`Routes` と `Route`コンポーネントを追加して実際のルーティング構造を再現することが重要です。
【365日後にPredictive Master】大企業の平社員がAlteryx Weekly Challengeに挑む #007

## はじめに
こんにちは、積立お兄さんです。
大企業新卒３年目のAlteryx初心者です。
ひょんなことから「**365日後にPredictive Masterになる！**」という目標を掲げて、公式のWeekly Challengeにコツコツ挑戦しています。

この記事では、Alteryx歴3か月の平社員が、実務で生かせそうなノーコード分析力をどうやって身につけていくかを記録＆共有していきます。

- 目標：ETLツールを自在に使いこなせるようになる
- 対象読者：Alteryxを始めたばかりの方/Weekly Challengeの解説が欲しい方

---

## 今回のチャレンジ：Weekly Challenge #007

- タイトル：[Weekly Challenge #007：ダイアモンド R 永遠の輝き (Diamond R Forever)] [LINK](https://community.alteryx.com/t5/%E3%82%A6%E3%82%A3%E3%82%AF%E3%83%AA%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA/%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8-7-%E3%83%80%E3%82%A4%E3%82%A2%E3%83%A2%E3%83%B3%E3%83%89-R-%E6%B0%B8%E9%81%A0%E3%81%AE%E8%BC%9D%E3%81%8D-Diamond-R-Forever/td-p/402792)
- レベル感：じょうきゅうしゃ向け
- ゴール：Rツールでrdaファイルを読み込み、指定のフォーマットで出力する。
- 入力
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658349/59fb408e-5741-466e-be7a-2a6fa29196ad.png
">
- 出力
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658349/8589f1ec-c622-4faf-a86d-06287abbe041.png
">

---

## 解いた流れと使用ツール

### ワークフロー全体

<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658349/20ccc9ef-3498-4dbf-bb9d-c91862ca8c34.png
">

### 処理の手順と解説
1. **Rツール**：rdaファイルを読み込む。R言語を直接書き込んで入力することができる。
式は以下の図を参照。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658349/684da531-5451-4cf9-8d37-e7067e82c87b.png
">
R言語は調べたり勉強するしかない。
write.Alteryx(df, n)のnで、ツールのどの出力ポートで出力するかを指定できる。
1. **タイルツール**：手動で範囲を指定し、carat列の値の範囲ごとにグループ化する。
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658349/4e08dc34-9848-42a4-934c-b831b1d7e55b.png
">
1. **集計ツール**：タイルツールで生成されたTile_Numでグループ化してカウントすることで、各グループにどのくらいの値があるのかを確認することができる。
1. **フォーミュラツール**：Range列を作るために、max列とmin列を作成する。その後、文字列に変換して指定のフォーマットに変換する。
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658349/b9c9db1b-9620-4ccf-9f04-4a6ac1ac3677.png
">
1. **セレクトツール**：列を整える。


---

## 詰まったポイントとその解決

- **問題：Rangeを指定して、それをしようしてグループ化する方法**
→ タイルツールを使用するとこれができることが調べて分かった。
---

## 結果と出力確認
<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658349/64045cc0-e334-451b-b9da-ebc7bb5cf8c9.png
">

→正しい出力フォーマットで、指定要件を満たしていました！

---

## 今日の学び・振り返り

- **新しく覚えたツール**：Rツール、タイルツール
- **工夫ポイント**：フォーミュラツールの式を分割してminとmaxを作成し、それらを文字列に変換して新しい列を作成した。
- **実務への応用**：Rangeを定義してグループ化する方法は汎用性高そうな気がする。
---

## 次回予告
次は【Weekly Challenge #008】に挑戦予定！
GWも後半戦ですね。
Inspireまでにどこまで進めることができるか...意外とすすまないもんですｎ

---
## タグ
`Alteryx` `weekly Challenge` `データ分析` `Predictive Master` `365日チャレンジ` `ノーコード`
IOS-XE で特定国からのアクセスを防ぐACLをNetconfで適用する

某オンライン証券でアクセス権奪取による被害が続いています。
何が原因であるかは現時点で定かではありませんが、不審な国・エリアからのアクセスを制御するのも1つの考え方です。
オンライン上には下記のような特定の国やエリアのIPアドレスを一覧にしているサイトがあります。

https://ipv4.fetus.jp/krfilter

今回はそれを利用して、Cisco IOS-XE のACLの形式にダウンロードしつつ、netconfで書き換えるPython3 scriptをChatGPTの協力を得て作成しましたので、備忘録を兼ねて公開します。


:::note alert
今回はkrfilter v1を利用しましたが、これだけでACL行数は6000行近くになります。デバイス側のキャパシティの管理にはご注意ください。
:::

:::note info
ACL行数があるため、timeout時間を600秒としています。
皆さんの環境に合わせて、そのあたりは書き換えましょう。
:::


```python
from ncclient import manager
import ipaddress
import requests

# ---------- 接続設定 ----------
DEVICE = {
    "host": "YOUR ROUTER IP ADDRESS",  # ルータのIP
    "port": 830,
    "username": "YOUR USERNAME",
    "password": "YOUR PASSWORD",
    "hostkey_verify": False,
    "allow_agent": False,
    "look_for_keys": False
}

ACL_NAME = "BLOCK_KR"
ACL_URL = "https://ipv4.fetus.jp/krfilter.1.txt"
# ------------------------------

def download_ip_list(url):
    response = requests.get(url)
    response.raise_for_status()
    return response.text.strip().splitlines()

def build_acl_config_xml(ip_list):
    seq = 10
    acl_entries = ""
    for cidr in ip_list:
        try:
            net = ipaddress.IPv4Network(cidr)
            acl_entries += f"""
          <access-list-seq-rule>
            <sequence>{seq}</sequence>
            <deny>
              <std-ace>
                <ipv4-address-prefix>{net.network_address}</ipv4-address-prefix>
                <ipv4-prefix>{net.network_address}</ipv4-prefix>
                <mask>{net.hostmask}</mask>
              </std-ace>
            </deny>
          </access-list-seq-rule>"""
            seq += 10
        except ValueError:
            continue

    # 最後に permit any を追加
    acl_entries += f"""
          <access-list-seq-rule>
            <sequence>{seq}</sequence>
            <permit>
              <std-ace>
                <any/>
              </std-ace>
            </permit>
          </access-list-seq-rule>"""

    # 完全なNetconf構成XMLを返す
    return f"""<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
    <ip>
      <access-list>
        <standard xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-acl">
          <name>{ACL_NAME}</name>
          {acl_entries}
        </standard>
      </access-list>
    </ip>
  </native>
</config>"""

def push_acl_config():
    ip_list = download_ip_list(ACL_URL)
    config_xml = build_acl_config_xml(ip_list)

    print("🔄 Connecting to device...")
    with manager.connect(timeout=600, **DEVICE) as m:
        print("🚀 Sending ACL config via Netconf...")
        response = m.edit_config(target="running", config=config_xml)
        print("✅ ACL successfully updated.")
        print("📄 Netconf reply:")
        print(response.xml)

if __name__ == "__main__":
    push_acl_config()
```

このACLをWAN interface に適用いただければアクセス制御はできるかと思いますし、cronなどで定期的に適用いただければ、データソースの更新を追いかけることがかのう
よいネットワークライフを！
覚えて損はない git & jq コマンドの使い方

## はじめに
下記のような人を記事対象者にしています。
- 日常的に、 git & jq コマンドの使用機会が多い
- 能率を上げたい、外部連携APIなどの出力結果から目的の情報を素早く探すなど効率化したいと思っている


## git技①：　対象のローカルブランチに素早く切り替える
```
git branch | grep XXX(※チケット番号を想定、例:1234)  | git checkout $(awk '{print $0}')

# ローカルブランチ一覧を表示させる
# チケット番号が含まれるブランチ名をフィルタリング
　　→　実践では、"issue/1234"など各プロジェクト規約に沿った命名が決まっていると思うので、そこから使える法則を探し値を設定する
# フィルタリングした行（ブランチ名）をgit checkoutコマンドに渡し実行させる
```
:::note info
使える場面
・開発が長期・大規模化するうちにローカルブランチが数十個に増加していて、git branch コマンドからの目視確認で探して切り替える操作が手間。
・ブランチ名にチケット番号や課題番号でも固有の値を含めれば、運用が変わっても流用可能。
:::

## git技②：　ブランチ間の差分を見て、ファイル単位で比較するコマンド
```
git diff XXX(※比較元ブランチ名) YYY(※比較先ブランチ名) --name-only | grep ZZZ（※資源置かれているフォルダ /app/resourcesなど）

# XXXとYYYを比較し差分が確認できるファイル名の一覧を表示する
```
:::note info
使える場面
・変更をマージする前の差分確認で使える。GUIツール（TortoiseGitなど）を使えない環境下にあればより時短が期待できる。
:::

## git技③：　Git管理下の全ファイルから特定文字列を含む行を探して出現回数付きで表示する
```
git grep -n "selectFoodMenu(/" | awk -F'[:]' '{print $NF}' | tr -d ' ' | sort | uniq -c

# これはselectFoodMenuという関数の表示箇所を全ファイルで確認し該当行の内容を取得したら、出現回数付きで表示する例です。
```
:::note info
・コメント文に対しても使用できるので、例えば"○○をする"などで調べ、表記ゆれや処理の中身が似ている関数の乱立を発見するのに活用もできる。
・awk や sed などの置換コマンドと併用したコードを検討しているなら、事前調査に向いている
:::

## git技④：　Gitのstage領域に特定のものだけ追加したい
```
git add $(find ./menu/ '*meat*json' -print)

# menuフォルダの中のmeatという文字が含まれる全jsonファイル名を抽出し、gitのstage領域に追加する例です。
# ※$(...)は別コマンド実行結果を呼び出し元のコマンドの中に埋め込む記法。
```
:::note info
「git add .」のようなGit管理されているファイルの全追加コマンドに対して、こちらは変更はしているけど特定のファイル群しかstage領域に上げたくない場合に活用できます。
:::


## jq技①：　連想配列情報から絞込む値や条件に一致する要素をキーバリュー構造のまま取得する
```
jq '.results[] | select(.code | test("^AB[0-9]{10}"))'
# JSON情報からキー「results」を参照し内部キー「code」値の先頭が
# "AB + 0～9までの数値10桁"であるかを判定して当てはまる要素をキーバリューごと取得する。
```
:::note info
この例ですと、code以外にnameやstatusなど他のキーが含まれている場合は、それらも全て含めた状態で返却値が用意されます。
:::

## jq技②：　連想配列情報から絞込む値や条件に一致する要素だけをキーバリュー構造のまま取得する
```
jq '[.results[] | .code | select( test("^AB[0-9]{10}") )]'

# JSON情報からキー「results」を参照し内部キー「code」値のみ全て取得して、
# 先頭が"AB + 0～9までの数値10桁"であるかを判定して当てはまる箇所のキーバリューを取得する。
```
:::note info
上記①と似ていますが、この場合はnameやstatusなど他のキーが含まれていても、code値以外は返却結果に含まれません。
:::
【Copilotとのたった2回の会話で解決】Next.js × Supabase 認証リダイレクト問題をシンプルに修正した話

# 【Copilotとのたった2回の会話で解決】Next.js × Supabase 認証リダイレクト問題をシンプルに修正した話
Next.js と Supabase を使ってシフト管理アプリを作っていたところ、「**ログインしていないとホーム画面が見れない**」かつ「**ログイン後に勝手に `/calendar` に遷移する**」という状態に陥りました。

今回はこの問題を、**GitHub Copilotとたった2回やり取りしただけでスムーズに解決できた**体験を共有します。
該当のサイト: https://shift-app-mu.vercel.app/

---

## 🐞 問題：ホームページにアクセスできない & 勝手にカレンダーページへリダイレクトされる

現象は次のとおりです：

- ログインしていないと `/`（ホームページ）にアクセスできない
- ログイン後に `/calendar` に自動でリダイレクトされてしまう
- ホームページでとどまりたいのに、それができない

---

## 💬 Copilotとの会話1：  
>「ログイン後に勝手に Calendar page に遷移せず、ログイン前後でホームページに止まれるようにしてください」

### Copilotの提案：

- `page.tsx` にあった `useEffect` の自動遷移ロジックを削除
- 代わりに、ログイン状態に応じて表示するボタンを切り替える実装を提案

```tsx
{session ? (
  <Link href="/calendar">
    <Button>カレンダーへ</Button>
  </Link>
) : (
  <Link href="/login">
    <Button>ログイン</Button>
  </Link>
)}
```

✅ これにより、自動遷移は止まり、ユーザーが自分でページを選べるように！

---

## 💬 Copilotとの会話2：
> 「loginしていない状態でも home 画面は開けるようにしてください」

### Copilotの提案：

- `middleware.ts` に定義されていたパブリックルートから `/` が抜けていたことに言及
- `publicRoutes` に `/` を追加するようにアドバイス

```ts
// 修正前
const publicRoutes = ["/login", "/signup"];

// 修正後
const publicRoutes = ["/", "/login", "/signup"];
```
✅ これにより、ログイン前でも / にアクセスできるように！

---
## ✅ 修正結果まとめ

| ステップ | 会話内容                                             | 修正内容                                                 |
|----------|------------------------------------------------------|-----------------------------------------------------------|
| 1回目   | ログイン後に勝手にリダイレクトしないでほしい         | `useEffect` を削除し、ログイン状態でボタン表示を制御     |
| 2回目   | ログイン前でもホーム画面にアクセスしたい             | `middleware.ts` の `publicRoutes` に `/` を追加           |

---

## ✨ 感想：Copilotと話すだけで、複雑な認証フローも解決！

今回のケースでは、どこの部分で問題が起きているのかを説明することで簡単に問題を解決することができました。
一方で、どこの部分でどのような問題が起きているのかを細かく説明する必要性はまだあるので、一度お願いして細かく全てをチェックしてくれるようなお願いはまだできないことを考えるとAIに全ての開発はまだできないなと思いました。
[ITensor] プライムレベルが一致していません！

# エラーの紹介
数値計算ライブラリITensorを使っているときに
このようなエラー文が出て困った経験はないでしょうか？
```
Warning: Calling `inner(x::MPS, A::MPO, y::MPS)` where the site indices of the `MPS`
│ `x` and the `MPS` resulting from contracting `MPO` `A` with `MPS` `y` don't
│ match is deprecated as of ITensors v0.3 and will result in an error in ITensors
│ v0.4. The most common cause of this is something like the following:
```
` indices ~ dont't match `とあり、インデックスになんらかの不整合があるようです。
以下のコードを実行することでエラーが出てきます。
```julia
using ITensors, ITensorMPS

site = siteinds("S=1/2", 10)
psi0 = randomMPS(site)

function Ising_Hamiltonian(N::Int)
    os = OpSum()
    for j in 1:N-1
        os += "Sz", j, "Sz", j+1
    end
    return os
end
H = MPO(Ising_Hamiltonian(10), site)

#psi0のエネルギー期待値計算
psi1 = H * psi0
E = inner(psi0, psi1)
```
`psi0`の状態におけるエネルギー期待値を計算しようとしています。`psi0`にハミルトニアン`H`を作用させて`psi1`を得ます。`inner`で`psi0`と`psi1`の内積をとることで、期待値$ \langle \psi_0 | H | \psi_0 \rangle $が得られるはずです。


一見して問題はなさそうです。

# 解説
エラーの原因を一言で表すと、
    **"インデックスのもつプライムレベルの不一致"** です。
    
まず、`MPS`型変数である`psi0`と`psi1`の1番目のサイトインデックスを確認してみましょう。
```julia 
println(siteind(psi0,1))
println(siteind(psi1,1))
```
出力は
```
(dim=2|id=307|"S=1/2,Site,n=1")
(dim=2|id=307|"S=1/2,Site,n=1")'
```
となります。`psi1`のサイトインデックスにだけ`'`が付いていることが分かります。
この`'`の個数はインデックスの**プライムレベル**と呼ばれます。

ITensor内部では、プライムレベルの異なるインデックスは別物と見なされます。そのため縮約が取れなくなり、`inner`がうまく働いていません。これがエラー文の意味するところです。

# 考察
**"プライムレベルはどこで変わってしまったのか？"**

その原因を探るために、`MPO`型変数である`H`の1番目のインデックスを表示してみましょう。
```julia
println(inds(H[1]))
```
出力は
```
((dim=3|id=394|"Link,l=1"), (dim=2|id=31|"S=1/2,Site,n=1")', (dim=2|id=31|"S=1/2,Site,n=1"))
```
となります。リンクインデックス`(dim=3|id=394|"Link,l=1")`を除けば、２つのサイトインデックス`(dim=2|id=31|"S=1/2,Site,n=1")', (dim=2|id=31|"S=1/2,Site,n=1")`をもっていることが分かります。

さらにサイトインデックスのうち片方はプライムレベル１です。

実は、`MPO`関数で`MPO`型変数を生成する際、同サイトを指すインデックスは異なるプライムレベルをもつように生成されます。
```julia 
psi1 = H * psi0
```
としたことで、`H`と`psi1`の間でプライムレベル0のインデックスが縮約され、`psi1`にはプライムレベル１のインデックスのみが残ったという訳でした。

# 最後に
関数`noprime`を使ってプライムレベルを0にすれば、うまく縮約を取ることができます。

```julia
psi1 = H * psi0
psi1 = noprime(psi1)
E = inner(psi0, psi1)
```
こんな感じです。
AUTOSAR: OSが主人公じゃない環境について

Unixは、OSが主人公ではなく、Ethernet, TCP/IPを助けるありがたいサービス群。
Unixを使うのに、OSの知識はほとんど必要がない。

C言語は、HostedとFreestandingの２種類がある。

![C.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51423/277875cb-bb32-cfa8-592e-490ce1453b96.png)

C言語とPOSIXは蜜につながっている。
Hostedは、main()関数がstartupである。
Freestandingでは、main()関数でなくてもよい。

実際には、POSIX関数とHosted関数

OSがない場合は、FreestandingのC言語規定を利用する。
POSIX OSより小さいOSは、FreestandingとそのOSを利用する。

OSEK/VDX は、OSが主人公ではない。
OSEK/VDX OSも、POSIX同様、Cの精神を継承している。

Cの精神とCの原則：C言語がわかるとは
https://qiita.com/kaizen_nagoya/items/d2a24a41f00c939c5e70

「本物のC」は「Cの精神」と 「freestanding と hosted」と「未定義、未規定、処理系定義」
https://qiita.com/kaizen_nagoya/items/11d66a02479239bf80dd

C言語を習得する３つの方法
https://qiita.com/kaizen_nagoya/items/84cab0888c193bba429b

C言語(C++)が必要な人と必要ない人
https://qiita.com/kaizen_nagoya/items/2afe9e846b55b24cb6f1
汚染データ検証と除染データ検証

## データの状態

バリデーションの観点から言うと、データには状態が2つ存在する。
1つは汚染されている状態、もう1つは除染された状態。
この2つの状態はデータの内容が変わるので、検証方法も変わる。

## 汚染データ検証

```php:
$num = $_POST['num'];
// $num は汚染データ
```

$_POSTから取ったばかりのデータは汚染されているデータである。
不潔、汚い、醜い、きらい。
そんなデータである。

これを検証する。

```php:
$result = filter_var($num, FILTER_VALIDATE_INT);
if ($result === false) {
    die("invalid num");
}
$num = $result;
```

`filter_var`関数は第1引数を第2引数の指定で検証する。上記ではnumをintにしている。
numが不正な値だったらfalseが返る。

この時点の検証は「汚染データの検証」である。
つまり、データは汚染されている。汚染されているのだ。

汚染データが不正だということは、入力が不正だということである。
入力がおかしいということは、攻撃やバグの可能性がある。

つまりアタッカーの攻撃は、汚染データ検証で検出することができる。

## 除染データ検証

さきほどは`filter_var`でデータを除染した。
`filter_var`によってnumはintになった。

ここからは除染データの検証である。

```php:
if ($num < 0 || $num >= 100) {
    die("invalid num range");
}
```

numが指定範囲の整数かどうかチェックする。
numは整数なのでシステムにとっては無害なものであるが、値の大きさによっては害があるものに変わることもありえる。
そのため、ここで検証する必要がある。

値が範囲外の大きさであればこれも攻撃か、あるいはバグである可能性が高い。

つまり汚染状態のデータでも攻撃を検知できるし、除染後のデータでも攻撃を検知できるということになる。
汚染データと除染データでそれぞれ検証を設けることで、二重に攻撃を検知することができる。

## サニタイズ

汚染データが不正である場合、攻撃かバグの可能性が高いということだが・・・。
汚染データの検証を入れずにデータをサニタイズすると、この攻撃を検知できなくなる。

```php:
// 以下のコードではmsgが攻撃データかどうか検知できない
$msg = $_POST['msg'];
$clean_msg = htmlspecialchars($msg);
echo $clean_msg;
```

よって、サニタイズ前に検証処理を入れることで攻撃を検知することができる。

```php:
// 汚染データ
$msg = $_POST['msg'];

// 汚染データ検証
if (has_html_tag($msg)) {
   die("invalid msg");
}

// 除染
$clean_msg = htmlspecialchars($msg);

// 除染データ検証
if (strlen($clean_msg) >= MAX_MSG_LEN) {
    die("invalid msg len");
}

// 出力
echo $clean_msg;
```

## 汚染と除染

検証におけるデータの状態は

* 汚染
* 除染（済み）

の2つ。
これを頭に入れておくとコードが捗る（はず）。
ぴよぴよぴ～！