OmniAICreator/Qiita-1.07M huggingface dataset:
wolfram alphaのグラフ書式メモ

# はじめに
wolfram alphaに数式をいれるとグラフを生成してくれますが、もっと明示的に指示したいときの方法です。

|```x^2+y^2=1```|```x^2+y^2+z^2=1```|
|:-:|:-:|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/e5c4af53-2b97-48a8-903c-607a0652b532.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/58354a68-aac3-43bc-8c20-db9d41b24a01.png)|

# 媒介変数によるグラフ
```wolfram
plot x = sin(6t), y = sin(5t)
```
または
```wolfram
plot x = sin(6t), y = sin(5t) for t from 0 to 2pi
```
または
```wolfram
parametric plot sin(6t), sin(5t) for t from 0 to 2pi
```
| 1 | 2 |
|:-:|:-:|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/09deb85d-ea9d-47d8-812d-558a08d45962.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/0cbab632-467d-45bb-be47-3fc8521a6204.png)|


# ３次元グラフ

```wolfram
ContourPlot3D[x^4+y^4+z^4-2(x^2y^2+y^2z^2+z^2x^2)==0,{x,-3,3},{y,-3,3},{z,-3,3}]
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/85a9ce3e-89ec-4644-99df-d16a00a192b3.png)

```wolfram
ContourPlot3D[x^4+y^4+z^4-2(x^2y^2+y^2z^2+z^2x^2)==1,{x,-3,3},{y,-3,3},{z,-3,3}]
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/80fc8fbd-d174-4e0e-a896-b21df4873e85.png)

https://www.wolframalpha.com/input?i=ContourPlot3D[x^4%2By^4%2Bz^4-2(x^2y^2%2By^2z^2%2Bz^2x^2)==1,{x,-3,3},{y,-3,3},{z,-3,3}]

※URL指定でwolfram alphaに直接飛ばせるが、プラス記号は%2Bに置き換える必要があった。

```wolfram
ContourPlot3D[x^4y^4z^4-2(x^2y^2+y^2z^2+z^2x^2)==1,{x,-3,3},{y,-3,3},{z,-3,3}]
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/67ae96f6-9dab-4f9f-8259-327ff7bbcbcf.png)


# おまけ
Macに付属のGrapherでの描画です
|  |  |
|:-:|:-:|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/f1a9479f-dfdc-4244-a69e-e210c702a522.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/20c6bf1b-207d-45f5-aa8f-46b89f313709.png)|
ChatGPTのDeep researchからGitHub Privateリポジトリが読み込めるようになっていた

## はじめに

普段はCopilotよりもChatGPTを使ってプログラミングしている者です。

https://help.openai.com/en/articles/11145903-connecting-github-to-chatgpt-deep-research

偶々、こんな記事を見つけました。
記事の内容をざっくり要約すると、

> **ChatGPT課金者限定**でDeep researchを使って、自分のGitHubリポジトリのコードを解析できます。
> 接続したリポジトリ（privateも可）内のコードを取得して、質問に対して該当箇所を読み解いて引用付きで回答してくれます。

これまでは（というか昨日までは）、いちいちコードをZip化してアップロードしていましたが、その手間がなくなりそうです。

Copilot無課金勢の自分からすれば、これは最高の機能では？と思い、さっそく試してみました。


:::note warn
（重ねて言うまでもありませんが、念の為…）情報の取り扱いについてはご注意ください。

https://help.openai.com/en/articles/11145903-connecting-github-to-chatgpt-deep-research#:~:text=code%20or%20files.-,Will%20OpenAI%20use%20content%20from%20GitHub%20to%20train%20its%20models%3F,-By%20default%2C%20content
:::

## 導入手順
:::note info
事前にChatGPTで多要素認証を済ませておく必要があります。

<details><summary>手順</summary>

1. 右端のアイコン
1. 設定
1. セキュリティ
1. 多要素認証の有効化
</details>
:::

### 1. ChatGPTをGitHubに接続する
https://github.com/apps/chatgpt-connector/installations/select_target
上記のURLにアクセスし、「ChatGPT Connector」をインストールします。
その後、ChatGPTに読み込ませたいリポジトリを選択してください。

![スクリーンショット 2025-05-18 181054.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3721815/c3474978-8ae7-49ba-990f-846dcaf8b275.png)

### 2. リポジトリのインデックスを作成する
:::note info
ChatGPTからリポジトリを利用するには、GitHub上でリポジトリのインデックスを登録する必要があります。
特にPrivateリポジトリは、初期状態でインデックスが作成されていない場合が多いため、必ずこの作業を行ってください。
:::

GitHubの検索バーで
```
repo:{username/repo_name} import
```
を実行し、インデックスを作成してください。

※ インデックスの作成には5~10分ほどかかります。

### 3. Deep researchで読み込むリポジトリを選択する
ChatGPTでDeep researchを選択し、右端の下矢印から情報源としてGitHubを指定します。
入力欄で読み込みたいリポジトリ名を検索し、表示されたリポジトリを選択してください。
なお、この際リポジトリは複数選択が可能です。

![スクリーンショット 2025-05-18 193137.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3721815/3870fd00-19a0-48c4-bcec-03cac283cceb.png)

※ 読み込みたいリポジトリが表示されない場合は、上述のインデックス登録がまだ済んでいない可能性があります。

## PrivateリポジトリをDeep research

実際にDeep researchがプライベートリポジトリをきちんと読み込めているのかを確認するため、いくつか質問してみました。
※なお、後述する Ymmy833y/NippoMaker は公開しても差し支えのないリポジトリです。

![スクリーンショット 2025-05-18 203801.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3721815/1acb5922-421f-4c27-8c82-d6fbde832f20.png)

![スクリーンショット 2025-05-18 203841.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3721815/e27173ae-bb8a-4e1d-91d2-f4bc7a7d14a8.png)

![スクリーンショット 2025-05-18 203901.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3721815/f08994b3-4503-487f-b0df-97147e6e6153.png)

プライベートリポジトリなので内容の妥当性は自分にしか判断できませんが、調査結果は期待通りのものでした。
READMEに記載していない技術スタックについても、package.json などから自動的に抽出して回答してくれているようです。

また、Issueの内容をもとにコード修正も依頼してみました。

https://chatgpt.com/share/6829c5b0-d810-8007-a303-d7240383a836

「共通処理を使ってほしい」や「routesにロジックを書かないで」といった点など、いくつか気になる指摘はありましたが、修正の方向性自体はほぼ正確だったように感じます。
なお、こうした指摘については、これまでにも一度で完璧なコードが出てきた試しはないので、「まぁそんなものか」と思っています。

## さいごに
今回Deep researchを試したリポジトリは小規模で、IssueやPRの数も30件ほどしかありませんでしたが、ざっくりとした質問にも関わらず、わずか5分ほどで関連するコードや修正箇所を的確に特定してくれたのには驚きました。

それに、今まで毎回ファイルをZip化してアップロードしていた手間が省けて、とても快適です。

Deep researchの利用頻度が減っていたことで回数制限が最大まで残っていましたが、この調子だとあっという間に使い切ってしまいそうです。

まだ「Deep research × GitHub」機能はβ版ということで、今後も改良されていく余地がありそうですが、正式リリースが待ち遠しい限りです。
ORMについて

# 今日のトピック
- ORMについて

## ORM（Object-Relational Mapper）について
端的に言うと、オブジェクト指向プログラミングとリレーショナルデータベースを繋ぐ技術である。
参考文献では、「オブジェクトとRDBのテーブルの行を対応付けることだ」と書いてあった。
※ 以下では、EFCoreを用いて説明したいと思う。

## なぜORMを使うのか
前回記事では、DBにおけるリレーションについて説明した。
[DBにおけるリレーションとは](https://qiita.com/unekiri/items/fbb79a3f372e838a7875)

そこで、こんな疑問が湧いてこないだろうか...
- 「データベースのスキーマを構築するために、アプリケーションコード内にSQLを書く必要があるの?」
- 「関連するデータを取得するために、毎回複雑なJOIN句を含むSQLを書かないといけないの？」

これらの問題を解決し、開発をよりスムーズにしてくれるのが、今回の主題であるORMなのである。

## ORMの使用例（EFCore）
ここでは、1対多のリレーションシップについて、ORMを使用した場合のモデル定義と操作を書いてみる。

### ORMでのモデル定義と操作
まず、EFCoreでデータベースとやり取りするためのDbContextクラスとエンティティクラスを定義する。

```
// --- DbContext ---
public class AppDbContext : DbContext
{
    public DbSet<Author> Authors { get; set; }
    public DbSet<Book> Books { get; set; }

    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 1対多: Author - Book
        modelBuilder.Entity<Author>()
            .HasMany(a => a.Books)
            .WithOne(b => b.Author)
            .HasForeignKey(b => b.AuthorId);

