OmniAICreator/Qiita-1.07M huggingface dataset:
(初心者向け)SQLでjoinをする際の色んな書き方のtips

# はじめに
上級者のSQLを見ると、joinをする際に色んな記法や省略記法が使われている事があると思います。
調べたことをまとめます

## jojnをする際に、これから結合するテーブルのテーブル名は省略できる

```sql
SELECT
  *
FROM
  posts JOIN comments ON (comments.post_id = posts.id)
```

```sql
SELECT
  *
FROM
  posts JOIN comments ON (post_id = posts.id)
```

どちらでも出力結果は同じです。

```
+----+---------+----+---------+-------------+
| id | message | id | post_id | comment     |
+----+---------+----+---------+-------------+
|  1 | post-1  |  1 |       1 | comment-1-1 |
|  1 | post-1  |  2 |       1 | comment-1-2 |
|  3 | post-3  |  3 |       3 | comment-3-1 |
+----+---------+----+---------+-------------+
```

## 同じカラム名で結合する際はonを使わず、usingキーワードで結合できる

両者にidというカラムがあれば、idで結合します
```sql
SELECT
  *
FROM
  posts JOIN comments using (id)
```
【Next.js】カレー作りで理解するSSRとCSR

# はじめに
SSR（Server Side Rendering）とCSR（Client Side Rendering）は、Webアプリケーションでよく耳にする言葉ですが、最初は「何が違うの？」と思いがちです。そこで今回は、それぞれの特徴をカレー作りで例えてわかりやすく説明しつつ、どんなサービスに向いているのかもご紹介します。

# プログラミングは料理と同じ

私は駆け出しのエンジニアですが、学びの過程で「プログラミングは料理と似ている」と感じることがよくあります。料理をしたことがない人が、いきなり「フランス料理を作って」と言われても難しいように、プログラミングでも最初から複雑なシステムは作れません。  
食材の切り方や火加減を学ぶように、プログラミングも基本の構文やロジックを一つひとつ身につけることが大切です。私自身も日々少しずつ積み重ねています。  
焦らず、玉ねぎを飴色になるまで炒めるように基礎を丁寧に学んでいけば、やがて自分だけの“味”を出せるようになります。ぜひ一緒に学び、成長していきましょう！

# SSRとCSRとは
- **SSR（Server Side Rendering）**  
  サーバー側でHTMLを生成してクライアント（ブラウザ）に送る仕組みを指します。サーバー側でページのレイアウトやデータを組み込んで完了した形のHTMLを返すので、ユーザーはページを開いてすぐに完成した画面を見ることができます。一方、サーバーへの負荷や通信量が多くなる可能性があります。

- **CSR（Client Side Rendering）**  
  クライアント（ブラウザ）上でJavaScriptが動き、HTMLを生成する仕組みです。最初は最小限のHTMLが返され、ページの表示や動的な要素の生成はブラウザ上のJavaScriptが担います。ユーザー側の端末で処理を行うため、インタラクティブなページを実現しやすい反面、初回表示が遅れる可能性があります。

# カレー作りで例えると・・・
- **SSRは「完成したカレーを配達するイメージ」**  
  カレーを作ってくれる人（サーバー）が、すべての工程を完了させてからユーザー（お客さん）に届けるイメージです。できたてアツアツで、パッと食べ始められますが、一度に大量の注文がくると、作る側（サーバー）の負担が大きくなり、配達（通信時間）も必要です。

- **CSRは「スパイスセットや下ごしらえの材料を送って、ユーザーが仕上げをするイメージ」**  
  カレーのベースとなるスパイスや材料（JavaScriptのコード）をユーザー（ブラウザ）側に送って、最終的な仕上げを自分たちで行います。一度準備（初回読込）は少し時間がかかるかもしれませんが、そのあとは好みに合わせてスパイスを調整したり、トッピングを加えたりと拡張がしやすく、ユーザーに合わせたカレーを自由に仕上げることができます。

# 向いているサービス
- **SSR（Server Side Rendering）が向いているサービス**
  - **SEOを重視するサイト**  
    （検索エンジンはJavaScriptで動的に描画するサイトを、必ずしも完全に読み取れない場合があるため、SSRで生成された静的HTMLが有利となる）
  - **初回表示速度を重視するサービス**  
    （ユーザーが素早くコンテンツを見られるようにしたい場合）
  - **コンテンツ重視のサイト（ブログ・ニュースサイトなど）**  
    （シェアやブックマークが多く、ページの読み込みが頻繁に行われる場合）

- **CSR（Client Side Rendering）が向いているサービス**
  - **SPA（Single Page Application）**  
    （画面遷移を少なくし、ダイナミックにUIを変化させたい場合）
  - **ユーザーのアクションによってリアルタイムにデータを表示・更新するようなインタラクティブなアプリ**  
    （チャットアプリやリアルタイムダッシュボードなど）
  - **大規模なフロントエンドフレームワークを活用して、画面間の動きにこだわりたいプロジェクト**  
    （React、Vueなど）

# まとめ
SSRとCSRはいずれもWebアプリケーションを動かすための「レンダリング手法」ですが、それぞれメリット・デメリットや向いているサービスが異なります。

- **SSR**  
  - SEOや初回表示の速度を重視したいサイトに向いている  
  - 完成したカレーをすぐに配達するイメージ

- **CSR**  
  - ユーザー操作によるダイナミックな変化を求めるSPAに向いている  
  - スパイスをユーザー側に渡し、自由に仕上げるイメージ

カレー作りを思い浮かべながら、SSRとCSRの特徴を考えてみると理解しやすいかもしれません。みなさんもぜひ、自分なりの“スパイス”を加えて、より美味しいWebアプリケーションを作っていきましょう！
Rails 5.1 Default Settings Changes

# Rails 5.1 Default Settings Changes

## config.action_view.form_with_generates_remote_forms: true

```ruby
# 以前の書き方
<%= form_for @post, remote: true do |f| %>

# Rails 5.1での新しい書き方
<%= form_with(model: @post) %>  # デフォルトでdata-remote="true"が付与

# 生成されるHTML
<form action="/posts" method="post" data-remote="true">
  ...
</form>
```

## 影響と問題パターン

1. すべてのform_withがデフォルトで非同期送信になる
2. JavaScriptを無効にしているブラウザでフォームが正しく動作しない可能性
3. Turbolinksとの競合が発生する可能性

## config.assets.unknown_asset_fallback: false

```ruby
# 設定による違い
image_tag("missing_image.jpg")

# true の場合
# => /assets/missing_image.jpg を出力

# false の場合
# => Sprockets::Rails::Helper::AssetNotFoundError
```

## 影響と問題パターン

1. 存在しない画像への参照時にエラーが発生するようになる
2. 動的に生成される画像パスで問題が発生しやすい
3. 開発環境とプロダクション環境で挙動が異なる可能性がある
4. プレースホルダー画像の仕組みを使っている場合に修正が必要

## 対応策

```ruby
# フォームの非同期送信を個別に制御
<%= form_with(model: @post, local: true) %>  # 同期送信

# アセット参照のエラーハンドリング
def asset_exist?(path)
  if Rails.configuration.assets.compile
    Rails.application.precompiled_assets.include? path
  else
    Rails.application.assets_manifest.assets[path].present?
  end
end
```
Regexp

# 正規表現クラスを作り出す
>`正規表現のクラス`。正規表現のリテラルは`スラッシュで囲んだ形式`で記述します。
```
/^this is regexp/
```
>`Regexp.new(string)`を使って`正規表現オブジェクトを動的に生成`することもできます。

```rb
irb(main):001> str = "this is regexp"
=> "this is regexp"
irb(main):002> rp1 = Regexp.new("^this is regexp")
=> /^this is regexp/
irb(main):003> p rp1 =~ str
0
=> 0
irb(main):004> p Regexp.last_match[0]
"this is regexp"
=> "this is regexp"
```
>Ruby 3.0.0 から正規表現リテラルは freeze されるようになりました。

```rb
irb(main):006> p /abc/.frozen?
true
=> true
irb(main):007> p /a#{42}bc/.frozen?
true
=> true
irb(main):008> p Regexp.new('abc').frozen?
false
=> false
```

### new 
>new(string, option = nil) -> Regexp
文字列 string をコンパイルして`正規表現オブジェクトを生成`して返します。

>`第一引数が正規表現であれば第一引数を複製`して返します。`第二引数は警告の上無視`されます。
#### 引数
>[PARAM] string:
`正規表現を文字列`nとして与えます。
>[PARAM] option:
`Regexp::IGNORECASE`, `Regexp::MULTILINE`, `Regexp::EXTENDED`の`論理和`を指定します。 Integer 以外であれば真偽値の指定として見なされ、真(nil, false 以外)であれば` Regexp::IGNORECASE`の指定と同じになります。
#### 例外
>[EXCEPTION] RegexpError:
`正規表現のコンパイルに失敗`した場合発生します。
備忘録　JavaScriptで「undefined is not valid JSON」エラーの解決方法

## 「undefined is not valid JSON」エラーの原因

