OmniAICreator/Qiita-1.07M huggingface dataset:
gRPC Keepalive に関するオプション

# gRPC Keepalive について

一般的に Keepalive と呼ばれているものには二種類があります。

- TCP Keepalive のようなもの
  - 定期的に ping を飛ばして死活監視をする
- HTTP Keepalive のようなもの
  - 通信が終わっても（一定時間は）接続を閉じずに次の通信を待つ

gRPC Keepalive と呼ばれているものは TCP Keepalive に相当するような機能です。もちろん、TCP Keepalive はトランスポート層で動作する一方、gRPC Keepalive はアプリケーション層で動作するなどの違いはあります。

gRPC Keepalive の主なユースケースは、ストリーミング通信を行っている最中に実際のデータのやり取りがない状態がしばらく続いた場合、相手がまだ生きているかどうかを確かめることです。

gRPC Keepalive に関連するプロポーザル:

- https://github.com/grpc/proposal/blob/master/A8-client-side-keepalive.md
- https://github.com/grpc/proposal/blob/master/A9-server-side-conn-mgt.md

一方で、gRPC では**デフォルトの状態で** HTTP Keepalive のようなものも実現されています。クライアントからチャンネルを閉じなければ、サーバ側から一方的に接続を閉じるようにはなっていません。この挙動は後述の「接続を閉じる条件の設定」によって変更可能です。

# gRPC のサーバ/クライアントでの設定項目

もし gRPC Keepalive を使用する場合は、サーバの設定でクライアントからの ping 受信を許容するようにしなければなりません。設定された頻度を超えて過剰な ping が送信されると、サーバは GOAWAY フレームを送信して切断することになります。多数のクライアントから想定を大きく超える数の ping がサーバになだれ込んでしまうと実質的な DDoS 状態に陥ってしまうため、このような仕様になっています。

下記のサンプルで実際に gRPC Keepalive を設定しているので、Python の場合のオプションの設定方法はこれを参考にしてください。

https://github.com/grpc/grpc/tree/master/examples/python/keep_alive

### gRPC Keepalive 自体の設定

- grpc.keepalive_time_ms
  - keepalive ping が送信されるまでの期間
  - サーバ側デフォルト: 2時間
  - クライアント側デフォルト: 無限（無効）

- grpc.keepalive_timeout_ms
  - keepalive ping を送信してから応答を待つ時間  
    タイムアウトすると接続を閉じる
  - サーバ側デフォルト: 20秒
  - クライアント側デフォルト: 20秒

- grpc.keepalive_permit_without_calls
  - 実行中の RPC がない状態でも ping の送信を許可 (0 : false; 1 : true) 
  - サーバ側デフォルト: 0
  - クライアント側デフォルト: 0

### gRPC Keepalive に関連する設定

- grpc.http2.min_ping_interval_without_data_ms
  - リクエストを送信せずに連続して ping の受信を受け付ける最小時間間隔
  - サーバ側デフォルト: 5分

- grpc.http2.max_pings_without_data
  - クライアントがリクエストを送信する前に送信できる ping の数（0 で無制限）
  - サーバ側デフォルト: 2
  - クライアント側デフォルト: 2

### 接続を閉じる条件の設定

- grpc.max_connection_idle_ms
  - チャネルに未処理の通信がない状態の最大時間  
    これが経過するとサーバは接続を閉じる
  - サーバ側デフォルト: 無限

- grpc.max_connection_age_ms
  - 通信の有無にかかわらずチャンネルが存在できる最大時間（寿命）  
    ロードバランサがサーバのスケーリングのために定期的に再接続させたい場合に利用される
  - サーバ側デフォルト: 無限

- grpc.max_connection_age_grace_ms
  - チャンネルが寿命に達した時点で通信が行われていた場合、その通信が終わるのを待つ猶予時間
  - サーバ側デフォルト: 無限
bits/stdc++.hをプリコンパイルしよう！！！

## はじめに
競技プログラミングをやっている高校生のButterFlvです！！
手元実行のコンパイル時におそらく最も時間がかかるであろう`bits/stdc++.h`のコンパイル時間を短縮する方法で、自分の環境でうまくいった方法を紹介します。

以下の記事を参考にさせていただきました。（全く同じことをすればできました。）ありがとうございます。MacOS版とありますがWindowsでもできました(なぜでしょうか...)

https://qiita.com/DaikiSuyama/items/e502e09a1090f4a2cee3

## 環境
:::note info
詳しくないのでわかりません。すみません。。。😢
:::

## 方法
#### ①コンパイラが置いてあるディレクトリで`bits/stdc++.h`を検索
このとき僕の環境では
```
\mingw64\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\x86_64-w64-mingw32\bits
```
と
```
\mingw64\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\x86_64-w64-mingw32\32\bits
```
の両方にありました。前者のディレクトリで作業するとうまくいきました。（前者は64bitで後者は32bitとかなのでしょうか）
#### ②コマンドプロンプトで以下を実行
```
mkdir stdc++.h.gch
g++ stdc++.h -o stdc++.h.gch/(適当なファイル名).gch
```

プリコンパイルする前と後で比較してコンパイルが爆速になっていることを確認してみてください。
色々な「文書のつくりかた」


# はじめに

## 本記事の目的
IT があまりよくわからない人向けに、文書のつくりかたを全体的に眺めてもらう。

## 文書とはページ or ドキュメント
本記事でいう文書とはページまたはドキュメントを指す。それなりの文章を表現する手段として、紙で表現された文書もあれば、ファイルの形の文書もあるし、ウェブページのような形の文書もある。

以下は含まない。

- 論文
- 雑誌やポスター（DPT含む）
- スライド

# ファイルの種類としては主に 4 種類
- テキストファイル
    - 素のテキストを書いたファイル
    - どこででも書けるし、どこででも読める
    - 例: テキストファイル（.txt）、Markdown(.md)
- リッチテキスト
    - 特定のアプリで読み書きするファイル
    - 例: Microsoft Office(.docx)
- 閲覧用ファイル
    - 書き込みはできず、専用のプロテクトがかかっている類のファイル
    - 例: PDF
- ウェブページ用のファイル
    - ウェブサイトとして表示する用のファイル
    - 例: HTML

# 各種類をどうやってつくるか（書くか）
テキストファイルは、**テキストエディタ** や **IDE** で書く。どちらもエンジニアやクリエイター、また IT に慣れた人などが使う道具であり、一般人は使わない。テキストエディタはテキストを書くのに特化したツールで、書くことを生業とするならおそらく避けられない。IDE は、元はプログラミング用の多機能ツール（統合開発環境）だが、テキストを書く手段としても使える。書くのは速いが、あまり込み入った見た目にはできない。

リッチテキストは、**専用のアプリ** で書く。単にテキストを入力するだけでなく、文字装飾をしたり、画像を入れたりなど豊富な編集ができる。見た目も自由自在である。その分、書くのは遅い。書けないことはないが、自転車でたとえるならこちらはママチャリだが、上述のテキストエディタや IDE はクロスバイクやロードバイクに相当する。同じ自転車（書く道具）でも、速さが違う。かんたんには使えるので、一般人はこれを使う。

閲覧用ファイルは、直接書くことはできない。リッチテキストか、テキストファイルから変換してつくる。

ウェブページ用のファイルは、テキストファイルと同様である。ただし、後述する SaaS でつくることもよくある。

# ファイル以外の選択肢として「SaaS」もある
近年では、自分でファイルをつくらず、SaaS（Webサービス）上でつくれるようにもなった。上述したエディタやアプリがなくても、ブラウザだけで文書をつくれてしまう。

いくつか例を挙げる。

- Wiki
    - （権限がある人は）誰でも自由にページをつくれるシステム
    - Wikipedia やゲーム攻略系の Wiki が有名
    - 会社や情報の情報をこれで貯めることもある
- ブログ
    - note、はてなブログなど多数存在する
    - 今皆さんが見ている Qiita も、このカテゴリに属する（エンジニア向けで高度、かつ扱うネタも IT だが）
- ウェブサイト
    - Google サイトなど、ブログのようにウェブサイトをつくるサービスもある
    - また企業向けとしてもよく見られる
        - Microsoft の SharePoint など（社内サイトつくったりとか）
- ドキュメント
    - Google ドキュメント、Microsoft OneNote、Box Notes、Dropbox Paper など多数存在する
    - Notion もこのカテゴリ
    - この中では最も後発であり、SaaS で（ページ的な）文書をつくる、かつ業務や個人で使うとなれば、先に挙がる選択肢だろう

# ややこしい観点たち

## 文書をつくることと、それを公開することは違う
ファイルの場合、公開したい人に渡したり、どこかストレージにアップロードしてそれを見てもらったりする必要がある。

ページの場合、つくった後に公開範囲を設定する。自分だけが見れるとか、招待した人だけ見れるとか、自分の組織だけ見れるなど。

## 公開には複雑な作業が伴うこともある
たとえば WordPress は、いわゆるブログに相当する（ブラウザで書ける）ものだが、それで書いたものはファイルとして存在する。これを自分でサーバーにアップロードしなけばならない。サーバーの契約や設定も必要で――と何かと面倒くさい。そもそもウェブページはそれなりに面倒くさい仕組みになっているものだが、ブラウザで完結する手段は、そのサービスが裏で肩代わりしているにすぎない。