        base.OnModelCreating(modelBuilder);
    }
}
// --- エンティティクラス ---
public class Author
{
    public int AuthorId { get; set; } // 主キー
    [Required, MaxLength(100)]
    public string Name { get; set; }
    public  ICollection<Book> Books { get; set; } = new List<Book>(); // ナビゲーションプロパティ
}

public class Book
{
    public int BookId { get; set; } // 主キー
    [Required, MaxLength(200)]
    public string Title { get; set; }
    public int AuthorId { get; set; } // 外部キー
    public Author Author { get; set; } // ナビゲーションプロパティ
}
```
- 上記AuthorクラスとBookクラスでは、Author.Books と Book.Author がナビゲーションプロパティとして1対多の関係を示している。Book.AuthorId が外部キー、OnModelCreating でリレーションが設定されている。
- ナビゲーションプロパティとは、エンティティから関連する他のエンティティ（オブジェクト）へアクセスするためのプロパティである。
<br>

ある著者の本を全て取得する操作は以下のようになる。
```
using var dbContext = new AppDbContext(options);
var author = dbContext.Authors
                      .Include(a => a.Books)
                      .FirstOrDefault(a => a.Name == "夏目漱石");

if (author != null)
{
    foreach (var book in author.Books)
    {
        Console.WriteLine($"書籍ID: {book.BookId}, タイトル: {book.Title}");
    }
}
```
※ 使用時のメリット、デメリットについては、参考文献や他の資料を参照下さい。
# おわりに
間違いがあれば、ご指摘いただけますと幸いです(__)

## 参考文献
[ORMとは？仕組みやメリットなどをわかりやすく解説](https://it.webcli.jp/topics/orm/)
[ナビゲーション プロパティ](https://learn.microsoft.com/ja-jp/dotnet/framework/data/adonet/navigation-property)
Flutterゲーム開発 - Flameでタイピングゲーム編

## この記事について

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2700602/d54f3c06-0d3e-47cf-9928-254cf0fa4f9a.gif)

以前から気になっていたFlutterのゲームエンジン[**Flame**](https://flame-engine.org/)でタイピングゲームを開発したので、紹介します。詳しい解説などは特にありませんが、この記事の反応が良ければ投稿しようと思います！

以前作ったFlutterのゲーム記事は[こちら](https://qiita.com/KAZMA_WED/items/ed43e1c7bbaec397c486)

## 制作物について

https://flutter-flame-typing.web.app

- シンプルなタイピングゲームです
- 単語タイピングの他に、超初心者向けのポジション練習モードも用意しています
    ![Screenshot 2025-05-18 at 23.21.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2700602/4450ad94-c24e-44fa-ae6f-cce1217adb40.png)
    ![Screenshot 2025-05-18 at 23.22.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2700602/d80abdad-baf0-42ee-bd31-e9c215dcd1a7.png)

- QWERTY配列以外のキー配列を趣味レーションして遊ぶ機能があります
    ![Screenshot 2025-05-18 at 23.22.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2700602/c9dd4de7-c036-42bb-8910-d890a5fc97e2.png)

## ソースコード

https://github.com/KazmaWed/flutter_flame_typing

- 画像や音源、フォントなどのアセットはソースコードに含まれていません
- この記事の反応が良ければダミーアセットでビルドできる様に更新しようと思います

## Flutterとゲーム開発について

<iframe height="480"src="https://www.youtube.com/embed/nsnQJrYHHNQ" title="How to build a physics based game with Flutter and Flame&#39;s Forge2D" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

現時点で、Flutterでゲーム開発というと[Flame](https://flame-engine.org/)一択になると思います。
(FlameをラップしたRPG特化版の[Bonfire](https://pub.dev/packages/bonfire)というフレームワークもあり、活発にアップデートされている様です)

Flameでモダンで本格的なゲーム開発ができるかどうか未知ですが、Google I/Oでも取り上げられたり、意外と情報や開発環境は充実している印象です。

メジャーなゲームでFlutterが利用されている事例を聞いたことがありますが、実際にはUIのレイヤーだけFlutterで、ゲームエンジンは別という場合がほとんだと思います。あくまでFlutterが好きでゲーム開発も好き、という人の趣味のフレームワークかな？という印象です。

でも楽しいのでオールOKです！個人的にはUnityに依存しないでVSCodeだけで開発できる点も好きです (3Dゲームを作る場合にどうするんだろう…)

## おわりに

今回はゲームの紹介まででしたが、ソースやゲームに関する質問などいただければお答えしますので、お待ちしています！
【Unity】色々なシーンで使うクラス・定数・変数にはStaticを使おう

# はじめに
Unityでゲーム開発をしていると、「どのシーンからでもアクセスしたい変数やクラス」が出てくることがあります。そんなとき便利なのが static（スタティック）というキーワードです。

# 🔍 Staticとは？
static は「静的なもの」、つまりインスタンス化せずに直接使えるという意味です。

通常、クラスの変数やメソッドを使うにはこうします：

```player.cs
Player player = new Player();
player.health = 100;
```

Unityでは，GameComponentごとにインスタンス化します．

でも static を使えば、こんなふうに 直接アクセス できます：

```
GameManager.score = 100;
```

# ⚙️ Staticを使うと何が起きるの？
- ✅ インスタンス不要	
    ゲームコンポーネント単位で設定する必要がない
- ✅ どこからでもアクセス可能	
    シーンをまたいでもアクセスできる（メモリ上に残る）
- ✅ 値が共有される	
    すべてのスクリプトで同じ値を参照・変更できる


# 🎯 具体的にStaticを使う場面
✅ ゲーム全体で共有するスコア・設定
```cs
public static class GameManager
{
    public static int score = 0;
    public static bool isSoundOn = true;
}
```
これならどのシーンのスクリプトからでも、

```cs
GameManager.score += 10;
```
と簡単に使えます。

# ✅ 共通定数（タグ名やレイヤー名など）
```cs
public static class Tags
{
    public const string PLAYER = "Player";
    public const string ENEMY = "Enemy";
}
```
ハードコーディングせずに、

```cs
if (collision.tag == Tags.PLAYER)
```
と書くことで、間違いも減ってメンテナンスも楽になります。

# ✅ ユーティリティクラス（汎用処理）
```
public static class Utils
{
    public static float GetRandom(float min, float max)
    {
        return UnityEngine.Random.Range(min, max);
    }
}
```
使うときは：
```
float speed = Utils.GetRandom(1f, 5f);
```
:::note warn

❗️Staticの注意点
破棄されない：シーンが変わっても残る。なので、明示的な初期化が必要。

依存しすぎ注意：何でも static にすると、テストしづらくなる・スパゲッティコード化の恐れも。

オブジェクトへの依存NG：GameObject や MonoBehaviour を static に持たせるのは避けよう（null や破棄の問題が起きやすい）。
:::

# ✅ まとめ
| よく使う用途 |	static にすべき？ |
| :-: | :-: |
| スコアや設定など全体共有 |	✅ Yes |
| タグ名やレイヤー名など定数 |	✅ Yes |
| 一度だけ使う変数 |	❌ No |
| MonoBehaviour（Transformなど）	| ❌ 基本的に No |

static は便利な機能ですが、**どこでも使える＝どこからでも壊せる**というリスクもあります。目的を明確にして、うまく使いこなしましょう！


# ✍️ おわりに
static は非常に便利で強力ですが、間違って使うとアプリ全体にバグを引き起こすこともあるため、慎重に扱う必要があります。

- 値を共有したいときに限定する

- 直接アクセスよりもプロパティ経由にする

- MonoBehaviourとは切り離す

この3つを意識して、安全に static を活用していきましょう！
C言語の文字列は3種類存在する！？――文字列リテラル／文字配列／文字列ポインタ

## はじめに
C言語の文字列には大きく分けて以下の3種類があります。
それぞれメモリ上の配置や取り扱いが異なるため、挙動の違いを理解しておきましょう。

1. **文字列リテラル（文字列定数）**
2. **文字配列**
3. **文字列ポインタ**

---

## 1. 文字列リテラル（文字列定数）

```c
char *s = "Hello, World!";
```

* **定数（`const`相当）**
* プログラム実行中は変更不可
* コンパイラが用意する「静的領域（.rodataなど）」に配置
* 複数回同じリテラルが出現すると、１つの領域を共有することがある

---

## 2. 文字配列

```c
char s[] = "Hello, World!";
```

* 実際には文字数＋終端文字分の要素を持つ配列
* 変数と同様、**スタック領域**（関数内宣言の場合）や**データ領域**（静的・グローバルの場合）に配置
* 要素を書き換え可能
* サイズは初期化時にしか決まらない

---

## 3. 文字列ポインタ

```c
const char *p = /* 何らかの文字列 */ ;
```

* ポインタ変数（アドレスを保持）
* ポインタ自体はスタック上に配置され、中身はどこかの文字列領域を指す
* 指している先が文字列リテラルなのか、ヒープや配列なのかはコード次第
* 書き換え可能な領域を指していなければ、参照先の書き換えは未定義動作

## まとめ

* **文字列リテラル**は定数、**文字配列**は可変、**ポインタ**は間接的に参照
* メモリ配置を意識して、安全かつ効率的なコードを書く


苦手意識のあるC言語の文字列周りも、メモリを意識するとグッと理解が深まります。ぜひ試してみてください！

---

### 参考リンク

* 文字列ポインタとリテラルの解説
  [https://www.kushiro-ct.ac.jp/yanagawa/C-2017/15-0613/index.html#strptr](https://www.kushiro-ct.ac.jp/yanagawa/C-2017/15-0613/index.html#strptr)
* メモリレイアウトと文字列の扱い
  [https://www.kushiro-ct.ac.jp/yanagawa/C-2017/24-0712/index.html](https://www.kushiro-ct.ac.jp/yanagawa/C-2017/24-0712/index.html)
Excelとサクラエディタで手軽にGrep自動化【VBAスクリプト付】

---
#### 1. はじめに

  日々のログ確認やファイル検索でサクラエディタのGrepを多用しているのですが、  
  毎回キーワードを入力して実行するのが面倒…。  
  そこでExcelとVBAを使って、複数ワードでGrepを自動実行する仕組みを作ってみました！


---
#### 2. 実現したこと

* GrepキーワードをExcelに書いておく
* 複数のキーワードを順番に自動検索
* サクラエディタを起動して検索画面表示、連続実行
* 一括検索の効率化

---

#### 3. スクリプトの構成と使い方

* Excelシートの準備

  * A列：キーワード
  * B1：検索対象フォルダ
  * C1：サクラエディタのパス（例：`C:\Program Files\sakura\sakura.exe`）

* コード

```vba
Sub RunGrep_ExecuteDirect()

    Dim row As Long
    Dim keyword As String
    Dim targetFolder As String
    Dim sakuraPath As String
    Dim command As String

    ' 設定をExcelから読み込む
    targetFolder = Range("B1").Value
    sakuraPath = Range("C1").Value
    
    row = 1
    Do While Trim(Cells(row, 1).Value) <> ""
        keyword = Cells(row, 1).Value

        ' サクラでGrep実行（ダイアログなし）
        command = """" & sakuraPath & """" & " -GREPMODE -GKEY=""" & keyword & _
                  """ -GFOLDER=""" & targetFolder & """ -GOPT=1 -GFILE="".*"" -GCODE=0"

        ' 実行（前面表示）
        Shell command, vbNormalFocus
        
        ' 少し待つ（連続実行のため）
        Application.Wait Now + TimeValue("0:00:02")

        row = row + 1
    Loop

