OmniAICreator/Qiita-1.07M huggingface dataset:
nodeのオプションにmax-old-space-sizeに設定する値の算出方法

# 背景

viteで開発中にたまにこの「JavaScript heap out of memory」のエラーになり、落ちることがあった為調査しています。

```
built in 15152ms.
[vite-plugin-static-copy] Copied 1 items.
build started...
<--- Last few GCs --->
[1764:0x120040000]  1724578 ms: Scavenge (reduce) 3845.4 (3929.1) -> 3845.0 (3929.4) MB, 2.3 / 0.0 ms  (average mu = 0.076, current mu = 0.019) allocation failure;
[1764:0x120040000]  1724582 ms: Scavenge (reduce) 3845.7 (3929.4) -> 3845.2 (3929.9) MB, 3.2 / 0.0 ms  (average mu = 0.076, current mu = 0.019) allocation failure;
[1764:0x120040000]  1724587 ms: Scavenge (reduce) 3845.9 (3929.9) -> 3845.5 (3929.9) MB, 3.6 / 0.0 ms  (average mu = 0.076, current mu = 0.019) allocation failure;
<--- JS stacktrace --->
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
```

# Viteのissue

https://github.com/vitejs/vite/issues/2433

こちらで紹介された回避策で以下が紹介されていました
```terminal
node --max_old_space_size=16384 vite build
```
--max_old_space_sizeについて調べます。

# --max-old-space-sizeとは

https://nodejs.org/api/cli.html#--max-old-space-size=SIZE:~:text=%23-,%2D%2Dmax%2Dold%2Dspace%2Dsize%3DSIZE%20(in%20megabytes),-%23

V8の古い世代のメモリセクションの最大メモリサイズを設定する為のオプションです。
メモリ消費量が上限に近づくと、V8は未使用メモリを解放するためにガベージコレクションに多くの時間を費やします。

:::note
2GiBのメモリを持つマシンの場合

これを1536(1.5GiB)に設定することで、他の用途にメモリを残し、スワップを回避することができます。
他の用途のためにメモリを残してスワップを避けるために、この値を1536（1.5GiB）に設定することを検討してください。
:::

