OmniAICreator/Qiita-1.07M huggingface dataset:
なぜシステムリプレイスは上手く行かないのか？

# はじめに

**システムのリプレイスが予定していた時期を超えて、そもそも終わる見込みがない**

これは私が最近体験したことでした。
そしてこの経験を経て、「リプレイス」ということについて色々議論をした中でシステムリプレイスのときに知っておくべきことを言語化することができました。

システムリプレイスはエンジニアをやっていれば、誰しもが経験することだと思います。

<font color="red">**あなたがやろうとしているリプレイスはうまくいきません**</font>

なぜシステムリプレイスがほとんどうまくいかないのかを今回は解説していきますので、いつかこの記事をプロジェクトの前に思い出していただければと思います。

# セカンドシステム症候群とは

システムのリプレイスやセカンドバージョンの多くの場合以下の問題を含んでいます。

- 新しい機能が追加される
- 機能がリッチになる
- UI/UXなどのデザインが改善される

これが「シンプルさを失う」「複雑化」などを引き起こします。

これはファーストリリースが最低限の機能だけで行われるのに対して、リプレイスの場合**既存のシステムが使える**ことに加えて、ビジネスサイドの「やりたいこと」「実現したいこと」などが追加されることにあります。

別の価値を追加することを理由にリプレイスすることが多くだと思います。そうなると既存の要件+αになりどんどん開発しないといけないことは増えていくわけです。

# リプレイスは予定通りに終わらない

もし仮にリプレイス対象のシステムを5年かけてコツコツ作り上げたものだとした場合、リプレイスは1,2年でやるとします。

このときに既存機能でも5年分を新しい技術などでやらないといけないのに、そこにデザインの刷新や機能追加などのビジネスサイドの要望もいれていくことになります。

長いプロジェクトになればなるほど、工数の膨らみは期間を伸ばすことになります。

例えば、1週間のプロジェクトが1.5倍に膨れても7.5日ですが、3ヶ月のプロジェクトであれば4.5ヶ月、2年のプロジェクトなら3年にも伸びてしまいます。

既存機能を完全にリプレイスするときには、既存機能がすべて使えることがマストな場合は多いです。するとすべての機能をリプレイス終えることがプロジェクトの単位にあるので、マイルストーンのような区切りをつけることが難しいです。

**プロジェクト期間は長くなり、工数が膨れたときの影響も大きくなるのでうまくいかないのです**

# うまくいくリプレイス

ではリプレイスを行うときにどうすれば予定通り、または予定とほぼ近い期間でリプレイスを行うことができるのでしょうか。

ここには2通りの方法があると考えています。

## 1. 既存システムから引き算をする

既存システムのリプレイスをする場合には多くの場合

既存システム + デザイン刷新や機能追加

と既存システム以外にも追加で作業が発生します。この機能追加がリプレイスを期間内で終わらない原因となります。
なので、追加した分だけ落とせる機能を見つける必要があります。

既存システム + デザイン刷新や機能追加 - 一部機能

このようにすることでプロジェクトの期間を縮めることができ、より確実にプロジェクトを進めることができるようになります。

**多くの場合既存機能はユーザーが利用しているため落とせないということも多く、なかなかこの選択を取れないことが多いです。**

# 2. 別システムを新たに作る

これはリプレイスとは少し考え方が変わります。
リプレイス対処のシステムを残したまま、共存したカタチで別システムを作ることにします。

この別システムでは、追加したい機能を提供したり、既存システムの改善したい機能などを部分的に提供するなどします。

どのように新しいシステムを作れば、ユーザーに価値が届くのかをしっかりと考える必要はあります。

リプレイスに比べてかなり小さいプロジェクトになるため、不確実な箇所が途中で工数を増加させても全体として大きな影響になることは少なくなります

**リプレイスをすることになった場合は別システムで対処できないかを考えることが大切です**

別システムを作ったうえで徐々にリプレイスをかけていくというのも将来的には可能です

# おわりに

そもそも最終的にかかるポイントはどんなやり方をしても代わらないはずです。

いかに早くして不確実なところを潰せるのか、工数の増加がサプライズにならないか(びっくりさせないか)が大切になります。

今回学んだのはプロジェクトが大きくなってしまうのはウォーターフォールのようにきっちりと不確実性がないという状態を作れないようなアジャイルではアンチパターンになるということでした。

もしアジャイルでリプレイスをやる場合はこの記事を参考にして新規システムが作れないかを考慮に入れてほしいです

ここまで読んでいただけた方はいいねとストックよろしくお願いします。
@Sicut_study をフォローいただけるととてもうれしく思います。

また明日の記事でお会いしましょう！

# JISOUのメンバー募集中！
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
実践的なカリキュラムで、あなたのエンジニアとしてのキャリアを最短で飛躍させましょう！
興味のある方は、ぜひホームページからお気軽にカウンセリングをお申し込みください！
▼▼▼

https://projisou.jp
【VSCode】エディタに文字数を示すルーラーを表示する方法

`settings.json`　に`editor.rulers`の設定を追記することでエディタに文字数を示すルーラーを表示できます。

```jsonc:settings.json
  "editor.rulers": [80, 100, 120]  // 80文字、100文字、120文字にルーラーを表示
```

記述すると以下のようにルーラーが表示されます。

![スクリーンショット 2024-06-19 19.45.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/b15878c7-7ccb-8a95-5304-cf6dffd15f6b.png)

また、ルーラーの色は `workbench.colorCustomizations` の `editorRuler.foreground` で変更できます。

```jsonc:settings.json
  "workbench.colorCustomizations": {
    "editorRuler.foreground": "" // ルーラーの色
  }
```
Amazon Linux 2にFishを導入してみよう


# Fish って？

https://fishshell.com/

Fishは、BashやZshと同じくシェルの一種です。
しかしFishはBashとは違い、保管機能があったり強調機能があったりと、より使いやすいシェルです。

# 早速入れてみよう

## 1. インストール
```Bash
cd /etc/yum.repos.d/
wget --no-check-certificate https://download.opensuse.org/repositories/shells:fish:release:3/CentOS_7/shells:fish:release:3.repo
yum install fish
```

## 2. デフォルトシェルを変更
```Bash
sudo yum install util-linux-user -y
sudo chsh -s `which fish` ec2-user
```

もう一回ログインし直すと、デフォルトシェルがFishになっているはずです。
## 3. 再起動
```Bash
exit
```

# 確認してみよう

以下のような画面が出れば成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/67839525-072e-b689-ceea-ae6d2bc3d684.png)

# 参考文献

https://stackoverflow.com/questions/42849248/how-do-i-install-fish-shell-on-aws-linux

https://dev.classmethod.jp/articles/amazon-linux2-install-fish/
⑧１日１０分で理解するコンテナ技術入門 - Docker Composeのネットワークについて -



# Docker Composeでネットワークを扱う方法
Docker Composeでネットワークを扱うには、`docker-compose.yaml`の最上位レイヤーで`network`セクションを追加して、ネットワークについて記述する必要があります。ここで指定するネットワークは、既存のものであっても、新たに定義するものであってもかまいません。

## 既存のネットワークを使う場合
既存のネットワークが、`docker network create my-external-network`コマンドで作成されたとすると、`docker-compose.yaml`は以下のようになります。
```yaml
version: '3'

services:
  web:
    image: nginx
    networks:
      - my-external-network

networks:
  my-external-network:
    external: true
```
`networks.my-external-network.external`を`true`にすることで、既存のネットワークを指定できます。

## 新たに定義する場合
`docker-compose.yaml`内で新しいネットワークを定義する場合、`docker-compose.yaml`は以下のようになります。
```yaml
version: '3'

services:
  web:
    image: nginx
    networks:
      - my-internal-network

networks:
  my-internal-network:
    driver: bridge
```
ボリュームの時と同様、`driver`を指定する必要があります。`driver`には以下のようなものが指定できます。
- bridge
- host
- overlay
- ipvlan
- macvlan
- none

他にも、サードパーティ製のネットワークプラグインをインストールして利用することもできます。

### bridge
デフォルトのL3ネットワークドライバです。同じブリッジネットワークに接続しているコンテナとIPアドレスを使って通信できます（`--link`オプションを使わない場合）。このドライバで通信できるのは、**同じDockerデーモンホスト上で動作するコンテナ**です。異なるDockerデーモン（例えば違うホスト上のコンテナ）と通信する場合には、OSレベルでルーティングを管理するか、`overlay`を使います。

ブリッジネットワークはデフォルトで用意されていますが、ユーザー定義も行えます。ユーザー定義とデフォルトにはいくつかの違いがあります。
- ユーザー定義の場合、コンテナ間のDNS名前解決を自動で提供
- ユーザー定義の場合、コンテナの接続・切断をコンテナを停止させずに行える
- デフォルトの場合、環境変数を共有する

また、ブリッジネットワークを使用する場合、外部にトラフィックを流すにはポートフォワーディングが必要になります。

### host
ホスト側のネットワーク機能を直接使う場合に使用する。コンテナは自身に対してIPアドレスを割り当てないので、コンテナがポート80をバインドして`host`ネットワークを使うと、ホストIPアドレス上のポート80で利用可能になります（ポートフォワーディングは不要）。