End Sub
```

---

#### 4. 応用・改善の余地
* 結果をファイルに出力する場合は `-GOUTPUT` オプションの追加
* 検索結果の取り込み → Excelに貼り付け or 解析も可能
* 検索対象を特定の拡張子に絞るなども可（`.log`, `.txt`など）

---

#### 5. おわりに

本当は[自動検索 + 1ファイルに自動保存]が理想なので、
これからも昼休みの時間を使って改良していきます！！
手作業が多い人にとっては少し時短になるかと思います。
地味に検索が楽になるのでぜひ使ってみてください！


---
【応用情報】価格戦略

## プライスライニング戦略
数段階の価格帯の商品を展開する戦略。
価格によって品質が分かりやすく、消費者にとって選びやすくなるのが特徴。

## 威光価格戦略
商品の品質の良さやステータスを訴えるために意図的に価格を高く設定する。

## キャプティブ価格戦略
商品本体の価格を安く設定し、関連消耗品の販売で利益を得る。

## スキミング価格戦略
新商品に高い価格を設定して早い段階で利益を回収する。
【macOS】Homebrewで入れたNginxが"error 1 root"になるときの対処法

Nginxでローカルサーバーを立ち上げようとした時に詰まったので備忘録

結論、sudoでNginxをスタートさせると、少し手を入れないと一般ユーザーでうまく立ち上がらなくなるということがわかりました。

理由としては、brew services は LaunchAgent をユーザーレベルで管理する前提ですが、sudo で起動してしまうと LaunchDaemon（システムレベル）に登録されてしまい、一般ユーザーでは解除・制御できなくなるためです。

今回の問題の根源は最初に管理者権限でNginxをスタートさせたことでした。
```zsh
sudo brew services start
```
以降、一般ユーザーでスタートさせても、
```zsh
brew services list
```
で確認すると
```zsh
nginx   error  1 root ~/Library/LaunchAgents/homebrew.mxcl.nginx.plist
```

となっていました。


試したこと

```zsh
brew services stop nginx
rm -f ~/Library/LaunchAgents/homebrew.mxcl.nginx.plist
```

試していませんが、以下のように権限を変更しても戻せたかもしれません。
```zsh
sudo chown -R $(whoami):admin /opt/homebrew/opt/nginx
sudo chown -R $(whoami):admin /opt/homebrew/Cellar/nginx
sudo chown -R $(whoami):admin /opt/homebrew/var/homebrew/linked/nginx
```
なお、whoamiは自身のユーザー名

さらに、こんな警告が出てくるので、macOSバックグラウンド項目からも削除しておきます。
「システム設定」→「一般」→「ログイン項目」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851826/319cbed2-82c2-4596-94a8-616cbe63d49b.png)

手動でrootが所有しているサービス定義ファイルを削除する（LaunchDaemonからrootサービスを削除する）
```zsh
sudo rm /Library/LaunchDaemons/homebrew.mxcl.nginx.plist
```

これで、一般ユーザーで立ち上げることができました。

すると、次の問題としてログファイルにアクセス権限がないと言われました。
```zsh
open() "/opt/homebrew/var/log/nginx/access.log" failed (13: Permission denied)
```
```zsh
sudo chown -R $(whoami):admin /opt/homebrew/var/log/nginx
```

無事起動
```zsh
nginx started user1 ~/Library/LaunchAgents/homebrew.mxcl.nginx.plist
```

一般ユーザーで作業したい場合になんとなくsudo使うと、Deamon消したりする作業が発生するので気をつけたい。
湘南ビーチFMを録音する

# はじめに
+ ラジオ好き。もちろんRadikoプレミアム
+ WindowsをRadiko録音アプリでラジオ録音サーバにしてGoogle Driveに保存して、iPhoneで好きな時に聴いている
+ タイムフリーでいいじゃんという意見もあるけど、１週間忘れることがある。録音したい
+ RadikoアプリはCMを流す必要があるため、早送りが弱い
+ Google Driveは音声も再生できるし、早送りも大丈夫。倍速とかはできないけど

# 湘南ビーチFM
+ [湘南ビーチFM](https://www.beachfm.co.jp/)というコミュニティFMラジオ局がある
聴くには
+ Webページ
+ SimulRadio（サイマルラジオ）
+ TuneIn Radio
+ ストリーミングURL
https://shonanbeachfm.out.airtime.pro/shonanbeachfm_c
http://shonanbeachfm.out.airtime.pro:8000/shonanbeachfm_c
+ radikoで聴けないので録音ができない

# で、Na Praiaを録音したい
+ ブラジル音楽をよく聴くので、鎌倉のカフェ「カフェ ヴィヴモン ディモンシュ」のマスター[堀内隆志さん](https://www.beachfm.co.jp/stafflist/524/)が湘南ビーチFMで日曜15時からやっている「Na Praia」を録音したい
+ 30分の番組。いつも聴きそびれる

# Ubuntuで録音する
+ Windowsでやっても面白くないので、Ubuntu Serverで録音する
+ Raspberry PiにUbuntu Server 24.04 LTSをインストール
+ ラズパイじゃなくてもなんでもいい
+ Ubuntuについてのセットアップは割愛

# [準備]UbuntuにGoogleドライブをマウント
↓ここを参考にGoogleドライブをマウントする

https://qiita.com/devzooiiooz/items/f08c7bb9e935a79f7367

# ストリーミングを録音する
前述の通り、湘南ビーチFMはストリーミングで聴くことができる。ストリーミングはffmpegで録音できる

# ffmpegのインストール

```sh:
sudo apt install ffmpeg
```
# シェルスクリプト
シェルスクリプト[na_praia_rec.sh]を作成。
```sh:~/na_praia_rec.sh
pico na_praia_rec.sh
```
中身はこれだけ
```sh:~/na_praia_rec.sh
#!/bin/sh
# ストリーミングのURLはどちらでも良い
url='https://shonanbeachfm.out.airtime.pro/shonanbeachfm_c'
# url='http://shonanbeachfm.out.airtime.pro:8000/shonanbeachfm_c'
# 出力先はマウントしたGoogle Drive
outpath='/home/hogehoge/mnt/gdrive/'
# ファイル名のフォーマット
fn=`date "+%Y_%m%d_%H%M%S_Na_Praia.m4a"`
# 録音時間(30分+前後１分=>32分=1920秒)
sec=1920
# 録音コマンド（ログは捨てる）
ffmpeg -i $url -t $sec -vn -ac 2 -acodec aac $outpath$fn > /dev/null 2>&1
```
保存したら実行権限をつける
```sh:
chmod 755 ~/na_praia_rec.sh
```
### テスト
シェルスクリプトを実行
```sh:
./na_praia_rec.sh
```
#### 確認
プロセスが表示されていればOK
```sh:
ps aux | grep ffmpeg
hogehoge    5009 29.3 10.8 676684 100028 pts/0   RLl  20:41   0:20 ffmpeg -i https://shonanbeachfm.out.airtime.pro/shonanbeachfm_c -t 1920 -vn -ac 2 -acodec aac /home/hogehoge/mnt/gdrive/2025_0518_204123_Na_Praia.m4a
```
ファイルサイズが増えているか
lsを何秒か毎に実行してファイルサイズが増えているか確認
```sh:
ls -la mnt/gdrive | grep Na_Praia
```
OKであればテスト終了。プロセスをkill
psで確認したPIDをkill
```sh:
kill PID
```

## cronに登録する
crontabを編集
```sh:
crontab -e
```
毎週日曜日14:59にシェルを起動
```sh:crontab
# m h  dom mon dow   command
59 14 * * 0 /home/hogehoge/na_praia_rec.sh
```
確認
```sh:
crontab -l
```
日曜15時を待つ

# 余談
+ ストリーミングURLが分かれば湘南ビーチじゃなくてもいける気が
Javaの基礎復習１

JavaSilverの取得を目指すにあたり、基礎から今一度復習しましたのでまとめていきます。
継承が特に詰まりました・・・


## クラスの継承について
まず継承とは、あるクラス（スーパークラス・親クラス）のフィールドやメソッドといった機能を別のクラス（サブクラス・子クラス）が引き継ぐといった仕組みのことを言います。
```
// 親クラス（スーパークラス）
class Animal {
    void speak() {
        System.out.println("動物が鳴きます");
    }
}

