OmniAICreator/Qiita-1.07M huggingface dataset:
【EC-CUBE4.3】mock-package-apiで「/packages.json」が500エラーになる原因と解決方法

EC-CUBEのプラグイン開発で `mock-package-api` を使って、ローカルに置いた `.tgz` プラグインパッケージを `/packages.json` で読み込ませようとしたところ、500エラーでつまずいたので原因と対処法を共有します。

---

## 💥 起きた問題

以下のように `mock-package-api` を起動した後…

```bash
docker run -d --rm \
  -v $(pwd)/repos:/repos \
  -e MOCK_REPO_DIR=/repos \
  -p 9999:8080 \
  eccube/mock-package-api
```

`http://host.docker.internal:9999/packages.json` にアクセスすると、こんなエラーが返ってきました。

```json
{
  "status": 500,
  "error": "Internal Server Error",
  "message": "Could not read from \"tgz:file:///repos/OrderInquiry.tgz!/composer.json\" because it is not a file."
}
```

---

## 🔍 原因

`.tgz` の中の構造が **「ディレクトリごと圧縮」されていた** ため、  
mock-package-api が探す `composer.json` の位置とズレていた。

### ❌ NGな構造（`tar -tzf` の結果）

```
OrderInquiry/
OrderInquiry/composer.json
OrderInquiry/...
```

mock-package-api は `OrderInquiry.tgz!/composer.json` を探すため、  
**この構造だと見つけられずに 500 エラーになります。**

---

## ✅ 正しい構造（flat構造）

以下のように `.tgz` の中に `composer.json` が **直に存在**している必要があります。

### ✅ OKな構造

```
composer.json
PluginManager.php
Resource/config/plugin.yml
...
```

---

## 🛠 解決方法：ディレクトリの中身だけを圧縮

```bash
# plugins ディレクトリ内の OrderInquiry の中に移動
cd app/Plugin/OrderInquiry

# repos フォルダがなければ作る
mkdir -p ../../repos

# ディレクトリではなく「中身」だけを圧縮
tar --exclude-vcs -czvf ../../repos/OrderInquiry.tgz *
```

---

## 🚀 再確認

```bash
curl http://host.docker.internal:9999/packages.json
```

以下のようなレスポンスが返ってくれば成功！

```json
{
  "OrderInquiry": {
    "version": "1.0.0",
    "file": "/OrderInquiry.tgz"
  }
}
```

---

## 📌 補足

- `composer.json` には最低限、以下のような情報が必要です：

```json
{
  "type": "eccube-plugin",
  "extra": {
    "code": "OrderInquiry",
    "version": "1.0.0"
  }
}
```

- `plugin.yml` は mock-package-api の動作には必須ではないが、プラグインの定義としてはあった方がよい

---

## 🙏 まとめ

- `.tgz` の中身は「1階層にまとめないといけない」
- `mock-package-api` は `.tgz` の直下に `composer.json` がある前提で動く
- `tar` コマンドで中身だけを圧縮すれば解決！

---

## 🔗 参考

