OmniAICreator/Qiita-1.07M huggingface dataset:
【Mac】ssh接続のたびにパスワード聞かれるのをなくす方法

# はじめに
秘密鍵・公開鍵を発行すればSSH接続できるようになります。
ただ、それだけではSSH接続するたびにパスワードを求められます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894261/4e8638ed-e916-4f15-923f-8b959c88ec42.png" width=70%>

これを解消するためには**SSH Agent**に秘密鍵を登録する必要があります。
さらに、Macを再起動しても登録状態を保持するには、**Keychain**にも登録して初回SSH接続時に読み込むよう設定します。

<br>

# 登録手順
1. SSH Agent登録の際に`apple-use-keychain`オプションをつける
    ```bash
    ssh-add --apple-use-keychain ~/.ssh/id_rsa
    ```
    これでKeychainにも登録できます。

    <br>

2. **~/.ssh/config**に読み込み設定を書き込む
    ```text
    Host *
    UseKeychain yes
    AddKeysToAgent yes
    ```

これで完了です。お疲れさまでした！

<br>

# （補足）登録解除するには...
1. SSH Agentから削除する
    ```
    ssh-add -d ~/.ssh/id_rsa
    ```

    <br>

2. Keychainからも削除する
    Spotlight（⌘+Space）「キーチェーン」と検索して**キーチェーンアクセス**を開く
    右上の検索窓から削除したい鍵を検索する
    右クリックで削除する
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894261/4898434d-b507-46e4-8cc6-551089a33dc6.png" width=80%>

これでMacを再起動すれば解除されます。
Geminiでカメと遊ぶ魔法少女を描いてみた。

# 概要

Geminiでカメと遊ぶ魔法少女を描いてみました。

# 実装

プロンプトと実行結果は以下の通りでした。

```
聖なるカメと遊ぶ魔法少女を描いてください。
```

![聖なるカメと遊ぶ魔法少女_20250621.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192024/985ad234-1ba2-467e-8ae3-12f3c7558f8e.png)

# まとめ

可愛い。何かの役に立てばと。
はじめてのWeb APIとMongoDBで作るシンプルなメモ帳アプリ

## はじめに

**Web API**について学んだことをきっかけに、実際に自分でも使ってみることにしました。

今回は、MongoDBというデータベースも初めて利用し、小さなアプリを実装してみました。

この記事では、その作成を通して得られた学びや気づきを、備忘録としてまとめています。

![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3841606/fe9052c7-ec1d-4629-bd6c-5f431fb827c5.gif)


## 実装前に混乱していたこと（MPAとSPA）

私がチュートリアルで触れてきたアプリでは、複数のページがあり、基本的にHTMLファイルをサーバー側でレンダリングして返すことが基本でした。

しかし、今回のように1ページで完結するアプリの場合、どのように実装すれば良いのかで混乱しました。

サーバーはデータだけ提供し、UIの見た目はフロントエンドで制御するという役割分担の考え方を意識することで、徐々に理解できるようになってきました。

### MPA（Multi Page Application）

- サーバー側で HTML を `res.render()` などで生成し、クライアントに送る
- 各操作（作成、編集、削除）ごとに新しいページに遷移する

### SPA（Single Page Application）

- 最初に読み込まれたHTML内で、すべてのUIがJavaScriptによって制御される
- 操作に応じて  API を呼び、データのみを取得または送信
- サーバーはデータ（JSON）を返すだけで、HTMLは返さない

### 実装の違い

- MPA：`res.render('page', { data })`
- SPA：`res.json({ data })`

## API設計（CRUD操作）

アプリで必要なデータ操作は、いわゆる**CRUD**（Create / Read / Update / Delete）に分類できます。

今回は、メモの作成・取得・更新・削除といった基本的な操作を以下のようにAPIとして設計しました。

| メソッド | パス | 内容 |
| --- | --- | --- |
| `POST` | `/api/memos` | メモを新規作成 |
| `GET` | `/api/memos` | すべてのメモを取得 |
| `GET` | `/api/memos/:id` | 特定のメモを取得 |
| `PUT` | `/api/memos/:id` | メモを更新 |
| `DELETE` | `/api/memos/:id` | メモを削除 |

## データベース（MongoDB）でのデータ管理

データベースにはMongoDBを使用しました。

まず、以下のようにメモのスキーマを定義しました。

```jsx
const memoSchema = new mongoose.Schema(
  {
    title: String,
    content: String,
  },
  { timestamps: true }
);
```

それぞれのAPIリクエストが、MongoDBのどの操作と対応しているかをまとめたのが以下の表です。

| メソッド | 内容 | MongoDBメソッド |
| --- | --- | --- |
| `POST` | メモを新規作成 | `new Memo({ title, content }).save()` |
| `GET` | すべてのメモを取得 | `Memo.find()` |
| `GET` | 特定のメモを取得 | `Memo.findById(id)` |
| `PUT` | メモを更新 | `Memo.findByIdAndUpdate(id, { title, content });` |
| `DELETE` | メモを削除 | `Memo.findByIdAndDelete(id)` |

## 感想

- 初めてのAPI設計とデータベースの操作を通じて、Webアプリの裏側の仕組みを少しずつ理解できたように思います
- 特に、サーバーはHTMLを返すのではなく、データ（JSON）を返すだけという設計について理解することができました
Linuxを基本からまとめてみた【ハードウェア・ディスク・パーティション・ファイルシステム】

## PCを構成するハードウェア
#### CPU
- PCの頭脳
- 演算処理を実行するための装置
#### RAM
- 処理に必要なデータを一時的に記録する
- メインメモリとも呼ばれる
#### HDD/SSD など
- データやプログラムなどを保存するための記憶領域
- OS などの重要なプログラムを含むこともある

## Linuxから見たハードウェア
#### デバイスファイル
- 接続されたデバイスに対し/dev/以下に対応するデバイスファイルが作成される

#### デバイスファイルの命名
```
HDD,SATA SSDなど
/dev/sda1
※a　検知順
※1　パーティション番号
```
```
光学ディスクドライブなど
/dev/sr1
※1　検知順
```
#### udev
- Linuxカーネル用デバイスファイルの管理ツール
- 1.適切なカーネルモジュールの自動読み込み
- 2.デバイス認識・デバイスファイルの動的作成⇨デバイスを自由に抜き差し可能
- パフォーマンス向上のために並列処理⇨デバイスファイルの名称は変わりうる

## 起動しているシステムの情報とprocディレクトリ
#### procディレクトリ
- メモリ情報⇨/proc/meminfoファイル
- CPU情報⇨/proc/cpuinfoファイル

## カーネルとデバイス
#### Linuxカーネルとは？
- Linux等のOSの中核的機能を果たす
- プロセスがハードウェアにアクセスする際のインターフェースとなる
#### カーネル内部情報を仮想的なファイルシステムをディレクトリに展開
```
/sys/
```
#### カーネル自身の情報をディレクトリに展開
```
/sys/kernel
```
#### カーネルモジュール
- カーネルの機能を拡張するための仕組み
- 必要に応じてロード・アンロードを行う
- デバイスを利用するためのドライバはカーネルモジュールで提供される
#### モジュールのアンロード
```
$ sudo rmmod sr_mod
```
#### モジュールのロード
```
$ sudo insmod sr_mod
```
## PCIデバイスとUSBデバイス
#### PCIデバイス
- コンピュータ内部でデバイスを繋ぐデータ伝送路の一つ
- CPUと周辺機器などを接続するためのもの

#### USBデバイス
- PCと周辺機器の接続に用いられる汎用的な規格

## パーティションとディレクトリの構成
#### マウント
- パーティション領域をディレクトリと関連付けて利用する仕組み
#### fdiskコマンド
- MBRパーティションを構成する
#### パーティション一覧を見る
```
$ sudo fdisk -l [disk]
```
#### パーティション編集
```
$ sudo fdisk <disk>
```
#### partedコマンド
- GPTパーティションを構成する
#### パーティション一覧を見る
```
$ sudo parted -l
```
#### パーティション編集
```
$ sudo parted <disk>
```

#### (LVM)Logical Volume Manager
- 複数の物理ディスクをまたがってパーティションを構成することができる機能

#### ファイルシステム
- ビット情報のどこにどのデータが記録されているか管理する
Linuxで利用できる主なファイルシステム

| ファイルシステム | 特徴 |
| --- | --- |
|ext4|Linuxで以前から利用されているext2やext3の後継ファイルシステム<br>多くのディストリビューションで標準的にされている|
|xfs|RedHot系ディストリビューションで標準的に採用<br>高機能的なジャーナリングファイリングシステムで、ディスクI／Oの高速化機能も実装|
|vfat|Windowsで利用されているファイルシステム<br>さまざまなOSで利用可能<br>Linuxの標準パーティションなどに利用できない|
|iso9660|CDやDVDなどのメディアで利用される|
|tmpfs|メインメモリ上に展開されるファイルシステム|

## ファイルシステムの作成・管理・マウント
#### /dev/sdb1 を ext4 ファイルシステムでフォーマット
```
$ sudo mkfs -t ext4 /dev/sdb1
```
#### ファイルシステムの情報を確認する -l オプション
```
$ sudo tune2fs -l /dev/sdb1
```
#### ファイルシステムにラベルを設定する -L オプション
```
$ sudo tune2fs -L practice /dev/sdb1
```
#### ファイルシステムをマウント
```
$ sudo mount /dev/sdb1 /mnt
```
#### アンマウント
```
$ sudo umount /dev/sdb1
```
#### ラベル名によってマウント
```
$ sudo mount LABEL=practice /mnt
```