// 子クラス（サブクラス）
class Dog extends Animal {
    void bark() {
        System.out.println("ワンワン！");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.speak();  // 親クラスのメソッドを使える！
        dog.bark();   // 子クラス独自のメソッド
    }
}
```
上記のコード例でいうとDogクラスをインスタンス化した変数dogでも、継承したAnimalクラス（親クラス）のメソッドであるspeakメソッドを呼び出せるようになるということです。

クラスを継承するときはextendsというキーワードを使用してどのクラスを継承するかを指定します。

ちなみにJavaでは継承できるクラスは一つだけです。多重継承したい場合はインターフェースを使います。（今回は省略）

## オーバーライドについて
オーバーライドとは親クラスに定義されているメソッドを子クラスで再定義することが出来ます。
この時オーバーライドの条件として下記のような３点があります。

・メソッドのシグニチャ（メソッド名、引数の型・数・順番）が同じであること

・戻り値の型が同じかそのサブクラスであること

・アクセス修飾子は親クラスと同じかそれよりも緩いこと
```
// 親クラス（スーパークラス）
class Animal {
    void speak() {
        System.out.println("動物が鳴きます");
    }
}

// 子クラス（サブクラス）
class Dog extends Animal {
    @Override
    void speak() {
        System.out.println("犬が鳴きます");
    }
}
```
また継承したクラスはインスタンス化した際に親クラスの型で扱うことが出来ます。
```
class Animal {
    void speak() {
        System.out.println("動物が鳴きます");
    }
}

class Dog extends Animal {
    @Override
    void speak() {
        System.out.println("犬が鳴きます");
    }
    
    void bark() {
        System.out.println("ワンワン！");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        Animal animal = new Dog();
        
        dog.speak(); // 犬が鳴きます
        dog.bark(); // ワンワン！
        animal.speak(); // 犬が鳴きます
        animal.bark(); // ※子クラス固有のメソッドはエラー!!
    }
}
```
上記のようにDogクラスのインスタンスはDog型だけでなく、Animal型としても扱うことが出来ます。注意点として、親クラスの型で扱う場合は子クラス固有のメソッドは呼び出せなくなります。

またspeakメソッドのようにオーバーライドしている場合は、親子どちらのクラス型で扱おうがオーバーライドしたメソッドが呼び出されます。


## 継承の禁止
下記のようにfinal修飾子を付けることで、クラスの継承を禁止することが出来ます。
```
final class Animal {}

class Dog extends Animal {} // コンパイルエラー！
```

## 継承時のコンストラクタの扱いについて
親クラスに引数ありのコンストラクタがある場合は、子クラスのコンストラクタの先頭で明示的に呼びだしてあげなければなりません!!
```
class Animal {
    Animal(String name) {
        System.out.println("Animal: " + name);
    }
}

class Dog extends Animal {
    Dog() {
        super("ポチ") // 親クラスのコンストラクタを呼び出す！
        System.out.println("Dogのコンストラクタ");
    }
}
```
この時は親クラスのコンストラクタ→子クラスのコンストラクタの順番で実行されます。

また、親クラスのコンストラクタが引数なしの場合は明示的に呼び出さずとも自動的にsuper();が追加されるのでエラーにはなりません。


以上
音声で「思いつき」を記録！iPhoneショートカット×GASで最強メモ術

# 概要
iPhoneのショートカットアプリとGoogle Apps Script (GAS) を連携させて、音声入力した内容をGoogleスプレッドシートに自動記録する方法を紹介します。
例えば、「今日の作業メモ」「日記」「アイデアのメモ」などを、手を使わずに記録したい人におすすめです！

# 背景・モチベーション
体重を記録したいのですが、パッとスマホにメモしてもスプレッドシートに転記することが面倒で長続きしません。

そこで、「声で記録→スプレッドシートに蓄積→あとで整理」という流れがあれば続けられるのでは？と思い、作ってみました。

# 構成と仕組み
この仕組みは、以下の3つのステップで構成されます。

0. 受信用のグーグルスプレッドシートを作成
1. iphoneのショートカットで音声入力 → テキスト（数値）変換
2. Webhook（URL）を叩いて、データを送信
3. Google Apps Scriptでスプレッドシートに記録

# 必要なもの
iPhone（iOS 14以上推奨）
Googleアカウント
Googleスプレッドシート
( Google Apps Script（GAS）の基本知識（Chatgptに聞けばよい？）)

# 手順
## Googleスプレッドシートの準備
新しいスプレッドシートを作成

A列に日付、B列にメモ内容を入れるとします（列はお好みで）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/915299/27b264b0-5f3e-4d24-ad61-7dbe21daa327.png)

2. Google Apps Script（GAS）の作成
GoogleDrive上でスプレッドシートを作成し、メニュー「拡張機能」→「Apps Script」を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/915299/7d3f592d-fa0a-467e-b9a3-b5096124d3c5.png)

以下のコードをコピペ：

```
function doPost(e) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("シート1");
  var data = JSON.parse(e.postData.contents);
  var date = new Date();
  
  // YYMMDD形式に整形
  var yy = String(date.getFullYear()).slice(-2);
  var mm = ("0" + (date.getMonth() + 1)).slice(-2);
  var dd = ("0" + date.getDate()).slice(-2);
  var formattedDate = yy + mm + dd; // 例: 230518

  sheet.appendRow([formattedDate, data.weight]);
  return ContentService.createTextOutput("Success");
}
```

デプロイ → 「新しいデプロイ」→ 「ウェブアプリ」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/915299/9d882983-190a-411c-975b-dea5afbdcf0e.png)

何かしら警告が出る場合がありますが、とりあえず無理やりOKにすればよいです（ログ取り忘れました）。
OKを押すとURLが表示されるので（図赤矢印）、コピーして保存しておいてください。あとでiphone上にて使います。
また、このＵＲＬは勝手に操作される可能性があるため、他人には教えないでください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/915299/a309e691-5df6-47e1-9904-c9e762d2ab37.png)




## iPhoneショートカットの作成
ショートカットアプリを開き、「+」から新規作成
下記アイコンです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/915299/94fca197-1d90-429c-b8b7-2c864347e87b.png)

1. アクション追加 → 「テキストを音声入力」

2. アクション追加 → 「音声入力されたテキストから数字を取得」

3. URL（ここで前の章で手に入れたURLを張る）

4. URLの内容を取得
  　方法：POST
    ヘッダ：（さわらず）
    本文を要求:JSONを選択。また新規フィールドを追加し、weight と　数値を選択する。

実際の画像例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/915299/ba9dd13f-45f7-4509-a821-368aa73c5a6d.png)

# 実行してみる
右下の三角形で実行

音声入力のアイコンが立ち上がってくるので、数値（体重）をしゃべる → その内容がスプレッドシートに記録される！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/915299/40ad149b-b07d-4df2-ad68-237f3f390617.png)


# 応用アイデア
* 毎日の日記記録

* 育児・健康記録（例：「赤ちゃんがミルク飲んだ」）

* アイデアメモのログ保存

 
# 注意点・ハマりポイント
GooglespreadSheetのURLを「全員に公開」する設定は慎重に。URLが漏れると、他人に書き込まれます。
iphoneの設定がわかりづらいです。まずは上記のままやって、通信できるかを確認するとよいかも？


# まとめ
「音声入力でスプレッドシート記録」は、アイデアを逃さず、整理もしやすい仕組みです。
ちょっとした工夫で手軽に記録できるようになるので、誰でもすぐ始められるので、ぜひ試してみてください！

# コメント・フィードバック歓迎！
もっと便利なショートカットのアイデアや、応用事例があればぜひ教えてください！
トリボナッチ・パターン

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/54840d9b-7958-4d71-9959-f630e2ac6365.png)

# トリボナッチ・パターン
トリボナッチ数列に基づき、非周期パターンを生成。

# フィボナッチ数列
```math
F_0 = 1
```

```math
F_n = F_{n-1} + F_{n-2}
```
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|1|2|3|5|8|13|21|34|55|89|144|

# トリボナッチ数列
```math
T_0 = 1
```

```math
T_n = T_{n-1} + T_{n-2} + T_{n-3}
```
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|0|0|1|1|2|4|7|13|24|44|81|149|
|1|1|1|3|5|9|17|31|57|105|193|355|

０開始と、１開始がある。

https://ja.wikipedia.org/wiki/フィボナッチ数

# プログラム

```java
String[] T = new String[20];
String patternX, patternY;
int cellSize = 8;  // 細かくする