- [EC-CUBEプラグイン仕様](https://doc4.ec-cube.net/plugin_spec)

---

ちゃんと公式ドキュメントを見ていなかったのが原因ですが、万が一同じところでハマった方の参考になれば幸いです 🙌

※ この投稿は、ChatGPTにひな型を作ってもらってます。
Docker 基本コマンド

## Container を起動する
```
sudo docker run --rm -d -it -p 8000:8888 image_name:vX.X bash
```
``--rm``: This option tells Docker to remove the container once it stops.
``-d``: Runs the container in detached mode (keep running even after the command window stops)
``-it``: This allows you to run the container interactively with a terminal.
``-p 8000:8888``: This maps port 8000 on your host machine (arbitrary) to port 8888 on the Docker container (default unless otherwise specified in the container). 
``docker_image:vX.X``: Docker image to use
``bash``: This starts a bash shell in the container, allowing you to run commands interactively.

## Container 内のJupyter lab を使用する
### Container 内でJupyter lab を起動する
```
jupyter lab --allow-root --ip=0.0.0.0 --port=8888 --no-browser
```

``jupyter lab list`` でjupyer lab が走っているか確認できる。いらないものは ``px aux | grep jupyter`` で見つけて ``kill <PID>``する。

### Container とJupyter lab を同時に立ち上げる
```
docker run -d --restart always -p 0:8888 docker_image:vX.X jupyter lab --allow-root --ip=0.0.0.0 --port=8888 --no-browser
```
``--restart``: You can specify the restart policy using the --restart flag when you run your container. Here are a few options for the restart policy:
	• ``no``: Do not automatically restart the container (default).
	• ``always``: Always restart the container if it stops.
    • ``unless-stopped``: Restart the container unless it has been manually stopped.

## Container ⇔ Host 間のデータのやり取り
### Container 内からHost にデータをコピーする
```
docker cp <container_id_or_name>:<source_path> <destination_path_on_host>
```
### Host からContainer 内にデータをコピーする
```
docker cp <destination_path_on_host> <container_id_or_name>:<destination_path>
```
【Salesforce】CMSワークスペースとは？仕組みと使い方をわかりやすく解説！

## はじめに

この記事では、**Salesforce CMSワークスペースとは何か？どう使うのか？** を初心者向けにわかりやすくまとめます。

---

## CMSワークスペースとは？

CMSワークスペースは、Salesforce内で以下のような**コンテンツを一元管理できる仕組み**です。

- 画像、テキスト、お知らせなどの「CMSコンテンツ」を作成・公開できる
- 複数の「コレクション」に分けて整理・表示できる
- Experience Cloud サイトに連携して、コンテンツを出し分け表示できる

### イメージ

```
[CMSワークスペース]
   ├─ コンテンツ（画像・お知らせなど）
   ├─ コレクション（表示セット）
   └─ チャネル（どのサイトで使うか）
```

---

## ワークスペースの作成手順

### ✅ Step 1：Salesforce CMSを有効化

Salesforce 設定画面で「Salesforce CMS」を検索

![スクリーンショット 2025-04-22 9.51.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492812/8722b983-f8ca-46a3-b394-968a9d80ebd3.png)

### ✅ Step 2：CMSワークスペース作成

Salesforce アプリケーションランチャーで「CMS ワークスペース」を検索

![スクリーンショット 2025-04-22 9.49.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492812/fc0897bd-2a09-4533-9307-b8b5c55566f1.png)

ここからあとはCMS ワークスペースを作成します。

---

## CMSコレクションを使う方法

1. CMSワークスペース内で「コンテンツ」を追加（画像や記事など）
2. 「コレクション」タブで、任意のコレクションを作成し、コンテンツを追加
3. Experience Builder で「CMS コレクション」コンポーネントを配置
4. 作成したコレクションを選択

---

## まとめ

| 用語 | 意味 |
|------|------|
| CMSワークスペース | コンテンツの作業スペース（土台） |
| コレクション | 表示セット（1つのまとまり） |
| チャネル | どのExperience Siteに表示するか |

CMSワークスペースがきちんと設定されていないと、**エラーや表示されない原因になります**。  
まずは本番と同じ構成にすることで、Sandboxの不具合も解消できることが多いです。

---

## おまけ：CMSを使わずに画像を表示したい場合

- 静的リソース（Static Resource）
- ファイル（Documentオブジェクト or ContentDocument）

用途に応じて、CMSを使う or 使わないを使い分けてみてください！

---

### 📎 参考

- [Salesforce Developers Blog: Deliver Beautiful Digital Experiences with Salesforce CMS](https://developer.salesforce.com/blogs/2019/10/deliver-beautiful-digital-experiences-with-salesforce-cms)
- [Salesforce ヘルプ：CMS ワークスペースの管理](https://help.salesforce.com/s/articleView?id=sf.cms_workspace_manage.htm)
【初心者向け】TypeScript製エージェントフレームワーク「Mastra」入門ガイド


## そもそもMastraってなに？

> **Mastraは、エージェント（AIで考える小さな作業者）を組み合わせて、自動的にタスクをこなしてくれるフレームワークです。**

---

## Mastraでできること

例えば、こんな流れが作れます。

1. **Webスクレイピングツール**でデータを集める（Tool）
2. **AIエージェント**でデータを要約する（Agent）
3. **プランナー**で一連の流れを管理する（Plan）

これを、**少ないコードで自然に構築**できるのがMastraです！

---

## Mastraのコンポーネント構成

Mastraは、  
**たった4つのコンポーネント**でできています！

| コンポーネント | 役割 | 例 |
|:---|:---|:---|
| Tool | 単純な作業をする | API叩く、ファイル読む |
| Agent | 判断・推論する | テキスト要約、分類 |
| Plan | 作業の流れを組み立てる | 「AしてBしてCする」フロー |
| Memory | 状態や履歴を記録する | 作業ログ保存（予定機能含む） |


このシンプルさが、初心者にもわかりやすく、応用しやすいポイントです。

---

## 1. Tool（ツール）

> **単純な作業を担当するパーツ。**

- Webスクレイピングをする
- APIを叩いてデータを取ってくる
- ファイルを読み込む

など、**「何かをする」シンプルな処理**をToolにまとめます。

---
✅ たとえば：

```typescript
class FetchUserData extends Tool {
  async run() {
    return await fetch("https://api.example.com/user");
  }
}
```

→ データ取得だけに専念する！

---

## 2. Agent（エージェント）

> **考えたり、判断したりするパーツ。**

- テキストを要約する
- データを分類する
- 意思決定をする

など、**「知的な作業」**をAgentに任せます。

---
✅ たとえば：

```typescript
class SummarizeTextAgent extends Agent {
  async run(text: string) {
    return `要約: ${text.substring(0, 100)}...`;
  }
}
```

→ 簡単な要約ロジックを持たせたりできる！

---

## 3. Plan（プランナー）

> **ToolとAgentをつないで流れを作るパーツ。**

- 「最初にこれをやって、次にあれをやって」という**順番管理**をします。
- 分岐や並列処理もサポート予定！（発展）

---
✅ たとえば：

```typescript
const plan = new Plan([
  new FetchUserData(),
  new SummarizeTextAgent()
]);
```

→ **流れ**を組み立てて「一気に自動実行」できる！

---

## 4. Memory（メモリー）

> **データや履歴を保存するパーツ。（※将来拡張される予定）**

- 途中結果を覚えさせたり
- 成功・失敗の履歴を取ったり
- チームで共有するために使う

現在はシンプルな使い方が中心ですが、  
**ログ管理・状態保持**などに活用できるようになる方向です。

---

# 【コンポーネントまとめ図】

```
[ Tool ] → [ Agent ] → [ Tool ] → [ Agent ]
     ↓           ↓            ↓          ↓
   作業        判断         作業        判断
            ↓
          [ Plan ] ← 流れを管理
```

- Tool：**動く手**  
- Agent：**考える頭**  
- Plan：**流れを設計する設計図**

これがMastraの基本設計！

---

## Mastraを使うメリット

- **TypeScriptだけで完結**（Node.js上で動く）
- **Tool/Agent/Planをシンプルに設計できる**
- **拡張・カスタマイズが超しやすい**
- **軽量＆最小構成から始められる**

---

## Mastraの始め方（超かんたんステップ）

### 1. インストール

まずnpmでインストール！

```bash
npm install mastra
```

またはyarnなら

```bash
yarn add mastra
```

  
これだけで準備完了！

---

### 2. 最初のサンプルコード

超シンプルな例を見てみよう！

```typescript
import { Tool, Agent, Plan } from 'mastra';

// Toolの定義（単純作業）
class FetchDataTool extends Tool {
  async run() {
    return "データを取得しました！";
  }
}

// Agentの定義（AI的な作業）
class SummarizeAgent extends Agent {
  async run(input: string) {
    return `要約結果: ${input}`;
  }
}

// Planの定義（流れを設計）
const plan = new Plan([
  new FetchDataTool(),
  new SummarizeAgent()
]);

// 実行
(async () => {
  const result = await plan.execute();
  console.log(result); // => 要約結果: データを取得しました！
})();
```

これだけで  
**「データ取得 → 要約」**の流れが自動で動きます！

---

## Mastraのイメージ図

```
[ FetchDataTool ] → [ SummarizeAgent ]
         ↓
      Planが順番に実行
```

こんな感じで、**小さな部品を順番に組み立てていくスタイル**です！

---

## Mastraはどんな人に向いている？

✅ TypeScript/Node.jsでAIや自動化に挑戦したい人  
✅ シンプルな自動ワークフローを作りたい人  
✅ フロントと連携して使いたい人（Next.js、NestJSとの相性も良い）


---

# 【参考】

- [Mastra GitHub（TypeScript版）](https://github.com/Mastra-AI/mastra)  
- [公式ドキュメント（英語版）](https://mastra.ai/docs)
OACでカスタム・マップレイヤーがたくさん保存できるようになった

# はじめに
OAC（**Oracle Analytics Cloud**）でカスタム・マップレイヤーを保存する際に「外部ストレージ」を選択することにより、より多くのマップを保存できます。

それぞれのカスタム・マップレイヤーは、最大100MBのGeoJSONファイルとして用意します。
アップロード時に空白は除去され、小数点も6桁に切り捨てられサイズは圧縮されます。
デフォルトのストレージ制限は、全体として200MBです。
外部ストレージの制限は、全体として50GBです。ファイルサイズの制限は同じです。

# カスタム・マップレイヤーの登録
管理者としてログインし「コンソール」の「マップ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/8d4ceb59-7e10-432b-8f77-810373d5e78f.png)

「＋」をクリックしてGeoJSONファイルを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/9ad3f2c7-446c-468e-948b-5cf10185b93a.png)

今回は日本の都道府県のカスタム・マップレイヤーです。
「拡張」タブに移動して、ストレージタイプを「外部」に変更します。
「保存」をクリックします。一度保存するとストレージタイプは変更できません。
変更したい場合は、一度削除して再登録してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/c73bc421-effe-4ef2-afa1-0e52dfd2a7e2.png)

「Japan」が今回外部ストレージに保管したカスタム・マップレイヤーです。
サイズが約70MBと大きく、これまでだと登録するのに躊躇する大きさです（全体の制限が200MBなので）。
「JP_PREF」は以前登録した小さなサイズの（都道府県の形がより簡略化された）カスタム・マップレイヤーです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/e8e6be79-be89-4578-98af-f8e34774e250.png)

# 試してみる
都道府県ごとの人口データをカスタム・マップレイヤー「Japan」と「JP_PREF」を使用してマップ・ビジュアライゼーションで表現しました。
左が外部ストレージの「Japan」マップレイヤー、右がデフォルトのストレージの「JP_PREF」マップレイヤーを使用したものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/bcd2868e-3c98-4c22-907d-15e616716a91.png)
外部ストレージの方が細かいですが、デフォルトも滑らかな線になっており、これはこれで悪くないように思います。

では、町田市付近をズームしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/fff0749f-6ea0-4dc8-b9b5-1f6a287929a8.png)

ここまでズームすると、かなり違いがあるのがわかります。

# まとめ
外部ストレージを活用すると、ストレージサイズの制限がこれまでよりもかなり緩和されます。
今回使用したような、大きなサイズのカスタム・マップレイヤーも、今までよりは躊躇なく使えるかも知れません。
大きな（そして詳細な）マップレイヤーだとパフォーマンス上の問題が発生するかも知れませんし、利用用途によっては小さな（粗い）マップレイヤーでも実用上大きな違いはないこともありそうなので、よく考えて使っていただきたいと思います。

カスタム・マップレイヤーの大型化よりは、より多くの種類のカスタム・マップレイヤーを登録できるようになったことの方が、メリットが大きいかも知れないですね。
git init を取り消す（git bash）

間違ってホームディレクトリ（~）で git init を実行してしまい、Git の管理を取り消したい場合の手順です。


1\. ホームディレクトリに移動します
``cd ~``

2\. .git ディレクトリを削除します
``rm -rf .git``

 - rm コマンドはファイルを削除するために使用します
 - -r オプションはディレクトリとその中身を再帰的に削除します
 - -f オプションは確認なしで強制的に削除します
::: note warn
 注意
 ディレクトリを間違えると、重要なファイルも消えてしまうため、コマンド 実行前に必ず実行するディレクトリを再確認してください。
:::

3\. .git ディレクトリがなくなっていることを確認します
 ``ls -a``
 実行結果に .git という名前のディレクトリが表示されなければ、削除は成功しています。
noopenerはもう要らねェ…！

(某海軍大将のようなセリフですみません)

HTMLやJavaScriptを書いていると、aタグを使って別タブでリンクを開きたくなる場面があると思います。

```HTML:aタグ
<a href="https://example.com" target="_blank">
```

2023年くらいまでの記事では、
「rel="noopener"を指定しないとタブナビング攻撃を受けるよ！」
という内容を見かけると思います。
しかし、現在は主要なブラウザ側で対策されているため、設定は不必要となります。
（内容としては今更感がありますが、自身の備忘録のためにまとめます）

# タブナビング攻撃
まずタブナビング攻撃とは、現在アクティブになっている(見ている)タブから、他のアクティブになっていない（見ていない）タブのページの内容を変更する攻撃のことです。

こちらのサイトの具体例わかりやすいです。
https://denno-lab.com/target-blank-safety/

つまり、target="_blank"によって新しいタブを開くと、
新しく開いたタブからwindow.openerを操作して、元のウィンドウの内容を変更できてしまう、ということのようです。

window.openerについてはこちらから
https://developer.mozilla.org/ja/docs/Web/API/Window/opener

# noopenerの役割
ここでnoopenerを指定することにより、window.openerがnullになります。
window.openerがnullになると元のウィンドウを参照することができなくなるので、元のウィンドウの内容を変えることもできなくなる（タブナビング攻撃を防げる）ということのようです。

