OmniAICreator/Qiita-1.07M huggingface dataset:
react-router-domのルーティング設定

react-router-domのルーティング設定備忘

# 開発環境
node v20.14.0
npm 10.7.0

"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.26.0",

# reactプロジェクトの作成
```:ターミナル
npx create-react-app PROJECT-NAME
```

# react-router-domのインストール
```ターミナル
npm install react-router-dom
```

# ディレクトリ構成
```
src/
├── components
│   ├── Nav.js
│   ├── Home.js
│   ├── Login.js
│   └── Logout.js
├── App.js
└── Index.js
```

# App.jsのルーティング設定の記述
Routeコンポーネントのpathに遷移したいパスの設定をする。
elementの中に遷移先のコンポーネントを指定できる。
pathに"*"を指定すると存在しないパスが入力された時に表示するページを設定することができる。(404NotFoundページ)

```App.js
import './App.css';
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Home from "./components/Home";
import Login from "./components/Login";
import Logout from "./components/Logout";

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Home />}></Route>
        <Route path="/login" element={<Login />}></Route>
        <Route path="/logout" element={<Logout />}></Route>
        <Route path="*" element={<h1>Not Found Page</h1>} />
      </Routes>
    </Router>
  );
}

export default App;
```

# Linkの記述
Linkコンポーネントのtoに遷移したいパス名を指定。
```Nav.js
import React from 'react';
import { Link } from "react-router-dom";

const Nav = () => {
  return (
    <nav>
      <Link to={"/"}>ホーム</Link>
      <Link to={"/login"}>ログイン</Link>
    </nav>
  )
}

export default Nav;
```

# 参考
https://zenn.dev/yurarin/articles/8369bfe666bff0


# 追記
共通したレイアウトを使うときはRouteの中にRouteを入れ込むこともできる

```App.js
import { BrowserRouter, Routes, Route } from "react-router-dom";
import AuthLayout from "./components/layout/AuthLayout";
import Login from "./pages/Login";
import Register from "./pages/Register";


function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<AuthLayout />}>
          <Route path="/login" element={<Login />}></Route>
          <Route path="/register" element={<Register />}></Route>
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

export default App;
```

外側のRouteで囲ったコンポーネントにOutletを使うとLogin,Registerの内容が反映される。
```AuthLayout.jsx
import React from 'react'
import { Outlet } from "react-router-dom"

const AuthLayout = () => {
  return (
    <div>
      <h1>Login,Registerの両方で表示する共通パーツ</h1>
      <Outlet />　 {/* Login, Registerの中身 */}
    </div>
  )
}

export default AuthLayout
```
ryeでNotebookを実行できない問題の解決法

## 問題発生状況

私はryeでパッケージを管理している。普段.pyは問題なく実行できているためpathは正しく通っているはずだが、.ipynbのセルを実行しようとした際に、
```
Running cells with '.venv (Python 3.12.3)' requires the ipykernel and pip package.
```
と表示されてしまう。

## 解決法
```
$ rye add ipykernel
$ rye sync
```
でおｋ。
【Javascript】ProgressBar が動かない(一連の処理が終わってから初めて動く)現象を回避したい

html で 処理に時間がかかる javascript を組んだ時に
ProgressBar を実装して
一連の処理が全て終了してから
初めて ProgressBar が動いて困った人はいますか？

この記事ではその場合の
応急処置の 1 例を紹介したいと思います。

この工程を踏めば
ProgressBar が処理中に動作してくれます。

***

手順1 重い処理全体を async なメソッドに配置する

まずは重い処理全体を
async なメソッドに配置して
実行して下さい。

```javascript:async なメソッドの例
async function MyFunction(ctx, canvas) {

}

MyFunction(ctx, canvas); // 必ず元の場所で実行して下さい。
```

***

手順2 ProgressBar の Value を変えた後に sleep 処理を書く

次に ProgressBar の Value を変えた後に
次の処理を記述します。

```javascript:記述する処理
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
await sleep(0);
```

すると ProgressBar が動きます。

***

以上 ProgressBar を正常に機能させる
応急処置の 1 例を紹介しました。

sleep させることで
処理を一瞬だけ中断させて
無理矢理動作させています。

ただし一瞬中断する関係上
動作は sleep しない時より
少しだけ遅くなります。

あくまでも応急処置である点に
御留意下さい。

何故動作するか、具体的な理由については
コメント欄で簡潔にまとめて頂く事が出来たため
気になる方はそちらをご確認ください。

この記事が皆さんの悪戦苦闘を
1 つでも解決できますように

閲覧ありがとうございました。
Typescript / Javascript：fast-csv で csvを取り込む

# Typescript環境でcsvを取り込みたい

管理画面系の開発をしていると、csvファイルを読み込みDBに保存するといった場面によく出会います。
私も最近 Nodejs を利用した開発でそのような機会があり、fast-csvというライブラリを用いたところ思ったより簡単に実装できたので、実際のコードと共に残しておきます。

typescriptの実行環境作成は以下記事などが参考になると思います。

https://qiita.com/jonakp/items/da5988b783cb28c03192

## 実装

### 実行環境
```
yarn: v1.22.22
node: v20.10.0
ts-node: v10.9.2
```

### fast-csvをインストール

parseを利用するので、devDependenciesにparseもインストールしました。

```:command
yarn add fast-csv
yarn add @fast-csv/parse
```

### ディレクトリ構成

※ package.json等は省略
```
csv-sample
├─ test.ts
└─ test.csv
```

### コード

```:test.csv
csvヘッダー項目1,csvヘッダー項目2,csvヘッダー項目3,csvヘッダー項目4
AAA,BBB,CCC,DDD
111,222,333,444
```

```typescript:test.ts
import { parseString } from '@fast-csv/parse';
import fs from 'fs';

// csvをstringに変換
const CSV_STRING = fs.readFileSync('./test.csv', 'utf8');

// csvのヘッダー項目
type ColumnType = {
  'csvヘッダー項目1': string,
  'csvヘッダー項目2': string,
  'csvヘッダー項目3': string,
  'csvヘッダー項目4': string,
}

// 変換後のオブジェクトtype定義
type Row = {
  db_1: string,
  db_2: string,
  db_3: string,
  db_4: string,
}

export const parseCsv = async (csv: string): Promise<Row[]> => {
  const rows: Row[] = [];
  for await (const data of parseString<ColumnType, Row>(csv, {
    headers: true,
  }).transform(
    (data: ColumnType): Row => ({
      db_1: data['csvヘッダー項目1'],
      db_2: data['csvヘッダー項目2'],
      db_3: data['csvヘッダー項目3'],
      db_4: data['csvヘッダー項目4']
    }),
  )) {
    rows.push(data);
  }

  return rows;
};

// 呼び出し

parseCsv(CSV_STRING).then((data) => {
  console.log(data);
})

```

実行結果
```:command
> npx ts-node test.ts
[
  { db_1: 'AAA', db_2: 'BBB', db_3: 'CCC', db_4: 'DDD' },
  { db_1: '111', db_2: '222', db_3: '333', db_4: '444' }
]
```

オブジェクトの配列に無事変換されました。
参考になれば幸いです。

## 参考

公式ドキュメント

https://c2fo.github.io/fast-csv/
mecabで辞書に固有名詞を登録する



https://qiita.com/rei-ta/items/3976a57f1f55594609e0

上記案件に付随して、固有名詞を追加したいという話しがあったので。
固有名詞だけだと、追加して辞書を再コンパイルする。

直下に置く
user_dic.csv

```
桜富士,,,1,名詞,固有名詞,人名,一般,*,*,サクラフジ,タケルフジ,サクラフジ,タケルフジ,サクラフジ,タケルフジ,固,*,*,*,*
紫こうじ,,,1,名詞,固有名詞,一般,*,*,*,ムラサキコウジ,ムラサキコウジ,紫こうじ,ムラサキコウジ,紫こうじ,ムラサキコウジ,固,*,*,*,*
アルカノイド,,,1,名詞,固有名詞,一般,*,*,*,アルカノイド,アルカノイド,アルカノイド,アルカノイド,アルカノイド,アルカノイド,固,*,*,*,*
```

Dockerfile
#user dictionary 以下で、再コンパイルしている。