## 参考サイト
[新・Linux入門編7(LinuC対策版): ハードウェア・ディスク・パーティション・ファイルシステム](https://paiza.jp/works/linux/new-primer/linux-new-primer-7)
JSON→DTO変換時に例外処理を仕込まず指摘された話

# はじめに
Clientクラスから渡されたJSONをDTOに変換して使う処理をstubクラスのロジックで実装していた。
事前の例外処理を怠っていたせいで、変換時に落ちるトラブルに直面した。
「なぜここで落ちる？」「どの値が悪い？」とデバックに時間を要したので反省と対策をまとめる

# 油断していたコード（Before）
```Java:Sample.java
ObjectMapper mapper = new ObjectMapper();
SampleDto dto = mapper.readValue(json, SampleDto.class); // ここで例外発生
```

# 改善策（After）
### 不明なフィールドを無視する設定を追加
```Java:Sample.java
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
SampleDto dto = mapper.readValue(json, SampleDto.class); 
```
これで 「余計なフィールド」は無視して変換できるようになる。

### try-catch で変換エラーに備える
```Java:Sample.java
ObjectMapper mapper = new ObjectMapper();

try {
    SampleDto dto = mapper.readValue(json, SampleDto.class); 
} catch (JsonProcessingException e) {
    log.error("JSON変換エラー: {}", e.getMessage());
}    

```
どんな理由で落ちたのかログで追えるように。

#  学び
・JSON入力は外部からの「不定形」なデータだと常に意識すべき
・バリデーション・変換の失敗は想定しておくのが基本
・例外がでる場所をあらかじめ潰しておくと、運用後に泣かずに済む
【Python】PEP8のコメントに関するルール

PEP8のコメントに関するルールは以下となります。

【ブロックコメント】
● コードと同じインデントで書く。
● コメント自体は1つの#と1つの空白の後ろに書く。

【インラインコメント】
● コードとコメントの間は1つ以上の空白を置く。
● コメント自体は1つの#と1つの空白の後ろに書く。

【docstring】
● 関数やメソッドの説明はdefの直下に書く。
● """で始まり、"""で終わる行とする。
● 説明が複数行の場合は1行目に要約を書き、1行目の下に空行を開けて説明を書く。
【通信編】TCP/IP説明できる？よわよわエンジニアが教えます

## はじめに

TCP\IPを説明しろと言われて説明できるでしょうか？よわよわエンジニアの私は当然説明できないので調べました。

この記事では、TCP/IPとは何か、その仕組みと役割について、基礎から解説していきます。

---

## TCP/IPとは？

TCP/IPは、**インターネット通信の基本となる通信プロトコルのセット**です。  
正式には「**TCP/IPプロトコルスイート**」と呼ばれ、以下の2つが特に重要な役割を担っています。

- **IP（Internet Protocol）**  
  → データを送る「宛先住所」の指定とルーティングを担当  
- **TCP（Transmission Control Protocol）**  
  → データを「確実に」「順序通りに」届けるための仕組みを提供

---

## TCP/IPの4階層モデル

TCP/IPは階層構造で設計されており、それぞれの層が役割分担をしています。

| 階層                        | 主な役割                             | 対応する技術やプロトコル       |
|-----------------------------|--------------------------------------|-------------------------------|
| アプリケーション層          | 実際に利用者が使う通信の形を定義     | HTTP, FTP, DNS, SMTPなど      |
| トランスポート層            | 通信の信頼性・データの分割と再構成   | TCP, UDP                      |
| インターネット層            | 宛先の決定とルーティング              | IP, ICMP                      |
| ネットワークインターフェース層 | 実際の物理的な通信                    | Ethernet, Wi-Fi など          |

※ OSI参照モデル（7階層）と異なり、TCP/IPは4階層構造で説明されることが多いです。

---

## TCPとUDPの違い（トランスポート層）

| プロトコル | 特徴                                      | 主な用途                        |
|------------|-------------------------------------------|---------------------------------|
| TCP        | 接続確立（コネクション）あり、信頼性が高い | Web通信（HTTP/HTTPS）、メール  |
| UDP        | 接続確立なし、軽量で高速だが信頼性は低い   | 音声通話（VoIP）、動画配信など |

---

## IPの役割（インターネット層）

**IP（Internet Protocol）** は、通信相手を指定するための **住所（IPアドレス）** を使って、  
**データを正しい経路で送る**役割を持ちます。

- 宛先IPアドレスに基づいてパケットを転送
- 複数のルーターを経由して目的地へ到達させる
- 分割されたパケットの管理も行う

---

## 通信の流れ（ざっくり）

たとえば、ブラウザでWebページを開くときは以下のような流れになります：

1. **アプリケーション層（HTTP）**：URLにアクセスする
2. **トランスポート層（TCP）**：接続を確立（3-wayハンドシェイク）
3. **インターネット層（IP）**：相手のIPアドレスにパケットを送る
4. **ネットワーク層（物理層）**：実際の通信（Ethernet/Wi-Fi）

---

## まとめ

- **TCP/IPは、インターネットを支える通信のルールセット**
- **IPは配送ルートを決め、TCPは届いたことを確認**
- **アプリケーションごとに、適切なプロトコルを使い分ける**

TCP/IPの理解は、ネットワークだけでなくWeb開発やサーバ設計にも直結する重要な知識です。  
基礎をしっかり押さえておくことで、トラブルシュートや設計の質が格段に向上します。

---
【Python】pip freeze > requirement.txt

## pip freeze > requirement.txt

実行環境にインストールされているパッケージを、テキストファイルにリストアップする際の記述です。パッケージ名とバージョンを合わせてリストアップできます。

requirement.txtの例
-------------------------------
psycopg2-binary==2.9.1
SQLAlchemy==1.4.20
-------------------------------
テストクラスで契約番号をハードコードして指摘された話

# はじめに
業務で作成したJUnitのテストクラスにおいて、契約番号をハードコードしていたらレビューで指摘を受けました。
「なぜダメなのか」「どう直すべきか」を自分なりに整理してみました。

#  問題のコード（Before）
```Java:Sample.java
@Test
public void test契約情報取得() {
    // Given
    String contractNumber = "4111";

    // When
    String result = target.execute(contractNumber);

    // Then
    assertEquals("OK", result);
}    

```
このコードでは、契約番号 "4111" を直接書いています。これ自体はエラーにもならず、見た目は問題なさそうです。

# なぜハードコードが問題になるのか？
### 意図が伝わらない
`"4111"` がどんな契約番号なのか分からず、読んだ人が「これは何？」「テストの目的は何？」と疑問を抱く。

### 再利用しづらい
他のテストでも契約番号を使いたくなった時に、重複してしまったり、メンテナンスコストが増える。

### 変更に弱い
もしテスト対象の仕様やデータが変わったら、値を変更する箇所が複数になる可能性がある。スケーラビリティに欠ける。

# 改善後のコード（After）
```Java:Sample.java
@Test
public void test契約情報取得() {
    // Given
    // テストデータを共通管理
    String contractNumber = TestDataFactory.createTestContractNumber();

    // When
    String result = target.execute(contractNumber);

    // Then
    assertEquals("OK", result);
}    

```
あるいは、値そのものが重要でなければ、定数にまとめるのもアリです。
```Java:Sample.java

private static final String VAILD_CONTRACT_NUMBER = "4111";

@Test
public void test契約情報取得() {
    // When
    String result = target.execute(VAILD_CONTRACT_NUMBER);

    // Then
    assertEquals("OK", result);
}    

```
# 学びと振り返り
・テストの目的は「動くことの確認」＋「将来的に壊れないことの保証」
・ハードコードは将来の不具合の温床になりやすい
・読む人の視点に立ち、意図が伝わるテストを書くこと
Filamentに Nested Comments プラグイン入れてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943876/15cecd35-fdfb-4c4d-b873-3859e30539d8.png)
https://filamentphp.com/plugins/coolsam-nested-comments

1.composer 経由でパッケージをインストールします。
```
composer require coolsam/nested-comments
```
2.artisanコマンドでnested-commentインストールします。
```
php artisan nested-comments:install
```
3.blogモテルに　commentを追加します。
```
use Coolsam\NestedComments\Concerns\HasReactions;ーー＞ここ追加
class Blog extends Model
{
use HasComments;ーー＞ここ追加

    protected $fillable = [
        'title',
        'status',
        'image',
        'detail',
    ];
}
```