# MDNを見たところ
しかし、MDNを見たところ、target="_blank" を aタグに設定するとデフォルトでwindow.openerを設定しないようにしてくれるそうです。
（つまり、noopenerを設定したのと同じ振る舞いになります）

>メモ: target="_blank" を `<a>` 要素に設定すると、暗黙的に rel の動作が rel="noopener" を設定した場合と同様、 window.opener を設定しないようになりました。対応状況についてはブラウザーの互換性を参照してください。

https://developer.mozilla.org/ja/docs/Web/HTML/Reference/Attributes/rel/noopener

互換性の部分を見ても主要なブラウザに対応しているみたいなので、やはりnoopenerは不必要そうだと考えて良さそうですね。

# window.open()メソッドは？
しかし、調べた感じだと指定したリンクを開くwindow.open()を使用する場合はnoopenerを設定する必要があるかも？と考えています。

https://momdo.github.io/html/window-object.html
https://developer.mozilla.org/ja/docs/Web/API/Window/open

window.open()はデフォルトでtarget='_blank'を指定するようなのですが、第3引数のwindowFeaturesについては特に触れられていなさそうです。
window.open()メソッドを使う場合は、明示的にnoopenerを指定した方が安心かもしれません。
（この辺りご存知の方いらっしゃれば教えてください）

# まとめ
2025年現在では、aタグにrel="noopener"を指定しなくてもブラウザ側でタブナビング攻撃対策をしてくれるよ、というお話でした。

あとこちらの記事も大変参考になりました。
ありがとうございます。
参考：https://cinci.jp/blog/20240723-review-target-blank-noopener-noreferrer-practices
AWS重要知識(AWS-SAA,SAP対策)　〜AmazonRDS編〜




## AmazonRDSとDNS
重要度⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️

結論をいうとアプリケーションサーバーからRDSに接続するとき、IPアドレスでの直通信はしません。

RDSインスタンスとの接続情報に関するドキュメント
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/CHAP_CommonTasks.Connect.EndpointAndPort.html?utm_source=chatgpt.com

>DB インスタンスの接続情報には、エンドポイント、ポート、およびマスターユーザーなどの有効なデータベースユーザーが含まれます。例えば、MySQL DB インスタンスの場合、エンドポイントの値が mydb.123456789012.us-east-1.rds.amazonaws.com であるとします。この場合、ポート値は 3306 であり、データベースユーザーは admin です。この情報を考慮して、接続文字列に次の値を指定します。


つまり、エンドポイント用のURLを指定して接続します。
RDSはプライマリ/セカンダリ構成で冗長化されていますが、セカンダリをプライマリに昇格させる時に内部ではこのDNSレコードを切り替えるという動作を行います。そのため、DNSを経由する通信にしておかなければフェイルオーバーができなくなってしまいます。(←SAP試験で結構聞かれる)


## RDS 7日間問題
重要度⭐️⭐️⭐️⭐️⭐️⭐️⭐️

RDSは、通常の方法だと最大7日間までしか停止できない。
7日経つと自動的に起動してしまいます。(もちろん課金も発生。)

:::note info
この仕様のせいで私は2万近く請求が来たことがあります。
個人で試す場合、RDSは削除しましょう。
DBの勉強をしたいだけであればEC2インスタンスにPostgreやMySQLを入れるでも良いかと思います。
:::

⭐️RDSの停止に関するドキュメント
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_StopInstance.html

>DBインスタンスの停止の仕組み
停止操作は、次の段階で実行されます。
DB インスタンスは通常のシャットダウンプロセスを開始します。
DB インスタンスのステータスが stopping に変更されます。
インスタンスは最大 7 日間連続して実行を停止します。
DB インスタンスのステータスが stopped に変更されます。

## RDSはリージョンサービス
重要度⭐️⭐️⭐️⭐️

RDSはリージョンサービスなのでグローバルサービスには向きていない
グローバルなユースケースでは、『AuroraGlobalDatabase』を使う(SAPでよく出る)

## AmazonRDSの最大同時接続数
重要度⭐️⭐️⭐️⭐️⭐️

インスタンスタイプとRDSの設定で決定

⚫︎AmazonRDSのクォータに関するドキュメント
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/CHAP_Limits.html#RDS_Limits.MaxConnections
>同時データベース接続の最大数は、DB エンジンのタイプと DB インスタンスクラスのメモリ割り当てによって異なります。最大接続数は、通常は DB インスタンスに関連付けられたパラメータグループで設定されます。例外は、Microsoft SQL Server Management Studio (SSMS) の DB インスタンスのサーバープロパティで設定される Microsoft SQL Server です。



## Multi-AZ RDS
重要度⭐️⭐️⭐️⭐️

Multi-AZ設定では、複数のリージョンに読み取り専用のDBを複製/同期し、プライマデータベースが落ちた時に自動的にフェイルオーバーできる。

### フェイルオーバー時間
MultiAZのRDSのフェイルオーバーダウンタイムは『60秒以上』でしかサポートされていない。
(Auroraは30秒未満)

SAPの問題文でRTOが指定されてる問題のフェイルオーバーでよく問われる。

:::note
後述するRDS Proxyを使うとRDsのフェイルオーバー時間を30秒未満にできます。
:::

## RDSの復元とバックアップ
重要度⭐️⭐️⭐️⭐️⭐️

### トランザクションログのバックアップ
RDSは5分間隔でトランザクションログをS3に出力する

:::note
トランザクションログとは？
データベース内で発生したすべての変更操作（INSERT、UPDATE、DELETEなど）を時系列で記録するログファイル
:::

⚫︎トランザクションログに関するドキュメント
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_PIT.html

### DBインスタンスのバックアップ
DBインスタンス自体のバックアップ最大保有期間は『35日』が最大


⚫︎DBインスタンスのバックアップ/復元に関するドキュメント
https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/backup-recovery/rds.html
>自動バックアップは、新しい DB インスタンスを作成するとデフォルトでオンになっています。
Amazon RDS は、DB インスタンスの作成時に定義したバックアップウィンドウ中にデータの日次バックアップを実行します。自動バックアップの保存期間は最大 35 日まで設定できます。


### RDS proxy
Multi-AZと同時に使われることが多い。
データベース間との通信を管理してくれるため、障害時のコネクションのフェイルオーバーやトランザクション維持が可能となる。

⚫︎RDS Proxyに関するドキュメント
https://aws.amazon.com/jp/rds/proxy/

>Amazon RDS Proxy では、アプリケーションがデータベースと確立した接続をプールおよび共有でき、データベースの効率とアプリケーションのスケーラビリティが向上します。Amazon RDS Proxy を使用すると、Amazon Aurora と Amazon RDS データベースのフェイルオーバー時間が最大 66％ 短縮し、AWS Secrets Manager および AWS Identity and Access Management (IAM) との統合によりデータベースの認証情報、認証、アクセスの管理が可能となります。



##
Pythonでダイアログボックスにてファイルを選択する

## ファイルサイズの大きなファイルの先頭30行だけ表示させたい

サイズの大きなデータファイルをExcelで読み込むには時間がかかりすぎる，あるいは読み込めない．このようなデータを扱う時には，先頭部分だけを表示して，ヘッダやデータの配列（並んでいる順番）を確認したい．

以下のようなPythonスクリプトを用いれば，任意の行までを瞬時に表示することができる．

```show30_file.py
# -*- coding: utf-8 -*-
import csv
import tkinter as tk
from tkinter import filedialog

# ファイルダイアログボックスを表示してファイルを選択
file_path = filedialog.askopenfilename()

# 選択したファイル名を取得して変数filenameに格納
filename = file_path.split("/")[-1]

print(f"Selected file name is : " + filename)

# csvファイルの最初の30行を表示する
# with open(filename, 'r', encoding='utf-8') as csvfile:
    # csvreader = csv.reader(csvfile)
    # lines = [next(csvreader) for _ in range(30)]

# txtファイルの最初の30行を表示する
with open(filename, 'r', encoding='utf-8', errors='ignore') as file:
    for i in range(30):
        line = file.readline()
        if not line:
            break
        print(line.strip())

# エンコーディングの問題を確認する
for i, line in enumerate(lines):
    print(f'Line {i+1}: {line}')
```

＜注意事項＞
ファイル内に日本語が含まれるなら，スクリプトの１行目は，必須（文字化け対策のおまじない）．

ASCIIフォーマットなら，csvの部分を任意の拡張子（txtやdatなど）に変更すればＯｋ．
個人的備忘録：MySQLの接続上限エラーを防ぐ max_connections の設定と確認方法

## はじめに
本記事では、MySQLサーバにおける同時接続数（`max_connections`）を500に設定する方法について解説します。

:::note info
**個人の備忘録程度の走り書きとなっておりますが、温かい目で見守っていただければ幸いです。**
:::

接続数が不足してアプリケーション側でエラーが発生するなど、実運用において重要なパラメータのひとつです。

