OmniAICreator/Qiita-1.07M huggingface dataset:
交通費検索RPAの落とし穴

# はじめに
みなさん初めまして。
普段あちこちでBizRobo!を用いてRPAの開発をしております。
今回は実際に私自身が経験したことを基にお話させていただきます。

# 初めの第一歩でよく使用されるお題
RPAを始めれば必ず誰しもが通ってきたのが、
この交通費検索のRPAではないでしょうか。
よくお題として挙がるのは、Excelに記入された交通費データ（出発駅、到着駅）を
交通費検索サイトで検索して、最安値運賃を取得し、
サイトから取得した運賃をExcelに記入するというものではないでしょうか。
たしかに、RPAの初めの第一歩としてすごく重要な項目がたくさん盛り込まれています。
 <font color="Blue">**文字入力、Webデータ抽出、クリック操作、Excel操作**</font>

今までRPAや、そもそも開発業務自体に触れてこなかった人も、
交通費検索は１度くらいは行ったことがあると思います。
すごく理解しやすい点やイメージを掴みやすい点を踏まえるとすごくいいお題だな～と。

:::note alert
しかし！一番初めに扱うものだといえど、
実際の業務でこのRPAを開発するとなると、
開発者はもちろん、ユーザーにとっても悩ませる項目があります
:::

# 項目①　～パターン①～
### <font color="red">**駅名の重複**</font>
駅名は全国に必ず１つで、駅名が重複しないとは限りません。
考慮しないといけない点は、
<font color="blue">**検索候補にたくさんの駅名が出てくるという点です。**</font>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/3760aaea-b269-1f55-6c16-b0802fe5688f.png)


>画像引用：https://transit.yahoo.co.jp/?from=%E6%A0%84&to=&fromgid=&togid=&flatlon=&tlatlon=&via=&viacode=&y=2024&m=03&d=15&hh=14&m1=2&m2=7&type=1&ticket=ic&expkind=1&userpass=1&ws=3&s=0&al=1&shin=1&ex=1&hb=1&lb=1&sr=1

例えば上記のように全国各地に駅名がある場合、
「どうやって絞るの？」という懸念点が出てきます。

<font color="blue">**RPAで検索を行う都道府県が固定されていて、
複数候補ある場合は、特定の県名を選択すると問題ないです**</font>が、
「全国各地の」となった場合どうする？という懸念点があります。

# 項目①　～パターン②～
実はこんなパターンもあるんです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/ed3a9f98-912f-f592-0cea-62a56f773f6b.png)

>画像引用：https://transit.yahoo.co.jp/?from=%E5%A4%A7%E9%98%AA%E6%A2%85%E7%94%B0&to=&fromgid=&togid=&flatlon=&tlatlon=&via=&viacode=&y=2024&m=03&d=15&hh=14&m1=2&m2=7&type=1&ticket=ic&expkind=1&userpass=1&ws=3&s=0&al=1&shin=1&ex=1&hb=1&lb=1&sr=1

<font color="red">**同じ駅名が違う路線である場合です。**</font>
こういった場合は、どちらの路線を選択するの？という懸念点が出てきます。

他にも駅名を検索したいが検索候補に、
<font color="blue">**検索しようとしていた駅名と同じバス停などが表示される場合もあります。**</font>

なので、RPA化する前にしっかりと開発者とユーザーが会話を行い、
上記のような懸念点をしっかり潰せるように、
お互いが認識を合わせたうえで開発するべき内容であると思います。

# 項目②
### <font color="red">**交通手段の制限**</font>

こちらの件に関しては、例えば電車で通勤できる範囲内であるのにも関わらず、
新幹線や飛行機が自動的に選択される場合です。

データによっては、全国範囲で検索を行うこともあるかと思います。
新幹線や飛行機等を使う人もいれば、使わない人もいらっしゃると思います。
新幹線等を使用しない人が、新幹線等を使った経路で検索されるというパターンも実際に存在します。

このような場合に、どのように交通手段に関して制限をかけるかが重要になると思います。

# 悩ませる内容　その①の解決例
交通費検索を行ううえで、駅名の重複は避けて通れない内容です。
なので、事前に内容を精査する必要があります。

あくまで例ですが、<font color="red">**最初から駅名が１つに絞れるように設定しておくこと**</font>が１番良いかと思います。
ユーザー側にとっては<font color="blue">**「データ整備」の負担があります**</font>が、RPAのメリットを考えれば
工数削減にはうってつけとなる内容かと思います。

::: note warn
各交通費検索サイトによって、表示のされ方が違います
予め対象の交通費検索サイトの表示を確認しておくことをオススメします。
:::

# 悩ませる内容　その②の解決例
新幹線や飛行機を含む・含まないで検索するという内容には、
<font color="red">**検索設定を変更してからRPAを稼働させるイメージ**</font>で進めると良いと思います。

各交通費検索サイトには、詳細設定で検索する交通手段を選択できるようになっています。
<font color="blue">**不必要な交通手段は検索できないように、予め選択から省くことをオススメします！**</font>
そうすることで、不必要な交通手段が検索できないようになっています。

またデータに関して全国を範囲とする場合、新幹線や飛行機を含む場合があると思います。
その場合は<font color="blue">**予め新幹線や飛行機を含むものは「別のデータ」として扱って処理をすること**</font>で、
RPAが非常に大活躍すると思います。

:::note alert
もしデータを別のシステム等から落として処理させる場合、
そのデータ（駅名や路線名）が最新であることを確認してください。
古いデータの場合は、駅名や路線名が変更になっていて、
検索を行っても表示されない場合があります。
その点は皆さまご注意ください。
:::
# 最後に
最後までご覧いただきありがとうございました。
少しでも参考にしていただければ幸いです。
[Google Calendar API(V3)] Javaでカレンダーのイベント変更を監視する

Google Calendar API V3(Java)を使用して、
Googleカレンダーのイベント変更を監視する方法
についてご紹介します。