4.blogのinfolistにコメントを追加します。
```
public static function infolist(Infolist $infolist): Infolist
    {
        return $infolist
        ->schema([
                Section::make()
                ->schema([
                TextEntry::make('name')
                    ->prose()
                    ->markdown()
                TextEntry::make('detail')
                    ->prose()
                    ->markdown()
                ]),
            \Coolsam\NestedComments\Filament\Infolists\CommentsEntry::make('comments'),ーー＞ここ追加

    ]);
    }
```
## 追加
reactionを追加したりカスタマイズもできます。
nested-commentsインストールする際にconfigフォルダの中にnested-comments.php作成されるので、
そのファイルに様々なカスタマイズできます。
いいねボタンを追加してみます。
```
    'allowed-reactions' => [
        '👍' => 'thumbs up', // thumbs up
        '👎' => 'thumbs down', // thumbs down
        '❤️' => 'heart', // heart
        '😂' => 'laughing', // laughing
        '😮' => 'surprised', // surprised
        '😢' => 'crying', // crying
        '💯' => 'hundred points', // angry
        '🔥' => 'fire', // fire
        '🎉' => 'party popper', // party popper
        '🚀' => 'rocket', // rocket
        'いいね！' => 'iine', // iine いいね！テキストを追加
    ]
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943876/e2cda40b-464a-4d98-914c-1c540a2a8775.png)
これから色々カスタマイズしてみたいと思います。
同期処理・非同期処理とはなんぞや？

# はじめに
昨日の飲み会で、あれは非同期処理だからいいんだよね〜みたいな話を聞いた。その時は、知ったかぶりをしたけど、翌日気になって朝からこの記事を書いている。今回、同期処理と非同期処理について軽く調べたのでまとめようと思います。

# 同期処理・非同期処理
- 同期処理
タスクを一つずつ順番に実行し、一つが終わるまで次のタスクが開始されない処理。
- 非同期処理
タスクの完了を待たずに、次のタスクに進むことができる処理。

![スクリーンショット 2025-06-21 9.46.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752598/e9435490-8b81-4518-9710-d28c4d8e90d2.png)

# 同期処理・非同期処理の比較表
| 項目 | 同期処理 (Synchronous) | 非同期処理 (Asynchronous) |
| :--- | :--- | :--- |
| **リソース効率** | 待ち時間中はCPUなどのリソースが遊んでしまい、効率が悪い | 待ち時間中に別の処理を実行できるため、リソースを有効活用できる |
| **ユーザー体験** | 時間のかかる処理で、画面が固まる（フリーズする）など応答性が悪化しやすい | 時間のかかる処理があっても、応答性が保たれ、ユーザーは操作を続けられる |
| **コードの書き方** | 処理の順序が明確で、コードが直感的で分かりやすい | 処理の順序が複雑になりがちで、慣れないうちは理解が難しいことがある |
| **主な用途** | ・処理の順序が絶対的に重要な場合<br>・単純なスクリプト<br>・CPUバウンドな（計算中心の）短い処理 | ・I/O処理<br>・GUIアプリケーションのイベント処理<br>・Webサーバーなど多数のアクセスを捌くシステム |

# 終わりに
単純なことしか調べていないが、こういった積み重ねがエンジニアとしての知識を深める大事な行動だと思っている。わからないことがあったらその都度、調べたり質問する。これを怠らなければきっと良い
【Python】pdbモジュール

pdbモジュールを呼び出してプログラムを実行すると、異常終了した際に自動的にデバックモードに移行します。

デバックモードに移行した後、「c」コマンドを実行するとエラー内容が表示されます。

また、「p 変数」で変数の内容を確認できます。
努力を仕組化するぞ①

## はじめに
Qiita初投稿の**yuyu4Tech**と申します。
第１回目の投稿の内容は📖「[努力は仕組化できる](https://bookplus.nikkei.com/atcl/catalog/24/07/23/01501/)」という本の紹介です。
まだ読み始めたばかりですが、本書の内容を自分なりに解釈しながら、章ごとにQiitaへ投稿していく予定です。
まず本稿では、第一章の内容について触れていきます。

## 📖努力は仕組化できる
### Author
山根 承子さん
株式会社パパラカ研究所 代表取締役社長
博士（経済学・大阪大学）。行動経済学を専門とする研究者・実践者。
近畿大学経済学部准教授などを経て、2020年より株式会社パパラカ研究所 代表取締役社長。
行動経済学の理論を、実社会の課題解決に応用することをテーマに、国内外の学術誌や書籍を通して数多くの研究成果を発信している。

### Contents（全10章構成）
- 第1章　「努力」を行動経済学で考える 　**☜ ココ**
- 第2章　「努力が勝手に続く」４つの仕組み
- 第3章　「努力を楽しむ」ことはできるのか
- 第4章　必要な努力が無理なく続く２つのナッジ
- 第5章　「誘惑」と戦う
- 第6章　【努力しない言い訳】と戦う①
- 第7章　【努力しない言い訳】と戦う②　
- 第8章　「環境からの悪影響」と戦う
- 第9章　他人からの低い評価に立ち向かう
- 第10章　人は何故公開するのか？

### 第1章　「努力」を行動経済学で考える
#### 努力って？
努力という言葉の意味を皆様説明できますか？
辞書を引くと以下のような説明が出てきます。
`ある目的の為に力を尽くして励むこと`

#### 努力×行動経済学？
努力にまつわる葛藤は`理性と衝動のせめぎあい`から生まれていると本書では書かれています。
この努力を解き明かすのに相性がいいのが、`理性と衝動`に研究が行われてきた**行動経済学**なのです。

#### 「努力」の経済学的理解（異時点間選択）
我々人間が、死ぬまでに得る幸福度の合計値を最大化するように「今」の選択を行っています。
幸福度の合計値を生涯効用と呼びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4115242/84172fd3-72ad-463f-8614-843f9a1424fa.png)
※図は、「今はつらいけれど将来に報われる努力」か、「今は楽だが将来に停滞する選択」かが対比されています。
努力とは、「今」苦労しても将来の効用（幸福）が大きくなるような選択を取ることになります。
一方もう一つの選択肢は、現在は快適or安定だが、将来の効用が少ないということになります。
人はこの2パターンの未来の間（異時点）に立たされた時に取る「今」の行動によって、生涯効用が変わってくるのです。


#### 「努力」と「時間割引率」
異時点に立たされた際に取る選択には、個人の性質が影響します。
この個人の性質を「**時間割引率**」と呼びます。
「時間割引率」は「待つという**心理的負担（心的コスト）**」の事を指します。
下図に示す例を見てください。右の人は６か月待つことによる心理的負荷が大きく、今得られる満足度を優先にしてしまいがちです。こういう人を時間割引率の高い人と言います。
一方で、左の人のように６か月待つことによる心理的負荷が小さいため、6か月後に得られる満足度を問う人もいます。こういう人を時間割引率の低い人と言います。
（「刹那主義」と「禁欲主義(きんよくしゅぎ)」という言葉が頭をよぎりました。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4115242/130d89df-9947-4548-95e7-6a1bf7611a9f.png)

#### 最良の選択とは？
頭では「最良の選択」がわかっている...
それでも、なぜか行動にうつせない——そんな経験、誰にでもありますよね。
時間割引率の高い人ばかりが良いわけではありません。生涯効用を最大化できる選択を随所で適切に取れていることが最も重要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4115242/43a6c770-587f-4e0f-9214-d080576a1134.png)

#### 努力と意志の力
興味深いのは、努力を継続できない人ほど「意志の力」が必要だと考える傾向がある一方で、努力を継続できている人は、そもそも努力を「努力」と感じておらず、「意志の強さ」をあまり意識していないという点です。
意志の力を鍛えることは困難であり、いろいろな外部要因によって左右されてしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4115242/48c1246c-6cb1-4808-a6e7-add2cdf630f8.png)

### まとめ
- 「努力」は、将来の幸福（効用）を最大化するために「今」をどう選ぶかという、**経済学的な選択行動**である。

- このような選択には「**時間割引率（待つことの心理的コスト）**」が影響し、人によって選び方が異なる。

- 努力を継続できている人は、努力を努力と感じておらず、意志の強さも意識していない傾向がある。

第2章からは、「意志の力に頼らずに努力を継続する」ための具体的な仕組みづくりに焦点が当てられていきます。
果たして、どうすれば努力を“無意識に続けられるもの”にできるのか——
そのヒントを、第2章でさらに深掘りしていきます！

### おわりに
本書は、努力を自然と続けるための実践的なヒントを行動経済学の視点から提示してくれています。
本書を読むきっかけは、ある方に勧めていただき、実際に本を貸してくださったこと、  
さらに「記事を書いてみては？」と背中を押してくれたことでした。
本書から「継続の仕組み化」を学び、自分の生活の中に取り入れて
「Qiitaの記事を書くこと」を続ける仕組みを作り習慣化することが、私のファーストステップです。
果たして、２投稿目が公開される未来はくるのか....🦉?
【可視化編】カロリー予測データの分布と相関をグラフで徹底分析

## はじめに
- 前回はEDAでデータの構造や特徴量の作成を行った
- 今回はグラフによって、変数の分布や相関関係を詳しく見ていく


## 1. 数値変数の分布と箱ひげ図

各数値変数について、ヒストグラムと箱ひげ図で分布を確認しました。

```python
numeric_graph = train_df.drop(["id" , "Calories"] , axis = 1).select_dtypes(include= ["number"]).columns
palette = sns.color_palette("tab10", len(numeric_graph))
color_dict = dict(zip(numeric_graph, palette))
fig = plt.figure(figsize=(40 , 8 * len(numeric_graph)))
gs = gridspec.GridSpec(len(numeric_graph) , 2 , figure = fig)

for i , col in enumerate(numeric_graph):
    ax_hist = fig.add_subplot(gs[i,0])
    
    #少数含む
    if col in ['Number of Dependents']:
        sns.histplot(data = train_df, x=col , discrete = Truem, ax = ax_hist, color= color_dict[col])
    #整数のみ
    else:
        sns.histplot(data = train_df, x=col , bins = 30, ax = ax_hist, color = color_dict[col] )
    
    ax_hist.set_title(f"Distribution of {col}", fontsize = 35)
    ax_hist.set_xlabel(col, fontsize = 30)
    ax_hist.set_ylabel("count",fontsize = 30)
    ax_hist.tick_params(axis = "both" , labelsize = 30)
    
    #ボックスプロット
    ax_box = fig.add_subplot(gs[i,1])
    sns.boxplot(data = train_df, x=col, ax=ax_box, color=color_dict[col] )
    ax_box.set_title(f"Boxplot of {col}", fontsize = 35)
    ax_box.set_xlabel(col,fontsize=30)ax_box.set_xlabel(col,fontsize=30)
    ax_box.set_ylabel("Value", fontsize=30 )
    ax_box.tick_params(axis="both", labelsize=30)

