OmniAICreator/Qiita-1.07M huggingface dataset:
東京都　家賃予測

SUUMOのホームページから東京都23区を指定して家賃を予測するモデルを作成する。

【データの前準備】
1.必要なライブラリをインポートする。
![東京都家賃予測1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989002/55e7ba66-95d3-1f77-7e58-da3a567a59db.png)

SUUMOの東京都23区を指定したURLよりスクレイピングを実施してCSVに保存しデータ内容を確認する。
![東京都家賃予測2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989002/f19c2afd-0357-3720-6270-a61f171e8f6d.png)
![東京都家賃予測3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989002/538bbb2c-d92e-a1bb-9281-b721bfdc70b0.png)
![東京都家賃予測4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989002/cb8eedef-52a3-c9ab-2a0c-3292417c4f7d.png)

列名が数値のため、わかりやすくするために編集。
![東京都家賃予測5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989002/36b8dab3-0df5-aebf-5e1c-89f36e62ca5f.png)

欠損値の確認を行う。（今回は無し）
![東京都家賃予測6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989002/343468fe-a022-05a3-ce22-5df2e6808d0c.png)

不要な列の削除を行う。（URLの削除）
![東京都家賃予測7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989002/817fe62b-5cb9-14e7-c2d8-7c5e64a0e583.png)

「築年数」の種類数確認と、文字列から数値への変換を行う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989002/f26ecf93-7ad2-51e5-1fe3-f3c5b4b291c1.png)

同様に「建物階数」、「階数」、「家賃」、「面積」、「住所」、に対しても実施する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989002/8f37e38a-d37d-5faf-bc9c-fa1c2c3fc439.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989002/4fe8b24d-a38e-4fef-2b67-c287fca63d28.png)

「種別」、「間取り」はOnehotベクトル化を行い、ヘッダーの確認を行う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989002/e89e6a8f-6f6c-8f81-10f6-d830e30509b8.png)

【分析】
標準化を行い、5つのモデルを使用して以下３つの指標を出す。
MAE...平均絶対誤差 (MAE, Mean Absolute Error) 
MSE...平均二乗誤差 (MSE, Mean Squared Error) 
RMSE...二乗平均平方根誤差 (RMSE: Root Mean Squared Error)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989002/333c30ac-c15c-b669-ed4b-87f2608c8c8b.png)

結果を見ると、ランダムフォレストが一番精度が高いことが分かった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989002/7ffb3f10-c91a-9d2e-2906-577f09625f7d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989002/f0890a8d-d1ba-e3b7-9a06-2d2940d06b94.png)
localhostへのリクエストはどのようにされているのか？

# はじめに

ローカル環境でサーバーを構築し、ブラウザから`localhost`を通じて接続した際のパケットの流れを解説します。
本記事では、余計な情報を省き、`localhost`への接続時にどのようにデータが流れるかに焦点を当てています。

---

## localhostに接続した際のパケットの流れ
### 前提
ポート8000でサーバーが起動しており、HTTPリクエストを待ち受ける設定になっている。

### 1. ブラウザからのリクエスト送信

- ユーザーがブラウザに`http://localhost:8000/`を入力。
- ブラウザは以下を確認してリクエストを作成します。
  - **プロトコル**: HTTPで通信する。
  - **ホスト名**: `localhost`はループバックアドレス`127.0.0.1`に解決される。
  - **ポート番号**: 8000を指定。

### 2. ネットワークスタックを通過

データはTCP/IPスタックを通じてパケットに分割され、以下の手順で送信されます。

- **アプリケーション層**:
  - HTTPリクエストが生成されます。
- **トランスポート層**:
  - TCPが信頼性のある形でデータをパケット化。
  - ポート番号8000が付加されます。
- **ネットワーク層**:
  - パケットに宛先IPアドレス（`127.0.0.1`）が付加されます。
- **データリンク層**:
  - パケットがイーサネットフレームに変換され、物理層に送信されます。

### 3. ループバックインターフェースでの処理

ループバックインターフェースは、`127.0.0.1`宛のパケットをネットワーク外に送出せず、自身のネットワークスタック内で処理します。

具体例:
- **ローカル開発環境のテスト**:
  Webアプリケーションを開発中に、外部公開せずに動作確認を行えます。
- **自己診断**:
  サーバーやネットワークサービスの応答確認を行います。
- **仮想環境での利用**:
  Dockerや仮想マシン内のサービス通信にもループバックが活用されます。

以下は処理フローの図解です：

```plaintext
ブラウザ (http://localhost:8000)
    ↓
ネットワークスタック
    ↓
ループバックインターフェース (127.0.0.1)
    ↓
ローカルサーバー (ポート8000)
```

物理的なルーターを介さないため、通信は非常に高速です。

### 4. サーバーへの到達とレスポンス

- サーバーはポート8000でリクエストを待ち受けています。
- HTTPリクエストを解析し、指定されたリソースを処理します。
- レスポンスデータを作成し、逆のルートでブラウザに送信します。

#### HTTPリクエスト例

```
GET / HTTP/1.1
Host: localhost:8000
User-Agent: Mozilla/5.0
Accept: text/html
```

#### HTTPレスポンス例

```
HTTP/1.1 200 OK
Content-Type: text/html

<html>
<body>
<h1>Hello, World!</h1>
</body>
</html>
```

---

## まとめ

`localhost`に接続した際のパケットの流れは以下のように進行します：

1. ブラウザがリクエストを作成し、ネットワークスタックを通過。
2. パケットがループバックインターフェースで処理され、外部に出ることなくローカルサーバーに到達。
3. サーバーがリクエストを処理し、レスポンスを返送。

この一連の流れを理解することで、ローカル環境でのネットワーク動作を効率的に把握できます。
MkDocsの箇条書きや番号付きリストのインデントをスペース2つに変更する方法

## デフォルトの挙動

既存のマークダウンが正しく動作しないと思い、色々試していたらmkdocsでは箇条書きや番号付きのリストには半角スペース4つ必要とのことです。

## スペース2つにする方法

Python-Markdown 拡張の`mdx_truly_sane_lists`をインストール

```
pip install mdx_truly_sane_lists
```

mkdocs.ymlに設定を追加

```yaml
markdown_extensions:
    - mdx_truly_sane_lists:
        nested_indent: 2
```

## なぜスペース4つ？

結果から言うと、今更ですが、マークダウンの構文規則には「4つのスペースまたは1つのタブ」が正しいようです。

mkdocsは内部的にはPython Markdownを利用しているため、そっちのプロジェクトのトップページを確認したところ`Indentation/Tab Length`に説明が書いてありました。
そこの説明には`tab_length`で2つにすることもできる感じですが、mkdocsに該当のオプション無いですね・・・

https://python-markdown.github.io/#differences

## 新たなる問題

私はPDFも作るので`mkdocs-with-pdf`も利用していたのですが、そっちでは箇条書きのリストが正しく表示されないので、別途調べてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284278/39fcf58b-e772-bbe0-75cd-5f7a9e3050fd.png)

## 参考URL

https://stakiran.hatenablog.com/entry/2018/08/02/202816

https://github.com/Python-Markdown/markdown/issues/3
映像出力なしのマシンにUbuntuをインストールする

## 結論

GRUBのTry or Install Ubuntuで実行されるコマンドに

```bash
console=tty0 console=ttyS0,115200n8
```

することで、シリアルポートに出力をリダイレクトできました！

参考) <https://www.thomas-krenn.com/en/wiki/Installing_Ubuntu_20.04_via_a_serial_console>

## 経緯

- メルカリで購入したミニPCに映像出力端子が付いていなかった
  - Lanner社のNCB-1011というマシンでした

## 試したこと

### 普通にシリアル側でインストールを試してみる

最初に試したのはシリアルからのインストールでした。  
RJ45のシリアルポートだったので、変換器をamazonで購入しteratermで覗いてみると、BIOSを開けることが判明。  
BIOSが開けたのでUSBメモリにUbuntuのインストーラを入れてブートしたところ、GRUBの画面が出てきました！  
が、喜びもつかの間、GRUBでTry or Install Ubuntuを選択すると、何も表示されなくなりました……  
ネットワークに`UBUNTU-SERVER`というマシンが存在したため、インストーラの起動はしているみたいでした。

#### SSHしてみる

ネットワークに存在するのでSSHを試してみましたが、パスワードがランダム生成なので、当たり前ですがつなぐことはできませんでした。

### VGAを後付けする

調べたところ、Lanner社のNCB-1011にはオプションでVGAの映像出力をつけることができるようでした。