color colA = color(230, 100, 100);  // a = 赤系
color colB = color(100, 230, 100);  // b = 緑系
color colC = color(100, 100, 230);  // c = 青系

void setup() {
  size(800, 800);
  generateTribonacci(14);    // n = 13 まで含むように生成
  patternX = T[13];           // 横糸（長さ：約2300以上）
  patternY = T[12];           // 縦糸

  int cols = width / cellSize;
  int rows = height / cellSize;

  println("織物サイズ: " + cols + "列 × " + rows + "行");

  noStroke();
  for (int y = 0; y < rows; y++) {
    char chY = patternY.charAt(y % patternY.length());
    color cy = getColorFromChar(chY);
    for (int x = 0; x < cols; x++) {
      char chX = patternX.charAt(x % patternX.length());
      color cx = getColorFromChar(chX);

      // 色の混合（交差点）
      color mix = lerpColor(cx, cy, 0.5);
      fill(mix);
      rect(x * cellSize, y * cellSize, cellSize, cellSize);
    }
  }
}

color getColorFromChar(char ch) {
  if (ch == 'a') return colA;
  if (ch == 'b') return colB;
  return colC;
}

void generateTribonacci(int n) {
  T[0] = "a";
  T[1] = "b";
  T[2] = "c";
  for (int i = 3; i <= n; i++) {
    T[i] = T[i - 1] + T[i - 2] + T[i - 3];
  }
}
```
Visual studio2022でDLLのデバッグをするには(C# WPF)

Teratailで偶然```DLLのデバッグ方法がわからない```という投稿を見かけたので(基本的に役立たずなので全く使わない)、深堀りしてみることにしました。初心者のころだけですね、使うのって。

最近は生成ＡＩもあるから猶更って感じで。

まあこんな質問あるんだから需要あるよね？っていうカンジで

でも一文にもならないんだよなあ:fearful:
せめて10いいねぐらいついて欲しい（笑）


## 前回の記事

https://qiita.com/EndOfData/items/50c025f1a1a0aaea850f

# 参考URL
Microsoft Learn

https://learn.microsoft.com/ja-jp/visualstudio/debugger/how-to-debug-from-a-dll-project?view=vs-2022

Visual Studioで外部ソースを含めたデバッグを実行する

https://blog.yucchiy.com/2022/01/debugging-external-sources-with-vs/

DLLのデバッグ方法

https://www.myway.co.jp/column/detail.php?id=5070


【C++】Visual StudioでDLLをデバッグする方法

https://shimons-labo.blog.jp/archives/31836174.html

# 自作のDLLをデバッグしてみる

前提はWPF、Visual studio2022です。


DLLの読み込み方法は静的ロードと動的ロードがありますが、基本的に静的なロード(Visual studioの```HintPath```に登録する)で行うことにします。(多分簡単に反映されるのは動的ロードの方)

以下を参考
	[DLLを外部プロジェクトに登録してみた](
https://qiita.com/EndOfData/items/50c025f1a1a0aaea850f#%E5%AE%9F%E8%A1%8C%E7%B5%90%E6%9E%9C%E8%87%AA%E4%BD%9C%E5%93%81%E3%81%AB%E9%81%A9%E7%94%A8)


この手順を行った上で(それほど難しくない)、```.pdb(シンボルファイル)```を実行ファイルと同じディレクトリに配置します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/620eb7c0-6c36-4c45-a120-5b2f6770907e.png)


``マイコードのみを有効にする``のチェックを外しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/6315c923-f9b2-4f47-80aa-0f45a1cb3f91.png)


:::note alert
### .pdbファイルを生成させるには

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/38014848-7b94-4ff5-a25b-254260aa3580.png)


プロジェクトのプロパティで```デバッグ シンボル```を選択すれば出力されます。　デバッグシンボルがない場合の手順は後日調べます(かなり難しいのでは)。
:::

# デバッグしてみる

前提としてデバッグシンボルが正常に読み込まれているか確認してください。

***デバッグ実行中に***``ウィンドウ``　→　``モジュール``を開きます。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/12177f16-a012-4fcb-8058-ae10ae853113.png)


正常に読み込まれた場合、``シンボルが読み込まれました``と表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/27c1a09a-3988-4d9a-a4de-0718102d4a7f.png)


シンボル読み込み情報
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/ebc83c6c-b830-4950-9e0d-8e60d406c5f0.png)


シンボルファイル``Targetdll.pdb``が読み込まれない場合はデバッグできません。



試しに削除してみましょう。

# ``.pdb``を削除するとデバッグできない

※キャッシュがあると再現できないため検索して削除しておく(通常はobjフォルダ内にある)


```PDB ファイルを開けないか、ファイルが見つかりません。```

と表示され、デバッグポイントで引っ掛からない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/0ffb4b1e-a24f-407d-810b-97df99703885.png)


# あとがき
そもそもWPFコントロール登録時、呼び出しクラスとコントロールがinternalだったせいで、そこだけてこずりました（笑）

チャンネル登録、高評価、面白かったらいいね、面白くなかったら悪いね、参考になったらLGTM、ストック、読み疲れたらTwitterへのフォローが励みになります。


個人的な信仰についてのツイート

https://x.com/sheephuman/status/1850098473535967568
AIエディターのコスト問題：CursorとClineを併用、VSCodeの標準機能や拡張機能を最大限に使う

# AIツールはコスト問題を避けて通れない

おそらく大企業であったとしても、AIツールのコスト問題は避けて通れないと思います。
よほどの大企業であればもしかしたら、無尽蔵に近いぐらいのAIツール使い倒しができるかもしれませんが、個人開発者、中小企業だとそうもいきません。

AIエディターについては、やはり定額で使えるCursor、GithubCopilot、WindSurfがよく使われていると思います。
私は、最初は、Clineを使っていました。プロジェクト初期に基底部分をつくるため、ガンガンエージェントにコードを作らせていたら、あっという間にCursorのProプランを超える金額に達しました。

それで、やっぱり定額のCursorにしてみようと思い、今はCursorをメインで使っています。

# プレミアムモデルの高速リクエストもあっという間に消費する

プロジェクトの後半になればリクエスも減るのかもしれませんが、やはり初期はかなりリファクタや直しが入ったり、新しい機能製造のために、エージェントを使うことが増えます。

Cursorも2日ぐらいでプレミアムモデルのリクエスも100回にいきました。そのとき、これはコスト管理しておいた方がいいのかなと思い始めました。

# コスト抑制方法の検討

多分、いろいろなやり方あると思いますし、Cursorで、追加料金を払って制限問題を解決するのも一つの手だと思います。今回は、Clineを使った案を書いてみます。

## 無制限モデルとManualモード

開発作業を改めて見返すと、AIエージェントにしてもらいたいけど、そんなに考えることもないようことが結構あります。たとえば、テストコード作るとか、簡単なモジュールであれば、CursorのManualモードでgpt-4o-miniをつかってコード書かせたりしてもそんなに問題がないと感じます。

ManualモードでつくったコードもChat画面で表示される、Applyボタンをおせば、ファイルを書き換えてくれたりしますし、コード内でチャットウィンドウを開いて直してもよいと思います。

エージェントモードより少し手数が増えますが、それでもファイル内容をコーディングしてくれるだけでもかなり楽です。

## Clineと併用

CursorもVSCodeをベースに作られているので、Clineは当然使えます。
.clinerulesと.cursor/rulesの併用になるところを工夫すれば、併用はできます。以下の手順でrulesを共有すれば良いと思います

:::note info
**cursorとclineのrules共有**
- .clinerulesフォルダを非表示にする
- cursor/rules配下のフォルダやファイルのシンボリックリンクを.clinerulesフォルダに作成
:::

https://zenn.dev/microsoft/articles/vscode-exclude-files

上記の設定を手動でしてもいいし、clineとかに作らせてもいいと思います。
これでcursorとclineのrulesが共有されます。clineにrules内の情報を質問してみると、rules内で定義した内容を返してくれます。

あと、右ペインがCursor専用になっているので、エディタペインで開いて使うのがよいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15972/6f806c73-92e1-4678-9b00-b140bd0fd3db.png)

ペインが多すぎて醜い場合はワークスペースを複製してウィンドウで開けばよいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15972/1dbae28c-4e7b-4151-870c-4c57ee810884.png)



Clineは従量制ですが、Geminiなど安いモデルを使えば、そこまでコストをかけなくてもエージェント利用ができます。無料枠もありますし。

https://qiita.com/SFITB/items/5d5e5db1c00d6954571b


## VSCodeの標準機能や拡張機能を最大限に使う

AIエージェントを使い出すとなんでもAIエージェント任せにしてしまいがちですが、もともと手動開発でつかっていた標準機能や拡張機能を使ってエージェント以外の工数削減をするのがよいと思います。
ファイル移動に伴うimport文の修正とかいろいろとエージェント関係なくできることもあります。

# さいごに

費用をきにせずガンガン使えればAIエージェントに全部させてもいいのですが、2025年5月時点ではそうもいかない人は少なくないと思います。

AIが便利なのは確かですが、やはり何度となくやりとりが発生します。そのたびごとにコストがかかります。早く、モデル利用のコストを気にしなくなる日がくればいいなとも思います。

あとは、なんでもAIに任せるという発想もときに、回り道になることもあると思いました。AI使わなくても済むならそれにこしたことないきもします。
Node.js で  YouTube Data API（v3）を軽く試す： 動画のタイトルの取得

## はじめに

以下の YouTube Data API を少し Node.js で試してみた話です。

●YouTube Data API の概要  |  Google for Developers
　https://developers.google.com/youtube/v3/getting-started?hl=ja


## さっそく試す

それでは、さっそく試していきます。


### プロジェクトの新規作成

以下の手順で、今回用のプロジェクトを新しく作ります。

●プロジェクトを作成  |  Google App Engine standard environment docs  |  Google Cloud
　https://cloud.google.com/appengine/docs/standard/nodejs/building-app/creating-project?hl=ja

名前は、分かりやすい適当な名前にしました。


### APIキーの取得

上記で作ったプロジェクトで APIキーを作成します。

[公式のクイックスタート（Node.js用）のステップ1](https://developers.google.com/youtube/v3/quickstart/nodejs?hl=ja#step_1_turn_on_the) に書かれた「こちらのウィザード」というテキストのリンクを開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/1355479f-7346-4b34-8775-70fdbaf9627c.png)


選択されたいるプロジェクトが、意図したものであることを確認して、YouTube Data API v3 を有効にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/b74dff6c-87ea-4b37-b2b3-3a919d8e3a9f.png)


あとは、認証情報のページ（ https://console.cloud.google.com/apis/credentials ）の画面上部の「＋ 認証情報の作成」から、APIキーを作成します。
APIキーが作成された後は、APIキーの名前を分かりやすいものにしたり、API の制限で「YouTube Data API v3」のみを対象にしたり、ということを行いました。

そして、この時に作成した APIキーをメモしておきます。


### Node.js で  YouTube Data API を使う

あとは、Node.js で  YouTube Data API を使ってみます。内容はシンプルなものにします。

#### 下準備

下準備として、以下のパッケージ（[Google APIs Node.js Client](https://www.npmjs.com/package/googleapis)）をインストールします。

```zsh
npm install googleapis
```

また、上で作成した APIキーを YOUTUBE_API_KEY という名前の環境変数で使えるようにしました。


#### Node.js での実装・処理の実行

Node.js で実装した内容は以下のとおりです。

[自分が過去にアップロードした動画](https://www.youtube.com/watch?v=hC7aml8pTa0)を指定して、そのタイトルを取得するという簡単な内容のものです。


```javascript
import { google } from "googleapis";