plt.tight_layout()
plt.show()
```
## 2. 相関ヒートマップ（全体）

数値変数同士の相関を確認するため、ヒートマップを作成しました。

```python
numeric_df = train_df.drop(["Calories"] , axis = 1).select_dtypes(include=['number'])
corr = numeric_df.corr(numeric_only=True)  
target_corr = corr[["Calories_log"]].sort_values(by="Calories_log", ascending=False)
plt.figure(figsize=(50,50))
ax = sns.heatmap(
    target_corr,
    annot=True,
    fmt=".2f",
    cmap='Blues',
    square=True,
    annot_kws={"size": 30, "weight":"bold"}
    )
# 横軸（x軸のラベルと目盛り）を上に移動
ax.xaxis.set_ticks_position("top")
ax.xaxis.set_label_position("top")

# さらに間を空ける（必要なら）
plt.xticks(rotation=45, fontsize=20 , ha='left', fontweight = "bold")
plt.yticks(fontsize=30, fontweight = "bold")

plt.title('corr', fontsize=20, pad=20)  # タイトルに余白を追加
plt.tight_layout()
plt.show()
```


## 4. CaloriesとCalories_logの分布比較

```python
sns.histplot(train_df["Calories"], kde=True, bins=50)
plt.title("Distribution of Premium Amount")
plt.show()

sns.histplot(train_df["Calories_log"], kde=True, bins=50)
plt.title("Distribution of Premium Amount")
plt.show()
```

## まとめ

本記事では、カロリー予測データに対して以下の可視化を行いました：

- ヒストグラム＆箱ひげ図による変数の分布確認  
- 相関ヒートマップで有効な特徴量の候補を探索  
- 対数変換による目的変数の正規化効果の確認  

次回はこれらの知見を活かして、実際にLightGBMなどのモデルで予測精度を上げていく工程を紹介します。
JWT認証の仕組みとは何か？改ざんを防ぐ仕組みを理解する

# はじめに 
アクセストークンによる認証方式の一つである「JWT（JSON Web Token）」の仕組みについて整理する。

---

## JWTの基本

JWTは次の3つの部分で構成されている。

```
<ヘッダー>.<ペイロード>.<署名>
```

それぞれの役割は以下の通り。

* ヘッダー：アルゴリズム情報（例：HS256など）
* ペイロード：ユーザーIDなどの認証情報
* 署名：改ざんされていないことを検証するための指紋のようなもの

---

## サーバーはトークンの何を検証しているのか？

クライアントはサーバーから受け取ったJWTを、以後のリクエストに添えて送る。

サーバー側で `@jwt_required()` のような仕組みを使うと、以下の流れでトークンを検証する。

1. トークンを `ヘッダー.ペイロード` と `署名` に分解する
2. サーバーが持つ秘密鍵（`SECRET_KEY`）を使って、ヘッダーとペイロードを元に署名を再計算する
3. トークン内の署名と、サーバー側で再計算した署名が一致するかを比較する

一致すれば「改ざんされていない＝サーバーが過去に発行したもの」と見なされる。

---

## 改ざんはどう検出されるのか？

仮にユーザーがトークン内の `user_id` を書き換えて不正にアクセスしようとした場合、`ペイロード`が変更されたため、サーバーが再計算する署名とトークンに含まれている署名が一致しなくなる。結果としてトークンは無効と判断され、アクセスは拒否される。

この仕組みによって、JWTは「内容を保持しつつ、改ざんを防ぐ」ことができている。

---

## サーバーは状態を持たない

JWTの特徴は「ステートレス」なこと。サーバーはセッション情報を保持する必要がなく、毎回トークンの署名を検証するだけで認証処理が完結する。そのため、サーバーのスケーラビリティが高く、大規模サービスにも向いている。

---

## 注意点

* JWTの内容はBase64エンコードされているだけで暗号化されていないため、機密情報を入れるべきではない
* トークンが漏洩すれば第三者が不正アクセスできるため、有効期限やリフレッシュトークンと組み合わせた対策が必要

---

## まとめ

JWTは「署名」という仕組みを通じて、ユーザー情報が改ざんされていないことを保証する。サーバーは毎回トークンを受け取り、内部の署名を検証することで、改ざんされていないことを確認している。

この仕組みによって、セッションを持たずに安全かつ効率的な認証処理が可能になっている。
【Python】Mock、MagicMock

MagicMockには、モックの呼び出し状況を確認するメソッドがあります。

assert_called_once()は、モックが1回だけ呼ばれていた場合はNoneを返し、2回以上呼ばれていた場合はAssertionErrorを返します。

assert_called_with()は、指定した引数のモックが直前に呼ばれていた場合はNoneを返し、直前ではない場合、もしくは1回も呼ばれていない場合はAssertionErrorが返ります。
学習17日目

# 今日学んだこと
プルダウンで選んだ属性での検索機能の実装

# 内容
下記手順で実装。
① ルーティングの記述
(例) config/routes.rb
```
get "search" to: "hoges#search"
```
② コントローラの記述
ここではまず、searchメソッドを定義し、処理は書かなくてOK。
(例)app/conrollers/hoges_controller.rb
```
def search

end
```

③ viewの記述
(例)app/views/hoges/index.html.erb
```
<%= form_with url: hoge_search_path, method: :get do |form| %>
  <%= form.select :input_category, ["氏名", "年齢", "出身地"] %>
  <%= form.text_field :input_word%>
  <%= form.submit "検索"
<% end %>
```
※パスはrails routesコマンドで確認し、適切なものを選択する。

④ コントローラの記述
(例)app/controllers/hoges_controller.rb
```
   def search
       if params[:input_category] == "名前"
           @search_results = Hoge.where("name LIKE ?", "%#{params[:input_word]}%")
       elsif params[:input_category] == "年齢"
           @search_results = Hoge.where("age LIKE ?", "%#{params[:input_word]}%")
       else
           @search_results = Hoge.where("come_from LIKE ?", "%#{params[:input_word]}%")
       end
   end
```
※キー名はviewで定義したものと一致させる
※LIKEの部分はカラム名と一致させる

# 感想
Qiitaを書いていて、params[:input_category]という記述が繰り返されていることに気づいた。
条件分岐の前に変数に代入してすっきりさせると可読性が更に向上すると感じた。

# 余談
最初「等しい」を表す論理演算子を「==」でなく「=」と記述していたので、正しく条件分岐されず困りました。
STUDIOのフォーム送信をトリガーに、Google Apps ScriptでLINE Bot通知を飛ばす仕組みを作った話

こんにちは。tampopo256です。
普段は教育系のWebサービスを作ったりしています。

## 📬 なぜこの記事を書こうと思ったか

STUDIOでランディングページを作っている中で、「問い合わせフォームの通知どうしよう？」という話に。
STUDIOはフォーム送信後にGoogleスプレッドシートと連携できるので、
「だったらスプレッドシートの変更をトリガーにして、LINEに通知すればよくない？」と気づいたのが始まりです。

当初はZapierやIFTTTも検討しましたが、どうしても柔軟性や費用に不満があったので、**GAS + LINE Botで自作した記録**を共有します。


## 💡 背景と前提

### やりたいこと

1. STUDIOのフォーム → Googleスプレッドシートに連携（フォーム送信が追記される）
2. その「行の追加」をトリガーにGoogle Apps Scriptが動作
3. LINE Bot（Messaging API）経由で、自分（またはチーム）に通知を飛ばす

### 使用技術

| 技術                 | 用途              |
| ------------------ | --------------- |
| STUDIO             | フォーム送信UI        |
| Google スプレッドシート    | フォーム受信データの保存先   |
| Google Apps Script | 通知処理の実行         |
| LINE Messaging API | 通知の送信（LINE Bot） |

## 🛠 実装手順

### 1. LINE Botを作成

* LINE Developersで「Messaging API」チャネルを作成
* 長期チャネルアクセストークンを発行
* Botを自分のLINEに友だち追加
* 自分の**LINEユーザーID**を取得（BotにWebhook経由で喋らせて確認する or LIFFで取得）

### 2. GASで通知スクリプトを書く

以下はスプレッドシートに新しい行が追加されたときにLINE通知を送るGASコードです。

```javascript
const CHANNEL_ACCESS_TOKEN = 'CHANNEL_ACCESS_TOKEN';
const TO_USER_ID = 'YOUR_LINE_USER_ID';

function onFormSubmit(e) {
  const sheet = SpreadsheetApp.getActiveSheet();
  const lastRow = sheet.getLastRow();
  const rowData = sheet.getRange(lastRow, 1, 1, sheet.getLastColumn()).getValues()[0];

  const name = rowData[0]; // 1列目に名前
  const email = rowData[1]; // 2列目にメール
  const message = rowData[2]; // 3列目にメッセージ

  const text = `
📨 STUDIOフォームに回答がありました！

👤 名前: ${name}
📧 メール: ${email}
📝 内容: ${message}
`;

  sendLineMessage(TO_USER_ID, text);
}