```
FROM public.ecr.aws/lambda/nodejs:18
COPY *.js* package*.json .env ./


RUN yum install -y gcc gcc-c++ git patch tar make which find xz file openssl unzip sudo
RUN rpm -ivh http://packages.groonga.org/centos/groonga-release-1.1.0-1.noarch.rpm

RUN mkdir ./mecab-service
RUN curl -L "https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7cENtOXlicTFaRUE" -o mecab-0.996.tar.gz
RUN tar zxvf mecab-0.996.tar.gz
RUN cd ./mecab-0.996 && ./configure --enable-utf8-only
RUN cd ./mecab-0.996 && make
RUN cd ./mecab-0.996 && make install

RUN curl -L "https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7MWVlSDBCSXZMTXM" -o mecab-ipadic-2.7.0-20070801.tar.gz
RUN tar zxvf mecab-ipadic-2.7.0-20070801.tar.gz
RUN cd ./mecab-ipadic-2.7.0-20070801 && ./configure --with-charset=utf8

RUN cd ./mecab-ipadic-2.7.0-20070801 && /usr/local/libexec/mecab/mecab-dict-index -f utf-8 -t utf-8
RUN cd ./mecab-ipadic-2.7.0-20070801 && make
RUN cd ./mecab-ipadic-2.7.0-20070801 && make install
RUN git clone --depth 1 https://github.com/neologd/mecab-unidic-neologd.git
#if [ ! -e ${BASEDIR}/../build/${ORG_DIC_NAME}.zip ]; then
#    curl --insecure -L "http://osdn.jp/frs/redir.php?m=jaist&f=%2Funidic%2F58338%2F${ORG_DIC_NAME}.zip" -o "${ORG_DIC_NAME}.zip"
COPY unidic-mecab-2.1.2_src.zip mecab-unidic-neologd/build/
RUN cd mecab-unidic-neologd && ./bin/install-mecab-unidic-neologd -n -y
RUN sed -i -e s/ipadic/mecab-unidic-neologd/g /usr/local/etc/mecabrc 

#user dictionary
COPY user_dic.csv mecab-unidic-neologd/build/unidic-mecab-2.1.2_src-neologd-20200910
RUN cd mecab-unidic-neologd/build/unidic-mecab-2.1.2_src-neologd-20200910 && /usr/local/libexec/mecab/mecab-dict-index -f UTF8 -t UTF8
RUN cd mecab-unidic-neologd/build/unidic-mecab-2.1.2_src-neologd-20200910 && /usr/bin/install -c -m 644 'dicrc' '/usr/local/lib/mecab/dic/mecab-unidic-neologd/dicrc'
RUN cd mecab-unidic-neologd/build/unidic-mecab-2.1.2_src-neologd-20200910 && /usr/bin/install -c -m 644 'char.bin' '/usr/local/lib/mecab/dic/mecab-unidic-neologd/char.bin'
RUN cd mecab-unidic-neologd/build/unidic-mecab-2.1.2_src-neologd-20200910 && /usr/bin/install -c -m 644 'unk.dic' '/usr/local/lib/mecab/dic/mecab-unidic-neologd/unk.dic'
RUN cd mecab-unidic-neologd/build/unidic-mecab-2.1.2_src-neologd-20200910 && /usr/bin/install -c -m 644 'sys.dic' '/usr/local/lib/mecab/dic/mecab-unidic-neologd/sys.dic'
RUN cd mecab-unidic-neologd/build/unidic-mecab-2.1.2_src-neologd-20200910 && /usr/bin/install -c -m 644 'matrix.bin' '/usr/local/lib/mecab/dic/mecab-unidic-neologd/matrix.bin'



RUN npm install
ENV MY_ENV_VAR=value

CMD [ "app.lambdaHandler" ]

```
github actions を使用して、github organization を跨いでprivate repository を参照する

かなり限定的な状況だったので同じ事例がなく困った。
# やりたかったこと
- github enterprise を使用して、enterprise内のorgAのprivate repo を、orgBのgithub actions 内で実行するterraform から参照したい
- terraform では、参照したrepo をmodule として取り込んでリソース作成を行いたい

# 起こったこと
- orgB のgithub actions ユーザーにはorgA のrepo を参照する権限がなかった
- よくある解決手段にはPATがあったが、システムユーザーにPATを付与して管理したくなかった
- また、github enterprise であったため対象URLがgithub.com でなく苦戦した

# やったこと
github app を使用し、orgA でappトークンを払い出す

払い出したトークンの
- appトークンのID
- シークレットキー
 を控える

以下をorgB のgithub actions 内のterraform 実行前step で実施する
```
steps:
      - name: Generate token
        id: generate_token
        uses: actions/create-github-app-token@v1
        with:
          app-id: ${{ vars.<variablesに設定したorgA のappトークンID> }}
          private-key: ${{ secrets.<secretsに設定したorgA のapp のシークレットキー> }}
          owner: "<orgAの名前>"
      - name: Set Token
        run: |
            export TOKEN='${{ steps.generate_token.outputs.token }}'
            git config --global url."https://x-access-token:${TOKEN}@github.<github enterprise ごとの値>//".insteadOf "https://github.<github enterpriseごとの値>/"
```
ルールエンジンの実践（１）

## なぜルールエンジンが必要か

ルールエンジンが必要とされる理由は以下の通りです：

1. ビジネスの俊敏性：
   - ビジネスルールの変更が頻繁に発生する環境で、迅速な対応が可能になります。
   - コードの再コンパイルや再デプロイなしでルールを更新できます。

2. 複雑性の管理：
   - 大規模で複雑なルールセットを効率的に管理し、メンテナンスを容易にします。
   - ルール間の依存関係や優先順位を自動的に処理します。

3. 非技術者によるルール管理：
   - ビジネスアナリストや領域専門家が直接ルールを定義・管理できるようになります。
   - 技術者とビジネス部門のコラボレーションが促進されます。

4. スケーラビリティと再利用性：
   - ルールを再利用することで、開発時間とコストを削減できます。
   - ビジネスの成長に合わせて、ルールセットを容易に拡張できます。


## ルールエンジンが解決する問題

ルールエンジンは、以下のような問題を解決するのに役立ちます：

1. 複雑な意思決定ロジックの管理：
   - 多数の条件や例外を含む複雑なビジネスルールを効率的に管理できます。
   - ルールの変更や追加が容易になり、ビジネスの変化に迅速に対応できます。

2. ビジネスロジックとアプリケーションコードの分離：
   - ビジネスルールをアプリケーションコードから分離することで、保守性が向上します。
   - ビジネスアナリストが直接ルールを管理できるようになり、開発者の負担が軽減されます。

3. パフォーマンスの最適化：
   - 効率的なアルゴリズムを使用して、大量のルールを高速に処理できます。
   - メモリ使用量を最適化し、リソースを効率的に利用できます。

4. 一貫性の確保：
   - 同じルールセットを複数のアプリケーションで共有することで、ビジネスロジックの一貫性を保てます。
   - ルールの集中管理により、矛盾や重複を減らすことができます。

## 適用可能なビジネスシナリオ

ルールエンジンは以下のようなビジネスシナリオで特に有効です：

1. 金融サービス：
   - ローン審査や信用評価
   - 詐欺検出と防止
   - コンプライアンスチェック

2. 保険：
   - 保険料の計算
   - クレーム処理の自動化
   - リスク評価

3. 電子商取引：
   - 動的な価格設定
   - 製品推奨システム
   - 在庫管理と配送ルール

4. 医療：
   - 診断支援システム
   - 治療計画の最適化
   - 医療保険の適用判断

5. 製造業：
   - 品質管理
   - 生産スケジューリング
   - サプライチェーン最適化

6. 顧客サービス：
   - カスタマーサポートの自動化
   - サービスレベルの決定
   - エスカレーションルールの管理

これらのシナリオでは、ルールエンジンを使用することで、複雑な意思決定プロセスを自動化し、効率性と一貫性を向上させることができます。また、ビジネス環境の変化に迅速に適応することが可能になります。

## オープンソースルールエンジンの技術選定と紹介

ビジネスロジックを効率的に管理し、柔軟に変更できるようにするため、多くの企業がルールエンジンを採用しています。以下では、主要なオープンソースルールエンジンの技術選定と特徴について紹介します。

### 1. Drools

Droolsは、Java環境で動作する最も人気のあるオープンソースルールエンジンの一つです。

特徴：
- 強力な推論エンジン
- DSL（ドメイン固有言語）のサポート
- 複雑なイベント処理機能

適している用途：
- 大規模で複雑なビジネスルールの管理
- リアルタイムの意思決定システム

### 2. Easy Rules

Easy Rulesは、軽量で使いやすいJavaベースのルールエンジンです。

特徴：
- シンプルなAPI
- 低い学習曲線
- 柔軟なルール定義（Java、MVEL、SpEL）

適している用途：
- 小規模から中規模のプロジェクト
- シンプルなルールセットの管理

### 3. OpenL Tablets

OpenL Tabletsは、Excelライクなインターフェースを持つルールエンジンです。

特徴：
- スプレッドシートベースのルール定義
- ビジネスユーザーにフレンドリー
- Javaとの統合が容易

適している用途：
- ビジネスアナリストが直接ルールを管理する必要がある場合
- 表形式のデータを扱う業務ロジック

### 4. CLIPS

CLIPSは、C言語で書かれた古典的なルールエンジンですが、現在も広く使われています。

特徴：
- 強力なパターンマッチング機能
- 多言語バインディング（Python、Java、Ruby等）
- 軽量で高速

適している用途：
- 人工知能や専門家システムの開発
- 組み込みシステムでのルール処理

## 技術選定のポイント

1. パフォーマンス要件
2. スケーラビリティ
3. 学習曲線と開発チームのスキルセット
4. ビジネスユーザーの関与度
5. 統合の容易さ
6. コミュニティのサポートと活発さ

## まとめ

ルールエンジンは、複雑な意思決定プロセスを持つ様々な業界で有効に活用されています。特に、頻繁に変更が必要なビジネスルールや、非技術者による管理が求められる場面で、その価値を発揮します。

オープンソースルールエンジンの選択は、プロジェクトの要件や制約によって大きく左右されます。Droolsは機能が豊富で大規模プロジェクトに適していますが、学習曲線が急です。Easy Rulesは小規模プロジェクトや初心者に適しています。OpenL Tabletsはビジネスユーザーの参加が重要な場合に有効です。CLIPSは高度な推論機能が必要な場合や、軽量なソリューションが求められる場合に適しています。

プロジェクトの特性を慎重に評価し、最適なルールエンジンを選択することが、成功への鍵となります。ルールエンジンの導入により、ビジネスの俊敏性、複雑性の管理、非技術者によるルール管理、そしてスケーラビリティと再利用性の向上が期待できます。

このシリーズ記事はEasy Rulesが選択します
npm-check-updates (ncu)でpackage.jsonの依存関係を最新に

# npm-check-updates (ncu) 