## 書こうと思ったきっかけ
MySQLへの接続が集中し "Too many connections" エラーが発生するケースのことを考えてみました。その対応として接続上限の調整を行い、エラーの解消する必要があると思いましたので、備忘録として整理しておきます。

## 実行内容
稼働中のサーバで以下のように接続数上限を変更しました：

```sql
set global max_connections=500;
```

設定後、以下のコマンドで反映されたかを確認します：

```sql
show global variables like '%connection%';
```

表示結果の例：

```
+--------------------------+-----------------+
| Variable_name            | Value           |
+--------------------------+-----------------+
| character_set_connection | utf8            |
| collation_connection     | utf8_general_ci |
| max_connections          | 500             |
| max_user_connections     | 0               |
+--------------------------+-----------------+
4 rows in set (0.00 sec)
```

## 永続化のための設定（自分調べ）
このままだとサーバ再起動時に設定が元に戻ってしまうため、永続的な変更も行います。

設定ファイル（例：`/etc/my.cnf`）に以下の行を追加または編集します：

```
[mysqld]
max_connections = 500
```

設定を反映させるには、mysqld の再起動が必要です：

```bash
sudo systemctl restart mysqld
```

または MariaDB を使用している場合：

```bash
sudo systemctl restart mariadb
```

## まとめ
- `set global` コマンドで一時的に接続数を変更可能
- `my.cnf` に追記することで永続化
- サーバ再起動後も反映されるようにするには設定ファイル編集が必要

運用中のシステムで接続数エラーが発生していた場合、今回の設定で解消できる可能性がありますので、参考にしてみてください...！
【CSS入門】レスポンシブデザインの基本とよく使うプロパティの解説【メディアクエリ／flex-direction／overflow】

# はじめに

スマホ・タブレット・PCなど、さまざまな画面サイズに対応したUIを作るには、**レスポンシブデザイン**の知識が欠かせません。

この記事では、レスポンシブ対応でよく使う以下のCSSプロパティや概念について、備忘録としてわかりやすく整理しておきます。

---

# ①レスポンシブデザインとは？

**「画面のサイズに応じて、レイアウトやデザインを自動で調整すること」**

- スマホでも見やすいデザインにするための手法
- メディアクエリやflexbox、overflowなどを組み合わせて実現

---

# ②メディアクエリ（media query）

画面サイズによってCSSの内容を切り替える方法。

```css
/* 画面幅が768px以下のときだけ適用 */
@media screen and (max-width: 768px) {
  .container {
    flex-direction: column;
  }
}
```
よく使う条件例：
![IMG_7809.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2246240/30435f4e-c9bb-4d8a-98b4-17437b5f4a73.jpeg)

# ③flex-direction: row / column
**Flexboxでの並び方向を指定するプロパティ。**

横並び(デフォルト)
```css
.container {
  display: flex;
  flex-direction: row;
}
```
→子要素が**横に並ぶ**

縦並び
```css
.container {
  display: flex;
  flex-direction: column;
}
```
→子要素が**上から下に並ぶ**

# ④実務での使い分け例
```css
.container {
  display: flex;
  flex-direction: row; /* PCでは横並び */
}

@media (max-width: 768px) {
  .container {
    flex-direction: column; /* スマホでは縦並び */
  }
}
```

# ⑤overflow-x: auto
**横スクロールできるようにする設定。**
```css
.scroll-box {
  overflow-x: auto;
  white-space: nowrap;
}


```
- 子要素が横にはみ出してもスクロールできるようにする
- 画像一覧、コードブロック、横長のリストなどに便利

**使用例：横スクロール可能なリスト**
```html
<div class="scroll-box">
  <div class="item">Item 1</div>
  <div class="item">Item 2</div>
  <div class="item">Item 3</div>
  ...
</div>
```

```css
.scroll-box {
  display: flex;
  overflow-x: auto;
  white-space: nowrap;
  gap: 16px;
}
```

# ⑥overflow: hidden
**はみ出た部分を非表示にする設定。**
```css
.box {
  overflow: hidden;
}
```
- 子要素が親のサイズをはみ出しても、表示しない
- デザイン上の崩れ防止・余白調整などでよく使う

# ⑦注意点
![IMG_7810.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2246240/12b88ac4-06bb-47f7-b78a-fa21071ddebd.jpeg)

# ⑧まとめ

![IMG_7811.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2246240/2ae2b473-c3e0-49e5-92c7-d826969bc9bd.jpeg)

レスポンシブ対応は、「PCだけ」ではなく「スマホで快適に使える」ことが求められる今のWeb制作では欠かせない技術です。

メディアクエリ＋Flexbox＋overflowの組み合わせは、実務でも最も使うパターンの一つなので、定型として覚えておくと非常に便利です。
agents Action でFlowを使った場合のエラー



# UNKNOWN_EXCEPTION  An error occurred when executing a flow interview. 

+ [How to send back the response from autolaunched flow to agents](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000PYnmo)


:::note
you will need to create a New Resource > Variable. Be sure to put a checkmark in "Available for output".  I have a Create Records element that populates the variable. 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/655d26cd-3b96-4e43-ad07-46af5beeb1a5.png)
:::
Symbolic Linkを使ってTerraformをDRYに管理しよう！

## 概要
Terraformを使ってインフラ構築する際にdev、stg、prdと環境を分けるかと思います
今回はSymbolic Linkを使って共通で使用するコードをDryに管理する方法について解説していきたいと思います

## Symbolic Linkとは
Wikipediaからの引用ですが
> In computing, a symbolic link (also symlink or soft link) is a file whose purpose is to point to a file or directory (called the "target") by specifying a path thereto.

ファイルまたはディレクトリ（「ターゲット」と呼ばれる）へのパスを指定することによって、そのファイルまたはディレクトリを指すことを目的としたファイル

とのことです
ざっくりと説明するとシンボリックリンクを貼ることで、そのディレクトリやファイルを参照するショートカットを作成する仕組みだと思っていただけたらいいと思います

## 今回検証するディレクトリ構成
```
├── dev
├── prd
├── README.md
├── shared
│   └── query
│       └── insert_coupon_usage.sql
└── stg
```

## Symbolic Linkを貼ってみよう！
以下のコマンドでSymbolic Linkを貼ることができます
```
ln -s {参照元ファイル/フォルダ}　{リンク名}
```

今回だとinsert_coupon_usage.sqlが参照元でdevフォルダ配下がリンク名です

```
ln -s shared/query/insert_coupon_usage.sql dev
```

以下のようにdev配下にSymbolic Linkを貼ることができれば成功です

```
├── dev
│   └── insert_coupon_usage.sql
├── prd
├── README.md
├── shared
│   └── query
│       └── insert_coupon_usage.sql
└── stg
```

## 実際に実行してみよう！
試しに以下のファイルにコメントを記載してみます
```insert_coupon_usage.sql
MERGE INTO ${dataset}.used_coupons AS target
USING (
    SELECT user_id, coupon_code, used_at
    FROM ${dataset}.coupon_usage
    WHERE is_used = TRUE
)
AS source ON target.user_id = source.user_id
AND target.coupon_code = source.coupon_code
-- 条件に一致しなければInsertする
WHEN NOT MATCHED THEN
    INSERT (user_id, coupon_code, used_at, migrated_at)
    VALUES (source.user_id, source.coupon_code, source.used_at, CURRENT_TIMESTAMP());
```

以下のように差分を検知することができれば成功です

```
Terraform will perform the following actions:

  # google_bigquery_data_transfer_config.insert_coupon_usage_query will be updated in-place
  ~ resource "google_bigquery_data_transfer_config" "insert_coupon_usage_query" {
        id                        = "projects/XXXXXXXXXXXXX/locations/us/transferConfigs/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXX"
        name                      = "projects/XXXXXXXXXXXXX/locations/us/transferConfigs/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXX"
      ~ params                    = {
          ~ "query" = <<-EOT
                MERGE INTO practice_dataset.used_coupons AS target
                USING (
                    SELECT user_id, coupon_code, used_at
                    FROM practice_dataset.coupon_usage
                    WHERE is_used = TRUE
                )
                AS source ON target.user_id = source.user_id
                AND target.coupon_code = source.coupon_code
              + -- 条件に一致しなければInsertする
                WHEN NOT MATCHED THEN
                    INSERT (user_id, coupon_code, used_at, migrated_at)
                    VALUES (source.user_id, source.coupon_code, source.used_at, CURRENT_TIMESTAMP());
            EOT
        }
        # (10 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.
```


## 参考
https://zenn.dev/pageo/articles/d90d89e2168061

https://atmarkit.itmedia.co.jp/ait/articles/1605/30/news022.html

https://qiita.com/att55/items/ab7781dae0bcd4d31395
Cコンパイラーいろいろ

いろいろ使っているので、一覧にしてみます。