・JavaScriptでは、undefinedは特殊な値であり、変数が値を持たないことを示す。
・JSONは、データ交換形式として広く使用されており、その構文はJavaScriptのリテラル構文に基づいているが、undefinedを含むことは許されていない。

したがって、JavaScriptオブジェクトにundefinedが含まれている場合、そのオブジェクトをJSONに変換しようとすると、「undefined is not valid JSON」というエラーが発生する。これは、JSON.stringify()メソッドがundefinedを無視または除外し、結果のJSON文字列にはundefinedが含まれない為である。


## このエラーを解決するため
・undefinedを含む可能性のあるオブジェクトをJSONに変換する前に、適切に処理する必要がある。
undefinedを別の値に置き換えるか、
undefinedを含むプロパティを完全に削除するかなど…。
vimをインストールしたい

◾︎自己紹介
エンジニア歴半年くらいのクラウドエンジニア。
インフラただでさえ分からないのに、このお仕事はプログラミングが多いことを知って息が止まった。
盛り上がってきたぞ〜〜〜！

## vimを使いたくなったきっかけ
お休みの日まで趣味でコーディングしているという先輩、vimが大好きらしい。
vimを徹底的にカスタマイズしているのだとか。
vimについてはいくらでも語れるらしい。
そこまで愛されているvim、気になる。。。私も触ってみたい。

部長👨‍💻「［vim インストール］で検索すればやり方分かるよ」

## [ vim インストール ] する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3677621/66d6879b-d0b3-3bfd-6276-f126236db85f.png)

おお〜簡単そう！早速実行してみる
```
brew install vim
```

↓ 結果

```
% brew install vim
zsh: command not found: brew
```

コマンド・ノット・ファウンド…？騙された。

`brew`は会社で見たことある。macでパッケージ管理するやつって言ってた。
`brew`をインストールすればいいのか🤔？

### [ brew インストール ] する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3677621/fff6e4ee-04de-4d5f-dd9f-96afd6d7c262.png)

> Homebrewページに移動し、記載されているインストールコマンド（シェルスクリプト）をターミナル画面にペーストし実行（Enter）します。

https://brew.sh/ja/

言われた通りコピペして実行してみる。

おおおお…！！
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3677621/0dcedf98-83c6-749e-1db7-39f604978eb6.png)

paizaで勉強してなかったら壊れたかと思ってたし、
待ち時間なの分からなくて途中で適当なボタンをポチポチしていただろう。
ありがとうpaiza。

ともあれこれで**Homebrewのインストールが完了**した

## 改めてvimをインストールする
もう一回！
```
brew install vim
```

↓ 結果

```
% brew install vim
zsh: command not found: brew
```

既視感。
なんでだよおおおおお


## brewインストール失敗？
<b>困った時のChatGPT先生</b>
> Homebrewがインストールされても、brew コマンドが認識されない場合、シェルのパス設定が不足している可能性があります。Homebrewのインストールスクリプトが、通常はこの設定を行ってくれますが、手動で設定する場合もあります。

何言ってるのかあんまり分からないけど、設定が足りてないらしい。
とりあえず言われた通りに実行してみる

まずは設定確認（出力が `/bin/zsh` になっていれば `zsh` シェルを使っている）
```
echo $SHELL
```

続いて `~/.zshrc` ファイルにHomebrewのパスを追加
```
echo 'export PATH="/opt/homebrew/bin:$PATH"' >> ~/.zshrc
```

ファイルの再読み込み
```
source ~/.zshrc
```

最後に動作確認（Homebrewのバージョンが表示されれば正常なインストールが完了している）
```
brew --version
```
（`brew -v` でもいけるらしい）

で、できたっぽい…！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3677621/8cee06b2-40e1-bb9d-0173-2279350df006.png)

## Re: Re: vim インストール

いっけぇぇぇぇ〜！！
```
brew install vim
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3677621/2d882ea2-fa32-fc34-56bc-04e626206cc1.png)

念のためバージョン確認して使えるか確認

```
vim --version
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3677621/65262bd8-3224-b963-6596-2a974b36f5f2.png)
なんかよく分からないけどいっぱい出てきてるからヨシ！

## vim 使ってみる
テスト用のテキストを作成してみる
```
touch test_text
```

いざ！
```
vim test_text
```

う〜ん、`vi` コマンドとの違いが全く分からない。
viをつよつよにしたのがvimかと思っていたけど、そもそもvimとviの違いも分からない。

もうちょっとちゃんと調べてみる必要がありそうだ。
また別の機会に調査してみます。