`npm-check-updates`（ncu）は、Node.jsプロジェクトの依存関係を管理し、最新のバージョンに更新するためのコマンドラインツールです。このツールは、`package.json`ファイルを分析し、依存パッケージの最新バージョンを検出して更新を支援します。

## インストール

ncuはnpmを使用してグローバルにインストールできます：

```bash
npm install -g npm-check-updates
```

## 基本的な使用方法

1. **更新可能なパッケージの確認**：
   ```bash
   ncu
   ```
   このコマンドは、更新可能なパッケージとそのバージョンを表示しますが、実際の更新は行いません。

2. **package.jsonの更新**：
   ```bash
   ncu -u
   ```
   このコマンドは、`package.json`ファイルを最新のバージョンで更新します。

3. **パッケージの実際の更新**：
   ```bash
   npm install
   ```
   `package.json`が更新された後、このコマンドで実際のパッケージをインストールします。

## その他の使用方法

1. **特定のパッケージのみ更新**：
   ```bash
   ncu -u -f packagename1 packagename2
   ```

2. **メジャーバージョンの更新を除外**：
   ```bash
   ncu --semver minor
   ```

3. **開発依存関係のみ更新**：
   ```bash
   ncu -d
   ```

4. **プロダクション依存関係のみ更新**：
   ```bash
   ncu -p
   ```

5. **インタラクティブモード**：
   ```bash
   ncu -i
   ```
   更新するパッケージを対話的に選択できます。

## 注意点

1. **バージョン固定**：
   特定のパッケージのバージョンを固定したい場合は、`package.json`で明示的にバージョンを指定。

## トラブルシューティング

1. **更新が反映されない**：
   `ncu -u`の後に`npm install`を忘れずに実行してください。

2. **特定のパッケージが更新されない**：
   パッケージが`peerDependencies`として指定されている可能性があります。`--deep`オプションを使用して確認
Tableauの表でNULLが文字列にならん問題


# 事例
特殊な値に入力しててもうまくいかないときの話です。
具体例は↓。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412138/51195c43-55a9-46ca-6b64-4e82c7d7590d.png)


# 原因
※メジャーバリューをテキストにぶっこんでいると想定して話を進めます  
※メジャーバリュー＝親、メジャーバリューに入ってる項目＝子とします

原因は書式設定が親と子で同期していないからです。
例えば
1. メジャーバリューをテキストに置く
2. メジャーバリュー内の項目で書式設定をする（数値の表示方法を変える、など）
3. メジャーバリューを右クリックして書式設定で特殊な値を編集する
上記の例だと2の時点で子オンリーの書式設定が適用されてしまい、親側の設定の変更を受け付けなくなります。

逆に言えば
1. メジャーバリューをテキストに置く
2. メジャーバリューを右クリックして書式設定で特殊な値を編集する
3. メジャーバリュー内の項目で書式設定をする（数値の表示方法を変える、など）
上記の例だと特殊な値の設定が適用されます。


# 解決策
子と親の書式設定をクリアしてからもっかい設定し直せばいいじゃんと思うかもしれませんが、シート内で設定が共有されているのか自分の環境では直りませんでした。
でもここからでもなんとかなる保険があるんですか！？
あります！（茶番終了）

1. メジャーバリュー内の項目をドラッグアンドドロップでテキストに持っていく
2. 1の項目を右クリックして書式設定で特殊な値を編集する
3. 1の項目をドラッグアンドドロップしてメジャーバリューの中に戻す

要は子側に単体で設定させるという方法です。
なので親側の設定を消しても同期はしませんが設定した文字は表示されるようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412138/63b07149-75fe-013b-67ea-49210212c587.png)
なんてひどい例。
メジャーバリューが10も100もあるなら大変ですが、そこそこの量ならこれでなんとかできるかと。

とはいってもこの設定はシート単位で持っているだけのようなので、新しく別シートで同じレイアウトの表を作れば一発ではあります。
レイアウトもっかいつくるのめんどくさいようという人は上記の方法で地道にドラッグアンドドロップしてみてください。



ちなみに当方のバージョンは2023.3です。ふ、古い・・・。
親の設定が神様だったら色々困るのは分かりますが、これはやはり仕様なんですかね。
特殊な値の項目は子にないので、項目増やすとか同期させるようにするとかしてほしいですけども。
【初心者向け】binding.pryの使い方

# まえがき
初めてbinding.pryを使ってデバッグをしようとしている方向けにわかりやすく使い方を書いたのでぜひ参考にしてみてください！
binding.pryを使えるようになると、バグの原因特定やアプリケーションの動きがわかるようになるなどのメリットが多いので、必須でできるようにした方がいいものです。この記事を読んでできるようになったら嬉しいです。

# 目次
- 設定方法
- binding.pryを挟む場所
- おまけ

# 設定方法

**`pry`のインストール**

Gemfileに以下のように追加します。

```ruby
gem 'pry'
gem 'pry-rails'
```

その後、`bundle install`を実行します。

あとはbinding.pryを挟んで使用するだけ！

# binding.pryを挟む場所

### 1. **メソッドの最初**

- メソッドの開始直後に挟むことで、そのメソッドが呼び出された際の引数やインスタンス変数の状態を確認できます。

```ruby
def create
  binding.pry
  @learning_datum = current_user.learning_data.new(learning_data_params)
  if @learning_datum.save
    redirect_to @learning_datum, notice: 'Learning data was successfully created.'
  else
    render :new
  end
end
```

### 2. **条件分岐の前後**

- `if`や`unless`などの条件分岐の前後に挟むことで、条件が正しく評価されているか、分岐前後での値の変化を確認できます。

```ruby
def create
  @learning_datum = current_user.learning_data.new(learning_data_params)
  binding.pry
  if @learning_datum.save
    binding.pry
    redirect_to @learning_datum, notice: 'Learning data was successfully created.'
  else
    binding.pry
    render :new
  end
end
```

### 3. **データベース操作の前後**

- `save`, `update`, `destroy`などのデータベースに影響を与える操作の前後に挟むと、その操作が正しく行われるか確認できます。

```ruby
def update
  binding.pry
  if @learning_datum.update(learning_data_params)
    redirect_to @learning_datum, notice: 'Learning data was successfully updated.'
  else
    render :edit
  end
end
```

### 4. **ループの中**

- ループの中に挟むと、各反復ごとに処理を止めて状態を確認できます。特に、ループ処理が期待通りに動作しているか確認したいときに有効です。

```ruby
def calculate_totals
  @totals = {}
  learning_data.each do |data|
    binding.pry
    @totals[data.category_id] ||= 0
    @totals[data.category_id] += data.time
  end
end
```

### 5. **エラーが発生している箇所**

- エラーが発生していると予想される箇所やエラーを捕捉している箇所に挟むと、原因の特定に役立ちます。

```ruby
def show
  @learning_datum = LearningDatum.find(params[:id])
  binding.pry
rescue ActiveRecord::RecordNotFound => e
  binding.pry
  redirect_to root_path, alert: 'Learning data not found.'
end
```

### 6. **コールバックやフック**

- `before_action`, `after_action`, `around_action`などのコールバックやモデルの`before_save`, `after_create`などに挟むと、コールバックが期待通りに動作しているか確認できます。

```ruby
before_action :set_learning_datum, only: [:show, :edit, :update, :destroy]

def set_learning_datum
  binding.pry
  @learning_datum = LearningDatum.find(params[:id])
end
```

### 7. **フォームデータの検証時**

- フォームから送信されたパラメータが適切に受け取れているか、またはバリデーションが正しく行われているかを確認したい場合に有効です。

```ruby
def learning_data_params
  binding.pry
  params.require(:learning_data).permit(:category_id, :skill, :time, :month)
end
```

# おまけ
唐突ですが弊社のご紹介もさせてください。

▼ コーポレートサイト
https://prum.jp/

▼ Wantedly求人
https://www.wantedly.com/projects/626662

弊社メンバーは学習した内容を日々Qiitaの記事にアウトプットしております。
弊社にご興味のある方、まずは求人を見てみてください！
ご応募お待ちしておりますー！
DynamoDBコスト削減ベストプラクティス

# はじめに

サーバーレス大好きなエンジニアです！
今日はDynamoDBのコスト最適化についてAWS SUMMIT2024の内容を参考に説明していきたいと思います。

https://aws.amazon.com/jp/summits/japan-2024/

# 対象読者

- NoSQLを使用している方
- 今後NoSQLを使用したい方
- DynamoDBに関心がある方
- サーバーレスが好きな人

# 目次

1. なぜコスト削減が重要なのか
2. データベースのコスト削減
3. NoSQLのコスト削減
4. Amazon DynamoDBのコスト削減

# 1. なぜコスト削減が重要なのか

システムを運用する際には、さまざまなコストが発生します。

- インフラコスト
- ライセンスコスト
- オペレーションコスト
- 開発コスト
- ビジネスコスト

コストが十分に確保できないと最新技術の導入が難しくなり、新機能の開発ができなくなる可能性もあります。
つまり、**コストを抑えることはビジネスの競争力を向上させる**ためにも非常に重要です。

# 2. データベースのコスト削減

データベースのコスト削減は、開発において必ずと言っていいほど取り上げられるテーマの一つです。
しかし、データベースが停止したり、データが消失したりすると、甚大な影響を及ぼすため、慎重に取り組む必要があります。また、専門的な知識が求められるため、むやみに手を加えない方が良いと考えるケースも多いと思います。

# 3. NoSQLのコスト削減

NoSQLは、他のデータベースと比較してコスト削減が容易です。また、AWSのサービスには目的別に特化したデータベースが用意されているのも特徴の一つです。
目的に応じたデータベースを選定することで、自然とベストプラクティスに近づけると言えます。

## 3.1 NoSQLのコスト削減ポイント