:::note info
APIを利用する環境の準備から始める場合や、コードを実行する際は、
[⧉[Google Calendar API(V3)] JavaでCalendar APIを使う](https://qiita.com/doran/items/c735c7b05c0a2ed4bfdb)
を参照ください。
:::

|No||目次|
|---|---|---|
|1||[イベントの変更を監視](#1-イベントの変更を監視)|
||1|[スコープ](#11-スコープ)|
||2|[実行](#12-実行)|
||3|[レスポンスの内容](#13-レスポンスの内容)|
|2||[イベントの監視を停止](#2-イベントの監視を停止)|
|3||[変更通知を受信](#3-変更通知を受信)|

## 1. イベントの変更を監視
Googleカレンダーのイベントの変更を監視します。

### 1.1. スコープ
このAPIを実行するには、以下のいずれかのスコープを指定してください。
```
CalendarScopes.CALENDAR_READONLY
CalendarScopes.CALENDAR
CalendarScopes.CALENDAR_EVENTS_READONLY
CalendarScopes.CALENDAR_EVENTS
```
[⧉[Google Calendar API(V3)] JavaでCalendar APIを使う(2.2 Calendarインスタンスを取得)](https://qiita.com/doran/items/c735c7b05c0a2ed4bfdb#22-calendarインスタンスを取得)
でスコープを指定してください。

### 1.2. 実行

```java
public static void main(String[] args) throws Exception{
    Calendar calendar = getCalendar();
    Calendar.Events events = calendar.events();
    
    Channel content = new Channel();
    content.setId("チャンネルを識別するUUID");
    content.setType("web_hook");
    content.setAddress("変更通知が配信されるURL");
    Calendar.Events.Watch watch = events.watch("カレンダーID", content);
    
    Channel res = watch.execute();
    System.out.println(res);
}
```
#### 1.2.1. HTTPリクエスト
POST:　https:\//www.googleapis.com/calendar/v3/calendars/{カレンダーID}/events/watch
が実行されます。

#### 1.2.2. クエリパラメータ
Calendar.Events.Watchのsetメソッドにより、クエリパラメータを追加できます。

|メソッド|引数|説明|
|---|---|---|
|setEventTypes|String|[監視するリソースのイベントタイプ](#イベントタイプ)|

#### イベントタイプ
|定義値|内容|
|---|---|
|default|定期的なイベント|
|focusTime|サイレント モードの予定|
|outOfOffice|不在の予定|
|workingLocation|勤務場所の予定|

#### 1.2.3. リクエストボディ
Channelのsetメソッドにより、クエリパラメータを追加できます。

|メソッド|引数|説明|
|---|---|---|
|setId|String|【必須】チャンネルを識別するUUID|	
|setAddress|String|【必須】変更通知が配信されるURL|
|setType|String|【必須】このチャンネルで使用される配信方法の種類<br>"web_hook"（または"webhook"）のみ|
|setToken|String|このチャンネル経由で通知と一緒に対象のアドレスに配布される任意の文字列|	
|setParams|Map\<String,String\>|配信チャンネルの操作を制御する追加のパラメータ|	
|setExpiration|Long|通知チャンネルの有効期間（秒）|

### 1.3. レスポンスの内容

#### Channel

|メソッド|戻り値|説明|
|---|---|---|
|getKind|String|リソースの種類<br>固定文字列："api#channel"|
|getId|String|このチャンネルを識別するUUID|	
|getResourceId|String|このチャンネルで監視するリソースを識別するID|
|getResourceUri|String|監視対象のリソースのバージョン固有のID|	
|getToken|String|このチャンネル経由で通知と一緒に対象のアドレスに配布される任意の文字列|
|getExpiration|long|通知チャンネルの有効期限|

## 2. イベントの監視を停止
Googleカレンダーのイベントの監視を停止します。

変更通知の停止は、
[⧉[Google Calendar API(V3)] Javaで変更通知を停止する](https://qiita.com/doran/items/3c3ad1d6406d8fac634e)
の記事を参照ください。

## 3. 変更通知を受信
カレンダーのイベントの変更があった場合、登録したURLへPOSTされます。
HTTPヘッダーの「x-goog」から始まるヘッダーの内容で確認できます。

|ヘッダ|内容|例|
|---|---|---|
|x-goog-channel-expiration|通知チャネルの有効期限|Tue, 02 Apr 2024 03:29:03 GMT|
|x-goog-channel-id|チャンネルを識別するUUID|test|
|x-goog-message-number|通知チャネルのこのメッセージを識別する整数|33666|
|x-goog-resource-id|チャンネルで監視するリソースを識別するID|uJ4NMuP6FGdkXqK0OPjligffaUc|
|x-goog-resource-state|通知をトリガーした新しいリソースの状態<br>sync,exists,not_exists|exists|
|x-goog-resource-uri|監視対象リソースの API バージョン固有の識別子|`https://www.googleapis.com/calendar/v3/calendars/xxxxxxxx/events?alt=json`|

<br>
<br>
おしまい。。
Google スプレッドシートのアドオンでClaudeを呼び出す

# はじめに

タイトルの通りGoogle SpreadSheetの拡張機能を使用して、Claudeを呼び出す方法について説明します。
（APIを使用する事でGASでも構築可能ですが、本記事では使用しません。）

以下のページを参考にしています。

https://docs.anthropic.com/claude/docs/google-sheets-add-on

# 準備

前提：スプレッドシート、Claudeが使える状態であること。

Claudeの会員登録がまだの方は以下より登録お願いします。（無料版で問題ありません）

https://claude.ai/

# APIキーの作成

会員登録が終わりましたら、こちらからAPIキーを作成してください。
初回の会員登録時に無料クレジット5$が付与されるので、ある程度は無料で使用できます。

https://console.anthropic.com/settings/keys

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/6d058d94-0430-ef5a-d571-8a4016e3d3b8.png)

# アドオンを取得する

スプレッドシートを新規作成して、アドオンを取得します。
アドオン名：`Claude for Sheets`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/7a32b780-3b17-198d-c84a-0233f2cb62dd.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/f10a5713-7964-621c-8105-52fecde50dff.png)



# APIキーを設定する

スプレッドシードの`拡張機能`に`Claude for Sheets`が追加されたので、
APIキーを設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/ffcd2a67-88dc-abdf-5491-0e26e7698ba7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/e14b2095-f048-e74a-58e9-d9153196fe85.png)

これで準備完了です。

# 使い方



セルに`=Claude(`と入力すると、Claudeを呼び出すメソッドが使えるようになっていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/e55e7e34-5513-1126-1363-943362edba15.png)

## 例１：プロンプトのみ入力する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/2e0c877e-504f-fb56-0c0e-a3d9b235e51c.png)


## 例２：別のセルを参照する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/66285ca0-33ed-f9dd-f40c-9e548abcd4b4.png)

## 例３：モデルを指定して呼び出す

opusが最上位のモデルです。その分、API呼び出しコストも高いのでご注意ください。

`=Claude("お疲れ様です。","claude-3-opus-20240229")`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/174f1fc7-e0fe-c305-47ef-b067c0c4b755.png)

低コストかつ高速なモデル`Haiku`を使う例
※末尾の日付が`0307`です。
`=Claude("お疲れ様です。","claude-3-haiku-20240307")`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/5cfcc1b1-7357-2c91-5b6e-01690733b026.png)


モデルを指定しなかった場合は`claude-3-sonnet-20240229`が呼び出されているようでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/74813e99-573c-b211-ed3e-0875b29d0e5f.png)

どのモデルが呼び出されたかは`Usage Logs`より確認できます。

https://console.anthropic.com/settings/logs

また、APIの残クレジットは`Plans & Billing`より確認できます。

https://console.anthropic.com/settings/plans

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/03cf08c3-209a-f5e5-54f6-94ed71a0a1bd.png)

おわり

# プログラムからClaudeを使用する

Blazor C# でClaude APIを使う方法について、まとめております。
参考になれば幸いです。

https://qiita.com/firesign2023/items/702407263cdfff117e05

https://qiita.com/firesign2023/items/fd539a7eb3a07dce2847
ITまっさら状態から基本情報技術者試験を１か月半で合格した話

## どういった経緯で受けることになったのか

私の個人的な話になってしまうのですが、つい最近いろいろな縁などがありIT企業に転職をしました。そして転職するや否やIT未経験ということもあり資格をとろうという話になりました。そこでITの登竜門といわれる「基本情報技術者」を取ろうと決意しました。

## エンジニアを目指しているのに必要なのか？

基本情報ってエンジニアには必要ないだったり、評価されずらいなどエンジニア目線からするとマイナスな意見が多かったりもします。
しかしIT未経験且つ情報系の学校に通っていたわけでもない自分は言葉や熱意以外のアピールがないとだめだと感じ、今回資格取得に挑みました。

## 勉強法

まず勉強するにあたって参考にさせていただいた方がいます。
「やるかやられるかチャンネル」さんです。

この方々の基本情報技術者試験の対策動画をみて勉強を進めました。
わかりやすいうえに面白いので自動的にみたくなるような方々です。
本当に助かりました。ありがとうございます。

![download.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691258/2f397059-4bf2-ecec-c24c-710605e34e07.jpeg)

具体的な勉強法は

①初めの2週間

科目A対策としてまずは問題集を1周、そこからはひたすら過去問（過去問道場）
はじめは正解率30～40%でした（正直心折れかけました笑）
けどとにかく科目Aは量をやりつつ、間違えた問題を問題集読みながら理解する。これを繰り返していました。

![download.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691258/208abca1-368f-7dbc-1852-846a69e01d71.jpeg)　　　　　![OIP.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691258/6fe5b174-c17a-3d1f-92c2-f828fda158a6.jpeg)

②3，4週目

[使った教材]

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691258/83f3570e-a83b-f6b8-5b0d-07c6cbf5a02d.png)

3週目に入ってからは科目B対策をメインに取り組みました。
ただここで自分がやっていて注意しないとなとおもったポイントがあります。

「科目Bは時間が取れるときのみやったほうがいい」　ということです。

以前までは科目Aを通勤の行き帰りやお風呂の時間など隙間時間にやったりしていて
科目Bも同じやり方でやっていたのですが過去問やサンプル問題をやってもなかなか解けませんでした。

そこで時間の取れる土日に上記の教材を使いながら量より質にこだわって取り組んでいきました。
特にこの教材に出てくるトレースが本番でもかなり役に立ちました。

③試験１週間、１０日前

試験１０日前あたりから科目Aは過去問道場、科目Bはサンプル問題＋YouTubeにある問題形式のものを解きました。

[お世話になったYouTube]

エンジニア養成コーチ：IT学校さいとうさん

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691258/b3cf4ce9-417b-a080-7369-14d5d6de7cec.png)

時間がある時は科目Aは９０分、科目Bは100分で行い、とにかく最後は本番に近い形で問題を解いていきました。

その結果とてもギリギリですが、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691258/6f597be7-142f-5b89-9947-b5943d781112.png)

合格することができました。

自分がIT未経験かつ文系の文系だったのでとても苦戦しましたが、とにかく計画的にやり続ければできることが自分自身に対してできるということを証明できましたし、これからの可能性を広げることができました。

これからも市場価値を高めるために資格やプログラミング学習を続けていきます！
投稿頻度の目標も達成する。
RDS ProxyをやめてRDS Data APIに切り替えた

## はじめに

RDS Proxyとは

https://aws.amazon.com/jp/rds/proxy/

RDS Data APIとは

https://docs.aws.amazon.com/ja_jp/rdsdataservice/latest/APIReference/Welcome.html

Lambda×RDS（Aurora含む）の場合、RDS Proxyを間に挟むのはごく一般的な構成かと思います。

私も以前はLambdaからRDSアクセスがあるなら必須だよな〜と思っていたのですが、あるシステムでRDSにAuroraServerlessV2を採用した際、従来通りRDS Proxyも作成したら料金が跳ね上がってびっくりしました。