### ◆ 参考にした記事
- [【Qiita】HomebrewでVimをインストールする](https://qiita.com/carrot000/items/c6f857554dee1617dbaf)
- [【Qiita】Homebrewのインストール](https://qiita.com/zaburo/items/29fe23c1ceb6056109fd)
【Web】Next.jsを使用した動的ルーティング設定時に発生したエラーの解消方法まとめ

# はじめに
今年から新たに弊社関連会社の新システム作成でNext.jsを使用し、開発を進めています。
Web自体もかなり久々で、思い出しながら手探りで実装を進めているのですがその際非同期処理関連でエラーが出ていたので対応しました。

出ていたエラーは以下になります。
```
Error: Route /sample/[id] used params.id . params should be awaited before using its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis 
```
今回はこのエラーを解消した方法を備忘録的にまとめておこうと思います。

# 解消方法
このエラーですが、どうやらNext.jsのバージョン15より、動的なパラメータに関する処理が非同期になった為直接値を取得しようとするとエラーが発生するようですね。
その為パラメータを取得する際には**Promise**と**await**を付与してあげることで解消可能です。

```page.tsx
// 修正前
export default async function PostPage(params: {id: string}) {
  const { id } = params;
  console.log({ id });
}

// 修正後
export default async function PostPage(params: Promise<{id: string}>) {
  const { id } = await params;
  console.log({ id });
}
```
以上になります。

# さいごに
Webは何かと専門用語が多いなと感じますが、すごい技術的な進歩を感じますね。
やはりこういった右も左も分からない新しい領域で緊張しながら手を動かすとゾクゾクしますね、自分で言うのもなんですが変態かもしれません(笑)
身近な例で理解するRTMとRTCの世界

# RTMとは
RTM（Real-Time Messaging）のこと

- テキストメッセージ、データの送受信に特化
- 主にチャットやデータ更新などの用途
- サーバーを経由してメッセージを配信
- 比較的軽量なデータ通信

### 従来のシステムとどう違うのか
従来のWebの仕組み（HTTP通信）は「**手紙**」のようなもの
- 相手に何か伝えたい時に手紙を書いて送る
- 相手からの返事を受け取るまで待つ
- また何か言いたいことがあれば新しい手紙を書く

誰かと連絡をする際に、タイムラグが発生してスムーズに連絡を取ることができない。
一度、途切れてからどんな内容の話をしていたのかを思い出すのが大変

RTMは日常生活の中での「**電話**」のようなもの
- 一度電話を繋げれば、そのまま会話が続けられる
- 相手が話したことがすぐに聞こえる
- こちらも即座に返事ができる

リアルタイムでの会話ができるためタイムラグなく話をすることができる。

## RTMが利用されている例
- チャットアプリ
    - LINEやSlackのような即座にメッセージが届く機能
    - 相手が「入力中…」という状態がリアルタイムで見れる
- オンライゲーム
    - ゲーム内のチャットがすぐに届く

### RTMの利点
ユーザーが新しい情報を得るために画面更新が必要ないこと。新しい情報が届いたら自動的に画面に表示される。
そのため、よりスムーズで以前なコミュニケーションや情報更新が可能になっている

# RTCとは
RTC (Real-Time Communication)のこと

- 音声・映像の双方向通信に特化
- 通話やビデオ会議などの用途
- できるだけ直接的なP2P通信を行う（低遅延のため）
- 大容量のデータをリアルタイムにやり取り

### 従来の音声・映像通信システムの特徴
1. サーバー経由の中央集中型
    - すべての通信がサーバーを経由
    - 遅延が発生しやすい
    - サーバーの負荷が大きい
2. 専用ソフトウェアが必要
    - 特別なアプリケーションのインストールが必要
    - プラットフォームごとに異なる実装が必要


RTCの技術により
- より低遅延
- より高品質
- より低コストな通信を実現している

# ライブ配信などでの活用方法
YoutubeライブやTwitchなどの配信プラットフォームではRTCとRTMを組み合わせて効率的なシステムを実現している

**配信者側（1対多の通信）**

- RTC：配信者の映像・音声を配信
    - 大人数への配信の場合は、配信サーバーを経由して配信する形が一般的
    - なぜなら、P2P接続を大量の視聴者と確立するのは負荷が大きすぎるため

**視聴者とのやり取り**

- RTM：チャットやリアクション（いいね！など）
    - テキストメッセージの送受信
    - スタンプや絵文字の送信
    - 「○○さんが入室しました」などの通知
    - 視聴者数のリアルタイム更新


役割分担をすることで
1. 重い処理（映像・音声）と軽い処理（テキスト）を分離
2. 配信の安定性を確保
3. インタラクティブなコミュニケーションを実現
n で Node.js のバージョン管理を行う際のセットアップ時のメモ（自分の Mac の環境での話）

以下の n を使った Node.js のバージョン管理関連の話です。

●tj/n: Node version management
　https://github.com/tj/n

![2025-01-11_12-18-43.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/bfd790fe-6e3d-c20a-ae0c-7c7828609291.jpeg)

以下の M4 Mac mini をセットアップした時に久しぶりに使ったのですが、その時のメモです。

https://x.com/youtoy/status/1855591540095389975

## セットアップ
公式の記載で複数のセットアップ方法が書かれていますが、自分がセットアップした際は Homebrew を使いました。

インストールは下記のコマンドで行いました。

```zsh
brew install n
```

### 設定
インストールに関わる設定の話です。

自分の Mac の環境でセットアップしている中、以下の「/usr/local への書き込み権限関連の話」の対応を行いました。

![2025-01-11_12-23-04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/db9e033d-fc8d-e6dd-98a4-9cf20bf53b8e.jpeg)

それぞれについて、軽くメモしておきます。

#### 対応方法1
対応方法 1つ目は「change the ownership of the relevant directories to yourself (see below)」と書かれたものです。

以下は公式手順の転載ですが、「sudoコマンドで /usr/local/n を作成してユーザーへの権限の付与を行う」といったことや、「/usr/local/ 以下の bin・lib・include・share への権限設定（フォルダがない場合は作成から）」ということをやっている感じです。

```zsh
# make cache folder (if missing) and take ownership
sudo mkdir -p /usr/local/n
sudo chown -R $(whoami) /usr/local/n
# make sure the required folders exist (safe to execute even if they already exist)
sudo mkdir -p /usr/local/bin /usr/local/lib /usr/local/include /usr/local/share
# take ownership of Node.js install destination folders
sudo chown -R $(whoami) /usr/local/bin /usr/local/lib /usr/local/include /usr/local/share
```

#### 対応方法2
対応方法 2つ目は「tell n to use a custom location where you do have write permissions (see N_PREFIX)」という内容です。

「see N_PREFIX」と書かれている内容に従いページ内を見ていくと、以下の記載があります。

![2025-01-11_12-31-01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/50334b9e-aaff-9278-d67e-5fa847e1fd51.jpeg)

「$HOME/.n」（「~/.n」）という、ユーザーのホームディレクトリ直下に「.n」というフォルダが作られるようにし、その下を n で使うというものです。

例えば zsh を使っている場合の対応の例としては、以下の設定を `.zshrc` に追記します。

```zsh
export N_PREFIX=$HOME/.n
export PATH=$N_PREFIX/bin:$PATH
```

変更後、上記の変更を即時反映させる場合は以下を実行します。

```zsh
source ~/.zshrc
```

#### 対応方法3
対応方法 3つ目は「put sudo in front of the command to run it as super user」と書かれた、「sudoコマンドを使った実行」という対応方法です。

上記のいずれかの対応を行うことで、n のセットアップ完了です。

## 自分の設定
上記の方法について、自分は当初は 2つ目でやってみていたのですが、以下の記事に書いた事象が起こり、上記の 1つ目のやり方に変更しました。

●Claude for Desktop で MCP を使おうとした際のエラーに関する対処メモ（npxコマンドまわり） - Qiita
　https://qiita.com/youtoy/items/21ebf4df0bfe7d8201e4
【ChatGPT】問題に対して、複数の思考方法からアイディアや意見を得るPromptです。


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

　今回は、問題に対して、複数の思考方法からアイディアや意見を得るPromptです。

:::note info
本記事は、ChatGPT（Plus版）
で行なっております。
画像はありません。あしからず。
:::
　ChatGPT等の動作状況を知らせる
　　OpenAIのステータスページ。
　　　[OpenAIステータス](https://status.openai.com/)
***
　ではさっそく、【本題】です。

　今回は、
　　問題に対して、
　　　複数の思考方法から
　　　　アイディアや意見を
　　　　　得るPromptです。

　これまでも
　　いろんな思考方法で
　　　アイディアなんかを
　　　　得てきました。

　今回も
　　そんなPromptです。

　まぁ、言っても
　　なんかネタを拾えれば
　　　“儲かった！”的な
　　　　レベルなんですけどね😅
***
　下記Promptの＊＊＊に
　　問題を入力して
　　　送信してください。
```Text:複数の思考方法からアイディア出力Prompt
問題[＊＊＊]について、以下の思考法を活用して具体的に回答してください。

1. ロジカルシンキング:
2. ブレインストーミング:
3. 6つの帽子思考法:
4. 逆転思考:
5. デザイン思考:
6. システム思考:
7. SF思考:
8. メタ思考:

テーマに関連する要素やアイデアを提案してください。
```

　ここから、出力結果を
　　さらにまとめるには、こちら。
```Text:総合するPrompt
総合して[＊＊＊]を書き出してください。
```

　これで総合すると、
　　すんなりとまとまり、
　　　必要な項目が得られる、かも😸

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

　今回は、ここまで。
Amazon LinuxのEC2にCloudwatch Agentをインストールしてみた

## はじめに
こんにちは小林です。
仕事でCloudWatchAgentを触りました野江備忘録としてまとめようと思います。

## 前提
・対象のEC2（AmazonLinux）は構築済みとする
・EC2にssm-agentがインストールされていてマネージドノードに設定済みとする
・本記事ではマネジメントコンソールを使用した手順を記す
## システム構成

![EC2&CloudWatch構成図.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3722085/8c3c7b7d-7fd0-25ab-7716-834815303571.png)

## EC2インスタンスプロファイル
CloudWatchAgentを使用してEC2とCloudWatchの連携を行う場合は下記のIAMポリシーが必要になります。

### CloudWatchAgentAdminPolicy
CloudWatch Agentのインストールと設定を行うためのポリシーです。

### CloudWatchAgentServerPolicy
CloudWatch AgentがメトリクスやログをCloudWatchサービスに送信するためのポリシーです。


## CloudWatchAgentを設定
EC2 コンソールを開き、対象のインスタンスを選択します。

・[Command document] リストから [AWS-ConfigureAWSPackage] を選択します。

・「アクション」、「モニタリングとトラブルシューティング」、「CloudWatchAgentを選択」の順にクリックする。

・必要に応じた追加設定と取得したいメトリクスを選択したらEC2にCloudWatchAgentが設定されます。

・CloudWatchAgentの設定ファイルは下記ディレクトリに格納されます。
設定変更の必要に応じて、設定ファイルの編集を行いましょう。（設定ファイルの編集は別記事にまとめる予定です。）

$ /opt/aws/amazon-cloudwatch-agent/etc

### おわりに
以上がCloudWatchAgentのインストールの手順になります。
CloudWatchAgentを使用するには設定ファイルの記述も必要になるため、次回の記事にてまとめようと思います。
是非合わせてご覧ください。
Dockerデーモンに接続できないエラー

年明け久しぶりにdockerを起動しようとしたら
下記のエラーが表示され、Dockerが立ち上がりませんでした。

```
com.intellij.docker.agent.ApiTaskException: unix:///var/run/docker.sock で Docker デーモンに接続できません。Docker デーモンは実行中ですか？ (詳細: [2] No such file or directory)
```

これに関する記事がたくさん転がっていますが、一番安全な方法として
**再起動→いかなかったらDocker Desktopを再インストールする**方法をおすすめします。

自分はそれだけで立ち上げることができました。
GASのから送った値を使ってスプレットシートで折れ線グラフを作成する

## 概要

GASから送った値を使いスプレットシートで折れ線グラフを生成する方法を簡単にまとめる。

## 前提

下記の内容が完了していること。

https://qiita.com/miriwo/items/1c2e2ea04a3e13535d86

## 方法

1. GASのコードを下記の様に書き換える

    ```js
    function makeGraph() {
      // スプレッドシートIDを指定
      const spreadsheetId = 'スプレットシートのID';
    
      // スプレッドシートを開く
      let sheet = SpreadsheetApp.openById(spreadsheetId).getActiveSheet();
    
      const min = 0;
      const max = 31;
      const value = getRandomInt(min, max);
    
      // スプレッドシートに追加
      sheet.appendRow([new Date(), value]);
    
      // データ範囲を指定
      let lastRow = sheet.getLastRow();
      let dataRange = sheet.getRange('A1:B' + lastRow);
    
      // 既存のグラフを取得
      let charts = sheet.getCharts();
      if (charts.length > 0) {
        // 既存のグラフがある場合は更新
        let chart = charts[0].modify()
          .clearRanges()
          .addRange(dataRange)
          .build();
        sheet.updateChart(chart);
      } else {
        // グラフがない場合は新規作成
        let newChart = sheet.newChart()
          .setChartType(Charts.ChartType.LINE)
          .addRange(dataRange)
          .setPosition(5, 5, 0, 0)  // グラフの位置を指定
          .setOption('title', 'Sample Line Chart')
          .build();
        sheet.insertChart(newChart);
      }
    }
    
    function getRandomInt(min, max) {
      const minCeiled = Math.ceil(min);
      const maxFloored = Math.floor(max);
      return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled);
    }
    ```

1. 一旦当該のスプレットシートのデータを削除
1. GASのコードを実行
1. A列B列にデータが追加されてグラフが作図される（何度か実行した例↓）

    ![CleanShot 2025-01-11 at 11.27.17@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/31899fd0-63bf-802f-db3b-de1465dbc957.png)

## 参考文献

https://developers.google.com/apps-script/reference/spreadsheet/embedded-chart-builder?hl=ja#addrangerange

https://developers.google.com/apps-script/reference/spreadsheet/embedded-chart-builder?hl=ja

https://developers.google.com/apps-script/reference/spreadsheet/embedded-chart?hl=ja

https://developers.google.com/apps-script/reference/charts/chart-type.html?hl=ja

https://developers.google.com/apps-script/reference/spreadsheet/sheet?hl=ja#getcharts

https://developers.google.com/apps-script/reference/spreadsheet/embedded-chart-builder?hl=ja#setPosition(Integer,Integer,Integer,Integer)

https://developers.google.com/apps-script/reference/spreadsheet/embedded-chart-builder?hl=ja#setOption(String,Object)

https://developers.google.com/apps-script/chart-configuration-options?hl=ja

getActiveSheet()について↓

https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app?hl=ja#getActiveSheet()
JavaScriptのreplaceに気をつけろ！

## はじめに

同じ名前の関数でも、言語によって機能が異なることがあります。
JavaScriptのreplaceは注意しなければいけないもののひとつです。


| 言語        | メソッド名           | 動作                                       |
|-------------|----------------------|-------------------------------------------|
| **C#**       | `Replace()`           | すべての一致を置換                        |
| **Python**   | `replace()`           | すべての一致を置換                        |
| **Java**     | `replace()`           | すべての一致を置換                        | 
| **JavaScript** | `replace()`         | **最初の一致だけ**を置換                    |


## 各言語の例

### **C#**
```csharp
string str = "2024/11/14";
string result = str.Replace("/", "-");
Console.WriteLine(result);  // "2024-11-14" (すべてのスラッシュを置換)
```

### **Python**
```python
str = "2024/11/14"
result = str.replace("/", "-")
print(result)  // "2024-11-14" (すべてのスラッシュを置換)
```

### **Java**
```java
public class Main {
    public static void main(String[] args) {
        String str = "2024/11/14";
        String result = str.replace("/", "-");
        System.out.println(result);  // "2024-11-14" (すべてのスラッシュを置換)
    }
}
```

### **JavaScript**
```javascript
let str = "2024/11/14";
let result = str.replace("/", "-");
console.log(result);  // "2024-11/14" (最初の1箇所だけ置換)

result = str.replace(/\//g, "-");
console.log(result);  // "2024-11-14" (すべてのスラッシュを置換)
```

**最初の1箇所だけ**なことに注意！！
全てを置換したい場合は正規表現を利用します。
新しめの環境ではreplaceAllでも一気に全部置換できます。

## まとめ
- **JavaScript** は**最初の一致のみ**を置換し、正規表現を使うことで全ての一致を置換可能。
- **C#**, **Python**, **Java** では `replace` メソッドがデフォルトで **すべての一致を置換**し、特別なフラグや設定は不要。

気を付けましょう！！
ZIOのエラーモデル

# 概要

Scala ZIOのエラーモデルについて共有させていただきます。

https://zio.dev/

## 1. エフェクト型とエラー型

ZIO は Scala の関数型プログラミングを活用し、非同期・並行処理を安全に記述できるライブラリです。ZIO のエフェクトは次のような三つ組の型で表されます。

```Scala
ZIO[R, E, A]
```

- `R`: エフェクトの実行に必要な環境  
- `E`: エフェクトが失敗するときに返す「エラー」の型  
- `A`: エフェクトが成功したときに返す値の型

ZIO の特徴は、**失敗しうる要因** をあらかじめ型 `E` として表現し、コンパイラの助けを借りながら失敗をハンドリングできる点にあります。

## 2. Error（エラー）

ZIO でいう **Error** とは、「アプリケーションレベルで予測・想定しうる失敗」を指します。たとえば文字列を整数に変換するとき、入力が不正な場合には `NumberFormatException` が起こり得ますが、これは「あり得る」ケースとして事前に考慮できます。

ZIO では、このように事前に想定できる失敗を型 `E` で表し、プログラム側で回復（リトライ、デフォルト値、別の処理への切り替えなど）を行うことが可能です。これによって、ビジネスロジックやアプリケーションのドメインルールに則した形で、きめ細かく失敗をハンドリングできます。

## 3. Defect（欠陥）

一方、ZIO でいう **Defect** は、「本来は起こり得ないはずの異常事態」や「コード上で想定していない実行時エラー」を指します。たとえば、

```scala
val divisionByZero: UIO[Int] = ZIO.succeed(1 / 0)
```

のように、絶対に失敗しない型（`UIO[Int]`）として定義しているのに、実行時に `ArithmeticException` が飛んでしまうケースなどが典型例です。ZIO の型シグニチャ上では「失敗しない」と明言しているにもかかわらず、実際には JVM の算術エラーが発生してしまうわけです。

この場合、ZIO は `ArithmeticException` を **Defect** として扱います。つまり、開発者が「想定済みのエラー」として対処していない領域で発生する問題であり、アプリケーションレベルで回復処理を行うことは通常できません。

## ISTQB が定義する Error / Defect と似ている点

ISTQB（International Software Testing Qualifications Board）では、ソフトウェア開発工程において次のような用語を定義しています。

- **Error（エラー）**: 人間が起こすミスや誤り  
- **Defect（欠陥）**: コードや設計に潜むバグ、実装ミスなど、ソフトウェア内に存在する問題

ここで興味深いのは、**ZIO の「Error」はアプリケーションが想定しうる失敗を意味し、ISTQB の「Error」は人間のミスを発端とするものではあるものの、いずれも「比較的コントロール可能な範囲で発生する問題」という点で似通っている**ことです。

また、**ZIO の「Defect」は、ISTQB の「Defect（欠陥）」と同様に「コードや設計が想定していないエラーや問題」を指す**ところに相似点があります。ZIO においては、こうした想定外の重大な問題が起きた場合に “Defect” として扱われ、回復が困難または不可能とみなされます。ISTQB においても、テストを通じて発見された欠陥は修正の対象となり、場合によってはシステムを致命的に停止させる可能性があります。
単純化した山火事シミュレーションを作ってみました

単純化した山火事のシミュレーションを作ってみました．
仮定は以下です．
* 木がランダムな位置に生えている
* 最初に1本の木が燃える
* 燃えている木と燃えていない木が一定の距離内にあると，一定の確率で燃え移る
* 燃えている木は一定確率で燃え尽きる

MATLABのmlx形式で作りました．
[Simplified simulation of mountain fire](https://jp.mathworks.com/matlabcentral/fileexchange/178959-simplified-simulation-of-mountain-fire)

木の本数，燃え移る可能性のある距離，燃え移る確率，燃え尽きる確率を設定できます．

実行した画像です．
![画像1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570966/42deccc3-96ae-9a84-fd5a-0fe705f5ecb1.png)
* 上図
    * 緑，赤，黒：それぞれ健康な，燃えている，燃え尽きた木
* 下図
    * 横軸：時刻
    * 縦軸：健康，燃えている，燃え尽きた木の本数

動画はこんな感じ．

![mountainFireSim_gif_01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570966/796d1744-213d-230f-c77c-fb8dfc53e9ab.gif)

同じパラメータでも木の配置と1本目の場所で結果がかなり異なります．山火事の予測が本質的に難しいことや，野焼きなどの伝統的な方法が大規模火災の抑制策となりうる(そもそもの木の密度を下げる，すでに燃えている地域を増やす，など)ことも示唆されます．

## 参考文献
[歴史は「べき乗則」で動く　―種の絶滅から戦争までを読み解く複雑系科学―（ハヤカワ文庫NF）](https://www.hayakawa-online.co.jp/shop/g/g0000090358/)
* 第7章「防火対策を講じるほど山火事は大きくなる」で，題名の通りとなることが紹介されています．
VSCode × AIアシスタント Clineで開発をスムーズに！コード補完からデバッグまで自動化

# はじめに

Clineは、**コード補完やバグ修正、ターミナルコマンドの実行、ブラウザ操作、ファイル編集**まで幅広くサポートするAIアシスタントです。

Clineは、VSCodeと連携しながら、**CLI（コマンドライン）やエディタを自在に操るAIアシスタント**として機能します。
従来のコード補完を超え、**実際に開発タスクを実行しながら**プロジェクトを進めることが可能です。

「ファイルを編集しながら、エラーが出たら自動修正し、ターミナルでビルドやテストまで行う」
そんな理想的な開発体験を実現するのが、Clineの強みです。

📌 **公式サイトはこちら**：[Cline GitHubリポジトリ](https://github.com/cline/cline)

## Clineでできること

### 📌 1. ファイルの作成・編集

Clineは、**コードを理解し、適切なファイルを作成・編集**できます。
さらに、**コンパイルエラーやlintエラーを監視しながら**修正を加えることが可能です。

例えば、以下のようなことができます。

- Reactコンポーネントを作成し、必要なimport文を自動追加
- TypeScriptの型エラーを検出し、適切な型を提案
- Djangoのビューを編集し、関連するURLルーティングを追加

変更内容は**diffビューで確認**できるため、手動で修正・承認も可能です。

### 💻 2. ターミナルコマンドの実行

VSCodeのターミナルと連携し、Clineは直接コマンドを実行できます。

**例えば…**

- `npm install` や `pip install` で依存関係をセットアップ
- `docker compose up` でコンテナを起動
- `pytest` でテストを実行し、エラーが出たら修正

Clineは実行中のプロセスを監視し、ビルドエラーやサーバークラッシュなどの問題を即座に検出します。
これにより、発生したエラーに対して迅速に対応し、開発環境の安定性を維持することができます。

### 🌐 3. ブラウザを活用したデバッグ

Clineは、Webアプリの動作確認やデバッグも得意です。

**ブラウザ操作の一例**

- `npm run dev` でローカル開発環境を起動
- ページを開き、ボタンをクリック・フォームに入力
- **スクリーンショットを取得し、UIの問題を可視化**
- **コンソールログを解析し、JavaScriptエラーを特定**

これにより、E2Eテストやデバッグの手間を大幅に削減できます。

### 🛠 4. MCPを活用したツールの追加

Clineの優れた点は、**MCP（Model Context Protocol）を活用して、新しいツールを柔軟に追加できること**です。

例えば、以下のようなカスタムツールを追加できます。

📝 **「Jiraのチケットを取得し、作業を整理するツール」**
☁️ **「AWSのEC2インスタンスを監視＆スケールアップするツール」**
📢 **「PagerDutyのインシデントを取得し、対応を自動化するツール」**

これにより、チームのワークフローを最適化し、作業をより効率的に進めることができます。

### 📁 5. コンテキスト管理

Clineは、開発環境の情報を適切に管理し、
**必要なデータのみを読み込んで処理**するため、無駄なAPIリクエストを抑えられます。

🔗 `@url` → 最新のドキュメントを取得し、Markdownに変換
🚨 `@problems` → VSCodeのエラーログを解析し、修正
📂 `@file` → 任意のファイルを追加して、コードの内容を参照

プロジェクトのサイズが大きくなっても、Clineは**無駄なく情報を整理**し、スムーズに動作します。

### 🕒 6. 変更履歴の管理とリストア

Clineはタスクの進行に応じて、**ワークスペースのスナップショットを自動作成**します。

例えば、

- `Compare` ボタンで、変更前後のdiffを比較
- `Restore` ボタンで、過去の状態にロールバック

複数のバージョンを試したいときも、簡単に切り替えられるため、
**「コードを試しながら安全に開発できる」環境**が整っています。

## まとめ

Clineはプロンプトをもとに、以下のような開発支援を自動で行います。

- **コードの作成・編集を実行し、エラーを自動修正**
- **ターミナルコマンドを実行し、リアルタイムで問題を特定・修正**
- **ブラウザ操作を通じて、UIのデバッグやE2Eテストを支援**
- **カスタムツールを追加し、ワークフローを最適化**
- **コンテキストを管理し、最適な情報を基に作業を進行**
- **変更履歴を保存し、安全にロールバック可能**

このように、Clineは開発プロセスの各ステップを効率化し、
エラーの発生を未然に防ぎながら、**コードの作成からデバッグ、デプロイまでの流れをスムーズに**します。
これにより、開発者はより短時間で高品質なソフトウェアを構築できるようになります。

**AIの力を活用して、より自由で生産的な開発を始めましょう！**
spawn psが見つからないエラー

## エラー対応備忘録

### 環境
・フレームワーク；Nestjs

### エラー内容
`
 {
errno: -2,
code: 'ENOENT',
syscall: 'spawn ps',
path: ps',
spawnargs: [ '-o', 'pid', '--no-headers', '--ppid', 78 ]
}
`

・エラーの意味
ホットリロード時にspawn psが実行されるが、コマンドが見つからない

コードの変更が検知された際にプロセス状態を確認して実行中であれば、そのプロセスを終了して新しいプロセスを起動する。そのプロセス状態を確認する際にpsコマンドを使用するが、見つからない。

nestjsのdockerコンテナはnode:18-slimを使用している
軽量版を使用しているためコマンドでツールを取得する必要があるのかもしれない


### 解決策
dockerFileに以下を追加
`apt-get install -y procps`
【2025年01月版】Ubuntu24.04 で構築した開発環境に自動アップデートを入れてみる【unattended-upgrades】

# はじめに

開発環境が多くて、定期的に `apt update && apt upgrade -y` と再起動やるのめんどくさいなぁ

セキュリティアップデートと再起動とか自動でやってくれたらいいのに

そうだ、`unattended-upgrades` でやろ、のメモ

# 設定

セキュリティアップデートして必要であれば再起動してくれる設定
セキュリティアップデートはデフォルトでしてくれるようになっているはず

※ コピーして差分をみてるけど、そのまま `/etc/apt/apt.conf.d/50unattended-upgrades` を修正してもいい

```terminal
$ sudo apt install unattended-upgrades  # デフォルトで入っているから必要ないはず
$
$ mkdir -p work/"$(date +%Y%m%d)"
$ cd $_
$ cp /etc/apt/apt.conf.d/50unattended-upgrades ./
$ sudo vim /etc/apt/apt.conf.d/50unattended-upgrades
$ diff /etc/apt/apt.conf.d/50unattended-upgrades ./50unattended-upgrades
95d94
< Unattended-Upgrade::Automatic-Reboot "true";
105d103
< Unattended-Upgrade::Automatic-Reboot-Time "04:00";
$ sudo dpkg-reconfigure unattended-upgrades
```

修正箇所

```/etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Automatic-Reboot "true";        # 自動再起動を有効化
Unattended-Upgrade::Automatic-Reboot-Time "04:00";  # 再起動時間指定
```

:::note warn
自動アップデートがおこなわれいないようなら、以下の設定になっているか確認する

```/etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";         # パッケージリストの自動更新
APT::Periodic::Unattended-Upgrade "1";           # 自動アップデートの有効化
```

デフォルトはセキュリティアップデートのみになっている
```/etc/apt/apt.conf.d/50unattended-upgrades
// Automatically upgrade packages from these (origin:archive) pairs
//
// Note that in Ubuntu security updates may pull in new dependencies
// from non-security sources (e.g. chromium). By allowing the release
// pocket these get automatically pulled in.
Unattended-Upgrade::Allowed-Origins {
        "${distro_id}:${distro_codename}";
        "${distro_id}:${distro_codename}-security";
        // Extended Security Maintenance; doesn't necessarily exist for
        // every release and this system may not have it installed, but if
        // available, the policy for updates is such that unattended-upgrades
        // should also install from here by default.
        "${distro_id}ESMApps:${distro_codename}-apps-security";
        "${distro_id}ESM:${distro_codename}-infra-security";
//      "${distro_id}:${distro_codename}-updates";
//      "${distro_id}:${distro_codename}-proposed";
//      "${distro_id}:${distro_codename}-backports";
};
```
:::


# 確認

## 手動による実行テスト

```terminal
$ sudo unattended-upgrades --dry-run --debug
```

## 設定の確認

```terminal
$ sudo apt-config dump | grep -i unattended | grep -i reboot
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
```

## 実行ログの確認

```terminal
$ sudo less /var/log/unattended-upgrades/unattended-upgrades.log
```

# さいごに

かんたんでしたね
【Rails】SimpleCovを導入してテストカバレッジを計測する

## はじめに
SimpleCovは、Rubyのテストフレームワーク（RSpecやMinitestなど）と統合してコードカバレッジを測定するためのツールです。コードカバレッジは、テストがどの程度コードをカバーしているかを示す指標であり、テストの充実度を把握するのに役立ちます。

この記事では、RailsアプリケーションにSimpleCovを導入して、テストカバレッジを計測する手順をまとめます。

## 導入手順
### SimpleCovをインストールする

まず、SimpleCovをGemfileに追加します。
```ruby
group :test do
  gem 'simplecov', require: false
end
```

その後、以下のコマンドでインストールを行います：
```ruby
bundle install
```

### SimpleCovを設定する

テストの実行開始時にSimpleCovを有効化する必要があります。通常はテスト設定ファイルに以下のコードを追加します。

RSpecの場合

spec/spec_helper.rbの先頭に以下を追加します：
```ruby
require 'simplecov'
SimpleCov.start 'rails' do
  add_filter '/bin/'
  add_filter '/db/'
  add_filter '/spec/'
end
```

これにより、Railsアプリケーション固有の設定が適用され、テスト実行時にカバレッジレポートが生成されます。

### テストを実行してカバレッジレポートを生成する

SimpleCovはテストスイートの実行時にカバレッジデータを収集します。
以下のコマンドでテストを実行してください：
```ruby
bundle exec rspec
```

テスト実行後、coverageディレクトリが作成され、その中にHTML形式のカバレッジレポートが生成されます。

### カバレッジレポートを確認する

生成されたレポートはcoverage/index.htmlにあります。ブラウザでこのファイルを開くと、以下のような情報が確認できます：

* 総カバレッジ率（%）
* ファイルごとのカバレッジ率
* カバレッジされていないコードの行番号

## 参考
https://github.com/simplecov-ruby/simplecov

https://qiita.com/oknoamazia/items/485b562ffed925bb04ff
論文まとめ：EscherNet: A Generative Model for Scalable View Synthesis

# はじめに
CVPR2024より以下の論文
[1] X. Kong, et. al. "EscherNet: A Generative Model for Scalable View Synthesis". CVPR2024
のまとめ

### project page
https://kxhit.github.io/EscherNet

### CVF Open Access
https://openaccess.thecvf.com/content/CVPR2024/html/Kong_EscherNet_A_Generative_Model_for_Scalable_View_Synthesis_CVPR_2024_paper.html

### github
https://github.com/kxhit/EscherNet

<font color="red">一部書きかけ</font>

# はじめに
- 対象物に対する１枚もしくは複数枚の参照画像から、その対象物に対して別の角度・位置から見た画像を生成する
- 学習データには無い、初めての対象物に対しても生成可能（zero-shoto）
- 既存手法に比べて精度よい（角度・位置の条件付き）画像生成を実現するため、新たにカメラ・パラメータのencoding方法を開発した
- 推論時には参照画像とそのカメラパラメータ、及び生成する画像のカメラパラメータが必要

以下の例では左のピンク色の枠が参照画像、右の青い枠の画像が新たに生成した画像。

![スクリーンショット 2025-01-11 9.05.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116706/eb863c79-989c-ba2f-5760-a82d9e2c7bab.png)

最上段は参照画像１枚から任意の視点の画像を生成している。最下段は４枚の参照画像から物体の背面まで正確に生成している。

# 既存の3D表現との違い
以下は既存の3D表現や別視点生成モデルとの違いを端的に表した図。

![スクリーンショット 2025-01-11 9.10.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116706/34a12a8f-a484-3152-6711-dba5f21b45fc.png)

左上：点群の3D表現
中央上：voxelの3D表現
右上：隠間数による3D表現
左下：NeRFによる3D表現

中央下は Zero-1-to-3（いわゆるzero123）モデル。今回の仕組みに似ているが、１枚の参照画像 ${\bf X}^R$ と出力する別視点画像とのカメラパラメータの差分 $\Delta{\bf P}$ から、別視点の画像 ${\bf X}^T$ を１枚生成する。

右下は本手法 EscherNet。N枚の参照画像 ${\bf X}^R\_{1:N}$ とそのカメラパラメータ ${\bf P}^R\_{1:N}$ 、出力するM個の視点に対応するカメラパラメータ ${\bf P}^T\_{1:M}$ から対応する画像 ${\bf X}^T\_{1:M}$ を生成する。

# ニューラルネットワークのアーキテクチャ
以下がNNのアーキテクチャの図。

![スクリーンショット 2025-01-11 9.43.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116706/da9d5546-2daa-0002-ddaa-a7718198a076.png)

左側２つが全体的な部分。右側２つはモジュールの詳細。

### 参照画像のencoding 
最左では ConvNext v2 tinyを使って参照画像をencodeする。

一般的なstable diffusionモデルはCLIPで画像をencodeするが、CLIPでは画像の詳細部分の特徴量を表現しにくいらしい。Convnextはその点優れているとのこと。

本 EscherNetでは参照画像が N 枚と任意なのが特徴的だが、batchを１と考えると [N, H, W, C]をreshapeして [N, HW, C]とする。Nの次元はProjectionで１つにされる（？）。

これをのちに cross-attention blockに入力する。

### stable-diffusionのUNet全体
図中、左から２番目でstable-diffusionのUNetを用いて画像を生成する。

self-attention blockではカメラパラメータをconditionとして与える。cross attention blockではカメラパラメータと参照画像をconditionとして与える。

### cross attention block
図中、右から2つ目。stable diffusionと同様に参照画像をencodeしたものをkey, valueとして、cross attentionする。

M個の視点の画像を生成するのでMの次元が加わっている。

### cross attention内の行列演算
本手法の特徴的な部分。カメラパラメータを使用する。

# camera positional encoding
本手法の特徴的な部分。
<font color="red">書きかけ</font>

# 学習方法
Objaverse-1.0 datasetを用いてモデル（UNet部分）を学習させる。
processingで日本語フォントを作成するときの備忘録

一部文字が表示されなかったのでそれの対処法をまとめました

![imagepng](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3962799/8e17dc77-cf3e-7a60-6f99-77cd76a4b675.png)

これの対処法です。

# 対処法

ツール→フォント作成→右下の`文字`を押す

![imagepng](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3962799/e4beda96-a87b-8ece-f2e5-b4a5e31accef.png)

ラジオボタンを`特定のUnicodeブロックに変更`して、下記のものにチェックを入れる
下記6つは[Processing で日本語を表示する](https://www2.kobe-u.ac.jp/~tnishida/misc/processing-japanese.html)からの引用です。

> - Basic Latin (半角英数)
> - CJK Symbols and Punctuation (句読点、全角括弧)
> - Hiragana
> - Katakana
> - CJK Unified Ideographs (主な漢字)
> - Halfwidth and Fullwidth Forms (全角英数、全角記号、半角カナ)
- Geometric Shapes（◯を表示するのに必要でした）
関数型プログラムについて、chatGPTに聞いてみた


関数型プログラムは副作用の隔離が主なメリットととしてあげられますが、現実的にはどうなのかchatGPTにいろいろ聞いてみました。私の素朴でわけのワカラン質問に答えてくれてありがたいとおもいつつ（ここはカットします；；）、最終的には以下のような結論に到達しました。

--------------以下chatGPT
関数型プログラミングには確かにメリットがあるものの、そのメリットが適用できる場面が限定的であり、実務においてはコストが大きすぎる場合がほとんどというのが現実です。


## 1. 学習コスト
関数型プログラミングには、純粋関数、不変データ構造、遅延評価、モナド（Haskellなどの場合）といった独特の概念が含まれます。
手続き型やオブジェクト指向に慣れた開発者にとっては、これらの考え方を理解し、実務に適用するには大きな学習コストが伴います。
特に、モナドや関数合成などの高度な概念は「直感的ではない」と感じられることが多い。
## 2. 開発コスト
実際に関数型スタイルでコードを書くと、状態変更を避けるために設計が複雑化し、実装に余分な時間がかかることが多い。
チーム全体で関数型の思想を共有し、適切に実装するには追加のコーディングガイドラインやレビューが必要。
例: 単純なデータ処理のタスクでも、関数型スタイルではコードが冗長になることがある。

#### 手続き型
```python
numbers = [1, 2, 3, 4]
result = [x * 2 for x in numbers if x % 2 == 0]
print(result)  # [4, 8]
```

#### 関数型
```python
from functools import partial
numbers = [1, 2, 3, 4]
double = partial(lambda x: x * 2)
result = map(double, filter(lambda x: x % 2 == 0, numbers))
print(list(result))  # [4, 8]
```

## 3. パフォーマンスのコスト
関数型スタイルでは、不変データ構造を扱うため、新しいデータを生成するオーバーヘッドが増える。
再帰処理を多用するとスタックオーバーフローや効率の悪化が起こる場合もある。
例: リストを再帰的に処理する場合、手続き型のループの方が効率的。

##### 再帰（関数型スタイル）
```python
def sum_recursive(lst):
    if not lst:
        return 0
    return lst[0] + sum_recursive(lst[1:])
```

##### ループ（手続き型）
```python
def sum_loop(lst):
    total = 0
    for x in lst:
        total += x
    return total
```


## 4. 適用範囲の狭さ
関数型プログラミングが真価を発揮するのは、主に次のような場面です：
#### 並列処理
データパイプライン
数学的なアルゴリズム
これ以外の一般的なアプリケーション開発（UI、CRUD操作、リアルタイム通信など）では、関数型のメリットがほとんど得られない。
メリットが大きいと思われがちな場面の実情
1. バグの低減
純粋関数や不変データを使うことで、確かに副作用によるバグが減ります。
しかし、これを無理に適用することで設計や実装が複雑になり、複雑性そのものが新たなバグを招く場合があります。
2. 再利用性
高階関数を活用することでコードの再利用性が向上すると言われます。
しかし、実務では「小さく再利用可能な関数を作る」よりも「具体的なユースケースを解決するコードを書く」方が重要な場合が多いです。
3. 並列処理やスレッドセーフ性
関数型の不変データ構造は、データ競合のない並列処理に適しています。
ただし、多くの実務プロジェクトでは、すでにライブラリやフレームワーク（例: Pythonのconcurrent.futures）がデータ競合を回避する仕組みを提供しており、関数型を導入するメリットは薄いです。

### コストとメリットを比較した結論
#### コスト
学習コスト: 開発者全体が理解し、適用するのは時間がかかる。
開発コスト: 実装が冗長になり、複雑性が増す。
パフォーマンスのコスト: 再帰や不変データ構造の扱いで効率が悪化することがある。
#### メリット
状態を持たない設計が予測可能性を高める。
並列処理やデータパイプラインで効果的。
特定のフレームワークや分野（React、データ解析など）で有効。
#### 結論: 実務ではコストが大きすぎる
関数型プログラミングのメリットは、限定的な状況では確かに存在します。しかし、それに伴うコスト（学習、開発、パフォーマンス）が大きすぎるため、以下のような考え方が現実的です：

## 関数型プログラミングを全面採用しない:

結論：必要性のない状況で無理に取り入れるのは避けるべき。
    部分的に採用する場合も慎重に:

map/filter/reduce のようなシンプルなツールは使うが、純粋性に固執せず、現実的な解決を優先する。
十分なメリットが得られる場合にのみ導入:
特定の分野（データ処理、並列処理、数学的アルゴリズム）でのみ活用。

## 最終的な判断基準
実務においては、「関数型プログラミングを採用することで具体的なコスト削減や品質向上が期待できるか」を冷静に判断し、メリットがコストを上回らない場合には、潔く採用しない選択をすることが重要です。

無理に使うことによる複雑性の増加は、実務では致命的なデメリットになります。

--------------

ということで、適材適所で使っていければと思いました。
Windows Visual C++でプライマリーディスプレイアダプターのベンダーIDを取得する

## Windowsアプリでプライマリーディスプレイアダプターのベンダーidを取得したい！
作成しているWindowsアプリでGPUのハードウェアエンコーダを利用したいと考えていますが、GPUのメーカーをどうやって取得したらいいのだろう？
Win32、Direct3D、WinRTなどいろいろなやり方があるっぽいですが、とりあえず動けば何でもいい。できれば簡単なやつがいい。
Windows Copilotに聞きました。
## Windows Copilotさんが提案してくれたコード
VisualStudioのリンカー＞入力に`DXGI.lib`を追加
```C++
#include <iostream>
#include <vector>
#include <map>
#include <dxgi1_6.h>
#include <wrl/client.h>

using namespace Microsoft::WRL;

int main() {
    // ベンダーIDとメーカー名のマップを作成
    std::map<UINT, std::wstring> vendorMap = {
        {0x10DE, L"NVIDIA"},
        {0x1002, L"AMD"},
        {0x8086, L"Intel"}
    };

    // DXGIファクトリーの作成
    ComPtr<IDXGIFactory6> factory;
    HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
    if (FAILED(hr)) {
        std::cerr << "Failed to create DXGI factory." << std::endl;
        return -1;
    }

    // アダプターの列挙
    ComPtr<IDXGIAdapter1> adapter;
    for (UINT adapterIndex = 0; factory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
        DXGI_ADAPTER_DESC1 desc;
        adapter->GetDesc1(&desc);

        // プライマリアダプターを確認
        if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
            continue;  // ソフトウェアアダプターをスキップ
        }

        // ベンダーIDの取得と16進数形式での表示
        std::wcout << L"Vendor ID: 0x" << std::hex << desc.VendorId << std::endl;

        // ベンダーIDに対応するメーカー名の取得と表示
        auto it = vendorMap.find(desc.VendorId);
        if (it != vendorMap.end()) {
            std::wcout << L"Manufacturer: " << it->second << std::endl;
        } else {
            std::wcout << L"Manufacturer: Unknown" << std::endl;
        }
        break;
    }

    return 0;
}

```

## その他の方法として
AMDのライブラリを使おうかとも考えたりしてました。

https://gpuopen.com/amd-gpu-services-ags-library/
MarkdownAIを触ってpythonの関数の使い方を教えてもらえるサービスを作ってみた

## この記事は
QiitaのMarkdownAIチャレンジのキャンペーンを見て、とりあえずMarkdownAIを触ってみた事例の紹介です。

## やったこと
Pythonの関数の使い方を教えてくれるサービスを作ってみました。
できたものは以下のリンクのものです。
https://mdown.ai/content/96febf5f-0f20-4fed-b73e-72444bdc1b97

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3974913/bf76a5e4-5620-26df-173c-a4b32488278d.png)

何となくお試しで作ってみたのですが、調べるのがめんどくさいときに便利かも知らん。

## PromptなどAIの設定
Modelはデフォルトのgpt-4o-miniを指定しました。

Promptとしては以下を入力。
~~~
list the arguments of input python function
~~~

Knowledgeは空欄のままです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3974913/2e51188c-eb47-139e-708b-349d3d3b7514.png)

## Webサイトの生成
チュートリアルの動画にあるように、空のMarkdownに作成したScriptをInsertしました。
それだけだと味気ないので簡単に説明をつけました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3974913/ad3da821-3c07-5134-b0bc-8e87516b2377.png)

「View」を押すと、以下のように表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3974913/6505136d-adea-035c-c916-76ca0cd69320.png)

## 動作確認
試しに"print"と入力して「Run AI」ボタンを押すと、いろいろと説明が出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3974913/3ab6231b-86c0-1ee3-a487-4bdac882c79d.png)

OpenCVの関数の使い方も出力できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3974913/8c5f81b7-ea88-addd-21ed-d9f5c3386cc3.png)

## 共有
URLボタンをクリックすると、以下のダイアログが出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3974913/5f2aa019-069a-a9ca-d39d-a2ecb8025864.png)