### overlay
オーバーレイネットワークは複数のDockerデーモンと同時に接続します。主にDocker Swarmを使う際に用いますが、今回はコンテナオーケストレーションツールとしてKubernetesを説明するため、省略します。

### ipvlan
IPvlanネットワークは、IPv4とIPv6の両IPアドレス割り当てを、ユーザーがまとめてコントロール可能にします。

### macvlan
macvlanネットワークは、コンテナに対してMACアドレスを割り当て可能にし、ネットワーク上の物理デバイスとして見えるようにするL2ネットワークです。DockerデーモンはコンテナのMacアドレスに従って、トラフィックをコンテナに対して転送します。MACアドレスを用いた通信を行いたい場合に使用します。

### none
全てのネットワーク機能を無効化します。このドライバを指定すると、コンテナ内では、ループバックデバイスのみが作成されます。

# まとめ
今回は、`docker compose`でネットワークを扱う方法を説明しました。`driver`は様々な種類がありますが、とりあえず`bridge`だけ使えるようにしておけばよいかと思います。次回は、`docker compose`を使ったサービスのスケーリングについて説明します。
Nucleo-L432KCとMbedOS6でエラー0x80FF0100の原因

Nucleo-L432KCでCAN通信をしようとしたらエラーが出たのでメモ

環境
マイコン：Nucleo-L432KC
開発環境：Keil Studio Cloud



以下エラーコード

```
++ MbedOS Error Info ++
Error Status: 0x80FF0100 Code: 256 Module: 255
Error Message: Fatal Run-time error
Location: 0x8004189
Error Value: 0x0
Current Thread: main Id: 0x20001BB4 Entry: 0x8005F6F StackSize: 0x1000 StackMem: 0x200007B8 SP: 0x20001684
For more info, visit: https://mbed.com/s/error?error=0x80FF0100&tgt=NUCLEO_L432KC
-- MbedOS Error Info --
can ESR  0x1200.0010 + timeout status 0
```

エラーの原因
**CANの周波数をどこで定義するか**でした。

修正前
```cpp:main.cpp
CAN can(PA_11,PA_12);

略

int main(){
    can.frequency(500000); //500kbps
    略
}
```


修正後
```cpp:main.cpp
CAN can(PA_11,PA_12,500000);//周波数もここで定義！！

int main(){
    略
}

```

初めて見たエラーで戸惑いましたがうまく動いたのでよし。
モーダルサイズを自動で調整できるプロパティに出会って感動した

# はじめに
cssでモーダルを実装していた際に「fit-content」というプロパティに出会って感動したのでまとめておきたいと思います。fit-contentで子要素のサイズを元に親要素をリサイズしてくれます。


# コードサンプル

モーダルのヘッダーに表示する文字列の長さに合わせて、モーダルのサイズを調整してくれるような動きを実装したコードになります。便利だ…。

```jsx:hoge.jsx

const [isModalOpen, setIsModalOpen] = useState(false);
const [modalHaederText, setModalHaederText] = useState('');

{isModalOpen && (
  <div className="modal-overlay">
    <div
      className="hoge-modal"
      // fit-content
      style={{ width: 'fit-content', height: '70%' }}
    >
      <div
        className="hoge-modal-header"
        style={{
          display: 'flex',
          justifyContent: 'space-between',
          alignItems: 'center',
          width: '100%',
          marginRight: '50px',
        }}
      >
        <h2>
          {modalHaederText.length >= 10
            ? modalHaederText.slice(0, 10) + '…'
            : modalHaederText}{' '}
          ヘッダーに表示する文字列
        </h2>
        <FontAwesomeIcon
          icon={faSquareXmark}
          className="close-button"
          onClick={() => setIsModalOpen(false)}
        />
      </div>
      // モーダルの中身を表示する処理
    </div>
  </div>
)}
```

```css:style.css
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(128, 128, 128, 0.1);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 99;
}

.hoge-modal {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  background: white;
  max-width: 70%;
  max-height: 70%;
  border-radius: 15px;
  z-index: 101;
  display: flex;
  flex-direction: column;
}

.hoge-modal-header {
  padding: 15px;
  height: 15%;
  background-color: #0d74d3;
  border: solid;
  border-color: #0d74d3;
  border-width: 1px;
  border-radius: 15px 15px 0 0;
}

.hoge-modal-header h2 {
  line-height: 1;
  color: white;
  margin: 0;
}

.hoge-modal-header .close-button:hover {
  opacity: 0.8;
}

.hoge-modal-header .close-button {
  position: absolute;
  right: 0;
  padding: 5px;
  cursor: pointer;
  color: white;
  margin-right: 10px;
  font-size: 30px;
  transition: opacity 0.3s;
}

```

# おわりに
普段はChakraUIを利用しているのですが、fit-contentに代替するプロパティはないようです。
postfixでのメールログ調査の流れ

今回はメールログ調査の流れについてご紹介させていただきます。

## postfixとは

postfixはメール転送エージェントとなっております。

postfixを使用する事でメール配送等を行う事が出来ます。

OSSとして開発されており、サーバー業界でも高いシェア率を誇っております。

## 調査の流れ

初めにログ調査を行う流れをご紹介いたします。

大まかな流れは以下となっております。

1\. ログファイルの場所を確認する
2\. ログファイルからキューIDを絞り込む
3\. 配送ステータスを確認する

## ログファイルの場所を確認する

初めにログファイルの場所を確認する必要がございます。

既にログのパスを知っている方はスキップして大丈夫です!

postfixのデフォルトでのログは以下のパスに出力されます。

```
/var/log/maillog
```

上記パスにログが無い場合、ログ出力の指定が行われている可能性がございます。

下記設定ファイル等を確認しパスを確認してください。

```
/etc/postfix/main.cf
```

## ログファイルからキューIDを絞り込む

次にログファイルからキューIDを絞り込みます。

下記は「test01@example.com」から「test02@example.com」へメールを送信した際の例となります。

```
Jan 15 12:34:56 hostname postfix/pickup[12345]: ABC123DEF456: uid=1000 from=<test01@example.com>
Jan 15 12:34:56 hostname postfix/cleanup[12346]: ABC123DEF456: message-id=<20230115123456.12345.test01@example.com>
Jan 15 12:34:56 hostname postfix/qmgr[12347]: ABC123DEF456: from=<test01@example.com>, size=1234, nrcpt=1 (queue active)
Jan 15 12:34:57 hostname postfix/smtp[12348]: ABC123DEF456: to=<test02@example.com>, relay=mail.example.com[192.0.2.1]:25, delay=1.2, delays=0.1/0.1/0.5/0.5, dsn=2.0.0, status=sent (250 2.0.0 OK)
Jan 15 12:34:57 hostname postfix/qmgr[12347]: ABC123DEF456: removed
```

上記例でのキューIDは「ABC123DEF456」となっております。

その他の細かい説明は省かせて頂きますがキューIDにてログの表示条件を絞る事で一連の流れを確認する事が出来ます。

### FROM情報からキューIDを絞り込む

FROM情報からキューIDを絞り込む場合は以下の様にgrepを使用して絞りこむ事が出来ます。

```
cat /var/log/maillog |grep "from=<メールアドレス名>"
```

今回の例を使用すると以下となります。

```
#コマンド
cat /var/log/maillog |grep "from=<test01@example.com>"

#結果
Jan 15 12:34:56 hostname postfix/qmgr[12347]: ABC123DEF456: from=<test01@example.com>, size=1234, nrcpt=1 (queue active)
```


### TO情報からキューIDを絞り込む

TO情報からキューIDを絞り込む場合も先程同様の手順でgrepを使用して絞りこむ事が出来ます。

```
cat /var/log/maillog |grep "to=<メールアドレス名>"
```

今回の例を使用すると以下となります。

```
#コマンド
cat /var/log/maillog |grep "to=<test02@example.com>"

#結果
Jan 15 12:34:57 hostname postfix/smtp[12348]: ABC123DEF456: to=<test02@example.com>, relay=mail.example.com[192.0.2.1]:25, delay=1.2, delays=0.1/0.1/0.5/0.5, dsn=2.0.0, status=sent (250 2.0.0 OK)
```

その他にも日付や時間、メッセージID、IPアドレス等の情報を組み合わせる事でキューIDの絞り込みを行う事が出来ます。

## 配送ステータスを確認する

先程の手順でキューIDの絞り込みが完了したら配送ステータスを確認します。

配送ステータスは「to=<メールアドレス名>」が記載された行の「status」項目で確認する事が出来ます。

```
status=ステータス名
```

ステータス一覧は以下となります。

| ステータス名 | 説明             |
|:------------|:-----------------|
| sent        | 配送成功         |
| bounced     | 配送失敗         |
| deferred    | 一時的に配送不可  |

今回の例のログは以下となります。

```
Jan 15 12:34:57 hostname postfix/smtp[12348]: ABC123DEF456: to=<test02@example.com>, relay=mail.example.com[192.0.2.1]:25, delay=1.2, delays=0.1/0.1/0.5/0.5, dsn=2.0.0, status=sent (250 2.0.0 OK)
```