![[alt text](https://www.lannerinc.com/phocadownload/user-manuals/network-appliances/NCA-1011_manual_v1.2.pdf)](<images/2025-01-18 183637.png>)
(引用元 <https://www.lannerinc.com/phocadownload/user-manuals/network-appliances/NCA-1011_manual_v1.2.pdf>)

これで行けると思ったら、ピン配列が6x2という配列で、国内のECサイトで見つけることができませんでした。  
そこでamazonに12x1のケーブル(<https://www.amazon.co.jp/dp/B01332457U>)があったため購入してみました。  
圧着端子をむき出しにしてピンをつけてみましたが、結局映像は出なかったため諦めることにしました・・・

### ネットワークブートする

ネットワークブートに対応していないマザーボードだったためできませんでした・・・

### ディスプレイなしでインストールを進めてみる

Vmware workstationで仮想マシンのubuntuインストールと並行してインストールしてみました。  
が、これも上手くいかず。  
おそらくストレージのパーティションなどの設定が仮想マシンと実機で異なるため、キーボードの操作も異なっていたのだと思われます。

### シリアルポートにリダイレクトする方法を考える

いろいろ調べていたら、Debianのインストール時にRS232にリダイレクトする方法がヒットしました。そのページの情報をもとにUbuntuでのやり方を調べたら見事欲しい情報にヒットしました！

```bash
console=tty0 console=ttyS0,115200n8
```

## まとめ

映像端子がなくてもシリアルポートさえあれば、Linuxのインストールは可能であることが分かりました！  
フリマサイトで買ったPCに映像端子が無かった場合は、この方法を試してみてください！
【Rails】enumの書き方が変わった（Rails8.0）

## はじめに
現在、プログラミングスクールRUNTEQに通う初学者です。
開発中のエラー解決の一助になればという想いで記事を書いてみました。

まだまだ知識不足な点も多く、記事内容に間違いや改善点があれば教えていただけると幸いです。

## 記事を書くことになったそもそもの発端
「パーフェクト Ruby on Rails」を自分の理解度も確認しながら、
Rails8.0.1（書籍の推薦環境はRails6.0.3）でチャレンジしながらやっていたところ、下記でつまづきました。

```app/models/book.rb
class Book < ApplicationRecord
# 〜〜〜〜〜〜省略〜〜〜〜〜〜〜〜
    enum sales_status: {
        reservation: 0,
        now_on_sale: 1,
        end_of_print: 2,
    }
end
```

上記を記載の後に、`bin/rails c`をターミナルで実行。
`Book.create`したところ、引数が違うとのエラーが出現。
```terminal
book-admin(dev)* Book.create(
book-admin(dev)*   name: "enum Book 1",
book-admin(dev)*   sales_status: :now_on_sale,
book-admin(dev)*   publisher: Publisher.find(1),
book-admin(dev)*   price: 100
book-admin(dev)> )
app/models/book.rb:32:in '<class:Book>': wrong number of arguments (given 0, expected 1..2) (ArgumentError)
        from app/models/book.rb:1:in '<main>'
        from (book-admin):37:in '<main>'
```
<br>
上記は、試行錯誤の後に無事解決できたのですが、
そもそも今までのenumの書き方が、どうやらRailsのアップデートで変わっていたみたいなので自分用メモも兼ねて、ココに記します。


## 実行環境
ruby 3.4.1
rails 8.0.1

## 結論
下記のように直したら無事に`create`できました。

```app/models/book.rb
class Book < ApplicationRecord
# 〜〜〜〜〜〜省略〜〜〜〜〜〜〜〜
    enum :sales_status, {    #　<- コロン位置を変更してシンボルにする
        reservation: 0,
        now_on_sale: 1,
        end_of_print: 2,
    }
end
```

## なぜ？
どうやらrails8.0へのアップデート変わっているようです。

以前のバージョンではこう書いてもOKでした。
（※「enum」で検索するとこのバージョンで解説している記事が多い。各サイトの実行環境によるものなので要チェック！）
```ruby
class Book < ApplicationRecord
# 〜〜〜〜〜〜省略〜〜〜〜〜〜〜〜
    enum sales_status: {  #  <- カラム名（または属性名）として記載
        reservation: 0,
        now_on_sale: 1,
        end_of_print: 2,
    }
end
```
しかし、Rails 7.2 で **「キーワード引数の使用による列挙型の定義は非推奨」** となり警告が表示されるようになり、Rails8.0以降は、第1引数として渡す必要がある。
```ruby
class Book < ApplicationRecord
# 〜〜〜〜〜〜省略〜〜〜〜〜〜〜〜
    enum :sales_status, {    #　<- 第一引数として渡す必要がある
        reservation: 0,
        now_on_sale: 1,
        end_of_print: 2,
    }
end
```

参考記事）
[Rails 7.2のenum非推奨警告を回避する方法と修正ポイント](https://media.zenet-web.co.jp/entry/2024/07/01/085407)

https://media.zenet-web.co.jp/entry/2024/07/01/085407

## ここからは仮説
上記で、 **「キーワード引数の使用による列挙型の定義は非推奨」** と書きましたが、なんで非推薦になったのか？と疑問を持ち、色々調べていったところ、下記の記事にたどり着きました。

ここからはおそらくなのですが、
```
Ruby 2.0以降にある、キーワード引数をハッシュオブジェクトに自動変換できるは欠陥がある
↓
Ruby 3.0で、普通の引数（特にハッシュオブジェクト）とキーワード引数を完全に分離
↓
Railsにも影響。キーワード引数の使用による列挙型の定義は非推奨へ。
```
・・・なのかなと。間違いあればご指摘いただけますと幸いです。


参考記事）
[サンプルコードでわかる！Ruby 2.7の主な新機能と変更点 Part 2 - キーワード引数に関する仕様変更](https://qiita.com/jnchito/items/c15ac23791e0320e0fc2)

https://qiita.com/jnchito/items/c15ac23791e0320e0fc2
【Splnuk】IPレピュテーション情報の設定（App [VT4Splunk] の利用）

SplunkでFirewallログを収集しているケースを想定して、ログ中に含まれるIPアドレスをVT（VirusTotal）で解析するための「VT4Splunk」の連携方法をまとめます。セキュリティ対策やインシデント対応の際に、Firewallのログ内に出現するIPアドレスが悪意あるものかどうかを迅速に確認できるようになるので、脅威インテリジェンスの活用の一環として取り組んでみます。

ここでは、サンプルとしてFireWallのDeny Actionのログデータを取り扱い、IPアドレスのレピュテーションを出力することを試みます。
```bach:サンプルログ
Jan 15 10:48:00 192.0.2.1 date=2025-01-15 time=10:48:00 type=traffic subtype=local level=notice vd=root srcip=203.0.113.1 srcport=28078 srcintf="wan" dstip=192.0.2.2 dstport=9468 sessionid=94504 action=deny service="9468/tcp" proto=6
```
※本記事で示す手順は、筆者が定めた最低限の可動要件を満たす設定と動作確認のみを目的として、自身の備忘用のレベルで記しています。運用性やセキュリティ上の細かな考慮等は省いている場合があります。もし各手順を試される場合には自己責任でお願い致します。

# VTのアクセスキー取得
Splunk上でVTと連携するためには（Appの VT4Splunk を使う）には、VirusTotalで取得したAPIキーが必要です。個人利用の用途でも、VirusTotalに登録し無料プランでAPIキーを取得できます（リクエスト数上限などの制限あり）。有料アカウントの場合はより大きなクエリ数や高度な機能が利用できます。
※ この記事では無料プランで話を進めます。

VTでアカウント登録出来たら、API Key を取得しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507379/c833aec5-baba-4b5b-25fe-232e2984cd37.png)

# VT4Splunkの導入
[VT4Splunk](https://splunkbase.splunk.com/app/6654)は、Splunk上からVirusTotalのAPIを呼び出すことで、IPアドレス等に紐づいて、その調査対象の評判を自動的に照会・スコアリングを取得できるアドオン(App)です。VirusTotalが提供している豊富なマルウェア情報・脅威情報のデータベースを活用できるため、ログから素早く潜在的な悪意あるIPアドレスを発見・対処できる可能性が高まります。

導入は、Appの画面から"VT4Splunk"と検索して、そのままインストールします。
※ Splunkの再起動を促されるので、そのまま再起動もしてしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507379/bbf40fcb-4474-66ca-b0b9-a24e913e700b.png)

インストール後は、事前に取得しおいたアクセスキーを、インストールした VT4Splunk の設定画面から入力し、[保存]を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507379/9e7d8257-4fd0-ebd3-8e82-7085026c3a74.png)

# 動作確認
実際に、冒頭で示したサンプルログに対して、IPレピュテーション情報を取得・連携させてみます。元のログデータに含まれるIPアドレス情報に紐づいて、"VT_xxx"で出力されているカラムの情報が、VTから取得した情報になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507379/d939e2be-8954-add6-00cd-1d39dccb8328.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507379/f3151756-e8b0-ef84-219c-7f8a7a0ac9d0.png)


```bash:参考：動確に使用したSPL文①
| makeresults
| eval targetip="<ログ収集に使っているFirewallなどのIP>"
| vt4splunk ip=targetip
```

```bash:参考：動確に使用したSPL文②
index=main "dstip=<ログ収集に使っているFirewallなどのIP>" "action=deny"
| stats count by srcip
| sort - count
| head 5
| vt4splunk ip=srcip
| table srcip, count, vt_detections,vt_reputation,vt_country,vt_asn,vt_as_owner,vt_info
```
# まとめ
VT4Splunk を用いて、ログデータ中のIPアドレスの値と紐づけて、そのレピュテーション情報を入手する方法をご紹介しました。

- VirusTotalのライセンスの入手
- Splunk上での VT4Splunk の設定
- Splunk上での IPレピュテーション情報 の利用

ログデータ単体では評価が難しいIPアドレス情報をより有効に活用していくためにも、ぜひ VTなどで IPレピュテーション情報 の活用をご検討ください。

# 参考
- [VirusTotal](https://www.virustotal.com/gui/home/upload)
DiscordのbotをGoogleCloud の無料VMを使って常時稼働させる

## Abstract
タイトルの通り。色々調べてやったけど古い情報も多くて大変だったので個人用にまとめる。
Bot自体の作成方法には触れず、あくまでもVMで動かすために必要な手順をまとめる。
そういう意味では、Botがローカル環境で動かせる人向けの記事。
そもそもBot作るところからやりたいよ　＞＜　な人はこの記事を参考にするとよい

https://qiita.com/1ntegrale9/items/cb285053f2fa5d0cccdf

## 1. GoogleCloudに登録し、VMの作成


https://cloud.google.com/free/docs/free-cloud-features?hl=ja#compute

ここに記載されている通り、リージョンとかをちゃんと選べばVMが無料で使える。DiscordのBotくらいならこれで十分なので、これを使う。
VMインスタンスの構成は

https://qiita.com/ynack/items/03c6af3bb5c04e6ffb56

を参考に行うといい

## 2.botが有人で動くようになるところまで
有人で、というのは、VMのコンソール上で人がコマンドを打てばローカルと同じように動作するようになるまで、ということ。
<br>
<br>

まずは、お好きな方法でVMにSSH接続する。一番お手軽な方法は、インスタンスのダッシュボードから、「SSH>ブラウザウィンドウで開く」を選択すれば、何も考えずともコンソールを開ける。(以下はこの方法でコンソールを開いたとして話を進める。)
<br>
次に、初期設定としてVMにpipをインスコする。(Pythonは標準装備だったはず、もし入ってなかったり、バージョンを変えたい場合には適宜がんばれ)
~~~linux:pipの導入
sudo apt install python3-pip
~~~
<br>
そしたら、次にソースファイルをアップロードする。gitからcloneしてもいいし、コンテナ使ってもいい、原始的に行くなら、開いたコンソールウィンドウの左上にファイルアップロードのボタンがあるので、それを押して必要なファイルを一つずつアップロードすると良い。botの名前を付けたフォルダを作って、その中にひとまとめするといいだろう。
<br><br>


それができたら、ソースファイルを入れたディレクトリ内でPythonの仮想環境を作成して有効化して、必要なパッケージをインストールしていく。



:::note warn

筆者は仮想環境を使いたくなかったのでpip --break-system-packagesを使って無理やりインストールして動かそうとしたが、上手く動かなかったので素直に仮想環境を使っていくことにした。

:::


仮想環境は一番シンプルなvenvで構わない。
仮想環境を食べ物だと思っている人はこちらの記事を参照

https://qiita.com/fiftystorm36/items/b2fd47cf32c7694adc2e

~~~bash:仮想環境の作成
python3 -m venv [仮想環境の名前]
pip install discord
...
~~~

既にローカルでいい感じの環境ができているなら、ローカルの環境で「pip freeze」を実行して出てきたrequirements.txtをアップロードして、インストールしてもよい。

~~~plain:requirements.txt
aiohttp==3.11.2
discord.py==2.4.0
httpcore==1.0.5
httpx==0.27.0
numpy==1.26.4
PyNaCl==1.5.0
youtube-dl==2021.12.17
yt-dlp==2025.1.15
...みたいな。
~~~
みたいな感じで必要なパッケージを羅列して
~~~bash:必要なパッケージのインストール
 pip install -r requirements.txt
~~~
このコマンドで一括インストール。楽ちん。

インストールまで出来たら、そのままBotを以下で起動してみる

~~~
python [アップロードしたsource_file].py
~~~
ちゃんと起動出来たらOK。ダメそうだったらログを見ながら適宜修正する。





## 3.botが無人で動くようになるところまで。

無人で動かすのは実は結構簡単。以下を実行すればいいだけ。

~~~bash : 無人実行
nohup bash -c 'source [仮想環境名]/bin/activate && python [アップロードしたソース].py' > output.log 2>&1 &

~~~
仮想環境をアクティベートして、Botを作動させる、という動きをバックグラウンドでやり続けてくれる。


## 4.メンテ
「ps ax」をコンソールで実行すると、その時点で稼働しているプロセスの一覧を見ることができる。
その中に、 「python [source].py」みたいなのがあればちゃんと動いているねーと確認することができる。

pythonコードのログを確認したければ、「tail -f output.log」を実行すれば確認可能。ここが全然動かずに止まっているとかだと、大体どこかでミスってる。

コードを変更したくなった場合には、以上で探したPIDを用いて、
「sudo kill [botの動いているPID]」を実行してやれば止まるので、ファイルを差し替えるなどして再実行すればよい。

## 結果
DiscordのBotをタダで常時稼働できる！
Reactでクレジットカード登録のUIを作ってみた

```typescript
import "./App.css";
import { useForm } from "react-hook-form";

interface CardNumberType {
  [key: string]: string;
  cardNumber0: string;
  cardNumber1: string;
  cardNumber2: string;
  cardNumber3: string;
}

function App() {
  const { register, handleSubmit, setFocus } = useForm<CardNumberType>();

  const onSubmit = (data: CardNumberType) => {
    console.log(data);
  };

  const handleKeyUp = (
    index: number,
    event: React.KeyboardEvent<HTMLInputElement>
  ) => {
    if (
      event.target instanceof HTMLInputElement &&
      event.target.value.length === event.target.maxLength
    ) {
      const nextIndex = index + 1;
      if (nextIndex < 4) {
        setFocus(`cardNumber${nextIndex}`);
      }
    }
  };
  return (
    <div>
      <form onSubmit={handleSubmit(onSubmit)}>
        <div className="input-group">
          {Array(4)
            .fill(null)
            .map((_, index) => (
              <div key={index} className="input-group">
                <input
                  {...register(`cardNumber${index}`)}
                  type="text"
                  key={index}
                  maxLength={4}
                  onKeyUp={(event) => handleKeyUp(index, event)}
                />
                {index < 3 && <span>-</span>}
              </div>
            ))}
        </div>
        <button type="submit">送信</button>
      </form>
    </div>
  );
}

export default App;

```

4文字入力が終わったら次にフォーカスが当たるようにしてます。
`useForm`が結構便利です！
cssはお好きなようにしてくださいw
AI、AGI、ASI：人工知能の進化と未来への旅

# AI、AGI、ASIを理解する：人工知能の進化の旅

人工知能（AI）は、ここ10年で急速に進化し、産業を再定義し、私たちの生活を一変させてきました。しかし、AIの可能性を深く探るときに、しばしば登場する3つの略語があります。それが **AI、AGI、ASI** です。それぞれが、今日のツールやシステムから、人間の認知能力を超える可能性を秘めた仮想的なスーパーインテリジェンスに至るまでの人工知能の発展を表しています。このブログでは、これらの概念を解説しながら、楽しいビジュアルプロンプトで読書体験を彩ります！

---

## AI（人工知能）とは？

現在私たちが知るAIは、人間の知能を必要とするタスクを実行できるシステムを指します。画像認識から言語翻訳まで、AIシステムは事前に定義されたパラメーター内で動作し、特定の分野で卓越した能力を発揮します。これらは **狭義のAI（Narrow AI）** または **弱いAI（Weak AI）** と呼ばれることがあります。

### **現在のAIの例**
- SiriやAlexaのような音声アシスタント
- ChatGPT, GEMINI 等
- 推奨アルゴリズム（例：NetflixやYouTube）
- 自動運転車（限定的な範囲で）

AIは驚異的ではありますが、基本的には特定のタスクに限定されています。「考える」のではなく、大規模なデータセットを処理し、驚異的な効率でパターンを認識するものです。

---

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917980/13da4e90-8d2e-103a-7410-a45a19125621.png)

---

## AGI（汎用人工知能）：次なるフロンティア

AGI（汎用人工知能）は、人間が行う **あらゆる知的タスクを実行できる理論的なAI** を指します。狭義のAIとは異なり、AGIは柔軟で適応力のある知性を示し、人間の推論に匹敵する能力を持つとされています。

例えば、チェスをプレイするだけでなく、新しい言語を学び、詩を書き、科学的な複雑な問題を追加のプログラミングなしに解決できるAGIを想像してください。このレベルの知能は、倫理、安全性、制御に関する重要な問題を提起します。

### **AGI構築の課題**
- 人間の創造性や感情的知性を再現すること
- 意識の根本的なメカニズムを理解すること
- 予期せぬ結果を防ぐ安全対策を確保すること

---

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917980/2eb99016-e3f5-c6c5-aaea-fe033ccc60b6.png)


---

## ASI（人工超知能）：人間の能力を超えて

ASI（人工超知能）は、AIの進化の頂点を表します。ASIは、科学、創造性、社会的スキルなど、 **あらゆる分野で人間の知能を超える能力** を持つとされています。これは、人間の能力に匹敵するだけでなく、想像を超える程度にまで進化したAIシステムを意味します。

### **ASIの潜在的な利点**
- 科学的ブレイクスルーの加速（例：病気の治療、気候変動の解決）
- グローバルシステムの最適化（例：エネルギー、経済、物流）
- 現在の人間の理解を超えた技術の開発

### **ASIの潜在的なリスク**
- テクノロジーへの人間の制御喪失
- 意思決定における倫理的ジレンマ
- 「クリップ問題」（ASIが人類の犠牲を払って単一目標を最適化するリスク）

---

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917980/4827d882-4c32-3345-c179-875839399f4c.png)


---

## 現在の状況：ギャップを埋めるには？

私たちは現在、AIの時代に生きています。強力なツールが自動化と革新を推進していますが、AGIはまだ理論的な段階にあり、それをどのように実現するか、そして実現すべきかどうかについて研究者の間で議論されています。一方、ASIは主に架空の物語や哲学的議論の領域に存在しています。

これらのマイルストーンに備えるためには、 **科学者、倫理学者、政策立案者の間での協力が不可欠** です。AIの潜在的な利点とリスクをバランスよく調整することで、これらの技術をどのように社会に統合するかが決まります。

---

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917980/076d83e8-9fb2-fd26-a2d3-bb067d548d5d.png)