Publishを押すと、URLが出力されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3974913/bc649e32-7c99-0892-0cef-b2dd11094a0a.png)

## 感想
- 5分くらいでAI入りwebサービスができたので、すごい（語彙）
- 入力されたデータを外部に飛ばすとかできたら面白そう
- IoTデバイスからのアクセスもやってみたい
    - 気温・湿度のデータを入れたら不快指数を返すくらいはできそうだけれど

## うまくできなかったこと
- 最初は気象庁のwebサイトのリンクをKnowledgeとして渡して「1980年の1月の気温を教えて」みたいなことをしようとしたのだけれども、エラーで固まってしまった
    - →詳細未調査
3分でFactoryBotを使ってテストデータを作る

## Overview
この記事では、`factory_bot_rails`Gem（FactoryBot）を使ってテストデータを作成し、テストを作成・実行するまでの方法を書いてみようと思います。

## Motivation/context
EverydayRspecの本を読んで、自分で作ってるアプリにfactoyBotを追加してみました。
何度も実行しそうなコマンドや内容なのでここにメモしておきます。

今回は`Faq`モデルに対するfactoryBotとRspecを追加していきます。
Faqモデルは「よくあるご質問」に関するモデルですので、タイトル（title）と内容（content）というシンプルな2カラム構成です。