「status=sent」となっている為、正常に配送された事が分かります。


以上の手順でメールログ調査を行う事が出来ます。
LLMガードレールとは

# はじめに

- LLMガードレールってなんですか？

## LLMガードレールとは
- LLMアプリケーションにおけるユーザーとのインタラクションを監視・制御するための一連の安全管理である
- LLMを組織内で定義された原則に沿って動作させるために、ユーザーと基盤モデルの間に位置するプログラム可能なルールベースのシステムである
- ガードレールの目的は、LLMの出力を特定の形式やコンテキストに強制し、各レスポンスを検証することである

## LLMにガードレールを実装する方法

### Guardrails.ai
- LLMアプリケーション用のガードレールフレームワークを提供するオープンソースのPythonパッケージである
- LLMレスポンスのpydantic形式の検証を実装している
- RAILの仕様に基づいて構築されており、LLMの出力に特定のルールを適用し、LLM APIコールを軽量にラップする

https://github.com/guardrails-ai/guardrails

### NeMo Guardrails
- NVIDIAが開発したオープンソースのツールキットで、LLMシステムにプログラム的なガードレールを提供する
- 会話システムにレールを作成し、LLMを動力源とするアプリケーションが望ましくないトピックの特定の議論に関与することを防ぐ
- モデル、チェーン、サービスなどをアクションとシームレスかつ安全に接続する機能を提供する
- LLMガードレールのための新しいモデリング言語であるColangを導入している

https://github.com/NVIDIA/NeMo-Guardrails

## Guardrails AIとNeMoの比較
- どちらのパッケージもリアルタイムでLLMアプリケーションにガードレールを提供し、オーケストレーションにLangChainをサポートしている
- XMLの構文に慣れていて、出力の単純なモデレーションとフォーマットのためにノートブック内でガードレールの概念をテストしたい場合は、Guardrails AIが適している
- LLMアプリケーションを本番環境に移行し、高度な会話ガイドラインとポリシーをフローに定義したい場合は、NeMoガードレールが適している

| 比較項目 | Guardrails AI | NeMo Guardrails|
|----------|---------------|-----------------|
| 開発元 | オープンソースコミュニティ | NVIDIA |
| 主な目的 | LLMの出力の検証と修正 | 会話システムにおけるガードレールの提供 |
| 設定方法 | RAIL (XML方言) を使用 | Colang (独自のモデリング言語) を使用 |
| 主な機能 | - LLMレスポンスのpydantic形式の検証<br>- LLM APIコールの軽量ラッピング | - 会話フローの定義<br>- モデル、チェーン、サービスとアクションの接続 |
| LangChainとの統合 | 可能 | 可能 |
| 適したユースケース | - ノートブック内でのガードレールの概念のテスト<br>- 出力の単純なモデレーションとフォーマット | - LLMアプリケーションの本番環境への移行<br>- 高度な会話ガイドラインとポリシーの定義 |
| ドキュメンテーション | 豊富な例を含む広範なドキュメント | 十分なドキュメント |
| コミュニティのサポート | オープンソースコミュニティによるサポート | NVIDIAおよびオープンソースコミュニティによるサポート |


## まとめ
- LLM内でのガードレールの実装は、責任あるAIガバナンスに向けた重要なステップである
- Guardrails.aiやNeMo Guardrailsのようなオープンソースのパッケージは、AIモデルが私たちの生活のあらゆる側面を支配しないようにするための良い出発点である

## Appendix 用語まとめ

| 用語 | 説明 |
|------|------|
| ガードレール (Guardrails) | LLMアプリケーションにおけるユーザーとのインタラクションを監視・制御するための一連の安全管理。 |
| Guardrails.ai | LLMアプリケーション用のガードレールフレームワークを提供するオープンソースのPythonパッケージ。 |
| RAIL (Reliable AI Markup Language) | LLMの出力に対して特定のルールと修正アクションを指定するための、言語に依存せず人間が読める形式。XMLの方言。 |
| NeMo Guardrails | NVIDIAが開発したオープンソースのツールキットで、LLMシステムにプログラム的なガードレールを提供する。 |
| Colang | NeMo Guardrailsで導入された、LLMガードレールのための新しいモデリング言語。 |
| LangChain | 言語モデルを使用してアプリケーションを構築するためのPythonライブラリ。ガードレールとの統合が可能。 |
| pydantic | Pythonのデータバリデーションとシリアライゼーションのためのライブラリ。Guardrails.aiではLLMレスポンスの検証に使用される。 |
学生必見！プログラミングで見る英単語！第四弾


# この記事は？
この記事はシリーズの途中になります。
いよいよこのシリーズも4回目になり、中級ぐらいの難易度で記事を書いています。

https://qiita.com/Takkesan/items/348aa47379cb791457dc

# 本編

## review

- 再検討する

```
I will review the code and get back to you.
コードを再検討してから連絡します。
```
コードレビューのレビュー！

## conference

- 会議

```
I will attend the Qiita conference.
Qiitaのカンファレンスに出席します。
```
技術系のイベントで〇〇カンファレンスってよく聞きますよね

## code

- コード
- 記号
- 暗号

```
This code has a critical bug.
このコードに致命的なバグがあります。
```
codeは記号って言う意味もあるから注意！アニメとかで〇〇コードとか聞く気がする

## virtual

- 仮想の

```
This is a virtual machine.
これは仮想マシンです。
```
サーバーとか弄り始めたから仮想マシンのことをよく聞くようになった

## request

- 要求する

```
You can request a new feature.
新しい機能を要求することができます。
```
APIとか叩くことで言ったり。やはりネットワークが普及したから広く使われるようになったのかも

## grant

- 付与する

```
In SQL, you can grant permission to a user
SQLではユーザーに権限を付与することができます。
```
許可っていう意味を表す単語はたくさん！
SQLのgrant文で見るよね

## ban

- 禁止する

```
You will be banned from this server.
このサーバーからあなたはBANされます。
```
ゲーマの間でよく聞く単語かも。強い言葉だからこれも使いどころには気をつけよう

## recover

- 回復する

```
You can recover the deleted file.
削除したファイルを回復することができます。
```
データ復旧ツールとかでつきがち。バックアップは大事。

## budget

- 予算

```
In AWS, we can make a budget.
AWSでは予算を作成することができます。
```
クラウドでは予算が設定できる。アラートを出して気付けるようにしよう

## fee

- 料金

```
Unity fee was discussed among users.
Unity fee についてユーザー間で話し合われました。
```
これ発表されたときすごく炎上したよね...
自分はこれでこの単語を覚えた

## route

- 道筋

```
This is the route to the nearest station.
これは最寄り駅への道筋です。
```
Route53でも見る単語。ルーターもこれから来てますね

## routine

- 決まりきった仕事

```
C# has a routine system.
C#にはルーチンシステムがあります。
```
非同期で処理をするときによく使う。ルーチンとかコルーチンとか

## client

- 顧客
- ユーザーのコンピューター

```
Unknown client is trying to connect.
不明なクライアントが接続しようとしています。
```
クライアントってITの世界だとコンピューターのことを表したり。
確かにサーバーに来るコンピューターはお客さんなのかな

## abstract

- 抽象的な

```
This is an abstract class.
これは抽象クラスです。
```
プログラミングをしてると覚える単語だけど、普段は全然見ない。

## minor

- 小さい

```
This is a minor bug.
これは小さなバグです。
```
majorの対義語。マイナーアップデートとか聞くよね

## stable

- 安定した

```
There are stable versions of the software.
そのソフトウェアには安定版があります。
```
最新バージョンよりも安定版！商用ならばなおさらですね

## commit

- 約束する

```
When you change the code, you should commit.
コードを変更するときはコミットするべきです。
```
Gitで毎回使うやつ。バシッと決めるイメージ

## enhance

- 向上させる

```
I made a tool to enhance the performance.
性能を向上させるためのツールを作りました。
```
enhanced 〇〇 とかゲームのアセットで見る。アプリ開発とかでもあるのかな

## quit

- やめる

```
When you leave the computer, you should type quit command.
コンピューターを離れるときはquitコマンドを入力してください。
```
quitをしないで接続を切っちゃうとゾンビプロセスが残っちゃうかも

## reserve

- 予約する

```
This EC2 instance is reserved.
このEC2インスタンスは予約されています。
```
リザーブドインスタンスのリザーブ！
他のクラウドサービスだとどんな割引があるんだろうか
RDCManめちゃ便利

# はじめに
リモートデスクトップ接続はどのように行っていますか？
うちでは残念ながらコンテナ化が進んでいないので仮想環境をたくさん立てて接続先を切り替えて開発をすることが多いです。

Windows標準のリモートデスクトップ接続だと環境の切り替えがかなりめんどくさいので、いいものないかなと思って使い始めたのがRDCManでした。

# RDCManとは
リモートデスクトップ接続を管理するアプリケーションです。
脆弱性が見つかって一時期配布終了していましたが、そちらも修正されて今は再度公開されています。