AuroraServerlessV2の場合のRDS Proxyの料金は、1時間1ACUあたり`0.025USD`で課金されます。

https://aws.amazon.com/jp/rds/proxy/pricing/

ただこの料金体系、よく見ると最低料金が8ACUとなっており、要は使用しているのが1ACUだけであっても、8ACU使ったものとして料金が計算されてしまうのです。
該当のシステムはサービスインする前のPoC段階だったので、ACUは`0.5`に設定していたのですが、8ACU分の料金が発生していました。

高いな〜RDS Proxy必要なのかな〜と悶々していたところ、AWSの方と話す機会があり、2023年12月にリリースされたばかりのAuroraServerlessV2に対応したRDS Data APIを教えてもらいました。

https://dev.classmethod.jp/articles/rds-data-api-now-supported-in-serverless-v2-and-provisioned-amazon-aurora-postgresql/

2024年4月現在、リージョンや使えるDBエンジンが限定されているものの、該当のシステム構成的に利用可能だったので、料金削減のため切り替えることにしました。

## どう変わったか

### 料金

RDS Data APIはHTTPでAPIをコールすることでAuroraにアクセスします。
料金はリクエスト数に応じて課金され、最初の10億件のリクエストは100万回あたり`0.42USD`、10 億件を超えた場合は`0.24USD`です。

該当システムは現状月10万件のリクエストに収まっていたので、請求は`0USD`でした。
RDS Proxyの場合はProxyだけで大体毎月`150USD`ほどかかっていたので激安ですね。

厳密にはData APIを使用するのにSecret Managerが必要になるので、その分の料金は発生しますが、月`1USD`もかからないのでほぼ無視できます。

RDS Proxyの場合はRDS関連だけで月`225.60USD`かかっていたのが、`75.18USD`まで削減できました。やったね！！

### 構成

副次的な効果で構成も単純にすることができました。

このシステムはLambdaからインターネットにアクセスする必要があり、VPC外Lambda→VPC内Lambdaをコールするという構成を取っていました。
RDSにLambdaからアクセスするにはLambdaをRDSと同じVPCのサブネットに入れる必要がありますが、その場合 NAT Gatewayをおかないとインターネットにアクセスできません。
このNAT Gatwayも結構高額なサービスで、コスト削減のためこんな構成にしていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1649149/192527f4-0e78-2af1-2129-6e6f9192c3aa.png)

Data APIを有効にすると内部で専用のエンドポイントが作られ、そこから通信をするので、LambdaをVPC内に入れる必要がなくなります。

こうなりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1649149/62da59d0-2f7b-e0e0-abb6-7c9d2d3473fb.png)

Lambda→Lambdaの構成が複雑だったので、すっきりしました。

## おわりに

RDS ProxyとData APIどちらが良いかは当然システム要件によって変わると思います。
そもそも同時アクセス数が多くないシステムはProxyなしでLambda→RDS直接続でも問題ないです。
Lambda×RDSだからRDS Proxy必須！ではなく、Data APIの利用も検討できるな、という話でした。

Data APIに切り替えたことでLambdaのコードも大幅に書き換えたので、それについては別途記事にします。

**→2024.12.23 記事にしました。**

https://qiita.com/hirooka622/items/6ad82808b52cde291661
MER(誤差率の中央値)を求める(SPSS Modeler データ加工逆引き8-17)

# MER(誤差率の中央値)を求める

![スクリーンショット 2024-04-01 17.10.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/48571070-3713-b4e7-c274-b19c34da5e2d.png)

## 1.想定される利用目的

・時系列予測モデルの性能評価
・数値予測モデルの性能評価

*平均ではなく中央値を利用することで外れ値の影響を受けにくいメリットがあります。

## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/raw/main/mer.str

## 3.サンプルストリームの説明

![スクリーンショット 2024-04-01 17.26.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/a5440f6a-e988-bc33-d807-c1d1ec0cb969.png)

a.入力するデータは以下の通りです。日毎の来場者の実績と予測のフィールドの３列です。

![スクリーンショット 2022-09-23 10.54.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/e0cb5587-6a05-305a-4156-61c834af1bd4.png)

b.[フィールド作成]ノードを編集します。誤差の絶対値を求めています。

![スクリーンショット 2024-04-01 17.17.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/12601606-ea95-85ec-6a56-53db53166ffd.png)

[プレビュー]します。

![スクリーンショット 2024-04-01 17.17.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/414e78d6-009b-b981-8658-0ddf9f209d9f.png)

c.[レコード集計]ノードを編集します。

![スクリーンショット 2024-04-01 17.18.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/dba6e9aa-4505-8263-ed76-92589542d04a.png)

[プレビュー]します。MERが表示されました。

![スクリーンショット 2024-04-01 17.19.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/5e64ceb2-3090-dbf0-29d9-7ce1181c2daf.png)

#### 注意事項

中央値を求める処理はSQL自動生成に対応していないため、大規模データの場合処理に時間がかかります。その際はソートやサンプリングを利用して別の出力方法を検討します。

逆引き8-16の絶対値を絶対誤差率にすることで規模の異なる複数系列の精度比較がしやすくなりました。

## 4.参考情報

#### RMSEを取り上げている記事

https://qiita.com/416nishimaki/items/24ae7ab2e3513cff282a

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/private/4bf813e6cba84b2a1008
HTAPのベンチマーク: Web3 Bench

# はじめに

先日、PingCAPブログにてHTAPワークロードのベンチマーク、Web3 Benchについてのブログが掲載されました。

https://www.pingcap.com/blog/web3bench-new-htap-benchmark-web3-workloads/

従来のデータベースのベンチマークは、TPC-CやTPC-H/YBCSのように、OLTPまたはOLAPいずれかのワークロードのベンチマークだったのですが、このベンチマークは両方のワークロードが同時に発生するHTAPワークロードを実施して計測している点が異なるとされています。

このようなワークロードが顕著に観測されるのがWeb3（と書いてありますが、ブロックチェーンデータのリアルタイム分析）です。ブロックの生成に応じたOLTPワークロードと、過去データも含めたOLAPワークロードの両方が発生します。本ベンチマークでは架空のEthereumデータをベースにしています。

発表内容と下記のリポジトリから、実際にどのようなベンチマークなのか中身を見ていきます。

https://github.com/cococo2000/Web3Bench/tree/master

## データモデル

データモデルはすごくシンプルで、4つのテーブルしかありません。