## Get Started!!

### Faqモデルスペックの作成
```bash
rails g rspec:model faq
```

### Faqのファクトリーファイル作成
```bash
rails generate factory_bot:model Faq
```

### テストケースを書いてみる

:::note info
ポイント
1. 普通であればitであるところをfitとしているのは、新規で追加したテストだけを`$bundle exec rspec`実行時に実行したいからです。（commit前にfitはitに変換されます）
:::

`spec/models/faq_spec.rb`
```ruby
require 'rails_helper'

RSpec.describe Faq, type: :model do
  fit "title,contextがあれば有効名こと" do
    faq = FactoryBot.build(:faq)
    expect(faq).to be_valid
  end
  describe "存在性" do
    context "titleがない場合" do
      fit "エラーになる" do
        faq = FactoryBot.build(:faq, title: nil)
        faq.valid?
        expect(faq.errors[:title]).to include("を入力してください")
      end
    end
    context "contentがない場合" do
      fit "エラーになる" do
        faq = FactoryBot.build(:faq, content: nil)
        faq.valid?
        expect(faq.errors[:content]).to include("を入力してください")
      end
    end
  end
  describe "文字数の境界値" do
    context "titleが1文字だけの場合" do
      fit "無効である" do
        faq = FactoryBot.build(:faq, title: "a")
        faq.valid?
        expect(faq.errors[:title]).to include("は2文字以上で入力してください")
      end
    end
    context "titleが2文字だけの場合" do
      fit "有効である" do
        faq = FactoryBot.build(:faq, title: "a" * 2)
        expect(faq).to be_valid
      end
    end
    context "titleが30文字の場合" do
      fit "有効である" do
        faq = FactoryBot.build(:faq, title: "a" * 30)
        expect(faq).to be_valid
      end
    end
    context "titleが31文字の場合" do
      fit "有効である" do
        faq = FactoryBot.build(:faq, title: "a" * 31)
        faq.valid?
        expect(faq.errors[:title]).to include("は30文字以内で入力してください")
      end
    end
  end
end
```


