OmniAICreator/Qiita-1.07M huggingface dataset:
[メモ] pytest 7.2.2を使用しているとVSCodeのPytestプラグインがテストを見つけてくれない

https://github.com/microsoft/vscode-python/issues/23773

## 現象
`pytest 7.2.2`を使用しているとVSCode起動時にPytestプラグインがテスト検索に失敗する。

バージョンを確認すると`7.2.2`だった。
```shell
$ pip show pytest
Name: pytest
Version: 7.2.2
```

## 解決方法

pytestのバージョンを最新版に更新し、VSCodeを再起動する。


```shell
$ pip install pytest --upgrade
$ pip show pytest
Name: pytest
Version: 8.2.2
```

---
AWSのECSファーゲートでウェブアプリをデプロイしたい

# コンテナをそのまま使えるやつ？
fargateってdockerコンテナをそのまま使えてドメインまで与えながらロードバランサーも簡単につけられるプロダクトってイメージ持ってます。※合ってるかは知りません
ただ設定がすごくめんどくさかったので備忘録で残しておきます。

# 手順
## １、ECRを作成してimageをpush
Amazon Elastic Container Registryでリポジトリを作成
↓
プッシュコマンドを表示 でCLIを用いてpushできる
自分はshellファイル作りました。
```shell
## AWSにログイン
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin <ECRのarnみたいなやつ>
## dicker imageのビルド
docker compose up -d
## imageにtag付け
docker tag dev-indeed-entry-express:latest 654654318735.dkr.ecr.ap-northeast-1.amazonaws.com/dev-indeed-entry-express:latest
## リポジトリにpush
docker push <ECRのarnみたいなやつ>
```

## ２、タスク定義
名前をつけて必要なスペックを入力<br>（とりあえずデフォルトのままにしました、お金怖い、、、）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833494/8486b881-c8c7-58e3-1aee-cea558b6ac82.png)

さっきのコンテナを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833494/2593eb02-e2a7-072f-081f-18805abfbcbe.png)

## ３、クラスターの作成
もちろん使うのはFargate
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833494/fdedc60e-57aa-ca13-040b-5dbfbba25e88.png)

## ４、ロードバランサーの作成
今回はアプリケーションをデプロイしたいのでApplication Load Balancerを使います 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833494/1a69a49d-f424-3754-b1ad-03e9efb0433e.png)
名前つける以外はそのまま
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833494/e4cb9758-9a98-ead0-18ad-109bfb051291.png)
VPCもdefaultのものでよいですが、インバウンドの設定で443と80は開けときましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833494/77957b23-6e79-7824-16de-a208f6e1ea0b.png)
ターゲットグループもここで作成
ロードバランサーに接続してきた人をコンテナで開けたportに転送する設定です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833494/ff999f98-587c-977c-d2af-bc2e1b83339b.png)


## ５、サービスの作成
環境はよくわからないのでそのままでいきます。

名前をつけて、タスクはとりあえず2にしときます。
※片方がクラッシュしたときとかに2つあれば便利そう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833494/8010a40d-0ea3-5415-b93f-f8f5247677b0.png)

ロードバランサー、リスナー、ターゲットグループは前項のものを使用してサービスを作成

## タスク
サービス作成後、自動で動き出します。cloud formationで見守りましょう。
立ち上がったら完成です！

# その他
route53でドメインを購入し、ACMで証明書を取得することでHTTPSの接続も可能になります。
WAFをつけたりとAWSってお金は高いですが簡単に技術を導入できる良いサービスですね！
Railsでhaml-rails gemをインストールしたのに新規生成されるviewファイルが全部erb拡張子になってた話

## 読んで欲しい人

- hamlをインストールしたのに、自動生成されるファイルの拡張子が全部.erbになって困っている人
- 過去の俺

## 動作環境

- Ruby 3.3.0
- Rails 7.1.3.4

## エラー内容

- gemfileにhaml-railsの記述があるのに、generateコマンドで生成されるviewファイルの拡張子が.erbになっている

```ruby

# gemfileの中身

source 'https://rubygems.org'

ruby '3.3.0'

gem 'rails', '~> 7.1.3', '>= 7.1.3.2'

gem 'bootsnap', require: false
gem 'pg', '~> 1.1'
gem 'puma', '>= 5.0'
gem 'sprockets-rails'
gem 'stimulus-rails'
gem 'turbo-rails'
gem 'haml-rails' #hamlを使用できるようにするgem
gem 'html2haml' #erbをhamlに変えてくれるgem

```

- `rails g controller ModelName`とかを打つと、viewファイルがerbで生成される


## 解決方法

- gemfile内のgemを追記する場所を変えると、viewファイルをhaml拡張子で自動生成してくれた

```ruby

# 修正後のgemfile

source 'https://rubygems.org'

ruby '3.3.0'

gem 'rails', '~> 7.1.3', '>= 7.1.3.2'

gem 'bootsnap', require: false
gem 'pg', '~> 1.1'
gem 'puma', '>= 5.0'
gem 'sprockets-rails'
gem 'stimulus-rails'
gem 'turbo-rails'

# 開発環境とテスト環境内で使用する
group :development, :test do
  gem 'haml-rails'
  gem 'html2haml'
end

```

## 原因

現時点ではわかりませんでした。

ただ、haml-rails gemはhamlジェネレータをrailsの5, 6, 7系に提供をすることで、hamlをディフォルトのテンプレートとして設定してくれています。

haml-railsのreadmeには特に環境指定をするような記述はないので、自分の知識不足だったのかもしれません。

https://github.com/haml/haml-rails

## 補足

同じ様なgemに`hamlit-rails`というgemがあるらしいです。

既存の`haml-rails`に挙げられているissueを参考にして生成されたgemらしいのでパフォーマンスはこちらの方が良いのかしら？

https://github.com/mfung/hamlit-rails

### ネットに落ちていたhamlit-railsについての記事

https://k0kubun.hatenablog.com/entry/2015/03/31/004021

https://qiita.com/kaba/items/208387228d50fb7eb8dc
DatadogAgentで複数のSNMP(v3)ユーザーを使用する方法

#### 初めに
Datadog AgentでSNMPのマネージャー側の設定をする機会がありました。
その際に、監視対象の機器側でユーザー名の命名規則に対立があり、一つのユーザーでは管理できない状況となりました。
そこで、Datadogの[ドキュメント](https://docs.datadoghq.com/ja/network_monitoring/devices/snmp_traps/?tab=yaml)を見てるとこんな文言(下図)が、今回は対応が必要でしたのでDatadog社に確認しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678759/843c6143-7508-6b26-2df5-5c7f6a3588e3.png)

## 回答
Datadog社の回答としては、英語版のドキュメントを見てねとのことでした。
先ほどのドキュメントで右側のLanguageをEnglishにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678759/18850740-47c3-bdbf-c032-5656f4626087.png)

そして、Configulationまでスライドをしてみてみると・・・
下図のようにサンプルがありました。これで設定は大丈夫ですね！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678759/93ec5470-48ab-76a8-0106-f9ba5d4ddd16.png)

## 注意点
ただし、設定には以下条件があるようなので注意が必要です。
・Datadog Agent 7.51 以上であること
Rspecを始めて行う

```
bundle exec rspec spec/models
```
このディレクトリ以下のテストを実行する