## 変換という概念
テキストファイルで書いたものをリッチテキストに変換したり、ウェブページ用のファイルに変換したりといった考え方がある。すでに述べたとおり、テキストファイルで書くのが一番速いからだ。たとえば Markdown で書いて、それを HTML に変換すればウェブページにできる（HTMLファイルをサーバーにアップロードしたり等も必要）し、Docx や PDF もつくることができる。

Markdown については右記記事も参照: [Markdown（マークダウン）の存在意義を理解する、ついでに .md ファイルの意味も #Markdown - Qiita](https://qiita.com/workhack20/items/5380d46368368b1be492)

## IDEをブラウザで使う
IDE は、手元のパソコンで動かすのは少々面倒くさかったりする。なので SaaS として提供してしまって、ブラウザだけで使えるようにするとの潮流が近年は台頭してきた。

## リッチファイルをブラウザで書く
リッチファイルは従来 PC 上で、専用アプリで書くものだったが、もうブラウザでもできる。Google ドキュメントを使えば、Word の .docx ファイルをブラウザで書くことができる。また、Microsoft 自身もブラウザ上で直接編集できる Online 機能を持っている。

## スマホで書く
スマホもコンピュータであり、テキストエディタやIDEや専用アプリはある。

スマホだけで作業を完結させる人もすでに珍しくないだろう。とはいえ、PC の方が画面が広いし、ツールも豊富だし、ファイルも扱いやすいし、キーボードも速く打てるし、でまだまだ PC の方が有利だと思う。
【iOS/macOS】iPhone / Mac メニューバーでテレビをみる

はい、緊急で書きました。

<blockquote class="twitter-tweet"><p lang="und" dir="ltr">iOS <a href="https://t.co/RaYwWtuMIs">pic.twitter.com/RaYwWtuMIs</a></p>&mdash; chanzmao (@maochanz) <a href="https://twitter.com/maochanz/status/1841798023585923516?ref_src=twsrc%5Etfw">October 3, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

いろんなことできますね、ネットは。

デコードかキャッシュか、1分遅れです。

(更新中...)

https://android.benigumo.com/20241002/ffmpeg-vp9/
なぜDI(依存性注入)を使うのか

# DI(依存性注入)とは
ChatGPTの回答は以下。
DIとはあるオブジェクトが他のオブジェクトを直接生成せずに、外部から提供されることでそのオブジェクトの依存関係を明示的にすること。

# なぜ使うとメンテナンスしやすくなるのか
以下4つほどがあると思う。それぞれ詳細についは別記事にまとめたりしようと思うが、現時点ではイメージを持つため詳細の説明は省く。

1. 疎結合の実現
クラス間で密結合になっていると、修正時に影響も出るためクラス間は疎結合であることが望ましい

2. テストの容易さ
DIを使っていないと、モックやスタブのを使用するのが難しくなる
この内容については後ほど別記事にまとめる

3. SOLID原則の遵守
SOLIDの原則について詳細を把握していないため、後ほど別記事にまとめる

4. その他の向上
柔軟性、拡張性、再利用性、メンテナンス性など色々な面で利便性がある
この辺りも深掘りできそなので、後ほど別記事にまとめる

# DIを使う前と使った後の違い

```csharp:DI未使用
public class SampleController
{
    private readonly SampleService _sampleService;

    public SampleController(SampleService sampleService)
    {
        // 具体的な実装に依存
        _sampleService = new SmpleService();
    }
    
    public ActionResult Index()
    {
        _sampleSerivce.Action();
        // 何かしらreturn
    }
}


public class SampleService
{
    public SampleService()
    {
    }

    public void Action()
    {
        // 何かしらの処理を実装
    }
}
```

```csharp:DI使用
public class SampleController
{
    private readonly ISampleService _sampleService;

    public SampleController(ISampleService sampleService)
    {
        _sampleService = sampleService;
    }
    
    public ActionResult Index()
    {
        _sampleSerivce.Action();
        // 何かしらreturn
    }
}


public class ISampleService
{
    void Action();
}

public class SampleService : ISampleService
{
    public SampleService()
    {
    }

    public void Action()
    {
        // 何かしらの処理を実装
    }
}
```

# まとめ
インスタンス化する時に、具体的なクラスを使うのか、インタフェースで定義されている抽象的なクラスを使うかによって保守開発やリファクタリングで、やりやすさの差が出る
テスト実装やSOLID原則、その他についてはこれから調査して行くが、以下参考書もあるため、目を通していく。
[なぜ依存を注入するのか　DIの原理・原則とパターン (Compass Booksシリーズ) ](https://www.amazon.co.jp/%E3%81%AA%E3%81%9C%E4%BE%9D%E5%AD%98%E3%82%92%E6%B3%A8%E5%85%A5%E3%81%99%E3%82%8B%E3%81%AE%E3%81%8B-DI%E3%81%AE%E5%8E%9F%E7%90%86%E3%83%BB%E5%8E%9F%E5%89%87%E3%81%A8%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3-Compass-Books%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-Steven-Deursen/dp/4839983062)
シェルを快適につかえるようになろう! みんなどうやってシェルの操作覚えてきた?

## シェルを快適につかえるようになろう! みんなどうやってシェルの操作覚えてきた?

これは omotesando.rb # 102 の LT プレゼンです。

---

## Kaigi on Rails でもよろしゃっす!

![Kaigi on Rails](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21799/ba6dec80-55c0-f175-e146-137e18af05d7.png)

---

## 時々、駆け出しさんのサポートをしているのですが、シェル操作を見ていて思うところがある…

---

## この再現動画を見てほしい

[再現動画](https://youtu.be/NgORMetlfZk)

---

## みなさんどうやってシェルを覚えた？

僕はもう昔すぎて覚えていない…

---

## この辺覚えていたらいいよな、というのを書いてみる

---

## 基本を覚えよう

- man
- cd, ls, mv, cp, rm
- パスの扱い(`/` `~` `.` `..`)
- パーミッション

---

## 覚えると気持ちいいやつ

- find
  - ファイル検索
  - ヒットしたやつに対して別の処理をすることもできる
- grep
  - ファイル内検索
  - pipe と組み合わせてフィルタみたいに使うことも多い
- `|` (pipe)
  - 他のコマンドに結果を渡せる 
- cat, tail, head

---

## ファイル編集もコマンドで!

- vi
  - おっと、誰か来たようだ…
  - 編集モードとノーマルモードがある
  - 奥が深いし、エディタはいろんな派閥がありますので好きなのを

---

## tabで補完しよう

- 押してみな、飛ぶぞ
- zshだとオプションも補完してくれる

---

## historyを使おう

- 上下キーで前回実行したコマンドをもう一回
- `ctrl + r` で `back incremental search(過去のコマンドを検索)` (bck-i-search: って出るやつ)

---

## カーソル移動、コマンド編集

- `ctrl+a` でカーソルを先頭に
- `ctrl+e` でカーソルを末尾に
- `ctrl+d` で1文字削除
- `ctrl+c` でクリア
---

## カラフルにしたり、現在のGitブランチを表示したり

- 賛否両論あるけど [oh-my-zsh](https://ohmyz.sh/) はお手軽だと思う
- 僕もこれをベースにカスタマイズしている
- アップデートも頻繁
- 起動がちょっと遅いので嫌がられる?

---

## 100万回使うコマンドはaliasにしよう

`~/.bashrc` や `~/.zshrc` に設定する。

```bash
alias st="git status"
alias cm="git commit"
alias co="git checkout"
```

---

## 定形作業をスクリプトにしよう

基本はコマンドを書くだけ。
曲があるけど、条件分岐とループもかけます。
Dockerなどでも使う。

```zsh
#!/bin/bash
cd /path/to/program
bin/rspec
```

---

## [上級編] ターミナルマルチプレクサ

最初はターミナルのwindowを複数作るのでもいいかもしれませんが、windows操作が億劫になってきたら。

- 最初から入ってる screen, ユーザの多い tmux
- 1枚の画面を分割できる
- うっかりターミナル閉じちゃっても復帰できる
- 分割したターミナル全部にコマンドを送れる
- 待ち時間に別のことを進められる

---

## …というようなのをどうやって覚えてきた?

「これ読んどけ」があればいいんだけど…

- Linux サーバの本?
- 一子相伝の先輩の作業

---

## みなさんからいただいたご意見

- LinuC の本高いけど体系的に学べる
- 一子相伝感あるからビギナーは物理出社の会社がいいかも
- 技術書典で書くか？
  - いや、僕もそんな詳しくないし…

---

## ありがとうございました。
文字化けの原因とは？

よくサーバーにアップされているソースを見たりすると、文字化けされている現象を見かけます。

何となくの理解でしかなかったので、根本的な原因を理解するために記事を書きます。


# 文字コードという存在

文字化けの原因を知るには、まず「文字コード」を知る必要があります。

### Shift_JIS, EUC-JP, UTF-8
よく目にするこれです。

:::note info
Wikipedia
文字コードとは
文字集合を定義し、その集合の各文字に対応するビット組み合わせを一意に定めたもの
:::



# 文字化けの原因
:::note warn
文字化けが発生する原因は、「HTMLファイル自体の文字コードと、ブラウザが解釈した文字コードが異なるとき」に発生します。
:::

例えば、Shift_JISで保存されたHTMLファイルを、ブラウザがUTF-8だと認識して、UTF-8で表示してしまうと文字化けが発生するということです。



通常Webブラウザは、サーバーへリクエストを送った後、サーバからHTMLを受け取り、レスポンスヘッダやHTMLを分析した上で、「文字コードはこれだろう」と解釈して、ページを表示します。



# HTMLでは、UTF-8で良い
HTMLの文字コードを「Shift_JIS」にしてサーバーに上げると、ソースは文字化けしていると思います。
軽微なミスの記録（備忘録）

# ちょっとしたミス（備忘録）
## 自己紹介
- 所属
>  九州工業大学情報工学部
- ハンドルネーム
> **buridaikon**

## 解いた問題
https://atcoder.jp/contests/tessoku-book/tasks/math_and_algorithm_ai

## 今回のミス
　関数のパラメータとして整数型配列を渡すときにポインタを使って参照していなかったことで、実行時間が余計に長くなっていた。（関数に渡すとき、毎回配列のコピーを行ってしまっていた）

### 提出したコード

```cpp
#include <iostream>
#include <vector>
using namespace std;

int result(int left, int right, vector<int> sum)
{
    int result_num = sum[right] - sum[left-1];
    return result_num;
}

int main()
{

    int n, k;
    cin >> n >> k;

    vector<int> vec(n);

    for (int i = 0; i < n; i++)
    {
        cin >> vec[i];
    }

    vector<int> sum(n + 1, 0);

    for (int i = 0; i < n; i++)
    {
        sum[i + 1] = sum[i] + vec[i];
    }

    for (int i = 0; i < k; i++)
    {
        int left, right;
        cin >> left >> right;
        cout << result(left, right, sum) << endl;
    }
    return 0;
}
```

### 修正後のコード

```cpp
#include <iostream>
#include <vector>
using namespace std;

int result(int left, int right, vector<int> &sum)
{
    int result_num = sum[right] - sum[left-1];
    return result_num;
}

int main()
{

    int n, k;
    cin >> n >> k;

    vector<int> vec(n);

    for (int i = 0; i < n; i++)
    {
        cin >> vec[i];
    }

    vector<int> sum(n + 1, 0);

    for (int i = 0; i < n; i++)
    {
        sum[i + 1] = sum[i] + vec[i];
    }

    for (int i = 0; i < k; i++)
    {
        int left, right;
        cin >> left >> right;
        cout << result(left, right, sum) << endl;
    }
    return 0;
}
```
### 修正箇所

```diff_cpp
- int result(int left, int right, vector<int> sum)
+ int result(int left, int right, vector<int> &sum)
```

## 実行時間への効果

**before**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618170/8fbcb5b3-cae4-2d37-cb4b-40bd6631c9fd.png)

**after**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618170/2a178437-aed4-cf75-74d4-96f80cd0721d.png)

　写真より、修正前と修正後で大きく計算量に差があると分かる。少し気を付けるだけでも計算量を少なくできる。
横並びにボタンと文字が並んでるフレキシブルボックスはalign-items: baseline;がきれいだと思う

よく言われてることかもしれないけど、個人的な考えのメモ


# align-items: center; の場合



![CleanShot 2024-10-03 at 19.23.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435274/89b673e3-e4e3-956e-bcae-e842160724dd.png)

```diff_javascript:index.html(react, unocss)
<div
  w-fit
  mt-12
  mx-auto
  text-center
  flex
+  items-center 
  gap-2
  text-gray-800
  className="pager"
>
      <button
        disabled={page === 1}
        className="prev"
        onClick={handlePrev}
      >
        Previous
      </button>
      <span mx-2 text="1.1em" className="page-number">
        {page}
      </span>
      <button
        disabled={limit > characters.length}
        className="next"
        onClick={handleNext}
      >
        Next
      </button>
</div>
```

# align-items: baseline; の場合

![CleanShot 2024-10-03 at 19.25.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435274/e7716845-3ab7-53a8-7b27-13a9e691c8f0.png)

```diff_javascript:index.html(react, unocss)
<div
  w-fit
  mt-12
  mx-auto
  text-center
  flex
+  items-baseline
  gap-2
  text-gray-800
  className="pager"
>
      <button
        disabled={page === 1}
        className="prev"
        onClick={handlePrev}
      >
        Previous
      </button>
      <span mx-2 text="1.1em" className="page-number">
        {page}
      </span>
      <button
        disabled={limit > characters.length}
        className="next"
        onClick={handleNext}
      >
        Next
      </button>
</div>
```

center↓
![CleanShot 2024-10-03 at 19.28.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435274/b53eec63-8848-683e-e96b-2d39cb99b8ca.png) 
baseline↓
![CleanShot 2024-10-03 at 19.27.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435274/e9ddb61a-6afb-c712-3ac8-16fbc17bc9fa.png)

すごいわずかな誤差なんですけど、なんか今更baselineの方がきれいだな、と思いました。
ケースバイケースかもしれませんが。
署名付きURLを生成して、ブラウザから直接GCSにアップロードする

# はじめに
ブラウザからサイズの大きいファイルをアップロードしようとした際にCloud Runの容量制限を越えられないため、GCSから署名つきURLを発行してブラウザから直接アップロードしました。

# 開発環境
- Next.js 14.2.2
- Terraform
- Cloud Run (実行環境)

# 署名付きURLの発行

```typescript:index.ts
export async function getSignedUrl(): Promise<string> {
  try {
    const filePath = "filename.wav";
    const storage = new Storage();
    const file = storage
      .bucket("your_bucket_name")
      .file(filePath);
    const [signedUrl] = await file.getSignedUrl({
      version: "v4",
      action: "write",
      expires: Date.now() + 24 * 60 * 60 * 1000, // 24 hours
    });

    return signedUrl;
  } catch (error) {
    console.error(error);
    throw new Error("Failed to get signed URL");
  }
}
```
# ブラウザ側からGCSにアップロード

```tsx:
async function uploadDataToGCS(): Promise<string> {
  try {
    const signedUrl = await getSignedUrl(encodedFileName);
    await fetch(signedUrl, {
      method: "PUT",
      body: value,
    });
  } catch (error) {
    console.error("Error upload file to GCS:", error);
  }
}
```

:::note warn
CORSの設定をしていない場合はエラーになります。必ず設定しましょう。
:::
実際はterraformで実装してますが、動作確認などローカル環境で実行させるにはコンソール、もしくはscriptで直接設定しても良いかもしれません。

```terraforme:storage_bucket.tf
resource "google_storage_bucket" "asset_bucket" {
  name          = "your-asset-bucket-name"
  location      = "US"
  force_destroy = true

  cors {
    origin          = ["http://localhost:3000"]
    method          = ["PUT"]
    response_header = ["Content-Type"]
    max_age_seconds = 3600
  }
}
```

```ts
async function configureBucketCors() {
  await storage.bucket(bucketName).setCorsConfiguration([
    {
      maxAgeSeconds,
      method: [method],
      origin: [origin],
      responseHeader: [responseHeader],
    },
  ]);
}
```
https://cloud.google.com/storage/docs/using-cors?hl=ja#storage_cors_configuration-nodejs


# サービスアカウントの権限の設定
権限設定もコンソールから設定できますが、実際はprod,stg,dev等の環境があるはずです。毎回コンソールから設定していてはミスしかねないので、このようにインフラもコード化しておきましょう！
```terraform:service_account.tf
resource "google_project_iam_member" "service_account_sign_blob" {
  project = "<YOUR_PROJECT_ID>"
  role    = "roles/iam.serviceAccountTokenCreator"
  member  = "serviceAccount:${google_service_account.my_service_account.email}"
}
```
LLVMでアセンブリから実行ファイルを作成する際にPIEオブジェクト作成エラーが出る

適当にC言語でhello.cを書き、

次のコマンドでC言語のファイルをLLVM IRに変換する
```
clang -S -emit-llvm -O3 hello.c
```

次のコマンドでLLVM IRからアセンブリファイルにコンパイルする
```
llc helloworld.ll
```

次でアセンブリファイルを実行ファイル(バイナリファイル)に変換
```
clang hello.s -o hello
```
---
### ここでエラーが出た場合
これすれば変換できました
```
clang hello.s -no-pie -o hello
```

`リンカに対して、PIEを生成しないよう指示します。つまり、コードは固定されたメモリアドレスで実行されることを前提とします。この形式では、実行ファイルがメモリの特定の位置にロードされる必要がありますが、アドレス空間配置ランダム化（ASLR） などのセキュリティ機能の恩恵は受けません。`

---

実行
```
./hello
```

参考サイト
https://qiita.com/Anko_9801/items/df4475fecbddd0d91ccc
diffについて調べてみた

## 調べるに至った理由
現在、参画しているプロジェクトの中盤でディレクターより「差分管理をしていく上でdiffをとる」とのことで、diffについて意味を知り理解したいと思い、下記まとめました。

## diffとは
「difference」のことで、指定した二つのファイルを比較した時の違い（差分）のことを指している。

## diffコマンドについて
二つのファイルを比較して差分を出力するコマンド

```
###基本的なコマンドの書き方
diff [オプション] ファイル1 ファイル2
```
- ファイル1とファイル2は比較したいファイル名
- オプションは表示方法や出力形式を制御するためのもので必須ではない

#### 出力結果
```
###ファイル比較(基本)
$ diff file1.txt file2.txt
1c1
< test
---
> tests
```
#### 出力内容
file1.txtとfile2.txtを比較する内容
「1c1」は「1行目が変更された」という意味で最初の「1」はfile1.txtの行番号、後ろの「1」はfile2.txtの行番号を表している。
つまり、file1.txtの1行目がfile2.txtの1行目に変更されたということ。

#### 変更内容

「---」より上に表示されている「< test」はfile1.txtの1行目
「---」は変更が発生したことを示す
「> tests」はfile2.txtの1行目であることを表している

## よく使われるオプション
- -uオプション（unified形式）
「---」は変更前のファイルを、「+++」は変更後のファイルを表している
変更後に存在しない行は「-」、変更後のみに存在する行は「+」が行頭についている。
見やすさはイマイチ、、、
```
# diff -u test1.txt test2.txt
--- test1.txt   2022-08-22 18:23:54.717925300 +0900
+++ test2.txt   2022-08-23 09:18:48.147925300 +0900
@@ -1,11 +1,11 @@
-あいうえお
-かきくけこ
+あいうゑお
+かきくケこ
 さしすせそ
 たちつてと
+ららららら
 なにぬねの
 はひふへほ
 まみむめも
-やゆよ
+やゆよよよ
 らりるれろ
 わをん
-アイウエオ
#
```

- -cオプション（contex形式）
「***」は変更前のファイルを、「---」は変更後のファイルを表している
変更のあった行は「!」、変更後に存在しない行は「-」にのみ存在する行は「+」が行頭についている
こちらも見やすさはイマイチ、、、
```
# diff -c test1.txt test2.txt
*** test1.txt   2022-08-22 18:23:54.717925300 +0900
--- test2.txt   2022-08-23 09:18:48.147925300 +0900
***************
*** 1,11 ****
! あいうえお
! かきくけこ
  さしすせそ
  たちつてと
  なにぬねの
  はひふへほ
  まみむめも
! やゆよ
  らりるれろ
  わをん
- アイウエオ
--- 1,11 ----
! あいうゑお
! かきくケこ
  さしすせそ
  たちつてと
+ ららららら
  なにぬねの
  はひふへほ
  まみむめも
! やゆよよよ
  らりるれろ
  わをん
#
```

- -yオプション（side by side形式）
エディタの左側に変更前、右側に変更後のファイルが表示されている
変更があった行には右側のファイルの左側に結果が表示される
変更のあった行は「|」、変更後に存在しない行は「<」、変更後にのみ存在する行は「>」が表示される
直感的に分かりやすい表示になっている
```
# diff -y test1.txt test2.txt
あいうえお                                                    | あいうゑお
かきくけこ                                                    | かきくケこ
さしすせそ                                                      さしすせそ
たちつてと                                                      たちつてと
                                                              > ららららら
なにぬねの                                                      なにぬねの
はひふへほ                                                      はひふへほ
まみむめも                                                      まみむめも
やゆよ                                                        | やゆよよよ
らりるれろ                                                      らりるれろ
わをん                                                          わをん
アイウエオ                                                    <
#
```

[参考](https://tech-blog.rakus.co.jp/entry/20220905/diff)

## 最後に
恥ずかしながらプロジェクト参画後に初めて知った言葉、コマンドでしたがこれを機に学ぶことができて良かったです。
今後、プロジェクトが進みテストも増えてくると、差分についての対応が増えると思うので使いこなせるようにしていきます。
M5NanoC6でボタン入力して遊ぶ



目的
GPIOのテスト

結果

![o_coq478.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/8880246c-bb9c-e3b2-c614-6a82ae347a2a.jpeg)



プログラム


```c++



//BlueLED_button_M5NanoC6_1


//初期化
void setup() {

  //GPIOの初期化
  pinMode(7, OUTPUT); //BlueLED
  pinMode(1, INPUT); //button

}//setup


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

  //ボタンの信号の読み込み
  int a = digitalRead(1);


  //ボタンが押されたら点灯、ボタンが離れたら消灯
  if ( a != 0 ) {

    //白を点灯
    digitalWrite(7, HIGH);

  } else {

    //消灯
    digitalWrite(7, LOW);

  }//endif


  delay(300);//0.3秒待つ

}//loop



```
amazonlinuxのDockerイメージでsudoコマンドを使用可能な状態にして起動するワンライナー

## モチベーション
本来のEC2で実行するのと同じようなコマンドを書いたshスクリプトを実行したいのですが、EC2に繋いだときにはsudoが必要なのにDockerイメージとして実行するとsudoがないのでうまく実行できないのが動きとして気に食わなかったので、以下のようなコマンドを実行する事で回避しました。

みんな大好きワンライナーで書けました。

```sh
docker run --rm -it -v `pwd`:/app -w /app amazonlinux:2023 bash -c "yum update -y && yum install -y sudo && exec bash"
```
iOS: ユーザーごとの通知設定情報はサーバー側に持つべきという話

Push通知機能の実装をしていて、ユーザーごとの通知設定情報(通知種類ごとの設定ON・OFF)をクライアント側かサーバー側どちらに持つべきか悩みました。結果としてサーバー側で持つことになったのですが、今回はその背景についてお話したいと思います。

## なぜサーバー側に持つべきなのか

### 当初の想定
通知機能の実装にあたり、当初はクライアント側に通知設定情報を持っておこうと考えていました(UserDefaultとかに保存)。そして、通知が来たタイミングで設定情報を見て受信制御を行うというのが当初の想定でした。しかし、通常の通知タイプでは受信を行った際に何か処理を挟むといったことはできなくて、上記のようなことを行いたい場合にはバックグラウンドプッシュ(サイレントプッシュともいう)という通知形式を使用する必要があります。ただこの通知形式は注意が必要です。

### バックグラウンドプッシュの仕様
バックグラウンドプッシュはアプリがバックグラウンド状態からでも、通知を受信して何かしら処理を行った後に通知を実行(自分でローカルpushを組み立てる必要あり)させることができます。
ただこの通知形式も、バックグラウンド状態で通知を受け取ろうとした場合、色々と制約があって具体的には以下のようなものが存在します。

 - システム上、優先度が低く扱われるので必ずしも即時で実行されるとは限らない
 - 通知数に限りがある(1時間に2〜3回程度まで)
 - ユーザーによって明示的に終了(ホームボタンダブルクリックからアプリをスライド等)した場合、通知を受け取ることができない

[公式参考リンク](https://developer.apple.com/documentation/usernotifications/pushing-background-updates-to-your-app)

### 結論
フォアグラウンド時は何の問題もなく通知を受け取ることができますが、バックグラウンド時には上記の制約が付きまとうので、確実に通知を送りたいといった状況の時は不向きです。今回通知で実現したかったのは、新着コンテンツが配信されたタイミングで確実にお客様へ通知を送りたいというものだったので、バックグラウンドプッシュでは実現できないということが分かり、途中で通知設定情報をサーバー側に持たせる方針へ切り替えました。設計段階で気付くべきだったのですが、学びになったとポジティブに捉えるようにします。

## 終わりに
一口に通知といっても色々な通知タイプが存在し、それぞれに制約だったり特徴があるので、それを理解した上で通知機能を実装することが大事なんだなと感じました(当たり前の話)
この辺りは引き続き勉強していきたいと思います。
DID YOU KNOW?

![Post 3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901221/676d4532-190e-3127-3b19-f65c6b04917e.png)
Over 60% of Startups Face Failure Due to Cash Flow Issues – Here’s How to Avoid Them!

Starting a business is an exciting journey, but cash flow issues can turn that excitement into stress. In fact, over 60% of startups fail due to poor cash flow management, which is one of the leading causes of business closures. But the good news is, avoiding these pitfalls is easier than you think! Let’s dive into how you can protect your business from cash flow problems and ensure long-term success.

1. Understand Your Cash Flow
First, it’s essential to understand the movement of money in and out of your business. Many startups fail because they don’t keep track of their cash flow. Make sure to monitor your income, expenses, and upcoming financial obligations regularly. A clear understanding of your cash flow helps prevent surprises and keeps your finances in check.

2. Create a Cash Flow Forecast
Forecasting your cash flow allows you to predict future income and expenses, helping you stay ahead of potential shortfalls. By projecting your cash flow over the next few months or year, you can plan for slow periods and avoid falling into the trap of cash shortages.

3. Avoid Overhead Expansion
Startups often fall into the trap of overspending on office space, staff, or equipment before they truly need it. Stay lean during your early stages by only spending on what’s necessary. Once your cash flow is stable and growing, then consider expanding.

4. Negotiate Payment Terms
One smart way to keep cash flowing is by negotiating payment terms with your suppliers. Try to secure longer payment periods, while also encouraging clients to pay as soon as possible. This gives you more flexibility and keeps cash in your business for longer.

5. Have a Cash Reserve
Building a reserve for emergencies can save your startup in tough times. A reserve fund ensures you can cover unexpected expenses or survive during slow periods without panicking over cash flow.

6. Invoice Promptly and Follow Up
Delay in invoicing can directly impact your cash flow. Send invoices promptly and don’t hesitate to follow up on unpaid bills. The quicker you receive payments, the more steady your cash flow remains.

7. Explore Alternative Financing Options
Consider exploring financing options like business lines of credit or short-term loans to keep cash flowing smoothly, especially during growth periods or seasonal dips. Having backup funding can prevent cash flow hiccups.

Conclusion
While cash flow issues are common, they’re far from impossible to overcome. By managing your finances wisely, forecasting, and staying proactive, your startup can avoid the pitfalls that lead to failure. Focus on keeping your cash flow healthy, and you’ll build a stronger foundation for long-term success!

Start smart, stay prepared, and your startup can thrive!
【CSS】テキストに関するcss


# テキストに関するcss

css適応前
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3890600/a476171f-8371-dc06-fd01-24ad2c62e126.png">


css適応後
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3890600/a7881a3f-c10b-68a1-2d87-5a542e197acf.png">


```html:index.html
<h1>CSS-TEXT</h1>
<a href="/">リンク</a>
<p>
    Lorem ipsum dolor sit, amet consectetur adipisicing elit. Consequuntur,
    qui! Dolor accusamus quas repellendus, nemo iste a doloribus, assumenda
    cupiditate excepturi temporibus adipisci. Totam, possimus? Magnam quidem
    nulla itaque? Quas?
</p>
```
```css:index.css
h1 {
  text-align: center;
  font-weight: 100;
  text-decoration: #f3a3b3 underline wavy;
  letter-spacing: 15px;
  font-size: 80px;
  font-family: "Segoe UI", Futura, Arial, sans-serif;
}

a {
  text-decoration: none;
}

p {
  line-height: 2;
}
```

<table>
<caption>css一覧</caption>
  <thead>
    <tr>
      <th>css</th> <th>説明</th> <th>例のどこに使われているか</th>
    </tr>
  </thead>
  <tr>
    <td> text-align </td> <td>文字の配置位置</td> <td>h1</td>
  </tr>
  <tr>
    <td> font-weight </td> <td>文字の太さ</td> <td>h1</td>
  </tr>
  <tr>
    <td> text-decoration </td> <td>下線を引いたり打ち消し線を引く</td> <td>h1とa</td>
  </tr>
  <tr>
    <td> line-height </td> <td>一行の高さ</td> <td>p</td>
  </tr>
  <tr>
    <td> letter-spacing </td> <td>文字と文字の間</td> <td>h1</td>
  </tr>
  <tr>
    <td> font-size </td> <td>文字の大きさ</td> <td>h1</td>
  </tr>
  <tr>
    <td> font-family </td> <td>フォント</td> <td>h1</td>
  </tr>
</table>

**補足説明**
* **text-decoration**のいちばんの使い道：リンクの下線を消す時
* **line-height**：`line-height: 2;`の場合、フォントサイズの2倍の高さに設定できる
* **font-size**の大きさの書き方：`px`は絶対単位（何があってもその大きさ）
* **font-family**：
    * カンマ区切りで複数フォントを書いておくことで、そのフォントがなかった時に、代わりのフォントを表示してくれる
    * 一番最後に総称ファミリー書いとくのがベスト
    * 総称ファミリーはフォントのまとまりみたいなもので、そのなかから適応できるものを選んで表示してくれる（`sans-serif`とか）
    * macとwinがそのフォントをどれだけ持ってるかを一覧で表示しているサイト（ https://www.cssfontstack.com/ ）
install rbenv/ruby systemwide on RockyLinux 9.0

# TL;DR

* require libyaml-devel

# install dnf packages

```
su -
dnf install git
```

```sh:for ruby-build
dnf install autoconf gcc patch bzip2 openssl-devel libffi-devel readline zlib-devel gdbm ncurses-devel tar perl-FindBin
```

https://github.com/rbenv/ruby-build/wiki#suggested-build-environment

## libyaml-devel(RHEL 9系)

```
dnf config-manager --set-enabled crb
dnf install libyaml-devel
```

https://www.hsbt.org/diary/20230126.html

## libyaml-devel(RHEL 8系)

```
dnf config-manager --set-enabled powertools
dnf install libyaml-devel
```

# rbenv

## proxy（必要な人のみ）

```
git config --global http.https://github.com/.proxy http://server:port
```

## install

```
cd /usr/local

git clone https://github.com/rbenv/rbenv.git rbenv
git clone https://github.com/rbenv/ruby-build.git rbenv/plugins/ruby-build
```

```sh:/etc/profile.d/rbenv.sh
export RBENV_ROOT="/usr/local/rbenv" 
export PATH="$RBENV_ROOT/bin:$PATH" 
eval "$(rbenv init - --no-rehash)" 
```

## check

```
exec -l $SHELL
rbenv -v
```

# rustc（YJIT使いたい人のみ）

https://gihyo.jp/article/2024/01/ruby3.3-jit#ghdFyfwHY5

## prepare

```
mkdir -p /usr/local/rust && cd /usr/local/rust/

export RUSTUP_HOME=/usr/local/rust
export CARGO_HOME=/usr/local/rust
```

## proxy（必要な人のみ）

```
export HTTP_PROXY=http://server:port
export HTTPS_PROXY=$HTTP_PROXY
```

## install

```sh:no-proxy
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

```sh:with-proxy
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -x http://server:proxy | sh
```

特に拘りがなければ```1) Proceed with standard installation (default - just press enter)```を選ぶ

## post-install

```sh:/usr/local/bin/rustc
#!/bin/sh

RUSTUP_HOME=/usr/local/rust exec /usr/local/rust/bin/${0##*/} "$@"
```

実行権限を付ける

```
chmod 755 /usr/local/bin/rustc
```

他のrustc関連実行ファイルにもパスを通しておく

```
cd /usr/local/bin/
ln -s /usr/local/rust/bin/* ./
```

```rustc```だけは失敗するが、想定通り
```ln: シンボリックリンク './rustc' の作成に失敗しました: ファイルが存在します```

## check

```
exec -l $SHELL
rustc -V
```

# ruby

## check

```
rbenv install -l
```

ここで出てくるものから選ぶのがおすすめ

## install 

```
rbenv install 3.4.1
```

```
rbenv versions
rbenv global 3.4.1
```

## check

```
ruby -v
```

# 参考

https://zenn.dev/tm_hack/articles/93fc83db270d78
[ChatGPT] 読みづらいスプレッドシートをChatGPT様に見やすくしていただいた

# はじめに

業務の中で、あまりにも視認性の悪いスプレッドシートに遭遇しました。
詳細は伏せますが、とあるアンケートの結果を集計したシートなのですが、自由記述欄のあるアンケートですので1つのセルに入力される文字数が膨大でした。
そのように膨大な文字が入力されたセルが縦横無尽に並んでおりまして、まぁ視認性の悪い悪い。
困り果てた私は、救いの神 ChatGPT様に救いを求めたのでした。

# やりとり

私の方からChatGPT様にお送りしたプロンプトは以下のような感じです。

- csvを読み込んで良い感じに見やすくするJS
- 読み込んだcsvに対して、GUI上で特定の列だけを選択して表示するようなwebアプリは作れないだろうか？
- 読み込むcsvが実はアンケートの結果で、1つのセルに格納されている文章量が多い。なので表形式だと見づらいので、選択した列に対して以下の操作をしたい
    - 1行目(ヘッダ部分)を項目名として表示
    - 2行目以降を、項目名の下に箇条書きで表示
- 箇条書きについて。空白の場合はスキップするように

たったこれだけです。
私の送ったプロンプトとプロンプトの間にはChatGPT様のご返答があるのですが、長いので省略しています。

# 結果

https://github.com/ryota37/csvformatter

## 詳細

- ChatGPT様に書いて頂いたHTML, CSS, JavaScriptのコードをそのまま入れてます
- git clone して index.htmlを開けばブラウザ上でアプリが開くはずです
- csvファイルを読み込ませれば、あとはブラウザ上に表示させたい項目のチェックボックスが出るので、それを適宜オンオフすれば読みたい項目だけ読むことができます

※私の場合はアンケート結果をGoogleスプレッドシートにて展開されたので、スプレッドシートをcsvに変換してから読み込ませました。

## デモ

言葉だけで説明しても分かりにくいと思ったので、テストデータを読み込ませて実際の表示をスクショしました。

![スクリーンショット 2024-10-03 18.43.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726845/f25922c5-5e5e-e5da-6fbb-4707e9c17bd1.png)

こんな風に、

- 表示させる項目をチェックボックスから選べる
- 表示した項目ごとに箇条書きで内容を表示する

といった実装にしてみました(書いたのはChatGPT様ですが)。

このテストデータではあまりありがたみが実感できないかもですが、箇条書き1つ1つに100文字〜200文字くらいの文章が入っていたらどうでしょうか。これを表形式で閲覧するのは、相当に苦痛を伴う作業になるのは想像に難くないでしょう。

# 終わりに

そんなわけで、視認性の悪いスプレッドシートをChatGPT様にあっという間に見やすくしてもらったという話でした。
出力されたコードは**一切いじっておらず**、実際にファイルを開けるようになるまでにかかった時間は**5分にも満たなかった**と思います。ChatGPT様、末恐ろしいですね。
大してデバッグもしておらず見た目も洗練されていませんが、ちょっとしたcsvを見やすくする用途には十分使えるものが仕上がったかと思います。使ってみたい方は是非上記のgithubリンクからDLしてみてください。

【2024/11/07 追記】

- GitHub Pagesにデプロイしてみました
    - https://ryota37.github.io/csvformatter/
    - ↑のURLにアクセスすれば、どなたでも使えるはずです
M5NanoC6、リレー Grove- Relay であそぶ



参考



![o_coq430.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/f8fd1030-536f-bcc4-c8f4-45651f332c71.jpeg)


https://wiki.seeedstudio.com/Grove_Starter_Kit_for_BeagleBone_Green/



結果

![o_coq477.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/441e557e-2575-a561-a50f-8c0e7579e43c.jpeg)


プログラム


```c++



//Grove_Relay_1S_M5NanoC6_1

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin as an output.
  pinMode(1, OUTPUT); //1 = G1
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(1, HIGH);   // turn the on (HIGH is the voltage level)
  delay(1000);             // wait for a second
  digitalWrite(1, LOW);    // turn the off by making the voltage LOW
  delay(1000);             // wait for a second
}




```
RSpecでRakeタスクを扱う効果的なアプローチ: グローバル定義とタスクの再利用方法

## はじめに
業務中にRSpecを使ってRakeタスクをテストする際、次のようなエラーに遭遇しました。

```
RuntimeError:
  Don't know how to build task 'batch:two' (See the list of available tasks with `rake --tasks`)
```
このエラーは、RSpecの複数のテストファイルで同じRakeタスクを再利用しようとしたときに発生します。一度定義されたRakeタスクが状態を保持したままになるため、再実行しようとするとエラーになるのです。

特に、次のようにディレクトリ構造を持つ場合、各テストファイルで個別にRakeタスクをロードしようとすると、この問題が発生します。

```
spec/
  └── lib/
      └── tasks/
          ├── one.rb
          └── two.rb
```
この記事では、RSpecでRakeタスクをテストする際に遭遇する問題と、その解決策について解説します。Docker環境などの複数のテストを一貫して行うシナリオにも対応する、効果的なアプローチを紹介します。

## 問題の概要
RSpecで複数のテストファイルを使ってRakeタスクをテストする場合、Rakeタスクが一度実行されると完了状態が保持され、再実行できないという問題に直面します。

例えば、以下のように、二つのテストファイルで異なるRakeタスクをテストしようとしたとします。

```spec/lib/tasks/one.rb
require 'rails_helper'

RSpec.describe "batch:one" do
  it "executes without errors" do
    Rake::Task["batch:one"].invoke
    expect(some_result).to be true
  end
end
```

```spec/lib/tasks/two.rb
require 'rails_helper'

RSpec.describe "batch:two" do
  it "executes without errors" do
    Rake::Task["batch:two"].invoke
    expect(some_result).to be true
  end
end
```

このコードでは、一つ目のテストファイルは問題なく通過します。しかし、二つ目のテストファイルを実行すると以下のエラーが発生します。

```
RuntimeError:
  Don't know how to build task 'batch:two' (See the list of available tasks with `rake --tasks`)
```

この問題は、特にDocker環境で `docker-compose exec web bin/rspec` のように複数のテストファイルを一度に実行した際に起こります。

## 解決策：グローバルなタスク定義とreenableの活用

この問題を解決するためには、次の2つの手法を活用します。

1. **Rakeタスクのグローバルな定義** : `spec_helper.rb` で `Rakeタスク` を一度だけロードして、すべてのテストで再利用できるようにする
2. **reenableメソッドを使用** : タスクの状態をリセットして再実行を可能にする

### 1. タスクのグローバル定義
まず、この問題に対処するために、`spec_helper.rb` ファイルでRakeタスクをグローバルに定義します。これにより、各テストファイルで重複してタスクを定義する必要がなくなります。

```
# spec/spec_helper.rb

require 'rake'

RSpec.configure do |config|
  config.before(:suite) do
    # Rakeタスクをグローバルにロードする
    Rake.application.rake_require("tasks/one", [Rails.root.to_s])
    Rake::Task.define_task(:environment)
  end
end
```
上記のように spec_helper.rb でタスクをロードすることで、すべてのRSpecテストでRakeタスクが再利用可能になります。

### 2. reenableメソッドを使用してタスクを再実行可能にする
次に、タスクを再実行するために reenable メソッドを利用します。一度実行したRakeタスクはデフォルトで再利用できません。このため、テストごとにタスクを再度有効化する必要があります。

```
# spec/lib/tasks/one.rb

require 'rails_helper'

RSpec.describe "batch:one" do
  let(:task) { Rake::Task["batch:one"] }

  before do
    # タスクを再度実行可能にする
    task.reenable
  end

  it "executes without errors" do
    expect { task.invoke }.not_to raise_error
  end
end
```
`spec/lib/tasks/two.rb`も同様に実装します。

reenableメソッドを使用することで、タスクは再実行可能な状態に戻り、各テストが独立して正しく動作するようになります。

## まとめ
RSpecでRakeタスクをテストする際には、以下の点を選択肢の一つに入れておきましょう：

**タスクをグローバルに読み込む**: `spec_helper.rb` でタスクをグローバルに読み込むことで、すべてのテストで利用可能にします。
**タスクを再利用可能にする**: `reenableメソッド` を用いてタスクを再実行可能にすることが、テストの一貫性を保つために重要です。

上記のアプローチを適用することで、Docker環境などの分離された環境でも、Rakeタスクを適切にテストし、安定したテスト実行を行うことができます。RSpecでのRakeタスクの扱いには注意点がありますが、これらの方法を活用することで、開発者にとって再現性の高いテスト環境を提供することが可能になります。

この記事が、RSpecを使用したRakeタスクのテストを行う際の参考になれば幸いです。業務でつまずいた点を共有することで、同じ問題に直面している方々に役立てばと願っています。！
API vulnerability scan I'm working on

Web App の脆弱性テストについて。

前職で ZAP の Baseline Scan [^2] を流したことはある。

しかし、ZAP API [^1] について詳しく学ぶことはなかった。今回、改めて ZAP API について学んだため、覚え書きとして残す。

## zaproxy を起動

- 今回は dind で起動している。Network はホスト側のネットワークを使用する。

```bash
docker run --name zap -u zap -p 8090:8090 --network="host"  -i zaproxy/zap-stable zap.sh -daemon -port 8090 -config api.addrs.addr.name=.* -config api.addrs.addr.regex=true -config api.disablekey=true
```

## コンテキストの作成

- スキャンする URL をコンテキストと言う。
- コンテキストを作成し、そのコンテキストに対して特定の URL パターンを含めて、セキュリティ スキャンなどに適用する準備を整える。

```bash
export MY_CONTEXT=hoge
echo $MY_CONTEXT

curl -X GET "http://localhost:8090/JSON/context/action/newContext/?contextName=$MY_CONTEXT"
curl -X GET "http://localhost:8090/JSON/context/action/includeInContext/?contextName=$MY_CONTEXT&regex=http%3A%2F%2Flocalhost%3A3000%2F.*"
```

## スパイダリング (Spider)

- `http://localhost:3000/` 以下のページを自動でクローリングし、リンクを辿って探索する。

```bash
curl -X GET "http://localhost:8090/JSON/spider/action/scan/?url=http://localhost:3000/&contextName=$MY_CONTEXT"
```

## アクティブスキャン (Active Scan)

- `http://localhost:3000/` 以下のURLに対して、脆弱性を検出するためのセキュリティ テストを実施する。

```bash
curl -X GET "http://localhost:8090/JSON/ascan/action/scan/?url=http://localhost:3000/&recurse=true&inScopeOnly=true&contextName=$MY_CONTEXT"
```

## アラートの要約を取得

- `http://localhost:3000/` に対するセキュリティ アラートの要約。アラートのレベル（ `High` `Low` `Medium` `Informational`）が含まれる。

```bash
curl -X GET "http://localhost:8090/JSON/core/view/alertsSummary/?baseurl=http://localhost:3000/"
```

## 詳細なアラート情報を取得

- `http://localhost:3000/` に関連するアラート情報を最大 N 件取得。
- JSON を DuckDB [^3] などで参照すると、必要なアラート レベルごとの調査ができる。件数をカウントしたり、条件で絞ったり。

```bash
curl -X GET "http://localhost:8090/JSON/core/view/alerts/?baseurl=http://localhost:3000/&start=0&count=100" | jq > zap.json
```

## Quick Note

10月は、久しぶりに Rust をやってみる予定。

https://gihyo.jp/book/2024/978-4-297-14413-5

しかし、今のところ、職場で Rust が役立つ予定は無い。

[^1]: https://www.zaproxy.org/docs/api/

[^2]: https://www.zaproxy.org/docs/docker/baseline-scan/

[^3]: https://duckdb.org/docs/
[Spring]thymeleafでプロパティを受け取る

## はじめに
controllerの引数@PathVariableでURLから受けとったプロパティを、
thymeleafで表示させる際の挙動について備忘録
※間違い等あればご指摘いただけますと幸いです。

## 環境
・JavaSE 17
・springframework 3.3.1
・PostgreSQL 12.17 
・MacOS 13.1

## 本題
idとnameからなる「カテゴリー」を登録・更新するformを作成する。
今回は更新の場合について注目。
カテゴリーの一覧画面から編集ボタンを押し、更新formを表示する流れを想定。
更新formには初期値として更新対象のid(readonly)とnameをinputエリアに表示させる。
※controllerとhtml部分のみ抜粋。

**CategoryController.java**
```
@Controller
@RequestMapping("/category")
public class CategoryController {
	
	@Autowired
	CategoryService categoryService;
	
		@ModelAttribute 
		public CategoryForm setUpForm() {
			CategoryForm categoryForm = new CategoryForm();
			return categoryForm;
		}

  // 中略

  // 編集ページ表示用
	@GetMapping("/{id}")
	private String showOneCategoryById(@PathVariable Integer id, 
			CategoryForm categoryForm, Model model) {
		categoryForm.setNewCategory(false);
		Optional<Category> categoryOpt = categoryService.selectOneById(id);
  
		if(categoryOpt.isPresent()) {
			Category category = categoryOpt.get();
			categoryForm.setId(category.getId());
			categoryForm.setName(category.getName());
		}
		
		model.addAttribute("categoryForm", categoryForm);		
		return "categoryPage";
		
	}
```
説明：
編集ボタンを押した際、URLパスに対象のidを設定、/category/{対象のid}にリクエストを送信、controllerのshowOneCategoryByIdで受ける。
@PathVariable Integer idでURLパスからidを取得。
idを条件にDBからレコードを取得し、CategoryクラスからCategoryFormクラスに詰め替えを行う。
model.addAttributeでcategoryFormオブジェクトをモデルに追加し、ビューに渡している。

**categoryPage.html(一部抜粋)**
```
	<div>
		<p th:if="${complete}" style="color: orange">[[${complte}]]</p>
		<form method="post"
		th:action="${newCategory}? @{/category/insert} :@{/category/update}" th:object="${categoryForm}">
			<label>ID：</label><br>
			<input th:if="${id}" readonly th:field="*{id}"><br>
			<label>カテゴリー名：</label><br>
			<input type="text" th:field="*{name}">
			<button type="submit">登録</button>
		</form>
	</div>
```
※新規登録と編集で共用のフォームになっているため、idは値がある場合＝更新の場合のみしか表示させない仕様。

渡されたcategoryFormから、*{id}、*{name}でそれぞれの値を取り出し、inputエリアに初期値として表示させている。

ふとここで疑問に思った。
idをmodel.addAttributeしていないのにth:if="${id}"が機能しているのはなぜだ・・・？と。

答えは下記にあった。
**CategoryController.java**
```
		@ModelAttribute 
		public CategoryForm setUpForm() {
			CategoryForm categoryForm = new CategoryForm();
			return categoryForm;
		}
  
        // 編集ページ表示用
        @GetMapping("/{id}")
        private String showOneCategoryById(@PathVariable Integer id, 
			CategoryForm categoryForm, Model model){
```
まず、@ModelAttributeでコントローラメソッドの引数で使用するフォームオブジェクトは自動的にモデルに追加される。

@PathVariableで受け取ったidは自動でmodelとcategoryFormにセットされる。
そのため、明示的にmodel.addAttribute("id", id)しなくても、thymeleafで＄{id}でアクセスすることができる。

また、上記により、
idは引数内でcategoryFormにセットされているため、model.addAttribute("categoryForm", categoryForm)しなくても
th：field="*{id}"でアクセスできるが、

nameはリクエストハンドラメソッド内で取得したパラメータなので、
model.addAttribute("categoryForm", categoryForm)しないと、
th：field="*{name}"でアクセスすることができない。


以上です。
fbxからアバターを構築するときの覚書

# パッケージの読み込み(VPAI化しておくと便利)
- Modular Avatar
- Liltoon
- LilicalInventory
- Av3Emulator

# モデルの読み込み
- フォルダ作成
- テクスチャを入れる、マテリアル作成
- fbxを入れる
- Materialsを適応、変だったらBlender見直し
- RigをHumanoidに設定、Chestを設定、Jawを外す
- Hierarchyに入れる
- 初回保存（この後は適宜保存）
    - メッシュ反転、結合忘れなど気づいたことがあれば修正

# セットアップ

- ルートにVRC Avatar Descriptorを付与
    - ViewPointを設定
    - LipSyncを設定
- ルートにMA Mesh Settingsを付与
    - AnchorOverrideを設定、Spineに設定
    - Boundsを設定、ルートボーンをHipsにして問題があれば調整
- 空のWD ONステートのControllerを作ってFXにセット


# 動作チェック1

- アップロードしてMMD等で正しく動くことを確認
    - AutoFixがあればやって保存しておく

# 細かい調整

- メインアバター等からPB・表情の設定をコピー
- SOM
- 距離クリッピングキャンセラー
深層強化学習の参考サイトまとめ

![スクリーンショット 2024-10-09 22.05.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900427/8ce41d48-9b49-f992-e0a7-e85bd2cf3976.png)


![puyopuyo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900427/1fdf8221-96c5-fcfa-3a52-383422a6fdc3.gif)
　ぷよぷよプログラミングAI学習システムは、中高生の自己調整学習に向けて開発されました。
　どうやって、Chromebookで、１０分で、素敵な人工知能を作れるのでしょうか？
　秘密は、３つ。
　１　jupyter liteで、webクライアントがpythonコードを実行
　２　超軽量な機械学習フレームワークdezeroを採用
　３　ぷよぷよのstageとactionがコンパクト

### Github&X

https://github.com/Lunanaedu/jupyterlite-puyopuyo

https://github.com/Lunanaedu/puyopuyo-kai

https://x.com/educationai_ai

### ぷよぷよプログラミングAI学習用まとめ

https://qiita.com/educational-ai/items/50c0fa689c01794d145e


# 深層強化学習の基礎

https://avinton.com/blog/2017/10/basic-deep-reinforcement-learning/

https://www.scsk.jp/product/oss/tec_guide/chainer_rl/1_chainer_rl1_1.html

# amaAI
2022年に開発された強豪AI

**ぷよぷよプレイヤーwiki**

https://w.atwiki.jp/puyopuyo-player/pages/151.html

**Youtube**

https://www.youtube.com/@ama_puyo

**X（Twitter）**

https://twitter.com/amapuyo

**GitHub**

https://github.com/citrus610/ama

**Discordリンク**

https://x.com/amapuyo/status/1799743420505923915

# puyoai
ぷよぷよ通のAIを書くためのフレームワーク
最終更新5年前

**Github**

https://github.com/puyoai/puyoai

# 研究論文
**深層強化学習を用いたぷよぷよAIの開発**
* ゲーム開始から10手の学習
* 上級者のプレイ動画から教師データを抽出し、深層学習
* 上級者のプレイを模倣するAIを開発



論文はこちら

https://www.jstage.jst.go.jp/article/fss/35/0/35_386/_article/-char/ja


***


**「ぷよぷよ」における深層強化学習による自己対戦の適応**

* 一人用ぷよぷよにおけるゲームルールの学習と性能向上を行った
* 深層強化学習と自己対戦を使った対戦用ぷよぷよにおける性能向上を行った

論文はこちら

https://www.jstage.jst.go.jp/article/pjsai/JSAI2023/0/JSAI2023_2M5GS1001/_article/-char/ja

以下のサイトで紹介されています。
**[JSAI2023]ゲーム開発に浸透するAI技術の諸相**

https://morikatron.ai/2023/06/jsai2023_game_and_entartainment/

***

**DQNを用いたぷよぷよの連鎖構築AI**
* DQNによる連鎖構築の学習
* 強いAIには勝てなかった

論文はこちら

https://www.jstage.jst.go.jp/article/fss/33/0/33_467/_article/-char/ja


***

**モンテカルロ木探索を用いたぷよぷよAI**
* Mayah（盤面を点数化する盤面評価システムとしらみつぶし探索を用いたAI）を参考にAIを作成
* 探索にモンテカルロ木探索を導入
* 高い点数を得られる盤面をより短い時間で探索することが目的

論文はこちら

https://www.jstage.jst.go.jp/article/fss/36/0/36_527/_article/-char/ja


# ぷよぷよ×強化学習
**DQNでぷよぷよを学習してみる**
* GitHubにソースあり
* GPUは使わない

https://qiita.com/tsuro/items/1f5b5cc0bfc03a18624c

***

**AlphaZeroで最強のターン制ぷよぷよAIを作る！**
* ソースコード無し
* 「AlphaZero 深層学習・強化学習・探索 人工知能プログラミング実践入門　著　布留川英一」を参考に実装

https://ykicisk.hatenablog.com/entry/2020/04/05/193356

***






https://tamatebako.i.nagoya-u.ac.jp/5513/


https://www.jaist.ac.jp/is/labs/ikeda-lab/rs_poje.html



https://note.com/puyo_conference/n/n5474b911ee8f

# アルゴリズム
**[強化学習]モンテカルロ木探索を解説・実装**
* モンテカルロ木探索
* 木探索アルゴリズムの一種
* 適当な回数ランダムに実行し、その結果から結論を導くアルゴリズム

https://qiita.com/pocokhc/items/392a7f89c79f5e1e6bca




# ぷよぷよ積み方
**ぷよぷよの連鎖土台一覧**
* 18種類の積み方が記載されている
* 詳しく積み方を記載しているものとそうでないものがある
* 全ての積み方において画像あり

https://mickey1blog.com/form/

***

**9割の人が使う形「GTR」のつくり方**
* 画像あり
* GTRの基本
* ２連鎖

https://puyo-camp.jp/posts/169779
ぷよぷよプログラミング

![puyopuyo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900427/1fdf8221-96c5-fcfa-3a52-383422a6fdc3.gif)
　ぷよぷよプログラミングAI学習システムは、中高生の自己調整学習に向けて開発されました。
　どうやって、Chromebookで、１０分で、素敵な人工知能を作れるのでしょうか？
　秘密は、３つ。
　１　jupyter liteで、webクライアントがpythonコードを実行
　２　超軽量な機械学習フレームワークdezeroを採用
　３　ぷよぷよのstageとactionがコンパクト

### Github

https://github.com/Lunanaedu/jupyterlite-puyopuyo

https://github.com/Lunanaedu/puyopuyo-kai

### ぷよぷよプログラミングAI学習用まとめ

https://qiita.com/educational-ai/items/50c0fa689c01794d145e


# ぷよぷよプログラミングとは
プログラミング学習環境「Monaca Education」において、セガが展開するアクションパズルゲーム「ぷよぷよ」をプログラミング学習できる教材です。無料で利用できます。

https://puyo.sega.jp/program_2020/

# やってみた

https://note.com/ganbaruonna/n/nfa922e36451b

https://qiita.com/san_bay3/items/8933ec9423318a72b93e
dezeroまとめ

![スクリーンショット 2024-10-09 22.05.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900427/21e2dcc1-9050-e3f9-4ea3-818a286bfaa6.png)


![puyopuyo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900427/1fdf8221-96c5-fcfa-3a52-383422a6fdc3.gif)
　ぷよぷよプログラミングAI学習システムは、中高生の自己調整学習に向けて開発されました。
　どうやって、Chromebookで、１０分で、素敵な人工知能を作れるのでしょうか？
　秘密は、３つ。
　１　jupyter liteで、webクライアントがpythonコードを実行
　２　超軽量な機械学習フレームワークdezeroを採用
　３　ぷよぷよのstageとactionがコンパクト

### Github&X

https://github.com/Lunanaedu/jupyterlite-puyopuyo

https://github.com/Lunanaedu/puyopuyo-kai

https://x.com/educationai_ai

### ぷよぷよプログラミングAI学習用まとめ

https://qiita.com/educational-ai/items/50c0fa689c01794d145e


# 本の紹介
ゼロから作るDeep Learning３　フレームワーク編　斎藤康毅　著

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900427/883cac2c-9c47-17e1-a64d-faeba97de39f.jpeg" width=50%>

↓Amazon購入サイト

https://www.amazon.co.jp/dp/4873119065/ref=cm_sw_r_tw_dp_U_x_KiA1Eb39SW14Q
next.jsにおけるレンダリングの違いについて思うこと

新規開発時、技術スタックとしてフロントエンドをReactで構築することだけは決まった。
レンダリング方法はどれが正解なのかよく忘れるので毎回調べてしまう。

備忘録としてまとめようとしたけど、ほとんど個人的な感想ばかりになってしまったので、読み物として。
間違いあれば指摘してくださいmm

以下の表はReact(next.js)におけるレンダリング方法の違いである。

| 種類 | 説明 | 特徴 | 利用シーン | 向いているアプリケーション |
|------|------|------|----------|-----------------------------|
| **SPA**（Single Page Application） | ページを一度に読み込み、必要に応じてコンテンツを動的に更新 | - ページ遷移が速い<br>- インタラクティブな操作が可能<br>- 初回ロードが重い<br>- SEO対応が難しい | - 高度なインタラクション<br>- リアルタイム更新が多い | - SNS、ダッシュボード、チャットアプリ |
| **SSG**（Static Site Generation） | 事前にページを静的HTMLとして生成し、ユーザーに配信 | - 事前ビルドで高速表示<br>- サーバー負荷が軽い<br>- SEOに強い<br>- 動的コンテンツには不向き | - 頻繁に更新がないサイト<br>- SEOが重要なサイト | - ブログ、企業サイト、ドキュメンテーション |
| **SSR**（Server Side Rendering） | リクエストごとにサーバーでHTMLを生成し、ユーザーに配信 | - 初回表示が速い<br>- 動的なデータに対応<br>- サーバー負荷が高い<br>- リクエストごとにレンダリング | - データが頻繁に更新されるサイト<br>- リアルタイム性が重要なサイト | - ニュースサイト、ECサイト、SNS |
| **ISR**（Incremental Static Regeneration） | 静的生成されたページを、バックグラウンドで段階的に更新 | - 静的生成の利点を活かしつつ、部分的に最新データを反映<br>- サイトのパフォーマンス維持<br>- 必要な部分だけを更新可能 | - 頻繁に更新があるが、リアルタイムでなくてよいサイト<br>- パフォーマンスが重要なサイト | - ブログ、ECサイト、ニュースアプリ |

簡単にchatGPTで生成したものだが、個人的な見解をさらに記述する。

#### デプロイ先
next.jsのデプロイ先といえばvercelがデファクトスタンダードはご周知の通り。
しかし知名度的の問題か、今までEC2へデプロイを希望するケースが多かった。
AWSは料金が高額になりがちなので、オンプレ→AWS→オンプレ（もしくは別のクラウド）のように戻るケースもあるらしい。
vercel以外でnext.jsを使用する場合は色々設定が面倒なので、後で後述する。

# SPA
そもそもnext.js使用しない選択はないだろうか？
自分がそうだったが、SPAは遅そうだからnext.jsにしとこう。SSRが良さそうなんてことになっていないだろうか。

SEO対策が特に必要なく、管理画面作るくらいであればSPAで十分だと思う。
速度面が問題にされているが、キャッシュで古いデータが表示された場合の対応など、それはそれでコストがかかる。
（そもそもパフォーマンスに問題がある場合、フロントの処理以前にもっと見直すべきところあると思う派）
page別にroutingしたい場合、`tanstackRouter`導入すればいいし、個人的に気に入っているのはURL欄が汚れないところ。（amazonとかrakutenとかマジ汚い）

**SPAのデプロイ先候補：**
Vercel, Netlify, GitHub Pages, Cloudflare Pages, S3

いずれも設定すれば`yarn deploy`コマンドなどを使用することにより、簡単にデプロイできるのでとにかく楽。

# SSG
上記の表にあるように、主にブログとされているが、フルスタックフレームワークのnext.jsを使用しないと構築できないような巨大ブログ用ってことだろうか？？

2024年10月現在、最近gatsby聞かないけど、どうなったんだろう‥。
結局SSGは今まで使ってこなかったが、今後も使うことないような気がする。

# SSR
next.js=SSRだと思っている。
`getServerSideProps`を使用して、関数内のコードをサーバーで実行（サーバーリソースで計算）させることができる。
SSR使えばとにかく高速なページが作れると思っていたが、そういうわけでもない。

[Link と ISR が引き起こす Next.js の過負荷](https://zenn.dev/takepepe/articles/nextjs-isr-prefetch)

こちらの記事が有用なので、そのまま貼ります。
Linkコンポーネントにprefetchをつけると速くなる。→サーバー負荷がかかる。
AWSのサーバー代は超高額。

大企業でお金あります！　→ OKそう
スタートアップで資金調達済み！　→ OKそう
スタートアップでお金ありません！　→ 無理そう
中小企業の営業で技術的なこと何もわかりません！　→ 無理そう

以下小言。
Vercel以外にデプロイする場合は簡単だけど、nginxからリバースプロキシしてあげる必要あり。
vercelはEC2が元となっています。
EC2のサーバー環境は、普通のデータセンターと変わらないし、物理的には結構落ちるようだ。
アプリケーションが速くても、ネットワーク遅ければ同じと思う。
アプリケーションが速くても、非力なデバイスでアクセスされたら遅いと思う。
サーバーリソース上げたら速くなる、ケチったら遅い。つまりサーバー側で計算リソースを提供するか、クライアントに任せるか。

開発する分には、巣のreactの開発と特に違いはないと思う。
serverSidePropsが存在して、書いてるコードがどこで実行されているのか、意識するところが違うだけ。

そもそもサーバーサイドで計算させないといけないようなフロントのコードって何？
重たい計算とか言っているけど、それAPI側のリソース使えばいいんじゃないの？
APIで高額なサーバーを用意して、フロントで高額なサーバーを用意して、その他いろんなAWSのサービスを使って、AWS儲けすぎじゃね？
と思っている派。

# ISR
Vercelにデプロイするのが大前提。
基本はSSGの挙動で`getStaticProps`を使用する。
これに加えて`revalidate`を設定することにより、任意のタイミングでフェッチを行う。

潤沢な資金がある場合は、AWSで構築することも可能。

# 結論
next.jsを使用するか、どのレンダリング方法が良いかは案件次第＆デプロイ先次第だと思う。
エンジニア的には新しい技術をぶりぶり使って、いかにも有能さをアピールしたいところではあるが、クライアントのお財布事情を考えた方が自分の身入りにもなると思う。（サーバーにお金かかりすぎて、自分の報酬が減ったりすると嫌なので）