- サイジング
- スケジューリング
- 価格体系
- オプション設定
- データモデリング

適切な量・適切なタイミングで利用されているかを確認することは、非常に重要です。また、価格体系も新しいものを試してみようというケースでコストが増加していることがあります。
データモデリングに関しては、アプリケーションの内容に深く関わるため一概には言えませんが、データベースの特性を活かしたより良いモデリングが可能な場合もあります。

## 3.2 コンピューティングリソースの価格設定

コンピューティングリソースの価格設定は、大きく3つの体系に分類されます。

### プロビジョンインスタンス

- インスタンスを使用
- スケールイン・アウトが可能
- 割り当てた分だけ支払い
- 定常的なワークロード向け

### プロビジョンキャパシティ

- サーバーレス
- キャパシティ変更が可能
- 割り当てた分だけ支払い
- ある程度予測可能で、変化が緩やかなワークロード向け

### オンデマンドキャパシティ

- サーバーレス
- キャパシティ変更が可能
- 実際に利用した分だけ支払い
- 予測が難しく、変化が急激なワークロード向け

# 4. Amazon DynamoDBのコスト削減

## 4.1 DynamoDBとは？

DynamoDBは、NoSQLの中でも非常に有名なデータベースです。主な特徴は以下の通りです。

- 一桁ミリ秒の応答速度
- 大規模なスケーラビリティ
- サーバーレス

DynamoDBは、大規模なデータでも一桁ミリ秒の応答速度を維持することができます。また、小規模なアプリケーションから大規模なシステムまで、同じアーキテクチャでスケールすることが可能です。さらに、サーバーレスであるため、サーバー管理の手間がなく、メンテナンスコストが低く抑えられるだけでなく、サーバーが落ちるといった障害もほとんどありません。

## 4.2 DynamoDBの価格帯系について

DynamoDBには、プロビジョンキャパシティとオンデマンドキャパシティの2つの価格体系があります。
その他の特徴として、結果整合性のある読み込みは消費リソースが半分になることや、読み込みは書き込みに比べて5倍安価であることが挙げられます。

プロビジョンモードは、オンデマンドモードと比較して最大7倍コストを削減できるというメリットがあります。さらに、プロビジョンモードではリザーブドインスタンスを利用することで、よりコストを抑えることが可能です。

一方、オンデマンドモードはオートスケーリングの設定やピーク時のキャパシティ管理が不要なため、オペレーションコストの削減につながります。

## 4.3 Standard-IAクラス

DynamoDBには、オプションとしてStandard-IAクラスがあります。
これは、ストレージへの書き込みが多い場合に有効で、特にデータ量が非常に多いケースに適しています。


# まとめ

NoSQLは、目的に応じてデータベースを選定することで、比較的コストを最適化しやすい特徴があります。
本記事では、DynamoDBの価格オプションについても説明しました。また、データベースのコスト最適化においては、リザーブドインスタンスの購入だけで終わるケースが多いですが、さらに追加でコスト削減の検討を行うことが非常に重要です。この記事が参考になれば幸いです。
ログアウトでルーティングエラー

# Routing Errorが起きた

deviseを導入して、ログアウトしようとしたところ、下記のエラーが発生しました

```
ActionController::RoutingError (No route matches [GET] "/users/sign_out"):
```

このエラーの原因はアプリを作成したばかりで、javascriptが正常に動作していないことが原因でした

# 原因の確認
ルーティングがあっているか確認
```
destroy_user_session DELETE /users/sign_out(.:format)　　　　public/sessions#destroy
```

```_header.html.erb
<%= link_to destroy_user_session_path, method: :delete, style: "display:flex; align-items: center; flex-direction: column;" %>
```

path名も正しい、`method: :delete`と記述しているにもかかわらず、ルーティングエラーでは[GET]を受け取っているようです

というのもこのmethodをサーバー側に伝えているのはjavascriptのようで、ここが動作していないとmethodがdeleteと伝わらないようです！

# 解決編
このコマンドを打てば一発解決しました！

```
$ yarn add @babel/plugin-proposal-private-methods @babel/plugin-proposal-private-property-in-object
```

何をしているかというと2つのプラグインをインストールしています！

`@babel/plugin-proposal-private-methods`
- このプラグインは、JavaScriptのクラス内でプライベートメソッドを使用できるようにするためのものです


`@babel/plugin-proposal-private-property-in-object`

- このプラグインは、オブジェクトリテラル内でプライベートプロパティを使用できるようにするためのものです
これにより、プライベートなクラスプロパティをオブジェクトの一部として扱えるようになります

# さいごに
新しいアプリ作成するたびにログアウトでエラー起きて同じことをしてたので、メモ残しとこうと思います笑

このコマンドは`rails new`したらとりあえずやっとけと、メンターさんに教えてもらったコマンドで、javascriptが正常に動作するために必要と聞いていました

プラグインについてまだまだわからないことが多いので、もう少し調べようと思います！
ひとまず今回はエラー解決方法をメモしておきます✍️

誤り等ございましたら教えていただけますと幸いです！
ログ管理

## はじめに
日ごろの運用に欠かせない、ログローテーションに関して記述します。
Linux で稼働することを前提に、以下の処理を含むログローテーションをシェルで記述します。

1. ログファイル名の変更 (アーカイブ目的)
2. ログファイルの圧縮
3. ログファイルの削除

## 処理内容

処理の全容は以下の通りです。変数で指定するディレクトリやファイル名、圧縮や削除のタイミングなどは、環境に合わせて変更しましょう。

```shell:全体
#!/bin/bash

#変数
log_directory='/usr/local/python/log/'
file_pattern='python.log'
file_pattern_compress='python*.log'
file_pattern_delete='python*.log.gz'
proc_date=`date '+%Y%m%d'`
compress_after=7
delete_after=30

#ファイル数分ループ
for file in log_directory
do
#アーカイブ
find $log_directory -name $file_pattern | xargs -I {} mv {} ${log_directory}python$proc_date.log
#圧縮
find $log_directory -mtime $compress_after -name $file_pattern_compress | xargs gzip -f
#削除
find $log_directory -mtime $delete_after -name $file_pattern_delete | xargs rm -f
done
```

#### 1. ログファイル名の変更 (アーカイブ目的)
```shell:変更
find $log_directory -name $file_pattern | xargs -I {} mv {} ${log_directory}python$proc_date.log
```

find でログディレクトリからファイル名のパターンに合ったファイルを検索し、 アーカイブ用のファイル名に変更しています。
xargs は、前の処理結果を後続の処理に引数として引き渡すコマンドです。そのため、パイプの前で検索したファイル名を、パイプの後ろに引き継いで、ファイル名を変更する流れです。{ } は引数の位置を指定します。
結果、python.logを検索して、python20240809.log のようなファイル名に変更します。

#### 2. ログファイルの圧縮
```shell:圧縮
find $log_directory -mtime $compress_after -name $file_pattern_compress | xargs gzip -f
```
find の条件に -mtime を指定して、最終更新日から compress_after で指定した日数が経過したものを圧縮しています。
結果、python20240809.log が圧縮され、python20240809.log.gz となります。

#### 3. ログファイルの削除
```shell:削除
find $log_directory -mtime $delete_after -name $file_pattern_delete | xargs rm -f
```
find の条件に -mtime を指定して、最終更新日から delete_after で指定した日数が経過したものを削除しています。

## 最後に
Yellowfin が参照するデータを [Python で処理](https://qiita.com/ExtremeCarvFJ/items/19ec4ec35872411fbcc4)し、その処理結果を[ログに出力](https://qiita.com/ExtremeCarvFJ/items/bbba76ba939f177e4a4a)する場合など、何もしなければ当然ログが肥大化します。
それがディスク容量の圧迫につながり、システム障害の原因となる可能性も否めません。

良いデータ分析のためにも、ログローテーションをはじめ、良い運用を行いましょう!

## 参考情報

https://medium.com/@anandhirematha/write-a-shell-script-to-automate-the-process-of-rotating-log-files-and-compressing-old-files-to-ae0fca227687
RD-GW on WindowsServer2022

# やりたいこと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017662/96f6534b-423c-426a-8090-9fceed6fe61b.png)







# 1. Windows Server 2022 のインストール


## 評価版のダウンロード

https://www.microsoft.com/ja-JP/evalcenter/evaluate-windows-server-2022

## Hyper-Vへのインストール

https://qiita.com/mindwood/items/5f18f753d916db0907aa

## インストール後作業

- Windows Update
- RDP有効化(暫定)

# 2. RD-GW セットアップ
## RD-GWインストール

https://www.kubalog.com/windows/windows_tech/rd-gateway/

※ **リソース承認ポリシー(RD RAP)は上記手順＋下記の通り関連グループをがっつり指定しないと入れんかった(理由はよくわからんかった...)**
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017662/14e1e9f2-7118-f7dd-1bb9-e6771d834b0a.png)

※ "3.2.5. 作成した証明書のエクスポート" 以降の手順はやらなくてもiOSから入れるので、スルー


## RDログイン用 ローカルユーザー作成

https://atmarkit.itmedia.co.jp/ait/articles/0609/02/news014.html

※ cmd.exe上で下記コマンドを実行してユーザー作成
```bat
net user <username> <password> /add
net localgroup Administrators <username> /add
```

※ 作成したユーザーは"パスワードあり Yes"になってないとRDP接続ができない
※ 前手順で作成したポリシーはAdministratorsのみRDPが貫通させられるようになっているため、"所属しているローカル グループ Administrators"とする必要あり。



# 3. RD-GW ログイン検知設定