const apiKey = process.env.YOUTUBE_API_KEY;
if (!apiKey) {
  console.error("環境変数 YOUTUBE_API_KEY が設定されていません");
  process.exit(1);
}
const youtube = google.youtube({ version: "v3", auth: apiKey });

// 動画IDを指定： https://www.youtube.com/watch?v=hC7aml8pTa0
const videoId = "hC7aml8pTa0";

async function fetchVideoTitle(videoId) {
  const res = await youtube.videos.list({
    part: ["snippet"],
    id: [videoId],
  });
  const snip = res.data.items?.[0]?.snippet;
  return snip ? snip.title : null;
}

(async () => {
  try {
    const title = await fetchVideoTitle(videoId);
    console.log("動画タイトル:", title);
  } catch (err) {
    console.error("動画タイトル取得中にエラー:", err);
    process.exit(1);
  }
})();

```

上記を実行した結果は以下のとおりです。[自分が過去にアップロードした動画](https://www.youtube.com/watch?v=hC7aml8pTa0)のタイトルを取得できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/043541d3-3505-498d-956d-9bd555aff1dd.png)
MacBook M4Pro での LoRA 機械学習実行ガイド

. はじめに
１ 目的と概要
* MacBook M4Pro の強化された GPU 機能を活用して、LoRA を用いた機械学習を実施します

２ 使用するツール・技術
* LoRA の CLI ツールを使って学習を行います。LoRA には Web ツールもありますが、Apple Silicon では fp16 に関連する制約があるため CLI ツールを利用します

2. 前提条件
必要な環境
* ハードウェア: MacBookPro M4Pro, メモリ 24GB
* 注: M4 や M3 系ではパフォーマンス不足の可能性あり
* ソフトウェア: Python 3.10, LoRA, accelerate

３. セットアップ手順
```bash
mkdir ~/kohya_lora && cd ~/kohya_lora
git clone https://github.com/bmaltais/kohya_ss.git
cd kohya_ss
python3.10 -m venv venv
source venv/bin/activate
pip install --upgrade pip setuptools wheel
pip install -r requirements.txt --extra-index-url https://download.pytorch.org/whl/cpu
pip install accelerate toml diffusers torch torchvision opencv-python transformers einops
```

４. コマンド解説
* accelerate launch:
Hugging Face 提供の分散トレーニング支援ツール
* train_network.py:
LoRA の CLI ツールとして機能します

５. パラメータ詳細
* --train_data_dir: 学習データディレクトリの指定。パス構成に注意
/モデルインストールパス/学習ステップ数_モデル名 のようにフォルダ構成を作る必要があり、コマンドに指定するのは/モデルインストールパス/の部分
* --output_dir: 出力ディレクトリ。書き込み権限が必要
* --optimizer_type=AdamW: 8 ビット系パラメータは非対応
* --mixed_precision=no, --no_half: Apple Silicon での 16 ビット浮動小数点計算を無効化

６. 実行手順
コマンド実行例
```bash
accelerate launch ./sd-scripts/train_network.py \
  --pretrained_model_name_or_path=runwayml/stable-diffusion-v1-5 \
  --train_data_dir=/Users/<ユーザ名>/LoRA/kohya_ss/dataset/images \
  --output_dir=/Users/<ユーザ名>/LoRA/kohya_ss/dataset/outputs \
  --resolution=512 \
  --network_module=networks.lora \
  --network_dim=8 \
  --network_alpha=8 \
  --train_batch_size=1 \
  --gradient_accumulation_steps=4 \
  --learning_rate=1e-4 \
  --max_train_steps=2000 \
  --mixed_precision=no \
  --no_half \
  --cache_latents \
  --optimizer_type=AdamW \
  --save_model_as=safetensors
  ```

７.期待される出力
学習結果は /Users/<ユーザ名>/LoRA/kohya_ss/dataset/outputs に保存され、Stable Diffusion などで使用可能です。

８. おまけ
学習中のアクティビティモニタのスクリーンショットも併せてご紹介します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136860/7ef174ff-b755-4d70-818a-f738b5e01534.png)
意外とメモリには余裕がありそう、LoRaを動かすには24Gあれば十分
トリボナッチ・木構造

# トリボナッチ・木構造
トリボナッチ数列に基づき、木構造を描く。
L-Systemと同様の結果。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/05d91b29-65b3-4f06-a10b-02d3bcd90ebf.png)

# フィボナッチ数列
```math
F_0 = 1
```

```math
F_n = F_{n-1} + F_{n-2}
```
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|1|2|3|5|8|13|21|34|55|89|144|

# トリボナッチ数列
```math
T_0 = 1
```

```math
T_n = T_{n-1} + T_{n-2} + T_{n-3}
```
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|0|0|1|1|2|4|7|13|24|44|81|149|
|1|1|1|3|5|9|17|31|57|105|193|355|

０開始と、１開始がある。

https://ja.wikipedia.org/wiki/フィボナッチ数

# プログラム

```java
float angle = PI / 5;
int maxDepth = 10;