# メリット
## 環境の切り替えが楽
RDCMan一つ立ち上げておけばいちいちリモートデスクトップ接続アプリを立ち上げなくても環境の切り替えがダブルクリックで済みます。

## パスワードを入力しなくていい
端末ごとのパスワードを保存できるのでパスワードを毎回入れる必要がないのでとても楽です。
また、パスワードは暗号化されているのでセキュリティ的にも安心です。
そして、親フォルダの認証情報を子のサーバが使用できるので共通のID/パスワードを使用している場合は親フォルダに情報を入力するだけで子の情報の入力がいらないとことも便利です。

# デメリット
## 使えないショートカットがある
エクスプローラを開いたりタスクマネージャーを開いたりするキーボードのショートカットはリモート接続先ではなく元のPCが反応します。

## まとめ
リモート接続環境を複数使う場合はとても便利なアプリなのでぜひ使ってみてください！！

## 参考
https://learn.microsoft.com/ja-jp/sysinternals/downloads/rdcman
あるWebエンジニアがchocolateyでインストールしているもののリスト

```
choco install -y 7zip 7zip.install adobereader autohotkey.portable bitcomet chocolatey chocolatey-compatibility.extension chocolatey-core.extension chocolatey-dotnetfx.extension chocolateygui chocolatey-misc-helpers.extension chocolatey-vscode chocolatey-vscode.extension chocolatey-windowsupdate.extension chrome-remote-desktop-chrome chrome-remote-desktop-host curl docker-desktop docker-for-windows docker-machine docker-toolbox DotNet4.5.2 DotNet4.6.1 dotnetfx ecm gimp git git.install GoogleChrome googledrive grep InkScape irfanview KB2919355 KB2919442 KB2999226 KB3033929 KB3035131 KB3118401 microsoft-windows-terminal obs-studio obs-studio.install openshot powershell-core python python3 python312 ruby ruby.install sakuraeditor slack strawberryperl vcredist140 vcredist2015 vcredist2017 vlc vlc.install voicemeeter-banana voicemeeter-banana.install vscode vscode.install vscode-docker vscode-python vscode-ruby vscode-yaml Wget
```
obnizのREST APIにアクセストークン付きでリクエストする


obnizのREST APIたまに使うと便利だったりします。

https://docs.obniz.com/ja/reference/cloud/hardware-api/rest-api

## 通常サンプル

アクセストークン無しだと以下のようにリクエストできます。

```bash
curl https://obniz.com/obniz/1234-5678/api/1 -H "Content-Type: application/json" -X POST -d '[{"display":{"clear":true, "text":"Works fine."}}]'
```

## アクセストークン付き

アクセストークン付きのサンプルリクエストがドキュメントページになかったのでメモしておきます。

HeaderのAuthorizationに入れ込めば良いという単純なやつですがコピペサンプルがあると楽なのと最近アクセストークン発行を行っておくと管理者コントロールがしやすいことを学んだのでこちらの使い方をデフォにしていく可能性もあったりします。

> ![スクリーンショット 2024-06-19 18.35.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/0bd416e0-27d2-69a6-07e1-5f11c6e43f74.png "スクリーンショット 2024-06-19 18.35.14.png")
> アクセストークン見えてますが更新済みです。


```bash
curl https://obniz.com/obniz/1234-5678/api/1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-X POST \
-d '[{"display":{"clear":true, "text":"Works fine."}}]'
```


これでうまく動きました。

> ![スクリーンショット 2024-06-19 18.37.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/02ad14f1-3df3-6098-eede-c0a573481e1b.png "スクリーンショット 2024-06-19 18.37.42.png")
Netlifyでデプロイしてみよう！

# はじめに

Netlifyというサービスを利用してデプロイしてみたのですが、無料で簡単にデプロイできたのでまとめておきたいと思います。

https://www.netlify.com/

# デプロイまでの流れ

①デプロイしたいプロジェクトを用意する

デプロイ方法は以下の通りです。私はプロジェクトフォルダをアップロードする方法で挑戦しました。
- プロジェクトフォルダをアップロードする
- githubなどからプロジェクトを指定する

※Reactなどで簡単にプロジェクトを作りたい場合はこちらの記事をぜひ参考にしてみてください！

https://qiita.com/does_not_exist/items/b79b3fd51ea6ef39df23

②Netlifyでアカウント登録を済ませる
割愛

③Netlify上でプロジェクトフォルダをアップロードする

![1718755866.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2889192/ad647a62-88e3-d2a2-632d-f827f36f62e6.png)


ちなみにドメインも無料で変更できます。「https://~.netlify.app」 とひな形は決まっていますが。

![1718756047.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2889192/f196ef50-7312-727e-ec9e-79d6d03c19fe.png)

無料枠で帯域幅が100GB/月もあるので試しにデプロイする分であれば全然問題にならないです。

![1718755994.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2889192/9690ab88-5f53-07d2-5677-4e9134fa2290.png)



# おわりに
個人で作った簡単なサイトを公開するくらいであれば使い勝手良くて便利です。
Kyselyでcompileしたsqlとparametersを安全に合体する（mysql)

普通にmysql2にformat関数があった。
```ts
import { format } from "mysql2";
	const upd = await db
		.updateTable("article")
		.where("article.id", "=", 1)
		.set({ title: "exampleTitle" })
		.compile();
	const formatted = format(upd.sql, upd.parameters);
 // update `article` set `title` = 'exampleTitle' where `article`.`id` = 1
```
⑦１日１０分で理解するコンテナ技術入門 - Docker Composeのボリュームについて -

