OmniAICreator/Qiita-1.07M huggingface dataset:
Snowflakeの試験に落ちた話

この投稿は[ちゅらデータアドベントカレンダー2023](https://qiita.com/advent-calendar/2023/churadata)の4日目の記事です。

# はじめに
おはようございます。こんにちは。こんばんは。
ちゅらデータの親会社 DATUM STUDIO でデータエンジニアをしているものです。

今回はDATUM STUDIOの社員3人がSnowflakeの試験に挑んだお話をしようと思います。

# きっかけ
DATUM STUDIOでは「Snowflakeの資格は試験に落ちてもそのお金を会社が補助してくれる」素晴らしい制度があります。

そこでMさん、私、Kさんの3人は「1ヶ月後に Snowflake の Advanced の試験を同日に試験受けようぜ」という話をしました。これが6月の上旬の話になります。

この3人の内訳は、Snowflakeを日常的に触っており社内でもリード的存在のMさん、ちょっと触っている私、案件で触ったことがないKさんです(2023/12/04時点でも触っていません)。各々、DATA ENGINEER・ARCHITECT・DATA SCIENTIST を受験することにしました。

(都合で、Mさんと私が7月の末に、Kさんは3日後に試験を受ける流れになりました)

# 最初に受けたMさんと私は...
Mさんと私は試験に向けてしっかりと準備をし挑みましたが、700/750という結果でした。

私たちが不合格の烙印を押されたその日、友達思いの我々はKさんの合格を祈願し飲み会を企画しました。するとKさんからこのような即レスをいただきました。
![f2Lc89fHzTKRKsz1701696902_1701696968.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633619/e3c54844-b63f-2fb0-82d5-bcbb01965135.png)

そして、飲み会中にはこのような発言をKさんは行っていました。
![KV4JZnY6HhxncFX1701697136_1701697202.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633619/d70f4998-a068-4554-afe9-691eaf709fae.png)

# 3日後に受けたKさんは...
これほど煽ったKさんですが、後日受けた試験では見事合格していた！
![スクリーンショット 2023-12-04 22.32.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633619/90c2bf84-87c6-b39f-d3d0-1387df5fe087.png)

祝勝会として、焼肉に連れて行きました。支払いはもちろんMさんと私です。

# 最後に
Kさんの合格は本当にすごいと思いますが、不合格者2人での反省会(in 居酒屋)は今でも忘れることはありません。明日は見事試験に**一発合格したKさん**のアドベントカレンダーの記事が公開されます！
![スクリーンショット 2023-12-04 22.45.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633619/5e71796e-4e63-9993-63d9-c371f23a5890.png)

追記) 記事書いたようなので貼っておきます

https://qiita.com/Camay119/items/016beaa295d143d07c87

# リベンジ
2023年12月27日に再度 私は ARCHITECT の試験を受けます。
アウトプット三日坊主の壁を突破出来た感想など【Advent Calendar 2023 4日目 / 人生4記事目】

Advent Calendar 2023への参加を機にアウトプットを始めてみた結果、何とか三日坊主の壁(?)を超えて4日目を迎える事が出来、また様々な気付きなどがありましたので、拙文となりますがその雑記となります。
## アウトプットを始めた理由など
- ~~**Qiitanぬいぐるみ欲しい！！！！！**~~
- アウトプットに興味を持ち始めていた時、周囲でAdvent Calendar 2023への参加の動きが有ったため、乗っかろうと思った
    - 自分から見た「強い人」は軒並みアウトプット力が高いという勝手なイメージがあり、自分もやってみれば何か分かる・変わるかもといった漠然とした思いは有ったが、中々重い腰があげられずに居ました。そんな中やってきた絶好の機会だと感じました。
- ~~かわいい𝓠𝓲𝓲𝓽𝓪𝓷ぬいぐるみをデスクに置くことで目の保養をしつつ「なんかこいつ強そう」感を出せそう~~
## 気付きや利点など
- 記事にする際、学んだ内容や気付き、記憶などが再構成される感覚といいますか「頭のこれまで使っていなかった部分」を使っている気がして、記事にした内容は**これまでの10倍は長く覚えていられそうな気がしました**
    - 「人に教えると自分にも定着する」といった話をあちこちで聞く気がしますが似たような感覚...?
- 記事にしようとする中で、自分はどこが分かっていて、どこがそうでないのかが非常に明確になると感じました
- (特にカレンダー期間中ということもあり)記事のネタを探そうとする行動を通して技術全般に対するアンテナが強化されるような感覚が有りました
    - ~~その結果ほぼ資格をこすることしかできなかった...~~ 
- 他の方の記事を読んだ際に「この記事のまとめ方上手すぎるだろ...」といった書く側の視点が加わることでアウトプットにも繋がる経験値を得られる
    - 未熟ゆえに殆どどの記事読んでもそう感じるため、「これまで無駄にしてきた経験値」がもったいなく感じる 
- ~~コードと同じように数年後に(今書いているような)初期記事を見返して悶絶したい~~
## やってみて難しく感じた点など
- ~~もはや難しく感じた点しか無いです~~
- 慣れていない状態ではちょっとした記事でも書くのにとても時間がかかる
    - 未経験でもちょっとした記事なら10～20分でまとまるやろ～~~𝓠𝓲𝓲𝓽𝓪𝓷楽々ゲットだぜグヘヘ~~と思って気が付いたら1時間以上経っていた＋ビックリするくらいまとまってなくて笑ってしまいました 
- 「簡潔な記事」を書くのはとても難しい
    - 読む側視点だとなんだか「簡単」に見えていましたが...
    - 要約能力に加えて、記事にしたい内容の全容を把握＋更にコアにあたる部分を正確に理解していないと書けない
        - 良記事を量産してる方々は前々から「何となくすごい」とは思っていたが、今では完全にバケモノにしか見えない 
    - あれもこれも入れたい⇒結局記事が膨れ上がってきて自分でもどんな方向性にしたいのか分からなくなってきてしまう
- 忙しい時にも継続できるのか？
    - 飛び入り参加だったためカレンダー開始時の記事のストックがゼロ...というかアカウントすら無い状態で、さらに12/3にAWS DBSの受験が控えていた状況でした。不慣れなことも有り最初の3日間は記事が~~泣きながら~~23:55～23:59辺りに書きあがるような状況でした
    - カレンダー期間中は ~~**𝓠𝓲𝓲𝓽𝓪𝓷欲しい！！！**~~ 一種のお祭りのような感覚であり、かつ毎日投稿によってとても良い感じにゲーム化(?)出来てる感があるため、このまま完走できそうな気配は有るが、カレンダー後に~~案件が燃えたりして~~多忙な際にも継続できるかが少し不穏に感じています
        - ~~まずはカレンダー完走してから心配しよう~~
    - カレンダーを完走出来れば一般的に物事の習慣化に必要とされている(?)21日間がカバーされてはいるのでそこに期待しています...?
## 今後の展望など
- 様々な変化を感じていますが、総じて強いプラス方向のものであるため、ひとまず今は ~~**𝓠𝓲𝓲𝓽𝓪𝓷欲しい！！！！！**~~ カレンダー完走に注力したいと思います！
## まとめ
軽いノリで始めてみたものの、数日間だけでも多くの気づきがあり、今では「何でもっと早くアウトプット始めなかったんだろう」~~2022𝓠𝓲𝓲𝓽𝓪𝓷とかもゲットできたのに~~という気持ちが強いです。
アウトプットを始めてみようか迷っている方にも強くオススメしたいと感じました。
このまま継続してみてカレンダー21日目 or 最終日辺りにまた振り返る事が出来ればと思います。
【速報】Microsoft Copilot Studio の価格（ライセンス料）について

# はじめに

**本日（2023/12/4）、Microsoft Copilot Studio の価格が発表されました。**

情報をくださったコミュニティ[「気ままに勉強会」](https://kimamani.connpass.com/)運営仲間の [たなさん](https://twitter.com/dreams_panda)、ありがとうございます。



# Power Virtual Agents のライセンスおさらい

ご存知の通り、Copilot Studio は、Power Virtual Agents が進化し、リブランディングされた製品です。
Power Virtual Agents の価格は以下でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/31232a9e-65d1-3c69-6b19-1cede23408c7.png)

テナントあたり、￥25,000。
これは、2022年4月から特別オファーとして、値下げされた価格です。
（以前は、$1,000 を超す価格でした）

https://twitter.com/MiTo60448639/status/1518180133038804992

また、￥25,000 は基本価格であり、**2,000セッション** を超す場合は、セッションアドオンを追加する必要がありました。


>セッションとは
>
>* ユーザーがチャット セッションを終了する。
>ボットが新しいメッセージを 30 分以上受信しない場合、セッションは終了したと見なされます。
>* セッションが 60 分を超えた場合。
>60 分後に発生する最初のメッセージによって、新しいセッションが開始されます。
>* セッションで 100 以上のターンがある場合。
>ターンは、ユーザーとボットの間の 1 つの交換として定義されます。 101 ターン目で、新しいセッションを開始します。

# Copilot Studio のライセンス

en-us の Microsoft Copilot Studio ページで確認できます。
改めて、情報をくださった [たなさん](https://twitter.com/dreams_panda) に感謝です。


https://www.microsoft.com/en-us/copilot/microsoft-copilot-studio#Pricing

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/f7a21513-2857-6986-ab2a-ddbabc52e4ab.png)