void setup() {
  size(400, 300);
  background(255);
  stroke(0);
  translate(width/2, height);
  drawTribonacciBranch(100, maxDepth);
}

void drawTribonacciBranch(float len, int depth) {
  if (depth < 1) return;

  line(0, 0, 0, -len);
  translate(0, -len);

  if (depth - 1 >= 1) {
    pushMatrix();
    rotate(-angle);
    drawTribonacciBranch(len * 0.7, depth - 1);
    popMatrix();
  }

  if (depth - 2 >= 1) {
    pushMatrix();
    rotate(0);
    drawTribonacciBranch(len * 0.7, depth - 2);
    popMatrix();
  }

  if (depth - 3 >= 1) {
    pushMatrix();
    rotate(angle);
    drawTribonacciBranch(len * 0.7, depth - 3);
    popMatrix();
  }
}
```
NestJSのモジュール　実践的に解説！

## NestJSのモジュールについて

NestJSの「モジュール」はアプリケーションを機能ごとに分割して管理・拡張しやすくする重要な要素です。本記事ではモジュールの役割、作成方法、実践的な設計手法について詳しく解説します。

### モジュールとは？

NestJSにおいてモジュールとは、関連するコンポーネント（コントローラー、サービス、リポジトリなど）をまとめて管理するための仕組みです。モジュールを利用することで、コードの整理、再利用性の向上、依存関係の明確化ができます。

### モジュールの構成要素

モジュールは通常、以下の要素から構成されます。

* **imports**: 他のモジュールをインポートして、機能を利用する
* **controllers**: リクエスト処理を担うコントローラーを定義
* **providers**: サービスやリポジトリなど、依存性注入の対象を定義
* **exports**: 他のモジュールで利用可能にする要素を定義

### 基本的なモジュールの作成方法

Nest CLIを使用してモジュールを作成します。

```bash
nest generate module users
```

これにより`users.module.ts`が作成されます。

```typescript
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  controllers: [UsersController],
  providers: [UsersService],
  exports: [UsersService],
})
export class UsersModule {}
```

### モジュールとディレクトリ構造の関係性

NestJSでは一般的に各モジュールは独立したディレクトリ内に作成されます。モジュールに関連するコントローラー、サービス、DTOなどは同じディレクトリ内で管理することで、可読性と保守性が向上します。

例:

```
src/
├── app.module.ts
├── users
│   ├── users.module.ts
│   ├── users.controller.ts
│   ├── users.service.ts
│   └── dto
│       └── create-user.dto.ts
├── auth
│   ├── auth.module.ts
│   ├── auth.controller.ts
│   └── auth.service.ts
└── products
    ├── products.module.ts
    ├── products.controller.ts
    └── products.service.ts