```ruby
RSpec.describe User, type: :model do
  context "with 2 or more comments" do
    it "orders them in reverse chronologically" do
      user = User.create!(:name => "hogehoge", :email => "gehogeho",  :forign => 1)
     expect(user).to eq(user)
    end
  end
end
```
テストのコメントは出鱈目です。(後でやります）
```ruby
expect(user).to eq(user)
```
In RSpec, assertions are called expectations, and every expectation is built around a matcher. When you expect(a).to eq(b), you’re using the eq matcher.
### 出典
https://rspec.info/documentation/6.1/rspec-rails/#:~:text=In%20RSpec%2C%20assertions%20are%20called%20expectations%2C%20and%20every%20expectation%20is%20built%20around%20a%20matcher.%20When%20you%20expect(a).to%20eq(b)%2C%20you%E2%80%99re%20using%20the%20eq%20matcher.

#### 自分の訳
Rspecにおいて断言は期待と呼ばれる。そして全ての期待はマッチを中心に建てられる。あなたが期待値aでマッチはbの時、あなたはeqマッチを使用する

とりあえず
```ruby
RSpec.describe Widget, type: :model do
  it "has none to begin with" do
    expect(Widget.count).to eq 0
  end
```
# 出典
https://rspec.info/features/6-0/rspec-rails/model-specs/transactional-examples/#:~:text=require%20%22rails_helper%22-,RSpec.describe%20Widget%2C%20type%3A%20%3Amodel%20do%0A%20%20it%20%22has%20none%20to%20begin%20with%22%20do%0A%20%20%20%20expect(Widget.count).to%20eq%200%0A%20%20end,-it%20%22has%20one

とりあえず
eqの値と一致すればテストが通るらしい。

# その他のマッチャー
https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/equality/

# 感想
生成したモデル同士を比べているから同じなのは当たり前だがテストを通ることができたので良しとする。
MySQLで爆速！簡単にランダムなテストデータを生成する方法

データベースのテストには、さまざまな種類のデータが必要です。ここでは、MySQLでランダムなテストデータを生成する簡単な方法をいくつか紹介します。

# 1. ランダムな文字列を生成する
まず、ランダムな文字列を生成する方法です。以下のクエリを使用すると、ランダムな文字列を取得できます。

```sql
SELECT SUBSTRING(MD5(RAND()), 1, 10) AS random_string;
```

# 2. ランダムな整数を生成する
次に、特定の範囲内のランダムな整数を生成する方法です。RAND()関数を使用します。
```sql
SELECT FLOOR(RAND() * 100) AS random_number;
```

# 3. ランダムなデータを含むテーブルを作成する
例えば、ユーザー情報を含むテーブルを作成し、ランダムなデータで埋める場合は以下のようにします。

まず、テーブルを作成します。
```sql
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100),
    age INT
);
```
次に、ランダムなデータを挿入します。

```sql
INSERT INTO users (name, email, age)
SELECT 
    SUBSTRING(MD5(RAND()), 1, 10),
    CONCAT(SUBSTRING(MD5(RAND()), 1, 5), '@example.com'),
    FLOOR(RAND() * 100)
FROM 
    information_schema.tables
LIMIT 100;
```
このクエリは、information_schema.tables テーブルからデータを取得し、100行分のランダムなデータを users テーブルに挿入します。

# 4. Fakerライブラリを使用する
よりリアルなテストデータが必要な場合、PythonのFakerライブラリを使用してデータを生成し、それをMySQLに挿入する方法もあります。以下はその例です。

まず、PythonとFakerをインストールします。
```bash
pip install mysql-connector-python faker
```
次に、Pythonスクリプトを書いてデータを生成し、MySQLに挿入します。

```python
import mysql.connector
from faker import Faker

# MySQLに接続
conn = mysql.connector.connect(
    host='localhost',
    user='your_username',
    password='your_password',
    database='your_database'
)
cursor = conn.cursor()

# Fakerインスタンスを作成
fake = Faker()

# ランダムなデータを生成して挿入
for _ in range(100):
    name = fake.name()
    email = fake.email()
    age = fake.random_int(min=18, max=80)
    
    cursor.execute(
        "INSERT INTO users (name, email, age) VALUES (%s, %s, %s)",
        (name, email, age)
    )

conn.commit()
cursor.close()
conn.close()
```
これで、ランダムなテストデータを簡単に生成してMySQLに挿入できます。ニーズに応じて、これらの方法を組み合わせて使用することも可能です。
統計学でよく見る定理のまとめ

## はじめに
統計学を勉強すると、重要な性質の証明にさまざまな定理が出てきます。
いちいち調べなおすのも大変なので、備忘録としてここに貯めておきます。
今後も内容を追加していけると良いと思っています。


## 大数の弱法則
:::note 
### 大数の弱法則

任意の$i$について確率変数$\theta_i$が独立同分布かつ$\mathbb{E}[|\theta_i|]$が有限であると仮定する。
標本平均を
```math
    \overline{\theta}_{(n)} = \frac{1}{n}\sum_{i = 1}^n \theta_i
```
と表すとき、これは$\mathbb{E}[\theta_i]$に確率収束する。
```math
    \forall \varepsilon > 0,\ \exists N \in \mathbb{N}:\ \forall n \in \mathbb{N},\ 
    n > N \implies \Pr(|\overline{\theta}_{(n)} - \mathbb{E}[\theta_i]\
    | > \varepsilon) = 0.
```
:::

### 説明
ある確率変数を$X$とし、その期待値$\mu$と分散$\sigma^2$が有限値で与えられるとき、
```math
  \forall k > 0,\ \Pr(|X - \mu| \geq k\sigma) \leq \frac{1}{k^2},
```
が成り立つことが知られています（チェビシェフの不等式）。
また、$\theta_i$が独立同一分布であるという仮定から、任意の$i$について$\mathbb{V}[\theta_i] = \sigma^2$とすると、
```math
  \mathbb{V}\left[\overline{\theta}_{(n)}\right] = \frac{\sigma^2}{n},
```
であることがわかります。この２つを用いると、
```math
  0 \leq \Pr(|\overline{\theta}_{(n)} - \mathbb{E}[\theta_i]| > \varepsilon)
  \leq \frac{\mathbb{V}\left[\overline{\theta}_{(n)}\right]}{\varepsilon^2}
  = \frac{1}{\varepsilon^2}\frac{\sigma^2}{n},
```
を得て、最右辺は$n \to 0$の極限において0に収束します. よって、はさみうちの定理から大数の弱法則がしたがいます。


## 連続写像定理
:::note
### 連続写像定理
$\\{\theta_n\\}_{n = 1}^{\infty}$を確率変数の列、$c$を定数とする。実数値関数$g$が$c$で連続ならば、
```math
    \theta_n \overset{p}{\to} c
    \implies g(\theta_n) \overset{p}{\to} g(c),
```
が成り立つ。ただし、$\overset{p}{\to}$は確率収束を表す。
:::

### 説明
実数値関数$g$が$c$で連続であるので、
```math
  \forall \varepsilon > 0,\ \exists \delta > 0: 
  |\theta_n - c| \leq \delta \implies |g(\theta_n) - g(c)| \leq \varepsilon,
```
がいえます。ここで、対応関係と余事象を考えると、
```math
\begin{align*}
  \Pr(|\theta_n - c| \leq \delta) \leq \Pr(|g(\theta_n) - g(c)| \leq \varepsilon),\\
  \Pr(|g(\theta_n) - g(c)| > \varepsilon) \leq \Pr(|\theta_n - c| > \delta).
\end{align*}
```
いま, $\theta_n \overset{p}{\to} c$を仮定すると, $n \to 0$で
```math
  0 \leq \Pr(|g(\theta_n) - g(c)| > \varepsilon) \leq \Pr(|\theta_n - c| > \delta) \to 0.
```
よって、はさみうちの定理から
```math
g(\theta_n) \overset{p}{\to} g(c)
```
が言えます。
🔰アルゴリズムの勉強の仕方を考える


## Q. プログラミングの勉強とアルゴリズムの勉強を分けたい
A. 数学の証明問題が近い

が、そもそも数学の知識が必要になってくるので苦手な人には良い方法ではない可能性が高いので、回答としては成立していても質問者の意図には添えていない可能性が高いので、ここでは別解を考えていきます。

:::note warn
レベルは主観です
人によっては無勉強でも次のレベルがあっさりと理解できるケースがあります（それも結構な頻度で）が、本当に難しいと感じる人にとっては妥当な設定になっているはず
:::

## Lv1. アルゴリズムをクイズにした例
とても良い取り組みだと思ったので紹介します。

https://www.youtube.com/watch?v=jzHwZbKI-YI

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

動画のコンテンツとしてのクイズではあるのですが、アルゴリズム問題としても非常に優秀です。

## Lv7. プログラミングを使わない発展系
1から作るならまだしも、0から作ります。
何もコードがない状態から書き起こす事もありますので、1ではなく0です。

https://www.nintendo.com/jp/switch/awuxa/index.html

ゼロから作るけど、ナビ付きなので最初の手順からどのようにゲームプログラムを書き起こすのかを可視化・体験できるすばらしいソフトです。

また、scratchを使う方法もあります。

https://scratch.mit.edu

## Lv12. プログラミングの問題へ
環境構築を伴わないものを想定しています。JavaScriptとか
このステップになると、とりあえず出力命令や四則演算を書いてみて、ガチャガチャいじる運用ケース（学習フェーズ）を想定します。

### Lv19. 条件分岐を使う
条件分岐処理を単独で書くと難しさは分かりませんが、たとえばif文ならelseやelse-if、ここにネストまで入れると複雑さが増します。
特にExcelで悩まされるケースは多いと思いますが、Excelで使いこなせるレベルがここでのレベルの期待値です。

なお、switch-caseも含まれます。

### Lv35. 繰り返し処理を使う
if文と比べると繰り返し処理が難しいのですが、仕組みをしっかり押さえておけばif文の条件にある限り繰り返していると考えることもできます。
for文はwhile文を理解した上で便利にしたもの、という学習の仕方をすると気付きやすいですが、大体はfor→while(do-while）の順で、前置と後置の概念まであるので純粋な条件処理の時と違って実行順まで気にする必要があります。

こういった考え方の組み合わせになれていって、その上で課題に着手していくぐらいのが良いのでは、と思ってます。

## Lv74. 配列との組み合わせによる繰り返し処理
配列に対して苦手意識がある人が多くなるのは、配列と繰り返し処理が切っても切り離せない前提で話があるため、という考え方もできます。
「配列の各要素に値を代入していく処理が面倒くさい！」とか「配列に連続して値を代入する処理がある」などを繰り返し構文を使うことで処理が楽になるという実感が分かりにくいのが問題で、たとえば(配列).forEachが使いにくいと思ってしまう要因にもなります。
配列の繰り返しでforEach構文を使うととても簡単！というのはあくまで仕組みやforEachの目的を認識している人の感覚で、まずは繰り返しを使うと便利になるという体験をする必要があります。

この段階にくると、今後のプログラミングコード全てに言えますが便利である事を理解して、導入していくための方法に着目していくと比較的解決しやすくなってきます。

## 経験値獲得を高めるためのスキル：PCリテラシースキル
たとえば、プログラミングはAIを活用すれば作れるよ、という人がどんどん出てきています。
これ自体は良い流れなのですが、いわゆるPCスキルの向上には寄与しないため、たとえばパソコンの操作体験(UX)を含めて「このアプリは大体こういう操作をするだろう」という操作自体への慣れについて、プログラミングスクールでは残念ながら考慮されていません。
ただしPCスキルはプログラミング学習をはじめPCを使ってのあらゆる活動に直結・影響します。シンプルにPCの操作がうまい・慣れている人がレベルアップも早い傾向があります。
極端な表現をすると、PCスキルはプログラミングにおいては基礎体力に相当する項目だと思ってよいです。プログラミングを筋トレに例えるなら、PCの操作が上手い人は基礎体力があるのでトレーニングが続きます。
まずはPCスキル面を高めて、ある程度操作・検索スキルが身についた後でアルゴリズム→プログラミングへとステップアップすると良いでしょう

## 昨今PCスキルとして注目されているのがプロンプトエンジニアリング
ここからは仮説や所感が多く根拠不十分ですが、プロンプトエンジニアリングはいわゆるアルゴリズムやプログラミングスキル面以外のスキルという位置付けです。
無理やり分類するなら、いわゆるワードやらエクセルやら、という内容ですね。これらと同等のカテゴリではありますが、ワードエクセル同様、専門スキルに分類できます。
プロンプトエンジニアリングのスキルを高めると直接的にアルゴリズムやプログラミングスキルを高める事にはつながりませんが、これらも含めて他の分野への強力なサポートが得られます。
特にAIは強力すぎるので活用方法を間違えると既存の勉強方法とはマッチしません。既存の勉強方法を踏襲するならAIの使い所は考える必要がありますし、同様にAIを活用した上で解決を目指す方法を考える必要もでてきます。

古い表現をすると、初見のゲームを攻略するのにいきなり攻略サイトや攻略本を使うようなものです。古いゲーマーの方なら共感しやすいと思います。

## 更にレベルの高いステージへ
関数の話や、オブジェクト指向、ライブラリの話を含めもっとレベルの高い、具体的には三桁以上の話はここに含めません。
なんなら、アプリ側の話ばかりでサーバーの話については本稿では全く触れていないため、まだまだ先の世界はありますが、これらも触れません。
この段階になっていたら、アルゴリズム面の問題については思考力的には問題なく（時間はかかるが、なんとか正解を導ける状態）対応できる状態になっているはずです。

まずはこの辺りを修められるように学習計画を考えていきましょう。
axios を使う

Vue勉強中にaxios というライブラリが出てきたので、調べた。

> HTTP通信（データの更新・取得）を簡単に行うことができる、JavaScriptのライブラリ。

とのこと。
Vueを使うのに必須という訳ではなく、Vueとは無関係に、このライブラリ単体で使えるものらしい。

https://qiita.com/s_taro/items/30114cfa370aac6c085f

axios には、`get` 以外にも `delete`, `post`, `put` と言った関数があるようだ。

https://qiita.com/ksh-fthr/items/2daaaf3a15c4c11956e9

https://rakuraku-engineer.com/posts/axios/

(Vue.js 3.1.5を使用)


```javascript:javascript
const app = Vue.createApp({
    data: () => ({
        users: []
    }),
    mounted: function() {   
        axios.get('https://jsonplaceholder.typicode.com/users')
        .then(response => this.users = response.data)
          .catch(error => console.log(error))
    },
})

app.mount('#app')

```


`mounted` は、ライフサイクルフックの１つで、Viewインスタンスがマウントされたときに呼ばれる。

`axios.get(url)`で、urlからデータを取得することができる。
成功した場合は、`then()`の中にレスポンスが返ってくる。
レスポンスは以下のような中身になっているので、
```javascript:レスポンス
{
  // サーバーから提供されたレスポンス
  data: {},

  // サーバーのレスポンスに含まれる HTTP ステータスコード
  status: 200,

  // サーバーのレスポンスに含まれる HTTP ステータスメッセージ
  statusText: 'OK',

  // サーバーが応答した HTTP ヘッダー
  // ヘッダー名はすべて小文字で、ブラケット記法でアクセスできます。
  // 例: `response.headers['content-type']`
  headers: {},

  // リクエストの際に `axios` に提供された設定
  config: {},

  // このレスポンスを生成したリクエスト
  request: {}
}
```
ので、`response.data` とすることで、データの内容を取得することができる。

URLの、https://jsonplaceholder.typicode.com/users から返ってくるデータの内容は、
以下の形式になっていて、

```json:データ
[
  {
    "id": 1,
    "name": "Leanne Graham",
    "username": "Bret",
    "email": "Sincere@april.biz",
    "address": {
      "street": "Kulas Light",
      "suite": "Apt. 556",
      "city": "Gwenborough",
      "zipcode": "92998-3874",
      "geo": {
        "lat": "-37.3159",
        "lng": "81.1496"
      }
    },
    "phone": "1-770-736-8031 x56442",
    "website": "hildegard.org",
    "company": {
      "name": "Romaguera-Crona",
      "catchPhrase": "Multi-layered client-server neural-net",
      "bs": "harness real-time e-markets"
    }
  },
  (以下略。複数人続く・・・。)
```

HTMLで、このデータのうち、`name`、`email`、`company.name` を表示するようにすると、

```html:html
<body>
    <div id="app">
        <ul v-for="user in users">
            <li >{{ user.name }}</li>
            <li>{{ user.email }}</li>
            <li>{{ user.company.name }}</li>
        </ul>
    </div>
</body>
```

以下のように表示された。

### 画面表示
![5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284134/8638150c-683a-5911-859e-89a2c96a97e8.png)
ITパスポート Webページ

・インターネットサービスプロバイダ
インターネットへの接続サービスを提供する事業者

・WWW（World Wide Web）
インターネット上の文字や画像、動画、音声などの様々な情報を「いつでも」「どこでも」「誰でも」扱えるように構築されたシステム

・URL
Webページなどの位置情報やプロトコルなどを指定する

https:// プロトコル
www3. ホスト名
jitec.ipa.go.jp ドメイン名
/JitesCbt/html/openinfo/ パス名（ディレクトリ名）
questions.html ファイル名

・パンくずリスト
トップページから各Webページへの経路情報

・Cookie
Webサーバにアクセスした利用者のWebブラウザに、Webサーバからの情報を一時的に保存する仕組み

・検索エンジン
・クローラ
Webページを巡回して、情報を収集するソフトウェア

・SEO
検索の際に上位に表示されるように、検索エンジンに高い評価を受けるWebサイトを作る工夫や技術

・共起キーワード
あるキーワードと同時に使用されることが多いキーワード

・CDN
コピーしたデータを各地のWebサーバに分散配置する仕組み
UnrealEngineのScalabilityのEffectsの内容をカスタムする

UnrealEngineのScalabilityのEffectsを設定する際にr.SkyLight.RealTimeReflectionCaptureを設定したくなかったのでどうすればいいのか調べたのでメモしておきます。

# 確認した環境

UE5.3.2

# 参照した情報

* [Customizing Scalability Settings - Development / Platform & Builds - Epic Developer Community Forums](https://forums.unrealengine.com/t/customizing-scalability-settings/393927)
* [Unreal Engine のスケーラビリティ | Unreal Engine 5.4 ドキュメンテーション | Epic Developer Community](https://dev.epicgames.com/documentation/ja-jp/unreal-engine/scalability-in-unreal-engine?application_version=5.3)

# 確認した内容

以下のようなファイルを配置するとScalabilityのEffectsを変えてもr.SkyLight.RealTimeReflectionCaptureが実施されないようになりました。

```ini:[プロジェクト]/Config/DefaultScalablity.ini
[EffectsQuality@0]
-r.SkyLight.RealTimeReflectionCapture=0

[EffectsQuality@1]
-r.SkyLight.RealTimeReflectionCapture=0

[EffectsQuality@2]
-r.SkyLight.RealTimeReflectionCapture=1

[EffectsQuality@3]
-r.SkyLight.RealTimeReflectionCapture=1

[EffectsQuality@Cine]
-r.SkyLight.RealTimeReflectionCapture=1
```

以下はうまくいかなかった事例です。

* UE_5.3/Engine/Config/BaseScalability.iniのEffectsの設定をコピーしてきてr.SkyLight.RealTimeReflectionCapture=0にする => Editor Playでは効くがパッケージングすると効かなかった
* [プロジェクト]/Config/BaseScalablity.iniに書く => 効かなかった
Difyを使って選手名から選手の球場飯を表示させたかったけど全員カレー表示になって困っている

私は野球が好きなので球場によく行きます。球場飯って今すんごくおいしいんですよ！
ちょっと高めですけどね。推し選手の球場飯とか食べたがりです！

## 【結論】失敗したのでご報告
<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784193/496c1d3e-d195-70a0-b4eb-685f08a62348.png">

Difyを使ってみたけど、多分プロンプトの書き方が悪かったのか、見事に**カレーライス**になった笑
もはやカレーライスbotだ。

<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784193/04f6dd91-08d6-b669-3916-9fb5672e246f.png">

<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784193/b022e41d-29c6-4c17-f295-859246c55fb9.png">

Googleさんは球場飯=カレーライスと思ってる以外こんな答えは返ってこないと思うんだ。

## ホーム球場以外の野球飯をカンタンに知りたい
これを作ってみた背景をお伝えします。

ちなヤクなので、神宮でのご飯はだいたい把握してます。
シーズン始まってお店が新しくできたりするとワクワクします。球場のグルメガイドを見ながら、何を食べようかなぁとまずは好きな選手のグルメ情報を確認します。

ハマスタや甲子園、先日は楽天スタジアムに行きました⚾

他球団の球場飯はそんな詳しくないし、ネットで調べたり、Xで聞いたりしてます。

私は他球団でも好きな選手割と多めなので、好きな選手の球場飯がササッと出てくるとうれしいなぁと思った次第です。はい。

## Difyを使うぞ！！
そもそも、Difyってなんぞ？
https://dify.ai/jp

LLMのデータ連携の救世主らしい。
>DifyはLLM(大規模言語モデル)アプリケーション開発プラットフォームです。オープンソースのプラットフォームであり、ノーコード開発が可能なため、非エンジニアでも直感的にAIアプリケーションを構築できます。

色々と出てくる

https://dx.tenda.co.jp/column/aboutdify/#:~:text=Dify%E3%81%AF%E3%80%81AI%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA,%E5%90%91%E4%B8%8A%E3%82%92%E5%AE%9F%E7%8F%BE%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82

分かりやすいかも！と思ってたらプロンプトが英語でギッシリ書かれてたのでそっ閉じしそうになった。

https://note.com/en2enzo/n/n6da32fcdaa73

RAGとかLLMとかもう横文字ばっかりで分からん！！
概念から教えてくれるnote発見。ありがたい。

https://note.com/kyutaro15/n/n3c3088c276a3

## 作っていくよ

始め方はいたってシンプル。
「最初から作成」を選択。
<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784193/3f25e1cd-321b-f600-7762-1270009f6908.png">

### 選手の画像から球場飯を教えてもらいたい

せっかくなので選手の画像から球場飯を教えてもらいたいなと思ったので、開始を画像を選択したかったのですが、入力フィールドはどうも選べないらしい。

>開始ノード内で定義できる入力変数は、次の4種類です：
>テキスト
>段落
>ドロップダウンオプション
>数字
>ファイル（近日対応予定）

https://docs.dify.ai/v/japanese/guides/workflow/node/start

### テキストで検索するものをつくる

検索はGoogleSearch
LLMはgpt3.5-turbo

プロンプトは画像のとおり。

GoogleのAPIキーは必要なのでここから取得してください。

https://serpapi.com/

作成した画面

<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784193/c6668cdc-d138-974c-0248-70a5ede9c6a6.png">

実行したら何も出ない。
青木選手の選手飯はちゃんどあるんですよ！
<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784193/d3b001fb-cd11-6ace-4878-f778a7c93da8.png">

https://jingu-stadium-gourmet.com/produce/outfielder/#23

他の選手でも出なくて各ブロックごとに実行で動作を確認。
APIも消費されてるのでGoogleSearchもLLMも問題ないみたい。

### 終了の設定

終了の設定でテキスト吐き出させるのを忘れていた。
設定したら無事に表示されました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784193/f0f5320c-a32e-35d5-629c-77be07f501e8.png)

山田哲人さんの球場飯にカレーあったかな？と思ったらなかった笑

他球団の推し選手でも調べたらカレーライスだった🍛

## 問題はプロンプト？

今のプロンプトは

以下の「野球選手名」に対して、「Google検索結果」を用いて「選手名の球場飯」を回答してください。

「野球選手名」:TEXT
「Google検索結果」:GoogleのTEXT
「選手名の球場飯」:GoogleのTEXT

「Google検索結果」:GoogleのTEXTはあってもなくてもあまり大差ない結果でした。

## 教えてください

検索したり自分でいじってても解決できないものは解決できない。

プロンプトの書き方や、お前コレつかったみろよ！などなど忌憚なご意見お願いします！

## 最終的に実現したいこと

選手名を入れたら球場の内野外野の位置と共に、選手飯がすべて出るようにしたい。
絶対便利。私が！

少し時間をおいて試してみますが、どんくさい私に愛の手を随時募集しております。

最後までお読みいただきありがとうございました！
日にちの始まりを取得する方法

「前日に」いいねされた記事を取得するという実装をするために、日にちの始まりと終わりを簡単に取得する方法を調べたので、備忘録として残しておきます！
## 日にちの始まりを取得する方法
```ruby
time = Time.current
=> Wed, 17 Jul 2024 13:58:08.985319000 JST +09:00
time.beginning_of_day
=> Wed, 17 Jul 2024 00:00:00.000000000 JST +09:00
```
他にも日にちを取得する便利なメソッドが多数用意されていました。
```ruby
# 日にちの終わりを取得する
>> time.end_of_day
=> Wed, 17 Jul 2024 23:59:59.999999999 JST +09:00

# 日にちの年の始まりを取得する
>> time.beginning_of_year
=> Mon, 01 Jan 2024 00:00:00.000000000 JST +09:00

# 日にちの週の始まりを取得する
>> time.beginning_of_month
=> Mon, 01 Jul 2024 00:00:00.000000000 JST +09:00
```

この他にも似たような日にちを操作するメソッドはたくさんありました。
`(beginning or end)_of_(year,month,week..のような時間軸を表す単語)`という組み合わせだということさえ、覚えておけばすぐに思い出せそうですね！
【Typescript 5.4】NoInferについて 【新機能】

## はじめに
2024年3月にTypeScript5.4がリリースされました。
その中で、NoInferという新しい機能が追加され、
これが便利だったので紹介します。

## NoInferとは?
>When calling generic functions, TypeScript is able to infer type arguments from whatever you pass in.
ref:https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/


ジェネリック関数で引数の型を元に、他の引数の型を推論できるものです。
既存の型のパラメータによって制限できるというものです。

|5.3以前|5.4|
|---|---|
|![f04395a8-3870-7405-6faa-f989690bebc1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/f37fc148-324c-5ce6-6935-24730959f03a.png)|![3fec28d3-90bf-3362-36a8-14dd68c0182a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/4102fd05-bb8b-637c-f1b5-5981c103c493.png)| 

### 実際のコード
```ts
declare function doBallGame<T extends string>(a: T[], b: NoInfer<T>): void
doBallGame(['baseball', 'soccer'], 'judo')

//下記のようなエラーが出力される
// 型 '"judo"' の引数を型 '"baseball" | "soccer"' のパラメーターに割り当てることはできません。

```

今回でいくと、`doBallGame`の第1引数の、`[baseball,soccer]から
第2引数が`baseball`か`soccer`のどちらかであることを推論してくれます。

これにより、`judo`を含む可能性がある型推論を防ぐことができます。

以下の手順でts5.4はインストールできるのでぜひ試してください

```
npm install -D typescript@5.4
```

## 参照
https://typescriptbook.jp/reference/type-reuse/utility-types/no-infer

https://www.totaltypescript.com/noinfer

https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/
Sunriseの概要 - Proof of Liquidityに特化したDAレイヤー -

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839047/ff06de79-74bb-f32c-277e-13f49406d9ea.png)

Sunriseは、DA手数料の抽象化（DA Fee Abstraction）とプルーフ・オブ・リクイディティ（POL: Proof of Liquidity）に特化したブロックチェーンのデータ可用性（DA）レイヤーです。開発者がセキュリティと流動性を強化したアプリケーションを構築できるよう、モジュラー型の設計をサポートしています。SunriseはBerachainの流動性証明（PoL）モデルをL2（レイヤー２）に拡張しつつ、Celestiaのシステムとの互換性も保っています。

クロスチェーンで収益を生み出す「Gluon」というシステムが、Sunrise L1ブロックチェーン上に独立したL2として展開されます。GluonとSunriseは直接やり取りを行い、データ保存スペース（blobspace）と引き換えに流動性を提供します。これにより、既存のDAプロバイダーよりも効率的なスケーリングソリューションを実現します。Sunrise上のPoLは、L2とSunrise双方のセキュリティと流動性を高め合い、Berachainと同様の相乗効果を生み出します。

Celestiaとの互換性により、L2の導入が容易になります。また、SunriseはIBCにも対応しているため、Celestiaを利用しているサービスプロバイダーやSDKは、Sunriseとも簡単に連携できます。

## Sunriseの主な機能：

1. Celestiaと互換性のある機能
    - Blob Tx
    - BlobStream
2. Sunrise独自の機能
    - プルーフ・オブ・リクイディティ（POL: Proof of Liquidity）
    - DA手数料の抽象化（DA Fee Abstraction）
    - ブロックチェーン外部ブロブデータの公開検証性（Off Chain Blob Data Availability）（※Sunrise DA v2にて導入）
    - Gluonによるソブリン・プルーフ・オブ・リクイディティ（Sovereign Proof of Liquidity by Gluon）

Sunriseは、PoLを活用してL1（レイヤー１）の安全性を高め、L2の流動性と独立性を強化します。他のDAネットワークと異なり、Sunriseは積極的にインセンティブを設けることで、ネットワークの処理能力を向上させています。これにより、開発者はスケーラブルなL2だけでなく、AIやゲームなどの最新技術もフルオンチェーンで実現できます。

## 収益（手数料構造）

収益は主に以下の3つから得られます：

1. トランザクション手数料（Transaction fees）
2. 流動性プールのスワップ手数料（Swap fees in the liquidity pool）
3. Skip Protocolを使用したMEV（※MEV＝「トランザクションの取引順序操作による利益」）の獲得（MEV captured with Skip Protocol）

### 開発者がSunriseを選ぶ理由：

- ユーザーは手数料なしでDAを利用できます。
- 既存の分散型取引所（DEX）と比べ、トークン発行者により多くのメリットを提供します。
- SunriseのDEXに流動性を提供することで、開発者は追加の機能にアクセスでき、他のDAレイヤーやDEXよりも魅力的な選択肢となります。

### 統合プロセスのロードマップ：

### Sunrise v1: DAWN

Sunrise v1（DAWN）では、blob、blobstream、tokenconverter、liquiditypool、liquidityincentive、swap、feeなどの基本モジュールを実装します。

- `*x/blob*` モジュール
- `x/blobstream` モジュール
- `*x/tokenconverter*` モジュール
- `x/liquiditypool` モジュール
- `*x/liquidityincentive*` モジュール
- `x/swap` モジュール
- `*x/fee*` モジュール

### Sunrise v2: セキュリティとインセンティブ

Sunrise v2では、セキュリティとインセンティブに焦点を当て、ブロックチェーン外部データの検証機能とGluonによるソブリン・プルーフ・オブ・リクイディティを導入します。

- Off Chain Blob Data Availability（ブロックチェーン外部ブロブデータの公開検証性）（Sunrise DA v2）
- Sovereign Proof of Liquidity by Gluon（Gluonによるソブリン・プルーフ・オブ・リクイディティ）


---

---

:::note info
【Sunriserとは】
SunriseはProof of Liquidity(POL)とFee Abstraction（手数料抽象化）を備えたデータ可用性レイヤーです。 私たちはDAの体験を再構築し、多様なエコシステムからのモジュラー型流動性を活用してロールアップを立ち上げています。
- [Sunrise -  Specialized DA Layer for Proof of Liquidity](https://sunriselayer.io/)
- [Sunrise / Glon Docs](https://docs.sunriselayer.io/)

【Social Links】
- [X(旧 Twitter)[英語])](https://twitter.com/SunriseLayer)
- [X(旧 Twitter)[日本語])](https://twitter.com/SunriseLayer)
- [Discord Community](https://discord.com/invite/sunrise)
- [Medium](https://sunriselayer.medium.com/)
- [Github](https://github.com/sunriselayer)
- [Linkedin](https://www.linkedin.com/company/sunriselayer)


【お問合せ】
Sunriseへのお問い合わせはこちらから👉 [Google Form](https://forms.gle/h8RVahxRtXUvYwnv6)

![1080x360.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839047/8971d83b-3331-4757-dc72-320d28618735.jpeg)

:::
SunriseがQiita Organizationを開設：Proof of LiquidityやData Availabilityの技術動向を発信

SunriseチームがQiitaにて公式テックブログを開設しました。

## はじめに

Sunriseは、Proof of Liquidity (PoL)とData Availability(DA)に特化したLayer 1ブロックチェーンです。
私たちの使命は、この革新的な技術を日本のデベロッパーコミュニティにも広く知っていただくことです。
Qiitaは、その理想的なプラットフォームの一つだと考えました。

## ブログの内容
- Proof of Liquidity (PoL)の詳細解説
- ブロックチェーンのデータ可用性レイヤーの最新トレンド
- SunriseLayerの開発アップデート
- モジュラーブロックチェーンの未来展望

ブロックチェーン技術の最前線で起こっていることを、分かりやすく、そして深く掘り下げてお伝えします。

## おわりに
みなさんのフォローとコメントをお待ちしています。また、TwitterやFacebook等で記事のシェアにご協力いただければ幸いです。

また、今月よりSunriseのPublicテストネットがオープンしました。ぜひご参加ください。
[Sunrise Public Testnet](https://testnet.app.sunriselayer.io/)


---

---

:::note info
【Sunriseとは】
SunriseはProof of Liquidity(POL)とFee Abstraction（手数料抽象化）を備えたデータ可用性レイヤーです。 私たちはDAの体験を再構築し、多様なエコシステムからのモジュラー型流動性を活用してロールアップを立ち上げています。
- [Sunrise -  Specialized DA Layer for Proof of Liquidity](https://sunriselayer.io/)
- [Sunrise / Glon Docs](https://docs.sunriselayer.io/)

【Social Links】
- [X(旧 Twitter)[英語])](https://twitter.com/SunriseLayer)
- [X(旧 Twitter)[日本語])](https://twitter.com/SunriseLayer)
- [Discord Community](https://discord.com/invite/sunrise)
- [Medium](https://sunriselayer.medium.com/)
- [Github](https://github.com/sunriselayer)
- [Linkedin](https://www.linkedin.com/company/sunriselayer)


【お問合せ】
Sunriseへのお問い合わせはこちらから👉 [Google Form](https://forms.gle/h8RVahxRtXUvYwnv6)

![1080x360.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839047/8971d83b-3331-4757-dc72-320d28618735.jpeg)
:::
Qiita Engineer Festa 2024 〜38記事完走〜

# はじめに

この記事でQiita Engineer Festa 2024の38記事目の投稿を迎えることができました！
やってみての感想や大変だったことについてまとめていきたいと思います！

# 続けられたきっかけ

会社でQiita Engineer Festaを盛り上げる担当として呼びかけなどをしていましたが、前半は正直言って私自身もあまり記事を書いていませんでした。しかし、3本目に書いた記事の「いいね」数が大きく伸び、「これは面白い！」と思い、最初はハーフマラソンを目指して記事投稿を始めました。

それ以降はなかなか「いいね」が伸びませんでしたが、発信すること自体が楽しくなり、「いいね」を伸ばすことよりも、発信することの楽しさや、自分が得意とする分野の深い内容を調べること、全く触れたことのない技術について学ぶことが楽しいと感じるようになりました。

後半は3連休に特に予定がなかったので、ここでフルマラソンを目指して頑張ろうと思い、一日中記事の作成に取り組みました。

# 学んだこと

### 生成AIの進化とその効果的な活用

最初に感じたことは、生成AIの進化です。多少拙い文章や書きたいことを箇条書きで整理することで、伝えたい内容の文章に変換してくれます。また、アイデアに詰まった時にはテーマの提案もしてくれました。効果的に活用することで、自分の知見を深め、その知識をわかりやすい形で発信できることの素晴らしさを実感しました。

### 「いいね」とのギャップ

次に感じたことは、自分がいいな！と思う記事と「いいね」で評価される記事には大きな乖離があるということです。個人的に推している記事よりも、他の記事が伸びることが多々ありました。この経験を通じて、自分が面白いと感じる知識を多くの方に共感していただける内容として発信できるようになりたいと思うようになりました。

# 大変だったこと

やはり、テーマを決めることと、発信したい内容を文章にすることが難しかったです。特に後半は詰め込みがちになり、1日に5記事投稿することもありました。

最近触っている技術についてはすぐに書くことができましたが、学生時代に触れていた機械学習などについては、調べ直して最新のトレンドも把握する必要がありました。


# おわりに

無事に最終日に完走することができてよかったです！次回以降はもっと計画的にマラソンに取り組みたいと思います。
Qiita運営の方々や記事を読んでくださった方々に本当に感謝しています。引き続き投稿を続けていきたいと思います！
まだgit stashで消耗してるの？Git Worktreeで作業効率アップ！

こんにちは、皆さん！今日は多くの開発者が日々直面している問題、そう、ブランチの切り替えについて話したいと思います。「あ、ちょっと待って！このコード、コミットしてないけど...」というシーンを想像してみてください。そんな時、みなさんはどうしていますか？多くの人が`git stash`を使っているのではないでしょうか。

でも、実は`git stash`よりもっと便利で、作業効率を劇的に向上させる方法があるんです。その秘密兵器とは...**Git Worktree**！

## Git Worktreeとは？

Git Worktreeは、同じリポジトリの複数のブランチを異なるディレクトリで同時に作業できるようにする機能です。つまり、ブランチごとに独立した作業ディレクトリを持つことができるのです。

## Git Stashとの比較

| Git Stash | Git Worktree |
|-----------|--------------|
| 一時的な変更の保存 | 複数のブランチを同時に扱える |
| 切り替え時に毎回操作が必要 | 切り替えが瞬時 |
| 変更の管理が複雑になりがち | 各ブランチの状態が明確 |

## Git Worktreeの使い方

1. 新しいworktreeの作成:
   ```
   git worktree add ../new-feature feature-branch
   ```

2. 作成したworktreeに移動:
   ```
   cd ../new-feature
   ```

3. 作業完了後、元のディレクトリに戻る:
   ```
   cd ../original-repo
   ```

4. 不要になったworktreeの削除:
   ```
   git worktree remove ../new-feature
   ```

## Git Worktreeのメリット

1. **コンテキストスイッチが速い**: ブランチ間の移動が瞬時にできます
2. **並行作業が容易**: 複数のブランチで同時に作業できます
3. **状態が明確**: 各ブランチの作業状態が別々のディレクトリで管理されるので、混乱が少なくなります
4. **stashの管理が不要**: 未コミットの変更を気にせずにブランチを切り替えられます

## 注意点

- ディスク容量をちょっとだけ多く使用する可能性があります
- 初めは少し慣れが必要かも

## まとめ

Git Worktreeを使えば、もう`git stash`で消耗することはありません。複数のタスクを並行して進める必要がある現代の開発環境において、Git Worktreeは強力な武器となるでしょう。ぜひ、あなたの開発フローに取り入れてみてください！

皆さんのGit生活が少しでも楽になることを願っています。Happy coding!
PostgreSQL: Python で Upsert

こちらの SQL を python で実装しました。
[PostgreSQL: Upsert](https://qiita.com/ekzemplaro/items/0da59b50cb4ac9db007a)

## プログラム

```py:postgre_upsert.py
#! /usr/bin/python
#
#	postgre_upsert.py
#
#				Jul/17/2024
#
# --------------------------------------------------------
import sys
import os
import psycopg2
from dotenv import load_dotenv
#
#
# --------------------------------------------------------
def sql_upsert_string_gen_proc ():
	insert_sql = '''
	INSERT INTO cities (id, name, population, date_mod)
	VALUES (%s, %s, %s, %s)
	ON CONFLICT (id) DO UPDATE SET
	(name, population, date_mod) = (EXCLUDED.name, EXCLUDED.population, EXCLUDED.date_mod);
'''
	return	insert_sql
# --------------------------------------------------------
sys.stderr.write ("*** 開始 ***\n")
#
dotenv_path = '.env'
load_dotenv(dotenv_path)
USER=os.environ.get("user")
PASSWORD=os.environ.get("password")
DATA_BASE=os.environ.get("data_base")
#
conn = psycopg2.connect("dbname=" + DATA_BASE + " user=" + USER + " password=" + PASSWORD)
#
cur = conn.cursor()
#
sql_str=sql_upsert_string_gen_proc()
print(sql_str)
cur.execute(sql_str,('t3501','山口',113549,'2024-7-17'))
cur.execute(sql_str,('t3502','下関',113762,'2024-7-17'))
cur.execute(sql_str,('t3503','宇部',111725,'2024-7-17'))
conn.commit ()
#
cur.close ()
conn.close ()
#
sys.stderr.write ("*** 終了 ***\n")
#
# --------------------------------------------------------
```

```text:.env
user='scott'
password='******'
data_base='city'
```
UUID と Base32

## UUID と Base32

### UUID
- 128ビットの一意な数値
- 文字列では `540d79a1-0d3f-4973-b340-1d4923033768` のような16進数 36文字で表現

### Base32
- 32を底とする（1つの文字で 0~31 を表す）
- 5ビットを1文字で表現できる
- 実際には、40ビット単位を8文字に変換する
- 使用するASCII文字により、Base32 と Base32hex がある

[Base32](https://datatracker.ietf.org/doc/html/rfc4648#section-6) で用いる文字一覧
```
                     Table 3: The Base 32 Alphabet

     Value Encoding  Value Encoding  Value Encoding  Value Encoding
         0 A             9 J            18 S            27 3
         1 B            10 K            19 T            28 4
         2 C            11 L            20 U            29 5
         3 D            12 M            21 V            30 6
         4 E            13 N            22 W            31 7
         5 F            14 O            23 X
         6 G            15 P            24 Y         (pad) =
         7 H            16 Q            25 Z
         8 I            17 R            26 2
```

[Base32hex](https://datatracker.ietf.org/doc/html/rfc4648#section-7) で用いる文字一覧
```
                 Table 4: The "Extended Hex" Base 32 Alphabet

         Value Encoding  Value Encoding  Value Encoding  Value Encoding
             0 0             9 9            18 I            27 R
             1 1            10 A            19 J            28 S
             2 2            11 B            20 K            29 T
             3 3            12 C            21 L            30 U
             4 4            13 D            22 M            31 V
             5 5            14 E            23 N
             6 6            15 F            24 O         (pad) =
             7 7            16 G            25 P
             8 8            17 H            26 Q
```


## UUID を Base32 で表現する
- 128 / 5 = 25.6 なので、26文字で表せる
- Base32自体は40ビット単位のため、160ビット分の文字列となり、6文字分のパディング(=)が付く

### python でエンコード／デコード

```python
import base64
import uuid

# ----------
# Base32
# ----------

# UUID を Base32 文字列にする
print(base64.b32encode(uuid.uuid4().bytes)[:26].decode())

# Base32 文字列を UUID にする
a = str(uuid.UUID(bytes=base64.b32decode('KQGXTIINH5EXHM2ADVESGAZXNA' + '======')))

# ----------
# Base32hex
# ----------

# UUID を Base32 文字列にする
print(base64.b32hexencode(uuid.uuid4().bytes)[:26].decode())

# Base32 文字列を UUID にする
a = str(uuid.UUID(bytes=base64.b32hexdecode('AG6NJ88D7T4N7CQ03L4I60PND0' + '======')))
```

### 一番小さい値と一番大きい値
- UUID4 で表現するならば、一番小さい値と一番大きい値は次のようにエンコードされる

| UUID | Base64 | Base64hex |
| ---- | ------ | --------- |
| 00000000-0000-4000-8000-000000000000 | AAAAAAAAABAABAAAAAAAAAAAAA | 00000000010010000000000000 |
| FFFFFFFF-FFFF-4FFF-BFFF-FFFFFFFFFFFF | 7777777775H77P777777777774 | VVVVVVVVVT7VVFVVVVVVVVVVVS |
React/JavaScript: 親要素の取得 - parentElement vs closest()

親要素を取得する際、parentElementとclosest()には以下のような違いがあります。

### 返り値の違い
- **parentElement**: 直接の親要素を返します。親要素がない場合はnullを返します。
- **closest()**: 指定したセレクターに一致する最も近い先祖要素を返します。該当する要素がない場合はnullを返します。

### 対象の範囲の違い
- **parentElement**: 直接の親要素のみを対象にします。
- **closest()**: 対象要素から上方向に遡って、指定したセレクターに一致する要素を探します。

### メンテナンス性の違い
- **parentElement**: コンポーネントの構造に依存しないため、メンテナンス性が高いです。
- **closest()**: 指定するセレクターに依存するため、コンポーネントの構造が変わるとメンテナンス性が低くなる可能性があります。

### パフォーマンスの違い
- **parentElement**: 直接の親要素を取得するため、パフォーマンスが高いです。
- **closest()**: 上方向に遡って要素を探索するため、パフォーマンスが若干低くなる可能性があります。

```html
<!-- HTML -->
<div class="parent">
  <div class="child">
    <div class="grand-child">Grand Child</div>
  </div>
</div>
```

```js
// JavaScript
// 1. parentElement
const grandChild = document.querySelector('.grand-child');
const parent = grandChild.parentElement;
console.log(parent); // Output: <div class="child">...</div>

// 2. closest()
const closestParent = grandChild.closest('.parent');
console.log(closestParent); // Output: <div class="parent">...</div>

```

説明
1. parentElement: .grand-child要素の直接の親要素である.child要素を取得します。
2. closest(): .grand-child要素から上方向に遡って、.parentクラスに一致する最も近い要素を取得します。

### まとめ
parentElementは直接の親要素を取得するのに適しており、closest()は柔軟な要素の取得に適しています。コンポーネントの構造が明確な場合はparentElementを使用するのが適切です。一方、コンポーネントの構造が複雑な場合はclosest()の使用が適切となります。
プリザンターでテーブルにマスタ項目を追加して選択できるようにする

# はじめに
プリザンターでとある画面の項目を、〇〇マスタから引っ張ってくる、という事をしたい。

SQL ServerのSQL文に例えるとこんな感じ。

```sql
SELECT
 A.*
,B.ItemX -- この部分を追加したい
FROM       Table_A A
CROSS JOIN Table_B B
```

## 機能説明
プリザンター公式ドキュメントにある **選択肢一覧のマスタデータとして使用する** を参考に作成します。

https://pleasanter.org/manual/wiki-master

# マスタの作成
SQL ServerのSQL文に例えた **Table_B** となるマスタを作成するため今回は既に用意されている **都道府県マスタ** を活用します。

### 作成方法
 **新規作成** から **分類マスタ** → **都道府県マスタ** を選択し名称を付けて作成します。
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/b94a0e40-27af-7eaa-4a00-1e6cf05e1fa4.png)
※ 今回は **都道府県マスタ** で作成しました。

# マスタのサイトIDを控える

 **都道府県マスタ** を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/2814574f-e70c-16db-2d3f-1fcd034527c4.png)

管理から **Wikiの管理** を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/3fe76223-0db5-e644-3c7f-2d964700b1d8.png)

 **サイトID** の項目があるので、こちらの数字を控えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/cec4d6f4-5283-503b-3cd7-f05fe773ce67.png)
※ この例では **10058** ですが、作成タイミングによって変わります。 

:::note warn
**注意**
私は別のIDをコピーして失敗しました。
:::

# テーブルを作成する
SQL ServerのSQL文に例えた **Table_A** となるテーブルを作成します。
今回は進捗管理テーブルを作成し、最終的に都道府県マスタをくっつけます。

 **新規作成** → **プロジェクト** → **進捗管理** → **作成** の順で進みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/c151cefb-c631-3269-5437-10f553837d20.png)
※ テーブル名は **進捗管理** としています。

# 進捗管理に都道府県マスタをくっつける
SQL ServerのCROSS JOIN部分までやってきました。

**進捗管理** を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/c81d785b-0cfc-e43b-c63c-ed8c84ca1c01.png)

**管理** → **テーブルの管理** を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/990dd02b-397c-3f1f-56e0-5301b9d183dd.png)

**エディタ** → **[進捗管理]分類D** → **有効化** を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/a331160a-7a89-9767-42dd-563bf3a3329b.png)

左側の **現在の設定** の最後の行に **[進捗管理]分類D** があるので、選択された状態で **詳細設定** を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/40eb0ec3-41f7-fac2-f756-409db5a0da1c.png)

**分類D** の項目から、選択肢一覧に **[[10058]]** を入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/60dc1507-87fe-bec2-a055-18fda9f081fc.png)

:::note info
インフォメーション
この **10058** という数字は先程控えた **都道府県マスタのサイトID** の事です。
:::

```選択肢一覧.txt
[[10058]]
```

入力すると、最後に更新ボタンを押して更新します。

# 確認
進捗管理に戻り、新規作成を行うと **分類D** の項目に都道府県が一覧表示されている事が確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/3cb99444-8411-b188-7fbc-204747f033e0.png)
Javaにおけるガベージコレクションについて

## はじめに

  Java Silverの学習を進めている際、ガベージコレクション（GC）という言葉が出てきました。  

  基本情報技術者試験の勉強の際、なんかメモリを掃除してくれる機能、というような認識程度で詳しくは知らなかったので、Javaにおけるガーベジコレクションについてまとめてみようと思います。
  
  ※誤りありましたら、ご指摘いただけますと幸いです。

## 想定読者
  初学者の方  
  普段Javaを使用している方

## ガベージコレクション（GC）とは  
  日本語にすると「ゴミ回収」となるように、自動的に不要なメモリ領域を解放するプロセスのことを指します。

  Javaプロセスを開始する際、メモリの割り当てが行われるわけですが、主に使われる領域のことを**ヒープ領域**と呼びます。

  ちなみに、JavaはGCを自動で行ってくれますが、CやC++といった言語では、プログラムが使用するメモリ領域の割り当てやメモリ領域の解放を、明示的に指示する必要があります。

  そのため、普段実装していてこの辺りはそこまで意識することはないかと思います。


## ヒープ領域とは
  ヒープ領域は、下記のような構造になっています。

#### 1. Young Generation (New領域)
  短期間しか生存しないオブジェクトを格納する領域です。さらに以下の3つの領域に分けられます。

  **Eden領域**: 新しく生成されたオブジェクトが最初に割り当てられる領域。

  **Survivor領域**: Young Generationでガーベジコレクションを生き延びたオブジェクトが移動する領域（上記で3つの領域があるとしたのは、Survivor Spaceは2つあり、コピーが行われるため）。

#### 2. Old Generation (Old領域)
  Young Generationでのガーベジコレクションを繰り返し生き延びた長寿命のオブジェクトが格納される領域。

#### 3. Permanent Generation (永久世代領域)
  メタデータ（クラス、メソッド、定数プール）など、Javaランタイムのためのデータを格納する領域。ただし、Java 8以降では、この領域はメタスペース（Metaspace）に置き換えられています。

#### ※Metaspaceとは
  Java 8以降のJava仮想マシン（JVM）に導入されたメモリ領域で、前述のPermanent Generation（永久世代領域）を置き換えるものです。

  従来のPermanent領域では、クラスやメソッドのメタ情報の他、staticな変数や定数等も領域内に格納していましたが、Metaspaceではクラス・メソッドの情報のみ保持し、その他の情報はJavaヒープ上（New領域、Old領域）の保持に変更されました。


## GCの対象例
  1つの例として、下記のようなコードがあったとします。

  ```java
  Example example1 = new Example();
  Example example2 = example1;

  example1 = null;
  example2 = null;
  ```

  1行目では、Exampleオブジェクトを生成し、2行目でexample2にexample1の参照をコピーしています。

  3行目ではexample1にnullを代入して参照を解除、そして4行目でexample2にnullを代入して参照を解除しています。

  この場合、3行目の時点ではexample2の参照があるため、まだExampleオブジェクトはまだGCの対象ではなく、4行目でexample2の参照が解除された時点でGCの対象となります。

  イメージとしては下記のような形です。

  ![garbage.png](http://hr-dash.tech/files/img/2024-07/20240717122803525.png)

## GCの種類
  大きく分けて2種類あります。

#### Scavenge GC (Minor GC)
  New領域のGCを指します。上述の通り、New領域はEden領域とSurvivor領域から構成されています。

  主にEden領域が満杯になったときに実行されます。

  生き残ったオブジェクトは、Eden領域からSurvivor領域へ移動され、Eden領域は空になります。一定回数のScavenge GCを経て、まだ生存しているオブジェクトはOld領域に移動されます。

  ちなみに、先述の通り、Survivor領域は2つ存在します。今回は便宜上Survivor1とSurvivor2と名付けます。
  
  Survivor領域に存在するデータで、参照が確認されている場合は、どちらか空いているSurvivor領域へデータがコピーされ、Survivor1とSurvivor2を行き来することになります。
  もちろん、Survivor領域に存在しているデータの中で、参照がなくなったものは削除されていきます。


#### Full GC

  New領域およびOld領域を一斉に処理するGCを指します。
  こちらは主にOld領域が満杯になったときに実行されます。

  Scavenge GCにおいて、Survivor領域間の移動回数はカウントされており、一定回数を超えたデータはOld領域へ移行されます。しかし、Scavenge GCではNew領域のみが整理されるのみで、Old領域はSurvivor領域から移行してきたデータが山積みになっていきます。

  そこで行われるのがFull GCになります。


## GCの頻発を避けるために
  ちなみに、Scavenge GCもFull GCも、実行されるとアプリケーションは停止されてしまいます。

  なので、GCが頻発すると性能トラブルにも繋がりかねません。

  そのため、メモリ効率を意識した実装が大切になります。

  例えば、未使用オブジェクトの参照は明示的に開放したり、文字列連結が多い場合はString型よりもStringBuilder型を採用した方がメモリ効率がよくなります。

  その他にも、final修飾子を使用することで、再代入やオーバーライドがされないことが保証され、メソッド呼び出し時のオーバーヘッド（付加処理的な）が削減されたりします。


## まとめ
  研修期間はそこまで膨大なデータを扱ってきていなかったので、GCを考えたりすることは一切なかったのですが、実際に調べてみて裏側を知ることで、メモリ効率の良い実装を心掛けるいい機会になったと思います。

  また、調べていく中で、スレッドの観点で見たGC、GCアルゴリズム等々、今回まとめきれなかった部分もたくさんありました。この辺りも、余裕があれば勉強していきたいと思います。
あなたの技術ライフを加速させるIoTの魅力と実践ガイド

# はじめに
IoT（Internet of Things）について紹介します！
**「モノのインターネット」** とも呼ばれるIoTは、日常生活に多大な影響を与えつつあります。
家電製品から産業機械まで、様々なデバイスがインターネットを介してつながり、新たな価値を生み出しています。このブログでは、IoTの基本からその魅力を伝えていきたいと思います！

# 対象読者
・IoTに興味がある全ての方
・技術ブログを読んで勉強したい方
・IoTプロジェクトに取り組みたいエンジニア

# 目次
1. IoTとは
2. IoTの魅力
3. IoTデバイスの連携方法
4. IoTの実践ガイド
5. まとめ

# 1. IoTとは
まずは基本から押さえましょう。IoTとは「Internet of Things」の略で、モノのインターネットを意味します。これは、物理的なデバイスやオブジェクトがインターネット経由で通信し、データを交換することを指します。

## IoTの基本について
IoTデバイスはセンサー、アクチュエーター、通信モジュールから構成されます。センサーはリアルタイムでデータを収集し、通信モジュールを介してデータをクラウドに送信します。アクチュエーターは受信したデータに基づいて物理的な動作を行う役割があります。

:::note info
例えば、スマートホームの温度調節器は、温度センサーが現在の室温を測定し、データをクラウドに送信。そのデータに基づいてエアコンが自動的に温度を調節します。
:::

# 2. IoTの魅力
では、具体的にIoTの何がそんなに魅力的なのでしょうか？ここでは、IoTが持つユニークな魅力について見ていきましょう！

## IoTが生活を豊かにする理由
IoTは日常生活を効率化し、より快適にする力を持っています。例えば、スマートホームシステムは、家の中のあらゆるデバイスを一元管理でき、外出先からでもコントロール可能です。また、医療の分野ではウェアラブルデバイスが常時健康データをモニタリングし、異常を検知した際には即座に通知します。

IoTを活用することで、新たなビジネスモデルやサービスが誕生しています。例えば、自動運転車やスマートシティの実現に向けた動きが加速中です！

# 3. IoTデバイスの連携方法
IoTの真骨頂は、複数のデバイスが連携して初めて機能する点にあります。この章では、IoTデバイス同士の連携方法について詳しく見ていきましょう。

## IoTデバイスのネットワーキング
IoTデバイスはさまざまなプロトコルを使用して通信しています。Wi-Fi、Bluetooth、Zigbee、LoRaWANなどがその代表例です。デバイスがどのプロトコルを使うべきかは、使用ケースや環境に依存します。例えば、高速で大量のデータを送受信する必要がある場合はWi-Fi、低電力かつ長距離通信が必要な場合はLoRaWANが適しています。

:::note info
デバイス間の通信には「メッシュネットワーク」も多く用いられます。これは、各デバイスが中継点として機能し、ネットワーク全体の通信範囲や信頼性を向上させます。
:::

# 4. IoTの実践ガイド
ここでは、実際にIoTプロジェクトを始める際のステップバイステップガイドを紹介します。どこから始めればいいのか？何が必要なのか？そんな疑問に答えます。

## IoTプロジェクトのステップ
1. **アイデアを具体化する**:
   最初のステップは、あなたのプロジェクトの目的と目標を明確にすることです。どのような問題を解決したいのか？どのような価値を提供したいのか？
2. **必要なデバイスを選定する**:
   次に、プロジェクトに必要なセンサー、アクチュエーター、通信モジュールなどのハードウェアコンポーネントを選定します。
3. **通信プロトコルとネットワーク設定**:
   選定したデバイスがどのプロトコルで通信するかを決め、それに応じたネットワーク設定を行います。
4. **データ処理とクラウドインテグレーション**:
   センサーデータを収集し、クラウドサービスに送信します。ここで重要なのは、リアルタイムにデータを解析し、アクションにつなげることです。
5. **アプリケーション開発**:
   最後に、デバイスをコントロールするためのアプリケーションを開発します。これはスマートフォンアプリでもウェブアプリでも構いません。

初めてのプロジェクトでは、シンプルなものから始めるのが成功への近道です。例えば、温度センサーを使ったスマートサーモスタットの作成などが良いでしょう。

# まとめ
IoTは非常に魅力的な技術分野であり、多くの可能性を秘めています。
本ブログでは、IoTの基本からその魅力、具体的なデバイスの連携方法、そして実践的なプロジェクトの始め方までを紹介しました。IoTに関心を持つ方が増えていただければ嬉しいです！
Dartで、enumの負担と他型のインスタンスを使用する列挙型。

# 本題
これはコンパイル時に計算されるので、負担が「.index」の場合と同じ

```dart:const.dart
class ENUMA_i{
  const ENUMA_i(dynamic i):v=
    i==c0?0:
    i==c1?1:
    i==c2?2:
    -1;
  /*
  const ENUMA_i(dynamic i):v=//順序を入れ替えたもの。enumよりは若干大変だが、この様に簡単に入れ替えれる。
    i==c1?0:
    i==c0?1:
    i==c2?2:
    -1;
   */
  final v;
  static const c0=0,c1=1,c2=2;
      //static const c0="0",c1="あ",c2=[true];//これでも可能だし、パフォーマンスに影響しない
}
```



## 負担の比較

```dart:const.dart
void main() {
  DateTime startTime = DateTime.now();
  for(var i=0;i<100000;++i){enumn.apple.index;}
  print(DateTime.now().difference(startTime));
}
enum enumn{
  apple,lemon;
}
```
0:00:00.000328
0:00:00.000332
0:00:00.000335
0:00:00.000341

```diff_dart
- enumn.apple.index;
- enum enumn{
-   apple,lemon;
- }
+ fluits.apple;
+ class fluits extends ENUM{
+   static const apple=0;//fluits.apple
+   static const lemon=1;
+ }
```
0:00:00.000258
0:00:00.000266
0:00:00.000261
0:00:00.000262
```diff_dart
- enumn.apple.index;
+ fluits.apple;
+ class fluits extends ENUM{
+   static const apple=0;//fluits.apple
+   static const lemon=1;
+ }
```
0:00:00.000267
0:00:00.000267
0:00:00.000273
0:00:00.000274
```diff_dart
- enumn.apple.index;
+ i;
+ const i=0;
```
この結果より、classのstatic constフィールドの呼び出しとconst変数の呼び出しの負担が等しいことが分かった
0:00:00.000272
0:00:00.000265
0:00:00.000266
0:00:00.000262
```diff_dart
- enumn.apple.index;
- enum enumn{
-   apple,lemon;
- }
+ ENUMA_i(1);
```
0:00:00.000338
0:00:00.000342
0:00:00.000325
0:00:00.000342
##
ところで、列挙されたものでconst値のintが返ってくるものを実装する方法ってありますか？私はずっとこの書き方をしていますが、少し不便だと感じています。>>
```dart:const.dart

class fluits{
   static const apple=0;//fluits.apple
   static const lemon=1;
}
```
Next.jsアプリケーションにGoogle Tag Managerを導入する最新ベストプラクティス 2024年版

Next.jsアプリケーションにGoogle Tag Manager（GTM）を導入する最新のベストプラクティスについて、2024年版の情報をお伝えします。Next.jsの最新バージョンである14.2.3（2024年4月現在）に対応した方法を解説します。

## 1. @next/third-partiesパッケージの使用

Next.jsでは、`@next/third-parties`パッケージを使用してGTMを簡単に導入できるようになりました。まず、以下のコマンドでパッケージをインストールします：

```bash
npm install @next/third-parties@latest next@latest
```

## 2. GoogleTagManagerコンポーネントの実装

アプリケーションのルートレイアウト（app/layout.tsx）にGoogleTagManagerコンポーネントを追加します：

```typescript
import { GoogleTagManager } from '@next/third-parties/google'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="ja">
      <GoogleTagManager gtmId="GTM-XXXXXXX" />
      <body>{children}</body>
    </html>
  )
}
```

GTM-XXXXXXXの部分は、実際のGTMコンテナIDに置き換えてください。

## 3. イベントの送信

クライアントコンポーネントでイベントを送信する場合は、`sendGTMEvent`関数を使用します：

```typescript
'use client'

import { sendGTMEvent } from '@next/third-parties/google'

export function EventButton() {
  return (
    <button
      onClick={() => sendGTMEvent({ event: 'buttonClicked', value: 'xyz' })}
    >
      イベント送信
    </button>
  )
}
```

## 4. ページビューの追跡

Next.jsのApp Routerを使用している場合、クライアントサイドのナビゲーション時に自動的にページビューが送信されます。これを確実に機能させるには、GTMの管理画面で「拡張計測機能」を有効にし、「ブラウザの履歴イベントに基づくページの変更」にチェックを入れてください。

## 5. サーバーサイドレンダリング（SSR）への対応

SSRを使用している場合、GTMのスクリプトがクライアントサイドで正しく動作するように、`next/script`を使用してGTMスクリプトを読み込むことができます：

```typescript
import Script from 'next/script'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="ja">
      <Script
        id="gtm-script"
        strategy="afterInteractive"
        dangerouslySetInnerHTML={{
          __html: `
            (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
            new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
            j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
            'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
            })(window,document,'script','dataLayer','GTM-XXXXXXX');
          `,
        }}
      />
      <body>{children}</body>
    </html>
  )
}
```

## 6. パフォーマンスの最適化

GTMの導入によるパフォーマンスへの影響を最小限に抑えるために、以下の点に注意してください：

- 必要最小限のタグのみを使用する
- カスタムJavaScriptの使用を控える
- 可能な限り、サーバーサイドでデータを収集し、GTMに送信する

## 7. プライバシーへの配慮

GDPRやCCPAなどのプライバシー法に準拠するために、ユーザーの同意を得てからGTMを読み込むようにしましょう。Next.jsでは、ユーザーの同意状態に基づいてGTMの読み込みを制御できます。

https://note.com/yonaka15/n/n25097fce19e9

以上が、2024年におけるNext.jsアプリケーションへのGoogle Tag Manager導入の最新ベストプラクティスです。これらの方法を適用することで、効果的かつパフォーマンスを考慮したGTMの導入が可能になります。
PostgreSQL: Upsert

こちらを参考にしました。
[PostgreSQL 16 INSERT](https://www.postgresql.org/docs/current/sql-insert.html)

## 元のテーブルの状態

```text
city=# select * from cities;
  id   |  name  | population |  date_mod  