## ログイン検知バッチの配置
detectLogon.bat
```bat
curl -s -X POST -H "Content-Type: application/json" --data "{\"content\":\"Login Detected.\"}"  https://discordapp.com/api/webhooks/HOGHOGE~
```

## ログイン検知バッチの起動設定
タスクスケジューラ設定：タスク スケジューラライブラリ
### 全般
- 名前：detect login
- ✓ユーザーがログオンしているかどうかにかかわらず実行する
- ✓最上位の特権で実行する
### トリガー
- イベント時 - ログ:Security、イベントID:6272
### 操作
- プログラムの開始 C:\Users\....detectLogon.bat
- オプションなし



# 4.セキュリティ強化設定
足りなそうだが...一応最低限

## RDPの無効化
リモートデスクトップの設定
- リモートデスクトップを有効にする：オフ
## Administratorの無効化
コンピュータの管理 ⇒  ローカルユーザーとグループ ⇒ ユーザー
Administrator ⇒ プロパティを右クリック
- 全般タブの"アカウントを無効にする"をチェックして、適用


 
# 5. iOS RDPソフト側設定
## ゲートウェイ設定
設定 ⇒ ゲートウェイ
- ゲートウェイ名：`<インターネット上に公開したFQDN>:<ポート番号>`
- ユーザーアカウント：`<username>`
     - ユーザー@ドメインまたはドメイン\Userユーザー：`<username>`
     - パスワード：`<password>`
## PC設定
- PC名：`<ローカルネットワーク内のPCアドレス>`
- ユーザーアカウント：`<ローカルネットワーク内のPCユーザ名>`
        - ユーザー@ドメインまたはドメイン\Userユーザー：`<ローカルネットワーク内のPCユーザ名>`
        - パスワード：`<ローカルネットワーク内のPCパスワード>`

※ ローカルネットワーク内のPCのRDPポートは開けておくこと
mac アプリのインストーラーいる? zip で良くない?

作ってはみたものの。

https://x.com/maochanz/status/1821350620118295004

この形式。

![sc 2024-08-09 at 13.27.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588914/64fe6ef0-3e6e-feb1-6f2c-e9448381dd5f.png)

これいる?

> Having a wrapper just to tell you "please drag the app to 
> /Applications" feels like an outdated practice to me.

>「アプリを Applications フォルダ にドラッグしてください」とだけ伝えるラッパーがあるのは、時代遅れのやり方のように思います。

zip で良くない? ファイルも同梱しといたら良くない?


詳細は以下から。

https://android.benigumo.com/20240808/macos-dmg-vs-zip/
azure functionsを新規作成したときにGithubActionsとの連携するときに「repository 〜 not found」と出る時

## 手順
以下参照（公式
https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-continuous-deployment?tabs=github%2Cazure-pipelines%2Cazure-portal

この操作からyamlを作成するとだいたい以下のようになる

``` yaml
# Docs for the Azure Web Apps Deploy action: https://github.com/azure/functions-action
# More GitHub Actions for Azure: https://github.com/Azure/actions

name: Build and deploy dotnet core app to Azure Function App - project-name

on:
  push:
    branches:
      - main
  workflow_dispatch:

env:
  AZURE_FUNCTIONAPP_PACKAGE_PATH: 'project-name' # set this to the path to your web app project, defaults to the repository root
  DOTNET_VERSION: '8.0.x' # set this to the dotnet version to use

jobs:
  build-and-deploy:
    runs-on: windows-latest
    permissions:
      id-token: write #This is required for requesting the JWT

    steps:
      - name: 'Checkout GitHub Action'
        uses: actions/checkout@v4

      - name: Setup DotNet ${{ env.DOTNET_VERSION }} Environment
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: ${{ env.DOTNET_VERSION }}

      - name: 'Resolve Project Dependencies Using Dotnet'
        shell: pwsh
        run: |
          pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}'
          dotnet build --configuration Release --output ./output
          popd
      
      - name: Login to Azure
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID }}
          tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID }}
          subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID }}

      - name: 'Run Azure Functions Action'
        uses: Azure/functions-action@v1
        id: fa
        with:
          app-name: 'project-name'
          slot-name: 'Production'
          package: '${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/output'
          
```

このまま動かすとリポジトリがPrivateだったりすると
`actions/checkout@v4`のStepで
` Error: fatal: repository 'https://github.com/hogehoge' not found`
とエラーが出て進まなくなる。
他の似たようなActionsではならないので意味不明だった。

## 解決
とりあえず検索した結果
https://github.com/actions/checkout/issues/1555
どうやらこのIssue

なので、
`jobs > build-and-deploy > permissions`
のセクションに
`contents: read`
を追加する。

``` yaml
    permissions:
      id-token: write # This is required for requesting the JWT
      contents: read
```

↑こうですね。
これでちゃんと解決した。

ドキュメントとかテンプレがちょっと古いものがあたったりすると解決に時間かかるな…
OracleのOGG連携って何？

#  OracleのOGG連携って何？
  
## はじめに
株式会社アシストエンジニアリング、エンジニアのsawasatoです。
弊社では所属のエンジニアが一人ずつ、各々興味がある分野や業務での気づきを定期的に投稿していきます！気になったらぜひ他のエンジニアの投稿もご覧ください！
 
突然ですが、皆さんの普段の開発現場ではデータベースは何を使っていますか？
私はOracleを使うことが多いです。Oracleを使う上で当たり前のように出てくるOGG連携という言葉。。意味がわからないですよね。。
私も最初はそうでした。なので今回は初めてOracleを使う方にOGG連携をわかりやすく説明できればと思います！

##  OGG連携とは
まずはOGG連携とは何か？について説明します。
ズバリ、データベースのコピー機能です！！
難しく考えてしまいますが、簡単にいうとデータベースのコピー機能なのです。
システムの規模が大きくなると、データベースを分散管理することが必要になります。その際に、データの一貫性を保ちながら複数のデータベース間でデータを同期することが重要です。そこで登場するのがOGG（Oracle GoldenGate）連携です！！名前がとってもかっこいいですよね！！

##  OGG連携の概要
次にOGG連携の概要について説明します。（Oracle GoldenGate）は、Oracleが提供するデータベース間のデータをリアルタイムで複製するためのソフトウェアです。このOGGを使うことで、とても早く、そして正確にデータベース間でデータを同期できるということです。めちゃめちゃ便利ですね笑

##  OGG連携の仕組み
じゃあOGG連携の仕組みはどうなってるの？これも一気に解決しちゃいましょう！
OGG連携は主に以下の3つのフェーズから構成されています。

1.抽出
・データベースの変更ログ（Redoログ）を読み取り、変更があったデータを抽出します。
・このフェーズでは、ソースデータベース上で行われた変更（INSERT、UPDATE、DELETE）を　　キャプチャします。

2.データの移動
・抽出されたデータは中間ファイル（Trailファイル）として保存されます。
・このファイルは、ソースデータベースからターゲットデータベースに転送されます。

3.適用
・ターゲットデータベースに到達した中間ファイルを適用し、データベースに変更を反映します。

仕組みを完全に理解する必要はありませんが、もし後輩エンジニアができた時に仕組みまで説明できたらかっこいいですよね！データベース全体の知識を深めるためにも気になったことは仕組みまで理解できるようにするといいと思います！

##  OGG連携の利点
仕組みについてはわかりましたが、それをすることでどんな利点があるのか。次は利点に着目していきます！

1.リアルタイム同期
・データの変更がリアルタイムでターゲットデータベースに反映されるため、最新のデータを常に利　用することができます。

2.高可用性
・データの複製により、システムの高可用性を確保できます。例えば、障害が発生した場合でも別の　データベースで作業を続行できます。

3.負荷分散
・複数のデータベースにデータを分散することで、読み取り負荷を分散し、システムのパフォーマン　スを向上させることができます。
資格の勉強などで高可用性や負荷分散などの言葉は出てきましたが、実際にこういったソフトウェアで実現されているんですね！
## まとめ
今回は、初めてOracleを使う方に向けてOGG連携について説明しました！OGG連携は、データベースの複製と同期を効率的に行うための強力なツールです。これを理解することで、システムのスケーラビリティや可用性を向上させることができるでしょう！Oracle初心者の皆さんに向けて執筆しましたので、かなり簡単な説明になっています。OGGやOracleもとても奥が深いです。興味がある方は、ぜひOGGのドキュメントやチュートリアルを参照して、実際に試してみてください！！一緒にデータベースのスペシャリストになりましょう！！

## 採用拡大中！
アシストエンジニアリングでは一緒に働くフロントエンド、バックエンドのエンジニア仲間を大募集しています！
少しでも興味ある方は、カジュアル面談からでもぜひお気軽にお話ししましょう！
お問い合わせはこちらから↓
https://www.assisteng.co.jp/contact/
DJMAX RESPECT V 用コントローラーを作成する Pt.1

# 背景
Steamで音ゲーを漁っていたところ、セールで安く、結構面白かったため、コントローラーを作ってみたくなった。
以下のような既製品があるので、参考にしながら作れると思ったため。

https://gamo2.com/jp/product/k28/

# 要件
・ProMicroを使用する。
・ホットスワップ対応とする。
・ケースはサンドイッチマウントとする。
・寸法は縦9cm,横23cm程度とする。
・キースイッチの数は28個とする。

# 設計
▷Keyboard Layout Editorでレイアウトを作成し、JSONファイルをダウンロードする

http://www.keyboard-layout-editor.com/

基板の設計で使用するため、レイアウトが完成したら、Download JSONを押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075609/1ce2003e-bf37-dc65-de13-c03d4220b464.png)

ケースの設計でRaw dataを使用するため、作成後も閉じないことをオススメします。