```

### 実践的なモジュールの設計方法

#### 1. 機能ごとのモジュール化

実務では、機能ごとに細分化したモジュールを作ることが推奨されます。

例:

* UserModule（ユーザー関連機能）
* AuthModule（認証機能）
* ProductModule（商品管理機能）

#### 2. モジュール間の依存関係管理

依存関係がある場合は`imports`で関連モジュールをインポートします。

```typescript
@Module({
  imports: [AuthModule, DatabaseModule],
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}
```

#### 3. 共通モジュールの作成

データベース接続や設定管理など、複数モジュールで共通する処理は専用のモジュールにします。

```typescript
@Module({
  providers: [DatabaseService],
  exports: [DatabaseService],
})
export class DatabaseModule {}
```

これにより、再利用性が向上します。

### 実際のプロジェクトでのベストプラクティス

#### 明確な依存関係

各モジュールの責務を明確にし、必要なモジュールだけをインポートしましょう。

#### モジュールの分割

巨大になったモジュールは機能単位で細かく分割して管理性を高めます。

#### レイヤードアーキテクチャの採用

機能に加えて、データアクセス層、ビジネスロジック層など、レイヤー別のモジュール化も効果的です。

```typescript
@Module({
  imports: [DatabaseModule],
  providers: [UserRepository],
  exports: [UserRepository],
})
export class UserRepositoryModule {}
```

### まとめ

NestJSのモジュール設計はプロジェクトのスケーラビリティや保守性を大きく左右します。実務では適切な粒度でモジュールを設計し、明確で再利用可能な構造を心がけましょう。
プリザンターで特権ユーザでログインしていることをわかりやすくする方法

## はじめに
プリザンターのユーザ権限の1つである「特権ユーザ」サイトやレコードのアクセス権限の設定を無視して最上位の権限を取得出来るSuperユーザですが、ログイン後に特権ユーザであることを視覚的に捉えるわかりやすい方法がありません。
今回はこれを改善する方法を紹介します。

## 実装してみた
今回はズバリで拡張スタイルを使って実装します。特権ユーザであることが直接取得できる方法があれば良いのですが、現状は方法がないのでユーザIDを使用します。ユーザIDはHTMLのBody要素の先頭にinputタグ群があり、その中でセットされているところがあります。今回はユーザIDは1ですが、各自の環境で読み替えてください。

```html
<!--関係ない部分は省略しています-->
<html>
    <body>
        <input id="UserId" name="UserId" type="hidden" value="1">
    </body>
</html>
```

CSSで書くと`:has(#UserId[value="1"])`です。これを使って背景色を変更します。

```css:PrivilegeUserBackGround.css
body:has(#UserId[value="1"]) {
    background: red;
}
```
これを拡張スタイルとして適用します。適用すると下記の様になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3555395/062a2b0e-3c69-4186-a6d0-85d8b5607b99.png)

赤一色になり通常のユーザとは異なるユーザであることが一目で分かります。背景色は赤にしていますが、環境に合わせていろいろと変更してみてください。
特権ユーザが複数の場合は、上記のCSSのセレクタをカンマで連結するなどして対応します。

## まとめ
今回は特権ユーザであることを分かりやすくる方法を紹介しました。この方法は、特権ユーザ以外でも特定の組織に所属しているアカウントの背景色を変えるなどいろいろと応用が利く方法なので、是非試してみてください。
📘 Obsidian × Cursor で爆速知的生産：AIと一緒にメモを「資産」に変える方法

## はじめに：メモは“ためるだけ”ではもったいない

紙のノート、メモアプリ、付箋…。情報は毎日蓄積されますが、**見返さない・使えない・つながらない**。  
そこで登場するのが、「**Obsidian × Cursor**」の連携。

- **Obsidian**：構造的にメモを蓄積できるMarkdownベースの最強メモアプリ  
- **Cursor**：AIエージェントが知識を理解・再構成してくれるコードエディタ

この2つを組み合わせれば、**メモが“知的資産”として循環しはじめます**。

---

## ステップ①：Obsidianで知識を蓄積

### ✅ 導入
- [Obsidian公式サイト](https://obsidian.md/)から無料インストール
- 新しいVaultを作成（例：`知的資産Vault`）

iCloud Drive との連携は、以下を参考にしてみてください。
Obsidian の初期構築と iCloud Drive 連携【前半】 
https://qiita.com/seiya-sugimoto/items/90c7d671f218c6341aee 

### ✅ テンプレ例：Daily Note

```markdown
# 2025-05-18

## 気づき（Fleeting Note）
- AIとの対話は、メモの外部化を加速する

## 読書メモ（Literature Note）
- 『アイデア大全』より「発信することでアイデアは磨かれる」

## 自分の考え（Permanent Note候補）
- 「内省＋AI対話」で思考は飛躍できるかも

```
## ステップ②：CursorでVaultを読み込む
### ✅ Cursorをインストール
・Cursor公式サイト(https://www.cursor.com/ja) からダウンロード
・初回起動後、テーマやキーバインドを設定（おすすめ：VS Code形式）

### ✅ ObsidianのVaultを開く
1．Open Project をクリック
2．iCloud DriveなどにあるVaultフォルダを選択（例：知的資産Vault）
3．.mdファイルが表示されればOK！

## ステップ③：AgentモードでAIに「整理・再構成」を依頼
Agent（Ctrl + I）：ファイルの中身をAIが読み込み、自動処理
Ask：雑談や質問用
Manual：手入力で文脈なし処理

### ✅ プロンプト例（Zettelkasten構造化）
```
このノートを「Zettelkastenメモ」として整理してください。
- 主張
- 出典
- 応用可能な場面
- 関連タグ
```

### ✅ 出力イメージ
```
# アイデアは「発信しながら育てる」もの

## 主張
アイデアは発信してこそ他者視点で洗練されていく

## 出典
2023年に読んだ『アイデア大全』

## 応用可能な場面
- SNS発信
- 会議でのアイスブレイク
- ブログの書き出し

## 関連タグ
#発信 #アイデア #Zettelkasten
```

## ステップ④：週ごとの知識をまとめて週報化
```
このフォルダのノートをまとめて「週次レポート」を作ってください。
構成は【要約】【重要な気づき】【今後やること】で。
```
→ AIが複数ファイルをまたいで構造的に整理してくれます！

## おわりに：Obsidianは「脳」、Cursorは「外部脳エージェント」
Obsidianでメモを蓄積し、

CursorのAIでメモを構造化・再利用し、

週報やSNS投稿、戦略ノートに展開していく。

この連携は、情報の流れを「インプット → 内省 → アウトプット」に変える知的生産フローになります。
DTOとインターフェイス

# DTOとインターフェイスの違い・用途を整理して理解する



## DTO（Data Transfer Object）とは？

DTOとは、主にデータをアプリケーションの異なる層間で転送するために使用されるオブジェクトです。

### 用途

* APIリクエスト・レスポンスの型定義
* 異なるレイヤー間のデータ受け渡し
* バリデーションや変換処理

### なぜ必要か？

* クライアントから受け取るデータや、サーバーから返却するデータの構造を明確にするため
* バリデーションを一元的に管理し、コードの安全性・可読性を高めるため

### いつ使うべきか？

* APIエンドポイントにおいて、データ構造を明確に定義したいとき
* 複数の層間でデータを渡す際に、データの変換・検証を明確にしたいとき

### どうやって使うか？

NestJSを例にすると、以下のように使います。

```typescript
import { IsString, IsEmail } from 'class-validator';

export class CreateUserDto {
  @IsString()
  readonly name: string;

  @IsEmail()
  readonly email: string;
}
```

---

## インターフェイスとは？

インターフェイスは型定義のための機能であり、特定の構造を持つデータ型やオブジェクトの構造を規定します。

### 用途

* オブジェクトの型定義
* コードの可読性向上と型安全性の確保
* 実装クラスが従うべき契約（約束）の定義

### なぜ必要か？

* コードの型安全性を保ち、予期しないエラーを防ぐため
* コードベース全体で一貫した構造を維持するため

### いつ使うべきか？

* 複数のクラスや関数が共通して利用するデータ構造を定義するとき
* メソッドやクラスに型安全な契約を課す必要があるとき

### どうやって使うか？

```typescript
export interface IUser {
  id: number;
  name: string;
  email: string;
}

const user: IUser = {
  id: 1,
  name: "Alice",
  email: "alice@example.com"
};
```

---

## DTOとインターフェイスの違いまとめ

| 項目         | DTO          | インターフェイス |
| ---------- | ------------ | -------- |
| 役割         | データ転送・変換・検証  | 型定義・契約   |
| バリデーション    | 可能（推奨）       | 不可能      |
| インスタンス化    | 可能           | 不可能      |
| NestJSでの利用 | コントローラー、サービス | 広く全体で使用  |

---

## 結局、使い分けのコツは？

* **DTOはアプリケーションの境界を超えてデータを転送するときに使う。**
* **インターフェイスは内部の型安全性とコード品質を維持するために使う。**

上記の原則を念頭に置いて設計すると、シンプルかつ安全なコードが書けるでしょう。

---
【Next.js (App Router) × microCMS × Netlify】リッチエディタの埋め込みが表示されない問題を解決した話

<br>

クライアントから連絡がありCMSの埋め込み機能を使って外部サイトリンクを置いた時「リロードをしないと表示されない」と連絡が来たので急遽対応しました。
## 1. 問題

- microCMSのリッチエディタの機能の埋め込みがリロードしないと表示されない

## 2. 環境

| 項目 | バージョン |
| --- | --- |
| Next.js | 15 (App Router) |
| Netlify | サイト設定 `output: "standalone"` |

---

## 3. 原因：embed.jsがロードされてない & iframely-embedが動いてない

検証ツールで該当部分を確認すると

```
<div class="iframely-embed">
    <div class="iframely-responsive" style="height: 140px; padding-bottom: 0;">
        <a href="https://www.example.jp" 
            data-iframely- url="https://cdn.iframe.ly/api/iframe?url=https....">
        </a>
    </div>
</div>
```

このようになっており正常な場合(リロード後)は画像のようにiframeタグが生成されています

![スクリーンショット 2025-05-18 20.46.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4055474/00f992fd-fdd6-4db5-bdba-82511576728a.png)

じゃあロードするようにすればいいんじゃねと思い以下のように解決しました。

---

## 4. **解決策**

```tsx
"use client";
import { useEffect } from "react";
import Script from "next/script";

export default function 省略....

  // content が変わるたびに再パース
  useEffect(() => {
    (window as any).iframely?.load();
  }, [content]);

  return (
    <>
      {/* embed.js を一度だけロード */}
      <Script
        src="https://cdn.iframe.ly/embed.js"
        strategy="afterInteractive"
        onLoad={() => (window as any).iframely?.load()}
      />

      {/* リッチテキスト本体 */}
      <div key={index} className={className}>
        ...
      </div>
    </>
  );
}
```

---

## 5.感想
一旦これで解決したので様子見です。
どなたか他にいい方法があればご教授して欲しいです。
ちなみにTikTokの埋め込みの場合は
```
<Script
    src="https://www.tiktok.com/embed.js"
    strategy="afterInteractive"
    onLoad={() => {
          (window as any).iframely?.load();
        }}
/>
```
これでいけます
【Android】EdgeToEdgeの対応のチートシート

# はじめに
Android SDK35以降から必要となる対応で対応内容などを調べなおしたりするのが面倒だと思ったので簡単なものをメモがわりに記事に残しておきます。

# 実装
ViewExtensionsなどで用意して各画面に書く。
もしくは、BaseActivityなどが広い画面に継承されている親クラスがあるならそこで実装するといい。
```
  ViewCompat.setOnApplyWindowInsetsListener(this) { v, windowInsets ->

    // インセットをビューのマージンとして適用します。
    // paddingでも可
    v.updateLayoutParams<MarginLayoutParams> {
      topMargin = insets.top
      bottomMargin = insets.bottom
      leftMargin = insets.left
      rightMargin = insets.right
    }

　　 // ウィンドウのインセットを子孫ビューに渡し続けたくない場合は、CONSUMED を返します。
    WindowInsetsCompat.CONSUMED
  }
```

# 参考

https://developer.android.com/develop/ui/views/layout/edge-to-edge
ExpressでSSEを使ってみた

## SSE(Server-Sent Events)とは？

SSE（Server-Sent Events）は、サーバーからクライアントに向けて**一方向に**リアルタイムでデータを送信できる仕組みのこと。HTTPを使用しているためテキストでの通信となります。
リアルタイム性が必要な通知機能、コメントのライブフィード、LLMのストリーミングなどで使われるようです。

SSEの他にリアルタイムで通信する技術にWebSocketがあります。
WebSocketはクライアントとサーバー間の相互通信が可能なため、クライアントからサーバーに向けての通信も必要な場合はWebSocketを使いましょう。

## 実装

Express で１秒ごとに0からカウントした値をクライアントに送信するコードを書いてみます。

### Expressサンプル

```javascript
const express = require("express");
const app = express();

app.listen(3000, () => {
  console.log("Server is running on port 3000");
});

app.get("/event", (req, res) => {
  res.setHeader("Content-Type", "text/event-stream");
  res.setHeader("Access-Control-Allow-Origin", "*"); // CORS は任意で設定

  let counter = 0;

  const sendData = () => {
    res.write(`data: ${counter}\n\n`);
    counter++;
  };

  const interval = setInterval(sendData, 1000);

  req.on("close", () => {
    clearInterval(interval);
    res.end();
  });
});
```

こちらのサンプルでは、`/event` へリクエストしてきたクライアントに対して値を返しています。
SSE を使用するには MIME タイプを `text/event-stream` に設定しましょう。
またデータを返却するときは、先頭に `data:` と 末尾に `\n\n` をつける必要があります。
通信が終了したときは、`res.end();` で HTTP レスポンスのプロセスを終了させましょう。

### クライアントサンプル

```javascript
const eventSource = new EventSource("http://localhost:3000/event");

eventSource.onmessage = (event) => {
  console.log(event.data);
};

eventSource.onerror = (err) => {
  console.error("Error", err);
};
```

クライアント側の実装も簡単です。EventSource に Express の情報を記載すると、onmessage イベントから受け取ったデータを取得することができます。
サンプルコードでは１秒おきに console.log で受け取った値を表示しています。