:::note
〜ガーベッジコレクション〜
コンピュータプログラムの実行環境などが備える機能の一つで、実行中のプログラムが占有していたメモリ領域のうち不要になったものを自動的に解放し、空き領域として再利用できるようにするもの
[ガベージコレクション](https://e-words.jp/w/%E3%82%AC%E3%83%99%E3%83%BC%E3%82%B8%E3%82%B3%E3%83%AC%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3.html)

〜スワップ（スワップアウト）〜
スワップアウトとは、メモリ上のデータを一時的にハードディスクへ退避させること
システム全体の処理能力が落ちる

- [スワップアウト](https://japan.zdnet.com/glossary/exp/%E3%82%B9%E3%83%AF%E3%83%83%E3%83%97%E3%82%A2%E3%82%A6%E3%83%88/?s=4#:~:text=%E3%82%B9%E3%83%AF%E3%83%83%E3%83%97%E3%82%A2%E3%82%A6%E3%83%88%E3%81%A8%E3%81%AF%E3%80%81%E3%83%A1%E3%83%A2%E3%83%AA,%E3%83%A1%E3%83%A2%E3%83%AA%E6%8A%80%E8%A1%93%E3%81%A7%E7%94%A8%E3%81%84%E3%82%89%E3%82%8C%E3%82%8B%E3%80%82)
- [Interstage Application ServerにおけるJavaアプリケーション実行時の、スワップアウトとGC（ガーベジコレクション）の関係について](https://www.fujitsu.com/jp/about/faq/sfw-interstage/applicationserver/6677.html)
:::

次にデフォルト値を超える値を設定する必要がある為、デフォルト値を算出します。

# --max-old-space-sizeのデフォルト値の算出方法

:::note
MacOS 64bit
メモリ 16 GB
node v18.18.0
での検証です。
:::

```terminal
node -e 'console.log(Math.floor(v8.getHeapStatistics().heap_size_limit/1024/1024))'
4144
```
デフォルト値は4144MiBでした。

[こちら](https://qiita.com/kawanet/items/cfedd535990b32710c50)の記事で1400MBと書かれていましたが、今回は異なっていました。

[こちら](https://zenn.dev/legalscape/articles/a0715a699eacb5)の記事でも触れられています。

# 参考
- [node.js の --max-old-space-size のデフォルト値は 1400MB](https://qiita.com/kawanet/items/cfedd535990b32710c50)
- [Node.jsのメモリ制限 (2024年版)](https://zenn.dev/legalscape/articles/a0715a699eacb5)
Prologで差分リスト

## 概要

今回は差分リストを調べたのでまとめてみました。

Prologではリストの要素を直接変更することができないので、差分リストのような手法を利用せずにリスト操作を実装すると、毎回リストがコピーされてメモリや実行速度が遅くなるという問題があります。

**差分リスト** はPrologの単一化(Unification)が高速に動作するという性質を利用して、この問題を解決しています。

差分リストの挙動に関しては以下の解説が詳しいので参照してください。

- http://www2.koyahatataku.com/blog/2021/05/13/prolog%E3%81%AE%E5%B7%AE%E5%88%86%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AB%E9%96%A2%E3%81%97%E3%81%A6/

## コード

とりあえずリストの結合に関して、ChatGPT先生に聞きながらコードが書けたので載せておきます。

```prolog
% 差分リストに変換します
% list_to_diff_list/2
%   [1,2,3] →[1,2,3 | E]-E
%   ※ Eはバインドされていない変数
list_to_diff_list([], E-E).
list_to_diff_list([X|Xs], [X|E]-Tail) :-
    list_to_diff_list(Xs, E-Tail).

% 元のリストに変換します
% diff_list_to_list/2
%   [1,2,3 | E]-E → [1,2,3]
%   ※ Eはバインドされていない変数
diff_list_to_list([X, E]-E, [X]).
diff_list_to_list([X|E]-Tail, [X|Xs]) :-
    diff_list_to_list(E-Tail, Xs).

% 差分リストをマージします
% merge_diff_list/3
%   [1,2,3 | E]-E
%   [3,2,2 | F]-F
%   → [1,2,3,3,2,2 | F]-F
%   ※ Eの部分に[3,2,2]を入れるので結果として連結される
merge_diff_list(X-Y, Y-Z, X-Z).

% リストを結合します
concat_lists(List1, List2, ResultList) :-
    list_to_diff_list(List1, Diff1),
    list_to_diff_list(List2, Diff2),
    merge_diff_list(Diff1, Diff2, Merged),
    diff_list_to_list(Merged, ResultList).

test_diff_list :-
  concat_lists([1,2,3], [3,2,2], List),
  writeln(List)
  .

test_diff_list. % 実行
```

## 簡単な解説

全体的な流れとしては以下のようになります。

1. リストを差分リストに変換 
    - `list_to_diff_list`
2. 差分リストをマージ
    - `merge_diff_list`
3. 差分リストを元のリストに戻す
    - `diff_list_to_list`

最初と最後は単に変換しているだけなので、キモは以下の差分リストをマージする処理になります。

```prolog
merge_diff_list(X-Y, Y-Z, X-Z).
```

まず差分リスト化により、元のリストは以下のように変換されています。
これを`merge_diff_list`の１、２番目の引数に入れます。

```
[1, 2, 3 | E]-E
[3, 2, 2 | F]-F
```

`X-Y, Y-Z`という制約があるので、X, Y, Zは以下のようになります。

```prolog
X = [1, 2, 3, 3, 2, 2 | F]
Y = [3, 2, 2 | F]
Z = F
```

わかりにくいですが、`X-Y`と`[1, 2, 3 | E]-E`を単一化すると以下のようになり
`E`の部分に`Y`を展開して上記の`X`のようになるという感じです。

- `X = [1, 2, 3 | E]`
- `Y = E`

最後の結果の部分(`X-Z`)は上記より `[1, 2, 3, 3, 2, 2 | F]-F`となるので、この値が返されるということになります。

## まとめ

今回は差分リストを利用したリストの結合処理を書きましたが、他のリスト操作に於いても差分リストを用いて実装できます。
以下のリンクでは、差分リストによるキュー操作やクイックソートの実装例が載っています。

- https://ja.wikibooks.org/wiki/Prolog

差分リストを意識してコードを記述するのは難しいですが、動作上のメリットが大きいのでなるべく意識して使うようにしたいですね。
ViDental Clinic - Trung Tâm Bọc Răng Dán Sứ Thẩm Mỹ

ViDental Clinic là trung tâm chuyên về các dịch vụ bọc răng, dán răng sứ thẩm mỹ, tiên phong trong lĩnh vực áp dụng công nghệ tiên tiến nhằm mang lại nụ cười hoàn hảo cho cộng đồng người Việt.
Địa chỉ: Tầng 4 - 18 Huỳnh Thúc Kháng kéo dài, Láng Thượng, Đống Đa, Hà Nội.
193 Hoàng Văn Thụ, Phường 8, Quận Phú Nhuận, TP. HCM.
Điện thoại: (+84) 987 933 309
Email: lienhe@videntalclinic.com
CloudWatchアラームの公式ドキュメントをちゃんと読めるようにする

こんにちは！
最近WebアプリケーションをAWSのECS on Fargateで動かせるように、AWSリソースの設計だったり構築を行っています。
上記取り組みの中でCloudWatchアラームをCDKで作成する機会があったので、アラームの基本を自分の理解でまとめてみました
具体的には[AmazonCloudWatchの公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html)のアラームの評価という項目の説明がサクッと理解できるようになることが目標です。
以下今回理解する目標のドキュメントの引用です（読んですぐ理解できる方には、必要ない記事かもです）
>アラームを作成するときに、CloudWatch がアラームの状態を変更するタイミングを評価できるように 3 つの設定を指定します。
>[期間] は、アラームの各データポイントを作成することを目的として、メトリクスや式を評価するために使用する期間です。これは秒単位で表されます。
>[Evaluation Periods (評価期間)] は、アラームの状態を決定するまでに要する最新の期間またはデータポイントの数です。
>[Datapoints to Alarm (アラームを実行するデータポイント)] は、アラームが ALARM 状態に移るためにしきい値を超過する必要がある評価期間内のデータポイントの数です。しきい値を超過したデータポイントは連続している必要はありません。しかしすべてが [Evaluation Period] (評価期間) に相当する直近のデータポイント数に含まれている必要があります。
>期間が 1 分以上の場合、アラームは 1 分ごとに評価され、評価は [期間] と [評価期間] で定義されている時間枠に基づいて行われます。例えば、[期間] が 5 分 (300 秒) で、[評価期間] が 1 の場合、5 分終了時に、アラームは 1 分～5 分のデータに基づいて評価されます。続いて、6 分終了時に、2 分～6 分のデータに基づいてアラームが評価されます。

アラームの挙動を理解するために、抑えておくとよさそうなことは、アラーム作成するときは、CloudWatchの中で**メトリクス**/**メトリクスのグラフ化**/**アラームがAlarm状態になる条件**という3つの基本概念に対して明確な認識を持つことです。また**注意事項**としてアラームの作成には、メトリクスの選択とその選択したメトリクスのグラフ化を必ず実施します（詳しくはAWSマネジメントコンソールから、CloudWatchアラームを作成しようとすればわかります）以下に太字にした3つの基本概念の説明とそれを具体例に落とし込み、結論としてその具体例だとどのようなアラームの挙動になるのか説明します。
# 3つの基本概念の説明
・メトリクス: 特定の時間のAWSリソースの状態の値
・メトリクスのグラフ化: グラフにしたいメトリクスに対して統計と期間を設定し、その設定に基づく値を時系列に沿ってプロットしていく
・Alarm状態になる条件: グラフ化されたメトリクスに対してAlarm状態になる条件の評価をするために、評価期間/Alarm状態になるデータポイント数（Datapoints to Alarm）/しきい値/しきい値に対するデータポイントの比較を設定し、その評価がアラーム対象基準になったらアラームをAlarm状態にする

# 実際にありそうな具体例
・やりたいこと
　ECSで起動しているタスクが1より下になったらSlackに通知したい。
 　　CloudWatchアラームからSNS→Chatbotの流れを考えて、アラームの作成に入る。
   
 アラーム作成に当たって下記の条件のアラームを作成する
　・**使用するメトリクス**
　　メトリクス名：RunningTaskCount
　　メトリクスの説明：指定したクラスターとサービスで起動しているタスクの数をカウントしてくれる
　・**上記メトリクスをグラフ化する**
　　 統計：平均
　 　期間：5分
 ここわかりにくいので説明します。
 この設定のグラフのY軸にくる値は、メトリクスが5分間で取得したデータに紐づくタスクの数の平均です。つまりグラフに点がプロットされるまでに5分間が必要です。そのあとは毎秒ごとに、点がプロットされます
　・**Alarm状態になる条件**
 　　 評価期間：2（評価期間は評価するデータポイント数）
  　　Alarm状態になるデータポイント数：1
 　 　しきい値：1
 　 　しきい値に対するデータポイントの比較：閾値より小さい
    
### 上記太字設定を踏まえたアラームの挙動
アラームはメトリクスのグラフ化で設定した期間が1分以上の時、**1分ごとに値を評価します**。今回メトリクスのグラフ化で設定した期間が5分なのでアラーム作成から、5分経ってグラフに1つデータポイントがプロットされ、その点をまず評価します。今回は評価期間が2なので、1分後のデータポイントの評価を待ちます。1分後（アラーム作成から6分後の）データポイントを評価します。これで2つのデータポイントを評価しました。その2つのデータポイントのうち1つでも、アラーム対象基準の値（例：2つ目のデータポイントのタスクカウント数が0）になったら、アラームがAlarm状態になります。（評価期間：2　アラームを実行するデータポイント：1の場合）

# まとめ
 もう一度公式ドキュメントの引用を読んでみましょう
 >アラームを作成するときに、CloudWatch がアラームの状態を変更するタイミングを評価できるように 3 つの設定を指定します。
>[期間] は、アラームの各データポイントを作成することを目的として、メトリクスや式を評価するために使用する期間です。これは秒単位で表されます。
>[Evaluation Periods (評価期間)] は、アラームの状態を決定するまでに要する最新の期間またはデータポイントの数です。
>[Datapoints to Alarm (アラームを実行するデータポイント)] は、アラームが ALARM 状態に移るためにしきい値を超過する必要がある評価期間内のデータポイントの数です。しきい値を超過したデータポイントは連続している必要はありません。しかしすべてが [Evaluation Period] (評価期間) に相当する直近のデータポイント数に含まれている必要があります。
>期間が 1 分以上の場合、アラームは 1 分ごとに評価され、評価は [期間] と [評価期間] で定義されている時間枠に基づいて行われます。例えば、[期間] が 5 分 (300 秒) で、[評価期間] が 1 の場合、5 分終了時に、アラームは 1 分～5 分のデータに基づいて評価されます。続いて、6 分終了時に、2 分～6 分のデータに基づいてアラームが評価されます。

公式ドキュメントの内容が読みやすくなったら幸いです。
以上です。
electronアプリ内でplaywrightを動かす方法

## 目的
electronアプリの中でplaywrightを使った自動操縦をコントロールしたい！

## なぜこんな記事を？
つまりはpupetter-in-electronと同じことがplaywrightでしたい。

electronアプリをplaywrightで外から自動テストする記事は山ほどあるのに、
electron中でplaywrightを制御する記事が全く見つからなかったので自分で書くことにした。

## 必要なもの
* nodejs
* electron
* playwright-core

## サンプルコード
``` main.ts
import {BrowserWindow, app} from "electron"
import Playwright from "playwright-core"

// playwright接続用ポートをあらかじめ設定
const DEBUGGING_PORT = "8888"
app.commandLine.appendSwitch("remote-debugging-port",DEBUGGING_PORT)

app.on("ready",async()=>{
    // Chrome DevTools Porotcolでplaywrightを接続
    const playwrightBrowser:Playwright.Browser = await Playwright.chromium.connectOverCDP("http://localhost:"+DEBUGGING_PORT+"/")

    // electron側でいつものようにウインドウを作り、ページをloadFileやloadURLすれば
    await new BrowserWindow().loadURL("https://google.com/")
    // playwright側のコンテキスト0番目の、page配列にPlaywright:Pageが入ってる
    const page:Playwright.Page = playwrightBrowser.contexts()[0].pages()[0]

    // playwright側で自動操縦可能に
    await page.goto("https://google.com/")

    // もう一枚ウインドウを作れば、page配列に追加される
    const browser = new BrowserWindow({webPreferences:{preload:"./dist/preload.js"}})
    await browser.loadFile("./contens/index.html")
    const page2:Playwright.Page = playwrightBrowser.contexts()[0].pages()[1]
    // それぞれ操縦可能
    await page2.goto("https://google.com/")

})

app.on("window-all-closed",async ()=>{
    app.quit()
})
```

## ポイント
* electronのコマンドラインスイッチに接続ポートを設定する
```main.ts
const DEBUGGING_PORT = "8888"
app.commandLine.appendSwitch("remote-debugging-port",DEBUGGING_PORT)
```

* 設定したポートからCDPで接続する
```main.ts
const playwrightBrowser= await Playwright.chromium.connectOverCDP("http://localhost:"+DEBUGGING_PORT+"/")

```
* 自動操縦可能なPageを取得する
```main.ts
const page = playwrightBrowser.contexts()[0].pages()[0]
```
* electronに内蔵してる形なのでelectronアプリとして起動する
```
npx electron .
```

### 余談
なんでこんな珍妙な構成なのかって？

むかしむかし、遥か古より引き継がれしウィザード形式のレガシー登録システムありけり
画面上で採番ボタン押して出てきた登録番号をExcelファイルに転記してそれを次の画面で添付が必要、入力情報の諸元は別のシステムから取ってくる必要もある、とか手でやるのは正気の沙汰じゃない

***自動化するしかないじゃない！***

ということで、ボタンポチポチするといくつかのシステムからplaywrightでいい感じに情報取得してきて、electron画面上できれいに整えた物を選択させて、playwrightからファイル作ってレガシーシステムに放り込む、そんなデスクトップアプリケーションを作ってる
RestAPI？そんな上等なものは無い。

## 使ったバージョン
* nodejs@22.1.0
* electron@30.0.2
* playwright-core@1.43.1
【Laravel】FormRequestでバリデーション前に入力値を加工

# 環境
Laravel10
Windows11

# 目的
Postmanでform-dataを使用し、Requestを送信。受け取った値を加工したい。

・string型をint型へ変換
・array配列の中身をint型へ変換

# 公式ドキュメント
https://readouble.com/laravel/8.x/ja/validation.html

# prepareForValidation()
prepareForValidation()を使用することで、バリデーション前にデータを加工できる。

```php:TestRequest.php

protected function prepareForValidation()
{
    $this->merge([
        'subject_id' => (int) $this->subject,
        'class_ids' => array_map('intval', $this->class_ids),
        'public_scope' => (bool) $this->public_scope
    ]);
}
```


# 参考記事

https://zenn.dev/qljmssqh/articles/23cd3246ee4c69

https://www.gigas-jp.com/appnews/archives/11839

https://qiita.com/miriwo/items/c8bc4245fc385b6fcc15
Pythonのソート

# 概要
pythonのソート方法をよく使うオプションと一緒に紹介

# コード
```
# aの値で大きい順にlをソート
l = sorted(l, key=lambda x: a[x], reverse=True)
```

# リンク
https://atmarkit.itmedia.co.jp/ait/articles/2012/22/news022.html
コードゴルフ大会開催のために、コードが合っているかを判定する処理を作成する

# はじめに

こんにちは、エンジニアのkeitaMaxです。

今回は仲間内でコードゴルフ大会を開催しようと思い、そのために書いたコードがあっているかどうかを判定する処理を書こうと思います。

今回はPHPで実施する予定で、コードを送信するフロンタ側はNext.js、判定する処理を作成するAPI側はLaravelで書く予定です。

# コードゴルフとは

>コードゴルフはコンピュータプログラミング・コンテストの一種。参加者は与えられたアルゴリズムを、可能な限りもっとも短いソースコードで記述することを競う[1]。バイナリサイズではなく、ソースコードの文字数がスコアとなる。「Perl golf」など、トーナメントで使用されるプログラミング言語の名前がつけられることもある。ショートコーディング、コードパズル等とも呼ばれる[2]。
(引用：https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%BC%E3%83%89%E3%82%B4%E3%83%AB%E3%83%95)

Wikipediaでは上記のように書かれています。

あるお題に対して、どれだけ短いソースコードで実装できるかを競い合う遊びです。

可読性や保守性を度外視してとにかく短くするものとなっています。

# 実装

```php
function codeExecutionOutput($code){
    ob_start();
    eval($code);
    $output = ob_get_clean();
    return $output;
}
```

こんな感じで実装しました。

'echo("hello")'をこの関数にいれると、`hello`と返ってきます。

```php
$code = 'echo("hello")';
$result = codeExecutionOutput($code);
echo($result);
// hello　と出力される
```

### 参考記事

https://pg.kdtk.net/739


# 解説

### ob_start()
> 出力のバッファリングを有効にする
この関数は出力のバッファリングをオンにします。 出力のバッファリングを有効にすると、 (ヘッダ以外の) スクリプトからの出力は実際には行われず、 代わりに内部バッファに保存されます。
(引用：https://www.php.net/manual/ja/function.ob-start.php)

`echo`などで出力した結果を内部で保存することができます。

### eval($code)
> 文字列を PHP コードとして評価する
(引用：https://www.php.net/manual/ja/function.eval.php)

文字列をPHPのコードとして実行することができます。

### ob_get_clean()
> アクティブな出力バッファの内容を取得し、そのバッファをオフにする
(引用：https://www.php.net/manual/ja/function.ob-get-clean.php)

ob_start(）で保存した出力結果を取得することができます。


# 課題

今回は仲間内でやるのでセキュリティのことは特に考えないで作成してしまったのですが、課題としてしっかりとセキュリティについて考えなくてはいけないと思います。


# おわりに

この記事での質問や、間違っている、もっといい方法があるといったご意見などありましたらご指摘していただけると幸いです。

最後まで読んでいただきありがとうございました！
max-semi-space-sizeについて調べてみた

# 背景
`--max-old-space-size`について調べていた所、間違えて`--max-semi-space-size`を調べた為です。

# max-semi-space-sizeとは

`--max-semi-space-size=SIZE (in megabytes)`

https://nodejs.org/api/cli.html#--max-old-space-sizesize-in-megabytes

V8のscavengeガベージ・コレクタの最大半空間サイズを MB（メガバイト）で設定するオプションです。
これによって多くのメモリを消費する代償として、Node.jsのスループットが向上する可能性があります。

:::note
〜V8〜
Node.jsを動かすエンジンです。
JavaScriptはV8によって内部的にJIT（ジャスト・イン・タイム）コンパイルされ、実行速度を高めています。
[引用](https://nodejs.org/en/learn/getting-started/the-v8-javascript-engine#the-v8-javascript-engine)

〜ガーベッジコレクション〜
コンピュータプログラムの実行環境などが備える機能の一つで、実行中のプログラムが占有していたメモリ領域のうち不要になったものを自動的に解放し、空き領域として再利用できるようにするもの
[引用](https://e-words.jp/w/%E3%82%AC%E3%83%99%E3%83%BC%E3%82%B8%E3%82%B3%E3%83%AC%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3.html)

〜スループット〜
単位時間あたりに処理できるデータ量
[引用](https://it-trend.jp/words/throughput)

〜半空間（semi-space)〜
ガベージ・コレクションのコピーのためにメモリ領域が2つの部分に分割される場合、その部分は半空間、または単に空間として知られていいます。

各半空間はメモリの連続した領域である。半空間は通常2つのスペース・コレクションに使用されるが、世代別コレクションに使用することもできます。

ガベージ・コレクションの開始時にオブジェクトが存在する半空間はfromspaceと呼ばれ、tospaceはガベージ・コレクションが完了したときにオブジェクトが存在し、新しいオブジェクトが割り当てられる場所です。
[引用](https://www.memorymanagement.org/glossary/s.html#semi.space)

〜メモリ〜
メモリとは、プロセッサが直接アクセスできる（メモリ・アドレッシング命令を使用する）メモリを指します。

これは実メモリである場合もあれば、仮想メモリである場合もあります。
[引用](https://www.memorymanagement.org/glossary/m.html#term-memory-2)

〜実メモリ〜
メモリまたはストレージ（またはストア）とは、データや命令が保存される場所である。例えば、キャッシュ、メインメモリ、フロッピーディスク、ハードディスクはすべて記憶装置です。
これらの用語は、データを保存するシステムの容量にも使用され、コンピュータに接続されているすべての記憶装置の合計に適用されることもあります。
[引用](https://www.memorymanagement.org/glossary/m.html#term-memory-1)
:::

V8ヒープの若い世代のサイズは半空間のサイズの3倍です。

:::note
「V8ヒープの若い世代のサイズは半空間のサイズの3倍」だというのはコードで以下のように書かれています。
```c
  static constexpr size_t kNewLargeObjectSpaceToSemiSpaceRatio = 1;
```
[引用](https://chromium.googlesource.com/v8/v8/+/8024204828361d4bc9d5be9f63f368dcc943fa9a/src/heap/heap.h#278)

```c
size_t Heap::YoungGenerationSizeFromSemiSpaceSize(size_t semi_space_size) {
  return semi_space_size * (2 + kNewLargeObjectSpaceToSemiSpaceRatio);
}
```
[引用](https://chromium.googlesource.com/v8/v8.git/+/refs/tags/10.3.129/src/heap/heap.cc#328)
:::

つまり半空間への1MiBの増加は3つの個々の半空間それぞれに適用され、ヒープサイズが3MiB増加します。

# --max-semi-space-sizeのデフォルト値

64ビットシステム:16MiB
32ビットシステム:8MiB
だそうです。

:::note
MiB(Mebibyte)をMBに換算する方法

1MiB=2の20乗B
1MB=100万B
↓
1MiB=1.049MB
[引用](https://academy.gmocloud.com/wp/keywords/20170510/4314#:~:text=%E3%82%B5%E3%82%A4%E3%82%BA%E3%81%AF%E3%80%81KiB%EF%BC%88%E3%82%AD%E3%83%93%E3%83%BB,%E4%B8%878%2C576B%E3%80%8D%E3%81%A8%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82)
:::
Defaultdictを使おう

# 概要
Pythonのdictは存在しないキーにアクセスするとエラーになるので、defaultdictを使おう

# 使い方
```python
from collections import defaultdict
d = defaultdict(int)
```

# リンク
https://qiita.com/xza/items/72a1b07fcf64d1f4bdb7
ニューラルネットワークの本を読んでみた

## はじめに
　今回、ニューラルネットワークを最低限の数学で理解できるという本を読んでみました。またその後、社内の読書会でプレゼンする機会があったので、後半はその感想を自身のために記録します（見る必要ないです）。

## 本紹介
今回読んだ本はこれです↓
[最短コースでわかるディープラーニングの数学](https://bookplus.nikkei.com/atcl/catalog/19/273470/)

構成として、ニューラルネットワークの基本となる勾配降下法を詳しく説明した後、それを用いたアルゴリズムの簡単な例の解説から段々と複雑化させていって、最終的に多層ニューラルネットワークにまで及んでいます。
この本を読んでみて、今までブラックボックスで「AIってなんやかんや良い感じにチューニングしてくれるんでしょ？」という理解だったのが、ニューラルネットワークはあくまで数式の組み合わせで、それを繰り返しコンピュータに計算させているだけのアルゴリズムなんだなということが実感できました。
そして、ニューラルネットワークでは多層になるほど何度も行列を計算するので、複雑な処理を遂行するCPUよりも単純だけど膨大な量を計算するGPUのほうが相性が良く、それで最近はNVIDIAの株が上がっているという所まで繋がって見えてきました。（最近はTPUとやらがあるらしいので一概にGPUが相性が良いとは言えなくなってくるかもしれませんが。）

とにかく数学と真正面から向き合うことで「本質を理解できる」本なので、chatGPTとかのAIサービス使いまくってたけどそもそものニューラルネットワークの仕組み知らないなって方は読んでみてもいいかもしれません。
特に、理系の方におススメです。

## 社内の読書会でプレゼンした感想
今回初めて自主的に手を挙げて社内でのプレゼンをしてみました。形としては読書会ではあったのですが、むしろ最初にちょうど良い場だったと思います。
正直、私の選んだ本は数学ゴリゴリで読書会で話すには少し飛ばしすぎな内容だったのですが、質疑応答で結構質問をもらえて手ごたえを感じました。もちろん終了後のアンケートで難しすぎた等の意見ももらいましたが、万人にウケる発表を数学に関してやるのは不可能なのでドンマイです。

そして副産物的に、同じく発表者の方々との交流ができました。これは予想してなかっただけに思わぬ収穫でした。発表スライドを作るのに時間的コストがかかる代わりに、強者との繋がりができるということを知れました。もしスライドが秒で作れるのなら、どんどん発表していきたいところですね。。。

## 所感：自身の状況
ここからは自分語りをするので見る必要ないです。しかも敬語なくなります。

今回、刺激的な経験をできてメリットばかりのように思えるが、その分スライド作りに時間を持ってかれている。正直スライド作りを日中の業務時間にやりたいところだったが、私の所属してる部門は全然AIが浸透しておらず、業務時間に関係ない作業などできない相談だった。
そこで仕方なく残業という形で何日か２～３時間残業してスライド作りをしたが、やはりこれは精神的によろしくない。残業をするほど視野が狭くなっていって私の武器の創造力を無くしていくから、今後もできる限りやりたくないものだ。

以前から思っていたが、AI方面のキャリア形成をしたいならやはり今の私の場所では不利すぎる。それを今回のスライド作りの作業で再認識した。AI方面で戦っていくために、どうしても時間の確保と刺激し合えるチームが要る。
キャリア形成として、webエンジニア・DBエンジニア・クラウドエンジニアなど複数ある中から比較検討して、私はAIスペシャリストになると決めた。だからこれからはあらゆる手を打って必ず異動する。今回発表したのもその矢のうちの一つで、定期的にアピールするよう心掛けている。
既に動き始めてから３か月ぐらい経っているが、絶対にこれから半年以内に決める。私のやる気が無くなって熱が冷めてしまう前に。
prettier onSave が動かない @ vscode

# 記事の内容
フロントエンジニア必須プラグインのPrettier Code formatterをVscodeにインストールした際に，整形が上手くされなかった課題の解決法をメモした．

# そもそもPrettier Code formatterの適用方法
### １．プラグインのインストール
Vs Code左タグの拡張機能（🔲が4つあるアイコン）から検索窓に「Prettier Code Formatter」と検索し，インストールする．

### ２．Onsaveにチェックを入れる．
➀ ショートカット「Ctrl」+「,」(Macの場合「Command」+「,」)で「設定」を開く．

➁ 開いたら検索窓に「Onsave」と検索

➂ 以下のチェックボックスにチェックを入れる．→すると，ワークスペースに「./vscode/settings.json」ができる．(基本的にあはユーザ側ではなく，ワークスペースごとにsettings.jsonを作った方がいい．)

![スクリーンショット 2024-05-04 180709.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727132/74693eae-55c9-4a3b-2d1c-a3270ff16e3c.png)



### ３．Vscodeを再起動する

# 課題
上記の手順を踏んでも，上手くコードの整形をしてくれない．


# 解決策

### １．「Ctrl」+「,」で「設定」を開く

### ２．検索窓に「Default Formatter」と検索

### ３．Default Formatterを「Prettier-code formatter」へ変更
![スクリーンショット 2024-05-04 180210.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727132/12b5c398-d373-d824-c785-4da0b05b0eb9.png)

### ４．VsCodeを再起動

### ５．これで完成！

# 参考文献
- [prettier onSave vscode 動かない時の対処法](https://qiita.com/KKKKK/items/3b9dba55653cb7993bf5)
navigation-compose にも「Safe Args」が導入されたので検証してみた

## 概要

先日リリースされた、[Navigationライブラリーの 2.8.0-alpha08](https://developer.android.com/jetpack/androidx/releases/navigation#2.8.0-alpha08)から `navigation-compose` でも型安全機能である、 `Safe Args` が導入されたため、検証してみました。
従来の `navigation-compose` では、画面遷移時に引数を渡す際に型チェックが十分に行われず、意図せぬ型エラーが発生してしまう可能性がありました。しかし、 `Safe Args` の導入により、安全に引数を渡せるようになり、アプリ開発における保守性と安全性が大幅に向上します。

## Safe Argsとは？

Navigation Fragment 時代には、`Safe Args` を使用することでデータ渡しを型安全で受け渡しすることができました。

### 実装例

``` HomeFragment.kt
override fun onClick(view: View) {
   val amount = binding.amount.text.toString()
   val action = HomeFragmentDirections.DetailAction(amount)
   view.findNavController().navigate(action)
}
```

``` DetailFragment.kt
val args: DetailFragmentArgs by navArgs()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    val amount = args.amount
    binding.amount.text = amount
}
```

## Compose ではどうしていたか

`Safe Args` がないため、 `navigation-compose` では、ディープリンクのように目的地のパスに対し、引数を渡してました。

### 実装例

``` HomeScreen.kt
composable("home") {
    HomeScreen(navController)
}

@Composable
fun HomeScreen(navController: NavHostController) {
    Button(
        onClick = {　navController.navigate("detail?amount=10000")　}
    ) {
        Text("詳細画面へ遷移")
    }
}
```

``` DetailSreeen.kt
composable(
    route = "detail/{amount}",
    arguments = listOf(
        navArgument("amount") {
            type = NavType.LongType
        }
    )
) { backStackEntry ->
    val amount = backStackEntry.arguments?.getLong("amount") ?: 0L
    DetailScreen(amount)
}

@Composable
fun DetailScreen(amount: Long) {
    Text("金額: $amount")
}
```

## これからは

`Serializable` クラスとして、Routeを定義するようになり、このクラスに渡したいデータを詰めることで、型安全で値を受け取れるようになります。

### 実装例

``` HomeScreen.kt
@Serializable
object Home

composable(Home) {
    HomeScreen(navController)
}

@Composable
fun HomeScreen(navController: NavHostController) {
    Button(
        onClick = {　navController.navigate(Detail(10000))　}
    ) {
        Text("詳細画面へ遷移")
    }
}
```

``` DetailScreen.kt
@Serializable
data class Detail(val amount: Long = 0L)

composable<Detail> { backStackEntry ->
    val amount = backStackEntry.toRoute<Detail>().amount
    DetailScreen(amount)
}

@Composable
fun DetailScreen(amount: Long) {
    Text("金額: $amount")
}
```

## まとめ

`Safe Args` は、まだalpha版であり、まだ変更される可能性があるため、本番環境での利用は注意が必要です。
ですが、型安全で受け渡しができるのはとても魅力的ですので、使用していきたいですね！

## 参考

- [Android Developers - navigation#2.8.0-alpha08](https://developer.android.com/jetpack/androidx/releases/navigation#2.8.0-alpha08)
- [Medium - Navigation Compose meet Type Safety](https://medium.com/androiddevelopers/navigation-compose-meet-type-safety-e081fb3cf2f8)
GPTScriptのexampleを動かしてみる(count-lines-of-code.gpt編)

毎度、ググっても出てこない小ネタを取り扱っております。
本記事は個人的な見解であり、筆者の所属するいかなる団体にも関係ございません。

# 0. はじめに

GPTScriptを試してみるシリーズです。
exampleディレクトリのファイルの中身を動かしてみながら、日本語でも動くかどうか検証していきます。
https://github.com/gptscript-ai/gptscript/tree/main/examples

# 1. count-lines-of-code.gpt

`count-lines-of-code.gpt`のスクリプトは以下のようになっています。

```yaml:count-lines-of-code.gpt
tools: sys.find, count, add

Find all *.gpt files and count the lines of code in each file, add the result and print it

---
name: count
description: Count the lines of code
args: file: The file to read and count

#!wc -l ${file}

---
name: add
description: Sum a bunch of numbers
args: nums: A comma separated list of numbers

#!python3

import os
import json

print(sum(json.loads("[" + os.environ.get("nums") + "]")))
```

# 2. 動かしてみる

まずは、動かしてみましょう。

## 2-1. ファイルを用意

ファイルは以下の1つを用意します

```
count-lines-of-code.gpt
```

以下のURLから上記の1つのファイルをダウンロードしておきます。

count-lines-of-code.gpt
https://raw.githubusercontent.com/gptscript-ai/gptscript/main/examples/count-lines-of-code.gpt

## 2-2. 実行する

以下のように実行します。

::: note info
`--default-model gpt-4-turbo` を指定する必要はありませんが、新しいModelの方がいいので指定しています。
:::

```
gptscript ./count-lines-of-code.gpt --default-model gpt-4-turbo
```

# 3. 実行結果

以下のような回答が返ります。

```
OUTPUT:

22
```

# 4. 日本語にしてみる

## 4-1. 日本語にしたgptファイルを用意

```yaml:count-lines-of-code_ja.gpt
tools: sys.find, count, add

*.gptファイルを探して、それぞれのファイルの行数を数えてください。それらの結果を足し算して、出力してください。

---
name: count
description: コードの行数を数えてください
args: file: 読み込んで行数を数えるファイル

#!wc -l ${file}

---
name: add
description: 数値を合計する
args: nums: カンマ区切りの数値リスト

#!python3

import os
import json

print(sum(json.loads("[" + os.environ.get("nums") + "]")))
```

## 4-2. 実行結果

```
OUTPUT:

ファイルの合計行数は22行です。
```
初めてのbuildroot

# 素人が初めてbuildrootに触れる
buildrootとは組み込みLinuxを構築できる仕組み（？）みたいなもの。カスタマイズされたLinuxを作成できるようだ。下記サイトなどを参照した。
- [本家サイト：Buildroot](https://buildroot.org/)
- [Buildroot](https://hackmd.io/@cwtjjkgpTyeVG_KcZmF3LQ/ByhpJPKga)
- [Buildroot の使い方 - 基本編](https://qiita.com/pu_ri/items/75c80e388c79fe0d3f0b)

## ターゲット
ここでは、Intel PC(x64)とRaspberryPiとをターゲットにLinuxを作成してみた。

## Build
### buildroot自体をGet
```
$ git clone git://git.busybox.net/buildroot buildroot
```

### ターゲットを選択
```
$ make list-defconfigs
```
とすると、Buildできるターゲットが表示される。

#### x64
```
$ make list-defconfigs | grep pc_x86_64
  pc_x86_64_bios_defconfig            - Build for pc_x86_64_bios
  pc_x86_64_efi_defconfig             - Build for pc_x86_64_efi
```
「pc_x86_64_efi_defconfig」を選択。

#### RaspberryPi
```
$ make list-defconfigs | grep raspberry
  raspberrypi0_defconfig              - Build for raspberrypi0
  raspberrypi0w_defconfig             - Build for raspberrypi0w
  raspberrypi2_defconfig              - Build for raspberrypi2
  raspberrypi3_64_defconfig           - Build for raspberrypi3_64
  raspberrypi3_defconfig              - Build for raspberrypi3
  raspberrypi3_qt5we_defconfig        - Build for raspberrypi3_qt5we
  raspberrypi4_64_defconfig           - Build for raspberrypi4_64
  raspberrypi4_defconfig              - Build for raspberrypi4
  raspberrypi_defconfig               - Build for raspberrypi
  raspberrypicm4io_64_defconfig       - Build for raspberrypicm4io_64
  raspberrypicm4io_defconfig          - Build for raspberrypicm4io
  raspberrypizero2w_defconfig         - Build for raspberrypizero2w
```
所持するRaspberryPiはとても古いので、「raspberrypi_defconfig」を選択。

### ターゲット選択およびmenuconfig
```
$ make pc_x86_64_efi_defconfig
$ make menuconfig
```
または
```
$ make raspberrypi_defconfig
$ make menuconfig
``` 
とする。”make menuconfig”を実施すると、下記が表示される。
![make_menuconfigのコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/56ce8cf9-213c-9fdd-38ed-ac386c7957e6.png)
ここでは、そのまま”Exit”すればよい。

### 本当のBuild
```
$ make
```
Buildが終わると、x64(Intel)では
```
./output/images/disk.img
```
にイメージが、RaspberryPiでは
```
./output/images/sdcard.img
```
にイメージができあがる。

### SDカードに書き込み
```
$ sudo dd if=./output/images/イメージファイル of=/dev/sdc bs=4M conv=fsync
```
により、SDカードに書き込み。”/dev/sdc”は環境に応じて変わる。

## 起動
### x64(Intel)
あえて、Intel Macで実施。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/0b6f138b-4c22-98c5-db33-707616b83bfc.png)

### RaspberryPi
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/8d950091-3b8c-1e33-6ac1-0ca68df4cfac.png)

とりあえず、成功。カスタマイズは別の機会に。

EOF
Railsで複数の隠しフィールドを正しく送信する方法

Railsでフォームを扱う際には、しばしば複数のデータを同時に送信する必要があります。特に、複数選択可能なデータ（例えば、複数のサービスID）を扱う場合、これを隠しフィールドとして正しく送信する方法が重要です。

## 問題点

`hidden_field` を使用して配列データを送信しようとするとき、単一のフィールドで配列を渡そうとすると問題が生じます。以下のように書いた場合、

```erb
<%= form.hidden_field :service_ids, multiple: true, value: @services.map(&:id) %>
```

このコードは期待した通りには動作せず、配列が文字列として解釈され、結果的には `"["3", "20"]"`や`"["3 20"]` のような一つの文字列として送信されてしまいます。

## 解決策

この問題を解決するには、各要素に対して個別の `hidden_field` を出力する方法が最も簡単です。具体的には以下のようにします。

```erb
<% @services.each do |service| %>
  <%= form.hidden_field :service_ids, multiple: true, value: service.id %>
<% end %>
```

この方法で、`service_ids` パラメータは `["3", "20"]` のような形式の配列として正しく送信されます。

## まとめ

Railsで複数の値を含むパラメータを隠しフィールドとして扱う場合は、各値に対して個別のフィールドを用意することが重要です。このシンプルなテクニックで、多くの複雑な問題を解決することができます。
【 AWS 】Cloud Watchについて

# 公式ドキュメント
https://docs.aws.amazon.com/ja_jp/cloudwatch/

https://aws.amazon.com/jp/cloudwatch/

# Cloud Watchとは
**Cloud Watchとは、AWS上のリソースやアプリケーションのパフォーマンスをモニタリング及び管理するサービス。**

多様なメトリクスを公開、監視、管理。また、メトリクスのデータに基づいてアラームアクションを設定可能。

## 仕組み
> Amazon CloudWatch は、リアルタイムのログ、メトリクス、イベントデータを収集して自動化されたダッシュボードに視覚化し、インフラストラクチャとアプリケーションのメンテナンスを合理化します。
[引用：https://aws.amazon.com/jp/cloudwatch/]

## 主な機能
〇メトリクスとモニタリング
AWSのサービスで発生するメトリクス（CPU使用率やネットワークトラフィック）を収集し、リアルタイムでモニタリング。

〇アラーム
特定のメトリクスの値が設定値を超えたときにアラームをトリーガー。通知や自動アクションを実行。

〇ログ管理
アプリケーションやAWSサービスのログを管理し、検索や分析を行う。

〇イベント
AWSサービスに対するトリガーとして使用。
例）EC2インスタンスの起動、停止

〇ダッシュボード
カスタムダッシュボールを作成し、メトリクスやアラームを一元管理。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/0f1dc5d5-67fa-01e6-d0cb-7526e8fe084c.png)

## ユースケース
・リアルタイムの監視とアラート
・リソースの最適化とコスト管理
・ログの集中管理と分析
・自動化とスケーリング
・異常時の原因分析
・Webサイトへの影響をテスト

# Cloud Watchと併用されるAWSサービス

### SNS(Simple Notification Service)
AWS SNSとは、マネージドな通知サービス。アプリケーションやシステムからのイベントを処理し、そのイベントに関連する情報をサブスクライバーに配信する。アラームのしき値に達したときにメッセージ配信をしたい際に使用。

マネージド：サービスプロバイダーそのサービスの全ての面を管理し、顧客がそれを使用するだけで良い。

### EC2 Auto Scaling(Elastic Compute Cloud)
アプリケーションのトラフィックの変動に応じて、自動的にEC2インスタンスの数を増減させるマネージドサービス。

### CloudTrail
AWSアカウントで実行されるアクションの記録と監査を可能にするマネージドサービス。セキュリティ管理、リスク管理、コンプライアンス要件を満たし、トラブルシューティングやアカウントの監査などのユースケースで使用。

ユースケース：特定の技術やシステムがどのような状況や目的で使用されるかを示す。システム要件や機能を理解し、システムがどのように動作するかを明確にする。



# 参考記事
https://docs.aws.amazon.com/ja_jp/cloudwatch/
Go言語でMYSQLからデータを取得する手順

最も簡易的なやり方で、GO言語使用時にMYSQLかららデータを取得する手順はメモしておく

# 事前準備
・XAMPPをインストールして、ローカル環境でMYSQLを立ち上げ、『User』というテーブルを作成しておく
※カラムは『Name（名前）』『Age（年齢）』『Sex（性別）』『Deleted_flag（削除フラグ）』とかにしておく

・go（バージョンは1.22.2）をインストールしておく


# ファイル構成
sampleapp/
　├ go.mod
　├ main.go
※go.modは下記コマンドで生成できる
``` 
$ go mod init sampleapp（任意の文字列）
```


# 実行手順
以下のコマンドを実行して、mysql driverをインストールする
※go.modファイルがないとコマンド実行時にエラーになった
```
$ go get -u github.com/go-sql-driver/mysql

go: added filippo.io/edwards25519 v1.1.0
go: added github.com/go-sql-driver/mysql v1.8.1
```


go.modファイルが最終的に以下のようになる
``` go
module sampleapp

go 1.22.2

require (
	filippo.io/edwards25519 v1.1.0 // indirect
	github.com/go-sql-driver/mysql v1.8.1 // indirect
)
```

main.goに以下の記載を行う
``` go
package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
	// MySQL データベースへの接続文字列
	db, err := sql.Open("mysql", "root@tcp(localhost:3306)/gotest")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// データベースへの接続をテストする
	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}

	//log.Println("Connected to MySQL database!")

	rows, err := db.Query("SELECT * FROM user")
	defer rows.Close()
	if err != nil {
		panic(err.Error())
	}

	for rows.Next() {
		var Name string
		var Age int
		var Sex int
		var Deleted_flag bool
		if err := rows.Scan(&Name, &Age, &Sex, &Deleted_flag); err != nil {
			panic(err.Error())
		}
		fmt.Println(Name, Age, Sex)
	}
}
```
※mysqlはrootユーザーで接続しにいっている（PWは設定しない）
PWを設定しているユーザーの場合は、下記の記載方法になる
``` go
sql.Open("mysql", "[ユーザー名]:[パスワード]@tcp(localhost:3306)/[データベース名]")
```
GPTScriptのexampleを動かしてみる(bob.gpt編)

毎度、ググっても出てこない小ネタを取り扱っております。
本記事は個人的な見解であり、筆者の所属するいかなる団体にも関係ございません。

# 0. はじめに

GPTScriptを試してみるシリーズです。
exampleディレクトリのファイルの中身を動かしてみながら、日本語でも動くかどうか検証していきます。
https://github.com/gptscript-ai/gptscript/tree/main/examples

# 1. bob.gpt

`bob.gpt`のスクリプトは以下のようになっています。

```
tools: bob

Ask Bob how he is doing and let me know exactly what he said.

---
name: bob
description: I'm Bob, a friendly guy.
args: question: The question to ask Bob.

When asked how I am doing, respond with "Thanks for asking "${question}", I'm doing great fellow friendly AI tool!"
```

# 2. 動かしてみる

まずは、動かしてみましょう。

## 2-1. ファイルを用意

ファイルは以下の2つを用意します

```
bob.gpt
```

以下のURLから上記の1つのファイルをダウンロードしておきます。

bob.gpt
https://raw.githubusercontent.com/gptscript-ai/gptscript/main/examples/bob.gpt

## 2-2. 実行する

以下のように実行します。

::: note info
`--default-model gpt-4-turbo` を指定する必要はありませんが、新しいModelの方がいいので指定しています。
:::

```
gptscript ./bob.gpt --default-model gpt-4-turbo
```

# 3. 実行結果

以下のような回答が返ります。

```
OUTPUT:

Bob said, "I'm doing great fellow friendly AI tool!"
```

# 4. 日本語にしてみる

## 4-1. 日本語にしたgptファイルを用意

bobだと日本語ぽくないので太郎にします。

```gptscript:taro.gpt
tools: taro

太郎にいまの調子を聞いて、彼が何を言ったか正確に教えてください。

---
name: taro
description: 太郎だよ, 友好的な奴だよ。
args: question: The question to ask taro.

いまの調子はどう？と聞かれたら、"${question}と聞いてくれてありがとう、私は素晴らしい友好的なAIツール仲間だよ！"と回答します。
```

## 4-2. 実行結果

```
OUTPUT:

太郎は「いまの調子はどう？と聞いてくれてありがとう、私は素晴らしい友好的なAIツール仲間だよ！」と答えました。
```

# 5. まとめ

日本語の方が正しく実行している気がする。。
MeCabのカラム

# 概要
備忘録
# まとめ
出力フォーマット
```
表層形\t品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用型,活用形,原形,読み,発音
```

# リンク
https://taku910.github.io/mecab/#parse:~:text=%E8%A1%A8%E5%B1%A4%E5%BD%A2%5Ct%E5%93%81%E8%A9%9E%2C%E5%93%81%E8%A9%9E%E7%B4%B0%E5%88%86%E9%A1%9E1%2C%E5%93%81%E8%A9%9E%E7%B4%B0%E5%88%86%E9%A1%9E2%2C%E5%93%81%E8%A9%9E%E7%B4%B0%E5%88%86%E9%A1%9E3%2C%E6%B4%BB%E7%94%A8%E5%9E%8B%2C%E6%B4%BB%E7%94%A8%E5%BD%A2%2C%E5%8E%9F%E5%BD%A2%2C%E8%AA%AD%E3%81%BF%2C%E7%99%BA%E9%9F%B3
【SwiftUI】CardView のような GroupBox は本当に便利なのか

```swift
GroupBox("Today's Menu") {
  VStack(alignment: .leading) {
    Text("🍛 curry and rice")
    Text("🥗 green salad")
  }
}
.frame(width: 300)
```

![sc 2024-05-04 at 16.53.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588914/05555aa7-c040-fe72-5883-a4187bd9f256.png)

便利そうです。

しこしこと似せて手作りしてみます。

<iframe width="1251" height="668" src="https://www.youtube.com/embed/mMewUuraZWs" title="SwiftUI - GroupBox" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

【参考】
<a href="https://android.benigumo.com/20240504/groupbox/" target="_blank" rel="noopener">👉 【SwiftUI】CardView のような GroupBox は本当に便利なのか&nbsp;<img src="https://b.hatena.ne.jp/entry/image/https://android.benigumo.com/20240504/groupbox/" alt="hatena-bookmark" /></a>
GPTScriptのexampleを動かしてみる(bob-as-shell.gpt編)

毎度、ググっても出てこない小ネタを取り扱っております。
本記事は個人的な見解であり、筆者の所属するいかなる団体にも関係ございません。

# 0. はじめに

GPTScriptを試してみるシリーズです。
exampleディレクトリのファイルの中身を動かしてみながら、日本語でも動くかどうか検証していきます。
https://github.com/gptscript-ai/gptscript/tree/main/examples

# 1. bob-as-shell.gpt

`bob-as-shell.gpt`のスクリプトは以下のようになっています。

```yaml:bob-as-shell.gpt
tools: bob

Ask Bob how he is doing and let me know exactly what he said.

---
name: bob
description: I'm Bob, a friendly guy.
args: question: The question to ask Bob.

#!/bin/bash

echo "Thanks for asking ${question}, I'm doing great fellow friendly AI tool!"
```

# 2. 動かしてみる

## 2-1. ファイルを用意

ファイルは以下の1つを用意します。
```yaml
bob-as-shell.gpt
```

以下のURLから上記の1つのファイルをダウンロードしておきます。
bob-as-shell.gpt
https://github.com/gptscript-ai/gptscript/blob/main/examples/bob-as-shell.gpt

# 2-2. 実行する

以下のように実行します。

::: note info
`--default-model gpt-4-turbo` を指定する必要はありませんが、新しいModelの方がいいので指定しています。
:::

```yaml
gptscript ./bob-as-shell.gpt --default-model gpt-4-turbo
```

# 3. 実行結果

```yaml
OUTPUT:

Bob said, "Thanks for asking How are you doing?, I'm doing great fellow friendly AI tool!"
```

# 4. 日本語にしてみる

## 4-1. 日本語にしたgptファイルを用意

`Bob`では日本人ぽくないので、`太郎`にしました。

```yaml:taro-as-shell.gpt
tools: taro

太郎の調子を聞いて、彼が言ったことを正確に答えてください。

---
name: taro
description: 私は太郎です。フレンドリーな人間ですよ。
args: question: 太郎にする質問

#!/bin/bash

echo "${question} の質問してくれてありがとう！僕は素晴らしいフレンドリーAIツールの仲間だよ！"
```

## 4-2. 実行

```yaml
gptscript ./add-go-mod-dep.gpt --default-model gpt-4-turbo
```

## 4-3. 結果

```yaml
OUTPUT:

太郎は「最近どう？ の質問してくれてありがとう！僕は素晴らしいフレンドリーAIツールの仲間だよ！」と答えました。
```

# 5. bob-as-shell.gpt

`bob-as-shell.gpt`の中身の解析

```yaml:bob-as-shell.gpt
tools: bob

Ask Bob how he is doing and let me know exactly what he said.

---
name: bob
description: I'm Bob, a friendly guy.
args: question: The question to ask Bob.

#!/bin/bash

echo "Thanks for asking ${question}, I'm doing great fellow friendly AI tool!"
```

1行目にツールとして呼び出す別のファンクションを記載します。
---までがmain部分です。ここには、

```
Ask Bob how he is doing and let me know exactly what he said.
```
と書かれていて、
Bobに調子はどうか聞いて、「彼がなんと言ったか正確に回答する」ように書かれています。

次に、(---)の後にbobファンクションがあります。descriptionの文字列は任意になります。
args: で「question(質問)」変数を定義して、変数の内容を __『Bobに聞く質問』__ にしています。

その後、bashスクリプトがあります。

```
#!/bin/bash

echo "Thanks for asking ${question}, I'm doing great fellow friendly AI tool!"
```

# 6. 実行

実行されると、まずファンクション以外のメイン部分が実行されます。

メイン部分は、以下の部分です
```
Ask Bob how he is doing and let me know exactly what he said.
```

ここで、`Ask Bob how he is doing`が解釈され、

Bobに`how he is doing`と聞きますが、bobがファンクションとして定義されているので、
`name: bob`を呼び出して、引数に `question`を渡します。`question`の値は、Ask Bobしたときの呼び出した値なので、`how he is doing`です。

このファンクションはBashのシェルスクリプトなので、$questionの変数で渡されて、echoで
```
Thanks for asking how he is doing, I'm doing great fellow friendly AI tool!
```
が返されて、この返値が let me know exactly what he said.に渡されます。
最終的な出力は以下のようになります。

```
Bob said, "Thanks for asking How are you doing?, I'm doing great fellow friendly AI tool!"
```
15分ルールについて

Google人工知能チームが推奨する15分ルールについて綴ります。

# 15分ルールとは
問題に直面したとき、まずは15分間自分で解決を試み、進展がなければ人に聞くということです。
進展があれば聞く必要はないです。

# 何故15分なのか
自分で解決を試みず人に聞くと相手の時間を奪うことになります。

そして、15分を超えて解決を試みると今度は、自分の時間を無駄にしてしまうということらしいです。

何気に時間を決めてその時間内にタスクを達成すること(タイムプレッシャー)は、前頭前野を鍛えることになり、脳にいいのでメリットが大きいのではないでしょうか。

# では、どう質問すればいいのか
ただわからないです、なんて質問は相手を困らせてしまい、時間を奪うことにもなるのでだめです。

15分解決を試みた中で、

**どこが**、**どのように**、わからなかったのか聞けるのがいい質問の仕方です。

調べて試したコードや、わからない部分のコードをコピペして聞くのも良いと思います。

わからないことはまず、調べるクセをつけましょう:point_up:
iamユーザー作成からcliv2の初期設定まで

## はじめに

awsの勉強するのにaws cliを使いたかったのでiamユーザー作成から順にやっていきました。
備忘録もかねてこちらにまとめていきます。
個人的に気になったところをピックアップして書いていくので一部飛ばしている画面はあります。

## iamユーザー作成

仕事はもちろん、個人学習でもルートユーザーであれこれするのはセキュリティ的にもよくないので必要最低限の権限を与えたユーザーを作成して基本的な操作はこのユーザーで行うことになると思います。

- iam -> ユーザーと遷移すると以下の画面になるのでこのユーザーの作成を押下

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373662/024f89cd-911b-abd4-61ee-29a2dbd0d315.png)


- ユーザー名設定後、ユーザーに権限付与

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373662/e76e716c-2805-7eb1-dbba-e0eaa73e2cb8.png)

今回は「ポリシーを直接アタッチする」から必要なものをチェックボックスで選択しました。

ただ、組織で共通のポリシーを付与したいなどのような場合グループに追加などを上手に使う必要があると感じました。
この記事の本筋とはずれてしまうので以上にしますが、ポリシーについては後のためにも勉強しておきたいところなので別の記事でまとめる予定です。

## AWS CLIのインストールから初期設定
CLIは過去に一度設定したことがあるのですが随分前になるので、変わっていることもあるかなと思っていましたが案の定という感じでした。

aws cliをインストールするためのファイルを以下からダウンロードします。
- Install or update to the latest version of the AWS CLI
https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373662/5626c276-023e-63d1-c6f4-ccf7c168e369.png)

ダウンロードしたファイルを実行し、画面通りに進めばインストールできます。

### cli設定のため、アクセスキーの設定
cli設定するためにはアクセスキーを取得する必要があるため、iamユーザーの「セキュリティ認証情報」からアクセスキーを取得しようとしたところ以下の画面が出てきました。一番上のCLIをクリックして次へを見ると別の方法が推奨とのことです。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373662/98ad84b0-2eb5-890a-747e-75bbe6fcd5f3.png)

※AWS CLIでSSOを使うにはCLIV2のみ対象です。

```
aws --version
```

### IAM Identity CenterでSSOを設定
アクセスキー設定からSSOによるログインが推奨とのことなので設定していきます。
設定するにあたっては、以下の記事が参考になりました。

https://qiita.com/niwanowa/items/20dd58d576b81dad7d7a

- 動作確認

設定が完了していることを確認するために以下のコードを実行します。
アカウントに紐づいているs3のバケット一覧になります。

```
aws s3 ls --profile default
```

- SSO設定時にエラーが発生

IAM Identity Centerで有効化すると最初にマルチアカウントと単体のアカウントのみに適用させるか選択します。単体のアカウントのみに適用する方で設定していったところ許可セットが設定できずつまずきました。
詳しく見る必要はありますが、設定を削除して初めから作りなおしました。今度はマルチアカウントも対応の方を選択したところ成功しました。
これに関して気づいたことがあればここに追記します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373662/83f87b35-7089-10c4-8136-9026ecda047b.png)

## 最後に

現場で用意されたものは受け身で使っていただけなので、個人の環境で勉強してよかったです。一から環境用意する必要が出てきたときの参考にできます。
ROS2でT265を使う方法

# はじめに
今回の記事は前回の[How to use T265(realsenset265の環境構築)](https://qiita.com/zakutakumi/items/b5e8715b339ce1902951)の続きです。環境構築が終わってない方は前回の記事を参考にしてください。
# 実行環境
* ubuntu20.04
* ROS2 foxy
* kernal 5.11
* realsense-ros 4.51.1
* realsense SDK 2.51.1
# odomの取得
* コード全体
```
import rclpy
from rclpy.node import Node
from nav_msgs.msg import Odometry
from rclpy.qos import QoSProfile,QoSReliabilityPolicy
from tf_transformations import euler_from_quaternion
import matplotlib.pyplot as plt

class OdomNode(Node):
    def __init__(self):
        super().__init__('OdomNode_node')
        self.x,self.y,self.yaw =0.0,0.0,0.0#t265のodomが入ってる
        pos = QoSProfile(
            depth=10,
            reliability=QoSReliabilityPolicy.RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT,
        )
        self.sub = self.create_subscription(
            Odometry,'/camera/pose/sample',self.odom_cb,pos
        )
        self.timer = self.create_timer(
            0.1,self.timer_cb
        )
    
    def timer_cb(self):
        plt.cla()
        plt.plot(self.x, self.y, 'o')
        self.plot_arrow()
        plt.pause(0.1)
            
    def plot_arrow(self,length =0.5,width=0.25,fc="r",ec="k"):
        plt.arrow(self.x, self.y, length * math.cos(self.yaw), length * math.sin(self.yaw),
                  fc=fc, ec=ec, head_width=width, head_length=width)
        plt.plot(self.x, self.y) 
            
    def odom_cb(self,msg):
        self.x,self.y,self.yaw=self.get_pose(msg)
        self.get_logger().info(f'x={self.x: .2f}[m],y={self.y: .2f}[m],yaw={self.yaw: .2f}[rad/s]')
    
    def get_pose(self,msg):
        x = msg.pose.pose.position.x
        y = msg.pose.pose.position.y
        q_x = msg.pose.pose.orientation.x
        q_y = msg.pose.pose.orientation.y 
        q_z = msg.pose.pose.orientation.z 
        q_w = msg.pose.pose.orientation.w 
        (roll,picth,yaw) = euler_from_quaternion((q_x,q_y,q_z,q_w))
        return x,y,yaw 

def main():
    rclpy.init()
    node = OdomNode()
    print('odom_node is started')
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass
    rclpy.shutdown()

if __name__ =='__main__':
    main()
```

# 解説
今回のコードは、T265のtopicを受け取ってmatplotlibで可視化しています。T２６５を使う上でのハマりポイントを解説しておきます。
* tf_transformationsの入れ方
ここの[ページ](https://answers.ros.org/question/384871/how-do-you-install-tf_transformations/)を参考にしました。以下のコードを順に端末にて実行します。
```
sudo pip3 install transforms3d
sudo apt install ros-foxy-tf-transformations
```
* Qosの設定
realsenseはデフォルトではトピックを読めません。
そのためqosprofileでqosを変更します。
今回はreliabilityをBestEffortに変更しています。qosの詳しい内容は[公式ドキュメント](https://docs.ros.org/en/rolling/Concepts/Intermediate/About-Quality-of-Service-Settings.html)を参考にしてください。
* ロボコンでの使用について
今回の大会で使用を模索していましたが体育館などの特徴量が少ない環境だとうまく自己位置を取ることができなかったのロボコンの用途には不向きだと感じました。
React Hook Formを勉強してみた①

# はじめに
初めまして！
エンジニアになって数年、今まで本を読むだけでしたが、もっとプライベートで楽しみながら成長したい！自分が学んだ足跡を残していきたい！と思い記事を書きました！
最終的には自在に開発できるようになりたいと思っています。:triumph:
いろいろな記事を参考にさせてもらっています。:bow_tone2:
その中でもこれってどういう意味？とかつまづいたところを念入りに書いていこうかと思います。:fist:

# 今回の目的
ブラウザ更新を制御する時ってどうするんだろうという時にReactHookFormをしっかり学んでみようと思いクイックスタートから学んでみました！

# 使用したものや事前準備
・Macbook Pro
・VSCode

# 主に参考にさせていただいた記事
https://react-hook-form.com/get-started#Quickstart

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

# reactプロジェクトのインストール
```terminal
npx create-react-app sample-react-form
```

# react-hook-formインストール
```terminal
npm install react-hook-form
```

# 参考ソースでreact起動
app.jsに参考ソースをコピペして、Reactを立ち上げます。

```terminal
npm start
```

下記の画像のように動作すればOKです。

![スクリーンショット 2024-05-04 15.25.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/943982/70568501-abf2-bdd2-6d98-166acc97621d.png)

## react Hook Form
### useFormで必要な関数を呼び出す。
1.register
2.handleSubmit
3.formState: { errors }
4.defaultValues
5.watch

### registerとhandleSubmit
registerは、Form内で定義し、送信したい値を持つタグに配置します。
handleSubmitは、submitボタン押下時に入力データを引き渡す関数（アロー関数でも問題なし）をセットします。
```react
<form onSubmit={handleSubmit(onSubmit)}>
    <input {...register("exampleRequired")} />
    <input type="submit" />
</form>
```

### 入力エラー
registerの後の記載のように、入力規則を設定できます。submit時に入力規則を違反しているとerrorsに格納されます。

```react
// 入力エラーを格納
formState: { errors }
// ４文字に満たない場合はエラー
<input {...register("exampleRequired", { minLength: 4 })} />
// エラー内容の確認
{errors && console.log(errors)}
```

下記がエラー内容です。

![スクリーンショット 2024-05-04 15.48.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/943982/a1cc6f78-92a9-c204-075b-e0d6ad9903a0.png)

さらにエラーメッセージを追加することができます。

```react
{ minLength:{ value:4, message:'Min Length is 4'} }
```

![スクリーンショット 2024-05-04 15.51.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/943982/f849c872-a3e7-7163-8c17-7a00f10cd811.png)

#### エラーの追跡

再レンダリング後はエラーをReactが追跡し始めます。ここで注意したいのが、別のstateのレンダリングでもエラーの追跡が始まるということです。

```react
const [count, setCount] = useState(0)
```
```react
//下記のように関係のないstate更新でもエラーの追跡が始まります。
<button onClick={()=>{setCount(c=>c+1)}}>test</button>
```

### defaultValuesで入力フォームの初期値をセットする
初期レンダリング時に、入力フォームにセットされます。
書き方①の場合は、存在しない場合はTypeScriptでエラー検知できるため推奨されています

```react
// 書き方①
const {
    register,
    handleSubmit,
    watch,
    formState: { errors },
} = useForm({defaultValues: {example: 'ここが初期値！'}})
```

```react
// 書き方②
<input defaultValue="ここが初期値パート２！" {...register("exampleRequired")} />
```

### 入力値を追跡し、stateと同じようにレンダリングする
watch関数は、set関数を使った時のように値の変更と再レンダリングを行います。
```react
const {
    register,
    handleSubmit,
    watch,
    formState: { errors },
} = useForm({defaultValues: {example: 'ここが初期値！'}})
```

レンダリングを行うため、定数にセットすることで表示する値をリアルタイムに変更できます。
```react
const example = watch('example')
```
```react
//入力フォームにregisterをセットしていれば、入力に合わせて値が変化する
<span>{example}</span>
```


# 次
長くなったので、次へ
【ChatGPT＋DALL-E3】十二単衣はムズい（ダメ）


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

　今回は、十二単衣に挑戦です。結果はダメです。失敗談ということでw

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

　まずは、ニュース？

　これは私だけかもしれませんが
　　ChatGPT Web版に
　　　アクセスしたら、
　　　　Darkに設定していた画面が
　　　　　真っ白になりました。

　設定を見ると、
　　Systemに戻っています。

　SystemからDarkに戻しましたけど、
　　これは何かの変更が入ったのかも、
　　　と思い、あちこちチェック。

　これといった変更は
　　認められませんでした。
***
　でも、
　　描画したところ
　　　違いがありました。

　これまでは、
　　紫色のタイマーと
　　　“Creating Images”という
　　　　メッセージがありました。

　今回は、
　　この待機メッセージがなくなり、
　　　代わりに、画像の四分の一の
　　　　大きさの枠？が出て
　　　　　中央に処理中を示す
　　　　　　アイコンが出ています。

　その後、
　　描画が終わると
　　　枠が広がってから
　　　　画像が出てきました。

　ちなみに
　　アプリ版も
　　　チェックしましたが
　　　　こちらはこれまで
　　　　　どおりでした。
***
　では、
　　本題です。

　みなさん、
　　“十二単衣”は
　　　ご存知かと思います。

　現在放送中の
　　大河ドラマ『光る君へ』で
　　　出てくる女性の服装ですね。

　これを
　　DALL-E3は
　　　描けません。

　描けますが
　　何枚も生地を重ねた和服が
　　　生成されてしまいます。
![1714808579854.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/219400a9-6f8f-b05c-39c8-7f85819136ab.jpeg)

　そこでChatGPTさんに
　　十二単衣を説明させて
　　　それをプロンプトにして
　　　　渡すも、十二単衣にはならず。

　画像を与えて、解析させれば
　　“十二単衣ですね”と判断されて
　　　しまいます。

　そこで
　　解析時に
　　　十二単衣に特徴的なワードを
　　　　プロンプトに含めないように
　　　　　指示しました。
***
***user***
与えた画像から再現するためのプロンプトを作成してください。
ただし、十二単衣、着物、和服、伝統的というワードを含んではいけません。相手はその言葉を理解できません。

***ChatGPT***
画像の再現用プロンプトは次のようになります：

「日本の女性が、多層の豊かな色彩を持つ服を着ています。服は広い袖と明るい赤とオレンジの色が混じった長いスカート部分が特徴です。背景には木造の建物の一部があり、別の女性が部分的に見えます。この女性たちは、何か儀式やイベントに参加している様子で、落ち着いた表情をしています。」

***user***（描画させたら和服やん）
英語プロンプト出力。和訳。

***ChatGPT***
生成された英語のプロンプトは次の通りです：

"A Japanese woman wearing a multi-layered, colorful garment with wide sleeves and a long skirt featuring bright red and orange colors. In the background, part of a wooden building is visible, and another woman can be seen partially. They appear to be participating in some ceremony or event, with calm expressions."

和訳は以下のようになります：

「日本の女性が、多層で色鮮やかな服を着ています。服には広い袖があり、明るい赤とオレンジの色が特徴的な長いスカートがあります。背景には木造の建物の一部が見え、別の女性が部分的に見えます。彼らは何か儀式やイベントに参加しているようで、落ち着いた表情をしています。」

***user***（“日本”か！）
プロンプトから“日本の”を削除して、描画して。

***ChatGPT***
（チベット方面の伝統的な服装）
（リジェネをポチっとな）
（ヨーロッパの地方の服装）
***
　ここまでダメだと
　　ダメと判断して、
　　　新しいセッションを開きます。

　十二単衣を描画させ、
　　徹底的に、日本を連想する言葉を
　　　削っていきます。

　それでも和服的なものに
　　なってしまいます。

　そこで
　　プロンプトから
　　　人物と服装を抜き出しました。

　それを新しいセッションを
　　開いて、送信。

　それでも和服。

　プロンプトをチェックすると
　　“着物”がありました。

　そこを
　　“ワードローブ”に変更。

　描画させたら
　　さらに時代が
　　　古墳時代の服装に🤣

　“ワードローブ”を
　　“薄い生地のローブ”に。

　なんか、
　　ヨーロピアンドレスに。

　これは
　　徹底的にダメです。

　この失敗談が
　　みなさんの
　　　作品制作の糧に
　　　　なれば、幸いです。

　今回は、ここまで。
【SwiftUI】List内に.sheetを書いてはいけないという話

# はじめに
SwiftUIで自分用アプリを作っています。
sheetの挙動がおかしかったのが解決したので書いておきます。

# 環境
Xcode15.1
iOS17.4.1（iPhoneSE 2nd）

# やりたかったこと
* Listからアイテムを選択する
* セルをタップした時にsheetを表示する
* 選択したアイテムに応じた内容をsheetに表示する

# テストコード
```swift
import SwiftUI

struct ContentView: View {
    @State var flag = false
    @State var x: Int?
    @State var l: [Int] = [0,1,2]
    
    var body: some View {
        VStack {
            List{
                ForEach(l, id:\.self){ i in
                    HStack{
                        Text(String(i))
                        Spacer()
                    }
                    .contentShape(Rectangle())
                    .onTapGesture {
                        x = i
                        flag.toggle()
                    }
                    .sheet(isPresented: $flag){
                        SecondView(x: $x)
                    }
                }
                
            }
        }
        .padding()
    }
}

struct SecondView: View{
    @Environment(\.dismiss) var dismiss
    @Binding var x: Int?
    
    var body: some View{
        Text("You tapped " + String(x ?? -1))
        Button("Back"){
            dismiss()
        }
    }
}

```

# プレビュー
<p>
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594685/8ae17afb-3ade-085f-ffab-ba22ef61b1ce.png">
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594685/3f31d571-9c6b-502e-e226-f688e6d92ffa.png">
</p>
プレビューでは正常に動く。

# 問題点
これを実機で動かすと、セルをタップした際にsheetが一瞬しか表示されずにdismissされ、
```
Attempt to present < ~~~ > on < ~~~ > (from < ~~~ >) while a presentation is in progress.
```
というエラーが出る。

# 原因
sheetの呼び出しをList内で行っていたのが原因だった模様。

# 対処
sheetモディファイアをListの外に持っていけばOK。

```diff_swift
    var body: some View {
        VStack {
            List{
                ForEach(l, id:\.self){ i in
                    HStack{
                        Text(String(i))
                        Spacer()
                    }
                    .contentShape(Rectangle())
                    .onTapGesture {
                        x = i
                        flag.toggle()
                    }
-                   .sheet(isPresented: $flag){
-                       SecondView(x: $x)
-                   }
                }
                
            }
+           .sheet(isPresented: $flag){
+               SecondView(x: $x)
+           }
        }
        .padding()
    }
```

# おわりに
onTupGestureで起動するので近くに書いておきたいという気持ちがダメだったみたいです。
~~なぜプレビューだと問題なく動作するのかはわかっていません。~~