[前回](https://qiita.com/goroneko/items/9d0f977787dcff48fa12)はざっとDocker Composeの使い方について説明しました。今回は、ボリュームを扱う方法について少し深掘りしたいと思います。

# Docker Composeでボリュームを扱う方法
主に二つの方法があります。
1. サービス宣言の一部として、オンザフライで宣言する（バインドマウント）
1. 名前付きボリュームを作成して、サービス内で利用を宣言する

## オンザフライで宣言
オンザフライで宣言する場合、以下のような使用方法があります。
- ホスト上のパスを指定して割り当てる
- 一時的なデータをメモリ上に保存する
- ほかのサービスやコンテナ上のボリュームを割り当てる
    `docker compose`のver3ではオンザフライで宣言してこの使い方をすることができなくなった（`volumes_from`が廃止された）ので、割愛します。
### ホスト上のパスを指定して割り当てる
`[ホストのパス]:[コンテナのパス]`でホスト上のディレクトリとコンテナのディレクトリを結びつけることができます。ここで指定した`[コンテナのパス]`にコンテナ上でファイルを配置すると、`[ホストのパス]`にそのファイルが保存されます。また、読み書き権限の制御も行えます。その場合は、`[ホストのパス]:[コンテナのパス]:rw`を指定します（読み取り専用にしたいなら`r`のみつける）。

`docker-compose.yaml`では、`services.<サービス名>.volumes`配下に指定します。例えば、以下のようになります。
```yaml
version: '3.8'

services:
  web:
    build: .
    container_name: web
    volumes:
      - /home/opc/app/uploads:/app/uploads:rw
```
### 一時的なデータをメモリ上に保存する
`tmpfs`マウントを使用することで、一時的なデータをメモリ上に保存することができます。コンテナが停止すると、データは失われます。`tmpfs`マウントを使うときは、`services.<サービス名>.tmpfs`配下に指定します。
```yaml
version: '3.8'

services:
  cache:
    image: redis:latest
    tmpfs:
      - /var/lib/redis # コンテナ内のマウントポイントを指定
```

## 名前付きボリューム
ボリュームに名前を付けて宣言して、複数のコンテナやサービス間で共有することができます。現在は`volumes_from`ではなくこちらを使って共有するようです。
名前付きボリュームは、Dockerが管理するボリュームで、コンテナが削除されてもデータは保持されます。

名前付きボリュームは、以下のように定義できます。
```yaml
version: '3.8'

services:
  web:
    image: my-web-app:latest
    ports:
      - "8080:5000"
    volumes:
      - uploads:/app/uploads

volumes:
  uploads:
    driver: local
```
`driver`には、そのボリュームがどのようにストレージを提供するかを指定します。指定できるものとして、以下のようなものがあります（ほかにもあります）。
- local
- nfs
- cifs

### local
`local`ドライバーは、デフォルトで使用されるドライバーで、ホストマシンのファイルシステムにデータを保存します。
```yaml
volumes:
  my-local-volume:
    driver: local
    driver_opts:
      type: none
      device: /absolute/path/to/dir
      o: bind
```
### nfs
`nfs`ドライバーは、ネットワークファイルシステムを使用して、リモートサーバーにデータを保存します。複数のホスト間で共有ストレージを提供する場合に使用されます。
```yaml
volumes:
  my-nfs-volume:
    driver: nfs
    driver_opts:
      type: nfs
      o: addr=192.168.1.100,rw
      device: ":/path/to/nfs/dir"
```

### cifs
`cifs`ドライバーは、CIFSを使用して、Windowsネットワーク共有をマウントします。`cifs`ドライバーを使うと、ホスト上のマウントポイントを変更しなくても、Dockerで直接Samba共有ディレクトリをマウントできます。
```yaml
volumes:
  my-cifs-volume:
    driver: local
    driver_opts:
      type: cifs
      o: addr=uxxxx.your-server.de,username=user,password=pass,domain=domain
      device: "//server/share"
```
# まとめ
今回は`docker compose`でボリュームを扱う方法について簡単に説明しました。次回は`docker compose`でのネットワークの扱いについて説明します。
Salesforce記録➁:FLOW使用制限について(202406)

# Flow 制限について
Flow を使用する際は、Flow 制限と Apex ガバナ制限を考慮してください。

## 必要なエディション
使用可能：Salesforce Classic（すべての組織で利用できるわけではありません）および Lightning Experience
使用可能：Essentials、Professional、Enterprise、Performance、Unlimited、および Developer エディション

:::note warn
最大フローインタビューサイズは 1,000,000 バイト（約 1 MB）です。インタビューが大きすぎる場合は、保存または一時停止できません。
:::

## 組織ごとの制限
|制限タイプ|	Essentials または Professional エディション	|Enterprise、Unlimited、Performance または Developer エディション|
|:-:|:-:|:-:|
|各フローのバージョン数	|50	|50|
|各フローの実行時に実行される要素数|  <font color=red>なし</font>	|<font color=red>なし</font>|
|各フロータイプのアクティブフロー数|	5	|2,000|
|各フロータイプの総フロー数|	5	|4,000|
|1 時間あたりに再開されるフローインタビュー数または特定の時間に基づいて実行されるスケジュール済みアクションのグループ数	|1,000	|1,000|
|レコードのフィールド値に基づいて開始または再開される自動化の合計<br><ul><li>アクティブフローで定義された再開イベント</li><li>アクティブプロセスで定義されたスケジュール済みアクションのグループ</li><li>アクティブワークフロールールで定義された時間トリガー</li><li>再開された非アクティブフローインタビュー</li></ul>|	20,000|	20,000|
|24 時間あたりのスケジュールトリガーフローインタビュー数|	250,000 または組織内のユーザーライセンス数に 200 を掛けた数のいずれか大きい方2	| 左側同様|

:::note warn
1 API バージョン 57.0 では、2000 フロー要素の制限が削除されました。API バージョン 56.0 およびそれ以前のバージョンでは、フロー要素の最大数は 2000 でした。

2 この制限にカウントされるライセンスタイプには、フル Salesforce および Salesforce Platform ユーザーライセンス、アプリサブスクリプションユーザーライセンス、Chatter Only ユーザー、Identity ユーザー、および Company Communities ユーザーが含まれます。
:::

# 上記の公式SITEの紹介について、主な三つ：

#### １．FLOWのInterview作成制限約 1 MB
#### ２．FLOWの実行要素制限はなし(API 57以降のみ)
#### ３．1 時間あたりFLOW Interview起動制限 1,000
実際応用する時、他の制限の考慮が必要です。[Salesforce記録①]の章を参考
例：FLOWにLOOP条件があり、一つAction要素100msがかかることを判明し、CPU LIMIT TIME :10000msので、実行要素最大100個で分かる。
エラーメッセージは下記のように：
```
EXCEPTION_THROWN|[EXTERNAL]|System.LimitException: Apex CPU time limit exceeded
FLOW_ELEMENT_ERROR|Apex CPU time limit exceeded|FlowLoop|X1
```
DEBUGログでLOOP実行要素の時間を見て、まだLOOP回数を決める、以上



参考資料:https://help.salesforce.com/s/articleView?id=sf.flow_considerations_limit.htm&type=5
1変数データの可視化手法

# はじめに

1変数データの可視化をまとめました．

Pythonのデータ可視化でググっても，変数が1つの場合と2つの場合が混在していること，よくありますよね．
この記事では1変数のデータ可視化をまとめています．

可視化の例のために使用させていただいたデータ: [House Prices](https://www.kaggle.com/competitions/house-prices-advanced-regression-techniques)

``` py
import pandas as pd
import seaborn as sns
df = pd.read_csv("./train.csv", index_col=0)
```

# 棒グラフ

種類が少ないデータのカウントなど．

## カテゴリカルデータ

種類が多いデータなら.head(10)などを使って，カウントが多いデータのみを表示するのもアリ．

``` py
df["SaleCondition"].value_counts().plot.bar()
# sns.countplot(df["SaleCondition"])
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609800/6b6be533-4444-59e3-bab7-4e2eabc7e12d.png)

## 数値データ

``` py
df["OverallCond"].value_counts().sort_index().plot.bar()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609800/f2911248-468c-b1bd-df1d-5d0064bddf8e.png)

# 折れ線グラフ

seabornのlineplotなら，複数の折れ線グラフを一つの画像にまとめられます．

``` py
df['OverallCond'].value_counts().sort_index().plot.line()
# sns.lineplot(df['OverallCond'].value_counts().sort_index())
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609800/412e7b31-0406-fd58-52ea-c1fead6cc019.png)

# カーネル密度推定

これ (上) が こう (下) なる．

ノイズが酷いデータなら採用してもいいかもしれません．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609800/c4cd57bf-b0c1-5456-e18f-ec3121796ccd.png)
``` py
sns.kdeplot(df['YearBuilt'])
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609800/5eb4b1b0-9b69-8666-2d58-81162f834f78.png)

# ヒストグラム

pandasなら，データを一定区間で区切ってカウントして……とやらなくてもよしなにやってくれます．

``` py
df['GarageArea'].plot.hist()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609800/f84462a9-43a9-2f82-6551-111c21b1de82.png)

# Swarm plot

値に合わせて，点の数でカウントの多さを表します．

カウントが多すぎる場所は省略される (画像真ん中下あたりの端っこ) ので注意．

真偽値などの離散データをx軸に設定可能です．

``` py
sns.swarmplot(df["GarageArea"])
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609800/2990b7d2-67ef-2856-e6cf-fe185603fe0b.png)


# 箱ヒゲ図

四分位数をプロットします．はずれ値も丸で表示してくれるのが嬉しい．

真偽値などの離散データをx軸に設定可能です．

``` py
sns.boxplot(df["GarageArea"])
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609800/3f7ff8eb-b832-eb05-7d5a-fa4496ff65f3.png)

# バイオリン

kagglerがよく使っている印象があります．

データのカウントに応じて膨らみが大きくなります．
折れ線グラフを90度回転させた感じ．

真偽値などの離散データをx軸に設定可能です．

``` py 
sns.violinplot(df["GarageArea"])
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609800/286558be-c596-df83-a458-5a59c73b73df.png)
[macOS] [Swift] シリアルポートのパス名を取得する

https://qiita.com/nak435/items/7ad479867d3e7e7e84e6