![データモデル](https://static.pingcap.com/files/2024/03/29132936/Screenshot-2024-03-29-at-4.29.15%E2%80%AFPM.png)

BigQueryの[Ethereum ETL](https://ethereum-etl.readthedocs.io/en/latest/)のスキーマをシンプルにしたもののようです。

https://github.com/blockchain-etl/ethereum-etl


## 検索ワークロード

検索については次の4種類のクエリカテゴリが定義されています。
* T(0.1秒以内)
* O(1秒以内)
* O(10秒以内)
* A(制限なし)

クエリ例を少し見ていきます。まず始めにTクエリ
```sql
SELECT to_address, from_address
FROM transactions
WHERE hash = ?
```
これはハッシュ値からトランザクション、誰と誰の取引だったかを探すものです。Etherscan(https://etherscan.io/) で Txn Hashで検索することに該当するものと思われます。

次に
```sql
-- R22
SELECT count(*)
FROM token_transfer
WHERE token_address = ?
```
あるアドレスのトークン取引件数をカウントするものです。こちらもEtherscanでも検索できます。

Aクエリを見てみます。
```sql
-- R34
SELECT sum(value) as totalamount, 
       count(value) as transactioncount,
       from_address as fromaddress
FROM transactions
GROUP BY from_address
ORDER BY sum(value) DESC
LIMIT 10
```
取引額の大きい送信元アドレスTop10です。

## 更新ワークロード

更新ワークロードは単一のINSERTだけではなく、バッチINSERTやJOIN UPDATEも行っています。
```sql
-- W2
INSERT INTO transactions VALUES 
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?), 
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),
...
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) /* 99回繰り返し */
```

```sql
-- W52
UPDATE token_transfers
SET value = value + 1
WHERE from_address IN (
  SELECT to_address 
  FROM token_transfers
)
```

## まとめ

ざっとみた感じでは、シンプルなデータモデル、かつ大量のレコードに対する、性能要求の異なるクエリの実施パフォーマンスを見るベンチマークとなっています。検索はどれも基本的なものですが、レコード数が多くなるとそれなりに時間がかかるものを選んでいるようです。

実際にTiDBやMySQLに対して動かしてみたら別途ブログに書いていこうかなと思います。
ディレクトリ以下の一括パーミッション変更コマンド

一括でファイル、ディレクトリのパーミッションを変更するコマンドです。
ファイルとディレクトリのパーミッションを分ける際に使用します。

```
# 現在のディレクトリ以下のファイルのみを [664] に変更
find . -type f -print | xargs chmod 664
# 現在のディレクトリ以下のディレクトリのみを [755] に変更
find . -type d -print | xargs chmod 775
```
g++とgccの導入でこけた話

ものすごいシンプルなコード

```test.cpp

#include <iostream>

using namespace std;

int main(){

  int a,c = 0;
  if(a==1)
  {
    c = 1;
  }
  else
  {
    c =2;
  }
  std::cout << "Hello world." << std::endl;
  
  return 0;
}

```

gccでビルド
```

hoge@hoge:~/lab/unit_test$ gcc -o test test.cpp
/usr/bin/ld: /tmp/ccrc3xcA.o: warning: relocation against `_ZSt4cout' in read-only section `.text'
/usr/bin/ld: /tmp/ccrc3xcA.o: in function `main':
test.cpp:(.text+0x36): undefined reference to `std::cout'

```

g++でビルド
```

hoge@hoge:~/lab/unit_test$ g++ -o test test.cpp
->OK

```

gccは標準ライブラリをリンクしてくれないという教訓。
Dev Container + poetryで簡単環境構築

## 概要

### Dev Containerとは

VScodeの拡張機能。定義ファイルを準備するだけで開発環境がまるっと全部揃ったコンテナにアタッチできる。

### 何が嬉しい？

- 作業者間でOSからエディタの設定まで環境を共有できる
- 定義ファイルさえ用意すれば一瞬で開発環境が整う
    - pyenvとかpoetryとかいちいちインストール不要
    - VScodeの拡張機能もぽちぽち入れなくて良い

### 使い方

Dockerはインストールされてるとする。

1. `.devcontainer/devcontainer.json`に開発コンテナの設定を書く
2. コマンドパレットから`Reopen in Container`を選ぶと開発コンテナが立ち上がりアタッチされる

## 使用例

以下の環境を用意する例。

- Python3.12
- poetry
- VScode拡張機能もろもろ

### リポジトリ構成

```
.
├── .devcontainer
│   ├── devcontainer.json
│   └── post-attach.sh
├── pyproject.toml
└── poetry.lock
```

### devcontainer.json

開発コンテナの設計図。書き方の詳細は以下のドキュメント参照。

https://containers.dev/implementors/json_reference/

ここでは最小限以下の項目を設定。

- `image`：ベースとするイメージ
- `features`：コンテナにトッピングしたい機能
    - ここでpoetryを入れる
- `extentions`：インストールしたいVScodeの拡張機能
- `postAttachCommand`：開発コンテナにアタッチしたタイミングで実行するコマンド
    - ここで用意したシェルスクリプト`post-attach.sh`を実行

```json
{
    "image": "mcr.microsoft.com/devcontainers/python:3.12-bullseye",
    "features": {
        "ghcr.io/devcontainers-contrib/features/poetry:2": {}
    },
    "customizations": {
        "vscode": {
            "extensions": [
                "ms-python.python",
                "ms-toolsai.jupyter",
                "ms-python.mypy-type-checker",
                "ms-azuretools.vscode-docker",
                "charliermarsh.ruff",
                "mhutchie.git-graph",
                "gruntfuggly.todo-tree",
                "formulahendry.code-runner"
            ]
        }
    },
    "postAttachCommand": ".devcontainer/post-attach.sh"
}
```

:::note info
必要に応じてDockerfileやdocker-compose.ymlを用意することで、コンテナの振る舞いをさらにカスタマイズすることもできる。
:::

</aside>

### post-attach.sh

コンテナにアタッチされたタイミングで依存関係のインストールを行う。post-attach.shはコンテナ内で実行されるように実行権限を付けておく。

```bash
#!/bin/bash

poetry config virtualenvs.in-project true
poetry install --no-root
```

:::note info
[こちらのissue](https://github.com/python-poetry/poetry/issues/1214)でも指摘されているように、poetryはユーザー権限でグローバルな環境にインストールする機能をサポートしておらず、`virtualenvs.create`を`false`とすると権限エラーとなる。環境が二重化しており若干気持ち悪いが、今回はコンテナ内にpoetryの仮想環境を作る。
:::

### コンテナへのアタッチ

VScodeのワークスペースがリポジトリのルートにある状態で`Ctrl + Shift + P`でコマンドパレットを開いて`Reopen in Container`を選択すると、devcontainer.jsonで設定した内容にしたがってカスタマイズされた開発コンテナが立ち上がり、アタッチされる。

リポジトリのルート以下は自動的にコンテナにバインドマウントされるため、コンテナ内の作業はホストマシン側にも反映される。

## Tips

### rootユーザーで作業しない

- コンテナに`root`で入ると作成したファイルの所有者が`root`となり、開発コンテナの外で通常ユーザーとして作業する際にファイルを編集できなくなってしまう
- Microsoftが提供しているDev Container用のイメージを使うと自動的に`vscode`というユーザーで入れるので便利

https://github.com/devcontainers/images/blob/main/src/python/history/1.1.7.md

### Gitの認証情報を設定する

https://code.visualstudio.com/remote/advancedcontainers/sharing-git-credentials

- Gitのユーザー情報はホストマシン側で設定すると、自動的に開発コンテナ内で共有される

```bash
git config --global user.name "Your Name"
git config --global user.email "your.email@address"
```

- 認証情報は、秘密鍵をホストマシン側のSSH Agentに読み込ませることで、開発コンテナ上にも反映される
    - 間違っても`~/.ssh`をコンテナにマウントしない

```bash
ssh-add ~/.ssh/<your-private-key>
```

## 参考

https://zenn.dev/streamwest1629/articles/vscode_wanderer-in-devcontainer

https://zenn.dev/naas/articles/dev-container-python-best-practice

https://future-architect.github.io/articles/20231212a/
メソッドの定義

### メソッドの定義
```
public static void メゾット名() {
 メゾットが呼び出された時の処理
 }
```

### メソッドの呼び出し
```
メソッド名()
```


```
例）
public class Main {
 public static void main(String[] args) {
  System.out.pirntln("メソッドを呼び出します");
  hello();
  System.out.println("メソッドの呼び出しが終わりました");
 } 
 public static void hello() {
  System.out.println("こんにちは");
 }
}
```
` hello();` メソッドを呼び出し
`public static void hello() {
  System.out.println("こんにちは");
 }` helloメソッドの本体

 メソッドを利用するには必ず呼び出す必要がある！
【Raspberry Pi】Nexmon環境構築手順

# 【Raspberry Pi】Nexmon環境構築手順
ここでは，Raspberry Pi 3/4Bに**Nexmon**をインストールし，実際にCSIを取得するまでの一連の流れを説明します．

:::note info
**Nexmon**
Cypress/Bloadcom製のWI-Fiチップ向けに開発された，オープンソースCSI収集用ファームウェアパッチです．
:::

## 参考にしたサイト

https://github.com/seemoo-lab/nexmon

https://github.com/nexmonster/nexmon_csi/tree/pi-5.10.92

## Raspberry Piの初期設定
### イメージファイルの書き込み
- バージョン　　：Bullseye
- アーキテクチャ：armhf(ARM hard float)
- タイプ　　　　：Lite版
- リリース日　　：2022年1月28日
- ダウンロードURL：
https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2022-01-28/2022-01-28-raspios-bullseye-armhf-lite.zip

## Nexmonのインストール
- Nexmon_csiのバイナリファイルから**インストールスクリプトを実行**（2分程度）
```
// （推奨）一度，再起動を行い，明示的に，キャッシュのフラッシュ，マウント状態やパーティション情報を更新する
$ sudo reboot

$ sudo curl -fsSL curl -fsSL https://raw.githubusercontent.com/nexmonster/nexmon_csi_bin/main/install.sh | sudo bash
$ sudo reboot
```

## CSI収集テスト
### 通信環境の確認
- **Wi-Fiアナライザ**などを使用して，観測したい無線通信チャネルと帯域幅を確認する

https://apps.microsoft.com/detail/9NBLGGH33N0N?hl=ja-JP&gl=JP

- mcpコマンドで，base64でエンコードされたパラメータ文字列を作成する

```
$ sudo mcp -C 1 -N 1 -c {チャネル}/{帯域幅}
```

:::note warn
ここで**生成された文字列をコピー**しておくことを推奨
:::

```
// mcpで指定できるオプションは-hで一覧表示可能
$ sudo mcp -h
```

### CSI収集開始
- パラメータ文字列を設定し，**モニターモードインターフェース(mon0)を追加**する

```
$ sudo ifconfig wlan0 up
$ sudo nexutil -Iwlan0 -s500 -b -l34 -v{mcpで生成した文字列}
$ sudo iw dev wlan0 interface add mon0 type monitor
$ sudo ip link set mon0 up
```

- **tcpdumpコマンドでCSIの収集を開始**する

```
//基本的な実行コマンド
$ sudo tcpdump -i wlan0 dst port 5500

//書き込みファイルの指定
$ sudo tcpdump -i wlan0 dst port 5500 -vv -w {任意のファイル名}.pcap

//指定パケット数だけ書き込みファイルに出力
$ tcpdump -i wlan0 dst port 5500 -vv -w {任意のファイル名}.pcap -c {観測したいパケット数}

//例：1000パケットに達するまで観測し，output.pcapファイルとして出力する
$ sudo tcpdump -i wlan0 dst port 5500 -vv -w output.pcap -c 1000
```

:::note info
mcpコマンドで更にオプションを追加することで特定MACアドレスでフィルタリングすることも可能です．
:::

```
// MACアドレスでフィルタリングするオプション（-m）の使用方法
$ sudo mcp -C 1 -N 1 -c {チャネル}/{帯域幅} -m XX:XX:XX:XX:XX:XX
```

- 以降は，mon0インターフェースを追加する部分からコマンドを打ち込みなおす
2025 年 3 月での files.upload API 廃止と移行方法について

こんにちは、Slack の[公式 SDK 開発](https://github.com/slackapi)と日本の Developer Relations を担当している瀬良 (@seratch) と申します 👋

この記事では、本日発表された [files.upload API](https://api.slack.com/methods/files.upload) の deprecation (非推奨) と移行方法について日本語で解説します。アナウンスメント（英語）は、以下のページでご確認いただけます。

https://api.slack.com/changelog/2024-04-a-better-way-to-upload-files-is-here-to-stay

## files.upload API 廃止までの流れ

[files.upload API](https://api.slack.com/methods/files.upload) は、2025 年春に廃止されます。それまでのスケジュールは以下の通りです。

1. 2024 年 5 月 8 日以降、新しく作成された Slack アプリは files.upload API にアクセスできなくなります。すでに存在している既存のアプリは廃止日（3. 参照）までは API を使用することができます。
2. 2024 年 6 月〜 2025 年 2 月の間、files.upload API を利用しているアプリの開発者、そのアプリを管理する Slack ワークスペースの管理者にリマインダーメールを送信します。
3. **2025 年 3 月 11 日**に files.upload API は廃止されます。以降は呼び出すことができません。

## 移行方法

移行先のファイルアップロード方法は、Slack のクライアントアプリとほぼ同様な方式になります。詳細については、公式 SDK の紹介の後に解説します。

公式の Node.js、Python、Java SDK を利用している場合は files.upload V2 というメソッドがすでに提供されており、こちらに移行することで同じアプリの機能を維持することができます。

### JavaScript/TypeScript (Node.js)

`@slack/web-api` の `WebClient#files.upload()` から `WebClient#files.uploadV2()` (内部の処理は同じなので `WebClient#filesUploadV2()` でも OK です) に移行します。詳しくは以下を参考にしてください。

https://slack.dev/node-slack-sdk/web-api#upload-a-file

### Python

`slack_sdk.WebClient#files_upload()` から `WebClient#files_upload_v2()` に移行します。詳しくは以下を参考にしてください。

https://slack.dev/python-slack-sdk/web/index.html#files

### Java/Kotlin

`com.slack.api.methods.MethodsClient#filesUpload()` から `MethodsClient#filesUploadV2()` に移行します。詳しくは以下を参考にしてください。

https://javadoc.io/doc/com.slack.api/slack-api-client/latest/com/slack/api/methods/MethodsClient.html#filesUploadV2(com.slack.api.methods.request.files.FilesUploadV2Request)

### 直接 API を利用する場合

上記のランタイム・言語でない場合は、v2 メソッドが内部でやっていることと同じ処理を実装する必要があります。処理は三つのステップに分かれます。

1. [files.getUploadURLExternal API](https://api.slack.com/methods/files.getUploadURLExternal) を呼び出してファイルアップロードに使用する `https://files.slack.com/upload/v1/...` URL とファイル ID を取得する
1. `https://files.slack.com/upload/v1/...` URL に POST リクエストを送信してファイルをアップロードする
1. [files.completeUploadExternal API](https://api.slack.com/methods/files.completeUploadExternal) にファイル ID に加えて チャンネル ID などを送信して、アップロード処理を完了させる

これまでとの違いとしては files.completeUploadExternal API を呼び出して応答が返ってきても、Slack のサーバー側ではまだファイルのセキュリティスキャンなどの処理が続いており、**チャンネル内でのファイル共有は非同期で行われる**という点です。これは、files.upload API が抱えていた巨大なファイルに対するパフォーマンス問題を解決するためのトレードオフとして挙動が変更されたものです。何卒ご理解いただければと思います。

ファイルのアップロード完了をトリガーに後続の処理を行いたい場合、以下の二つの対応方法があります。

1. [files.info API](https://api.slack.com/methods/files.info) を一定間隔でポーリングして、ファイルのメタデータが更新されるまで待つ
1. イベント API の [file_shared イベント](https://api.slack.com/events/file_shared) を使って処理を継続する

## 新しい方式で変更された点

公式 SDK の v2 メソッドを使うと呼び出すメソッドを変えるだけでほぼそのまま動作するはずですが、いくつか挙動の変更点がありますので、まとめておきます。

1. **一つのメッセージで複数のファイルを一括アップロードできるようになりました**
1. ファイルを共有する先を指定するパラメーターが channels -> channel_id に変更され、複数のチャンネルの指定やチャンネル名での指定はできなくなりました
1. 上記の通り、アップロード処理の完了は非同期になったので、同期的な後続処理がある場合は files.info API のポーリングまたはイベント API での連携が必要です

## 終わりに

先日の [RTM API の件](https://qiita.com/seratch/items/736c2e33c69ac722dae7)に続いて、お手数をおかけいたしますが、何卒よろしくお願いいたします 🙇
EC2 インスタンスタイプの変更

ec2のインスタンス変更する機会が時々あり、忘れないように忘備録



#### 1.インスタンスの停止

ec2の画面にアクセスに変更したいインスタンスを選択します

選択したら「インスタンスの状態」 > 「インスタンスの停止」でインスタンスを停止します

![スクリーンショット 2024-04-09 17.38.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276326/01635540-43af-396e-d675-dc2d98e5904d.png)

停止済みになる待ち待ちます

#### 2.インスタンスの変更

「アクション」 > 「インスタンスの設定」 > 「インスタンスタイプの変更」から変更を行います

![スクリーンショット 2024-04-09 17.41.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276326/38af56d7-af27-f5dc-0723-0146a24d5947.png)

画面の画面で、「新しいインスタンスタイプ」が選択できます

現在のインスタンスと比較し、適用で変更完了です

![スクリーンショット 2024-04-09 17.41.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276326/11203ea0-d92f-faae-0269-3c497243a3ad.png)

一覧に戻り希望のインスタンスになっているか確認ください

#### 3.インスタンスの起動

停止と逆の手順で、対象インスタンスを選択したら
「インスタンスの状態」 > 「インスタンスの開始」でインスタンスを開始します


#### 終わり

手順はこれだけでインスタンス停止すること以外は、お手軽に変更できます

ec2のインスタンスはスペックがいいものにあげた後、元のインスタンスに戻すことができるので、

一時的にメモリで試したい時など使えます
JUnit5のasserThrowsを使おう

# JUnit5のasserThrows
kotlinでサーバサイドアプリ開発していますが、今までJUnitでテスト対象の関数が例外をthrowするような場合、こんな風に書いていました。
また、JUnit4でも、このような書き方になると思います。
```kotlin
try {
    hogehogeFunc()
    fail("例外がthrowされませんでした")
} catch (e: Exception) {
    when (e) {
        // assert
        is MyException -> assertThat(e.message).isEqualTo("エラーメッセージ")
        else -> {
            e.printStackTrace()
            fail("throwされた例外が異なります")
        }
    }
}
```

JUnit5のドキュメントを見ていたら、assertThrowsなるものがあるのを発見！
これだと
```kotlin
val err = assertThrows<MyException> { hogehogeFunc() }
assertThat(err.message).isEqualTo("エラーメッセージ")
```
たったこれだけです。
期待通りの例外がthrowsされればテストは成功します。

期待したのと違う例外がthrowsされた場合は
```
予想:class foo.IOException
実際:class java.lang.IllegalArgumentException
IO Errororg.opentest4j.AssertionFailedError: Unexpected exception type thrown, expected: <foo.MyException> but was: <java.lang.IllegalArgumentException>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:67)
	at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:35)
	at org.junit.jupiter.api.Assertions.assertThrows(Assertions.java:3115)

```
となります。

期待した例外がthrowsされなかった場合は
```
Expected foo.MyException to be thrown, but nothing was thrown.
org.opentest4j.AssertionFailedError: Expected foo.MyException to be thrown, but nothing was thrown.
```
となります。

随分、簡潔に書けますね。これからはこの書き方で書こうと思います。
DBeaverからAmazon RDS for Db2にアクセスする

当記事はOSSのDB Tool [DBeaver](https://dbeaver.io/)からAmazon RDS for Db2に接続する方法について説明します。
この検証はMac版で行っています。

基本 AWSの公式ドキュメント「[DBeaver を使用して RDS for Db2 DB インスタンスに接続する](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/db2-connecting-with-dbeaver.html)」と「ほぼ」同じですが、画面が日本語になっているもので説明しています。

DBeaver バージョン24.0.2で検証しています。

# 1. 接続情報の準備

DB接続用の
- userid
- password
- ホスト名(エンドポイント)
- ポート番号
- データベース名

を準備してください。

ホスト名、ポート番号、データベース名の取得方法が不明の場合はこちらの[Amazon RDS for Db2: AWSでフルマネージドDb2 データベースを作ってみた!: 3.1 事前準備: 接続情報の取得](https://qiita.com/nishikyon/items/13ecab95e2bf296531f1#31-%E4%BA%8B%E5%89%8D%E6%BA%96%E5%82%99-%E6%8E%A5%E7%B6%9A%E6%83%85%E5%A0%B1%E3%81%AE%E5%8F%96%E5%BE%97)を参考に取得お願いします。

# 2.　DBeaverを開き、接続を作成

### 2-1.上部メニューから「データベース」→「新しい接続」を開く
### 2-2.　DB2 LUWのアイコンをクリックし、「次へ」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/8d5714f3-6ef0-2732-ca99-425bdaa8deed.png)


### 2-3. DB2 LUW接続設定を入力
まずは、「接続の詳細」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/64dc7540-a1e9-9669-a7c3-06bb93879ab9.png)


接続名にわかりやすい名前を入れ,「戻る」をクリック
(そのままでもOKですが、たくさん作成するとわからなくなるのでわかりやすい名前にした方がよいです)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/8d9d67a3-4f0c-95e3-0598-26f1a2bbc07f.png)

次に [1. 接続情報の準備](#1-接続情報の準備)で取得した接続情報を入力します。
#### [一般]タブ
- Host: ホスト名(エンドポイント)
- Port: ポート番号
- Database: データベース名
- ユーザー名: userid
- パスワード: password
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/24a9ddbc-fbdf-bce1-023b-ce823312e184.png)




#### [ドライバのプロパティ]タブ
左下の＋印をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/ecda409a-4511-7dd2-2676-a819159726fe.png)

プロパティ名に`encryptionAlgorithm`と入力、OKをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/778c8b98-daf8-6ea1-7188-2d01e4798295.png)


`encryptionAlgorithm`をクリックして、`2`を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/65de9b59-8e1b-fe45-22de-cb822ffbd5c8.png)

再度左下の＋印をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/da200924-136b-c0af-dbd9-f870eccdf5cd.png)


プロパティ名に`securityMechanism`と入力、OKをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/6ad0bde7-8bb5-1807-3c11-5213e43d273a.png)



`securityMechanism`をクリックして、`7`を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/52d7ca4d-4974-2105-e28c-5dd17fe2c4b7.png)



最後に「テスト接続」をクリックして設定を確認します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/3d459d99-7e30-310f-6eac-7b93d30c8681.png)


接続が確認できました! 「OK」をクリックしてダイアログを閉じます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/031c9d5c-0e0e-9385-c190-d27b3eabcc2a.png)