▷KiCadをインストールし、json-layouterでJSONファイルを読み込む

https://www.kicad.org/

以下URLからKiCadの外部プラグインのjson-layouterをダウンロードします。

https://github.com/takashicompany/json-layouter

json_layouter.pyをインストール先のフォルダのKiCad\8.0\scripting\pluginsへ移動すると、KiCadから外部プラグインとして利用できるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075609/41fdbb6c-5aec-a4cc-fce0-fb2af032cc25.png)

Keyboard Layout EditorでダウンロードしたJSONファイルを選択し、Runボタンを押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075609/3193c968-92dd-2593-ec5a-fa92f772e46a.png)

すると、このようになります(ダイオードは今回省略しています)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075609/6ce073ce-0a56-8e9b-59e2-b60e8bec3f6d.png)

▷回路図を設計する
格子状にすればいいっぽいです。
行と列については、後ほどプログラミングでも使います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075609/06a5f637-a1c0-2e1a-ecc3-bf5779518ddc.png)

▷基板の配線、外形など
回路図を基に、ダイオードを設置し、配線します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075609/c2366bde-633e-e375-7bc2-dc14b8698b93.png)
エラーが出なければ問題ないと思います。

▷ケースの設計
以下のPlate & Case Builderを使用します。

http://builder.swillkb.com/

Plate Layoutに、Keyboard Layout Editorで生成されたRaw dataをコピペして、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075609/0efd70ae-e9f0-411a-13b1-5c26529c790b.png)

Draw My CADボタンを押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075609/248678b1-e615-900a-9867-5bf63176efbe.png)

他にも何枚かレイヤーが作成されますが、シンプルな作りにしたいので、今回はSwitchとBottomのみ使用します。
生成されたレイヤーをSVGファイルで保存しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075609/1b3727df-6cba-91a1-1dee-4f932084bf39.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075609/d0ffe592-dbde-ae24-b2ef-c0fbcdd987db.png)

# 発注
▷基板の発注
自作キーボード界隈(?)では有名なんですかね。JLCPCBを使用しました。

https://salicylic-acid3.hatenablog.com/entry/jlcpcb-order

▷ケースの発注
遊舎工房のレーザー加工サービスを使用しました。
初めてだったので、念のため安心サポートのオプションを使用しました。
SVGファイルをイラレ等で、フォーマット通りに編集し、納品します。

https://shop.yushakobo.jp/products/lasercut

▷その他のパーツ
・Pro Micro Type-C版

https://shop.yushakobo.jp/products/3905?_pos=2&_sid=d5dd0b7ef&_ss=r

・チェリー(Cherry) MX RED Switches

https://amzn.asia/d/iSvePmc

・Kailh ホットスワップ可能 PCBソケット

https://amzn.asia/d/e8Z9S2t

・六角スペーサー

https://amzn.asia/d/fymZKp4
Amazon Inspectorのエージェントスキャンとエージェントレススキャンで結果が異なることがある原因と対処

# これは何？

Amazon Inspectorにおける EC2の脆弱性検出において、エージェントベーススキャンだと検出されなかったアプリケーションのパッケージ脆弱性が、エージェントレススキャンで検出されたため、原因を調べた時のメモです。

# 結果が異なる原因

以下公式ページの注意点に書いてありました。

https://docs.aws.amazon.com/inspector/latest/user/scanning-ec2.html#agentless

:::note
Linuxインスタンスでアプリケーションプログラミング言語パッケージの脆弱性をスキャンする際、エージェントレス方式ではすべての利用可能なパスをスキャンしますが、エージェントベースのスキャンではデフォルトのパスと、Amazon Inspectorのディープインスペクションの一環として指定した追加パスのみをスキャンします。このため、同じインスタンスでもエージェントベース方式とエージェントレス方式でスキャンされた場合、異なる結果が得られる可能性があります。
:::

エージェントベーススキャンでは、デフォルトでは以下のパスがスキャンされます。

- /usr/lib
- /usr/lib64
- /usr/local/lib
- /usr/local/lib64

これらのパスのいずれにもアプリのパッケージが配置されていなかったため、エージェントスキャンでは脆弱性が検出されず、結果が異なったようです。

# 対処方法

カスタムパスを設定することで、エージェントスキャンでスキャンするパスを追加することができます。

## 設定手順

- Inspectorコンソールの左のタブメニューから
全般設定→EC2 scanning settings をクリック
- **Custom paths for your own account** の編集をクリック
- 追加するフォルダを設定する。ここに設定したフォルダ以下のファイルが、スキャン対象に追加される。
- アプリ配置先をパスに追加する。例えば `/home/ubuntu` とすると、 /home/ubuntu 以下の全てのファイルがスキャン対象に追加される

:::note warn
Deep Inspection では、インスタンスあたりのパッケージ数の上限が 5,000 個、パッケージインベントリ収集の最大時間は 15 分に設定されています。カスタムパスを適切に設定することで、これらの制限を回避することが推奨されます。
:::

# まとめ
公式ドキュメントはしっかり読むべきですね。

# 参考ページ

- https://docs.aws.amazon.com/inspector/latest/user/deep-inspection.html#deep-inspection-paths
- https://dev.classmethod.jp/articles/amazon-inspector-deep-inspection-ec2-instances/
Saliency map の評価指標 - Deletion metric, Insertion meric

こんにちは。ぺいぺいです。本記事は、RISE: Randomized Input Sampling for Explanation of Black-box Models を参考に作成した。画像処理 XAI の評価指標の Saliency map（顕著性マップ） の評価指標である、Deletion metric, Insertion meric を解説します。

https://arxiv.org/pdf/1806.07421

本手法の公式Githubは以下のリンクにあります。

https://github.com/eclique/RISE/blob/master/Evaluation.ipynb

RISEの手法の解説記事はすでにいくつか存在するため、今回は、そこで提案された評価指標に焦点を当てます。

# Deletion metrics, Insertion metric の概要
* これらはともにGrad-CAMやRISEなどのニューラルネットワークのSaliency mapによる可視化がどのくらい重要な場所を捉えられているかを評価する指標である
* Deletion metrics は、Saliency mapの値の大きい領域から入力画像を消していき、急激に精度が下がるSaliency map = 良い説明 というように考える指標
* Insertion metrics はSaliency mapの値の大きい領域から情報のない画像（真っ暗やぼやけた画像）に入力画像の領域を追加していき、急激に精度が上がるSaliency map = 良い説明 というように考える手法

# 背景
論文中（2018年時点）では以下の問題点が指摘されていた。
* XAIの研究が進んできているのにも関わらず、「説明可能性(Explainablity)」を統一して使用されている評価指標が存在しない。以下にSaliency map の例を示す。これは画像が金魚と分類された際のSaliency map である

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2718862/76463bde-b5a3-4ec7-b019-3e210eba6468.png)

* Explainability の評価として人間による評価が多く行われている。例えば、Saliency map（ニューラルネットワークが判断をする際に注目している位置を可視化したマップ）を使用し、それを人間がどの程度尤もらしいかを判断する
* しかしこれでは、「どうしてそのような判断をしたのか」について解釈できない。例えば、画像中の車を識別したとしても、ただ車の特徴を捉えたのか、道路に注目して「道路の上にある物体は車である」と捉えたのかは区別できない
* 人間を評価のループから外すことで、モデルの問題に対する独自の見解をより公正かつ客観的に反映することができると主張

# Deletion metrics
Deletion metrics のキーアイディアは、「画像中からモデルの出力の根拠となる部分を除くと出力結果が変わる」というものである。Deletion metrics では、画像中の重要と思われる領域をSaliency mapから決定し、重要な順に削除していく。その際、分類されていたクラスの確信度が減少する。その減少が急激なほど、「良い説明」をしていると判断する。

では、「削除する」というのは具体的にどのようにして行うべきなのだろうか？ 論文中では３種類提案されている。
* 画素値を 0 もしくは、とある一定の値にする
* 対象領域を blur つまりぼやかす
* 小さなバウンディングボックスで切り抜く

実像では、どのように削除するかは関数の引数として渡せるようになっているが、実際の論文中では、画素値を0にすることで実験を行った。その理由として、「削除」する目的は、モデルを騙すことであり、blur をしたとしても、よく学習したCNNはその周りの情報を参照してクラスを当ててしまうことが多くあるためである。

Deletion metrics を求める具体的な手順は以下の通りである。
1. 画像分類器を学習
1. GradCAM、RISE などのSaliency mapを得られるアルゴリズムによりSaliency map を取得
1. Saliency map の高いピクセルから入力画像の対応するピクセル値を0にしていく。横軸に消去したピクセルの割合、縦軸に監視するクラスのモデルが出力する確信度をとり、曲線を描く
1. 曲線と横軸からなる領域の面積(Area Under the Curve)を計算、低ければ低いほど良い

# Insertion metrics
Insertion metrics のキーアイディアは、Deletion metrics の逆で、「情報量が少ない画像に対して出力の根拠となる部分を挿入すると出力結果が変わると」と言うものである。Saliency map の値が高い順に情報量が少ない画像に対して、領域を追加していく。その際、分類されていたクラスの確信度が増加する。増加が急激なほど「良い説明」をしていると判断する。

重要な領域を挿入していくとしても、どのような画像をスタートラインとし、どのように挿入していくかいくつかの手法が考えられる。スタートの画像と挿入の方法のペアとして以下の2つが考えられる。

* 真っ黒な画像にSaliency map の高い領域と対応する画像の領域をただ追加していく
* ぼやかした画像に対して、Saliency map の高い領域と対応する画像の領域から順に、blur を解除していく