### FactoryBotでテストデータを作成
`spec/factories/faqs.rb`
```ruby
FactoryBot.define do
  factory :faq do
    title { "Sample" }
    content { "..." }
  end
end
```

### Faqモデルを編集
```ruby
class Faq < ApplicationRecord
  validates :title, presence: true, length: { in: 2...31 }
  validates :content, presence: true
end
```

### Rspecの実行
:::note info
`it`を`fit`に変更していたことにより、このコマンドでも新規追加分のテストだけを実行してくれる。
いちいち全部のテストケースを流す必要はないですからね！！
:::

```bash
$ bundle exec rspec
```


### 終わった後に気づいたこと
:::note warn
テストの構造なのですが... `context`の中にitが１つだけなんて、なんか悲しいので、こういう感じにすればよかったと後悔！！
```diff
- context "titleが1文字だけの場合" do
- context "titleの入力値が足りない場合" do
```
こうすれば、contextの数が少なくなって、条件を一まとめにできた・・・。
:::
「Error Code: 1055. Expression #2 of SELECT」の解決（MySQL）

# はじめに
こんにちわ、千秋です。

先日、担当する業務でSQLの知識が必要となったため、勉強のために「[達人に学ぶSQL徹底指南書（2008年出版）](https://www.valuebooks.jp/%E9%81%94%E4%BA%BA%E3%81%AB%E5%AD%A6%E3%81%B6SQL%E5%BE%B9%E5%BA%95%E6%8C%87%E5%8D%97%E6%9B%B8--CodeZine-books-/bp/VS0013821379)」を読み始めました。

しかし、記載されているコード通りに実行すると表題のエラー（Error Code: 1055）が発生しました。これの解決方法を本日は共有しようと思います。

# 使用するSQL言語
- MySQL WorkBench 8.0

# 本題
## 表について
次のような表（studentclub）があります。
- 学生はクラブに所属している
- 学生は複数のクラブに所属していることがある
- 学生が一つのクラブにしか所属していない場合、main_club_flgはtrue
- 学生が複数のクラブにしか所属している場合、main_club_flgはfalse

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3136613/25dfdf08-6e95-e219-d43c-5c2cda4a9288.png)