右下の「終了」をクリックしてください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/79d30b20-d128-88f5-7211-d590415818ba.png)


無事データベースナビゲータに表示されました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/61c43af7-8a29-b26e-3b56-c8ab28c72b46.png)

以上です。
Spotifyをcrontabからxdotoolで制御

朝のアラーム用にspotifyを使いたかったので、crontabから再生・停止を制御できるようにしたメモ
xdotoolを使って制御する
spotifyは起動してある前提

xdotool search --name spotifyだと見えないウィンドウしか取得できなかったのでPIDからWindowを取得している

spotifyのホットキーがPlay/Stopのトグルキーなので、スクリプトを実行したときに再生されていれば止まるし、止まっていれば再生される

DISPLAY変数は環境に合わせて変更する
自分の環境ではGUIを切ってXRDP経由でSpotifyを起動している

以下スクリプト
```bash
#!/bin/bash
export DISPLAY=:10
pid=`ps -ef | grep /snap/spotify/75/usr/share/spotify/spotify | head -1 | awk '{print $2}'`
window_id=`xdotool search --onlyvisible --pid $pid`
xdotool windowactivate $window_id
xdotool key space
```
【Next.js】サーバコンポーネントとクライアントコンポーネントについてよくわからなかったのでまとめた

# はじめに