昨年末の↑この記事は、内部で`ls /dev/cu*`コマンドを実行して、その結果を使う方法でした。それに対し、今回は [IOKit](https://developer.apple.com/documentation/iokit/)のAPIを使用して シリアルポートのパス名を取得する方法です。


元ネタは次のブログで公開されていたC言語のコードで、それをSwiftに書き直したものです。

https://ta2884.net/wordpress/osxでほにゃららするにはシリーズ（忘備録）/接続したusbのシリアルポート名を取得するには


<img width="350" alt="seri.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/0a97c6b0-d364-e70c-d2b2-a62a19760228.png" />


# コード

```swift:main.swift
import Foundation
import IOKit
import IOKit.serial

let main: () = {
    guard let serialBSDService = IOServiceMatching(kIOSerialBSDServiceValue) else { return }
    guard var dict = serialBSDService as NSDictionary as? [String: AnyObject] else { return }

    dict[kIOSerialBSDTypeKey] = kIOSerialBSDAllTypes as AnyObject
    var serialPortIterator = io_iterator_t()
    guard IOServiceGetMatchingServices(kIOMainPortDefault, serialBSDService, &serialPortIterator) == kIOReturnSuccess else { return }

    while case let modemService = IOIteratorNext(serialPortIterator), modemService != 0 {
        let prop = IORegistryEntryCreateCFProperty(modemService, kIOCalloutDeviceKey as CFString, kCFAllocatorDefault, IOOptionBits(0))
        if let value = prop?.takeUnretainedValue(), let bsdPath = value as? String {
            print(bsdPath)
        }
    }

    IOObjectRelease(serialPortIterator)
}()
```

```terminal:実行例
% swift main.swift
/dev/cu.wlan-debug
/dev/cu.usbmodemHIDEF1
/dev/cu.Bluetooth-Incoming-Port
/dev/cu.usbserial-53250003491
```

さすがネイティブ、早いです。
後日、chooserialコマンドも、こちらの方法に変更します。
Vue.js の Slot: コンポーネントの柔軟性

Vue.js の Slot は、コンポーネントのテンプレート内で、他のコンポーネントのコンテンツを挿入するための場所を提供する強力な機能です。これにより、コンポーネントの構造を柔軟にカスタマイズし、異なるコンテンツを組み合わせて使用することができます。Slot を活用することで、再利用可能なコンポーネントを作成し、アプリケーションの開発効率を向上させることができます。

### 1. Slot の基本

Slot は、コンポーネントのテンプレート内で `<slot>` タグを使用して定義されます。`<slot>` タグは、他のコンポーネントからコンテンツが挿入される場所を示します。

```vue
<template>
  <div>
    <slot/>
  </div>
</template>
```

この例では、`<div>` 要素内に `<slot>` タグが定義されています。この `<slot>` には、他のコンポーネントからコンテンツが挿入されます。

### 2. Slot の使用

Slot を使用するには、親コンポーネントで子コンポーネントの `<slot>` にコンテンツを挿入します。

```vue
<template>
  <HelloWorldComponent>
    <p>こんにちは、世界！</p>
  </HelloWorldComponent>
</template>
```

この例では、`HelloWorldComponent` コンポーネントの `<slot>` に `<p>` 要素が挿入されています。`HelloWorldComponent` のテンプレートで定義された `<slot>` は、`<p>` 要素のコンテンツで置き換えられます。

![スクリーンショット 2024-06-18 21.40.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2544275/a038cdb4-bc4e-c660-785f-9f71ff51ed02.png)
検証ツールで確認してみても置き換えられていますね！

### 3. 名前付き Slot

Slot に名前を付けることで、複数の異なるコンテンツを挿入することができます。

```vue
<template>
  <div>
    <slot name="header"></slot>
    <slot name="content"></slot>
    <slot name="footer"></slot>
  </div>
</template>
```

この例では、`header`、`content`、`footer` という名前の Slot が定義されています。

```vue
<template>
  <HelloWorldComponent>
    <template v-slot:header>
      <h1>タイトル</h1>
    </template>
    <template v-slot:content>
      <p>コンテンツ</p>
    </template>
    <template v-slot:footer>
      <p>フッター</p>
    </template>
  </HelloWorldComponent>
</template>
```

この例では、`HelloWorldComponent` コンポーネントの `header`、`content`、`footer` の各 Slot に異なるコンテンツが挿入されています。`v-slot` ディレクティブを使用して、Slot の名前とコンテンツを指定します。

### 4. Slot のメリット

* **柔軟性**: Slot を使用することで、コンポーネントの構造を柔軟にカスタマイズできます
* **再利用性**: Slot を使用することで、コンポーネントを再利用し、異なるコンテンツを組み合わせて使用することができます
* **可読性**: Slot を使用することで、コードをより明確で読みやすくすることができます

### まとめ

Slot機能を初めて使用した際は理解に苦しみましたが、こうやって自分の中でまとめてみるとシンプルにしていたんだと改めて感じました。
色々なプロジェクトで色々な使用方法があるため復習して応用できたら効率的に開発ができると感じました。
[AWS #9] WAF

## はじめに
こんにちは
今回はセキュリティ分野の「WAF」について紹介いたします。

:rolling_eyes:これは何の略称でしょうか
:upside_down:**「Web Application Firewall」** ですね。
:rolling_eyes:あれ、ここでも**ファイアウォール**が出てきましたね。これも「防火壁」でしょうか
:upside_down:簡単に言うと、**「ウェブアプリケーションを保護するための防火壁」** ですね。

## WAF
WAF（Web Application Firewall）とは、ウェブアプリケーションの**脆弱性を狙って仕掛けられる悪意のある攻撃から<font color=red>「ウェブアプリケーションを保護するため」</font>の防火壁です。**

:upside_down:アクセスしてくるユーザーとウェブアプリケーションの間に「WAF」を挟むことで、**悪意のある攻撃の通信を遮断してウェブアプリケーションを防御します。**
:rolling_eyes:[[AWS #8]](https://qiita.com/aoiku/items/dfba4584e6e472c8f28d)とはまた違うパターンのFirewallですね。
:upside_down:ECサイトやソシャゲなどの顧客情報、クレカの情報に関する**データのやり取りが発生するWebサービスで使用されます。**

![AWS09_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806875/1298e28e-6f8d-3e29-84a4-42913a5258a9.png)

これを※SQLインジェクション、※XSSなどの脅威から**Webアプリケーションを保護する**ことができます。

※[**SQLインジェクション**](https://www.shadan-kun.com/waf_websecurity/sql_injection/)：Webアプリケーションの脆弱性を意図的に利用し、断片的なSQL文をアプリケーションに不正に注入（インジェクション）し、実行させる攻撃手法。

※[**XSS**](https://www.hitachi-solutions.co.jp/security/sp/words/xss.html)(Cross site scripting)：Webアプリケーションの脆弱性を利用して不正なスクリプトを埋め込み、ユーザーの個人情報を騙し取り、マルウェアに感染させたりする「サイバー攻撃」の一つです。

## AWS WAF
AWSのWAFはAWSが提供する**クラウド型のWAFサービス**です。
・Amazon CloudFront
・Application Load Balancer(ALB)
・API Gateway
などの上で動作します。
![AWS09_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806875/57446bd1-2ef8-31f2-667c-e2c9e4dbf05d.png)

ウェブセキュリティ（通信遮断など）のルールをカスタマイズ定義することが可能で、ウェブアプリケーションに対して**どのトラフィックを許可するか**、あるいは**ブロックするのかを制御する**ことができます。

---
**AWS WAFを理解する上で把握しておく必要があるもの**
### Web ACL
→ 通信リクエストを制限するルールを内包するものです。
### ルール
→ 通信リクエストを制限するルールのことです。
![AWS09_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806875/5a82a2b1-dfc8-3cdc-bd0a-d5b8360ecee9.png)
AWS WAFとWeb ACL、ルールの関係性は図の通りになります。
AWS WAFのWeb ACLの中にルールを作成します。作成したら**通信の「許可・拒否」を判別**します。
## おわりに

ちょっとしたまとめになります。

:::note info
AWS WAFとは、**Webアプリケーションに特化したAWSのファイアウォール**のこと
:::
:::note info
AWS WAFは、CloudFront、ALB、API Gatewayなどへの**アクセスを制御**することができる
:::
またAWS WAFには料金体系があります。（使用分のみ支払い、初期費用はかかりません）
[AWS WAFの料金はこちら](https://aws.amazon.com/jp/waf/pricing/)

最後までお読みいただきありがとうございました！

>日頃より活用しているAWS CLFの資格対策用の参考書です。
>> **「参考書」**
[AWS認定クラウドプラクティショナー改定第3版](https://x.gd/19i6N)
>
> **「AWS公式サイト」**
[AWS WAF](https://aws.amazon.com/jp/waf/)
>
> **「参考元」**
[AWS WAFとは？](https://www.shadan-kun.com/blog/measure/1414/)
>
> **「Youtube」**
[【CLF-C02：AWSクラウドプラクティショナー】第13回 AWS WAF (セキュリティとコンプライアンス分野)](https://x.gd/lzVe2)
colordiffを使って見づらいdiffコマンドからおさらばしよう!

## 背景

diffコマンド、見づらい…。

なんかいいのないかな？

## colordiffを使おう
https://github.com/daveewart/colordiff


## インストール方法

```
$ brew install colordiff
```

```
$ apt-get install colordiff
```


## ファイルの準備

``` text01.txt
$ cat text01.txt
aaa
bbb
ccc
ddd
eee
fff
```


```text02.txt
$ cat text02.txt
aa11a
bbb
ccc222
ddd
eee333
fff
```


## 出力例(-uなし)

```
$ diff text01.txt text02.txt
```

![スクリーンショット 2024-06-19 14.37.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327773/a5c3e505-7bb3-5773-e858-6bca54e4a8d0.png)


```
$ colordiff text01.txt text02.txt
```

![スクリーンショット 2024-06-19 14.37.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327773/b47c0e46-7363-9065-7327-12d36ece2e59.png)


## 出力例(-uあり)
```
$ diff -u text01.txt text02.txt
```

![スクリーンショット 2024-06-19 14.38.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327773/d0ff7bd1-9863-a589-ea13-f4a80f7a7b85.png)


```
$ colordiff -u text01.txt text02.txt
```

![スクリーンショット 2024-06-19 14.38.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327773/e807b463-31cf-bf1c-d494-080768e8b019.png)



## おまけ (aliasの対応)

`alias diff='colordiff -u'` と設定すると `colordiff` がインストールされていない環境ではダメなので以下のように設定しました。
`-u` オプションをつけると `git diff` の出力に近くなります。

.zshrcファイルをopen

```
$ vi ~/.zshrc
```

以下を記載

```.bashrc
if [[ -x `which colordiff` ]]; then
  alias diff='colordiff -u'
else
  alias diff='diff -u'
fi
```

.zshrcファイルをsave

```
$ source ~/.zshrc
```


# 参考記事


https://qiita.com/aramasa_ash/items/1d5bad775e372d52ed59
OpsRamp - チケットをメール通知する方法について

本記事では、OpsRampのチケットに関するメール通知方法について記載します。

# 概要
OpsRampでは、チケットの作成時または更新時にメール通知することが可能です。OpsRamp社から提供されている通知条件またはユーザ側でカスタムの条件を作成することが可能です。

# 設定方法
チケットのメール通知は、Setup > Service Desk > 通知 から設定することが可能です。
![ticket-notification.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/2385ce81-3329-e8b2-c748-9d70168e3542.png)
「カスタマイズ」から送信者を設定することが可能です。
「リソース」では、登録されているユーザから選択可能です。
「Notify To」では、チケットの情報に沿ったユーザまたはメールアドレスに送信されます。
「追加送信者」では、指定したメールアドレスに送信されます。
![ticket-notification_customize.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/7c2a1cf7-2393-5d09-2747-a2d2eaaaefa6.png)
「Eメールのカスタマイズ」からメール内容を編集することが可能です。
「件名」および「内容」を任意に編集します。「トークン」からチケットに関する情報を変数として使用することが可能です。
![ticket-notification_email-customize.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/2ec45457-0452-7c4d-94ae-c2aa2deb7933.png)

「追加」から任意の通知条件を設定することが可能です。

---------------------------------------
[<img width = 250 height = 200 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/111de30a-4d33-aa33-5c7d-83d9015093e6.png">](https://www.vistanet.jp/knowledge-base/)
Unityでデザインパターンを使ってみる ~シングルトン~


# デザインパターンとは？
ソフトウェアを開発する際に、よく使われる設計のパターンのことです。
いわば数学の公式のようなものです。

# シングルトンをUnityで使ってみよう
シングルトンは、インスタンスが1つしか生成されないことを保証するデザインパターンです。
例えばマネージャークラスを取得するときに使えます。

:::note warn
覚えたてのデザインパターンは乱用しがちです。(n敗)
そもそもマネージャークラスを参照するべきか、シングルトンを使うべきかを考えましょう。
:::

1. マネージャークラスを作成します。
```csharp
using UnityEngine;

public class Manager : MonoBehaviour
{
    // シングルトン
    public static Manager Instance { get; private set; }

    // 同じのがあったら消すことでManagerが複数個存在しないようにする
    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
        }
        else
        {
            Destroy(gameObject);
        }
    }
    
    private int _score = 0;
    
    public int GetGameScore()
    {
        return _score;
    }
    
    public void IncrementScore()
    {
        _score++;
    }
}

```

2. 参照するクラスを作成します。
```csharp
using UnityEngine;

public class Player : MonoBehaviour
{
    private void Start()
    {
        Manager manager = Manager.Instance; // ここでManagerのインスタンスを取得
        Debug.Log(manager.GetGameScore()); // ここでManagerのスコアを取得
        
        manager.IncrementScore(); // ここでManagerのスコアをインクリメント
    }
}

```

なんとシングルトンはこれだけで実装できます！
次にどのような挙動をするのかを確認してみましょう。

# 動作確認

1. Managerクラスをアタッチする
![Singleton_manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/139f5b71-98ff-2de9-45d4-7ae7d9c0e9dc.png)

2. Playerクラスを適当なオブジェクトにアタッチする
![Singleton_player.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/22efeae0-b033-8540-770e-cebd19ee5ee5.png)

3. ログを確認してみよう
![Singleton_Simple_log.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/42e02783-230b-c57d-beac-bf9391d64ae9.png)


これでシングルトンを使うことができました！

試しにPlayerクラスがアタッチされたオブジェクトを複数個コピーしてみましょう。

![Singleton_MultiPlayer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/46bfd304-26d7-6c96-39a0-f009087c8091.png)

同じように実行してみると...
![Singleton_MultiPlayer_log.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/43e2782b-a6c6-9fa0-af26-e17c5ee0432b.png)

この結果から同一のインスタンスにアクセスしていることがわかりますね！

# これってだめなの？

こんな風にSerializeFieldでインスペクターからアタッチするように書いて...
```csharp
using UnityEngine;

public class Player : MonoBehaviour
{
    [SerializeField] private Manager manager; // ここでManagerをインスペクターからアタッチ
    private void Start()
    {
        manager.IncrementScore(); // ここでManagerのスコアをインクリメント
    }
}
```

![Singleton_serialize_field.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/f24f2a7e-0428-6dda-a045-f07537c51c69.png)

これでも立派なコードです！
ただしシングルトンのミソというのは
**インスタンスが1つしか生成されないこと**

SerializeFiledで取得する場合は、Managerクラスが複数個存在しているときにアタッチのするものを間違えてしまう可能性があります。
これを解決するためにシングルトンを使うのです。

# おわりに

シングルトンは様々なデザインパターンの中の一つです。
この記事は初めてデザインパターンっていうのを知ったよ！という方向けに書いています。
他にもたくさんのデザインパターンがあるので、興味がある方は調べてみてください！

:::note warn
デザインパターンは用法・用量を守って正しくお使いください
:::
[メモ]新しいkubeconfigを追加するときに使うと便利なシェル

新しいkubeconfigがあるファイルのところに移動して、下記を実行

```shell
export KUBECONFIG=${HOME}/.kube/config
export KUBECONFIG=${KUBECONFIG}:$(pwd)/<YOUR_NEW_KUBE_CONFIG_FILENAME>

mkdir -p ~/.kube
kubectl config view --flatten > ~/.kube/config.new
mv ~/.kube/config ~/.kube/config.bak
mv ~/.kube/config.new ~/.kube/config
export KUBECONFIG=${HOME}/.kube/config
chmod go-r ~/.kube/config
```
初投稿

# 前書き
#### はじめに</dt>
記念すべきはじめての投稿。
アウトプットも兼ねて記録を残してみようと思います。
勝手がわからず、至らないところがあるかもしれませんがご容赦ください。

#### 簡単に自己紹介
氷河期世代のアラフォー。
エンジニアではないですが、プログラミングに触れる機会が増え、学習を始めました。
現在は、Excel VBA や JavaScript が少しできる程度。

# まずは投稿方法から
マークダウン記法って？
からスタートしたので、テストも兼ねて調べた結果を残すことにします。

# 所感
- サイトを見ても理解が進まず困った
- 動画を閲覧したところわかりやすく理解でき、サイトでより深く理解できた
- 個人的には、調べた動画 → サイトの順番が性に合っていた

# 学習教材（参考になった動画やサイト）
#### ■動画
- [Qiitaの記事の書き方【研究生活ハック】](https://www.youtube.com/watch?v=pHfIs-5AJ5E&t=324s)
#### ■サイト
- [Markdown記法 チートシート](https://qiita.com/Qiita/items/c686397e4a0f4f11683d)
- [Qiita記事作成方法 初心者の備忘録](https://qiita.com/U-MA/items/996ae933ae94c5711883)
- [Qiitaのテーブルの書き方についてまとめた](https://qiita.com/zakuroishikuro/items/f33929eab9d55c5bd073)

# 学習コスト

|項目  |時間（H）  |日数  |金額  |
|---|---|---|---|
|動画 |1  |1  |0|
|検索（サイト閲覧）  |1  |1  |0|
|記事投稿（アウトプット）  |1  |1  |0|
|TTL  |3  |1  |0|
【メモ】毎回調べるのが面倒なので自分が使っているツールのアップグレード法をまとめてみた

# はじめに
OS: Ubuntu22.04

::: note warn
あくまで自分の環境ですのでご容赦ください。
:::

# Docker

```bash
sudo apt upgrade docker
```

バージョン確認
```bash
// 詳細を確認ができる
docker version
// 簡易
docker --version
```

# minikube

```bash
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 \
   && sudo install minikube-linux-amd64 /usr/local/bin/minikube
```

アップデート情報確認
```bash
minikube update-check
```

バージョン確認
```bash
minikube version
```

# skaffold

```bash
curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64 && \
sudo install skaffold /usr/local/bin/
```
バージョン確認
```bash
skaffold version
```

# npm

```bash
npm install -g npm@latest
```
バージョン確認
```bash
npm --version
```

# yarn

```bash
npm -g uninstall yarn
npm -g install yarn
```

```bash
yarn --version
```

# 最後に

ひとまずよく使うツールについてまとめてみました。
なにかアップグレードするたびに書き足していきます。
【メモ】S3クロースアカウント・Denyバケットポリシー書き方（ロール＆インスタンス）

# <前提>
Bアカウントのバケットのバケットポリシーは特定のuser・roleのみアクセスできるようにするため、Denyポリシーを利用している。

# <登場人物>
#### Aアカウント
* インスタンス用ロール
* インスタンス
#### Bアカウント
* アクセス対象バケット


# <ロール・バケットポリシー>
#### Aアカウント
* Bアカウントのバケットへアクセスできるポリシーを追加
#### Bアカウント
* 下記のようにバケットポリシーを設定する。
```バケットポリシー.json
 {
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "allowaaccountaccess",
			"Effect": "Allow",
			"Principal": {
				"AWS": [
					"arn:aws:iam::<アカウントID>:role/<ロール名>",
					"arn:aws:iam::<アカウントID>:user/<ユーザー名>"
				]
			},
			"Action": [
				"s3:Put*",
                "s3:List*"
			],
			"Resource": [
				"arn:aws:s3:::<Bアカウントバケット名>",
				"arn:aws:s3:::<Bアカウントバケット名>/*"
			],
			"Condition": {
				"StringEquals": {
					"s3:x-amz-acl": "bucket-owner-full-control"   ← ここは必須ではない ※ただ、付いている場合オプションを付けないと弾かれます。（--acl bucket-owner-full-control）
				}
			}
		},
		{
			"Effect": "Deny",
			"Principal": "*",
			"Action": "s3:*",
			"Resource": "arn:aws:s3:::<Bアカウントバケット名>/aa/11/*",
			"Condition": {
				"StringNotLike": {
					"aws:userid": [
					    "<ロールID>:<インスタンスID>",
					    "<ロールID>:<インスタンスID>"
					    ]
				},
				"StringNotEquals": {
					"aws:username": [
						"<user名>",
						"<user名>"
					]
				}
			}
		}
	]
}
```
TailscaleのDNSをオフにする方法

AWSのVPC内に配置した時のめも

MagicDNS機能が有効になっている場合、`tailscale up`すると、tailscale側のDNSを参照するようになるのでVPC内のパブリックゾーンとの通信がおかしくなる。

## 原因

MagicDNS機能によりパブリックIPが取得されてしまい、プライベートIPでアクセスできなくなってるため。

## 対応方法

以下でMagicDNSを利用しないようにできる。

```
sudo tailscale up --accept-dns=false
```

## 追加

プライベートゾーンの場合はDNSでもプライベートIPが返ってくるため、問題にはならなさそうです。

## 参考

https://tailscale.com/kb/1081/magicdns
闘魂Elixir ーー AtCoder Beginner Contest 335(A)をElixirで楽しむ

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと。}$</font></b>
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>
<b><font color="red">$\huge{ことだと思います}$</font></b>


# はじめに

[AtCoder Beginner Contest 335](https://atcoder.jp/contests/abc335)を[Elixir](https://elixir-lang.org/)で解いてみます。

[AtCoder](https://atcoder.jp/)を解くのが趣味で、休憩時間に解いているという若い人がいて、それってすごい意識の高い休憩時間の過ごし方だと思って、私も真似してみることにしました。


# [AtCoderをElixirでやってみる](https://zenn.dev/torifukukaiou/articles/ac84c87736ceebf4da01)

入力の読み取り方や解答の作り方は、別の記事にまとめています。


https://zenn.dev/torifukukaiou/articles/ac84c87736ceebf4da01

ご参照くださいませ。

[Elixir](https://elixir-lang.org/)で[AtCoder](https://atcoder.jp/)を楽しむためには、エントリポイントを`Main.main/0`にする必要があります。つまり`Main`モジュールを作って、その中に`main/0`関数を定義するわけです。

# [A - 2023](https://atcoder.jp/contests/abc335/tasks/abc335_a)

問題はリンク先をご参照くださいませ。
私の解答を貼っておきます。


<details><summary>私の解答</summary>

_問題文を読んでいることを前提にひとこと解説をしておきます。_

文字列を分割すればよいので[String.slice/2](https://hexdocs.pm/elixir/String.html#slice/2)関数を使いました。


```elixir
defmodule Main do
  def main do
    s = IO.read(:line) |> String.trim()

    solve(s)
    |> IO.puts()
  end

  def solve(s) do
    "#{String.slice(s, 0..-5//1)}2024"
  end
end

```




</details>




---

# さいごに

[AtCoder Beginner Contest 335](https://atcoder.jp/contests/abc335)を[Elixir](https://elixir-lang.org/)で解くことを楽しみました。

あなたのお好きなプログラミング言語でお楽しみください。

---


**闘魂**とは、  **「己に打ち克つこと。そして闘いを通じて己の魂を磨いていくことである」** との猪木さんの言葉をそのまま胸に刻み込んでいます。
知っているだけで終わらせることなく、実行する、断行する、一歩を踏み出すことを自らの行動で示していきたいとおもいます。
**アントニオ猪木さんのメッセージから元氣をもらったものとして、それを次代に語り継ぎ、自分自身が「闘魂」を体現するものでありたいとおもいます。**

---

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>
<b><font color="red">$\huge{１、２、３ ぁっダァー！}$</font></b>
PostmanでJsonでPOSTしてみよう

# Postman って？

PostmanはAPIのテストをするためのツールです。
ただテストをするだけじゃなくて、APIのドキュメントを作れたり組織を作って共有できたりと、様々な機能があります。

https://www.postman.com/


# 使い方

https://dummyjson.com/

今回はこのサイトを使ってダミーデータを作成して、Jsonのデータを送信するAPIをPostmanでテストしてみます。

## 1.HTTPリクエストを作成する
左上の新規ボタンを押しましょう。
そうすると以下のようなダイアログが出てくるので、HTTPを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/54dd8548-8475-c680-520f-895615717f7f.png)


## 2.Jsonデータを作成する

以下のような画面になったでしょうか。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/b6ea6a6f-8790-3712-66d8-214d9f5cfc9a.png)

ここまでできたら、ボディを選択し、Rawを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/cdc5b956-a92b-f5bf-a68c-f57f96c3b15b.png)

テキストエディタのような画面が登場したらOKです。
そしてここにJsonデータを入力します。
今回のダミーのAPIは以下のようなJsonデータを受け取るのでコピーして使ってください。

```json
{
  "userId": 1,
  "products": [
    {
      "id": 98,
      "quantity": 4
    },
    {
      "id": 144,
      "quantity": 1
    }
  ]
}
```

## 3.リクエストを送信する
左上の GET と表示されているところをクリックして
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/00a12811-e9c0-97cd-586c-9cfee152314a.png)

POST に変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/4f8a8de0-ec63-7c5f-03e7-cdda8e0e2d64.png)


## 4.リクエストを送信する

ここまで全てできていれば以下のような画面になるはずです。
最後に送信ボタンを押してリクエストを送信します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/359e2230-f645-9d9a-1578-d01964eecac0.png)


こんなメッセージが帰ってきたら成功です。
```JSON
{
    "id": 51,
    "products": [
        {
            "id": 98,
            "title": "Rolex Submariner Watch",
            "price": 13999.99,
            "quantity": 4,
            "total": 55999.96,
            "discountPercentage": 0.82,
            "discountedPrice": 55541,
            "thumbnail": "https://cdn.dummyjson.com/products/images/mens-watches/Rolex%20Submariner%20Watch/thumbnail.png"
        },
        {
            "id": 144,
            "title": "Cricket Helmet",
            "price": 44.99,
            "quantity": 1,
            "total": 44.99,
            "discountPercentage": 10.75,
            "discountedPrice": 40,
            "thumbnail": "https://cdn.dummyjson.com/products/images/sports-accessories/Cricket%20Helmet/thumbnail.png"
        }
    ],
    "total": 56044.95,
    "discountedTotal": 55581,
    "userId": 1,
    "totalProducts": 2,
    "totalQuantity": 5
}
```
COCO形式の物体検出アノテーションファイルからYOLO形式への変換

# はじめに
COCO形式のアノテーションファイルをYOLO形式に変換する必要が生じた際に少し躓いてしまったので、最終的に上手くいったコードを備忘録として残しておきます。(YOLOv8にて動作確認済)
なお、COCO形式とYOLO形式の違いとして重要な部分が以下の2点になり、これらに注意をしながらコードを作成しております。
* **バウンディングボックスの座標の取り方**
* **画像1枚に複数のアノテーションがある場合のアノテーションのやり方**

# 変換コード
以下のコードを用いることで、COCO形式のアノテーションファイルをYOLO形式に変換するここができます。

```
import os
import json

# パスの設定
coco_json_path = '変換したいjsonファイルのパス'
yolo_txt_save_dir = 'YOLO形式のtxtファイルを出力したい場所'

# JSONファイルの読み込み
with open(coco_json_path, 'r') as json_file:
    json_load = json.load(json_file)

annotations = json_load['annotations']
images = json_load['images']

# 画像IDとファイル名の対応辞書を作成
image_id_to_file_name = {image['id']: image for image in images}

# 各アノテーションに対して処理
for annotation in annotations:
    image_info = image_id_to_file_name[annotation['image_id']]
    file_name = image_info['file_name']
    im_w = image_info['width']
    im_h = image_info['height']
    
    # テキストファイルのパスを作成
    txt_path = os.path.join(yolo_txt_save_dir, os.path.splitext(os.path.basename(file_name))[0] + '.txt')
    
    # バウンディングボックスの座標を変換
    bbox = annotation['bbox']
    x_center = bbox[0] + bbox[2] / 2
    y_center = bbox[1] + bbox[3] / 2
    bbox_converted = [x_center / im_w, y_center / im_h, bbox[2] / im_w, bbox[3] / im_h]
    
    # カテゴリーIDを取得
    cls = int(annotation['category_id'])
    
    # 書き込む行を作成
    line = (cls, *bbox_converted)
    
    # テキストファイルに追記モードで書き込み
    with open(txt_path, 'a') as f:
        f.write(('%g ' * len(line)).rstrip() % line + '\n')

```






この記事は以下の情報を参考にして執筆しました。

- [COCO形式（json）の物体検出アノテーションファイルを、yolo形式（txt）に変換するスニペット](https://qiita.com/john-rocky/items/29badbc8c1d86558978e)