Power Virtual Agents の価格とほぼ同程度の価格となりそうです。
Copilot Studio に改名し、機能が多く追加されてたにもかかわらず、据え置き価格なのはお得と言えるのではないでしょうか。


ただし、Power Virtual Agents と大きく異なるのが、
**セッション数の上限からメッセージ数の条件に変更**されている点です。

セッション数：2,000 ⇒ メッセージ数：25,000

旧ライセンスでは、1セッションあたり、100メッセージまでやりとり可能でしたので、ここは割高感があります。

また、メッセージ数のアドオンライセンスは未発表ですが、近いうちに公表されると思われます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/d3fe4de3-ee19-7882-2222-251d62bf0f62.png)

>[1] Licenses are capacity based and additional messages can purchase. A billable message is a request or message sent to the copilot/bot triggering an action and/or response. Prices shown are for marketing purposes only and may not be reflective of the actual list price due to currency, country, and regional variant factors. Your actual price will be reflected in the checkout.
[2] Microsoft Copilot Studio provides support for select copilot experiences in Microsoft Copilot, with plans to support additional copilot experiences such as Copilot in Microsoft 365. Availability and features are subject to change.



また、［2］の記載から、Copilot for M365 のライセンスと、Copilot Studio のライセンスは別物であるように見受けられます。
プラグインアクションは、Copilot Studio のライセンスで作成し、それを利用するには、Copilot for M365 のライセンスが割り当たったユーザーとなるのではないでしょうか？

# 2023/12/05 朝
Microsoft 365 管理センターにてライセンスが表示されました。
￥25,000/月（年間契約） です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/c81fd0c0-5a76-95ef-bb92-4f78537e81fc.png)

# 2023/12/06

Power Platform License Guid December 2023 が公開されました。
新しい情報として、生成AI（生成型回答）からの応答は、2メッセージを消費するとのことです。


# まとめ

2023/12/4 時点で、

* Copilot Studio の価格は、Power Viwer Agents の特典価格と大差ない価格となりそう。
* 上限として、セッション数：2,000 ⇒ メッセージ数：25,000 となったっぽい。
* Copilot Studio で構築した 会話プラグイン や AIプラグイン を利用する場である、Copilot for M365 の利用は、別途ライセンスが必要となりそう。
* メッセージアドオンライセンスは未発表。



想定内容も含まれますがご参考になれば。
Projectileを繰り返して使う

[Unreal Engine (UE) Advent Calendar 2023](https://qiita.com/advent-calendar/2023/ue)の9日目の記事になります。

## はじめに
アンリアルクエスト5に参加した際に、躓いたことについて書き出したいと思います。
確認環境はUE5.1になります。
間違いなどありましたら、ご指摘いただけると有難いです。

## アンリアルクエストについて
アンリアルクエストは、UE FESTのタイミングで行われるヒストリアさん主催のイベントです。
提示されたクエスト(課題)を毎日クリアしていくと、最終的にゲームが完成しているというイベントです。

https://historia.co.jp/unrealquest05

参加時にアップした動画が以下になります。

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

## 何に躓いたのか
メイン武器である剣を投げるアクションを実装しました。メインの武器なので、一度投げた後に拾って再度投げることが可能な仕様です。ProjectileMovementを使用しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165865/5f99543a-29ac-81fb-86fa-d2dd4c21de34.png)

クエスト4日目「中級：爆弾を作ろう」の派生として、ついでに剣を投げてみたくなったので、こんな感じで剣を投げさせました。

![剣を投げる.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165865/55e5cdb8-a702-b2a8-1307-eb5c9ebc2d5e.gif)

今までは、ショットや投擲物などの使い切りのオブジェクトにProjectileMovementを使っていたので気づかなかったのですが、一度投げたオブジェクトを再度投げようとすると、以下の動画のように飛ばなくなってしまいます。

![拾った剣が飛ばない.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165865/d637f0c0-4e93-5cdf-0575-7e37fbec9874.gif)