こんにちは、エンジニアのkeitaMaxです。

サーバコンポーネントとクライアントコンポーネントについてよく理解していないで困ったことがあったので、調べたことについてまとめます。

# サーバコンポーネントとクライアントコンポーネントについて

Next.js 13.2でサーバコンポーネントとクライアントコンポーネントの概念が追加されたようです。

PHPとJavascriptで開発をするときに例えると、

サーバコンポーネントはPHPのようなサーバー側の処理、クライアントコンポーネンはJavascriptのようなブラウザ側の処理、というようなイメージらしいです。

## サーバコンポーネント

>React Server Components を使用すると、サーバー上でレンダリングしたり、オプションでキャッシュしたりできる UI を作成できます。 Next.js では、レンダリング作業がルート セグメントごとにさらに分割され、ストリーミングと部分レンダリングが可能になり、次の 3 つの異なるサーバー レンダリング戦略があります。
(引用：https://nextjs.org/docs/app/building-your-application/rendering/server-components)

### メリット

サーバコンポーネントを使用するメリットとしては、公式では７つ紹介されていました。

- **データ フェッチ**
データフェッチをサーバ側で行うことにより、フェッチにかかる時間とリクエスト数が減少し、パフォーマンスが向上するらしいです。

- **セキュリティ**
トークンや API キーなどのロジックをクライアントに見られる心配がなくなります。

- **キャッシュ**
サーバー上でレンダリングすることで、結果をキャッシュして後続のリクエストなどで再利用することができるので、パフォーマンスが向上し、コストが削減されるそうです。

- **パフォーマンス**
ブラウザでダウンロード・解析・実行するクライアント側のJavaScript が少なくなるため、ネットが遅いユーザーやデバイスを使用しているユーザーにとって、パフォーマンスが向上するらしいです。

- **最初のページ読み込みと最初のコンテンツフル ペイント (FCP)**
サーバ上でHTMLを生成しているので、Javascriptのダウンロードや解析を待たずにユーザがすぐにページを開くことができます。

- **検索エンジンの最適化とソーシャル ネットワークの共有性**
サーバ側でHTMLを生成しているので、SSOが向上するらしいです。

- **ストリーミング**
準備ができたらクライアントに随時送信することができる(ストリーミング)ので、サーバ上でページ全体がレンダリングするのを待たずにページの一部をより早く表示できるらしいです。

### サーバレンダリング戦略

また、公式には3つのサーバレンダリング戦略があると記載されていたので、それぞれ見ていこうと思います。

#### 静的レンダリング
>静的レンダリングを使用すると、ルートはビルド時、またはデータの再検証後にバックグラウンドでレンダリングされます
(引用：https://nextjs.org/docs/app/building-your-application/rendering/server-components#static-rendering-default)

ビルドするときにレンダリングします。

ユーザが変わっても同じ情報を出すときに使用するらしいです。

#### ダイナミックレンダリング

>ダイナミック レンダリングを使用すると、リクエスト時にルートがユーザーごとにレンダリングされます。
(引用：https://nextjs.org/docs/app/building-your-application/rendering/server-components#dynamic-rendering)

リクエストがあった時にレンダリングをします。

ルートにユーザごとのパラメータが付与されていたり、リクエストのみ知ることができる情報をもっていたりする時に使用するらしいです。


#### ストリーミング

>ストリーミングを使用すると、サーバーから UI を段階的にレンダリングできます。作業はいくつかのチャンクに分割され、準備が整うとクライアントにストリーミングされます。これにより、ユーザーはコンテンツ全体のレンダリングが完了する前に、ページの一部をすぐに確認できるようになります。
(引用：https://nextjs.org/docs/app/building-your-application/rendering/server-components#streaming)

段階的にレンダリングすることができます。

情報取得までに時間がかかるものをレンダリングするときに使用するらしいです。

### 使用方法

Appルータでデフォルトで使用できます。

また、`"use server"`をファイルの一番最初に記載すると使用することができます。

## クライアントコンポーネント

>クライアント コンポーネントを使用すると、サーバー上で事前レンダリングされる対話型 UI を作成できます。クライアント JavaScript を使用してブラウザで実行できます。
このページでは、クライアント コンポーネントがどのように機能するか、どのようにレンダリングされるか、いつ使用できるかについて説明します。
(引用：https://nextjs.org/docs/app/building-your-application/rendering/server-components)


### メリット

クライアントコンポーネントを使用するメリットとしては、公式では2つ紹介されていました。

- **インタラクティブ性**
状態を管理することができるので、UIが向上するらしいです。

- **ブラウザ API**
位置情報などのブラウザ用のAPIや、ローカルストレージにアクセスすることができます。

### 使用方法

Pageルータでデフォルトで使用できます。

また、`"use client"`をファイルの一番最初に記載すると使用することができます。

# おわりに

サーバコンポーネントとクライアントコンポーネントをよく理解していないせいで、AppルータにしたときにAPIをたたくところで詰まったことがありました。

この記事での質問や、間違っている、もっといい方法があるといったご意見などありましたらご指摘していただけると幸いです。

最後まで読んでいただきありがとうございました！

# 参考

https://qiita.com/JNJDUNK/items/2c2a5f433c7d4ae6ea1d

https://zenn.dev/yutabeee/articles/dd614f2e0c5455
Pypy導入後に，VS CodeのrunのデフォルトpathがPypyになってしまう

時間がないので取り急ぎメモをします

Pypy導入後にVSコードのdefault interpreterが変わってしまうことがありました．

問題点としては，pypyにないライブラリを使うと推奨されるレコメンドが変わってしまうこと
右上のrunボタンでの実行などができなくなります（あたりまえ）

解決策としてはCtrl+Shift+Pでコマンドパレットを開いて，
python: Select interpreterを選択し
画像のようにRecommendedになっているPypyではなく，Globalのpythonを選択することで解決します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3064963/775327f1-d9e2-44c2-bd5f-48b81f434a41.png)
【Suno AIでつくった楽曲】ピアノ曲( ショパンのオマージュ ) ver.1【動画 2分02秒】【YouTubeチャンネルからの転記です】

この記事は、わたしの[YouTubeチャンネル](https://bit.ly/Yamanaka-YouTube "Living without things. 持たない生き方 手放す生き方")にある公開動画を転記しております。
( どこかのタイミングで、プログラミング-Google Apps Script or iPaaS-Zapier をつかって自動転記させる予定です )

転記のための時間コストを少なくしたいので、文字装飾( Markdown記法 )を極力つかわずに書いております。

こちらが動画内容です👇

***

![99 サムネイル 【Suno AIでつくった楽曲】ピアノ曲( ショパンのオマージュ ) ver.1【動画 2分02秒】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386308/0cf3654a-ac7b-5c8f-c8cc-670c297b4784.png)



* # 動画URL
    * https://youtu.be/swrTxn9dpwk

<br>

* # 動画タイトル
    * 【Suno AIでつくった楽曲】ピアノ曲( ショパンのオマージュ ) ver.1【動画 2分02秒】

<br>

* # 動画の説明欄(一部を抜粋)

📅撮影日 = 2024-04-06(土)

Suno AIでつくった曲をMP3で出力してから、動画編集いたしました。
Suno AIとは、文章から音楽を生成することができるAI( Text-to-Music-AI )です。
ぜひ聴いてみてください。

楽曲の正式名称:
Moonlight Sonata ver.1

Suno AI Library URL:
https://bit.ly/suno-Moonlight-Sonata-ver-1

Instrumental:

作曲日:
2024-04-02(火)

契約の種類:
Pro Plan


---


Suno AIへの指示文章( プロンプト ):


🇬🇧English

A gentle piano piece that soothes the mind and induces sleep for my sweet lover, in homage to Chopin.


🇯🇵日本語訳

わたしの伴侶のための、穏やかで心が休まりながら睡眠を誘うピアノ曲、ショパンのオマージュ


---


Suno AI 公式URL
https://accounts.suno.ai


---


✓ 🎥この動画と関連が強いわたしの動画 ↙
　・“Suno AIでつくった楽曲”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghMLdiSVqwvSs_Z5y0H4VGOe


　・“効果的にSuno AIを活用するヒント”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghPuaNOVZn-N53wVvsBkeHdI


　・【Suno AI】文章から音楽を生成するAI( Text-to-Music-AI )で、3分間で2曲、6分間で4曲作りました【試聴可能】1)伴侶の曲 2)税理士の曲【動画 16分11秒】
　https://youtu.be/QKfhk4HgQ_g


✓ 🎥Shortened URL for this video | この動画の短縮URL ↙
　https://bit.ly/4anTRFN
「桜が舞う」SSD1306でランダム表示(StampS3)


x 過去ログを見よ


目的
OLEDのテスト
一応、仮想VRAM方式(白黒)



結果

![o_coq025.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/53f458db-9710-4be4-139c-e33d2a8005b4.jpeg)



プログラム


```c++



//有機ELのSSD1306でランダムに点を描画
//秋月のOLEDとアイテンドウの売り切れ?OLEDのアドレスは3C
//SSD1306_RAND_M5S3_1


//ヘッダー
#include <Arduino.h>
#include <Wire.h>


//定義
#define MAX_PAGE                   (7)
#define MAX_COL                    (127)

#define COMMAND_MODE               0x80 // continuation bit is set!
#define DATA_MODE                  0x40

#define SET_COLUMN_ADDRESS         0x21 // takes two bytes, start address and end address of display data RAM
#define SET_PAGE_ADDRESS           0x22 // takes two bytes, start address and end address of display data RAM

#define SET_MEMORY_ADDRESSING_MODE 0x20 // takes one byte as given above
#define HORIZONTAL_ADDRESSING_MODE 0x00


//I2Cに配列を転送する
void write_s(uint8_t *str1, uint8_t len1) {

  Wire.beginTransmission(  0x3c  );

  for (int ii = 0; ii < len1; ii++) {

    //一文字出力
    Wire.write(*str1 ++);

  }//for

  Wire.endTransmission();

}//write_s


//セットページアドレス
void setPageAddress(uint8_t start, uint8_t end)
{
  uint8_t databytes[6] = {COMMAND_MODE, SET_PAGE_ADDRESS, COMMAND_MODE, start, COMMAND_MODE, end};
  write_s(databytes, 6);
}//setPageAddress


//セットカラムアクセス
void setColumnAddress(uint8_t start, uint8_t end)
{
  uint8_t databytes[6] = {COMMAND_MODE, SET_COLUMN_ADDRESS, COMMAND_MODE, start, COMMAND_MODE, end};
  write_s(databytes, 6);
}//setColumnAddress


//セットメモリーアドレシングモード
void setMemoryAddressingMode()
{
  uint8_t databytes[4] = {COMMAND_MODE, SET_MEMORY_ADDRESSING_MODE, COMMAND_MODE, HORIZONTAL_ADDRESSING_MODE};
  write_s(databytes, 4);
}//setMemoryAddressingMode


//初期化
void setup() {

  delay(3000); //not Delete (絶対消すな)(消しちゃィゃーん)

  //I2Cのポートの変更
  //Wire.setSDA(19); //PA10
  //Wire.setSCL(18); //PA9

  //I2Cの初期化
  Wire.begin(); //C011
  delay(200);

  //SSD1306の初期化スペル(魔法)
  //0x80,0x8d,0x80,0x14,0x80,0xAF
  write_s( (uint8_t*) "\200\215\200\024\200\257", 6);
  delay(100);

  //セットメモリーアドレシングモード
  setMemoryAddressingMode();

}//setup


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

  uint8_t buff_a[((128 / 8) * 64)]; //バッファー
  memset(buff_a, 0, ((128 / 8) * 64) ); //バッファーのクリア

  //ランダムにドットを200点打つ
  int x, y;
  for (int loop_count1 = 0; loop_count1 < 200; loop_count1++) {

    x = random(128);
    y = random(64);
    buff_a[x + (y / 8) * (128)] |= (1 << (y & 7));//ドットに点を打つ

  }//for loop_count1

  //範囲の設定
  setPageAddress(0, MAX_PAGE);  // all pages
  setColumnAddress(0, MAX_COL); // all columns

  //データの配列の定義
  uint8_t databytes[2] = {DATA_MODE, 0x00};

  //128x64の再描画
  for (int icount = 0; icount < ((128 / 8) * 64); icount++) {
    databytes[1] = buff_a[icount];
    write_s(databytes, 2);
  }//for icount

  delay(1000);//1秒待つ

}//loop




```
Flutter  〜Dartの基本文法〜

●変数の宣言
```
//整数型
int number = 0;

//文字列型
String str = 'Dart';

//類推
var one = 1;
```
varを使用した変数宣言は変数の型を明示的に指定しない。
Dartの型推論機能が変数に代入される値からその型を推測する。
上記の場合はint型と推測される。

●他のソースからの参照可否設定
_をつけて宣言した変数は他のソースから参照できない。

```
int view = 0;
int _notView = 0;
```

●関数
全ての関数は別の名前がつけられている必要がある。

```
//サンプル
int func(int a, int b) {
  return a + b;
}
```

int：
戻り値の型。

func：
関数名。

(int a, int b) ：
パラメータリスト。例では二つの整数a、bを引数として受け取る。

{  return a + b;}：
関数が呼び出された際に実行されるコードのブロック。
例ではa+bの結果を返す。

●関数（短縮形式）
```
int func(int a, int b) => a + b;
```
=>の表記を使って{}とreturnを省略可能。

文字列の中での変数の使用例。
```
void greet(String name, [String greeting = 'Hello']) {
  print("$greeting, $name!");
}
```
●位置引数と省略可能引数
```
int func(int a, [int b = 0]) => a + b;
```
int aは関数呼び出すに必須の引数。
[int b = 0]は省略可能な引数で初期値が0となる。


●final
```
//値の初期化後、再代入は不可
final int zero = 0;
final one = 1; // 型推論もできる
```
上記の例だとzero, oneの値の変更は不可。
ただし、finalでリストを宣言した場合、リストへの追加や削除は可能。
変数が初期化された後、その変数に対する再代入は禁止。
その変数が指すオブジェクトの内部状態（プロパティや要素）は変更可能。
プログラムが実行されて初めて値が決定されるような場合や、
インプットとして与えられた情報を変更不可として取り扱いたい場合に使用する。

●const
変数はコンパイル時にその値が確定し、そのメモリ領域は完全に不変。
constで作成されたインスタンスがすべて同一のメモリ参照を共有する。
constで宣言された変数やオブジェクトは、その内容も含めて完全に変更不可能

```
const int two = 2;
const three = 3; // こっちでも型推論できる
```
constは完全に不変でどんな変更も許可されない。
上記のtwoやthreeはコンパイル時に確定し、プログラム全体で一意のインスタンスを共有する。
コンパイル時に値が固定されるオブジェクトに使用する。
プログラムが実行される前に値が既にわかっている場合や、
同一の不変のインスタンスを複数箇所で共有したい場合に適している。


Dartは型の修飾子としてfinalとconstが存在する。
finalはJavaのfinalと同じ意味で再代入不可。
constはコンパイル時定数。つまり、「再代入不可 + そのメモリ領域の書き換え不可」となる。
```
final int zero = 0;
// 型推論
final one = 1; 

const int two = 2;
//型推論
const three = 3; 
```

●null safety
```
//nullを許容
int? a = 0;

//nullを許容しない
int  a = 0;
```
型名?のような型がnullになりうる型
?が付かない型がnullを許容しない型。
```
int? a = null;

// a == nullであればnull、a != nullであればa.toString()の値
a?.toString(); 

// a == nullであれば0、a != nullであればaの値
a ?? 0; 
```
claudeを使って説明書に対しての質問をしてみた

# はじめに
当記事ではClaude(クロード)を使ってみた感想を記載しています。

Claudeに興味を持ったきっかけは
Microsoft AI Tour Tokyoに参加した時のセッションを聞く中で
「URL指定したサイトをINPUTにして独自のAIを作成できるのすごい！」
と衝撃を受けたのですが
* 法人でしか使用不可
* 利用料金が高い

の理由で挫折したところから始まりました。
もやもやを抱えたままAIについて情報収集する中で、
無料でも使用できINPUTになる情報を添付できるClaudeに出会いました。

# 使用するまでの流れ（ざっくり）
claudeのサイトにアクセス
[claude](https://claude.ai/login?returnTo=%2F)
↓
メールアドレスを登録
↓
受信したメールに記載されている認証コードを入力
↓
電話番号を登録
↓
受信したSMSに記載されている認証コードを入力
↓
ユーザ名を登録

# 取り扱い説明書を指定して質問をしてみる
今回は自宅で使用しているKOIZUMIのエッグスチーマーの説明書を添付し、
半熟卵の作り方について質問をしてみます。

### 説明書を添付
下記の赤枠部分をクリックしてファイルを添付します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/1e26d49d-6e72-0fe4-98ee-f54ecf96275e.png)

下記赤枠のようになれば添付は完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/6c49e36b-3371-c351-c0db-98178f9fe5f8.png)


### 質問内容を入力
下記赤枠部分に質問内容を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/789c3089-8303-5473-77f1-5391ad001265.png)

### 実行
下記の赤枠部分をクリックして実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/93426dad-725b-55b6-665f-13574ad7c24b.png)