表を作成する場合は、下記SQLを実行してください。
<details><summary>studentclubのCREATE文、INSERT文</summary>

```sql

-- 複数のクラブに属している場合、主に活動している部活動のレコードのmain_club_flgが1になる
-- 一つだけに属している場合、main_club_flgは0になる
CREATE TABLE `studentclub` (
  `std_id` int NOT NULL,
  `club_id` int DEFAULT NULL,
  `club_name` varchar(45) DEFAULT NULL,
  `main_club_flg` tinyint DEFAULT NULL
) 

INSERT INTO  studentclub (std_id, club_id,club_name,main_club_flg)
VALUES 
(100, 1, '野球', true),
(100, 2, '吹奏楽', false),
(200, 2, '吹奏楽', false),
(200, 3, 'バドミントン', true),
(200, 4, 'サッカー', false),
(300, 4, 'サッカー', false),
(400, 5, '水泳', false),
(500, 6, '囲碁', false);

```

</details>

## 期待するSELECT結果
この表に対して、次のようなSQLを作成したいです。
- １つだけのクラブに所属している学生については、そのクラブIDを取得する
- 複数のクラブを掛け持ちしている学生については、主なクラブのIDを取得する

## エラーとなった原因
そこで、次のSQLを作成しましたが、Errorとなりました。
```sql
SELECT 
    std_id, 
    case when count(*) = true then club_id
    ELSE MAX( case when main_club_flg = true then club_id
					else null end
    )
    end as main_club
FROM
    studentclub
group by std_id
```