|ターゲット|コンパイラー|
|:--|:--|
|rtlbm-mruby|Realtek社提供のLinux用GCC 4をFreeBSDのLinuxエミュレーションで使用|
|bcmbm-mrubyなど|FreeBSDのportsでビルドしたネイディブのMIPS GCC 4|
|armbm-mruby|FreeBSDのpkgのARM GCC 4|
|rx-mrubyc|ルネサス社提供のLinux用GCC 4をFreeBSDのLinuxエミュレーションで使用|
|マイコンいろいろ|platformioのpackagesのLinux用GCC/SDCCをFreeBSDのLinuxエミュレーションで使用|
|HC908|platformioのSDCCを使用|
|H8|FreeBSDのportsでビルドしたネイディブのMIPS GCC 8|
|PIC32MX|penguinoのLinux用GCCをFreeBSDのLinuxエミュレーションで使用|
|DOS/Win 3.1|Open Watcom V2.0のLinux用のバイナリをFreeBSDのLinuxエミュレーションで使用|
|FreeBSD 12/mips|GCC 4|
|FreeBSD/amd64|clang|
|NetBSD 10/arm|GCC 10.5|
SwitchBotを操作するMCPサーバをGo(mcp-go)で作った話

最近流行っているMCPサーバを理解するためにも、なにか作ってみたいなと思い手元にあったSwitchBotを操作するMCPサーバを作ってみました。

またGitHub公式のMCPサーバでも使われているmcp-goを使ってGo言語で作ってみたのでmcp-goの使い方も軽く紹介したいと思います。

# SwitchBot MCPサーバ紹介

今回作成したSwitchBotのMCPサーバは下記のリポジトリで公開しています。

https://github.com/yasu89/switch-bot-mcp-server

## 設定方法