### 結果確認
20秒ほどで回答で得られることができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/b94f3f22-f014-b3a6-aea8-0dca0a4b6f4a.png)


肝心の「回答内容が正しいか」についてですが、
説明書に記載されている内容
* 1個、2個の場合は、BまたはEに卵をセットする
* 3個の場合は、A、C、D、Fのいずれかにセットする

がClaudeからの回答にも含まれているので
正しく回答が得られていることが確認できました。
※INPUTに指定した説明書（抜粋）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/b29358a9-29bc-003f-99ba-9936de222a8e.png)


# さいごに
ページ数の多い資料から必要な情報を得るのに苦労するケースが多々あると思います。
対象資料を添付してClaudeから回答を得られれば
だいぶ楽になるのではないかと感じました。
【Flutter】キーボードが現れるまたは、消えるときにウィジットの再構築が走る

# 無駄に再構築される
TextFieldをタップしてキーボードが表示されるだけなのに、なぜか再構築が走る。しかも、それがかなりツリーの上の方なので、パフォーマンスにかなりダメージを与えてくれる。その原因追及に苦労したので、備忘録として残しておく。

# 自分の場合の解決策
resizeToAvoidBottomInsetはfalseにしたのに、再構築が走った。
調べてみると、MediaQueryを使うと、再構築が走るらしい。
英語記事だが、下の記事が参考になった。
https://stackoverflow.com/questions/68244573/why-does-my-widget-rebuild-when-i-use-keyboard
鳥さん、たまごからの飼い方「姫うずら編」