## どう対応したのか
こちらの[フォーラム](https://forums.unrealengine.com/t/make-a-projectile-move-again-after-it-comes-to-a-stop/138713/2)をヒントに対応しました。
投げたオブジェクトが止まったタイミングで、ProjectileMovementのリセットを入れています。

![BP_Blade-EventGraph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165865/76b8906d-1a85-61ee-3095-a4b79da83604.png)
リセット内容は以下になります。

![BP_Blade-ResetProjectile.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165865/f30a9949-9100-b316-20d5-40a889160c16.png)

上の対応を入れた後、2度目以降も無事に剣を投げることができるようになりました。

![何度も投げれる.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165865/6d13a9c3-1c82-afbe-ff1e-0de3697e9f43.gif)

期間の短いイベントなので焦りましたが、何とか解決できてよかったです。

## 最後に
イベントに参加することで、普段はやらないことに挑戦し、気付きを得ることができました。

アンリアルクエストは、クエストという形で課題が提示されるので、アイデアを考えるのが苦手な自分にとっては、とても有難いイベントです。また、ゲームをプレイする感覚で楽しんで勉強できることを改めて感じました。
Svelte DevToolsが公式からリリースされたので使ってみる！

# はじめに
Svelte DevToolsがSvelte公式から2023年11月にリリースされました！
今までSvelte DevTools自体は[RedHatter](https://github.com/RedHatter)氏が最初に作成されて利用されていましたが、メンテナンスされなくなってしまって、最新のSvelteやSvelteKitでは動作しないものになってしまっていました。
その後、コードリポジトリをSvelteチームに移管されて、アップデートされました！

# インストール
現在、Svelte DevToolsはGoogle Chromeのみで利用することが可能です。
下記のリンクから拡張機能を追加しましょう。

https://chromewebstore.google.com/detail/kfidecgcdjjfpeckbblhmfkhmlgecoff

# 使い方
インストール後、デベロッパーツールにSvelteのタブが表示されます。このタブには、ページにレンダリングされたSvelteコンポーネント、HTMLxブロック、DOM要素のツリーが表示されます。ツリー内のノードを1つ選択することで、右側のパネルで現在の状態を検査および編集できます。

![スクリーンショット 2023-12-04 22.54.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217487/89a1d608-9c00-25d0-feb8-bd03996d3462.png)

上記の例のように配列内のオブジェクトの状態も見ることができるのでデバッグが容易になります！

当たり前ですが、開発中でしか動作しませんので注意してください。

## 今回使用したテストコード

```svelte
<script>
	let todos = [];

	function remaining(todos) {
		console.log('recalculating');
		return todos.filter(todo => !todo.done).length;
	}

	function addTodo(event) {
		if (event.key !== 'Enter') return;

		todos = [
			...todos,
			{
				done: false,
				text: event.target.value
			}
		];

		event.target.value = '';
	}
</script>

<input on:keydown={addTodo} />

{#each todos as todo}
	<div>
		<input bind:value={todo.text} />
		<input type="checkbox" bind:checked={todo.done} />
	</div>
{/each}

<p>{remaining(todos)} remaining</p>
```

# さいごに
Svelte DevToolsを使ってみましたが、個人的には使いやすいとは言えないかな...。という感想です。
ただ、開発をしている中で、コンポーネントのProps, Events, Stateが見えるのは便利だと思いますので複雑な実装をしていて状態を確認したい場合には便利かと思いました！
YOLOv7で画像にオブジェクトカウンターをつける方法

YOLOv7で画像にオブジェクトカウンターをつける方法をメモしておきます。
T. Nukuiさんの記事を参考にしました。

https://farml1.com/yolov7_objectcounter/

[YOLOv7](https://github.com/WongKinYiu/yolov7)では、物体検出を行うことができます。
従来のコードでは、画像にオブジェクトカウンターをつけることはできません。
そこで、画像にオブジェクトカウンターをつけることができるコードを調べたところ、T. Nukuiさんの記事を見つけました。
T. Nukuiさんの記事ではmuratali016さんのコードが使われており、私もmuratali016さんのコードを使います。

https://github.com/muratali016/Yolov7-Object-Counter-Custom-Funcitons

# 従来のコード
Google Colaboratoryにて実行しました。
ランタイム->ランタイムのタイプを変更->T4 GPUを選択
```Python
from google.colab import drive
drive.mount('/content/drive')
```
```Python
%cd "/content/drive/MyDrive"
!git clone https://github.com/WongKinYiu/yolov7
```
```Python
%cd "/content/drive/MyDrive/yolov7"
!pip install -r requirements.txt
```
バウンディングボックスの色を指定するために[detect.py](https://github.com/WongKinYiu/yolov7/blob/main/detect.py)の62行目に以下のコードを挿入します。
```detect.py
# 62行目
colors[0] = (204, 122, 122)
colors[27] = (255, 102, 102)
```
物体検出（結果はyolov7/runs/detectに保存される）
```Python
%cd "/content/drive/MyDrive/yolov7"
!python detect.py --weights yolov7.pt --conf 0.3 --img-size 640 --source "/content/drive/MyDrive/yolov7/inference/images/zidane.jpg"
```

![zidane.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569835/1e049f98-8157-e5bc-c73e-3d2517b60c6b.jpeg)

この画像が出力されます。
オブジェクトカウンターはついていないことがわかります。

# 画像にオブジェクトカウンターをつける
https://github.com/muratali016/Yolov7-Object-Counter-Custom-Funcitons

[detect_and_count.py](https://github.com/muratali016/Yolov7-Object-Counter-Custom-Funcitons/blob/main/detect_and_count.py)をyolov7ディレクトリに配置します。
バウンディングボックスの色を指定するためにdetect_and_count.pyの79行目に以下のコードを挿入します。
```detect_and_count.py
# 79行目
colors[0] = (204, 122, 122)
colors[27] = (255, 102, 102)
```
そして、以下のコードを実行します。
```Python
%cd "/content/drive/MyDrive/yolov7"
!python detect_and_count.py --weights yolov7.pt --conf 0.3 --img-size 640 --source "/content/drive/MyDrive/yolov7/inference/images/zidane.jpg"
```

![zidane.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569835/6427d70b-7906-e552-67b3-d1785d792bbc.jpeg)


右下に黄色のオブジェクトカウンターがつきました。
カウンターの色を白色に変えるため、[detect_and_count.py](https://github.com/muratali016/Yolov7-Object-Counter-Custom-Funcitons/blob/main/detect_and_count.py)の29行目を以下のように書き換えます。
```detect_and_count.py
# 29行目
cv2.putText(im0, str(a) ,(int(align_right),align_bottom), cv2.FONT_HERSHEY_SIMPLEX, 1,(255,255,255),1,cv2.LINE_AA) # colorを(255,255,255)に変更
```
以下のコードをもう一回実行します。
```Python
%cd "/content/drive/MyDrive/yolov7"
!python detect_and_count.py --weights yolov7.pt --conf 0.3 --img-size 640 --source "/content/drive/MyDrive/yolov7/inference/images/zidane.jpg"
```

![zidane.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569835/26deb13a-420b-2c8a-6688-0978f34127ec.jpeg)

カウンターの色が白色になりました。

muratali016さんのコードにより、画像にオブジェクトカウンターをつけることができました。
また、コードを書き換えることにより、カウンターの色を変えることができました。
YOLOv8で物体検出を行ってみた

YOLOv8で物体検出を行ってみました。
YOLOの最新版であるYOLOv8には日本語のドキュメントもあります。

https://docs.ultralytics.com/ja/

https://github.com/ultralytics/ultralytics

ドキュメントと[Google Colaboratoryのノートブック](https://colab.research.google.com/github/ultralytics/ultralytics/blob/main/examples/tutorial.ipynb)を読みながらYOLOv8を実行してみました。

# 物体検出
Google Colaboratoryにて実行しました。
ランタイム->ランタイムのタイプを変更->T4 GPUを選択
```Python
from google.colab import drive
drive.mount('/content/drive')
```
```Python
!mkdir "/content/drive/MyDrive/yolov8"
```
```Python
%pip install ultralytics
import ultralytics
ultralytics.checks()
```

物体検出（結果はyolov8/runs/detectに保存される）
```Python
%cd "/content/drive/MyDrive/yolov8"
!yolo predict model=yolov8n.pt source='https://ultralytics.com/images/zidane.jpg'
```

![zidane.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569835/3806ea9a-b0f7-f486-2448-bbbc2eace083.jpeg)

この画像が出力されました。

# 学習＆物体検出
次に、COCO128データセットを用いて、事前学習済みモデルの学習を行いました。

学習（結果はyolov8/runs/detectに保存される）
```Python
%cd "/content/drive/MyDrive/yolov8"
!yolo train data=coco128.yaml model=yolov8n.pt epochs=100 imgsz=640
```
学習結果を用いて、もう一度物体検出を行います。
```Python
%cd "/content/drive/MyDrive/yolov8"
!yolo predict model="/content/drive/MyDrive/yolov8/runs/detect/train/weights/best.pt" source='https://ultralytics.com/images/zidane.jpg'
```

![zidane.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569835/69001ecb-5862-139a-01cf-064717b38bd9.jpeg)

この画像が出力されました。
学習前に比べて、スコアが上がったことがわかります。

実際に、車両のスペアパーツ検出、サッカー選手検出、人の転倒検出に応用できるということで、YOLOv8が実用的なツールであることがわかりました。
AWS re:Invent 2023 アップデート速報【AWS Black Belt】の要約

# はじめに
この記事は株式会社ナレッジコミュニケーションが運営する [クラウド AI by ナレコム Advent Calendar 2023](https://qiita.com/advent-calendar/2023/knowcom-cloudai) の4日目にあたる記事になります！

この記事では[AWS re:Invent 2023 アップデート速報【AWS Black Belt】](https://www.youtube.com/watch?v=Mq_I3H3BPQI)を要約しました。

# AWS re:Invent 2023 アップデート速報【AWS Black Belt】

AWSブラックベルトオンラインセミナーリインベント2023アップデート速報の内容をまとめると以下のようになります。

- Amazon Aurora Limitless Databaseの発表：秒間数百万書き込み、ペタバイト規模のデータ量にスケールするデータベース。
- Amazon Elastic Cache Serverlessの発表：インフラを構築せずに可用性の高いキャッシュを作成可能。
- Amazon Redshift Serverless with AI Driven Scaling and Optimizationの発表：AIがワークロードの特性を学習し、リソースを調整。
- Amazon S3 Express One Zoneの発表：データアクセスが高速で高パフォーマンスを必要とするワークロード向けの新しいストレージクラス。
- AWS Graviton for ProcessorとEC2のR8Gインスタンスの発表：新世代のアームベースのプロセッサー。
- AWS Trainium 2とEC2 TRN2インスタンスの発表：機械学習のトレーニング処理向けのアクセラレーター。
- Amazon Bedrockのファインチューニング機能の発表：ラベル付きの小規模なデータセットでモデルをカスタマイズ可能。
- Amazon Bedrockのナレッジベースの発表：生成系AIの正確性を高めるためのラグ拡張検索生成テクニックの組み込み。
- Amazon Bedrockのコンティニュードプリトレーニングの発表：ラベルなしのデータでカスタマイズ可能。
- Agents for Amazon Bedrockの発表：生成系AIのアプリを作成するためのフルマネージドサービス。
- Guardrails for Amazon Bedrockの発表：生成系AIのアプリケーションに問い合わせる内容や応答を評価し、フィルタする機能。
- Amazon Qの発表：エンタープライズグレードのセキュリティとプライバシーが組み込まれた生成系AIのアシスタント。
- Amazon RedshiftのZero ETL機能の拡張：Amazon Aurora PostgreSQL、RDS for MySQL、DynamoDBがRedshiftに対するゼロETLに対応 。
- DynamoDBからオープンサーチサービスに対するゼロETLの発表：トランザクショナルなデータをDynamoDBで処理し、オープンサーチ で全文検索可能。
- AmazonデータゾーンAIレコメンデーションズの発表：データのカタログを社内に展開し、データの利活用を推進するサービス。

その他、多数のサービスアップデートや新機能が発表されています。公式のウェブサイトでの記述と矛盾する場合は公式の記述を優先するとのことです。また、資料は後日共有される予定です。

# まとめ
いかがでしたでしょうか。特に生成AI技術のAmazon Bedrockに関する多くの技術アップデートが発表されました。これらの新機能は、生成AIの進化と発展に大いに貢献するものと期待されており、今後の展開が注目されます。

またナレッジコミュニケーションでは[「Musubite」](https://musubite-job.com/)というエンジニア同士のカジュアルトークサービスを利用しています！この記事にあるような生成 AI 技術を使ったプロジェクトに携わるメンバーと直接話せるサービスですので興味がある方は是非利用を検討してください！

https://recruiting.musubite-job.com/features/company/knowledge-communication

今後もクラウド AI の最新情報を皆さんに届けていきたいと思います。お楽しみに！
オレオレステータスボードを作ってみた

# 前書き
研究室に置いてあった去年のカレンダーとその後ろに付いてあった「外出」「テレワーク」などのステータスボードを発見した僕。そのボードを活用していたが、「テレワークと決めても遠隔で操作できないと意味ないのでは？」と思い始め、Web上で操作できるステータスボードの作成を決意する。これが、この物語の始まりである。

# 使用技術選定
## ステータスボードに使用するハードウェア
### ESP32（却下）
WiFi接続マイコンのド定番であるESP32。最初はこれを採用し、手作り感満載のステータスボードを作ろうとしたが、思いもよらぬ壁をぶつかる。なんと、大学のWiFi認証は単なるパスワード認証ではないため、普通にESP32だけでは接続が困難であることが発覚したのだ。
そのため、電子工作オタクである僕もこの案は諦めることにした。

### Amazon Fire 7（採用）
そうなると次はやはり安物のAndroidタブレットを検討することとなる。WiFi認証も問題なく突破できる上、最近はコスパの良いモデルもたくさん登場している。しかし、ずっとつけっぱなしにしておくので、ある程度検証されたものを使いたいと思った。
その時思いついたのがAmazonのタブレットPCである。いつのタイムセールでとんでもなく安値で叩き売りされるあのタブレットである。しかし、決意した時はセール期間ではなく、やや高値。画面表示器にしては出しづらい価格帯であった。
そのため、メルカリで古めのFire 7を購入し、ステータスボードを作ることに。

## サーバ
### 要件
最低でもこれくらいの機能は実装したかった。
- リアルタイムで画面表示を切り替える
- 複数の状態を設定できる

当たり前の機能だが、「リアルタイム」でとなると多少実装が面倒なことになる。候補に上がったのはWebsocketとFirebaseである。

### 自前Websocketサーバ（却下）
そこまで実装が苦ではないし、リアルタイム性も充足できるため、要件は満たしている。しかし、このようなものを動かそうとすると当然維持コストがかかるわけで、ステータスボードのためにサーバに課金したくはなかったため、ボツとなる。

### Firebase（採用）
大規模になると高くなりがちなFirebaseであるが、個人が使う分には無料枠でも十分すぎるくらいである。維持コストがほとんどかからない上に、データベース（Realtimeの方もFirestoreの方も）のAPIによるリアルタイム更新もできる。多少クセのある書き方が気に入らないところではあるが、サーバに課金したくなかったので今回はFirebaseを採用した。

## Webフロントエンド
なんでもよかったが、当時慣れていたNuxtとVuetifyを採用することにした。動けばなんでもよかったのと、Webフロントエンは自分の主戦場でもないのでここは楽したい。

# 実装
## ボード
言語はKotlinで、今回初めてJetpack Composeを使用することにしてみた。しかし、SwiftUIと似て似つかないものであって、「ほとんど同じものだろ」と安易に思っていたが少し実装中に戸惑ってしまう。思想的には似ているが、コンポーネントの名前や設計がやや異なるので、割と困惑したのである。
画面構成はログイン画面、ボード画面、設定画面の三パターンある。

設定画面: デバイスIDを設定する
![Screenshot_20231204-172338.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487309/b7d311ad-6ab3-dfa0-230b-a8665b91647c.png)

ボード画面: ログアウトボタンと設定ボタンが存在
![Screenshot_20231204-172312.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487309/d5001d66-a62b-e367-a016-7efa8ec42ba8.png)

## サーバ
Firebase Databaseを状態保存及び配信用のストレージにし、認証はGoogle認証にしようとしたが、FireタブはGAppsがデフォルトで入っていない（当たり前ではあるが）。そのため、認証はGithubのOAuth認証にした。パスワード認証にしなかった理由は、単にボード側の実装が面倒だからである。データ構造は、

- users（コレクション）
    - user_id（ドキュメント）
        - deivce_ids（コレクション）
            - device_id（ドキュメント）
                - name: 名前
                - status: 任意の数字

のような構造になっている。なお、認証にはFirebase Authenticationを使用しているため、`user_id`はFirebase Authenticationの`UID`となる。

## Webフロントエンド
NuxtとVuetifyを採用し、割と適当なページ構成にした。ステータスボードの操作画面にコストをかけたくなかったので、バグ多めだが実用上問題ない程度の適当な実装にした。

デバイスリスト:「追加」でデバイスの追加ができる
![スクリーンショット 2023-12-04 172845.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487309/b3a054b6-0c7b-a038-b89c-2cb047396d75.png)

状態変更:「状態」に割り当てられた数字を入れると画面の変更ができる
![スクリーンショット 2023-12-04 172912.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487309/0d57fe84-9424-62d7-2419-27858a7fac30.png)

# 終わりに
## 感想
大したものではないが結構役に立っている。僕は「外出」「テレワーク」「帰宅」「在席」「移動中」のステータスを設定できるようにしている。研究室の他学生もこれでステータス把握できていいらしい。

## 運用中の姿
![IMG_1895.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487309/eb2b0acd-f686-ce18-7091-2a329d248cf2.jpeg)

# ソースコード等
- [ボート側 (Status Screen Android)](https://github.com/Prokuma/Status-Screen-Android)
- [ウェブ側 (Status Screen Manager)](https://github.com/Prokuma/Status-Screen-Manager)
初学者向けGoogleColab上でのJapanese Stable Diffusion XL(JapaneseSDXL) with LCM LoRA 実行環境爆速構築

この投稿はKDDIテクノロジーアドベントカレンダーの7日目の記事となります。

[前回の記事](https://qiita.com/sakamoto1209/items/bbac5a0a9c536fdc7a37)に引き続きGoogleColabo上でLCM LoRAを試します。

# LCM LoRA(Latent Consistency LoRAs)とは？
[SDXL in 4 steps with Latent Consistency LoRAs](https://huggingface.co/blog/lcm_lora)によると
> Latent Consistency Models (LCM) are a way to decrease the number of steps required to generate an image with Stable Diffusion (or SDXL) ~

「Latent Consistency Models（LCM）は、Stable Diffusion（またはSDXL）を使って画像を生成するために必要なステップ数を減らす手法です」とのことです。
今回はこの手法を使って画像生成の高速化を図ります。

# 実行手順
<b>※[前回の記事にある「実行手順」項の④](https://qiita.com/sakamoto1209/items/bbac5a0a9c536fdc7a37#%E5%AE%9F%E8%A1%8C%E6%89%8B%E9%A0%86)まで進めてください。</b>
<br>

⑤下記コマンドを実行し日本語版SDXLをダウンロードする。
```python
model_id = "stabilityai/japanese-stable-diffusion-xl"
lcm_lora_id = "latent-consistency/lcm-lora-sdxl"

pipeline = DiffusionPipeline.from_pretrained(model_id, trust_remote_code=True, variant="fp16")

pipeline.load_lora_weights(lcm_lora_id)
pipeline.scheduler = LCMScheduler.from_config(pipeline.scheduler.config)
pipeline.to(device="cuda", dtype=torch.float16)
```
※HTTPError: 401となり「OSError: Cannot load model stabilityai/japanese-stable-diffusion-xl: model is not cached locally and an error occured while trying to fetch metadata from the Hub. Please check out the root cause in the stacktrace above.」と出た場合はHuggingFace Hubにログイン出来ていないため再度[前回記事](https://qiita.com/sakamoto1209/items/bbac5a0a9c536fdc7a37#%E5%AE%9F%E8%A1%8C%E6%89%8B%E9%A0%86)の④にあるHuggingFace Hubへのログインコマンドを実行すること。
<br>

⑥下記コマンドを実行し画像を出力する。
※promptの部分を出力したい任意の文字列に変更する。
```python
prompt = "水たまり 写真"
image = pipeline(prompt=prompt).images[0]
image
```

# 実行結果
LCM LoRAを使った場合と使っていない場合で比較します。
結果の比較には実行手順⑥に示したコードの代わりに以下のコードを使用しています。

```python
prompt = "水たまり 写真"
images = []
for steps in range(0, 16, 5):
    generator = torch.Generator(device=pipeline.device).manual_seed(2345)
    image = pipeline(
        prompt=prompt,
        num_inference_steps=steps+1,
        guidance_scale=1,
        generator=generator,
    ).images[0]
    images.append(image)
images[15] 
# 数字はStep数を指します。
# 低Step時の挙動が見たい場合はimages[0]、images[5]、images[10]に置き換えて実行してください。
```

### ◎LCM LoRAを使っていない場合
![raw_c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704655/fdf36afa-c7f5-b531-cd0a-66939eadb0ac.png)


### ◎LCM LoRAを使った場合
![lcm_c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704655/b3fa6ede-bc57-d8fd-3d80-f8c3cfa76d44.png)

使っていない場合はそもそも水たまりが生成されないので比較出来ないですが、
使った場合はStep5辺りから鮮明な画像が生成されており高速生成に成功しているであろうことが確認出来ました。


以上です。
Goで並行処理を扱う

#並行処理
アドベントカレンダー4日目は並列処理についてです。[3日目はこちら](https://qiita.com/shuyaeer/items/60ce23324dc1063c4e98)

## Goにおける並行処理
Goは並行処理ととても相性がよく、最大の特徴の一つといってもいいでしょう。

次に並列処理のプログラムとその実行例を見てみます。
プログラムは0から4までの数字を2倍にして表示するというものです。
```go
package main

import (
	"fmt"
	"sync"
	"time"
)

func worker(id int, wg *sync.WaitGroup, results chan<- int) {
	defer wg.Done()

	fmt.Printf("Worker %d starting\n", id)
	time.Sleep(time.Second)
	fmt.Printf("Worker %d done\n", id)

	results <- id * 2
}

func main() {
	const numWorkers = 5
	var wg sync.WaitGroup
	results := make(chan int, numWorkers)
	for i := 0; i < numWorkers; i++ {
		wg.Add(1)
		go worker(i, &wg, results)
	}

	wg.Wait()
	close(results)

	for result := range results {
		fmt.Printf("Result: %d\n", result)
	}
}

```

```bash
$ go run app/day4/main.go
Worker 4 starting
Worker 0 starting
Worker 1 starting
Worker 2 starting
Worker 3 starting
Worker 3 done
Worker 4 done
Worker 0 done
Worker 1 done
Worker 2 done
Result: 6
Result: 8
Result: 0
Result: 2
Result: 4
```

もう一度実行してみます。
```go
 go run app/day4/main.go
Worker 4 starting
Worker 2 starting
Worker 3 starting
Worker 1 starting
Worker 0 starting
Worker 1 done
Worker 0 done
Worker 4 done
Worker 3 done
Worker 2 done
Result: 2
Result: 0
Result: 8
Result: 6
Result: 4
```
1度目の実行と2度目の実行で値が異なっています。
Goにおける並行処理は非同期に行われ、実行順番が保証されないので注意が必要です。

実行時間を計測してみます。
```bash
$ time go run app/day4/main.go
Worker 4 starting
Worker 0 starting
Worker 1 starting
Worker 2 starting
Worker 3 starting
Worker 3 done
Worker 0 done
Worker 4 done
Worker 1 done
Worker 2 done
Result: 6
Result: 0
Result: 8
Result: 2
Result: 4

real	0m1.119s
user	0m0.079s
sys	0m0.095s
```
`time.Sleep(time.Second)`を5度呼んでいるため、逐次処理ならば5秒かかるはずですが、実際は1.1秒ほどしかかかっていません。このように、待ちが発生しているようなプログラムにおいて並行処理はとても有効です。
アクセシビリティ_HTMLページには意味のある`<title>`をつけましょう

# これはなに？

WCAG2.1のアクセシビリティの「操作可能」の中の、「ナビゲーション可能」ガイドラインの「[2.4.2: ページタイトル](https://waic.jp/translations/WCAG21/Understanding/page-titled.html)」についてまとめた記事です。

https://waic.jp/translations/WCAG21/Understanding/page-titled.html

# 対象読者

* HTMLやCSSをコーディングするデザイナーやエンジニア
* SEOの担当者

# HTMLページには空ではない`<title>`を用意する

いわゆる`<head>`タグ内の`<title>`のことを指します。
健康的な方はもちろん、視覚障害の方は音声読み上げでページを確認します。
また、運動障害がある人は音声操作でウェブページを行き来したりすることもあります。

ちなみに`<title>`は`<head>`内に1つしか指定できません。

# 今更聞けない `<title>`の役目

ナビゲーションには、主に二つの機能があります

- 利用者に自分がどこにいるのかを知らせる
- 利用者が他のどこかへ行けるようにする

`<title>`はこの2つの機能を提供しています。
なので、`<title>` がついていないと、利用者は迷子になってしまいます。
必ずHTMLページには意味のある `<title>` をつけましょう。

## `<title>`どこに表示されるの？

- ブラウザのタイトルバーまたはタブバー
- お気に入り（ブックマーク）の登録時のタイトル
- 検索エンジンの検索結果
- SNSなどで共有した時のページのタイトル

## Qiitaでの事例

- qiita.com が提供しているページは共通してお尻に ` - Qiita` が付いています
    - トップページ(https://qiita.com/) は「Qiita」
    - リリースノート(https://qiita.com/release-notes) は「リリースノート - Qiita」
- 記事ページは記事タイトルが`<title>`になり、おしりに ` - Qiita` は付きません

# SEOにおける`<title>`

検索結果において1番目にとまる要素と言って過言ではないのではないでしょうか。
タイトル自体はSEOにとって重要な要素です。
昔はタイトルにキーワードが入っていると検索順位に影響があると言われたこともありますが、今はキーワードの有無は強い影響はないはずです。
私の解釈では、今ではタイトルはCTR（クリックしてもらいやすさ）に影響すると考えています。

良いタイトルをつけることができ、良いコンテンツを提供すれば下記のサイクルが発生すると思います。

1. 検索したキーワードに関連していそうなタイトル
2. クリックされる
3. コンテンツに満足してもらう
4. CVが発生する or ユーザーが満足して検索行動をやめる
5. 有益なページだと評価される

タイトルだけでページの評価は決まりませんが、きっかけになるのは間違いないないのではないでしょうか。
だからこそ、「タイトルは順位に影響する！」と主張しているサイトが世の中にあるんだろうなと思いました。

### タイトルをつけるときのポイント

- わかりやすい
- 文字数はモバイルで36文字、デスクトップで30文字を目安にする
- 重要なキーワードはできるだけ前に入れる
    - 検索エンジンでは長すぎると文字が省略されるため
- ページの内容にズレがない
    - ズレが有ると離脱が発生し、ユーザーに有益なページでないと評価されてしまいます
- サイト名を統一でつける
    - 露出機会アップ
- 他のページと同じタイトルをつけない
    - 重複コンテンツ対策

## `<title>`の内容が検索結果のタイトルと一致しないこともある

ときどき、`<title>`以外のテキストが追加されていることがあります。
例えば、見出しやそのページへのリンクなどが該当します。
検索エンジンの仕様…と言ってしまったら元も子もありませんが、それでも `<title>`の内容が反映されることのほうが多いと思います。

## まとめ

- アクセシビリティとしては、HTMLページには意味のある `<title>` をつけましょう
- SEOの観点ではページに訪問してもらえるように、良いタイトルを考えよう

以上です。

この記事が誰かのお役に立てれば幸いです。
【SwiftUI】SpriteKitでうんこの雨を降らす

# はじめに
SpriteKitを今まで触ったことがなかったので入門してみました。
実用的なのを作っても面白くないのでうんこを降らせてみました。

# サンプルアプリ
![Simulator Screen Recording - iPhone 15 - 2023-12-04 at 22.38.33.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/8e68aa88-e1ae-064c-5d1e-bcbd17d9897c.gif)

# フリーのうんこ
今回はこちらのうんこを使用します。

![unchi_character.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/8c99c430-393b-57f9-37bc-d548cc4e2a40.png)

https://www.irasutoya.com/2015/08/blog-post_385.html

# やりかた
① `SpriteKit`と検索します。
② `SpriteKit Particle File`を選択します。
③ 「Next」を選択します。
![スクリーンショット 2023-12-04 22.16.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/2df127a9-cff0-b948-f683-3a1298f61eec.png)

④ 「Show」を選択します。
⑤　「Next」を選択します。
![スクリーンショット 2023-12-04 22.18.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/c676c5bd-5972-eaa1-4589-fb7a6cd91e4d.png)

⑥ ファイル名を指定します(今回はUnkoParticleにしました)
⑦ 「Create」を選択します。
![スクリーンショット 2023-12-04 22.20.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/a77ae575-76ab-d378-01ff-4a418fb04ac3.png)

⑧ Assetsの中に「Particle Sprite Atlas」というフォルダができていると思うので、そこにうんこを投入します。
![スクリーンショット 2023-12-04 22.29.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/75ab461c-7b6e-f606-c732-5ff434316abe.png)

⑨ 「UnkoParticle」を選択します。
⑩ 「Texture」に`Unko`を指定します。
![スクリーンショット 2023-12-04 22.30.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/17cd29f3-e4e8-a072-ada8-c1546ce4dd8b.png)

⑪ ちょっと大きかったので「Scale」に`0.005`を指定して小さくします。
![スクリーンショット 2023-12-04 22.33.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/505948f7-0f55-93fa-110f-2d66e34912b5.png)

⑪ 実装します
```swift
import SwiftUI
import SpriteKit

struct ContentView: View {
    var body: some View {
        GeometryReader { geometryProxy in
            SpriteView(scene: scene(size: geometryProxy.size))
        }
    }
    
    private func scene(size: CGSize) -> SKScene {
        let emitterNode = SKEmitterNode(fileNamed: "UnkoParticle")!
        let scene = SKScene()
        scene.addChild(emitterNode)
        scene.size = size
        scene.anchorPoint = .init(x: 0.5, y: 1)

        return scene
    }
}
```

# おわり
うんこが降ってきましたね大成功

# 参考記事
https://qiita.com/xiii111/items/cdeefb3c76eb015918ce#2-%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%81%AE%E9%9B%A8%E3%82%92%E6%94%B9%E5%96%84%E3%81%99%E3%82%8B
超小型ゲーム機 Thumby を手持ちのパーツで再現してみた：その②

[前回記事](https://qiita.com/inachi/items/c98ac3c0c77876596c6e)の続きです。

# 回路図調べ

前回記事に書いたとおり、Thumbyの回路図は[ここ](https://github.com/TinyCircuits/ASM4008-TinyCircuits-Thumby/blob/main/design_files/ASM4008-Rev5.pdf)から入手できます。これを元に何をそろえればよいか調べていきます。

![スクリーンショット 2023-12-04 22.12.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/32cd272c-f15a-68ef-a870-2edafe37a789.png)

## 心臓部

心臓部は [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/)そのまま使えそうです。

![スクリーンショット 2023-12-04 22.13.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/02ff42ea-be23-4528-1617-ce324f7acf3f.png)

## 電源管理部

電源管理部分は　Raspberry Pi Pico　のUSBからの電源供給で十分でしょう。

![スクリーンショット 2023-12-04 22.16.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/d67bb268-a4fa-df3a-2b6b-302fc3fda556.png)

## 表示部

表示部はSSD1306のOLEDです。72x40のサイズのものは、日本ではなかなか扱っているところがありませんが、よくある128x64サイズのものが使えます。というのも、SSD1306のものはどのサイズでも内部メモリとしては128x64だけのものが備えられていて、それより小さなサイズのOLEDでは、そのメモリの一部を表示しているからです。

![スクリーンショット 2023-12-04 22.19.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/3b138c2e-fbc7-4497-f352-6b7f7c592567.png)

## ストレージ部

ストレージ用の EEPROM は Raspberry Pi Pico 内蔵のフラッシュメモリで十分です。

![スクリーンショット 2023-12-04 22.23.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/9b12abd5-20ef-8783-bbb7-65b94adab937.png)

## サウンド出力部

圧電スピーカー用に増幅しているっぽいところは、とりあえず無視して、スピーカー直結することにします。

![スクリーンショット 2023-12-04 22.26.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/4199ae78-352b-dd94-1763-5a92d8240563.png)

# 再現に手持ちのパーツから用意したもの

結局、用意したのはこれだけです。

* **長めのブレッドボード**<br>よくあるサイズだとラズピコだけでかなり占有されてしまうため
* **Raspberry Pi Pico**
* **SSD1306 OLED**<br>手持ちのSPI接続 128x64 のもので代用。　後でわかったことですが、API上はI2C接続のものでも使えます
* **タクトスイッチ７個**<br>方向ボタン用４個、A/Bボタン用２個、リセットスイッチ用１個
* **スピーカー**
* **ジャンパーワイヤー**

# 再現してみた！

![スクリーンショット 2023-12-04 22.34.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/363a4a5b-125d-cb73-100d-0e6508e40eab.png)

実物です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/66218a53-2c06-9905-00e9-ad19898062cc.png)

ソフトウェアについては[次回](https://qiita.com/inachi/items/41753d09c500ca15d491)で。
default_scopeが悪ならscopingを使えば良い

Railsの小ネタ。

以下の記事にあるように `default_scope` はバッドプラクティスという風潮があるみたいで、その理由も理解はできる。

https://techracho.bpsinc.jp/hachi8833/2021_11_04/47302

要するに、default_scopeを使うと一部の処理だけdefault_scopeを外したいといった場面が必ず出てくるが、適切に解除してあげないとバグを生み出す。バグの温床なのでdefault_scope使うな。ということらしい。

そうは言ってもアプリケーションのほとんどの処理に同じscopeを適用するのも適用漏れがありそうで、それはそれでバグの温床な気がする。

そんな時にはscopingを使うと良さそう。

## scoping

https://railsdoc.com/page/scoping

default_scopeがモデルの処理全てにscopeが適用されてしまうのに対して、scopingは処理のブロックの範囲にのみscopeが適用される。

これを適切に運用できれば、scopeを解除するといったバグの温床になるようなコードを書かなくても済む。

## コード例

`/a_service/` というprefixのパスと `/b_service/` というprefixのパスのAPIエンドポイントがあり、Postモデルのデフォルトスコープをパスで切り替えたいとする。

その場合以下のように `around_action` でControllerのメソッドをラップしてあげることで、デフォルトスコープを切り替えることができる。

routes.rb
```rb
  namespace :a_service do
    resources 'posts', only: %i(index)
  end

  
  namespace :b_service do
    resources 'posts', only: %i(index)
  end
```

ApplicationController.rb
```rb
class ApplicationController < ActionController::API
  around_action :set_default_scope

  def set_default_scope
    scope = if request.path.start_with?('/a_service/')
              Post.where(service: :a)
            else
              Post.where(service: :b)
            end
    scope.scoping do
      yield
    end
  end
end
```

## 利用場面

１つのアプリケーションとデータベースで複数のサービスを運用したい時。（上記コード例のような）
SQLの置換変数

# 置換変数とは
置換変数を使うと、入力したSQLの一部を、実行前に書き換えることができる。この機能はSQL*Plus及びSQL Developerで使用できる。
置換変数を利用するには、書き換えたい箇所に「＆＜変数名＞」を指定する。

# 対話的に指定する方法
置換変数を含むSQL実行時に置換変数の値の入力を求めるプロンプトが表示されるため、これに入力する。
```sql
SQL> SELECT empno,ename,sal,deptno
  2  FROM employees
  3  WHERE deptno = &deptno;
deptnoに値を入力してください: 10
旧   3: WHERE deptno = &deptno
新   3: WHERE deptno = 10

     EMPNO ENAME                                           SAL     DEPTNO
---------- ---------------------------------------- ---------- ----------
      1001 佐藤                                         500000         10
      1008 中村                                         245000         10
      1014 佐々木                                        230000         10
```


# DEFINEコマンドで指定する方法
DEFINEコマンドで置換後の値をあらかじめ指定することができる。夜間などにSQLスクリプトを自動実行する場合に便利である。
```sql
SQL> DEFINE deptno = 20
SQL> SELECT empno,ename,sal,deptno
  2  FROM employees
  3  WHERE deptno = &deptno;

     EMPNO ENAME             SAL     DEPTNO
---------- ---------- ---------- ----------
      1002 鈴木           200000         20
      1005 渡辺           280000         20
      1009 小林           300000         20
      1011 加藤           110000         20
      1013 山田           280000         20 
```
ステートレスとステートフルの違い

## ステートフルとステートレスについて

- ステートフル（stateful）:状態を維持する仕組み
前回のデータを保存して、データ保存した内容を処理結果に反映される仕組み
    - メリット
    　1. やり取りが完結に済む 
    　2. それによりネットワークの帯域を節約できる
    - デメリット
      1．クライアントの状態を都度把握しておかなければいけないのでクライアントが増えると負荷も増える
      2. サーバを複数台設置する場合にはそれぞれのサーバ間でクライアントの状態を同期しなければいけない
      3. スケールアウトには向かない 

- ステートレス（stateless）：状態を維持しない仕組み
前回のデータを保存しないで、前回のデータを内容に処理結果に反映させない仕組み
    - メリット
    　1. クライアントのリクエストは状態に依存せず、常にリソースに対する操作に必要十分な情報となる
    　2. 処理がクライアントの状態に依らないので処理がシンプル
    　3. サーバが増えてもそのままのリクエストでいつも同じリソースに対する操作ができる
    　4. スケールアウト向き  
    - デメリット
      1．やり取りが冗長
      2. リソース操作が必要な場合に毎度やり取りが必要
      3. サーバが状態を保持していないのでトラブル時のハンドリングが難しい場合がある


[今回の参考URL](https://a1026302.hatenablog.com/entry/2021/02/21/080052)
Javaの商標と大文字小文字

　しばしば話題になるJavaの商標とその大文字小文字について。

## 実際に登録されている商標

　Java™ の商標権は2023年現在、米Oracle社が保有しています。

https://trademarks.justia.com/866/94/java-86694276.html

　歴史的な経緯としては1995年に 米Sun Microsystems がJavaを発表し商標権も取得していたわけですが、経営が傾き、Oracleに買収されました。買収の完了が2010年1月27日とされます。

## 米国の商標における大文字小文字

https://trademark-registration.jp/faq/capital-and-small-letter

> 米国出願では、全て大文字で記載した場合には、小文字や頭文字のみ大文字での使用も商標の使用と認められますが、小文字での権利化の場合、小文字での使用しか商標の使用と認められない場合があります。

　アメリカでの商標の取り扱いとしては上記のような理由で、大文字で商標登録する事情があるようです。

## Javaのロゴ

　Javaは時代によってロゴが何度か変更されてきました。

https://x.com/yoshioterada/status/601040128862068736?s=20

　最初期のJavaのロゴは細いたくさんの線で構成されています。その後のロゴはシンプルな構成となりました。

　Javaには組み込み向けのサブセットのJava ME というものがあって、古い時代に携帯電話などでよく使われた時期があるのですが、その頃に解像度が低くても分かりやすいようにロゴが変わったという、いかにもそれっぽい、しかし典拠不明の噂がまことしやかに囁かれています。

　さておき、ここで注目するべきは最初期のロゴで、日本人には大文字でJAVAと書かれているように見えると思います。しかし、これはJavaと書かれているという話をしておきましょう。

## Trajanフォント

　このフォントですがTrajanフォントであると言われています。このTrajanは 1989年にAdobeのCarol Twombly氏によって作られました。

https://en.wikipedia.org/wiki/Trajan_(typeface)

　この Trajan はイタリアのローマにある[トラヤヌスの記念柱](https://ja.wikipedia.org/wiki/%E3%83%88%E3%83%A9%E3%83%A4%E3%83%8C%E3%82%B9%E3%81%AE%E8%A8%98%E5%BF%B5%E6%9F%B1)を元にデザインしたものとされます。ここで出てくるのがスモールキャピタルないしスモールキャップスと呼ばれる代物です。

## スモールキャップス Small Caps

　小文字のフォントを大文字と同じ形状で小書きにすることがあるようです。これをスモールキャップスなどといいます。

 https://en.wikipedia.org/wiki/Small_caps

 アルファベットの大文字小文字観というのは日本人にはいまいちピンとこない話でありますが

 > The glyphs of lowercase letters can resemble smaller forms of the uppercase glyphs restricted to the baseband (e.g. "C/c" and "S/s", cf. small caps) or can look hardly related (e.g. "D/d" and "G/g")

https://en.wikipedia.org/wiki/Letter_case#Typographical_considerations
 
　小文字は C/c や S/s のように似たものがありますが、その並びに small caps とあるのが分かるでしょうか。対比として形が違うものとして D/d や G/g の例が挙げられていますね。

　そして、先に挙げたTrajanフォントはこのスモールキャップスを採用しているフォントであるため、初期のJavaのロゴは日本人の目にはあたかも大文字でJAVAと書かれているように見えるわけです。

## Oracle はどのように記載しているか

　基本的に Oracle は Javaについては先頭大文字、以後は小文字で記載しています。

　しかし、過去の日本法人のサイトではJAVAと書かれていたようで、やはり日本人には英語の大文字小文字の機微というのは良くわからないものなのでしょう……

 https://forest.watch.impress.co.jp/docs/serial/yajiuma/1411827.html

 とっぴんぱらりのぷう
【Java】jdbctemplateメモ（DataClassRowMapper）

## jdbctemplateでDBのデータを扱う際の型について

現在SoringBootについて学習中ですが、参考書（プロになるためのSpring入門）にて、jdbctemplateの使用方法で便利な機能を見つけたので忘れないようにアウトプットするために下記に殴り書きしていきます。

SpringBootのjdbctemplateにてDBから1レコードを取り出す際に、
今まではqueryForMapを使用してDAOファイルで変換を行っていました。

下記のコードは予約管理システムに使用した予約情報をIDを使用して検索するためのコードです。
引数で予約に紐づくIDを受け取りReserve型をインスタンス化して型ごとにmapを使用して変換していました。

```java
    public Reserve idFind(String id) {
        String sql = "SELECT * FROM reserve WHERE id = ?";
        try {
            Map<String, Object> map = jdbcTemplate.queryForMap(sql, id);
            Reserve reserve = new Reserve(
                    map.get("id").toString(),
                    ((Date) (map.get("date"))).toLocalDate(),
                    ((Time) map.get("time")).toLocalTime(),
                    map.get("menu").toString(),
                    map.get("name").toString(),
                    map.get("email").toString(),
                    map.get("tel").toString());
            return reserve;
        } catch (IncorrectResultSizeDataAccessException e) {
            return null;
        }
    }
```

このコードでもデータを取り出すことは可能ですが、どうしても可読性が悪くなると書いているときから感じていました。
DataClassRowMapperを使用することにより、DBからデータを取り出しする際に自動で変換してくれるのでわざわざ変換するためのコードを書かなくてよい。
<a href="https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/DataClassRowMapper.html#%3Cinit%3E(java.lang.Class)">公式リファレンス（DataClassRowMapper）</a>

これを使用し、書き換えたコードが以下。
```java
    public Reserve idFind(String id) {
        String sql = "SELECT * FROM reserve WHERE id = ?";
        try {
            Reserve reserve = jdbcTemplate.queryForObject(sql,new DataClassRowMapper<>(Reserve.class),id);
            return reserve;
        } catch (IncorrectResultSizeDataAccessException e) {
            return null;
        }
    }
```


正直めちゃめちゃ便利です。。
もっと早く知りたかった（笑）

自分はまだまだ初心者のため、こういった便利な機能を参考書などで仕入れするしか方法がないのですが、ベテランエンジニアの皆さんはどういった方法で学習されているのかが気になります。
ぜひコメント欄で教えて下さい。🙇‍♂️
VSCode×Git VSCodeとGitの連携方法

# はじめに
こんにちは。くりもちです。[Visual Studio Code Advent Calendar 2023](https://qiita.com/advent-calendar/2023/vscode) 4日目の投稿です。今回は、VSCodeとGitを連携する方法を紹介した初心者向けの記事となっております。連携することによって開発効率がぐっと上がると思いますので、ぜひご覧ください。

# VSCodeとGitのインストール・初期設定(できている方は飛ばしてください)
## インストール
まず、VSCodeとGitをインストールしていきます。
[VSCodeのダウンロードページ](https://code.visualstudio.com/Download)からVSCodeのインストーラーを、[Gitのダウンロードページ](https://git-scm.com/downloads)からGitのインストーラーをダウンロードし、インストーラーを実行したらそれぞれ指示に従ってインストールしてください。
## VSCodeの初期設定
インストールした後拡張機能のメニューで「Japanese」と検索し、表示された言語パックをインストールしVSCodeを再起動してください。
## Gitの初期設定
Gitに関しては、Gitが使えるかどうかを確認し、初期設定を行ってください。VSCodeのターミナルで`git --version`を実行し、Gitのバージョン名が表示されたら使えます。
また、以下のコマンドを実行してGitの初期設定を行ってください。
( {username} のところをユーザーネームにしたい名前に、 {email} のところを自分のメールアドレスにしてください)
```PowerShell:Gitの初期設定
git config --global user.name {username}
git config --global user.email {email}
```

# ローカルリポジトリの作成
## ディレクトリの作成
任意の場所にディレクトリを作成してください(このディレクトリがリポジトリとなります)。
## ディレクトリをVSCodeで開く
VSCodeで「ファイル > フォルダーを開く」から先ほど作成したディレクトリを選択し、ディレクトリを開いてください。
## ローカルリポジトリとして初期化
`git init`を実行し、ディレクトリをローカルリポジトリとして初期化します。実行した後、ディレクトリ内に隠しファイルとして`.git`ディレクトリが作成されていることを確認してください。

# ローカルリポジトリにファイル・変更履歴を追加
## ファイルを作成・編集
まず、ファイルを作成したり編集したりしてください。
## ローカルリポジトリにステージング
ソース管理メニューから、ステージングしたい変更履歴の+ボタンをクリックしてステージングしてください。
## ローカルリポジトリにコミット
ステージングされたら、メッセージ欄に変更履歴のコメントを入力し、チェックボタンをクリックしてコミットしてください。
VSCode の左側のアレを出したり消したり出来るようにする方法

VSCode、便利なのですが、左側のバー (Activity Bar) がスペース食ってるのが鬱陶しく感じることもあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7048/57c5e94b-6af1-e905-7651-51a719fcedca.png)

かといって色々便利な機能 (ファイルリスト、検索とかとか…) もあるので、完全に消してしまうのもそれはそれで不便です。

色々設定を試してみて、その辺なんとかするような個人的にしっくり来る設定を見つけたので、今回はそれを紹介しようと思います。

最終的にはこんな感じに、使わない場合は横をめいいっぱい使えるように、使う場合もやや省スペースで使えるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7048/762e9d0e-1d6c-6c55-71db-bcb1c550df8b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7048/c458fc42-cf5f-4e82-48b2-6480decfc36f.png)



## 1. Activity Bar の位置を top にする

[最近の VSCode の update](https://code.visualstudio.com/updates/v1_84#_customize-activity-bar-position) で Activity Bar の場所を変えられるようになりました。まずはこれを使ってみます。

Activity Bar 上で右クリックをして、 「Activity Bar Position」 → 「Top」を選択します。

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7048/f5a7a4e2-3947-e8d8-cc28-a7343989b2e1.png)

すると、 Activity Bar の位置が Primary Side Bar (ファイル一覧とか検索とか出るところ) の上部に移動して、一体化したような表示になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7048/be54f674-d713-5cda-54f4-f31b0486e380.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7048/1dcd8560-d673-1856-6119-e2afd655bb6e.png)
(アカウントや設定のボタンはウィンドウ右上に移動します)

Activity Bar が上部に移動したことで横幅が少し空いたのですが、この状態だと **Activity Bar のボタンをクリックしても Primary Side Bar を消せなくなる** ので、別の方法で Primary Side Bar を消せるようにします。

## 2. Primary Side Bar を消せるようにする

### タイトルバー右側のボタン or ショートカットキー (Ctrl+B or Cmd+B) で出したり消したり出来る

Primary Side Bar の切り替え方として、タイトルバー右側にある ↓ のボタンがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7048/4e823390-dd92-5c08-724c-0c35b1360d48.png)

押すと、以下のように Primary Side Bar と (それの上部にある) Activity Bar をセットで出したり消したり出来るようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7048/762e9d0e-1d6c-6c55-71db-bcb1c550df8b.png)

これにはショートカットキー (Win, Linux だと Ctrl+B, Mac だと Command+B) が割り当てられているので、それを押すことで切り替えすることも出来ます。 

### Activitus Bar を使って左下に切り替えボタンを配置する

切り替えボタンが右側にあるとやや遠く不便なので、左下にもボタンを配置できるようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7048/e0e98d2a-b6ab-9a5b-a229-2d4dc4adfc1b.png)

ここでは [Activitus Bar](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.activitusbar) という、Status Bar (ウィンドウ下側にあるバーのことです) 上で Activity Bar のボタンを表示できるようにする拡張機能を使います。

インストールすると↓のようなボタンが追加されて Activity Bar のボタンと同じように使えます。これらを擬似的に切り替えボタンとして使えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7048/f50e651d-8700-6e78-0d45-3a92ccd8f520.png)

デフォルトだとボタンの数が多いので、自分は以下の設定を書いてボタンの数を削っています。 (表示の切り替えに使いたいだけなので1つだけ)

```json
{
  "activitusbar.views": [
    {
      "name": "explorer",
      "codicon": "layout-sidebar-left"
    }
  ]
}
```
autoInputで常に時間をメモしてチェック

自動入力
```
Dim WshShell
Set WshShell = CreateObject("WScript.Shell")

Dim i
Dim ans

ans = msgbox("実行を開始します。キー入力されるので注意してください" & vbLf & "VDI側でも監視プロセスを動かしてください" & vbLf & "VPNの有効時間に注意してください", vbOkCancel)
WScript.Sleep 5000

Do Until ans = vbCancel
	If WshShell.AppActivate("個別VDI") Then 
		WshShell.AppActivate "個別VDI"
		WScript.Sleep 1000
		WshShell.SendKeys Now() & " | "
		WshShell.SendKeys "^s"
	Else
		WshShell.Run "rundll32 user32.dll, MessageBeep", 0, False
	End If
	ans = WshShell.PopUp("再度実行しますか？", 60, "自動キー入力", vbRetryCancel)
Loop
```

自動チェック
```
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

MsgBox, , , vdi_access_check.txtの更新時刻を確認します。
URL := "通知エンドポイント"
HttpObj := ComObjCreate("WinHttp.WinHttpRequest.5.1")

HttpObj.Open("POST", URL, 0)
HttpObj.SetRequestHeader("Content-Type", "application/json")

Loop{
    WinActivate, ahk_exe Hidemaru.exe
    FileGetTime, lastUpdateTime, 対象ファイル
    timeDiff := lastUpdateTime
    EnvSub, timeDiff, %A_Now%, seconds 
    ; 5分以上変化が無かった場合
    If (timeDiff < -300) {
        json_str := "入力無し"
        Body := json_str
        ; MsgBox %Body%
        HttpObj.Send(Body)
        ; 5分待つ
        sleep 300000
    }
    ; 5秒ごとに確認
    sleep 5000
}
```
google formで申請してもらった情報をもとにCHに招待する

# はじめに
会社に部活の仕組みが創設されました。
そこの部に入ってもらうとき、どういうふうに入ってもらうか〜みたいなWFが全く決まってなかったので、

「よっしゃ、じゃあうちの部活は、google formで申請してもらうぞ！」
と決めました。

ただし、お金が発生したりする兼ね合いで、会社の表計算シートに色々と記述せねばなりません。
大変面倒です。

よし、色々自動化しよう！！
っていう、キッカケで、情報をやり取りしたりするCHに招待したい、そんな話です。

# google formを用意する
必須事項は以下

- 名前

これだけで大丈夫です！
一番大事なのは、次の設定です。

![スクリーンショット 2023-12-04 22.00.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1026740/ae093580-1421-e19f-bae3-6009989314d0.png)

メールアドレスを収集するようにしましょう。

# 準備は整った、手順を説明する
1. google formから申請してもらう
1. 任意のSlackCHに招待する（招待するのはBot)
1. トリガーを設定する

botはすでに作ってある前提とします。（作り方については割愛）

## Slackの招待

招待するソースコードです。確かどっか、良い記事があって使わせていただいた記憶・・。
記載ミスあったらごめんね。

```javascript
// slack apiを投げる〜
function callWebApi(token, apiMethod, payload) {
  const response = UrlFetchApp.fetch(
    `https://www.slack.com/api/${apiMethod}`,
    {
      method: "post",
      contentType: "application/x-www-form-urlencoded",
      headers: { "Authorization": `Bearer ${token}` },
      payload: payload,
    }
  );
  //console.log(`Web API (${apiMethod}) response: ${response}`)
  return response;
}

// メンバーを招待します
function inviteMember(channel, id) {
  try {
      const apiResponse = callWebApi(bot_token, "conversations.invite", {
                channel : channel,
                users : id,
                      });

    var json = JSON.parse(apiResponse.getContentText());
    if (json["ok"] == false) {
      Logger.log(json["error"]);
    }
  
    Logger.log("channel : " + channel + " id : " + id);

  }
  catch (e) {
    Logger.log("error:" + e.essage);
  }
}

// emailアドレスからuserIdを取得します
function getUserId(email) {
  const apiResponse = callWebApi(bot_token, "users.lookupByEmail", {
    email : email,
  });

  var json = JSON.parse(apiResponse.getContentText());
  var values = json["user"];
  var id = values["id"];
  var name = values["name"];
  Logger.log("id :" + id + " name : " + name);
  return id;
}

// google formを送るとここに来ます
function submitForm(e) {
  var email = e.response.getRespondentEmail(); // 投稿者に紐づいているmailアドレスを取ってくる
  var id = getUserId(email);
  inviteMember("CHのID", id);
}
```
基本的には、
**emailアドレスから、userIDを割り出し、そのuserIDを対象CHに招待する** 、これだけです。

## slack botの権限
必要なのは以下。
- [conversations.invite](https://api.slack.com/methods/conversations.invite)
    - channels:manage
- [users.lookupByEmail](https://api.slack.com/methods/users.lookupByEmail)
    - users:read.email
    - users.profile:read（コレも必要だったかも）

だったかな・・。ちょっと前に書いたコードなので、間違ってたらごめんね。

最後に、`招待するべきCHに利用するbotを追加して`終了です。

## おっと忘れてました、トリガー設定しましょう
GAS側のトリガー設定する必要があります。
GASを手動で叩くんじゃなくて、google form申請時に動くようにしたいからですね。

![スクリーンショット 2023-03-29 18.34.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1026740/f996a5fe-06bb-2288-af39-495773e49102.png)

実行する関数と、イベントを設定してOKです。

# はまりどころ
ハマりどころを一応共有しておきます。
ハマりどころはなんといっても、GASのダイアログ連投問題です。

GAS様が、
「ねえ、権限ないよ！許可してよ！」
「google formからの連絡くるよ！許可してよ！」

みたいにやたらと権限を要求してくるんですけど、これをちゃんとOKしないとGASが権限ないぜ、って動かないこと多々あります。
エラーがわかりにくいのがハマりどころですかね。

# まとめ
CH招待自動化したので、DMやり取りとか発生せずに、とっても楽です。
入社者とか、組織変更時に勝手にCH追加や、削除されると便利だと思いますね。
手作業、駆逐してやる！！（誰）
なぜ海水魚飼育は難しいのか

## はじめに

[デフエンジニアの会 アドベントカレンダー 2023](https://qiita.com/advent-calendar/2023/deafengineers)の第3日の記事です。

昔に海水魚飼育を始めたのだが、どうもうまくいかない。金魚は何年も飼えるのに、海水魚はなぜか数週間の命で終わってしまうのだった。

そこで大枚をはたいてオーバーフロー式大型水槽に切り替えて、クーラー、ヒーターだけでなく大きなろ過槽も接続して臨んだところ、混泳する魚の相性が悪くない限り、何年も飼育できるようになりました。

![我が家の水槽](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33023/d3fcab45-43ca-5de7-74f3-0ce16673ce2e.png)

淡水よりも海水のほうが頻繁に水換えなどをして水質を良い状態に保つ工夫が必要なわけですが、その理屈がずっと解らないままでした。

## 発表資料との出会い

飼育を初めてかなり経った後に、ようやく海洋生物環境研究所に掲載されていた記事「[マダイの卵及び仔稚魚のアンモニア耐性](https://www.kaiseiken.or.jp/publish/leaflets/lib/leaf10.pdf?fbclid=IwAR2cBsf0LvGWPDJwE4jZCCJhgSpEKCYEHiLowxMcvKBT1WcoV_PX5vtaZYM) 」を発掘しました。そこにこんな数式が紹介されていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33023/756847f0-5513-a87c-33aa-6e0da78382c2.png)

平たく言うと、生物の糞尿などで放出されたアンモニアは、水中ではイオン化されたアンモニア($NH_4^{+}$）とイオン化されていないアンモニア（$NH_3$）が平衡状態で混在するのですが、$HN_3$の割合をこんな数式で計算できますよと。

## Pythonでグラフを描いてみる

というわけで、前述の数式をPythonを使ってグラフを描くコードを書いてみました。

```Python
import numpy as np
import matplotlib.pyplot as plt

# 非イオン化アンモニアのアンモニウムイオンに対する割合（%）を求める関数
def cal_NH3_Percentage(T, pH):
    n = 9.35 + 0.0324 * (298-T) - pH
    return 100 / (1 + (10 ** n))

# 6～10の間を50個の等間隔で分割したpHを求める（定義域）
pH = np.linspace(6, 10, 50)

# 25℃をKに変換
T  = 25 + 273.15

# グラフで描画
plt.xlabel('pH')
plt.ylabel('NH3(%)')
plt.grid(True)
plt.plot(pH, cal_NH3_Percentage(T, pH))
plt.show()

# 数値で出力
print('pH=7.0: NH3 {0:.5f} %'.format(cal_NH3_Percentage(T, 7.0)))
print('pH=8.5: NH3 {0:.5f} %'.format(cal_NH3_Percentage(T, 8.5)))
```

そのコードで描画したグラフが次のとおりです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33023/8b1fcfc5-3c28-e6d7-9ad2-61b742ee7e32.png)
**図1. 非イオン化アンモニアのアンモニウムイオンに対する割合**

## グラフからわかったこと

淡水はpH 7くらいで、海水はpH 8.5くらいです。グラフを見ると、pH 7付近では$NH_3$はほぼゼロであるのに対し、pH 8.5付近だと12%を超えることがわかります。

実はイオン化されていないアンモニア$NH_3$は毒性が非常に強く生体に大きなダメージを与えるわけですから、海水魚飼育の難しさがここで腑に落ちるように分かります。

海水水槽はpHが高いため、淡水水槽に比べてアンモニアをいかにして抑制できるかが肝要だというわけです。

生物の話なのかITの話なのかわからないような記事になってしまいましたが、ご海容をば…