論文中では、ぼやかした画像をスタートとし、blur を解いていく方法が推奨されている。真っ黒な画像からスタートしてしまうと、追加の仕方によっては、人間でさえ本当の物体とは全く違うものに分類してしまう可能性があり、確信度の出力がバラバラになってしまう可能性があるためである。例えば、バースデーケーキのいちごの部分から表示された際にいちごクラスに分類されてしまうなどの例が考えられる。

# 適用例
論文中で示されている適用の例は以下の通りである。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2718862/91d20240-fc59-1fce-f87c-00ba0371707d.png)

また、論文中では、これらの指標を使用して、提案手法RISEが従来手法のLIMEやGrad-CAMと比較して優れているということを主張している。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2718862/ba3327a0-13b6-5550-5841-e925a6101f7e.png)
マザボ交換後、OSが起動しない

## マザボ交換後にOSが起動しない
先日、マザボとCPUを交換してストレージをそのまま移植しました。
その際、OSが起動しなかったので状況を整理した上で対応内容を備忘録として共有します。
まず結論から述べると、ストレージのフォーマットがGPTではなかったことが原因になります。
結構稀なケースだと思うのであまり需要はないかと思いますが、原因や症状を認識して知見を広めていただければと思います。

## 状況整理
1．移植後、OSが立ち上がらずBIOS画面に移行
2．ストレージは認識している
3．Bootが存在しない

単純にストレージの認識はしているのですが、Bootが認識されていないことから起動することができませんでした。

## BIOS設定でCSM有効化
調べていると、BIOS設定でCSMを有効にすると正常にBootが認識されるということで有効にしたところ、無事Boot選択ができ、起動することができました。
尚、CSMを有効にする場合はセキュアブートを無効にする必要があります。

## CSM無効でも認識させるには
Windows11を使うには、セキュアブートを有効にする必要があります。
しかし、先述の通りCSMを有効にする場合はセキュアブートも無効にする必要があります。
それでは困ってしまうのでCSMを有効にしなければなぜ認識されないのかを調べたところ、フォーマット形式がMBRであることが要因でした。

## MBRからGPTに変換
ここまで要因が分かればあとはGPTに変換するだけです。
私はWindowsなのでコマンドプロンプトを**管理者権限**で起動します。

安全のため、変換が可能であるか検証してから実行します。
```dosbatch
rem 変換検証
mbr2gpt /validate /disk:0
```

**Validation completed successfully**と表示されれば、変換可能ですので、続いて以下のコマンドで実行します。
```dosbatch
rem 変換実行
mbr2gpt /convert /disk:0 /allowfullos
```
**Conversion completed successfully**と表示されれば成功です。
念の為変換されたことを確認してください。

## CSM無効化
あとはBIOS画面でCSMを無効化します。
私の場合、Windows11なのでセキュアブートも併せて有効化します。
BIOS設定の変更を保存したら再起動して、Bootを認識してOSが起動することを確認して作業完了です。

## 最後に
まさかMBRで使っていたとは思っていませんでした。自分の物なのに把握できておらず。。。
てっきりOSが飛んだかと思ってわざわざUSBにWindowsインストールメディアを作成して回復環境からデータだけ退避させたのですが、取り越し苦労でした。
今回のようなケースが遭遇しましたらまずはフォーマット形式も確認してみるといいですね。
記事強制の功罪について考える。

ポエムだけど、それだけだとQiita的な記事にはならないと思うので最近のあるある。

### 標準出力を標準入力リダイレクトする時あるある
あれ？
```
$ prog 2>&1 > /dev/null
```
だっけ？
```
$ prog 2&>1 > /dev/null
```
だっけ？最近使っていないから忘れちゃった。
あれ？なんか
```
$ ls
1
```
`1`ってファイルができてるよ･･･orz。

以上。最近私も陥ったコマンドあるあるでした。

# さて本題

ここからが本題です。最近よく見るのが「XXXにQiitaに100本書き込むと良いことが起きると言われた」みたいな書き込みが見られるようになりました。

私はそういった組織に属していないので、この良いことが何かは私にはわかりません以下は予想です。

- 受講料が減るよ
- 単位認定条件だ
- それがあなたのためだから

みたいなことを言われているのでしょうか？これには功罪があると思います。

* 功：指示しいてる側は良くも悪くも宣伝効果がある。実際に書き込んでいる人は **(技術的に有用な場合だけ)** 宣伝効果がある。
* 罪：強制的に書き込みの圧力をかけているのでいやいや書くと質が下がるので本人の評判が下がるだけではなく指示している側の評判も下がる。

功はとくに実際書き込んでいる人には全く関係ない場合が大半です、圧力をかけられている側は気づかずに広告塔へ仕立て上げられている **だけ** です。
罪は書いている本人にも書かせている側にもデメリットになっています。

::: note alert
書かされている側は早く気がつくべきです、良いように扱われているだけのことを･･･。
:::

企業あげてQiitaに書き込みしているところも見受けられますが、質の悪い書き込みを多量に書き込んでいることを許容しているのが信じられません。
その上「私たちと一緒に働きませんか？」って言われても…働く気には1ビットにもなりません。
質の悪い書き込みで集まる社員なんて質の悪い人じゃないかなぁ･･･と私が勝手に心配にしてしまいます。

きっと書いている本人はこう言っているのでしょう。
「だってXXXさんが書けっていったから･･･。」

私の技術的な書き込みは質が悪いですが、良くっても悪くっても自己に責任があります。しかし、こういう場合って責任の所在ってどこにあるんでしょうね？よくわかる人に教えて頂ければ幸いです。

ちょっと関係ないですが、「だってXXXさんがやれって言ったから」の典型例です。
皆様はどうお考えでしょうか？

https://nlab.itmedia.co.jp/nl/articles/2408/07/news190.html

わたしも友人とこの書き込み非常に気にしていました。