# エンジニア であるのか?
**エンジニアとは**専門知識や技術を持った技術者のこと。
姫うずらをたまごから孵してたまごを産ませられるまで育てて今も、育てているから成功した飼育者だよな? ここは、そんなところやない、とか言わずに、ノウハウがあると思ったから、立てたのです。
つまり、多くが死ぬ。。。そして、それには原因と思われるのに、至った数少ない記録と成りえる。
たかだか、うずらの飼育やろ。たまごが問題になってるわ。じゃ、あのサイズになりえる物はすべて、問題でしょう? じゃ、餅をのどに詰まらせて亡くなられた数と、どちらが多いのかという議論は出ていない。
なぜ、この話をしたかは、出荷が止まれば、育成が止まり、種の保存が止まる。固体の生存率が、種全体の生存率になっていき鳥類の事になり、生命体の事につながっていく。日本からウズラを消して良いのかとなる。
私の持っている、気付く前の数字で行くと、たまご4個のうち2羽孵り、1羽しか生き残らない。1シーズンに4個たまごを産んだとしても1羽残るか残らないか、で、籠の中の鳥なら1羽も残らないと言う結論に行き当たった。籠で適切に処置しなければ、籠の飼い鳥は絶滅してしまうという結論に至った。
この発表が価値のない物なら、受け入れよう。順を追って、プロセスを話していこう。

**砂嚢**（さのう、英: gizzard、鳥類においては ventriculus、gastric mill、 gigerium とも）は**鳥類、爬虫類**、ミミズ、魚類などに見られる消化器官である。
###### 出典: フリー百科事典『ウィキペディア（Wikipedia）』 (2023/01/08 09:25 UTC 版) ######

もう、分かったな?　たまごの中には**泥も砂も小石**も入っていない。どうやって、消化するんや? 入れてやらないと食った物が消化できないだろう?
籠の中に、**泥や砂や小石を入れてあげなければならない**。類として、**必須要素**となっている。ニワトリだけやろとか、馬鹿な事を言うなよ。ついでに言っておくが、砂のない水槽の魚はヤバい事になるという理論も導ける。

何が問題かというと、消化できないまたは、少ししか出来ないと、栄養失調になり、下痢を起こす、結果、生きていけなくなる。

雛の犠牲になった上で気付いた。小さいのしか飲み込めん。体だ大きくなり、内臓も大きくなる、小さい物は排泄される。すり減って小さくもなる、砂嚢の出口より小さくなると排泄される。結果、砂嚢が空になっていき、吸収できなくなり食べても空腹となっていく。多く採っても下痢として排泄されてしまう。

籠の鳥は自然と違って、補う事が出来ない。**あなたが入れてやらないと**。

ここまで来ると、餌と同等に大切であるという事になる。栄養のある物以上に。

どの様な物をchoiceするかというど、姫うずらの場合、メダカの観賞用敷き砂となる。もちろん、彼らは体に合わせて飲み込むから、心配はいらないが、与えなければならない。

まぁ、わたしのホームページには飼育日誌として、ふ卵器から、環境までかいてあるが、宣伝は避ける。

以上。
【Zod】maxやminで文字列を書記素単位で数える方法

以下のように記述すると 👪 などの絵文字も1文字としてカウントされます。

```js
function countGraphemes(str: string) {
  const segmenter = new Intl.Segmenter('ja-JP', { granularity: 'grapheme' })
  const graphemeSegments = segmenter.segment(str)
  return Array.from(graphemeSegments).length
}

const schema = z.object({
  sample: z
    .string()
    .refine((value) => countGraphemes(value) <= 250, {
      message: '最大文字数を超えています。',
    })
})

```