function sendLineMessage(toUserId, text) {
  const url = 'https://api.line.me/v2/bot/message/push';

  const payload = JSON.stringify({
    to: toUserId,
    messages: [{ type: 'text', text }]
  });

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      'Authorization': `Bearer ${CHANNEL_ACCESS_TOKEN}`
    },
    payload
  };

  UrlFetchApp.fetch(url, options);
}
```


### 3. トリガーを設定

* GASの「トリガー」から、関数：`onFormSubmit`
* イベントの種類：**スプレッドシート → スプレッドシート更新時**
* これで、新しいSTUDIOのフォーム入力が来るたびにLINE通知が飛びます


## 🧠 学びと気付き

* STUDIO → スプレッドシートの連携は「通知のトリガー」に使える
* LINE Notify終了後もBotなら代替できる。**Messaging API最強説**
* GASの`onFormSubmit`トリガーが非常に優秀。Zapierなどの有料サービスを使わなくても通知ができる

## ✅ まとめ

* STUDIOのフォーム送信は、スプレッドシート経由でGASトリガー化できる
* GASからLINE Botを使えば、自由なメッセージ通知が可能
* LINE Notify終了の今、Bot + GASは有効な選択肢

## 🔄 追記：こんな応用もできそう

* LINEだけでなくSlack通知やメール送信も追加可能（GAS次第）
* n8nなどのノーコードツールと組み合わせても良さそう
* フォームの内容で通知をフィルター・分類することで担当分けも可能

## 📣 最後に

STUDIOを使っていて、「問い合わせを即座にLINEで知りたい」という人には
この構成、めちゃくちゃおすすめです。

わからないことがあれば、ぜひコメントください！必要なら「ユーザーIDの取得方法」や「複数人に通知する方法」も記事にします！
[kaggle初心者] Calories予測コンペで機械学習を練習してみた（EDA）

#コンペ概要：Calories Burnt Prediction（Kaggle Playground）

本記事は、KaggleのPlaygroundコンペティションになります。  
「Calories Burnt Prediction」に取り組んだ内容をまとめたものです。

コンペ名    ：Predict Calorie Expenditure 
URL　　　　 ：[https://www.kaggle.com/competitions/playground-series-s5e5]
開催時期　　：2025年5月 〜 6月（1か月開催）  
タスクの種類：回帰予測（Regression）
目的変数    ：Calories（消費されるカロリー）  
評価指標    ：Root Mean Squared Error（RMSE）

このコンペは初心者向けに設計されており、 体の特徴データ（年齢・体重・身長・運動時間・心拍数・体温）を使用して消費カロリーを数値予測するというテーマです。

機械学習のことについて書籍で勉強していましたが、実践形式でアウトプットするために、KaggleのPlaygroundシリーズに参加しました。
Playgroundシリーズは機械学習の練習用のコンペであり、まずは完走して、機械学習の基本ステップを体験する」ことが目的です。

このコンペを通じて以下のようなことを学ぶことを目的に取り組みました。

- EDA（探索的データ分析）の実践  
- 特徴量エンジニアリングの考え方  
- モデル比較（LightGBM / CatBoost / XGBoost）  
- パラメータチューニング（Optuna）  
- Stackingによるアンサンブルの導入

全体を通じて

記事は以下の3部構成で分けて投稿する予定です：

1.EDA編（データ理解・特徴量設計）
2.可視化編（分布や相関の可視化）
3.モデル編（モデル構築〜精度改善）

まず今回はEDA編として、データの中身を確認し、どんな特徴量を作ったかを中心に紹介していきます。

# 1. データの読み込み
本記事では、ローカルに保存した`./data/train.csv`および`./data/test.csv`を使用しています。
再現の際は、任意のパス名を指定して下さい。

```python
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
train_data = pd.read_csv ("./data/train.csv")
test_data = pd.read_csv ("./data/test.csv")
train_df = train_data.copy()
test_df = test_data.copy()
```

読み込んだら、先頭の数行を確認します。
```python
train_df.head()
test_df.head()
```

それぞれのカラムのデータ型や欠損状況を確認します。
```python
train_data.info()
print("train data: \n" + str(train_df.isnull().sum()) + "\n")
print("test data: \n" + str(test_df.isnull().sum()) + "\n")
```
今回のデータには欠損値はありませんでした。



重複データの確認をします。
```python
train_duplicates = train_df.duplicated().sum()
print("train data duplicates: " , train_duplicates)

test_duplicates = test_df.duplicated().sum()
print("train data duplicates: " , test_duplicates)
```
数値変数の偏りを確認
→ 目的変数（カロリー）の偏り大きい
→ 右に歪んだ分布をしていたため、対数変換して正規性を改善
```python
print(train_df[numeric_columns].skew())
`````````
# 2. 特徴量エンジニアリング
以下のように、数値特徴量同士を掛け合わせた特徴量を作成しました。

```python
cols = ["Age", "Weight", "Height", "Duration", "Heart_Rate", "Body_Temp"]
for data in [train_df, test_df]:
    for i in range(len(cols)):
        for j in range(i + 1, len(cols)):  # i != j かつ順序固定
            col1 = cols[i]
            col2 = cols[j]

            # 除算（col1 / col2）
            new_col_div = f"{col1}_div_{col2}"
            data[new_col_div] = data[col1] / (data[col2] + 1e-6)  # ゼロ割対策

            # 積算（col1 * col2）
            new_col_mul = f"{col1}_mul_{col2}"
            data[new_col_mul] = data[col1] * data[col2]

train_df["BMI"] = train_df["Weight"] / (train_df["Height"]/100)**2
test_df["BMI"] = test_df["Weight"] / (test_df["Height"]/100)**2
train_df["Calories_log"] = np.log(train_df["Calories"])

```

# 3.変数名の抽出
```python
#数値変数のみ抽出
numeric_columns = train_df.select_dtypes(include = ["number"]).columns.sort_values(ascending=True)
print ("numeric columns: \n" , numeric_columns.tolist() )

#文字変数のみ抽出
chara_columns = train_df.select_dtypes(include = ["object" , "category"]).columns
print ("character columns: \n" , chara_columns.tolist())
```


次回は、これらの変数を**グラフで可視化**していきます。  
分布や相関から、より有効な特徴量を見つけていきます。
Gmailの新着メールをDiscordに通知してみた【GAS × Discord Webhook】～LINE Notify終了からの乗り換え〜

こんにちは。tampopo256です。
普段は教育系のWebサービスを作ったりしています。

## はじめに ～プライベートGmail × LINE Notify依存民の悲劇～

個人のGmailアカウントで、Amazonの配送通知や家族・サークル関連の連絡をLINEで通知していたのですが──

2024年3月、ついにこの瞬間が訪れました。

> **LINE Notify サービス終了**

地味に愛用していたのに……。
「新着メールがLINEに飛ばなくなったけど何で!?」と気づいた時のショックたるや。

とはいえ、LINEに代わる通知先が必要です。
LINEよりよく使うチャットアプリ、それが「**Discord**」でした。

というわけで今回は、**Google Apps Script（GAS）を使って、Gmailの新着メールをDiscordに通知する方法**を紹介します。

---
:::note info
何としても引き続きLINEに通知したい方はこちらをご覧ください。
月200通までの制限があるため、件数が少ない方お勧めです。
:::
https://qiita.com/tampopo256/items/d4b56cfdbe1c64c866a5


## 背景と前提

### 📌 目的

* プライベートGmailの通知（家族、ネット通販、イベントなど）をLINEの代わりにDiscordへ
* 通知を逃したくないけど、アプリを増やしたくもない
* GASとWebhookだけでサーバーレスに実現したい

### 🛠 使用技術

* Google Apps Script（Gmailチェック＆通知送信）
* Discord Webhook（チャンネルへの通知）

### 🔑 前提

* Discordサーバーと通知チャンネルを持っている
* Webhookを発行できる権限がある


## ステップ① Discord Webhookの作成

1. Discordの通知したいチャンネルを開く
2. 歯車（チャンネル編集）→「連携サービス」→「Webhookを作成」
3. 任意の名前とアイコンを設定
4. **Webhook URLをコピー**しておく（例：`https://discord.com/api/webhooks/...`）


## ステップ② GASで通知スクリプトを作る

Googleドライブから「スクリプトファイルを作成」して以下を記述：

```javascript
const DISCORD_WEBHOOK_URL = 'https://discord.com/api/webhooks/xxxx/yyyy'; // 取得したWebhook URLに置き換え

function notifyNewEmailsToDiscord() {
  const threads = GmailApp.search('is:unread newer_than:10m');
  
  for (const thread of threads) {
    const messages = thread.getMessages();
    
    for (const message of messages) {
      if (!message.isUnread()) continue;
      
      const subject = message.getSubject();
      const from = message.getFrom();
      const body = message.getPlainBody().slice(0, 200); // 本文冒頭だけ

      const content = `📩 **新着メール**\nFrom: ${from}\nSubject: ${subject}\n\n${body}`;
      sendDiscordWebhook(content);

      message.markRead(); // 通知済みとして既読に
    }
  }
}

function sendDiscordWebhook(message) {
  const payload = { content: message };

  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload),
  };

  UrlFetchApp.fetch(DISCORD_WEBHOOK_URL, options);
}
```


## ステップ③ トリガーで定期実行を設定

1. GASエディタ画面 → 左メニュー「時計マーク」（トリガー）をクリック
2. `notifyNewEmailsToDiscord` を選び、5〜10分ごとの「時間主導型トリガー」に設定


## 実際に使ってみての感想

### ✅ よかった点

* Discordに通知を集約できて便利
* GASだけで動くので、無料でメンテ不要
* LINE Notifyより**メッセージ構造を自由に書ける**

### ❗ 注意点

* Gmailの無料アカウントはAPI制限がある（数百回/日）
* Discordの1投稿は2000文字以内に制限されている
* 通知が多すぎるとDiscordチャンネルが荒れる（件数制御を推奨）

## まとめ

* LINE Notify終了後も、**GAS × Discord Webhookで代替可能**
* 個人メール通知用途でも十分実用的
* DiscordはSlackやLINEより通知専用Botの導入が気軽
* GAS + Discord = ノーサーバー通知のベスト組み合わせ
Crystal で Int32 や Float64 など数値をまとめて引数に取る場合

タイトルの通りです。
Rubyのような動的言語だといい感じに数値を処理してくれるので、Crystalでどのすればいいか案外たどり着かないと思って記事化しました。

### オーバーロード