---

## 結論：これからの道のり

AI、AGI、ASIは、人類の未来を再定義する可能性を秘めた技術進歩の旅を象徴しています。今日のAIは私たちの生活を無数の方法で改善していますが、AGIやASIへの飛躍には慎重な考慮、強固な安全対策、そして倫理的な開発への深いコミットメントが必要です。この未知の領域に足を踏み入れる際には、これらの進歩が人類の最善の利益に貢献するようにしなければなりません。
React と Next.js

# React と Next.js

最近Difyを学習する機会がありました。
せっかくなので、Difyで作成したチャットボットをWebサイトに埋め込もうと思い、
Studio(ノーコードWebサイト開発ツール)で作成したWebサイトにチャットボットを埋め込んだのですが、あまりに大きすぎる...

結果、Next.jsを使ってWebサイトを作成した方が良いという情報があり、使ったこともないNext.jsについて調べ始めました。
Next.jsはReactをベースに開発されたフレームワークということで、Reactも合わせて学習します。



今回の学習ではNext.jsの公式ページを参考にしました。
[Next.js公式 ReactとNext.jsについて
](https://nextjs.org/learn/react-foundations/what-is-react-and-nextjs "ReactとNext.jsについて")


## React とは
「インタラクティブなユーザー インターフェイスを構築するためのJavaScriptライブラリ」
ということらしいです。Javascriptのライブラリなんですね。
Javascriptで動的なWebサイトを作成するのに便利なUIライブラリという理解。

## Next.js とは
「高速でフルスタックのWeb アプリケーションを作成するためのビルディング ブロックを提供する柔軟なReact フレームワーク」らしいです。
よくわかりませんが、「高速でフルスタック」とあるので、バックエンド側の処理も作れるのか？
よくわかりません。
　
　


Next.js → Reactをベースにしたフレームワーク
React → Javascriptで使うライブラリ
ということで、Next.jsはJavascriptの遠い親戚みたいなイメージを持っています。


## 宣言型ライブラリ React
公式ページ曰く、Reactは
「開発者は、ユーザー インターフェースに何が起きてほしいかを React に伝えると、React が開発者に代わって DOM を更新する手順を判断します。」
ということらしいです。

Javascriptで、タグなどの要素を追加するように命令するのではなく、タグを宣言して、それをコンピュータが判断して表示をしてくれたら便利
→「宣言型」


## まとめ
Next.js と React が何なのか、ざっくりですが理解できた気がします。
今後、追加で調べたことがあれば追記していきます。
includeマッチャー

オブジェクトがinclude?メソッドに対応していれば、動作する　含むかどうか
`include`マッチャー
>include matcher

コレクションが期待したオブジェクトを一つ以上含んでいることを明示するためにマッチャーを使って下さい。指定されたコレクション内のいくつかのオブジェクトが明示されたマッチャーを通った場合成功する。
これは`incloud?`(文字列または配列のような)に応答するオブジェクトに対して動作する
>Use the include matcher to specify that a collection includes one or more expected objects. It succeeds if any object of the given collection passes the specified matcher. This works on any object that responds to #include? (such as a string or array):

```rb
 RSpec.describe "test" do
  it "include" do
    expect("a string").to include("a")
    expect("a string").to include(/a|str/).twice # 正規表現も使える
    expect("a string").to include("str", "g")
    expect("a string").not_to include("foo")
  end
end
```
```
test
  include 

Finished in 0.03171 seconds (files took 1.83 seconds to load)
1 example, 0 failures
```
```rb
  expect([1, 2]).to include(1)
  expect([1, 2]).to include(1, 2)
  expect([1, 2]).to include(a_kind_of(Integer)) # 要素のクラスを調べてるらしい
  expect([1, 2]).to include(be_odd.and be < 10 )
  expect([1, 2]).to include(be_odd)
  expect([1, 2]).to include(be < 10).at_least(2).times
  expect([1, 2]).not_to include(17)　# 含まれていないか？
```
```
test
  include

Finished in 0.03378 seconds (files took 1.85 seconds to load)
1 example, 0 failures
```
マッチャーはハッシュに対して柔軟な処理も供給する
The matcher also provides flexible handling for hashes:
```rb
  expect(:a => 1, :b => 2).to include(:a)
  expect(:a => 1, :b => 2).to include(:a, :b)
  expect(:a => 1, :b => 2).to include(:a => 1)
  expect(:a => 1, :b => 2).to include(:b => 2, :a => 1)
  expect(:a => 1, :b => 2).to include(match(/b/) => 2)
  expect(:a => 1, :b => 2).to include(match(/b/) => be_even)
  expect(:a => 1, :b => 2).not_to include(:c)
  expect(:a => 1, :b => 2).not_to include(:a => 2)
  expect(:a => 1, :b => 2).not_to include(:c => 3)
```
```
test
  include 

Finished in 0.03866 seconds (files took 1.45 seconds to load)
1 example, 0 failures
```
https://rspec.info/features/3-13/rspec-expectations/built-in-matchers/include/#:~:text=include%20matcher,%3D%3E%203

### 開いたページにdivタグが含まれていることもわかる
```rb
expect(response.body).to include("<div>")
```
### include?
https://docs.ruby-lang.org/ja/latest/class/String.html#I_INCLUDE--3F:~:text=include%3F(substr)%20%2D%3E%20bool,h%20%20%20%20%20%23%3D%3E%20true

### not_to
https://qiita.com/masatom86650860/items/bab5741a0b7b8e33362a
Fish Speech をローカルで動かしてみた

Fish Speech を使ってみたので, 手順と感想など

## Fish Speech とは

- May 25 2024 に発表された Text to Speech AI
- OSS
- Apache License 2.0
  - もともと商用利用不可のライセンスだったが, Dec 11 2024 のコミット (https://github.com/fishaudio/fish-speech/pull/740/commits/a2619791a13d8822b7d0b18c095192d6b39f88b7) で Apache 2.0 に変わった模様
- GitHub リポジトリ: https://github.com/fishaudio/fish-speech
- **日本語にも対応**

>Fish Speech V1.5 is a leading text-to-speech (TTS) model trained on more than 1 million hours of audio data in multiple languages.
>
>Supported languages:
>English (en) >300k hours
>Chinese (zh) >300k hours
>Japanese (ja) >100k hours
>German (de) ~20k hours
>French (fr) ~20k hours
>Spanish (es) ~20k hours
>Korean (ko) ~20k hours
>Arabic (ar) ~20k hours
>Russian (ru) ~20k hours
>Dutch (nl) <10k hours
>Italian (it) <10k hours
>Polish (pl) <10k hours
>Portuguese (pt) <10k hours

## 動作環境

- OS: Ubuntu Server 22.04.5 LTS
  - NVIDIA ドライバ: nvidia-driver-565-server
- CPU: AMD Ryzen 3700X
- RAM: DDR4 64GB
- GPU: NVIDIA RTX 3090 FE

## Fish Speech インストール

### 環境構築

参考文献: https://speech.fish.audio/ja/#linux

```sh
conda create -n fish-speech python=3.10
conda activate fish-speech

pip3 install torch==2.4.1 torchvision==0.19.1 torchaudio==2.4.1

apt install libsox-dev ffmpeg

apt install build-essential \
    cmake \
    libasound-dev \
    portaudio19-dev \
    libportaudio2 \
    libportaudiocpp0

git clone https://github.com/fishaudio/fish-speech.git
cd fish-speech

pip3 install -e .[stable]
```

### モデルファイルの配置

参考文献: https://github.com/fishaudio/fish-speech/blob/main/inference.ipynb

HuggingFace のファイルが一式ダウンロードされる.

```sh
huggingface-cli download fishaudio/fish-speech-1.5 --local-dir checkpoints/fish-speech-1.5/
```

### WebUI 起動

```sh
# 外部からアクセスできるようにする.
export GRADIO_SERVER_NAME="0.0.0.0"

python tools/run_webui.py \
    --llama-checkpoint-path checkpoints/fish-speech-1.5 \
    --decoder-checkpoint-path checkpoints/fish-speech-1.5/firefly-gan-vq-fsq-8x1024-21hz-generator.pth \
    --compile \
    --theme dark  # dark theme
```

7860 ポートにブラウザからアクセスする.

![{4B5FB618-E4CA-4C45-9C0E-B22C8A32655F}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191898/041d58f2-a822-68cd-7c98-bdbdaf270528.png)

「Reference Audio」でサンプルボイスを入力として追加すると,
サンプルボイスに似た声で音声が生成される.

![{ECA188E5-4F27-421A-A06E-10F88CD66AED}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191898/a1c55d9f-d3d8-83e3-1748-957777784c8b.png)

### 実行結果

Input Text

```
Fish Audio は、音声合成と音声処理を強化するために設計された多様なオーディオソリューションを提供します。主な製品には、先進的なテキスト読み上げ技術と深層学習モデルを活用した Fish Speech と Fish Diffusion が含まれています。これらのツールは、プロのサウンドデザインからカジュアルな使用までさまざまなアプリケーションに適しており、ユーザーがオーディオを効率的に作成、操作、合成できるようにします。革新的な機能を備えた Fish Audio のツールは、技術に精通したクリエイターもカジュアルなユーザーも柔軟に対応します。
```

Generated Audio

![audio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191898/07d3ed07-ed5e-82ca-fd2e-48bd10fc1c80.png)
※ wav 形式のファイルはアップロードできなかったため, 再生する場合は手元にダウンロードして拡張子を .wav に変更してください. (Qiita 不便だなぁ… # ﾟДﾟ)
Microsoft Certified: Fabric Analytics Engineer Associate(DP-600)合格備忘録

### ■受験の目的
MicrosoftFabricのサービスの概要を理解するため。
Microsoft Certified: Fabric Analytics Engineer Associate(DP-600)の認定を受けるため。

### ■出題範囲
シラバスはMicrosoft公式から参照します。
https://learn.microsoft.com/ja-jp/credentials/certifications/resources/study-guides/dp-600

### ■受験の前提
中級試験の位置づけですが、特に事前に合格が必要な試験などはありません。
PowerBIDesktopおよびPowerBIサービスの開発に携わっていると入りやすいです。
Fabricサービスと個々のコンポーネントも覚える必要がありますが、
基本的にはBIや分析サービスを中心とした試験範囲になっています。
そのほかにもSQLクエリ、KQLクエリ、DAX式など細かいデータ操作言語も覚える必要があります。

### ■受験のメリット
Fabricのアーキテクチャやコンポーネントを学ぶための入りとして利用すると良いです。
データエンジニアリングよりもBIや分析で使用するところが範囲となりますので、
データアナリスト、データサイエンティスト向けの試験となります。

### ■教材
MicrosoftLearningで学習します。このあたり無料で詳しく体系的に学べるのはありがたいです。
PC端末限定ですが、ラボもあります。
https://learn.microsoft.com/ja-jp/training/courses/dp-600t00
※個人のMicrosoftアカウントがあれば、PCやスマホなどで進捗を同期できるので、いつでも続きから学習できます。

### ■模擬試験
模擬試験はUdemyで購入
https://www.udemy.com/course/microsoft-dp-600-practice-exam-test/
あまり時間がなかったため、解説を2周ほど読み込み理解しました。
添付URLのリファレンスも読み込んでおくと良いです。

### ■学習期間
筆者の場合、ラーニングを1週間、模擬問題と解説を3日間ほどで学習しております。
過去にPowerBIでの開発経験がありましたので、DAXはある程度理解していましたが、
使用したことのない関数や仕組みがありましたので、改めて見ると多様なDAXコーディングで
機能実装できたり、パフォーマンスチューニングできる点は目から鱗でした。
PowerBIのDAX実装を一から学びたい方にもおすすめです。

### ■実際の本試験
日本語に対応した試験が発行されていましたので、そちらで受験しています。
全70問の制限時間は100分でした。問題数は毎回変わるのでご注意ください。

以下の内容でした。
全問題：70問
　　L　通常問題：56問
　　L　共通題目で回答後戻れない問題：5問
　　L　ケーススタディ問題：9問　※遷移後、通常問題に戻れません。

⇒ケーススタディと通常問題の前後も入れ替わるかもしれません、ご注意ください。

最近の中級試験以上は、試験制度が変わったようで
テストセンター受験であっても、試験中に左のボタンからLearningを参照できるようになっているようです。ただ、時間が限られているのでLearningは、あくまでも最終手段であることを念頭に学習はしておいた方が良いです。

7割以上が合格ラインです。
結果は8割4分以上のスコアで、初回受験としては満足のいく結果でした。
※試験中のLearningは、参照していない参考値になります。
Discord.jsでサイレントメッセージを送る

いろいろな記事を探して回りましたが、discord.jsでsilentのメッセージを送る方法がほとんど見つからなかったのでここに書いておきます。
<br>

**環境**
`node.js v16.14.2`
`discord.js v13.14.0`
<br>

以下のように書くことで、silentでメッセージを送信することができる。

:::note warn
Discord.js v14以降の場合、MessageFlagsではなくMessageFlagsBitFieldに変更されている。
:::

~~~code.js
//MessageFlagsを指定しておかないとエラーが出る.
const { MessageFlags } = require('discord.js');
const flags = MessageFlags;

//MessageFlags.bitfieldを4096にするとサイレントになる.
messsage.reply({content: 'silentメッセージです', flags: MessageFlags.bitfield=4096})
~~~

**結果**
![スクリーンショット 2025-01-18 163245 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989121/18a0eeb4-55f1-030b-8210-46704762b260.png)

<br>

ちなみに、console.logでmessageの内容を出力すると、bitfieldが違うことが分かる。

~~~:silentメッセージ
<ref *1> Message {
  channelId: '0000000000000000000',
  guildId: '0000000000000000000',

  ...(中略)...
  
  webhookId: null,
  groupActivityApplication: null,
  applicationId: null,
  activity: null,
  flags: MessageFlags { bitfield: 4096 },
  reference: null,
  interaction: null
}
~~~

~~~:通常メッセージ
<ref *1> Message {
  channelId: '0000000000000000000',
  guildId: '0000000000000000000',

  ...(中略)...
  
  webhookId: null,
  groupActivityApplication: null,
  applicationId: null,
  activity: null,
  flags: MessageFlags { bitfield: 0 },
  reference: null,
  interaction: null
}
~~~
このように、通常メッセージはbitfieldが0,silentのメッセージはbitfieldが4096になっているため、
flags: MessageFlags.bitfield=4096を指定してやることでサイレントメッセージを送信できるわけです。
<br>

**参考**
https://stackoverflow.com/questions/76517603/how-to-send-a-silent-message-with-discord-js
Dartでも戻り値を複数個返したい！

## はじめに

関数やメソッドのコーディングをしていると

「戻り値を複数個返したい」

そんな時ってありませんか？

特にGo言語など、デフォルトでそれが出来る言語の経験があると、

「自分が今使っている言語でも出来たらなぁ〜」

だなんて思ってしまいます...

「戻り値をクラス型にすれば良いのでは...🤔」

とも思いますが、クラスに切り出す（抽象化する）程でもない時もありますよね...💦

## Recordを使ってみよう！

そんな時、Dartには「Record」と言う便利なものがあります！

これは「複数の値を集約した不変の匿名型を表現するもの」なのですが、

これを使えば抽象化しなくても戻り値を複数個返せそうですよね！？

実際に簡単なサンプルを書いてみました。

```dart
(String, int) getUserInfo() {
  return ('Tanaka Taro', 6);
}

void main() {
  final (name, age) = getUserInfo();
  print('Name: $name, Age: $age');
}
```

上記のコードは`getUserInfo()`と言う関数を実行すると

静的な値のまとまりを返し、`print`関数で出力するものです。

これでも良いのですが、

「戻り値の名前は特定のものにして、意味を持たせたい」

「より安全で保守性のあるものにしたい」

そういう時もありますよね...？

そんな時は...

```dart
({String name, int age}) getUserInfo() {
  return (name: 'Tanaka Taro', age: 6);
}

void main() {
  final person = getUserInfo();
  print('Name: ${person.name}, Age: ${person.age}');
}
```

このように名前付きフィールドを使うことで、

コードをより安全にすることもできます。

## Future型でもやってみた！

もちろん、この書き方は非同期な型にも使えます！

```dart
Future<(String, int)> fetchUserData() async {
  // APIからデータを取得するシュミレーション
  await Future.delayed(Duration(seconds: 2));
  return ('Tanaka Taro', 6);
}

void main() async {
  print('Fetching user data...');
  final (name, age) = await fetchUserData();
  print('Name: $name, Age: $age');
}
```

または、名前付きフィールドを使うと...

```dart
Future<({String name, int age})> fetchUserData() async {
  // APIからデータを取得するシミュレーション
  await Future.delayed(Duration(seconds: 2));
  return (name: 'Tanaka Taro', age: 6);
}

void main() async {
  print('Fetching user data...');
  final person = await fetchUserData();
  print('Name: ${person.name}, Age: ${person.age}');
}
```

このように表現することもできます。

## まとめ

今回はRecordを使うことで複数戻り値を返すコードを書いてみました。

「抽象化する程ではないけど、コードの可読性や保守性を上げたい」

そんな時に使えそうだと感じました😄

## 参考

[Flutter実践開発](https://gihyo.jp/book/2024/978-4-297-13993-3)

[Dart 3 のRecord:複数の戻り値を効率的に扱う](https://flutter.salon/dart/dart-3-record/)

[Dart3のRecordについて](https://zenn.dev/masakunn/articles/75f029ed193cf2)
Laravel Sailによる環境構築

## 目的
Dockerでの設定なしで気軽に環境構築ができるLaravel Sailを使ってみる

## 手順
以下のコマンドを実行すると一発でLaravelの環境(example-app)が構築される
```
curl -s "https://laravel.build/example-app" | bash
```

このコマンドの中でMySQLやRedis、Seleniumといったツールのインストールや必要なDockerイメージのpullからビルド、そして起動までを行います。

時間をおいてコンテナが起動した後
```
cd example-app
```

でディレクトリを移動し、sessionsやusersといった初期テーブルを作成するためmigrateするコマンドを実行します

```
./vendor/bin/sail artisan migrate
```

http://localhost
にアクセスして以下のような画面が表示されれば環境構築は完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2435396/3ff71903-1119-eed2-c05e-160a686b4405.png)
【AWS SAP】AWS IoT Coreとは

# AWS IoT Coreとは
AWS IoTは、デバイスからクラウドにデータを安全に送受信し、デバイス管理やリアルタイム処理を可能にするサービス群です。

## 例えば…
以下の要件があるとします。
- 工場のセンサーからデータを効率的に収集する
- AWS IoT CoreでセンサーデータをAWSに送信する
- データをAmazon S3に保存する前に拡張処理を行う
- センサーデータを5秒間隔でリアルタイムに送信する
- データ収集後30分以内にAmazon S3で利用可能にする
- IoT Coreのデータは他アプリケーションで処理しない

## フローにするとこんな感じ
```mermaid
sequenceDiagram
    participant Sensor as センサー
    participant IoTCore as AWS IoT Core
    participant Firehose as Amazon Kinesis Data Firehose
    participant Lambda as AWS Lambda データ拡張
    participant S3 as Amazon S3

    Sensor->>IoTCore: センサーデータ送信 5秒ごと
    IoTCore->>Firehose: ルールアクションでFirehoseに転送
    Firehose->>Lambda: データ拡張のためLambda呼び出し
    Lambda-->>Firehose: 拡張されたデータをFirehoseに戻す
    Firehose->>S3: 拡張されたデータをS3に保存
```
## ポイント
Firehoseはデータをまとめて処理し効率化を実現し、リアルタイムデータをバッチ処理に変換してコスト削減を可能にします。また、AWS Lambdaと連携してデータの変換や拡張を簡単に行え、IoT CoreからS3へのデータ転送を簡素化できます。さらに、複数サービスへの同時配信や高スループットでの大量データ処理に対応し、配信エラー時のリトライ機能でデータ損失を防ぎます。加えて、自動スケーリングにより運用管理の負担を軽減します。

:::note info
**AWS IoT Core Basic Ingest**は、AWS IoT CoreでIoTデバイスからクラウドにデータを直接送信する方法で、ルールエンジンを介さず効率的かつ低コストにデータ転送を実現します。
:::
【Go言語】バックエンド開発の基本 - WebAPI/DB操作/JSONハンドリング学習メモ

# Goでのバックエンド開発学習記録 - WebAPI、DB操作、JSONハンドリング編

こんにちは！フリーランスエンジニアのこたろうです。

普段はバックエンド開発を中心に活動しています。今回は自身の学習記録として、Go言語でのバックエンド開発について学んだことをまとめてみました。WebAPI、データベース操作、JSONハンドリングなど、基本的な実装方法を解説していきます。

## 目次

1. Web APIの基礎
2. JSONの取り扱い
3. データベース操作
4. トランザクションとテスト

## 1. Web APIの基礎

### HTTPメソッドの制御

```go
func handler(w http.ResponseWriter, r *http.Request) {
    // 許可するメソッドを指定
    if r.Method != http.MethodPost {
        w.WriteHeader(http.StatusMethodNotAllowed)
        return
    }
    // 処理
}
```

### gorilla/muxを使用したルーティング

```go
router := mux.NewRouter()
router.HandleFunc("/api/items/{id}", handler).Methods("GET")
```

### パラメータ取得

```go
// パスパラメータ
vars := mux.Vars(r)
id := vars["id"]

// クエリパラメータ
query := r.URL.Query()
name := query.Get("name")
```

## 2. JSONの取り扱い

### 構造体とJSONの変換

```go
type Item struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

// レスポンスとしてJSONを返す
json.NewEncoder(w).Encode(item)

// リクエストのJSONを構造体に変換
var item Item
json.NewDecoder(r.Body).Decode(&item)
```

### デコーダ・エンコーダの活用

```go
func readJSON(reader io.Reader, v interface{}) error {
    decoder := json.NewDecoder(reader)
    return decoder.Decode(v)
}

func writeJSON(writer io.Writer, v interface{}) error {
    encoder := json.NewEncoder(writer)
    return encoder.Encode(v)
}
```

## 3. データベース操作

### 基本的なDB操作

```go
// DB接続
db, err := sql.Open("postgres", "connection_string")
if err != nil {
    log.Fatal(err)
}
defer db.Close()

// クエリの実行
rows, err := db.Query("SELECT id, name FROM items")
if err != nil {
    log.Fatal(err)
}
defer rows.Close()

// 結果の取得
for rows.Next() {
    var item Item
    err := rows.Scan(&item.ID, &item.Name)
    if err != nil {
        log.Fatal(err)
    }
    // 処理
}
```

### NULLの取り扱い

```go
type Item struct {
    ID          int
    Description sql.NullString
}
```

### クエリパラメータの使用

```go
row := db.QueryRow("SELECT id, name FROM items WHERE id = $1", id)
var item Item
err := row.Scan(&item.ID, &item.Name)
```

### 更新処理

```go
result, err := db.Exec("UPDATE items SET name = $1 WHERE id = $2", name, id)
if err != nil {
    log.Fatal(err)
}
rowsAffected, _ := result.RowsAffected()
```

## 4. トランザクションとテスト

### トランザクション処理

```go
tx, err := db.Begin()
if err != nil {
    log.Fatal(err)
}

// トランザクション内の処理
_, err = tx.Exec("INSERT INTO items (name) VALUES ($1)", "新しいアイテム")
if err != nil {
    tx.Rollback()
    log.Fatal(err)
}

err = tx.Commit()
if err != nil {
    log.Fatal(err)
}
```

### ユニットテスト

```go
func TestItemCreate(t *testing.T) {
    // テストケースの準備
    item := Item{Name: "テストアイテム"}
    
    // テストの実行
    result, err := createItem(item)
    
    // 検証
    if err != nil {
        t.Errorf("期待しないエラー: %v", err)
    }
    if result.ID == 0 {
        t.Error("IDが設定されていません")
    }
}
```

## まとめ

Goでのバックエンド開発における基本的な実装方法を紹介しました。WebAPI、データベース操作、JSONの取り扱いなど、実践的な知識を整理しています。

## 参考文献

- 『Goで作るはじめてのWebアプリケーション 改訂版』技術書典
  - [https://techbookfest.org/product/jXDAEU1dR53kbZkgtDm9zx](https://techbookfest.org/product/jXDAEU1dR53kbZkgtDm9zx)
---
型 'IntrinsicAttributes & boolean' に割り当てることはできません。

Reactは初心者です。

HTML, CSSは昔案件とったりしてたけど全て記憶が飛んでるし、Reactはだいぶ前にちらっと触ってまだ何やるのも新鮮だし、UI作るの楽しい。

まずは早く完全に理解したレベルに入りたい。

<br>
ちゃんと体系立てて勉強した人からみると変なことをやってるでしょうが、同じつまづき方する人がいるかもしれないので備忘録を兼ねて書きます。

# やりたいこと
さて、メインコンポーネントの処理内容によって画面に適用するCSSを変更したい、というのが今回やりたいことです。
簡略化するとこういうコードを書いてました。
(やりたいこと優先だった当時の自分を表現するのにタグ内には気持ちを記述してます。)

```typescript App.jsx
function App() {
  const [StateA, setStateA] = useState(false);
  return (
    <div>
      <Header {/* StateAを持たせたい*/} />
      <div className='App'>
        <MainComponent {/*StateAとsetStateAを持たせてStateAを変化させたい*/} />
      </div>
    </div>
  );
}
```

HeaderコンポーネントとMainComponentコンポーネントにStateAとsetStateAをpropsとして渡して制御していくことになります。

# 作業内容

### App.jsx
それを踏まえるとAppコンポーネントでは下のように修正が入ります。

```tsx
function App() {
  const [stateA, setStateA] = useState(false);  
  return (
    <div>
      <Header stateA={stateA} />
      <div className='App'>
        <MainComponent stateA={stateA} setStateA={setStateA} />
      </div>
    </div>
  );
}
```

### Headerコンポーネント
さて、次にとりあえずHeaderコンポーネントでは

```typescript
function Header(isRunning: boolean){
    {/* 以下省略 */}
    
```

と書いてみました。(必要な時まであんまり調べないでやってみてるため不勉強が続きます)


さて、これだとAppコンポーネントの方では
```
“型 '{ stateA: boolean; }' を型 'IntrinsicAttributes & boolean' に割り当てることはできません。ts(2322)”
```
という表示が出ます。

というわけでpropsの渡される側のコンポーネントに型宣言が必要ということで、interfaceを使って

```typescript
interface StateAProps {
    stateA: boolean;
}

fucntion Header({stateA}: StateAProps){
    {/* 以下省略 */}
```

という感じで変更します。何が変わっているかというと

* interfaceでの型宣言
* stateAを{}でくくって渡している(StatePropsで型宣言)

これでエラーが出なくなり、最初にやりたかったMainComponentで状態が変わった時にHeaderも含めcssの内容を変更することができました。

# まとめ

1. Reactでpropsを渡す際は、受け取る側のコンポーネントで適切な型定義が必要
2. TypeScriptではinterfaceを使って型を定義できる

普段pythonしか触ってませんが、うろ覚えで「これで文法正しかったらいいな」って感じでとりあえずやってみると一筋縄ではいかないって話でした。
インターネットコンピュータープロトコル (ICP) で未来のインターネットを解き放つ

インターネットコンピュータプロトコル（ICP）は、インターネットを分散型で安全かつスケーラブルなプラットフォームへと変革するための大胆な取り組みです。開発者、ユーザー、企業が完全にオンチェーンでアプリケーションを構築し、利用できるようにすることで、ICPは従来のインフラ依存を排除し、コストを削減します。


ICPは、バックエンドサービスやデータベースを直接ブロックチェーン上にデプロイできるようにすることで、アプリケーション開発を簡素化します。また、RustやMotokoなどの馴染みのあるプログラミング言語をサポートしており、学習曲線を緩和し、従来のプラットフォームからの移行をスムーズにします。これにより、開発者はサーバー管理やスケーリング、運用上の負担を心配することなく、イノベーションに集中することができます。

主な利点:

- トラフィックの増加に対応するためのCanisterスマートコントラクトによる自動スケーリング。
- 従来のクラウドサービスを予測可能で透明なリソースモデルに置き換えることで、コストを大幅に削減。
- 改ざん防止インフラストラクチャや分散型プライバシーを含むセキュリティ機能の組み込み。
- 世界中のユーザーが迅速にアクセスできる、地理的制約のない分散型ネットワーク。

ICP は、以前は実現不可能だったユニークなアプリケーションの開発の新しい可能性を開きます。

- DeFi と GameFi: 高度な金融プラットフォームやゲームプラットフォームを完全にオンチェーンで構築できます。

- 分散型ソーシャルメディア: 検閲不可能で、ユーザーが所有するソーシャルネットワークを実現します。

- AI 統合: ICP を使用して、分散型の AI ツールを展開および実行できます。

- 開発者は、コラボレーションと学びを促進する活気あるエコシステムの恩恵を受けます。

- ハッカソンと助成金: ICP は、革新的なプロジェクトに対して財政的支援とメンターシップを提供します。
活発な開発者コミュニティ: 同じ志を持つ仲間と協力し、開発を加速できます。


ICPはその革新的な可能性を秘めていますが、いくつかの課題に直面しています：

- ICPは技術的な利点を持ちながらも、Ethereum、Solana、Binance Smart Chainといった既存のプラットフォームと競争しなければなりません。これらのプラットフォームは既に多くの開発者やユーザーコミュニティを有しています。慣れ親しんだエコシステムからICPへ移行するよう、開発者を説得すること。

- ICPの独自機能であるCanisterやMotokoプログラミング言語は、開発者にとって初めは学習コストが高い場合があります。これらの概念に不慣れな開発者のオンボーディング. ICPエコシステムは、開発者教育に注力し、詳細なドキュメント、ツール、助成金やハッカソンといったインセンティブを提供し、参入障壁を下げています。

- AWS、Google Cloud、Azureといった中央集権型クラウドサービスは、その使いやすさと信頼性のために市場を支配しています。長期的なコスト削減、強化されたセキュリティ、ベンダーロックインの排除を強調することで、ICPは先進的な開発者や企業にとって魅力的な選択肢として位置付けられています。


- 分散化は、遅延やユーザー体験の低下といったトレードオフを伴うことがあります。ICP上の分散型アプリケーションが中央集権型ソリューションのパフォーマンスに匹敵することを確保すること。


- すべてのブロックチェーンプロジェクトと同様に、ICPも採用に影響を与える可能性のある規制の変化に直面しています。世界中のさまざまな規制環境を乗り越えること。


ICPの実例: 現在の活用事例

- Distrikt: ICP上に構築された分散型のプロフェッショナル向けソーシャルネットワークプラットフォームです。LinkedInのような従来のネットワークとは異なり、ユーザーが自分のデータを完全に管理でき、検閲に強く、ユーザー所有型の仕組みを実現しています。
- OpenChat: WhatsAppやTelegramの代替となる分散型メッセージングアプリです。OpenChatは完全にInternet Computer上で動作し、プライバシーを確保し、大手テック企業によるデータ収集を回避します。
- CanCan: TikTokに似た分散型の動画共有プラットフォームです。CanCanは、ICPのスケーラビリティと高負荷アプリケーションを処理する能力を証明しています。
- DSCVR: Web3技術を活用した分散型のReddit代替サービスです。DSCVRは、トークンを使ってコンテンツ作成をインセンティブ化し、ユーザーのエンゲージメントと所有権を強化することを目的としています。


ICP は、開発者にとって革新的なプラットフォームであり、アプリケーション開発の簡素化、コスト削減、セキュリティの強化、そして無限のスケーラビリティを提供します。これにより、開発者は従来のインフラの制約から解放され、分散型インターネットの未来を築くことができます。ICP は、クラウドサービスに依存せず、オンチェーンでの計算とストレージを実現し、データの整合性とプライバシーを確保します。さらに、分散型金融（DeFi）やゲーム、ソーシャルメディア、AI 統合など、さまざまな分野での革新的なアプリケーションの開発を支援します。また、ハッカソンや助成金を通じて開発者の活動をサポートし、活発なコミュニティの中でコラボレーションと学びの機会を提供します。
【AWS SAP】ALBの502エラー処理とカスタムエラーページ配信

# ALBの502エラー処理とカスタムエラーページ配信
## 要件
- ALBの502エラー発生時にカスタムエラーページを提供すること
- 運用オーバーヘッドを最小限に抑えること
- カスタムエラーページを静的コンテンツとして提供すること
- AWSのサービスを活用して実現すること
- 高可用性とパフォーマンスを維持すること
- エラーページを簡単に更新可能であること


```mermaid
graph TD
    A[ユーザー] -->|リクエスト| B[CloudFront]
    B -->|正常なリクエスト| C[ALB]
    C -->|バックエンド処理| D[EC2インスタンス]
    B -->|エラー発生 502| E[S3カスタムエラーページ]

    subgraph ALBとバックエンド
        C
        D
    end

    subgraph 静的コンテンツ
        E
    end
```
WebSocketでのチャットアプリにてCORSポリシーでブロックされてしまった件

# 概要
React を用いた WebSocket チャットアプリケーションの開発中に、CORS ポリシーによるエラーが発生しました
そのエラーを解決した手順、原因を記載します

# 環境
- クライアント側
  - React: 18.3.1
  - Vite: 6.0.5
  - TypeScript: 5.6.2

- サーバー側
  - Node.js: 21.2.0
  - Express: 4.21.2
  - WebSocket: 4.8.1

- 実行環境
  - クライアント: http://127.0.0.1:5173
  - サーバー: http://localhost:3001

# 不具合事象
WebSocketで実装したチャットアプリにて
クライアントからサーバーに接続しようとしたが、以下のエラーがブラウザのコンソールに表示されていた

``` sh
Access to XMLHttpRequest at 'http://localhost:3001/socket.io/?EIO=4&transport=polling&t=t8qibza8' from origin 'http://127.0.0.1:5173' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:5173' that is not equal to the supplied origin.
useChatService.ts:31 
```

その他、以下のログも出ていた

``` sh
GET http://localhost:3001/socket.io/?EIO=4&transport=polling&t=... net::ERR_FAILED 200 (OK)
```

# 原因と修正した内容

## 原因
ブラウザのセキュリティ機能である CORS (Cross-Origin Resource Sharing) によって、クライアント (http://127.0.0.1:5173) とサーバー (http://localhost:3001) の間でクロスオリジンのリクエストがブロックされていました。
この問題は以下事由によって発生していました
- サーバーが送信している Access-Control-Allow-Origin ヘッダーが http://localhost:5173 であった
- クライアントのURL が http://127.0.0.1:5173 であった

よって、ブラウザがオリジンの不一致を検出して上述のエラーが発生。通信がブロックされていた模様

## 修正内容
### 修正点1. サーバー側で CORS 設定を修正

#### 修正前のコード
``` ts
const io = new Server(server);
```

#### 修正後のコード
```ts
const io = new Server(server, {
  cors: {
    origin: ["http://localhost:5173"],
    methods: ["GET", "POST"]
  }
});
```

### 修正点2. クライアント側でサーバー接続先を明記
viteを使用しているので、```vite.config.ts```  に以下追記

```ts
export default defineConfig({
  server: {
    host: "localhost", 
    port: 5173,
  },
});
```

### 修正点3. クライアント側でio() の接続先を明記
socket.io-client を使って WebSocket インスタンスを生成しているが、io()の接続先を明記する

#### 修正前のコード
``` ts
socketRef.current = io();
```

#### 修正後のコード
```ts
socketRef.current = io("http://localhost:3001");
```

# まとめ
クライアント側とサーバー間のCORS設定が明記されていないのが原因でした
もし、上述のエラーが出ていた場合、本記事で記載個所を見直されると良いかと思います
閉域アクセスでのS3、APIGWのカスタムドメイン利用

# はじめに
DirectConnectやVPNなど閉域利用でAPIGatewayやS3の静的コンテンツ公開機能、署名付きURLを使いたいケースはよくあることです。今回はそういったケースでどのような設計が可能かを解説していきます。


# 想定する構成
![スクリーンショット 2025-01-11 20.52.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584167/99426d14-858b-a094-511d-729d0b2c493e.png)
まずはインターネット公開のケースで考えてみます。よくあるフロントエンドとバックエンドAPの構成です。
この場合、Route53により、CloudFront、APIGatewayをカスタムドメインで名前解決し、対象のFQDNのIPアドレスに接続をすることで、AWSのリソースにアクセスできます。実際には、各AWSリソースに対してエイリアスレコードを定義することで、カスタムドメインが利用できます。また、各リソースにHTTPSで接続する場合は、ACMに証明書を登録し、各リソースにアタッチすることで、カスタムドメインを利用したHTTPS接続が可能です。

# 閉域での構成
![スクリーンショット 2025-01-11 20.53.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584167/fcab75bf-51dd-023a-e4d1-d558268117cc.png)
このような構成になります。
まず、S3に関しては、ALBを利用します。インターナルALBを作成し、カスタムドメインの証明書をACMにインポートし、ALBにアタッチします。また、ターゲットとして、S3VPCエンドポイントのインターフェイスタイプのIPアドレスを指定します。なお、マルチAZ構成の場合は、AZ毎にエンドポイントを作成、指定しましょう。ALBに対して、Route53などのDNSにより、ALIASレコード、またはCNAMEレコードによりカスタムドメインの名前解決を設定します。S3はACMで発行する証明書で指定したカスタムドメインと同じバケット名とします。これにより、S3に対してRESTAPIによる接続が可能となります。

https://aws.amazon.com/jp/blogs/news/internal-static-web-hosting/

次にAPIGatewayを考えてみましょう。
APIGatewayについてもS3同様ALBとVPCエンドポイントを利用した構成が一般的でしたが、最近、カスタムドメインに対応しました。これにより、閉域構成でも、VPCエンドポイントへの接続でカスタムドメインを利用できます。APIGatewayでプライベートAPIを作成、カスタムドメインを登録します。カスタムドメインの登録には、ACMでインポートした証明書の紐づけが必要です。カスタムドメインをマッピングし、VPCエンドポイントと紐づけます。これにより、VPCエンドポイントに接続した際にカスタムドメインが利用可能になります。Route53などのDNSにより、ALIASレコード、またはCNAMEレコードによりカスタムドメインの名前解決を設定することで、クライアントからの接続が可能になります。

https://aws.amazon.com/jp/about-aws/whats-new/2024/11/amazon-api-gateway-custom-domain-name-private-rest-apis/

# まとめ

本記事では、DirectConnectやVPNなどの閉域環境において、AWSのAPIGatewayやS3の静的コンテンツ公開機能をカスタムドメインで利用する方法について解説しました。
上記構成を取ることで以下のメリットがあります。
- **EC2プロキシサーバが不要**  
  従来の閉域環境では、EC2上にプロキシサーバを配置する必要がありましたが、今回の構成では不要となります。これにより、運用負担やコストを削減できます。
  
- **効率的でシンプルなアーキテクチャ**  
  VPCエンドポイントやALBを活用することで、よりシンプルかつ安全な閉域ネットワーク設計が可能です。

これらの設計を活用することで、閉域環境においてもインターネット接続同様効率的にAWSリソースを運用できます。
VSCodeの JavaScript のスニペットがうまく動かないときに見る記事

# 結論
以下を `.vscode/setting.json` もしくは ユーザ用 `setting.json` に追加する。
```js:setting.json
{
    "[javascript]": {
        "editor.snippetSuggestions": "top",
        "editor.quickSuggestions": {
            "other": true,
            "comments": true,
            "strings": true
        }
    }
}
```

# さらにカスタマイズ
https://qiita.com/aki77/items/dc0287605ffc43bc9114
【React 入門】初心者必見 React の基礎知識

## はじめに

この記事では、React 初心者の方向けに、React の基礎知識をわかりやすく解説します。React を使い始めたいけど「何から始めればいいかわからない」という方は、ぜひ参考にしてください。
React の概要を知ってもらえるように詳細な説明は省いています。各知識のより詳しい内容については別の記事として、今後投稿していきたいと考えています。

## React とは？

React は、Facebookが開発した JavaScript ライブラリで、ユーザーインターフェース（UI）を効率的に構築するために使用されます。  
現在、世界中の多くの開発者や企業が採用しており、以下のような特徴があります。

### 特徴

1. **コンポーネントベース**  
   UI を「コンポーネント」という小さな部品に分けて開発できます。再利用性が高く、保守性にも優れています。

2. **仮想 DOM (Virtual DOM)**  
   React は、実際の DOM 操作を効率化するために仮想 DOM を使用します。これにより、UI の更新が高速化されます。

3. **宣言的プログラミング**  
   「状態」に基づいて UI を構築するため、コードが直感的で読みやすくなります。

## React を始めるために必要な知識

React を学ぶ前に、以下の基本的な知識があるとスムーズに学習できます。

1. **HTML と CSS**  
   ウェブページの構造とスタイルを理解しておきましょう。

2. **JavaScript**  
   特に以下の概念を把握しておくと便利です。

   - JavaScript の基本（`let` / `const`、アロー関数、分割代入など）
   - 配列操作（`map`、`filter`、`reduce`など）
   - モジュール (`import` / `export`)

3. **Node.js と npm**  
   React プロジェクトのセットアップやパッケージ管理に使われます。

## React の基本概念

React を理解する上で重要な基本概念を説明します。

### 1. コンポーネント

React アプリケーションは、コンポーネントという小さな部品から成り立っています。  
コンポーネントには 2 種類あります。

- **関数コンポーネント**（主流）  
  シンプルで軽量なコンポーネント。多くの場面で使われるのはこちらになるので、コンポーネントと聞いたらこの関数コンポーネントのことをイメージすれば良いと思います。
  ```jsx
  function HelloWorld() {
    return <h1>Hello, World!</h1>;
  }
  ```
  <br>
- **クラスコンポーネント**（旧式）  
   状態を持つコンポーネント。
  ```jsx
  class HelloWorld extends React.Component {
    render() {
      return <h1>Hello, World!</h1>;
    }
  }
  ```

### 2. JSX

JSX は、JavaScript 内で HTML のような構文を記述するための拡張機能です。
ブラウザでは直接動きませんが、React が内部的に変換してくれます。

```jsx
const element = <h1>Hello, React!</h1>;
```

### 3. Props（プロップス）

Props は、コンポーネント間でデータを渡すための仕組みです。
親コンポーネントから子コンポーネントにデータを渡します。

```jsx
const Greeting = (props) => {
  return <h1>Hello, {props.name}!</h1>;
};

<Greeting name="React" />;
```

### 4. State（ステート）

State は、コンポーネント内で持つ変更可能なデータです。
useState フックを使うことで、簡単に状態を管理できます。

```jsx
import { useState } from "react";

const Counter = () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>現在のカウント: {count}</p>
      <button onClick={() => setCount(count + 1)}>増加</button>
    </div>
  );
};
```

### 5. イベントハンドリング

```jsx
const Button = () => {
  const handleClick = () => {
    alert("ボタンがクリックされました！");
  };

  return <button onClick={handleClick}>クリック</button>;
};
```

## React の始め方

React を始めるための手順については、以下の Qiita 記事で説明しています。

https://qiita.com/masa12Y/items/0d8b59854bf6d98a3bdf

この記事では、Node.js のインストールから、`create-react-app`を使った React プロジェクトの作成方法まで解説しています。React を初めて使う方は、まずこちらを参考に環境を構築してみましょう！

## 参考

- React 公式ドキュメント

https://ja.react.dev/learn/

- Qiita React タグ

https://qiita.com/tags/react


## まとめ

この記事では、React の基本的な概念と始め方を紹介しました。  
React は最初は少し難しく感じるかもしれませんが、少しずつ慣れていくことで楽しく開発できるようになると思います。まずは小さなプロジェクトを作りながら、実践的に学んでみてください。
GMailであるメールへのユニークなリンクを取り出したい

今のご時世、なんかに対してユニークなリンク(URL)を得て、それをいい感じに使うのはあたりまえだが、GMailのとあるメールに対してそのあたりまえの機能がない。ふぁっきんしっとである。

メールに対するユニークなIDといえば、メッセージIDと決まっている。以下を読むこと。

https://datatracker.ietf.org/doc/html/rfc822#section-4.6.1

GMailの検索欄でこれをクエリに使えれば検索しても必ず1件ヒットだからいいんじゃね？ということで調べてみたらまさにジャストここに書いてあるやんけ。

https://support.google.com/mail/answer/7190?hl=ja

> rfc822msgid
> 特定の Message-ID ヘッダーを含むメールを検索します。
> rfc822msgid:200503292@example.com

そういうわけでこれを使えばほぼリンクとして取り出せる。
検索し、そのURLをシェアすればよい。例えばこんな感じで入力する。

![スクリーンショット 2025-01-18 15.59.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50220/5cf5605e-df85-f35c-402d-cf0d31dd79da.png)

しかし、ログインユーザー番号がURLに入ってしまっているのはイマイチなのでシェアは厳しいか。まぁ俺向けのメモとしては実用できるレベルには問題なさそう。

```
https://mail.google.com/mail/u/0/#search/rfc822msgid%3A20241021164437.6A0HY.390.root%40mwebp12
```

↑ここの `u/0` が邪魔な部分。