MCPサーバの設定方法はGitHubの[README](https://github.com/yasu89/switch-bot-mcp-server/blob/main/README_ja.md)にも記載してあります📝

今回は[SwitchBot API](https://github.com/OpenWonderLabs/SwitchBotAPI)を使用するためSwitchBotのアプリの「開発者向けオプション」からトークンとシークレットを準備する必要があります。
（初回はアプリバージョンを10回タップして「開発者向けオプション」を表示させる必要があります）

MCPサーバのバイナリは[releasesページ](https://github.com/yasu89/switch-bot-mcp-server/releases)で配布しているのでダウンロードしてください。

:::note info
現状ローカルでMCPサーバを動かすことが多い中で、Go言語の複数プラットフォーム向けのバイナリを簡単に準備して配布できる点はGo言語でMCPサーバを作るメリットだなと思いました
:::

Claude DesktopのMCPサーバの設定は下記のようにバイナリを指定して、トークンとシークレットを`env`に記載してください。

```json
{
  "mcpServers": {
    "switchbot": {
      "command": "~/Downloads/switch-bot-mcp-server",
      "env": {
        "SWITCH_BOT_TOKEN": "YOUR_SWITCH_BOT_TOKEN",
        "SWITCH_BOT_SECRET": "YOUR_SWITCH_BOT_SECRET"
      }
    }
  }
}
```

## 使い方

現在はデバイス一覧の取得と、各デバイスのステータス取得、デバイスのON/OFFのToolのみを実装しています。

上記のように単純なToolのみしか実装していないですが、LLMを介すことでデバイスをON/OFFするような単純なことだけでなく、下記のように複数のデバイスにまたがって操作を指示することができるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295261/a5ee46e9-091b-46aa-adaf-0955e3ac2bf7.png)

:::note info
今回実装したToolやレスポンスについてLLM向けの説明を全然書いていないですが、SwitchBotが一般的に広まっていてLLMの事前学習データに含まれているため特に説明しないでも良い感じに動いているのかなと思いました
:::

他にもこのMCPサーバを使用して便利な使い方など見つけましたらコメントでぜひ教えてください！

# mcp-goの使い方

この記事時点ではmcp-goは`v0.22.0`を使用しているので、実装方法が変わっている可能性などには注意してください。

https://github.com/mark3labs/mcp-go

## MCPサーバ起動とToolの実装方法

簡単な紹介ですがToolの実装であれば下記の通りすぐに実装することができます！
その他の細かい使い方は[mcp-goのexamples](https://github.com/mark3labs/mcp-go/tree/main/examples)などが参考になると思います。

```go
package main

import (
	"context"
	"fmt"
	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

func main() {
	// MCPサーバの定義
	mcpServer := server.NewMCPServer(
		"Tax MCP",
		"0.1.0",
	)

	// Toolの追加
	mcpServer.AddTool(
		mcp.NewTool(
			"calc_tax",
			mcp.WithDescription("税抜き金額を受け取って税込金額を返す"),
			mcp.WithNumber("price", mcp.Required(), mcp.Description("税抜き金額")),
		),
		func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
			price := request.Params.Arguments["price"].(float64)
			tax := 0.1
			taxIncludedPrice := price * (1 + tax)
			return mcp.NewToolResultText(fmt.Sprintf("%.2f", taxIncludedPrice)), nil
		},
	)

	// stdioを介したMCPサーバを起動
	if err := server.ServeStdio(mcpServer); err != nil {
		fmt.Printf("Server error: %v\n", err)
	}
}
```
Flow Error Handling Superbadge Unit



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

+ 有効なデータ入力をサポートするためにフローを強化します。 
+ フローに障害パスとエラー処理を追加します。


# ケース番号 4014: 有効なデータ入力をサポートするフローの強化

既存のフローを更新することで、データ品質を向上させ、エラーを削減します。 


:::note alert
A newly updated version of the flow 'Opportunities for Main Stage Analytics' wasn't activated.


フロー「メインステージ分析の機会」の新しく更新されたバージョンがアクティブ化されませんでした。
:::


# ケース番号4021: 障害処理と通知の管理

フロー エラーが発生した場合の障害処理を追加します。 

:::note alert
We can't find the appropriate fault path to the 'Flow Pro Error Messaging' flow.


「Flow Pro エラー メッセージング」フローへの適切な障害パスが見つかりません。
:::

:::note alert
The 'Consent Capture for Main Stage Analytics' flow doesn't sufficiently alert the user of an error or isn't correctly configured.

「メインステージ分析の同意取得」フローで、ユーザーにエラーが十分に警告されないか、正しく構成されていません。
:::


# ケース番号 4036: フローによるエラーのロールバックと追跡

カスタムエラー ログオブジェクトにインシデントのレコードを追加することで、ユーザー エクスペリエンスを強化し、フロー エラーを追跡します。

:::note alert
The 'New Account Contact' flow doesn't have a fault path.


「新規アカウント連絡先」フローには障害パスがありません。
:::

:::note alert
The 'New Account Contact' flow doesn't prevent a new opportunity record from incorrectly forming.

「新規取引先担当者」フローでは、新しい商談レコードが誤って形成されるのを防ぐことはできません。
:::

:::note alert
The 'New Account Contact' flow doesn't redirect the user to the New Account Contact screen.


「新しいアカウント連絡先」フローでは、ユーザーは「新しいアカウント連絡先」画面にリダイレクトされません。
:::
XIAO ESP32C6+SSD1306、「回復のアイテム」を表示して遊ぶ。(drawBitmap)


参考
----

https://qiita.com/caa45040/items/574231109a31cb6c55eb

https://qiita.com/caa45040/items/3c57c159be0fd0f7a718

https://qiita.com/caa45040/items/f7698f087967381f91af

いろいろ、注意
----

- 過去ログをみよ
- 3.2.0
- Adafruit GFXのインストール
- Adafruit SSD1306のインストール
- 8x8ビットマップ表示の命令

```c++

display.drawBitmap(0, 0, databytes, 8, 8,  WHITE);

```




結果
----

![o_coq876.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/1ed2158f-7c0b-44cb-9fc4-d29a44c1a9e7.jpeg)


![o_cop275.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/24a1e43b-14a1-471c-804a-b2744a99dcc9.jpeg)


![o_cop372.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/7ccd92e4-3187-444f-8b30-5eacc6d69c0b.jpeg)


プログラム
----

```c++



//OLED_SSD1331_BITMAP_TEST1_XIAO_ESP32C6


//ヘッダーファイル
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>


//定義
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


// ビットマップデータ
uint8_t databytes[] = {
0b01100110,// ..  ..
0b10101111,//. . ....
0b10111111,//. ......
0b11011111,//.. .....
0b01111110,// ......
0b01111110,// ......
0b00111100,//  ....
0b00011000 //   ..
};


//初期化
void setup() {

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

  // I2Cアドレスは使用するディスプレイに合わせて変更する
  display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);

}//setup


//メインループ
void loop() {

  // 画面表示をクリア
  display.fillScreen(BLACK);

  //ビットマップの表示
  display.drawBitmap(0, 0, databytes, 8, 8,  WHITE);

  // 描画バッファの内容を画面に表示
  display.display();


  delay(1000); //1秒待つ

}//loop


```
インターフェース分離の原則（ISP）におけるOOPとFPの比較

インターフェース分離の原則（ISP: Interface Segregation Principle）は、「クライアントは自分が使用しないメソッドへの依存を強制されるべきではない」という原則です。これは、肥大化したインターフェースから生じる影響を避け、小さく目的ごとに分割されたインターフェースを使うことを推奨します。

OOPではインターフェースの分割と実装によって、FPでは関数の構成と引数単位の依存注入によってISPを達成できます。

#### インターフェース分離の原則についての詳しくはこちらで
https://shuji-bonji.github.io/Notes-on-SOLID-Principle/interface-segregation-principle.html

## OOPにおけるISPの実装例

```ts
interface Printer {
  print(): void;
}

interface Scanner {
  scan(): void;
}

class MultiFunctionPrinter implements Printer, Scanner {
  print(): void {
    console.log('Printing...');
  }

  scan(): void {
    console.log('Scanning...');
  }
}

class SimplePrinter implements Printer {
  print(): void {
    console.log('Printing...');
  }
}
```
必要な機能だけを持つインターフェースを定義し、クラスはそれを選んで実装することで、余計な依存を避けることができます。

## FPにおけるISPの実装例

```ts
type Print = () => void;
type Scan = () => void;

const createMultiFunctionPrinter = (print: Print, scan: Scan) => ({
  print,
  scan,
});

const createSimplePrinter = (print: Print) => ({
  print,
});
```

- 必要な関数だけを構成要素として渡すことで、不要な依存を避ける構成が自然に実現されます。
- 各機能（副作用）を関数単位で分離して注入するため、モジュールの関心が明確になります。


## 比較まとめ

| 観点 | OOP | FP |
|------|-----|----|
| 分割の単位 | インターフェース | 関数と構造体 |
| 実装方法 | 実装クラスが必要なものを選択 | 必要な関数だけを構成する |
| 拡張性 | インターフェース追加と実装切り替え | 関数の合成・組み合わせで対応 |
| テスト容易性 | 不要な機能を含まないことで容易になる | 最小構成の関数をテスト可能 |
| 注意点 | 分割しすぎると煩雑化 | 関数注入の構造がわかりづらくなる場合がある |

OOPではインターフェースの肥大化を避け、FPでは関数の責任を明示的に分離することで、インターフェース分離の原則はどちらのパラダイムでも自然に適用できます。

次回は[「依存性逆転の原則（DIP）における関数型の応用」](https://qiita.com/bonji/items/4aa41cbe3bb40a00428e)についてです。
リスコフの置換原則（LSP）におけるOOPとFPの比較

リスコフの置換原則（LSP: Liskov Substitution Principle）は、「派生クラスは基底クラスと置き換えてもプログラムの正しさが保たれるべきである」という設計原則です。OOPでは継承の安全性が問われるのに対し、関数型では型の整合性と構造の一貫性に注目が集まります

#### リスコフの置換原則についての詳しくはこちらで
https://shuji-bonji.github.io/Notes-on-SOLID-Principle/liskov-substitution-principle.html


## OOPにおけるLSPの実装例
```ts
interface Flyer {
  fly(): void;
}

class Bird {
  // 共通の鳥の性質（例: 鳴くなど）
}

class Sparrow extends Bird implements Flyer {
  fly(): void {
    console.log('スズメが飛んだ');
  }
}

class Penguin extends Bird {
  // fly() は実装しない
}
```
```ts
function makeFly(flyer: Flyer): void {
  flyer.fly();
}

const sparrow = new Sparrow();
makeFly(sparrow); // ✅ OK

const penguin = new Penguin();
// makeFly(penguin); // ❌ コンパイルエラー（型不一致）
```

このようにすれば、`Flyer` 型に対してのみ `fly()` を呼び出せるようになるため、**置き換え可能な設計＝リスコフの置換原則に準拠した設計**になります。


## FPにおけるLSPの実装例
関数型では「型ごとの明確な分離」と「構造の保証」により、LSP違反を事前に防ぎやすくなっています。

```ts
type Bird = { kind: 'bird'; fly: () => string };
type Ostrich = { kind: 'ostrich' };

type Animal = Bird | Ostrich;

const isBird = (a: Animal): a is Bird => a.kind === 'bird';

const makeFly = (animal: Animal): string =>
  isBird(animal) ? animal.fly() : 'I cannot fly';
```

- 明示的に `Ostrich` の飛行不能を表現することで、「安全に置換できる前提」を避けている。
- ユニオン型とパターンマッチにより、型の置換が意味的にも安全。


## 比較まとめ

| 観点 | OOP | FP |
|------|-----|----|
| 抽象化手段 | 継承とインターフェース | ユニオン型・タグ付き構造 |
| LSP違反の危険 | 実行時に現れる | 型で表現され防止しやすい |
| 置換の安全性 | 意図しないオーバーライドに注意 | 明示的な分岐で安全な選択 |
| テスト性 | モックによる検証が必要 | 型の分離により検証容易 |

継承や共通インターフェースを使うOOPでは、意味的な一致まで注意が必要です。関数型では構造的に明示することで、LSPのリスクを低減できます。

次回は[「インターフェース分離の原則（ISP）におけるOOPとFPの比較」](https://qiita.com/bonji/items/6060ec1fa721e0e5b89c)についてです。
cscの作法 その585

# 概要
cscの作法、調べてみた。
OpenRCF v2.8、見つけたので、windows11で、MSbuildしてみた。
練習問題やってみた。

# 練習問題
ぶつかり判定せよ。ローバーが壁にぶつかったら止まれ。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/fedc6edb-a334-4133-a7a0-237bdcc83b32.png)


# サンプルコード

```

using System;
using System.Windows;
using OpenRCF;
using Vector = OpenRCF.Vector;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;


namespace OpenRCF
{
	partial class MainWindow: Window {
		Sphere rover = new Sphere(0.25f);
		Cuboid wall = new Cuboid();
		Sphere p1 = new Sphere(0.05f);
		float[] point1 = new float[3] {3.0f, 0, 0.2f};
		bool isMoved = false;
		class Agent {
			float err2 = 0;
			float err = 0;
			float P = 0;
			float I = 0;
			float D = 0;
			public float get_action(float setPoint, float input) {
				float Kp = 0.02f;
				float Ki = 0.002f;
				float Kd = 0.002f;
				float dt = 0.05f;
				this.P = setPoint - input;
				this.I += this.P * dt;
				this.D = (this.P - this.err2) / dt;
				float u = Kp * this.P + Ki * this.I + Kd * this.D;
				this.err2 = this.err;
				this.err = this.P;
				return u;
			}
		}
		float getDistance(float x, float y, float x2, float y2) {
			float distance = (float) Math.Sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y));
			return distance;
		}
		Agent agent0 = new Agent();
		Agent agent1 = new Agent();
		void to(float[] point) {
			float x = rover.Position[0];
			float y = rover.Position[2];
			float u0 = agent0.get_action(point[0], x);
			float u1 = agent1.get_action(point[2], y);
			Console.WriteLine(u0);
			rover.Position[0] += u0;
			rover.Position[2] += u1;
		}
		void Setup() {
			rover.Position[0] = -3.0f;
			rover.Position[2] = rover.Radius;
			p1.Position = point1;
			wall = new Cuboid(0.3f, 1, 0.5f);
			wall.Position[2] = 0.25f;
			Button1.Content = "start";
			Button2.Content = "reset";
			Button3.Content = "none";
			Button4.Content = "none";
			Button5.Content = "none";
		}
		void Loop() {
			if (isMoved)
			{
				float dis = getDistance(point1[0], point1[2], rover.Position[0], rover.Position[2]);
				if (dis < 0.3)
				{
					isMoved = false;
					return;
				}
				to(point1);
				if (wall.IsCollided(rover))
				{
					rover.Color.SetRed();
					isMoved = false;
				}
				else
					rover.Color.SetGray();
			}
		}
		void Draw() {
			rover.Draw();
			wall.Draw();
			p1.Draw();
		}
		void Button1_Click(object sender, RoutedEventArgs e) {
			isMoved = true;
		}
		void Button2_Click(object sender, RoutedEventArgs e) {
			rover.Position[0] = -3.0f;
			rover.Position[2] = rover.Radius;
			rover.Color.SetGray();
			isMoved = false;
		}
		void Button3_Click(object sender, RoutedEventArgs e) {
		}
		void Button4_Click(object sender, RoutedEventArgs e) {
		}
		void Button5_Click(object sender, RoutedEventArgs e) {
		}
	}
}





```

以上。
Java解説 20250422

### 一度書けばどこでも動く
JVMを利用することでOSの違いに依存することなく動作する。
### JVMによる処理
Javaを動かすためのソフトウェア
### オブジェクト指向
オブジェクトとは属性(データ)とメソッド(データに指示する操作)の2つがある。
<br>
[オラクル認定資格教科書 Javaプログラマ Bronze SE(試験番号1Z0-818)](https://www.amazon.co.jp/%E3%82%AA%E3%83%A9%E3%82%AF%E3%83%AB%E8%AA%8D%E5%AE%9A%E8%B3%87%E6%A0%BC%E6%95%99%E7%A7%91%E6%9B%B8-Java%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E-Bronze-SE-%E8%A9%A6%E9%A8%93%E7%95%AA%E5%8F%B71Z0-818/dp/479816206X/ref=pd_lpo_d_sccl_1/357-5313211-9846263?pd_rd_w=VQCzo&content-id=amzn1.sym.855d8f70-df76-4181-80b0-56e48ae3bb9b&pf_rd_p=855d8f70-df76-4181-80b0-56e48ae3bb9b&pf_rd_r=JRR4W9RKV32K4AXF1WRZ&pd_rd_wg=l7VoD&pd_rd_r=1d465f85-0562-4b51-b523-77f8486c1508&pd_rd_i=479816206X&psc=1 "オラクル認定資格教科書 Javaプログラマ Bronze SE(試験番号1Z0-818)")
H8のbinutilsとgccをportsにしてみた

以前作った[mipsのgcc4](https://qiita.com/yamori813/items/4e56dd404ec8617ccbab)と同じようにして、FreeBSDのportsにしてみました。FreeBSD 12,13でビルドできます。他は分かりません。

gccは8.4でbinutilsは2.37です。8.4が動作実績があり、なおかつ手元にaarch64-gcc 8.4のportsがあったので、これをMASTERにして作ってみました。

https://yamori813.github.io/hp/ports.tgz


binutilsは以下のようにしてmakeします。

```
% make FLAVOR=h8300_elf
```
知識ゼロの未経験エンジニアがTodo アプリを作った話

# 知識ゼロの未経験エンジニアがTodo アプリを作った話 ✨

こんにちは、Web 開発を始めたばかりの駆け出しエンジニア、k33です。\
コードの知識はまだ浅いですが、「使いやすくて見た目もかっこいい Todo リストを自分で作りたい！」と思い立ち、ChatGPT を相棒にプロトタイプを完成させました。

---

## ⭐ はじめに

- **Enter** でタスク追加、**Shift+Enter** で改行
- タスクは **ドラッグ＆ドロップ** で並び替え（SortableJS）
- **ダーク／ライトモード** 切替 ＋ **背景画像** のアップロード
- タスクの **完了チェック・編集・削除**
- **GA4** （gtag.js） でアクセス計測
- 完全クライアントサイド × **localStorage** で永続化
- **Vercel** で静的ホスティング

制作から公開まで約1週間。分からないことは ChatGPT に質問しながら進めたら、いつの間にか形になっていました。

デモ👉 [https://todo-static.vercel.app](https://todo-static.vercel.app)\
ソース👉 [https://github.com/k33-dev/todo-static](https://github.com/k33-dev/todo-static)

---

## 🎣 作ろうと思ったきっかけ

- 学習のモチベーションを保つために「自分だけの成果物」を作りたくて
- 最初は「localStorage にタスクを保存するだけ」のシンプル版からスタート
- 触ってみたら思いのほか面白くなり、機能をどんどん追加
- 特に「ChatGPT にコード例を聞く→コピペ→動作確認」を繰り返したら、一人でも高速に学べました

---

## 🛠 環境 & 技術スタック

- **言語／ライブラリ**\
  HTML / CSS / JavaScript (Vanilla)\
  [SortableJS](https://github.com/SortableJS/Sortable)
- **アクセス計測**\
  Google Analytics 4 (gtag.js)
- **データ永続化**\
  localStorage
- **ホスティング**\
  Vercel

---

## 🐞 実装のハマりどころ

### 1. SortableJS で画面とデータを同期

```js
new Sortable(taskList, {
  animation: 120,
  onEnd: e => {
    // 画面上の要素は動くけれど、データ配列も動かないとズレる！
    const [moved] = tasks.splice(e.oldIndex, 1);
    tasks.splice(e.newIndex, 0, moved);
    save();  // localStorage に保存
  }
});
```

### 2. GA4 の測定IDを正しく設定
```html
<script async src="https://www.googletagmanager.com/gtag/js?id=G-R0PYZSP0YC"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-R0PYZSP0YC');
</script>
```
- **Point**: `?id=` と `gtag('config', ...)` の値を**同一**にしないと計測されません。

---

## 🎨 カスタマイズポイント

- **テーマカラー変更**: CSS の `--accent` を書き換えるだけで雰囲気を一新できます。
- **アニメーション速度調整**: `transition-duration` や `animation` の値を変えて、スムーズさを好みの速さに。
- **背景画像アップロード**: 自分だけのオリジナル背景を設定して個性を演出。

---

## 📊 GA4 で見える化

- ページビューやユーザー数を**リアルタイム**レポートでチェック
- タスク追加・削除は**イベント計測**も実装
  ```js
  gtag('event', 'add_task');
  gtag('event', 'delete_task');
  ```
- ユーザー行動を分析し、今後のアップデートや機能改善に活かせます。

---

## 💡 まとめ

- 駆け出しエンジニアでも、ChatGPT のサポートでここまで作り込める！
- 完全クライアントサイド設計でシンプル＆高速。
- SortableJS × Vanilla JS の組み合わせは軽量ながら高機能。
- GA4 を導入すればユーザー動向をデータとして蓄積・分析可能。

ぜひデモを触ってみて、GitHub でスター・フォーク、コメントをお待ちしています 🌟

---



#### SNS
Twitter(X): [@toe78560468](https://x.com/toe78560468)
Geminiでギターを使う魔法少女を描いてみた。

# 概要

Geminiでギターを使う魔法少女を描いてみました。

# 実装

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

```
炎のギターを使う魔法少女を描いてみてください。
```

![炎のギターを使う魔法少女_20250422.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192024/6478bc24-ef62-418e-98d9-3a6515e19a44.png)

```
電撃のギターを使う魔法少女を描いてみてください。
```

![電撃のギターを使う魔法少女_20250422.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192024/d6622f34-340f-4f42-a9cc-a0e41b7eea71.png)

# まとめ

電撃の子が可愛い。
何かの役に立てばと。
2025/4/22主にITとかセキュリティの記事

npm偽Telegramパッケージが仕掛けるLinuxへのSSHバックドア攻撃 – starjacking手法で開発者を欺く新たな脅威(4/20)
https://innovatopia.jp/cyber-security/cyber-security-news/51990/

Kubescape事例から学ぶオープンソース戦略：20万クラスターが証明する信頼構築の力(4/20)
https://innovatopia.jp/cyber-security/cyber-security-news/51987/

OpenAI Codex CLI のソースコードを読む(4/19)
https://zenn.dev/takiko/articles/e2b8065158c8d0

MCPサーバーでAIエージェントをおどおど系ボクっ娘後輩キャラにする(4/19)
https://zenn.dev/abelia/articles/4e0f9dd67d93e4

サイバー捜査にNEC・セコムの知恵　回り始めた人材ドア(4/20)
https://www.nikkei.com/article/DGXZQOUE164NF0W5A410C2000000/

＜社説＞アルバム漏えい　脅かされる子どもの情報(4/20)
https://www.hokkaido-np.co.jp/article/1150568/

【Codex CLI実践検証】非エンジニアでも業務効率化できる！画像からUI生成、PDF文字起こしまで(4/20)
https://weel.co.jp/media/tech/openai-codex-cli/

米国 下院 中国共産党に関する特別委員会 DeepSeekに関する報告書...(2025.04.16)(4/20)
http://maruyama-mitsuhiko.cocolog-nifty.com/security/2025/04/post-78ba2c.html

Terraform と ecspresso を使って CloudFront + ALB + ECS + gRPC な環境を構築してみた(4/20)
https://dev.classmethod.jp/articles/grpc-cloudfront-terraform-ecspresso/

Amazon Neptuneで始めるグラフDB(4/19)
https://qiita.com/yakumo_09/items/f1c29a3b46abd10a45a5

平井一夫　私の履歴書（20）サイバー攻撃 ソニー元社長(4/20)
https://www.nikkei.com/article/DGXZQOCD161GH0W5A310C2000000/

「+」で始まり「0110」で終わる電話番号からの着信に要注意！増加の一途をたどる警察官なりすまし詐欺の実態(4/20)
https://nikkeimatome.com/?p=57818

アメリカで急成長している高収入の仕事トップ20 2025年版(4/20)
https://www.businessinsider.jp/article/2504-high-paying-occupations-job-growth/

かつてビットコインを「マネロンの温床」と公然と批判したブラックロックのラリー・フィンクCEOが、わずか数年で態度を一変させ、世界最大級のビットコインETF運営と巨額保有へ至るまでの軌跡とは？(4/20)
https://nikkeimatome.com/?p=57887

小売業の未来：消費者エンゲージメントとテクノロジー統合の新時代(4/19)
https://internationalsupermarketnews.com/ja/archives/19442

ＡＩの軍事利用禁止を 衆院委　無人機開発合意で塩川氏(4/20)
https://www.jcp.or.jp/akahata/aik25/2025-04-20/2025042002_03_0.html
計算がはやくなるPythonコード(日記)

https://examist.jp/sokusanjyutu/
```Python
# プログラム名: math_operations_all_in_one.py
# 内容: 素因数分解・累乗・演算・恒等式検証などを一括実行するPythonコード

import sympy as sp

# === (1) 1〜300 の素因数分解 ===
print("[1] 素因数分解 (1〜300)")
for n in range(1, 301):
    print(f"{n}: {sp.factorint(n)}")
print("-" * 50)

# === (2) 累乗と逆数の計算 ===
N = 10
print("[2] 累乗と逆数（N=10）")
print(f"2^{N} = {2**N}")
print(f"3^{N} = {3**N}")
print(f"5^{N} = {5**N}")
print(f"6^{N} = {6**N}")
print(f"7^{N} = {7**N}")
print(f"N×N = {N * N}")
print(f"1 / 2^{N} = {1 / 2**N:.10f}")
print(f"1 / 5^{N} = {1 / 5**N:.10f}")
print("-" * 50)

# === (3) 四則演算（A, B, C, D の設定） ===
A = 1000
B = 5
C = 999
D = 6

print("[3] 演算処理")
print(f"A - 1 = {A - 1}")
print(f"B + 1 = {B + 1}")
print(f"(C + 1) + (D - 1) = {(C + 1) + (D - 1)}")
print("-" * 50)

# === (4) A² = (A+B)(A−B) + B² の恒等式確認 ===
lhs = A**2
rhs = (A + B) * (A - B) + B**2
print("[4] 等式 A² = (A+B)(A−B) + B² の検証")
print(f"LHS = {lhs}")
print(f"RHS = {rhs}")
print("等式成立 ✅" if lhs == rhs else "等式不成立 ❌")
print("-" * 50)

# === (5) 演算：乗除 ===
print("[5] その他の演算")
print(f"48 × (100 − 1) = {48 * (100 - 1)}")
print(f"48 × (10 + 1) = {48 * (10 + 1)}")
print(f"133 ÷ 171 = {133 / 171:.10f}")
print("-" * 50)

```
M_String：各種定義

# 文字列処理の各種定義
```
'##############################################################################
' 文字列処理
'##############################################################################
' 参照設定          |   Microsoft VBScript Regular Expressions 5.5
'------------------------------------------------------------------------------
' 参照モジュール    |   ―
'------------------------------------------------------------------------------

'==============================================================================
' 公開定義
'==============================================================================
' 定数定義
'------------------------------------------------------------------------------
Public Enum E_STRING_SPEC
    E_STRING_SPEC_NONE = &H0
    E_STRING_SPEC_POS_START = &H1
    E_STRING_SPEC_POS_END = &H2
    E_STRING_SPEC_POS_MID = &H4
    E_STRING_SPEC_POS_BOTH = E_STRING_SPEC_POS_START Or E_STRING_SPEC_POS_END
    E_STRING_SPEC_MATCH_START = &H10
    E_STRING_SPEC_MATCH_END = &H20
    E_STRING_SPEC_MATCH_MID = &H40
    E_STRING_SPEC_MATCH_WORD = &H80
    E_STRING_SPEC_MATCH_ALL = E_STRING_SPEC_MATCH_START Or E_STRING_SPEC_MATCH_END
    E_STRING_SPEC_MATCH_MASK = E_STRING_SPEC_MATCH_START Or E_STRING_SPEC_MATCH_END Or E_STRING_SPEC_MATCH_MID
End Enum

Public Enum E_STRING_IDX_SRCH_INF
    E_STRING_IDX_SRCH_INF_NONE = D_IDX_START - 1
    E_STRING_IDX_SRCH_INF_POS_START
    E_STRING_IDX_SRCH_INF_LENGTH
    E_STRING_IDX_SRCH_INF_MAX
    E_STRING_IDX_SRCH_INF_EEND = E_STRING_IDX_SRCH_INF_MAX - 1
End Enum

Public Const D_STRING_MATCH_CHECKWORD As String = "[^A-Za-z0-9_]"

Public Const D_STRING_DLMT_EXTENSION As String = ";"

'------------------------------------------------------------------------------
' 構造体定義
'------------------------------------------------------------------------------
Public Type T_STRING_ARG_ADD_INF
    '文字列
    Target As String
    
    '区切り
    Dlmt As String
    DlmtChkFlg As Boolean
    
    '追加
    Add As String
    AddChkFlg As Boolean
    AddSpec As E_STRING_SPEC
    
    '対象外
    Excluded As String
End Type

Public Type T_STRING_ARG_SEARCH_INF
    '文字列
    Target As String
    
    '検索指定
    Search As String
    SrchSpec As E_STRING_SPEC
    SrchPtn As String
    
    '一致指定
    ChkPtn As String
    ChkSpec As E_STRING_SPEC
    ChkPtnOfs As Long
    
    '検索位置指定
    SttPos As Long
    EndPos As Long
    Length As Long
    
    '取得位置指定
    GetIdx As Long
End Type

Public Type T_STRING_ARG_GET_INF
    SrchInf As T_STRING_ARG_SEARCH_INF
    
    SttStr As String
    EndStr As String
    
    AddBefFlg As Boolean
    AddSrchFlg As Boolean
End Type

Public Type T_STRING_ARG_DEL_INF
    SrchInf As T_STRING_ARG_SEARCH_INF
    
    DelPosSpec As E_STRING_SPEC
    AddDelFlg As Boolean
End Type

'==============================================================================
' 内部定義
'==============================================================================
```
Mac × Raspberry Pi Pico 2 W でLチカしてみた【ラズパイ初心者】

3月に発売されたばかりのRaspberryPi Pico 2 W を買ったので動かしていきます。

ラズパイ自体慣れてないので練習としてとりあえずLチカ(その名の通りLEDをチカチカさせる)にチャレンジしてみました。

Pico 2 W の魅力は2,000円以下という超低価格で手に入るうえ、Wi-FiとBluetooth LEを搭載している点です。
初心者が練習用として扱うにはかなりちょうどいいと思います。

ちなみに私は秋月電子通商さんで購入しました。
ラズパイは公式の正規品を扱っているショップさんから買うのがおすすめです。

あと補足ですが、
**買うならぜっっっったいピンヘッダ実装済みのほうがいいです。あとで死ぬほど後悔します。**
スイッチサイエンスさんのこれとかいいと思います。

https://www.switch-science.com/products/10258


## とりあえずやっていきます！
### 今回使用するもの
- RaspberryPi pico 2 W
- Mac
- USB–microUSB ケーブル
- USBハブ



## 1\.MicroPythonのダウンロード

以下のリンクから一番上にある最新版をダウンロードします。

https://micropython.org/download/RPI_PICO2_W/

そしたらBOOTSELを押しながら、マイクロUSBコードを差し込みブートモードでラズパイに入ります。
するとFinderにラズパイが表示されます。

## 2\.ラズパイをブートモードで接続する
BOOTSEL ボタンを押しながら、マイクロUSBケーブルでPCに接続します。
すると、Finder上にラズパイがUSBドライブとして表示されます。

先ほどダウンロードした`.uf2`ファイルを、Finderに表示されたラズパイのドライブへドラッグ＆ドロップして書き込みます。
書き込みが完了すると、自動的にラズパイが再起動され、ドライブが表示されなくなります。
何も書き込まれていないと感じるかもしれないが気にしなくてOKです。

## 3\.Thonnyのインストール
Homebrewを使う場合
ターミナルで以下のコマンドを実行
```
brew install --cask thonny
```
または公式からインストール
https://thonny.org/

## 4\.Thonnyの設定
初回時に使用する言語を選んだら、
右下にあるボタンをクリックします。
![Monosnap Thonny  -  <無題>  @  1 : 1 2025-04-22 01-05-37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3982231/94bcfacf-3888-4053-95c1-3fc0d5cf1f72.png)
「インタプリタ設定」を次のようにする。
インタプリタ:
`MicroPython(Raspberry Pi Pico)`
ポートまたはWebREPL:
`/dev/cu.usbmodemXXXX` か `/dev/ttyACM0`

もしポートが表示されない場合は

ラズパイがブートモードで起動している可能性があるので、もう一回ラズパイを抜き差ししてみましょう。
その際BOOTSELボタンには触らないでください。

## 5\.Lチカしてみる
```python
# 0.5秒ごとにLチカさせる
from machine import Pin
import time

led = Pin("LED", Pin.OUT)

while True:
    led.toggle()
    time.sleep(0.5)
```
チカチカ光った！

止めたいときは、Thonnyで停止ボタンを押せば止まります。
ちなみにラズパイこんな感じです。めちゃめちゃ小さくてかわいいです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3982231/1137d0cb-bbc7-4871-9a02-215fc936131f.jpeg" width="300">

次はこのPico 2 W を使って、簡単なWebサーバーを構築してみたいと思います！