-------+--------+------------+------------
 t3461 | 広島   |      25176 | 2003-09-24
 t3462 | 福山   |      47935 | 2003-05-15
 t3463 | 東広島 |      28654 | 2003-02-08
(3 rows)
```

## 最初の Upsert
データが挿入されます。

```sql:upsert01.sql
INSERT INTO cities (id,name,population,date_mod)
    VALUES ('t3501','山口',23541,'2022-5-10'),
	('t3502','下関',83762,'2022-5-10'),
	('t3503','宇部',31725,'2022-5-10')
    ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name,
	 population = EXCLUDED.population,
	 date_mod = EXCLUDED.date_mod;
```

実行結果

```text
city=# select * from cities order by id;
  id   |  name  | population |  date_mod  
-------+--------+------------+------------
 t3461 | 広島   |      25176 | 2003-09-24
 t3462 | 福山   |      47935 | 2003-05-15
 t3463 | 東広島 |      28654 | 2003-02-08
 t3501 | 山口   |      23541 | 2022-05-10
 t3502 | 下関   |      83762 | 2022-05-10
 t3503 | 宇部   |      31725 | 2022-05-10
(6 rows)
```

## 次の Upsert
データが更新されます。

```sql:upsert02.sql
INSERT INTO cities (id,name,population,date_mod)
    VALUES ('t3501','山口',993541,'2024-7-12'),
	('t3502','下関',993762,'2024-7-12'),
	('t3503','宇部',981725,'2024-7-12')
    ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name,
	 population = EXCLUDED.population,
	 date_mod = EXCLUDED.date_mod;
```

実行結果

```text
city=# select * from cities;
  id   |  name  | population |  date_mod  
-------+--------+------------+------------
 t3461 | 広島   |      25176 | 2003-09-24
 t3462 | 福山   |      47935 | 2003-05-15
 t3463 | 東広島 |      28654 | 2003-02-08
 t3501 | 山口   |     993541 | 2024-07-12
 t3502 | 下関   |     993762 | 2024-07-12
 t3503 | 宇部   |     981725 | 2024-07-12
(6 rows)
```