以上、Qiitaにはポエムしかしたためないことを決めているそんなお盆前でした。
技術的な書き込みが見たい方は[Zenn.dev](https://zenn.dev/evakichi)へ。(と宣伝してみる。)
Next.js の dashboard tutorial 用の docker image を作ってみました。

## 作成した Dockerfile

```
FROM node:20-alpine
RUN apk update && \
    apk upgrade && \
    apk add --no-cache g++ && \
    apk add --no-cache make && \
    apk add --no-cache python3 && \
    mkdir /home/pnpm && \
    npm install -g npm@latest && \
    npm install -g pnpm && \
    pnpm config set store-dir /home/pnpm/store
```

### npm が古いと警告が出たので npm を最新に upgrade しています。

```
npm install -g npm@latest
```


出た警告

```
1 package is looking for funding
  run `npm fund` for details
npm notice
npm notice New patch version of npm available! 10.8.1 -> 10.8.2
npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.8.2
npm notice To update run: npm install -g npm@10.8.2
```

### npx create-next-app を実行すると no such file or 
directory エラーが出たので、 pnpm をインストールした後で、ストアの設定をしています。

```
pnpm config set store-dir /home/pnpm/store
```

出た警告

```
 ERR_PNPM_ENOENT  ENOENT: no such file or directory, copyfile '/tmp/.pnpm-store/v3/files/bb/fff7acd12649dcbaa64c9525e49808b3c214609635b0aa22c35e5b21b923a9535c00ecaabbc4bfd4fe5491b158e9f6a227cf1e35c728dd4d606cf6075e9b34' -> '/tmp/nextjs-dashboard/node_modules/.pnpm/any-promise@1.3.0/node_modules/any-promise_tmp_42/register/bluebird.d.ts'
Progress: resolved 227, reused 0, downloaded 113, added 104

Aborting installation.
  pnpm install has failed.
```
Javaで「文字列の先頭や末尾などの位置にマッチするパターンを記述する」の動作を確認してみた

# 概要

Javaで「文字列の先頭や末尾などの位置にマッチするパターンを記述する」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/start/regex/index9.html

# 実装

以下のファイルを作成しました。
```JSample9_1.java
import java.util.regex.*;

class JSample9_1{
  public static void main(String[] args){
    String regex = "^Red";
    Pattern p = Pattern.compile(regex);

    Matcher m1 = p.matcher("Red Table");
    System.out.println(m1.find());  // true

    Matcher m2 = p.matcher("Reduce speed");
    System.out.println(m2.find());  // true

    Matcher m3 = p.matcher("Border Color is Red");
    System.out.println(m3.find());  // false
  }
}
```

以下のコマンドを実行しました。
```
$ javac JSample9_1.java 
$ java JSample9_1 
true
true
false
```

# まとめ

何かの役に立てばと。
【ChatGPT＋Code Interpreter】で文章をワード単位で出すアニメGIFです。


　どうも、カーブミラーです。

　今回は、文章をワード単位で出すアニメGIFです

:::note info
本記事は、ChatGPT（有料版）
で行なっております。画像は
あります。　あしからず。
:::

　まずは、ニュース。

　OpenAIから。

　なんと、
　　無料版に
　　　DALL-E3を
　　　　二枚だけ開放。

　二枚だけって……
　　五枚くらい開放しようよ😅

　[OpenAI公式ポスト](https://x.com/OpenAI/status/1821644904843636871?t=JEJbNngUQK59osouLU2M7Q&s=19)
***
　次のニュース。

　先日、
　　ChatGPT で
　　　Code Interpreterを
　　　　使用した際に、
　　　　　ダウンロードリンクが
　　　　　　出ない不具合について。

　さきほど
　　直ったのが
　　　確認できました。

　よかった😅
***
　さて、本題です。

　今回は、
　　文章をワード単位で出す
　　　アニメGIFです。

　よくテロップで、
　　音声を出すときに
　　　ワード単位で出てくる
　　　　ものがありますよね。
　　　　　アレを擬似的に
　　　　　　やっています。

　出来上がりはこちら。
![animated_text (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/905843a7-ef84-c31f-d68f-7ff0d2b1128a.gif)

　Promptがこちらです。
```Text:
# CodeInterpreterで文字列処理

### 初期設定
1. 画像のサイズ: `width = 512`, `height = 512`
2. 背景色: `bg_color = (255, 255, 255)` （白）
3. テキスト: `text = "I am a ChatGPT."`
4. テキストの色: `text_color = (0, 0, 0)` （黒）
5. フォントサイズ: `font_size = 48`
6. フォントパス: `font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"`
7. フレーム数: `frames = 60` （1秒あたり30フレーム）

### 注意事項
コード不要。
確実に実行せよ。

### 処理内容
1. 白い正方形画像を作成する。
2. 画像中央にテキストを描画する。
3. [テキストがワード単位で0.5秒間隔で出てくる]アニメーションGIFを作成する。
    - 各フレームにおけるテキストの位置を計算して配置する (`x`, `y`)
4. GIFを保存する (`gif_path`).
```

　3. [テキストがワード単位で0.5秒間隔で出てくる]

　この部分が
　　やりたいことの指示に
　　　なります。

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
＃26　【Chrome用】Google Chatのメッセージのリンクをコピーできる拡張機能を作った

## 追記

Google Chat公式でメッセージのURLをコピーする機能がが追加されたため、拡張機能を使わずともコピーが可能になりました。
本記事は公式が対応する前に執筆したものです。

## 概要

Google Chat にて特定のメッセージを指したいときに、そのメッセージのURLが分からないと不便でしたので、URLをコピーできる機能を作成しました。

URLをクリックすると、そのメッセージのところまで移動します。
もちろん、自分が参加していないルームのURLは開けません。(警告が出るのみ)

## 使い方

こちらのページからインストールしてください。
https://chrome.google.com/webstore/detail/google-chat-copy-message/fcpndhggcmeanomlafjkgdnbjkbpkeih

インストール後は、Google Chat のメッセージにフォーカスを当てるとクリップボードマークのボタンが表示されるようになり、ボタンを押すとURLがコピーされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3843084/70385ebd-df1d-af30-6fb5-979ea64fb920.png)


## 仕組み

こちらの拡張機能を作る際、まずは Google Chat にメッセージごとのURLが存在するかの調査からしました。
調べてみたところ、Google Chat のメッセージごとのURLは存在するけど、見つけにくいところに隠されていることが分かりました。
<br>
「受信トレイに転送」というボタンがあり、そのボタンを押すとGmailにメールが届くのですが、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3843084/8b560f7d-5b48-de61-e65c-d66a85e39153.png)

届いたメール内にあるリンクの遷移先がメッセージのURLです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3843084/3015ef74-e2a7-86e6-3073-81089e5497b4.png)

なので、今回ご紹介した拡張機能を導入しなくても、URLを知りたいメッセージを毎回受信トレイに転送すれば、一応URLはわかります。
<br>
以上より、メッセージのURLが存在することが分かったので、続いてURLの法則性を調査しました。
色々なメッセージのURLを先ほどの方法で見てみたところ、以下の法則があることがわかりました。

| 種別 | URL |
|--|--|
| チャットのメッセージ | `https://chat.google.com/dm/{グループID}/{トピックID}` |
| スペースのメッセージ | `https://chat.google.com/room/{グループID}/{トピックID}` |
| スペースのスレッド内のメッセージ | `https://chat.google.com/room/{グループID}/{トピックID}/{データID}` |

グループID, トピックID, データIDについては、それぞれ data-group-id, data-topic-id, data-id という名前で、HTMLの中に埋め込まれています。
<br>
これでURLの法則性も掴めたので、ボタンがクリックされたときに javascriptでグループID, トピックID, データIDをHTMLから取得してURLを生成しています。
細かいロジックについては、公開したChrome拡張機能のソースコードから確認可能です。
Chrome拡張機能のソースコードを見る方法は、調べたらすぐ見つかると思います。

## 既知の不具合

コピー用ボタンが複数表示されてしまうことがあるそうです。
再現しなかったため修正はできていませんが、もし発生した場合はページを再読み込みしてください。

## まとめ

[以前の記事](https://qiita.com/nxted_sapporo/items/4b9364dda2c0a2c58d0a)に続き、今回もChromeの拡張機能を作ってみました。
今後も業務効率化に繋がるスクリプトを思いついたら積極的に挑戦していきたいです。
最後まで読んでいただきありがとうございました。
Raspberry PiでUbuntu ServerのIPアドレスをNetPlanで固定する方法（LLMを活用して効率的に設定ファイルを生成）

# ゴール
Ubuntu ServerをインストールしたRaspberry PiのIPアドレスを、NetPlanを使用して確実に固定する手順を解説します。この記事では、ChatGPTなどのLLMを活用して効率的に設定ファイルを生成し、ネットワーク設定を簡単に行う方法も紹介します。

# 実行環境
- Raspberry Pi5
- Ubuntu 24.04 LTS

# Netplanについて
Netplan は、UbuntuなどのLinuxディストリビューションで使用されるネットワーク設定ツールです。これは、シンプルなYAMLファイルでネットワーク構成を記述し、その設定をNetworkManagerやsystemd-networkdといったバックエンドに適用するフロントエンドツールです。WindowsOSでは「ネットワークと共有センター」が近い役割を果たしています。主に以下を設定できます。

- ネットワークインターフェースの設定
- IPアドレスの管理
- ゲートウェイとルーティングの設定
- DNSサーバーの設定
- VLAN（仮想LAN）の設定
- ブリッジインターフェースの設定
- Bonding（リンクアグリゲーション）の設定
- プロキシ設定
- インターフェースのメトリックの設定
- IPトンネルの設定
- MTUの設定
- Wake-on-LANの設定
- IPアドレスの動的変更
- ポリシールーティング 


Netplanは、/etc/netplanディレクトリのNN-cloud-init.yaml（Nは整数）の内容を読み込み、システムの起動時に指定されたネットワークインターフェースに適用します。50-cloud-init.yamlが初期に作成されます。NNを変更したファイルを作成することで、異なる設定ファイルの適用順序を制御できるため、特定の設定が他の設定よりも後に適用されるようにしたい場合に有効です。

Netplanがこれを処理することで、指定されたIPアドレス、ゲートウェイ、DNSサーバーなどの設定が有効になります。

# 目標
NetPlanの活用により 60-cloud-init.yaml を作成することでIPアドレスを固定することができます。
ここでは、ChatGPTなどのLLM（例ではChatGPT4oを使用）を活用して60-cloud-init.yamlを作成するコマンドを生成することを目指します。

1. 50-cloud-init.yamlの内容を確認する
    ```sh
    cd /etc/netplan
    sudo cat 50-cloud-init.yaml

    <50-cloud-init.yamlの内容>
    ```
1. ChatGPT 4oなどで下記プロンプトを実行
    ```
    NetPlanを活用してUbuntuServerのIPアドレスを"<IPアドレス>"に固定したいです。
    50-cloud-init.yamlの内容は下記でした。
    IPアドレスを"<IPアドレス>"に固定し、60-cloud-init.yamlというファイル名で作成するためのコマンドを生成してください。
    
    ~~~
    <1で取得した50-cloud-init.yamlの内容>
    ~~~
    ```
1. 下記のような内容が出力されます
    ```
    sudo tee /etc/netplan/60-cloud-init.yaml > /dev/null <<EOF
    <指定のIPアドレスに固定する60-cloud-init.yamlの内容>
    EOF
    
    sudo netplan apply
    ```
1. 上記コマンドを実行後「sudo reboot」を実行し、IPアドレスを確認します。

# おわりに
今回の記事では、Raspberry PiにインストールしたUbuntu ServerのIPアドレスをNetPlanを使って固定する手順を解説しました。ネットワーク設定はシステムの安定稼働において重要な要素であり、特にRaspberry Piのような小型デバイスをサーバーとして運用する場合、固定IPアドレスの設定は必須とも言えます。

さらに、ChatGPTなどのLLMを活用することで、ネットワーク設定の作業が効率化され、ミスを減らしながら素早く設定できることをお伝えしました。NetPlanの設定に限らず、様々な技術的課題に対して、LLMを活用することで解決策を迅速に得られる可能性が広がります。

この手順を参考に、ぜひご自身の環境でもIPアドレスの固定化に挑戦してみてください。もし何か問題が発生した場合やさらなる知識を深めたい場合は、引き続きLLMや関連ドキュメントを活用してみるのも良いでしょう。安定したネットワーク環境で、快適なサーバー運用を実現してください。
Zoomで初回起動で落ちる対策方法

# 前提
OS Ubuntu 22.04
メモリー　DDR5-4800 32GB*4 = 128G
CPU 13th Gen Intel(R) Core(TM) i9-13900KF
　　└マイクロコード 0x125
マザーボード　ASUSTeK ProArt Z790-CREATOR WIFI
　　　　　　　　└BIOS　American Megatrends Inc. 2402

# 結論
メモリの周波数をBIOSで4800MHzから4000MHzまで下げたら安定しました

# なぜ、気づいたか？
今話題の問題のIntel K付きCPU使ってます
だが、他のソフトは事実上問題起きてないです
BIOSで「Intel Default Settings」の状態でベンチ10分間高負荷かけても耐えきりました

となると、メモリが怪しい
以前、メモリテストで4800MHz失敗しました
（4本の時に起こる問題、2本は大丈夫）

そして、4200MHzでもテストでは完走してました
今回さらに4000MHzにさげたら、Zoomの落ちる問題は解決しました