まずは、大前提としてのオーバーロードです。
型によって条件分岐が発生するときはこれがベストでしょう。

```cr
def your_method(x : Int32)
end

def your_method(x : Int64)
end

def your_method(x : Float32)
end

def your_method(x : Float64)
end
```

### `Int` と `Float`

整数と浮動小数点をまとめて引数に取りたい場合は、`Int` と `Float` が使えます。

```cr
def your_method(x : Int)
  @x = x.to_i64
end

def your_method(x : Float)
  @x = x.to_f64
end
```

### `Number` - 整数も、浮動小数点数もすべて引数に取る

```cr
def your_method(x : Number)
  @x = x.to_i32 # 例
end
```

これで任意の型の数値を取ることができます。

### `BigDecimal` と `BigFloat` を引数に取りたい場合

このほかに特殊な型として `BigDecimal` `BigFloat` があります。これらは、`Number`を継承しません。なのでこれらを `Number` と一緒に扱う場合はオーバーロードが必要です。

BigDecimalが十進数の計算に適しておりCrystalで実装されているのに対して、BigFloatはGMPを内部で利用しており任意制度の二進浮動小数点の計算に向いているそうです。金融計算ではBigDecimal、科学計算ではBigFloatを使うといいみたいですね。

### Crystalの数値型のまとめ

- `Number` (抽象基底型)
  - `Int` (整数の抽象基底型)
    - `Int8`, `Int16`, `Int32`, `Int64`, `Int128`
    - `UInt8`, `UInt16`, `UInt32`, `UInt64`, `UInt128`
  - `Float` (浮動小数点の抽象基底型)
    - `Float32`, `Float64`

`BigDecimal`と`BigFloat`は独立した型として定義されており、`Number`を継承しない。

---

この記事は以上です。
Gmailの新着メールをLINE公式Botで通知する方法【GAS × Messaging API】

こんにちは。tampopo256です。
普段は教育系のWebサービスを作ったりしています。


:::note alert
LINE Notify終了のため、月200件以上の通知は無料では送信できません...
SlackやDiscordに通知を飛ばすことをお勧めします。
:::


## はじめに ～「あれ、LINEに通知が来ない？」～

2024年3月某日。
個人のメールをLINEに転送していたところ...

調べてみたところ、まさかの事実が判明。

> **LINE Notifyが2024年3月で終了していた**。

LINE Notifyを使っていた自動通知の仕組みはすべて停止。
でも「GmailをLINEに通知したい」というニーズは変わらない──。

今回は、**LINE Notifyの後継としてLINE公式Bot（Messaging API）を使い、GASからGmail通知をLINEに送る方法**をまとめます。


## 背景と前提

### やりたいこと

* Gmailで特定の条件に合うメール（例：未読、特定アドレス）を受信
* その内容を**LINEに自動通知**
* 通知は個人LINEでも、チームグループでも可

### 使う技術

* Google Apps Script（Gmail監視スクリプト）
* LINE Messaging API（Bot作成とPush通知）
* Webhookは使わず**GASからPush APIで送信**

## ステップ① LINE Botアカウントの作成

### 1. LINE Developersに登録・ログイン