```sql
Error Code: 1055. Expression #2 of SELECT list is not in GROUP BY clause
 and contains nonaggregated column 'world.studentclub.club_id' which is not 
 functionally dependent on columns in GROUP BY clause; 
 this is incompatible with sql_mode=only_full_group_by
```
読み砕くと、「group by句で指定していないカラムをSELECTで指定してはいけない」ということです。SELECT句で指定するのは集計対象のカラム、つまりgroup by句で指定するカラムのみとなるようです。

設定値の「ONLY_FULL_GROUP_BY」を無効にすると、上記のSQLでも実行結果が得られるそうですが、標準の設定値をいじることは極力したくないですね。

## 解決方法：ANY_VALUE()
ANY_VALUE()でgroup by句で含めないカラムを指定することで、そのカラムを非集計カラムとして扱うことができます。これにより、SQLを問題なく実行できるようになりました。
```sql
SELECT 
    std_id, 
    case when count(*) = true then any_value( club_id)
    ELSE MAX( case when main_club_flg = true then any_value( club_id)
					else null end
    )
    end as main_club
FROM
    studentclub
group by std_id
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3136613/80e448c2-37ac-8faa-0067-036f5497ecd7.png)

# 終わりに
以上となります。

標準ドキュメントに記載してありますが、group by句で指定していなくても、関数従属性がある場合はSELECT句で指定できるなど、色々と細かい条件があるようです。是非そちらもご一読ください。

# 参考
- [MySQLでのGROUP BYの処理](https://dev.mysql.com/doc/refman/8.0/ja/group-by-handling.html)
- [BigQueryでANY_VALUE関数とHAVING_MAX,HAVING_MIN句を使ってみる](https://dev.classmethod.jp/articles/bq_maxmin_by/)
Exrayを使ってElixirで円を描画してみる

Elixirで手軽に描画する方法があります
それはExrayを使うことです
Exrayはraylibを参照してます

https://www.raylib.com/

いま時点ではExrayは2Dしか動かないです

# 検証済み環境
- Ubuntu 22.04(実機)
- Windows 11 + WSL2(Ubuntu 22.04)

※macOSは動かなかった


# 作成方法

```sh
$ mix new hoge
$ cd hoge
```

https://hexdocs.pm/exray/readme.html

を見ながら

exrayを追加
```diff_elixir:mix.exs
# 省略
  defp deps do
    [
+     {:exray, "~> 0.6.0"}
    ]
  end
# 省略
```

ライブラリ取得＆コンパイル
```sh
$ mix deps.get
$ mix compile.exray
```
# ソースを書く

hexdocsのソースに円を追加しただけです

https://hexdocs.pm/exray/opening-a-window.html#stage-2-adding-raylib-stuff

のソースをコピーして修正


```diff_elixir:lib/hoge.ex
- defmodule SuperCoolGame do
+ defmodule Hoge do

  # We import Exray.Core.Window, like we did in IEX.
  import Exray.Core.Window
  # But, we also import Exray.Core.Drawing, to have access to begin_draw() and end_draw() calls.
  # This is to poll for window_should_close?() events, as without end_draw() no inputs will be polled at all.
  import Exray.Core.Drawing
  # We also need to import Exray.Core.Timing in order to set our FPS. This is VERY important.
  import Exray.Core.Timing
+ alias Exray.Utils.Colors
+ alias Exray.Shapes.Basic


  def run(width \\ 200, height \\ 200, title \\ "Hello World!") do
    init_window(width, height, title)
    set_target_fps(60) # <-- SUPER important! Call this just after you init_window, or segfaults are gonna happen a lot.
    main_loop()

    # As another layer of safety, if for some reason our window *didn't* close, we can do it here in this check.
    if window_should_close?() do
      close_window()
    end

    :ok # :ok, because we're :ok :)
  end

  defp main_loop() do

    # Stay out of update and draw unless our window is ready to update and draw.
    unless window_is_ready?(), do: main_loop()

    # If at any point we press Raylib's default "Quit Application" key, (ESCAPE), stop looping and exit.
    unless window_should_close?() do
      update()
      draw()
      main_loop()
    end
  end

  defp update() do
    # Nothing yet!
  end

  defp draw() do
    # Before drawing, we'll clear the background with the Exray.Utils.Colors.black function result- Which is %Exray.Structs.Color{r: 0, g: 0, b: 0, a: 255}.
-   clear_background(Exray.Utils.Colors.black())
+   clear_background(Colors.white)
    begin_drawing()

    # Nothing yet!
+   Basic.draw_circle(100, 100, 50.0, Colors.red)

    end_drawing()
  end

end
```


# 実行

```sh
$ mix run --eval "Hoge.run()"
```
  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/6d359b8b-43cb-2daf-f0c8-81d1a93402f7.png)

# 基本的な描画

https://hexdocs.pm/exray/Exray.Shapes.Basic.html

を参照してください

今回は`draw_circle`を使いました

色はこちらに定義されてます

https://hexdocs.pm/exray/Exray.Utils.Colors.html#summary

# 今回のソース

https://github.com/ymn-t-yamanashi/exray_draw_circle


おわり
ESP32を使ったIoTお試し　メモ

## やりたいこと
ESP32とI2C接続可能な温度センサを使って、室内環境のログをとってみたい

- 温度データなどを取得、PCで表示
- PC上に立てたflaskサーバに温度データなどを送信、DBに入力
- ブラウザからグラフなどを閲覧可能に
- AWSに送信なども試したい


## 手配する機材
- ESP32：手元にあるものを使用
- 温度センサ：BME280使用 温湿度・気圧センサーモジュールキット
    - https://akizukidenshi.com/catalog/g/g109421/
- その他、ブレッドボードなど
     ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3974913/48ba0c14-8948-7665-6cf9-8763d647fd4c.png)

## その他
- やったことは少しずつQiitaに書く