[https://developers.line.biz/console](https://developers.line.biz/console)

### 2. プロバイダーを作成

* 名前は何でもOK（例：`通知Bot`）

### 3. チャネルを作成（Messaging API）

* チャネルタイプ：Messaging API
* Webhookは一旦OFFでOK
* 作成後、「チャネルアクセストークン（長期）」をコピー
  → これがGASからの認証に必要

## ステップ② Botと自分（通知対象ユーザー）を友だちにする

1. チャネル設定ページの「QRコード」から、Botを友だち追加
2. さらに、通知先のユーザーIDを取得する必要があります

## ステップ③ GASでユーザーIDを取得する（1回限り）

GASに一時的にWebhookを作成して、LINEから受信した内容をログ出力：

```javascript
function doPost(e) {
  const json = JSON.parse(e.postData.contents);
  const userId = json.events[0].source.userId;
  Logger.log('User ID: ' + userId);
  return ContentService.createTextOutput('OK');
}
```

GASをデプロイ → Webhook URLに設定 → Botに「こんにちは」と話しかける → `userId` がログに出力されます。

## ステップ④ Gmail通知スクリプトを作成する

```javascript
const LINE_ACCESS_TOKEN = 'チャネルアクセストークン';
const TO_USER_ID = '取得したユーザーID';

function notifyNewGmail() {
  const threads = GmailApp.search('is:unread newer_than:10m');
  for (const thread of threads) {
    const messages = thread.getMessages();
    for (const message of messages) {
      if (!message.isUnread()) continue;

      const subject = message.getSubject();
      const from = message.getFrom();
      const body = message.getPlainBody().slice(0, 100);

      const text = `📩 Gmail新着\nFrom: ${from}\nSubject: ${subject}\n---\n${body}`;
      sendLineMessage(text);
      message.markRead(); // 通知済みマーク
    }
  }
}

function sendLineMessage(text) {
  const url = 'https://api.line.me/v2/bot/message/push';
  const payload = {
    to: TO_USER_ID,
    messages: [{ type: 'text', text }],
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      Authorization: `Bearer ${LINE_ACCESS_TOKEN}`,
    },
    payload: JSON.stringify(payload),
  };

  UrlFetchApp.fetch(url, options);
}
```

---

## ステップ⑤ 定期実行トリガーを設定する

GASのメニューから「トリガー」 → `notifyNewGmail()` を5分ごとに設定すれば完了。


## 実運用して感じたこと

* ✅ LINE Notifyより自由度が高く、通知の内容や送信先も自在
* ❗ Messaging APIは無料枠（月200通）を超えると送信不可
* ❗ 通知相手はBotと「友だち」でないと通知不可
* 💡 BotをチームLINEグループに招待すれば、**複数人通知も可能**

## まとめ

* LINE Notifyは**2024年3月に完全終了済み**。もう使えません
* Gmail通知をLINEに送るには、**Messaging APIのPush機能**が現実解
* GASとの連携で、ノーサーバー・無料枠運用が可能
* 早めにLINE Botへの移行を！
正規化（Normalization）とは（超基礎）

# はじめに
「アジャイルデータモデリング」を読み始めたが、そもそもER図や正規形の話をあまり理解していなかった。調査した結果を下記にまとめる。

## ■ 結論（まとめ）

**正規化とは**：データの重複や矛盾を防ぎ、安全なデータ更新ができる形に整えること  

**正規化を行う目的** ：
- データの重複（冗長性）をなくす  
- データの矛盾を防ぐ（整合性維持）  
- 更新や削除時の不具合を防ぐ  

**正規化の段階と内容：**  
- **1NF**：カラムに複数の値を入れず、1セル＝1つの値とする  
- **2NF**：複合キーの一部だけに依存するカラムは切り出す  
- **3NF**：非キー同士で依存関係があるカラムは切り出す  

**現場での使い分け(アジャイルデータモデリングの話)：**  
- **ビジネス実行（OLTPなど）**：3NFまで整えるのが基本  
- **ビジネス評価（DW/BIなど）**：意図的に「非正規化」するケースもある（スタースキーマ）


## ■ 正規化の目的

### ① データの重複（冗長性）の排除

**同じ情報があちこちに重複して存在する状態をなくす**
- データが無駄に膨れ上がるのを防ぐため
- 同じ情報を「すべて探して更新」する必要を防ぐため  

#### 【例】山田さんの住所が何度も入っていて「冗長」

| 注文ID | 顧客名 | 顧客住所  | 商品名 |
|--------|--------|-----------|--------|
| 001    | 山田   | 東京都千代田区 | リンゴ |
| 002    | 山田   | 東京都千代田区 | バナナ |


---

### ② データの整合性（矛盾防止）の確保

**矛盾したデータが発生しないようにする**
- 1つの情報が複数箇所に存在すると矛盾が起きやすいため  

#### 【例】

| 顧客ID | 顧客名 | 顧客住所  |
|--------|--------|-----------|
| C01    | 山田   | 東京都千代田区 |
| C01    | 山田   | 東京都港区 ← どっちが正？ |

---

### ③ データ操作（更新・削除など）の安全性の向上

**更新や削除時に意図しないデータ欠損や不整合が起きないようにする**
- 関連データが密結合になっていると、誤って重要な情報まで削除してしまう可能性があるため  

#### 【例】「注文002」を削除 → 山田さんの顧客情報も消えてしまう危険

| 注文ID | 顧客名 | 顧客住所  | 商品名 |
|--------|--------|-----------|--------|
| 001    | 田中   | 東京都渋谷区 | リンゴ |
| 002    | 山田   | 東京都千代田区 | バナナ |

---

### ■ 目的まとめ表

| 目的 | 簡単な言い換え |
|------|-----------------|
| ① 重複排除 | データが「スリム」になる |
| ② 整合性確保 | データが「正しく一貫性を持つ」 |
| ③ 操作安全性向上 | データが「壊れにくくなる」 |

---

## ■ 正規化の段階（1NF〜3NF）

### ● 1NF（第1正規形）

**カラムに複数の値を入れてはいけない**  

#### 【NG例】

| 注文ID | 商品名           |
|--------|------------------|
| 001    | リンゴ, バナナ   |

#### 【OK例】

| 注文ID | 商品名  |
|--------|---------|
| 001    | リンゴ  |
| 001    | バナナ  |

---

### ● 2NF（第2正規形）

**複合キーの一部だけに依存するカラムは切り出す**  


#### 【NG例】

| 注文ID（主キー） | 商品ID（主キー） | 商品名  | 注文日      |
|--------|--------|---------|-------------|
| 001    | A01    | リンゴ  | 2024-06-01  |
| 001    | A02    | バナナ  | 2024-06-01  |

**注文日** は「注文ID」にしか依存しており、商品ID には依存していない

#### 【OK例】
**複合キー（注文ID, 商品ID）の一部（注文ID）だけに依存するカラム（注文日）** を「注文テーブル」に切り出した

##### 注文テーブル

| 注文ID | 注文日      |
|--------|-------------|
| 001    | 2024-06-01  |

##### 注文詳細テーブル

| 注文ID | 商品ID | 商品名  |
|--------|--------|---------|
| 001    | A01    | リンゴ  |
| 001    | A02    | バナナ  |  

### ● 3NF（第3正規形）

**非キー同士で依存関係があるカラムは切り出す**  

#### 【NG例】

| 商品ID（主キー） | 商品名  | 商品カテゴリID | 商品カテゴリ名 |
|--------|---------|----------------|----------------|
| A01    | リンゴ  | C01            | 果物           |
| A02    | バナナ  | C01            | 果物           |
| A03    | キャベツ | C02            | 野菜           |

**「商品カテゴリID → 商品カテゴリ名」** という依存関係が埋め込まれている
- 商品カテゴリ名が **商品カテゴリID から決まる情報** にも関わらず、行ごとに保持している  
- **カテゴリ名を変更したい時、全ての行を更新する必要** が出てしまう  

#### 【OK例】
**「商品カテゴリID → 商品カテゴリ名」の依存関係** を別テーブルに切り出すことで**変更や追加に強いテーブル構造** になる
##### 商品カテゴリテーブル

| 商品カテゴリID | 商品カテゴリ名 |
|----------------|----------------|
| C01            | 果物           |
| C02            | 野菜           |

##### 商品テーブル

| 商品ID | 商品名  | 商品カテゴリID |
|--------|---------|----------------|
| A01    | リンゴ  | C01            |
| A02    | バナナ  | C01            |
| A03    | キャベツ | C02            |
---

## ■ 正規化はどこまでやるべき？

- ビジネス実行（OLTPなど）は3NFまで整えるのが基本
- DW/BIは逆に「崩す」こともある（クエリのしやすさやパフォーマンス重視）
ChatGPTを使用したアプリ開発記【投稿一覧画面で投稿時間を降順で表示】

## 投稿ページでserverTimestampを取得
```PostPage.js
import { serverTimestamp } from "firebase/firestore";

const newPost = {
  uid: user.uid,
  text,
  createdAt: serverTimestamp(), // ← 追加（投稿日時）
  likes: 0,
  user: user.email,
  displayName: resolvedName,
  photoURL: resolvedPhoto,
  imageUrl,
  videoUrl,
  comments: [],
  draftComment: ''
};
```
## 投稿一覧取得時に「createdAt」で降順にソート
```Home.js
import { collection, getDocs, query, orderBy } from "firebase/firestore";

const fetchPosts = async () => {
  try {
    const postsCollection = collection(db, "posts");
    const q = query(postsCollection, orderBy("createdAt", "desc"));  // ← ここで降順指定
    const snapshot = await getDocs(q);

    setDebugInfo(`Firestore投稿件数: ${snapshot.size} 件`);

    // 以降は同じコードでOK
    const postsData = await Promise.all(snapshot.docs.map(async (docSnap) => {
      //...
    }));

    setPosts(postsData);
    setDebugInfo(prev => prev + `\n読み込み成功: ${postsData.length} 件の投稿を取得`);
    setLoading(false);
  } catch (err) {
    setDebugInfo(`❌ 投稿取得エラー: ${err.message}`);
    console.error("Error getting posts:", err);
  }
};
```

## UI

![スクリーンショット 2025-06-01 11.21.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1058366/91434ef8-0922-40e1-8b2d-527cb140629b.png)
セキュリティ確認・監査項目での業務用ノートPCのローカルストレージ（HDD/SSD）暗号化

# 企業間取引や外部委託・業務委託契約の際のセキュリティ確認・監査項目での業務用ノートPCのローカルストレージ（HDD/SSD）暗号化

1. 情報セキュリティ審査（ISMSやプライバシーマーク取得企業との取引）
取引先がISMS（ISO/IEC 27001）やPマークを取得している場合、委託先のセキュリティ水準の確認が義務づけらる。
その一環で「業務PCの暗号化の有無」が確認される。
2. 機密情報を扱う業務委託・BPO契約の締結前
個人情報や営業秘密を扱う場合、端末の盗難や紛失時の情報漏洩防止策として、暗号化の有無がチェックされる。
3. 委託元からのセキュリティチェックシート提出時
企業から「情報セキュリティチェックシート」や「ベンダー評価シート」の提出を求められ、その中に含まれていることが多い。
4. 官公庁・大手企業との入札・契約時の要件
公共事業や大企業との契約では、「セキュリティ要件チェックリスト」内に明示されている。


**特にクラウド業務を行うSaaS事業者は必須事項になりがち。**

# 📌 なぜこの質問が重要なのか？
物理盗難時のリスクを最小限に抑える
暗号化されていない場合、ストレージを取り外して別PCに接続すればデータ抽出が可能。

# 法令・規格対応
個人情報保護法、マイナンバー法、GDPRなどでも「適切な保護措置」として暗号化が求められる。

**委託元が責任を負う可能性がある**
情報漏洩時に、元請側（委託元）も連帯責任となるため、事前に対策状況を確認したい。

# Windowsパソコン「BitLocker」ストレージ暗号化
https://mjeld.com/blog2/win-bitLocker-security.html
# Macの「FileVault」ストレージ暗号化
https://mjeld.com/blog2/macos-filevault-security.html
韓国オンラインゲームを通じて学んだ文化と価値観

オンラインゲームが好きな私は、最初はただ楽しいゲーム体験を求めて韓国のオンラインゲームをプレイし始めましたが、ゲームを進めるうちに、それ以上のことに気づきました。リネージュやメイプルストーリーといったゲームは、単なるエンターテイメントを超えて、韓国の文化や価値観、さらには人々の協力や共感の重要性を学ぶ素晴らしい機会を提供してくれました。これらのゲームを通じて、韓国社会の文化的背景や人々の行動パターンについて深く理解することができました。Outlook Indiaの韓国語の記事はこちら> [카지노사이트](https://www.outlookindia.com/xhub/e-gaming/2025년-추천하는-가장-안전한-카지노사이트-5가지-리뷰-및-순위)


![한국 엔터테인먼트 글로벌 현상으로 자리잡다.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4015689/aa3cf781-0081-4829-b5a3-c74460385cb1.jpeg)


## 韓国オンラインゲームにおける協力とチームワーク
最初にリネージュをプレイしたとき、最も驚いたのは、個人の成績よりも協力の重要性が強調されていることでした。多くのオンラインゲームでは、プレイヤーが個別に成長し、競い合うことが一般的です。しかし、リネージュでは、ギルドを組み、仲間と協力し合うことがゲームの進行において非常に重要です。成功するためには、他のプレイヤーとの連携が不可欠であり、チームワークこそが鍵となります。

このような協力の価値は、韓国社会における和の考え方と深く関連しています。韓国文化では、個人主義よりも集団の調和が重視され、共同で物事を成し遂げることが文化的に根強く定着しています。ゲーム内でも、プレイヤー同士が協力して目標を達成し、共に成功を収めることが、現実社会の価値観を反映していることに気づきました。

ゲーム内で形成されるコミュニティと絆
メイプルストーリーなどのゲームでは、ただレベルを上げたりアイテムを集めたりすること以上に、他のプレイヤーと協力して共通の目標を達成することが重要です。ギルドを作り、クエストを一緒に進め、困難なタスクを協力してクリアすることで、プレイヤー同士の絆が深まります。ゲーム内で築かれた友情や協力は、プレイヤーがゲームを続ける動機となり、現実の社会でも長期的な関係を築く土台になります。

このような共同体精神は、韓国社会における価値観にも通じています。韓国では、家族や職場、学校など、あらゆる場所で共同体の利益が重視され、個人の成功よりも集団の成功が優先されることが多いです。ゲーム内での協力と絆は、まさにこの文化的な価値観が反映されたものであり、実際の社会にもその影響を感じることができました。

## 韓国オンラインゲームにおける尊敬と階層
韓国オンラインゲームのもう一つの特徴は、ゲーム内での階層や尊敬の概念です。リネージュでは、経験豊富なプレイヤーが新しいプレイヤーに対してアドバイスをしたり、リソースを提供したりすることが一般的です。このようなシステムは、単なる競争や力関係ではなく、知識や経験に対する尊敬が基盤となっています。

韓国文化では、年齢や経験に基づく階層が重視されることが多く、社会的な敬意を払うことが重要とされています。ゲーム内でも、このような敬意の精神は重要です。経験豊富なプレイヤーが新しいプレイヤーに対して教育的なアプローチを取ることで、ゲーム内での知識や技術の伝承が行われ、全体のコミュニティが成長します。このシステムは、韓国社会における尊敬の文化をゲーム内で体験する良い機会を提供してくれました。

## 韓国オンラインゲームの国際的影響力
韓国のオンラインゲームは、国内での成功にとどまらず、国際的にも大きな影響を与えています。PUBGやリーグ・オブ・レジェンドなど、韓国発のゲームは、世界中で数百万人のプレイヤーに愛されており、その影響力はゲーム産業にとどまらず、文化的な側面にも広がっています。これらのゲームは、単にゲームとして楽しむだけではなく、韓国の文化的価値観を世界中に広める手段としても機能しています。

また、韓国のゲームが世界中で人気を博している理由の一つは、その中に含まれる協力や尊敬、共感といった価値観が、さまざまな国や文化で共感を呼び起こしているからです。韓国語とその文化に対する関心は、ゲームを通じてますます高まっており、多くの国で韓国ゲームを通じて韓国語を学ぶ人々が増えています。韓国のオンラインゲームが持つ文化的な力は、グローバルな現象となり、ますます多くの人々を惹きつけています。

## 結論：韓国オンラインゲームから学んだ文化的価値
韓国オンラインゲームを通じて、私はゲームの楽しさ以上のものを学びました。それは、韓国社会の重要な文化的価値である協力、尊敬、そしてコミュニティの大切さです。リネージュやメイプルストーリーで体験したチームワークや協力の精神は、ゲーム内での成功を超えて、現実社会でも大切にすべき価値観であることを実感しました。

これらのゲームを通じて、韓国文化の深い部分を理解し、オンライン空間での協力や共感がどれほど大きな力を持っているかを学びました。韓国のオンラインゲームは、単なる娯楽を超えて、世界中のプレイヤーが共感し、協力し合うための貴重な体験を提供しています。ゲームを通じて得た文化的な教訓は、私にとって非常に価値のあるものであり、今後もオンラインゲームを通じて多くの学びを得ていきたいと感じています。
X(旧Twitter)検索ツールを作ってみた(html)

## はじめに
X(旧Twitter)検索ツールを作ってみました。
できあがったものは[こちら](https://ken1math.github.io/my-website/xSearch.html)です。

Xの検索はURLパラメタをかくことで直接実行できます。
この記事ではこのツールの紹介とXの検索のURLパラメタについて簡単に説明します。 

## １. 検索ツールの概要

自分好みの条件でXの検索結果をワンクリックで表示できます。
できることは以下です。

- **検索ワード入力**  
- **言語フィルタ**（日本語／英語など）  
- **特定アカウント指定**
- **日付範囲指定**

さきほどのリンクと同じものをCodePenで用意しました↓。試せます。
<p class="codepen" data-height="750" data-theme-id="dark" data-default-tab="result" data-slug-hash="LEVmbpB" data-pen-title="Twitter検索" data-user="8787kazuye" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/8787kazuye/pen/LEVmbpB">
  Twitter検索</a> by ken1math (<a href="https://codepen.io/8787kazuye">@8787kazuye</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://public.codepenassets.com/embed/index.js"></script>




## ２. Xの検索URLパラメタについての簡単な説明

Xでは、検索キーワードやフィルタ条件をURLパラメタとして指定することで、さまざまな絞り込み検索が可能です。主なパラメタは以下のとおりです。

| パラメタ       | 説明                                             |
|---------------|--------------------------------------------------|
| `q`           | 検索クエリ。キーワードやフィルタ条件をスペース区切りで列挙します。例：`q=猫 カフェ` |
| `lang`        | 言語フィルタ。`ja`（日本語）、`en`（英語）などを指定します。                       |
| `from`        | 投稿アカウントを指定。例：`from:ken1math`                              |
| `since`       | 検索開始日。`YYYY-MM-DD`形式で指定します。                                |
| `until`       | 検索終了日。`YYYY-MM-DD`形式で指定します。                                |
| `f`           | フィルタタイプ。`f=live`で最新ツイートを表示、`f=top`で話題のツイートを表示します。 |
| `src`         | 検索の起点を示す補助パラメータ。通常は typed_query を指定 （なくてもよい）            |

たとえば、2025年6月4日から6月10日まで日本語の最新ツイートを「switch2 発送」で検索する場合は、以下のようなURLになります。（実際の検索ではスペースは %20 にエンコードされます。）

```
https://x.com/search?q=switch2 発送 lang:ja since:2025-06-04 until:2025-06-10&f=live&src=typed_query
```

先ほどのツールはURLパラメタを利用して、組み立てられたURLにとぶようにつくっています。


## おわりに
こんなツールがなくても、直接打ち込めば結局変わらないのですが。お手軽かと思ってつくってみました。
[小技]加算器を使い1と0を反転して遊ぶ。0→1、1→0


いろいろ、注意
----

- arduinoでの予定は、未定


プログラム
----

オンラインコンパイラ　paiza


```c++

#include <stdio.h>
int main(void){
    // Your code here!
    
    
    
    unsigned char a;
    
    a = 0;
    
    a = 1 - a;
    
    printf("0 -> %x\n",a);
  
    a = 1;
    
    a = 1 - a;
    
    printf("1 -> %x\n",a);

}


```

```

0 -> 1
1 -> 0

```
🔧 設計構成の観点：PAM×AI構成の全体像（完全再設計）

### 🧩 1. 背景と目的  
ゼロトラスト環境下での特権アクセス管理（PAM）の役割は、単なる「認証・認可」ではなく、「リアルタイム異常監視」「適応制御」「予測的制御」へと拡張されている。ここにAI技術を統合することで、単なるアクセスログの蓄積を超えた、**自律型制御構造**の構築が可能となる。  

本稿では「PAM×AI構成」の三層構造をベースに、その**運用的意義**・**拡張性**・**実践的応用例**までを俯瞰する。

---

### 🔍 2. 三層構成の詳細  

#### 【入力層】  
- **ユーザー行動データ**：操作・時間・端末種別・頻度パターンなど  
- **構成管理データ**：アカウント状態・権限変動・資産への影響  
- **環境データ**：業務イベント・システムログ・外部APIとの連動  

これらの**多軸データ**をリアルタイム収集し、**異常兆候の芽**を早期検知。

---

#### 【処理層：AIモデル群】  
- **逸脱検知モデル（Anomaly Scoring）**：非定常行動をスコアリングし、過去の統計と照合  
- **準拠率推定モデル**：各ユーザーの行動が、事前定義されたガバナンスに対しどの程度準拠しているかをスコア化  
- **適応制御アルゴリズム**：閾値を超える異常行動が検出された場合、次の行動選択をAIが予測し先回り制御  

👉 **特徴**：モデル群は、日次・週次で自動更新（Online Learningベース）により“常時自己進化”。

---

#### 【出力層】  
- **可視化ダッシュボード**：即時確認可能なUI（個人単位・部署単位）  
- **リアルタイムアラート出力**：Slack／メール／SIEM連携  
- **制御トリガー実行**：  
　例：  
　- セッション強制終了  
　- 管理者承認フロー起動  
　- 自動修復（スクリプト実行による再構成）

---

### 🚀 3. 実運用での応用例  

| ユースケース | 処理内容 | 成果 |
|---------------|----------------------|---------|
| 異常検出 | 定時外・別端末でのログイン | スコア上昇 → 強制セッション終了 |
| ガバナンス推定 | 勤怠規則未遵守の接続 | アラート送信 → 承認フロー起動 |
| システム連動制御 | 開発環境への異常アクセス | VPN制御とスクリプトによる遮断 |

---

### 📈 4. 成長可能性と今後の布石  
- **生成AIとの統合**（行動説明生成・ユーザー向け説明文自動化）  
- **セキュリティオーケストレーション（SOAR）連携**による全自動処理  
- **GPT系LLMとの役割分担によるセキュリティ説明支援**  

---

### 🔚 まとめ  
PAM×AIの融合は、「静的アクセス制御」から「**予測的・自律的統制**」への進化を象徴している。  
本稿で示した三層構成は、あくまで“起点”。次回以降では、**「逸脱検知モデルの精度向上手法」や「準拠率スコア設計」**を掘り下げ、より実践的な次元に進む。
Ubuntu で Kubernetes 三昧その２

[Ubuntu で Kubernetes 三昧その１](https://qiita.com/intrajp/items/1a4b9f9a3ce3d4ae081e)の続きです。

MACアドレスとUUIDの値がユニークであることを確認します。
マスターノードで

```
$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:9e:cb:2f brd ff:ff:ff:ff:ff:ff

$ sudo cat /sys/class/dmi/id/product_uuid
30f05dee-44f6-0a4d-ae10-65bf368cb4c2
```

ワーカーノードで
```
$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:b2:38:f1 brd ff:ff:ff:ff:ff:ff

$ sudo cat /sys/class/dmi/id/product_uuid
144ae75e-cda0-564f-938d-762818b689bb
```
Kubernetesが使用するポートに関しては、[こちら](https://kubernetes.io/docs/reference/networking/ports-and-protocols/)。
とりあえず、オープンできていないようだ。
```
$ nc 127.0.0.1 6443 -zv -w 2
nc: connect to 127.0.0.1 port 6443 (tcp) failed: Connection refused
```
```
$ free
               total        used        free      shared  buff/cache   available
Mem:         4008872     1327468     1986072       39976      956872     2681404
Swap:        4007932           0     4007932
fujiwara@masternode1:~$ sudo swapoff -a
fujiwara@masternode1:~$ free
               total        used        free      shared  buff/cache   available
Mem:         4008872     1324340     1989140       39976      956916     2684532
Swap:              0           0           0
```
仮想マシンリセットすると元に戻っている。
```
$ free
               total        used        free      shared  buff/cache   available
Mem:         4008872     1190172     2228376       36280      847396     2818700
Swap:        4007932           0     4007932
```
fstab 編集
```
/dev/disk/by-uuid/590ed445-1860-4655-aaa4-4e022464c16f / ext4 defaults 0 1
#/swap.img      none    swap    sw      0       0 <<--- コメントアウト
```
仮想マシンリセット
```
$ free
               total        used        free      shared  buff/cache   available
Mem:         4008872     1164260     2253108       36112      848520     2844612
Swap:              0           0           0
```
worker マシンでも上記を同様におこなう。

[Ubuntu で Kubernetes 三昧その３](https://qiita.com/intrajp/items/9bba127da61a91f23a83)に続く。

参考：

https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/