OmniAICreator/Qiita-1.07M huggingface dataset:
Qt Creator を微かに改善してみました

# はじめに

この記事は [Qt Advent Calendar 2024](https://qiita.com/advent-calendar/2024/qt) 19日目の記事です。

一昨日は @Ndgt さんによる [3DCG分野からの Qt/PySide 入門記](https://zenn.dev/nadegata_memo/articles/qt_intro_from_3dcg) でした。

結構昔から Maya が Qt で作られていて、Qt を使ったプラグインで拡張できるのは知識としては知っていましたが、それ以外にも幅広く使われているんですね。

---

今日は、Qt Creator にちょっとしたパッチを送ったのでそれを記事にしました。

# きっかけ

最近 [Slint](https://qiita.com/advent-calendar/2024/slint) という Qt とは別の GUI フレームワークをよく使っているのですが、プロパティの設定画面でホイールをスクロールしていたらイライラしました。

![slint-scroll-combobox.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13867/1596289f-5a1b-df3a-7cdb-01234e3d621a.gif)

そしてバグ報告をしようと思ったら、すでに報告されていました。

https://github.com/slint-ui/slint/issues/5929

そこで開発者の１人が以下のようにコメントしていました。

> Thanks for the bug report.
> We should do the same as what the platform natively does.
> I tried Qt and the wheel does change the combobox even within scroll area.
> On windows, it seems that the wheel only change the content of the combobox > if it has focus.

それで、昔 Qt Creator で同じ問題にいらっとして修正したことを思い出しました。

[QComboBox: not accept wheel events for changing values](https://codereview.qt-project.org/c/qt-creator/qt-creator/+/429103)

その詳細を調べようと Qt Creator を起動したら、同じような別の問題を見つけてしまいました。

![qt-creator.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13867/78f8c806-786b-a0f2-86c9-89006163b374.gif)

多分、昔は CMake 使ってなかったので、普段 Qt Creator で操作するところに QTabBar が無かったんじゃないかなと思います。


# 直してみました

私の上記の変更をとりあえず受け入れた上で、開発者の１人がもっといい感じにしてくれたので、その仕組みをここの QTabBar に対して適用するような簡単な変更をしました。

```diff
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
index 80b249620b9..013402b5923 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
@@ -227,6 +227,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
     m_configurationStates = new QTabBar(this);
     m_configurationStates->addTab(Tr::tr("Initial Configuration"));
     m_configurationStates->addTab(Tr::tr("Current Configuration"));
+    setWheelScrollingWithoutFocusBlocked(m_configurationStates);
     connect(m_configurationStates, &QTabBar::currentChanged, this, [this](int index) {
         updateConfigurationStateIndex(index);
     });
```

[CMakePM: Disable wheel events for QTabBar](https://codereview.qt-project.org/c/qt-creator/qt-creator/+/613057) というパッチにして、本体に送りました。

レビューがスムーズに済んで、取り込まれるといいなと思っています。


# おわりに

普段自分がよく使うツールなので、ちょっとでも気になるところがあるとすぐ改善したくなります。世界中のそんな人たちのおかげで、Qt Creator ってすごく使いやすい開発環境なんじゃないかなと思っています。私のちょっとした改善のいくつかも、みんなの役に立っていたらいいなと思っています。

明日は @Ndgt さんがなにか書いてくれるようです。期待しましょう！
Google Docs APIではドキュメントをMarkdownで取得できる

LIFULL社内で開発された[AI基盤プロジェクト「keelai」](https://www.lifull.blog/entry/2024/08/29/173000)は、社内リソースのURLを変換してAPIを通じて開く機能を提供しています。

その中でもGoogle Workspaceが広く使われているツールの一つなのですが、keelaiでは特に重要なGoogle Docs, Google Sheets, Google Slidesの読み込みをサポートしています。その際にAPIで実装してます。

従来Google Docsは `text/plain` のmime typeを利用して読み取っていたのですが、実は `text/markdown` で構造化した形で読み込めるようです。以下のドキュメントにも書いています。

https://developers.google.com/drive/api/guides/ref-export-formats?hl=ja


というわけで、plain textでの読み込みではなくmarkdownの読み込みに切り替えてみました。特に表形式が崩れないのが嬉しいかもしれません。

## 経緯

社内で[MarkItDown](https://qiita.com/ninomiyt/items/f9451f5384f9fd7e969b)の話が出たときに、「実はGoogle WorkspaceのAPIのいくつかにはMarkdown出力のオプションがありそうだ」という話が出てきて調べたところ、Docsは対応してました。

> ちなみに、Google Docs系にMarkdownで出力ボタンがいつのまにかついてるんだけど、APIも生えてたりしないかな。

調べてみると、おそらく去年の7月ごろに対応していたようです。

https://pulse.appsscript.info/p/2024/07/using-google-drive-api-and-google-apps-script-to-convert-between-google-docs-and-markdown/

おそらく特に生成AIとの相性を狙ったものではなく、単にユーザーがMarkdownで入力できると便利だからって理由みたいですね。


更に欲を言うと、Google SheetsやSlidesも同じようにMarkItDownを使って変換できるようなきれいなmarkdownで出力できればと思ったのですが対応していませんでした。そのため一旦別のファイル形式で出力して[Unstructured](https://github.com/Unstructured-IO/unstructured)で文字列に変換しています。

まだ欲を言うとPythonのgoogleapiclientはasync対応してほしいのもあります🙏
airCloset Advent Calendar 20日目: よく使うコマンドラインツールを紹介！

こんにちは！本日は、airClosetで日常的に使用している便利なコマンドラインツールをいくつかご紹介します。サーバー管理や効率的な作業のために役立つものばかりなので、ぜひ参考にしてください！

https://qiita.com/advent-calendar/2024/air-closet

## 1. ssm-session-start: サーバーへの簡単ログイン

通常、サーバーにログインする際は、```pem```キーを使用して```SSH```接続を行うのが一般的です。しかし、複数のサーバーを管理していると、IPアドレスやインスタンス情報を覚えるのが大変ですよね。

```ssm-session-start```を使えば、これらの情報を覚える必要がなく、選択するだけでサーバーにログインできます。
このツールは、AWS Session Managerを利用して自社で作成したものです。

### スクリプト内容
以下のスクリプトを```/usr/local/bin/ssm-session-start```として保存してください。

```
#!/bin/bash

if !(type aws > /dev/null 2>&1); then
  echo AWS CLI をインストールしてください。
  exit 1
fi

if !(type fzf > /dev/null 2>&1); then
  echo fzf をインストールしてください。
  exit 1
fi

export NAME_SSM2EC2=$(aws ec2 describe-instances --filter "Name=instance-state-name,Values=running" --query "Reservations[].Instances[].Tags[?contains(Key, \`Name\`)].Value" --output text | fzf)

if [ -z "$NAME_SSM2EC2" ]; then
  echo Exiting script.
  exit 0
fi

echo Connect instanceName: $NAME_SSM2EC2
export ID_SSM2EC2=$(aws ec2 describe-instances --filter "Name=instance-state-name,Values=running" "Name=tag:Name,Values=${NAME_SSM2EC2}" --query 'Reservations[].Instances[].InstanceId' --output text)

IDS=(`echo $ID_SSM2EC2`)
if [ "${#IDS[@]}" -gt 1 ]; then
  echo $NAME_SSM2EC2 が複数のインスタンスに同一名で付与されています。
  echo このツールは、複数のインスタンスに同一のインスタンス名が付与されている場合には対応していません。
  echo インスタンス名が一意になるように統一してください。
  exit 1
fi

echo Connect instanceId: $ID_SSM2EC2
aws ssm start-session --target ${ID_SSM2EC2}
```
### 使用方法

1> スクリプトの設置: 上記のコードを```/usr/local/bin/ssm-session-start```として保存し、実行権限を付与します。
```
chmod +x /usr/local/bin/ssm-session-start
```

2> 前提条件: 対象インスタンスにAWS Session Managerがインストールされている必要があります。詳細はこちらの記事をご覧ください。
https://qiita.com/mksamba/items/6d7a0b84894578feafa8

3> 実行例:
```
ssm-session-start
```
実行すると、以下のようにインスタンスの一覧が表示されます。接続したいインスタンスを選択するだけで、自動的にログインできます！


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103998/426060c0-04c2-848b-e419-c626b2a53f0e.png)

## 2. fzf: インクリメンタル検索ツール

https://github.com/junegunn/fzf

fzfは、Goで実装されたインクリメンタル検索ツールです。サーバー操作や日常のコマンド履歴検索など、さまざまな場面で便利に使えます。特に、コマンド履歴の検索機能がおすすめです。

### コマンド履歴検索

通常、コマンド履歴を確認する際に```history```コマンドを使うと、結果が見づらくて大変ですよね。```fzf```を導入すれば、直感的に履歴を検索できます。

以下のスクリーンショットのように、簡単に過去のコマンドを見つけることができます！


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103998/e86a8b4e-9507-6138-ed19-0881557d5c3e.png)

## 3. ripgrep: 超高速テキスト検索ツール

https://github.com/BurntSushi/ripgrep

ripgrepは、Rust製のテキスト検索ツールです。その名の通り、grepに似た機能を持ちながら、圧倒的な検索速度を誇ります。

### 使用例
特定の文字列を検索したいときに、以下のように使えます。

```
rg tableName
```
上記のコマンドを実行すると、検索結果が瞬時に表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103998/dd39543c-7194-b85e-e5b9-b0439228a3c4.png)

### インストール

詳しいインストール手順は、公式GitHubページをご参照ください。

---
以上、今回はairClosetで日常的に使っている便利なコマンドラインツールを3つご紹介しました。これらを活用することで、作業効率を大幅に向上させることができます。ぜひ試してみてください！
RubocopとRspecの導入について

# はじめに
私は初学者で、現在ポートフォリオの作成をしています。そのため、間違えた情報を発信してしまう可能性もありますことを始めにお詫びいたします。万が一間違えていた場合は、コメント等で教えていただきますよう、お願いいたします。
今回は、RubocopとRspecの導入を説明していけたらと思います。

# 導入理由
初学者であるため、自分が記述したコードや機能が正しいのか確認するためにも、RubocopとRspecの導入を考えております。また、現在Heroku・CirclCIの導入も実装しているため、gitをプッシュしたタイミングで自動でチェックして欲しいと感じ、RubocopとRspecの導入を先に行います。

# 導入の流れ
まずはじめにGemfileにRubocopとRspecを記述します。
```php:Gemfile
group :development, :test do
    gem 'rspec-rails'
    gem 'rubocop', require: false
    gem 'rubocop-performance', require: false
    gem 'rubocop-rails', require: false
    gem 'rubocop-rspec', require: false
end
```
こちらの[サイト](https://qiita.com/piggydev/items/074e020e07af7ebc872d#%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89%E5%86%85%E3%81%A7%E7%89%B9%E5%AE%9A%E3%81%AE-rubocop-%E3%81%AE%E8%AD%A6%E5%91%8A%E3%82%92%E7%84%A1%E8%A6%96%E3%81%99%E3%82%8B%E8%A4%87%E6%95%B0%E6%8C%87%E5%AE%9A%E5%8F%AF)を参照したところ、rubocopの導入は以下のコマンドを入力するらしい。
###### rubocop
```php
bundle exec rubocop --auto-gen-config
```
そうすると、`.rubocop_todo.yml`と`.rubocop.yml`が作成されました。
`.rubocop_todo.yml`は現在rubocopでエラーが出ているコードを一度無視するために作成されています。注意点として、これでrubocopのエラーが出なくなるのですが、そのままにしておかずに、エラーを解決していって、.rubocop_todo.ymlから該当の部分を削除していく必要があるとのことでした。
`rubocop.yml`はrubocopで違反の検出をそもそも実行しないファイルを設定するものです。こちらに該当のファイルを入れることで、そのファイルをスルーしてくれます。

Gemを追加したので、下記を実行しました。
```php
docker-compose up --build -d
```
実行したところ、(Bundler::GemNotFound)というエラーが、、、どうやらGemfileに追加したGemが見つからないということらしいです。
⇨正しくGemfileに記述されていることやDockerfileにbundle installが記載されていることを確認。その後、バージョンを指定してみたりしたが解決されない。そのため、一度下記の記述をしてコンテナ、イメージ、ボリューム、ネットワークなどをすべて削除してみました。
```php:ターミナル
docker-compose down --rmi all --volumes --remove-orphans
```
その後、Dockerをビルドした結果、解決しました。
少し調べてみた結果キャッシュの関係で不都合がでた結果、うまくbundle installが実行されなかった可能性があるとわかりました。キャッシュは便利だけども、こういう場面でエラーの原因となることもあるのだなと発見がありました。次に同じようなエラーがあった場合は、Dockerfileのにてキャッシュの部分を変更してみようと思います。

# 終わりに
これでRubocopとRspecの導入が終了です。詳細の設定等はアプリを制作しつつ、少しずつ覚えていいこうと思います。
最後までご閲覧いただき誠にありがとうございました。少しでもお役に立てれば幸いです。
１つのキーボードとマウスで２台のPCを操作したい！

# 新しいPCを購入した

２台のPCになったのですが、キーボードとマウスを２セットで運用するのも面倒くさいと思いますよね。
今時１セットで入力を切り替える良い方法を誰か考えてくれないかと調べました。

## ハードウェアで対応

おお、ありますね。
ロジクールのflow対応のキーマウなら複数PCをいい感じに切り替えられるようだ。
２０年近くロジクール愛用者なので、選択肢としてはありだ。
とはいえ、現在も愛用しているキーマウから買い替えるの微妙に忍びないのでソフトウェアでどうにか出来る方法が無いか調べる事にしました。

## ソフトウェアで対応

ソフトウェアでも対応できそうだ。

その名も「mouse without borders」！！
しかも、うれしい事にMicrosoft純正です。
使い方を見ると、インストール後はマルチディスプレイと同じ感覚でスクリーン境界をまたぐと別PCに自動で切り替わるという優れものの仕様のようです！

```
キーマウ -  PC1 ┬ display1
               └ display2
           PC2 - display3
```
こんな感じの構成でも、display3をPC1から操作でるんです。

かなり良い感じ！！
…かなり良い感じなんですが、WIFIで繋ぐと結構怪しい挙動になったりするので、有線LANで繋ぐことをお勧めします。
また、特定のウインドウにフォーカスされるとマウスカーソルが非表示になる場合があります。（設定で改善される人もいるようですが私は改善されないですが、レアな条件なので我慢しています）

とりあえずは、mouse without bordersで頑張ってみたいと思います。
AWS上で建てたFedoraのユーザー名を変更するまで

# はじめに

この記事は、Qiita Advent Calendar 15日目の記事です。
以下の記事より、すべての記事をご覧になれます。

https://qiita.com/0_terarin_0/items/2b60d47a2d0e64a273c3

# 本編

実は先日のZedのサーバーを立てた記事なのですが、ずっと悩んでることがありました。ユーザー名がデフォルトの「fedora」なんです。しかも、大方の方は思っている、なぜそもそもAWS上でFedoraを建てることができたのか。このことに関して自分のメモも含めて書いておきたいと思います。

## Fedoraを使いたかった

ここでみなさん疑問があると思います。別に普通にUbuntuを使えばいいやんと。しかし、僕はFedoraを使いたかった。というのも、僕が今後手を出していきたい色々な分野でFedoraって結構カスタムが用意されてたり、あるいはそもそも僕がデュアルブート環境でFedoraを用意していてるので慣れておきたいなど、まあ主な理由はそんな感じです。ということで、Fedoraを使っていきたいんですけど、多くの方は思ったでしょう。「そもそもOSの選択肢にFedoraってあった？」と。実は公式に提供しているものは僕も直接は見つけられませんでしたが、流石にないなんてことはないだろうと思い探していましたらやはり公式からありました。

https://fedoraproject.org/cloud/download

ということでこれの下の方に行ったら下の方にあるリンクからAWS上のEC2インスタンスを作ることができますのでそこから立ち上げました。

## デフォルトのユーザー名を変えたい！

ということでここまで来て起動して接続するとなんとユーザー名が「fedora」。このままはちょっと嫌ですよね、変更したいですよね！ということで、これを変更する手順を下に載せていきたいと思います。

まず、テスト用のユーザーを作成します。

```zsh
# パスワードの設定
passwd

# ユーザーの作成
sudo useradd test

# パスワードの設定
sudo passwd test

# wheelグループに追加
sudo usermod -aG wheel test
```

ここまでいたらログイン！と行きたいのですが、SSHの設定を変更する必要があります。デフォルトでAWS上ではパスワードではなく公開鍵認証方式しか使うことができない状態ですので、これをパスワード認証のログインでも使えるように変更していきたいと思います。ちなみに、変更するファイルは`/etc/ssh/sshd_config.d/50-cloud-init.conf`

```zsh
sudo nano /etc/ssh/sshd_config.d/50-cloud-init.conf
```

```diff_conf
- PasswordAuthentication no
+ PasswordAuthentication yes
```

ここまで来たら新しく作成したユーザーでSSHでログインし直しましょう。あとは、変更するだけです！たとえば僕は`fedora`という名前から僕の下の名前の`koki`に変更したいのでこうなります。

```zsh
sudo usermod -l koki -d /home/koki -m fedora
```

この際にもしかしたらプロセスを使用中って怒られるかもしれないのでその時は大人しくそのプロセスをKillしましょう。

ということで、以上の手順でもう一度変更したユーザー名でログインするとログインできるようになっているはずです！
論文メモ: Phonetic Word Embedding (Sharma 2021)

# はじめに
Phonetic Word Embedding (Sharma 2021)を読んでみます。
## 論文情報
- タイトル: Phonetic Word Embedding
- 出版年：2021
- 著者：Rahul Sharma, Kunal Dhawan, Balakrishna Pailla
- URL：
  - arxiv: https://arxiv.org/abs/2109.14796
  - github: https://github.com/rahulsrma26/phonetic-word-embedding

## 動機
趣味で空耳替え歌を自動生成する試みをしており、タイトルに惹かれたので読んでみる。

# 背景
- 単語埋め込みは単語の特徴を表現する有用な技術だが、主に意味特徴に基づいており、音韻特徴を捉える能力は低い。
- 音韻特徴を捉えられるようになることで、キーワード検出や詩の生成など様々な下流タスクへの応用が期待される。

# 関連研究
- 先行研究では、カーネギーメロン大学の発音辞書の単語を音素バイグラムの有無で表現した疎行列にPCAを適用することで、単語を音素に基づく50次元の埋め込みに変換した。しかし、この研究では、音素の位置の影響を排除する調整が行われていた。
# 提案手法
- 先行研究では音素の位置の影響を考慮しなかったが、実際には音素の位置は、音韻特徴に影響すると思われる。そこで、音素の位置を考慮したルールベースの類似度計算方法を提案し、それをベースに次元圧縮することで、より品質の良い音韻埋め込みを得ることを目指す。
- 以下、音素の類似度、単語の類似度、埋め込み計算の３ステップで手法を説明する。
## 音素の類似度
- ユニグラム: 単一音素（ユニグラム）の類似度は、音素をいくつかの特徴セット（有声、無声などの言語学的な音響特徴）の集合で表したときの、集合同士のjaccard係数とする。つまり共通する特徴が多いほど高くなる。
- バイグラム: バイグラムの場合の特徴セットは、各音素の特徴セットの和集合とする。
- 母音の重み: 母音は子音と比べて長いことが多いので、バイグラムの２つめの音素が母音かつ同一の場合、似て聞こえやすい。これを反映するために、２つめの音素が母音でかつ一致するときの類似度が高くなるように補正する。具体的には、母音が一致するなら類似度を0.5乗し、それ以外なら2乗する。
## 単語の類似度
- 重み付き編集距離: 単語を音素列に変換し、重み付き編集距離を類似度とする。バイグラムの場合は、語頭、語末にBGN、ENDという特殊音素を付加したうえでバイグラムの音素列に変換して、同様に重み付き編集距離を求める。
- 非対角ペナルティ: 編集距離の計算において非対角ペナルティを設定することで、位置が異なる音素の置換を起こりにくくする（注：感想に書いたけど式5は色々間違っている気がするし、非対角にペナルティを与えられているのかも不明）
## 埋め込み計算
- 単語の類似度行列を作って因子分解で次元圧縮する

# 実験結果
## 実験
- CMU発音辞書の単語をもとに埋め込みを作成
- unigramかbigram、非対角ペナルティの有無、母音重みの有無など条件を変えて評価
- 先行研究の音素の位置情報を考慮しない手法（PSSVec）と比較。
- Vitz（1973）の人間が評価した類似度データと相関係数を比較。
- 提案手法の中では非対角ペナルティp=2.5で母音重みありのbigram（次元圧縮前）が最も高性能（fig1）、PSSVecよりも高性能（fig2）、次元圧縮してもほぼ精度が維持（fig4）

## 埋め込み空間の評価
- 英語とヒンディー語でいくつかの単語をマッピング。音韻が近そうな単語が埋め込み空間上でも近くにマッピングされることを確認（fig5, 6）
## ダジャレベースの評価
- ダジャレデータセットから対応する語彙が同一でないもの（ヘテログラフィックダジャレ）の単語ペアを取得し、コサイン類似度を計算。PSSVecより提案手法のほうが1に近いところにより高いピーク。


# 感想
- ルールベースで類似度行列作って因子分解で圧縮するというやり方は参考になる。
- 評価方法も参考になる。
- 埋め込みの作り方の数式の細かいところはよくわからなかったり納得感薄かったりする。
  - バイグラムの音素類似度で和集合つかっているけど順番の情報が失われていいの？
  - 母音の重み付けで２乗したり0.5乗したりするのがだいぶトリッキー。重み係数にしなかった理由が不明。
  - 式5はDPでminを求めているけどmaxを求めるべきだと思うし、挿入や削除に相当する計算の部分（otherwiseのところ）でS(a,b)が登場するのも違和感。無音との類似度であるべきでは？ 「非対角ペナルティ」もよくわからなくて、式5ではai!=bjのときにペナルティつけてるけど「非対角」というならi!=jのときにつけるべきでは。あと音素列の長さが同じじゃないときの対角要素をどう扱うかも不明。
- 精度はルールベースと同等で計算量だけ減らしたという感じ。パラメータは結局手動で決定している。もう少し人がルールを作らない方法があるといいなと思った。
- 音韻特徴を反映した埋め込みの研究、今まで知らなかったけど、[Googleとかも普通にやっていそう](https://static.googleusercontent.com/media/research.google.com/ja//pubs/archive/42543.pdf)？ 次読んでみたい。
CS関連を含む勉強したい事、気になる事リスト


新しい事思いついたら追記していきます。

◯進行中　CS関連
・E資格
・線形代数
・微積
・Dashでのデータ可視化
・ビッグデータ解析
・MQTT
・

◯進行中　その他
・地学
・行動分析学（心理学）
・ボイトレ
・計画力を高める
・後輩の指導
・スペイン語
・料理/外食　比率を高める
・瞑想
・姿勢の改善
・善く生きる

◯準備中
・ドラッカー読破
・マチアプ攻略
・ウェハー上へのチップ実装の座学（ざっくり）
・地政学
・データマネジメント
・早起きしてモーニングノートを書く
・Proxmoxのインストールと設定
・デスクの配線整理

◯凍結中
・LPIC
・


◯やってみたい事/気になる事
・FastAPI or Flask
・オレオレ証明書発行
・C言語
・C++
・C#
・Rust
・カーネル
・システムコール
・Linuxのビルド&カーネルのプリントデバッグ
・一般&特殊相対性理論を理解する
・ローレンツ収縮
・信号処理へのAI適用
・AIエッジデバイスの開発
・人間の脳のニューロンの動き
・スモール事業つくる
・会社に事業提案
・開発企画書をつくる
・開発企画書を出してみる
・回路設計
・FPGAのプログラミング
・マイコンを利用したデバイス開発
・素子開発
・バンジージャンプ
・航空機の操縦
・無重力の体験
・宇宙旅行
・ダイビングでサメに囲まれる
・結婚
・子育て
・起業
・部下を5人持つ
・本を出す
・noteで有料記事を購入してもらう
・歌がうまくなる
・歌で1円稼ぐ
・毎月5万円本に使っても痛くないくらいの収入を得る。
　-> 年収800万くらい？
・ロケットの打ち上げ
・人工衛星の打ち上げ
・宇宙ビジネスに携わる
・宇宙基地に携わる
・軌道エレベータ事業に携わる
・電気工事士の資格取得
・応用情報取得
・データベーススペシャリスト取得
・ネスペ取得
・自分の製品を作る
・外国の友人を作る

◯満足した事
・FPS
・トレード（微勝）
・服
・ギター
・漫画
・YouTubeの鑑賞
・映画鑑賞
・音楽鑑賞
・ネット小説；なろう系
・住環境
・スノーボード
・バイク
・スポーツカー
・転職したいと思うこと
・上司との軋轢（解決）
・研究者になりたい気持ち
・友人とのカラオケ
・
Delve の後継機能の説明ってどこだ？

# 背景

同僚から　
「○○さん、プロフィールの電話番号ってどうやって変えたんですか？」
と質問チャットが来た。

ん？そうえいば、Delve ってあったけど、引退したな、どうなったんだっけ？

編集ってどうなってんだ？となった際の調査記録

公式としては、以下が詳しかった。

https://learn.microsoft.com/ja-jp/sharepoint/delve-retirement

# 結論

以下のような URL にアクセスすると、User 情報を開ける。

> https://<font color=red>{tenant name}</font>.sharepoint.com/_layouts/15/sharepoint.aspx?pp=<font color=red>{user ID}@{tenand ID}</font>|<font color=red>{ user information, ID, emal, etc.}</font>&v=search/overview

ex.) `https://shimakuma.sharepoint.com/_layouts/15/sharepoint.aspx?pp=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx@xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx|shima_kuma&v=search/overview`

`user information` のとこは、User Principal Name とか、Mail とか一意になるもののほうがよいが、そうじゃなくても最初に見つかったユーザーが表示される。

公式だと以下の記述
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/f59174f1-03b8-ab3a-89b7-32a103f416b6.png)


Delve のときの User 検索に似た感じかな、と

で、まぁ、こんな感じで表示される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/c45a1d34-05f7-2bd3-511c-9926e3b927c8.png)


ここの `プロフィール更新` で、編集も出来るので、Delve の時のように使えますね :star:

また、そこから、以下のlinkで　Sharepoint らしい設定ページにいけます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/1aad0c88-2e89-effe-4656-82a0264fcd48.png)

URL としては

> https://<font color=red>{tenant name}</font>-my.sharepoint.com/_layouts/15/editprofile.aspx?UserSettingsProvider=<font color=red>{user ID}</font>


## 補足

単にモダン検索の使い方を知るなら以下とかのほうが分かりやすい

https://support.microsoft.com/ja-jp/office/sharepoint-%E3%81%A7%E3%81%AE%E3%83%A2%E3%83%80%E3%83%B3%E6%A4%9C%E7%B4%A2-b81ab573-ec9c-4aa9-a369-b3c630f878a7

# あとがき

Delve 引退した時の代替情報しかなく、`editprofile.aspx` についてもまとめられているページが見つからなかったのは、進化が激しいからなんだろうか？ :thinking: 

まぁ、触ればわかることも多いからいいんだけどね :laughing:
【Rails】Devise Token Authでパスワードリセットトークンの有効期間を変更する方法

## 変更方法
`config/initializers/devise_token_auth.rb`に以下のように`reset_password_within`を記述することでパスワードリセットトークンの有効期間を変更できます。

```

Devise.setup do |config|
  config.reset_password_within = 2.hours
end

```

## 参考

https://github.com/heartcombo/devise/blob/fec67f98f26fcd9a79072e4581b1bd40d0c7fa1d/lib/generators/templates/devise.rb#L227
【React Hook Form】watchでのname属性の所得の方法について

# はじめに
業務で`react-hook-form`の`watch`を使用している際、`name`プロパティの付け方について混乱した経験があります。`name`プロパティはHTML一般において重要な概念ですが、`react-hook-form`での使い方に着目して記事にしました。

:::note warn
***この記事は<font color="Red">個人的なアウトプット</font>を目的として作成したものです。そのため、誤った情報や不足している内容が含まれている可能性があります。もし間違いや気になる点がございましたら、ぜひご指摘いただけますと幸いです***。
:::

# watchの基本
`react-hook-form`は、`name`をキーとしてフォームフィールドの状態を管理します。
そのため、`watch`メソッドで特定のフィールドを監視する際には、対応する`name`プロパティを正しく指定する必要があります。`name`が異なるフィールドの値を取得することはできません。

https://react-hook-form.com/docs/useform/watch

今回の記事では、複数のチェックボックスやテキストボックスの`name`の扱いに焦点を当てます。

# nameの付け方
## 固有の場合
基本的には、`name`はフィールドごとに固有である必要があります。以下のような例では、異なるnameを使用することで、各フィールドの値が個別に管理されます。
```react
<input type="text" {...register("firstName")} />
<input type="text" {...register("lastName")} />
```
しかし、同じ`name`を複数の`inputPに設定すると問題が発生します。

```react
<input type="text" {...register("name")} />
<input type="text" {...register("name")} />
```
このように書いた場合、HTMLの仕様上、同じname属性を持つ要素の値は***最後の要素が優先されます***。つまり、2つ目の`input`の値が優先され、最初の`input`の値は上書きされます。これはテキストボックスでは複数の値を格納できないためです。

***この挙動は`react-hook-form`ではなく、HTMLの仕様によるものです***。

## 共通の場合
チェックボックスやラジオボタンのように複数のフィールドをまとめて管理したい場合、`name`を共通に設定します。`react-hook-form`では、同じ`name`を持つチェックボックスの選択状態を配列として扱います。

```react
const values = watch("fruits");

<input type="checkbox" value="りんご" {...register("fruits")} />
<input type="checkbox" value="ばなな" {...register("fruits")} />

console.log(values) //["りんご", "ばなな"]出力結果
```
このように、複数のチェックボックスを一つの`name`でグループ化することで、選択された値をまとめて取得できます。これにより、状態管理が簡潔になります。

一方、チェックボックスが独立した状態を持つ場合（例: 個別のonChange処理が必要な場合など）は、固有の`name`を設定します。

```react
<input type="checkbox" value="りんご" {...register("apple")} />
<input type="checkbox" value="ばなな" {...register("banana")} />
```
このようにすることで、各チェックボックスを個別に管理することができます。

#　終わりに
`name`プロパティはフォーム要素を識別するための基本的な要素ですが、使用する状況によって設計が変わります。今回の件で`react-hook-form`や一般的なHTMLフォームにおける`name`の役割についての理解が深まりました。引き続き学習していきたいと思います。


# 参考

https://tomi-no-tubuyaki.com/programming/same_name_problem_in_form/

https://qiita.com/hanaten/questions/b15f6ebccce7e1e0cb97

https://react-hook-form.com/docs/useform/watch
ExpressRouteの接続確認


# はじめに

ExpressRouteの接続確認（テスト）ってどうするんだろうと思い、
公式ドキュメントを読んで整理してみました

# ExpressRouteの概要

下記で整理してみましたので、よければご参照ください
https://qiita.com/yuyanz/items/251c08f4daaf057e2577

# 接続テストの手順

下記のドキュメントに沿って確認していきます。
※効率的になりそうと思った箇所はわざと順番を前後させている箇所があります。

https://learn.microsoft.com/ja-jp/azure/expressroute/expressroute-troubleshooting-expressroute-overview


# プロビジョニングと回線の状態確認

Azure portalから確認可能
ExpressRouteの概要より下記を確認

> ExpressRoute 回線を運用可能にするには、[回線の状態] が [有効]、[Provider status (プロバイダーの状態)] が [プロビジョニング済み]である必要があります。


# ピアリング構成の検証

Azure portalから確認可能
ExpressRouteの概要からピアリングの欄より
構築したピアリングがプロビジョニング済みであることを確認

# ARP検証

Azure プライベート ピアリングの場合

PowerShellより
リソースグループの名前とExpressRoute Circuitの名前を変数に入れてARPテーブルを取得

~~~ powershell
$RG = "<Your Resource Group Name Here>"
$Name = "<Your ExpressRoute Circuit Name Here>"

Get-AzExpressRouteCircuitARPTable -ResourceGroupName $RG -ExpressRouteCircuitName $Name -PeeringType AzurePrivatePeering -DevicePath Primary

Get-AzExpressRouteCircuitARPTable -ResourceGroupName $RG -ExpressRouteCircuitName $Name -PeeringType AzurePrivatePeering -DevicePath Secondary
~~~

Microsoft ピアリングの場合は下記から参照ください

https://learn.microsoft.com/ja-jp/azure/expressroute/expressroute-troubleshooting-arp-resource-manager

# MSEE 上の BGP とルートを検証


MicrosoftのEdgeルータ上のBGPとルートの確認
PowerShellよりリソースグループの名前とExpressRoute Circuitの名前を書き換えて入力

~~~ powershell
Get-AzExpressRouteCircuitRouteTable -DevicePath Primary -ExpressRouteCircuitName <CircuitName> -PeeringType AzurePrivatePeering -ResourceGroupName <ResourceGroupName>
~~~

# トラフィック フローを確認

入出力バイトがでてきます

PowerShellよりリソースグループの名前とExpressRoute Circuitの名前を書き換えて入力
~~~ powershell
Get-AzExpressRouteCircuitStats -ResourceGroupName <ResourceGroupName> -ExpressRouteCircuitName <CircuitName> -PeeringType 'AzurePrivatePeering'
~~~

# プライベート ピアリング接続 テスト

### 事前準備

PsPingを使ったテストがあるので、下記を準備

https://learn.microsoft.com/ja-jp/sysinternals/downloads/psping

### テスト開始
Azure portal ⇒ExpressRoute 
⇒問題の診断と解決⇒接続とパフォーマンスの問題
⇒発生している問題の詳細を教えてください
⇒プライベート ピアリングの問題
⇒プライベート ピアリング接続のテスト

オンプレIP⇒AzureのIPへPsPing(事前準備しておいたpingツール)を実行したままにしておく

Portalに戻り、PsPingで入力したものと同じ IP アドレスをフォームに入力して送信ボタンを押す 

# GWの可用性

Azure portal ⇒ExpressRoute 
⇒問題の診断と解決⇒パフォーマンスの問題

結果によってはSKUのアップグレードを検討。
[Rust]パッケージとクレート

## パッケージ

Cargoを前提とした、いくつかのクレートの集まりを指します。

:::note
筆者の理解だと、一つのパッケージにつき`Cargo.toml`が一つあるイメージです。
:::

## クレート

ある程度の大きさの機能の集合体です。クレートには大きく
- バイナリクレート
- ライブラリクレート

の2種類があります。
一つのパッケージは少なくとも1つはクレートを持っていなければなりません。また、ライブラリクレートは2つ以上存在してはいけません（バイナリクレートに上限はありません）。

ビルドの結果、バイナリクレートとライブラリクレートのそれぞれからファイルが得られますが、それらの用途は異なります。

### バイナリクレート

バイナリクレートからは実行可能なバイナリが生成されます。バイナリクレートはそれぞれ`main`関数が定義されていなければならず、バイナリクレートの数だけバイナリが生成されます。`cargo new`した段階では一つの`src/main.rs`が存在しますが、このファイルはデフォルトでバイナリクレート（のクレートルート）として扱われます。他にバイナリクレートを増やしたい場合は、
- ファイルを作成して`Cargo.toml`に追記する
- `src/bin`ディレクトリにファイルを作成する

のどちらかで増やせます。ここで追加する、`main`関数が定義されているファイルをバイナリクレートのクレートルートと呼びます。

バイナリクレートは実行可能なエントリポイントであるため、他のクレートから参照されることは想定されていません。

:::note
厳密には「バイナリクレートに含まれるコードはモジュールとしてライブラリクレートから再利用可能」にすることは可能です。ただし、通常の使い方では、バイナリクレートは実行エントリポイントであり、他から参照される設計にはしないのが慣例です。
:::

### ライブラリクレート

ライブラリクレートからは他のクレートから参照かのうなバイナリが生成されます。ライブラリクレートには`Cargo.toml`で定義された名前が付けられます。この名前は一つしか定義できないので、一つのパッケージには二つ以上のライブラリクレートが存在できないのです。

ライブラリクレートは`src/lib.rs`がクレートルートであると決まっています。

## クレートルート

クレートルートとは、あるクレートのトップレベルのファイルを指します。あるクレートに属するモジュールは、クレートルートからのパスを使って、他のモジュールから参照できます。

```
my_project/
├── Cargo.toml
├── src/
│   ├── main.rs  // デフォルトのバイナリクレートのクレートルート
│   ├── lib.rs   // デフォルトのライブラリクレートのクレートルート
│   └── bin/
│       ├── additional_binary.rs  // 追加のバイナリクレート
│       └── another_binary.rs     // さらに追加のバイナリクレート
```

### バイナリクレート

```rust:src/main.rs
fn main() {
    println!("Hello, world!");
}
```

```rust:src/bin/additional_binary.rs
fn main() {
    println!("This is another binary crate!");
}
```

```rust:src/bin/another_binary.rs
fn main() {
    println!("Yet another binary crate here!");
}
```

### ライブラリクレート

```rust:src/lib.rs
pub fn greet(name: &str) {
    println!("Hello, {}!", name);
}
```

`Cargo.toml`で定義されている名前が`my_project`だった場合、他のクレートからは`my_projet::`で参照できます。

```rust:src/main.rs
use my_project::greet;

fn main() {
    greet("Alice");
}
```

ライブラリクレートがモジュールファイルを参照している場合は、`my_project::モジュール名`でそのモジュールを参照できます。

```rust:src/lib.rs
pub mod utilities;

pub fn use_utility_function() {
    utilities::helper_function();
}
```

```rust:src/utilities.rs
pub fn helper_function() {
    println!("This is a helper function!");
}
```
```rust:src/main.rs
use my_project::use_utility_function;

fn main() {
    use_utility_function();
}
```

:::note
クレートは、TypeScriptでいうnpmパッケージに近いかもしれません。
バイナリクレートはそれ自身が動作するロジックを持ち、それは一つのパッケージ（Cargoプロジェクトのこと）に複数存在します。
一方、ライブラリクレートはそのパッケージ名を冠した他のクレートに使ってもらうためのクレートです。こちらの方がTypeScriptでいうnpmパッケージの存在に近いでしょうか。
:::
【Next.js】GET通信で渡されたパラメータをuseSearchParamsで取得する方法

# useSearchParamsコンポーネントの導入はシンプル
Next.jsが用意しているクライアントコンポーネント「<b>useSearchParams</b>」は、
<b>GETパラメータの各クエリを取得するためのAPI</b>です。

しかも、導入はとってもカンタンなんです！

パッケージ管理ツールnpmやyarnでインストールしなくても、<b>Next.jsプロジェクトを作成した時からデフォルトで入っています！</b>


https://nextjs.org/docs/app/api-reference/functions/use-search-params

クライアントクラスに下記のようにいImportすれば完了です！
```app/auth/eventEdit/page.tsx
'use client'

import { useRouter, useSearchParams } from "next/navigation"
```

# 画面イメージを見ながらコード解説をしてみる
では、さっそくコードの解説をしていきましょう。

たとえば、次のような一覧画面があるとします。
![編集画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/94cd7820-2a82-8a10-063c-74d7c1a94917.png)

この一覧画面のローカルWebサーバでのURLは次の通りです。

![URL.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/d7a8bff3-cfb9-1e57-95cf-25024a8d8190.png)

さて、このURLから<b>①userIdと②eventid</b>をブラウザのコンソールに出力してみましょう。

どう書けばいいかというと、<b>たった2ステップで取得することができます。</b>
<b>【手順】</b>
①useSearchParams関数を定義します。
```app/auth/eventEdit/page.tsx
const searchParams = useSearchParams();
```
②取得するパラメータのクエリ名をgetする。
```app/auth/eventEdit/page.tsx
const userId = searchParams.get('userId');
const eventId = searchParams.get('eventId');
```
はい、これで完了です。

全体のコードはこちら↓（この画面は、これから作りこみ予定です...）




```app/auth/eventEdit/page.tsx
'use client'

import { useRouter, useSearchParams } from "next/navigation"
import { useEffect,useState } from "react";
import SelectEvent from "@/app/pages/api/selectEvent";
//import { GETQueryParams } from "@/app/pages/api/urlQueryParameters";

export default function EventEdit(){
    //ルーティングの設定
    const router = useRouter();
    //クライアントコンポーネントフックであるuseSearchParamsを使用する
    const searchParams = useSearchParams();

    //URL Query Paramsからパラメータを取得する
    const userId = searchParams.get('userId');
    const eventId = searchParams.get('eventId');

    console.log("GETパラメータから受け取ったユーザーIDは、" + userId);
    console.log("GETパラメータから受け取ったイベントIDは、" + eventId);

    //ダッシュボードに戻るボタン押下時の処理
    const backToMyDashboard = ()=>{
        router.push("/auth/login/dashboard");
    }
    //状態でイベント情報を管理する
    const [targetEvent,settargetEvent] = useState<any>(null);

    useEffect(()=>{
        const fetchEvent = async ()=>{
            try{
                const event = await SelectEvent(Number(userId),Number(eventId));
                console.log("サーバから取得してきた編集対象イベントは、" + event);
                settargetEvent(event);
            }catch(error){
                console.error("イベントの取得中にエラーが発生しました：", error);
            }
        };
        fetchEvent();                
    },[userId,eventId]);

    console.log("編集対象のイベントは、" + JSON.stringify(targetEvent));

    return (
        <div>
            編集ページ
            <div className="eventEditArea">
                <button className="btn btn-primary">編集する</button>
                <button className="btn btn-accent">クリアする</button>
                <button className="btn btn-secondary" onClick={backToMyDashboard}>戻る</button>
            </div>
        </div>
    )
}
```

以上です。
Unityの見やすさに関する設定を変更した

# Unityの見やすさに関する設定を変更した
## 使用しているUnityバージョン
- 2022.3.22f1
## 導入したアセット
- Sortify(ヒエラルキーウィンドウの機能拡張)
    - https://assetstore.unity.com/packages/tools/utilities/sortify-301537
## 追加したスクリプト
- VisualStudioのデフォルトの保存文字コードをutf-8に変更する(日本語の文字化け対策)
    - https://nosystemnolife.com/unity_script_mojibake/
- ヒエラルキー内の王ジェクトを階層ごとに色分けするスクリプト
    - https://qiita.com/tus18/items/6309fb41e39912a944a4

## Sortify
 ヒエラルキーウィンドウの拡張
- メモを追加できる
- オブジェクトを色分けできる
- オブジェクトが所有するコンポーネントをアイコン表示
DataStore処理のユニットテストを書くためにInMemory版DataStoreを使う

DataStoreを使った処理のユニットテストを書く際に、mockkでインスタンスを作って、入出力を書いて･･････ってやってたんですが
NowInAndroidで以下のクラスを見つけました

https://github.com/android/nowinandroid/blob/main/core/datastore-test/src/main/kotlin/com/google/samples/apps/nowinandroid/core/datastore/test/InMemoryDataStore.kt

そうだ、DataStoreってinterfaceなんだから、普通にInMemory版のDataStore実装すればいいだけですやん！
しかもめっちゃシンプルに実装できるやん！

```kotlin
class InMemoryDataStore<T>(initialValue: T) : DataStore<T> {
    override val data = MutableStateFlow(initialValue)
    override suspend fun updateData(
        transform: suspend (t: T) -> T
    ): T = data.updateAndGet { transform(it) }
}
```

DataStoreのdataはFlowですが、上記ではMutableStateFlowになっています。
InMemoryDataStoreとしてであれば `data.value` で現在の値にもアクセスできるわけですね。
これは便利！

PreferencesDataStoreを使っている場合、以下のように初期値をpreferenceの内容で指定できるようにしたり、直接値を確認できるようにしておけばさらに便利かもしれません。

```kotlin
open class InMemoryDataStore<T>(initialVale: T) : DataStore<T> {
    private val valueFlow = MutableStateFlow(initialVale)
    val value: T
        get() = valueFlow.value
    override val data: Flow<T> = valueFlow
    override suspend fun updateData(transform: suspend (t: T) -> T): T =
        valueFlow.updateAndGet { transform(it) }
}

class InMemoryPreferencesDataStore(
    vararg initialValues: Preferences.Pair<*>,
) : InMemoryDataStore<Preferences>(preferencesOf(*initialValues)) {
    operator fun <T> get(key: Preferences.Key<T>): T? = value[key]
}
```

このインスタンスをテスト対象クラスに渡して、結果を確認することでお手軽にユニットテストを書くことができますね

```kotlin
val dataStore = InMemoryPreferencesDataStore()

...

asertThat(dataStore.data.value.get(KEY)).isEqualTo(VALUE)
```
aabファイルのAndroidManifestを確認する方法

UnityでビルドしたaabファイルのAndroidManifestの中身を確認したいときに使えるコマンドです。

# 前提
- Windows 11
- bundletool 1.17.1
- Java 21.0.4

# 手順
1. https://github.com/google/bundletool/releases からbundletoolをダウンロードする
2. コマンドを打ち込む   
    ```shell
    java -jar bundletool-all-1.17.1.jar dump manifest --bundle android-build.aab > AndroidManifest.xml
    ```
クイズ形式で解きながらコマンドが覚えられる「Command Challenge」

## タイピングもコマンドを覚えるのも苦手。。
タイピング練習 :keyboard: 
ただもくもくとキーボードを打つのでは退屈になって長続きしないので、monkey typeをつかってゲーム感覚でタイピング練習をしようという話をしました。

https://qiita.com/uekkie/items/7296816045f8a66fcc9b#%E3%82%BF%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0%E9%80%9F%E5%BA%A6%E7%B2%BE%E5%BA%A6%E3%81%AE%E5%90%91%E4%B8%8A%E3%81%AE%E6%96%B9%E6%B3%95


ターミナルで作業しているときのコマンドについても同じことがいえます。
必要な時に思い出せないのは、絶対的に打った回数が少ないからです。

つかう場面が毎日100回あればあっという間におぼえられるはず。
ただ、コマンド表とにらめっこしながら丸暗記はツライし、楽しくない。

そんなあなたも今日から遊びながら覚えられる良さげなWebアプリを見つけたので紹介します。

## Command Challenge

ストレートですね。

https://cmdchallenge.com/

アクセスすると、

> Your first challenge is to print "hello world" on the terminal in a single command.
>
>Hint: There are many ways to print text on the command line, one way is with the 'echo' command. Try it below and good luck!

> 最初のお題は、1つのコマンドで端末に「hello world」を出力してね！
>
> ヒント: コマンドラインにテキストを出力するにはさまざまな方法がありますが、その 1つは「echo」コマンドを使用する方法です。以下で試してみてください。頑張ってください!

という感じにナビされているので、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883/4596b4c5-8793-d2d6-79ee-f413405642fa.png)


正解だとおもわれるコマンドを入力してEnterしましょう。要求を満たす出力があれば次の問題に進めます！

ここで「要求を満たす出力があれば」とわざわざ書いたのは、このお題への回答は何パターンもあるからです。


ページにある **View Solution** をクリックしてみると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883/1463e2ef-994d-813f-8032-15b0367c521e.png)

ずらーっと、他の解き方が一覧されます。

シンプルなお題にも複数のパターンがあることで、`echo`のほかに`printf`、`cat`も使えるんだ。という発見がありますよね。

順番に進めていくと、難易度も上がっていくのでぜひチャレンジしてみてください。

## 研修として使う時によさそうなゲームルール

- 毎朝10分だけやる
- １周クリアするまでは続きからやってよい
- ２周目はタイムアタックして10分で完走できるところを目指す
- 10分で完走できるようになったら、前に使ったコマンド禁止ルールを追加してやってみる
AWS Lambda で Python の SnapStart がGAしたので試してみた

ジャーニーマン( @beajourneyman )です。長いの"ジャニ"と呼ばれています。

こちらは[AWS Lambda と Serverless Advent Calendar 2024](https://qiita.com/advent-calendar/2024/lambda)の7日目が執筆時点で空いていたので、後追いでお邪魔した記事になります。実行時間を繰り返し検証してまとめました。よろしくお願いいたします。

# AWS Lambda で Python の SnapStart がGA
> 11 月 18 日、Python および .NET 関数向けの AWS Lambda SnapStart の一般提供の開始を発表しました。これにより、関数の起動パフォーマンスが数秒からわずか 1 秒未満にまで高速化され、通常は Python、C#、F#、Powershell におけるコード変更が最小限またはまったく不要になります。

https://aws.amazon.com/jp/blogs/news/aws-lambda-snapstart-for-python-and-net-functions-is-now-generally-available/

# Lambda SnapStart を有効化する
- プロダクションで1日におびただしい回数呼び出している Lambda があった
- Amazon Connect のフローブロックはタイムアウトにシビア

上記、背景から該当の関数に設定して試してみました。

「Lambda」を選択します。検証したい関数を表示します。「設定」タブの「一般設定」を確認します。「SnapStart」が"none"設定になっているので、"Published version"に設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155285/9f4d8984-8195-3e4a-8264-8b989430fe4d.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155285/7fa90f94-ecc8-2b57-30fa-070d963c4ba2.png)

SnapStart の互換性に関する考慮事項
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/snapstart.html#snapstart-compatibility

# SnapStartを有効にし走行させて検証する
キャッシュが効くであろう想定で、何度か実行しました。

SnapStart設定前の初回実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155285/b196e8c4-46bb-d522-4723-4b0fd7c85401.png)
↓
SnapStart設定後の初回実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155285/a803c6fe-7434-7187-ea8a-8f093e987e3d.png)

「初期所用時間」が「復元時間」になっているコトが分かります。

前回の実行からおおよそ5分以内に実行(SnapStart設定前)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155285/2da3c30a-c405-3c19-251b-2e1615925f04.png)
↓
前回の実行からおおよそ5分以内に実行(SnapStart設定後)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155285/784e82bc-20ee-ae16-8613-af1c72265dec.png)

同様に複数回繰り返し実証してみた結果が以下の通りです(単位は秒)。

|  | 設定前初期所要時間平均 | 設定後復元時間平均 | 差 |
| :-: | :-: | :-: | :-: |
| 平均 | 0.332  | 0.485 | 0.153 |
| 最大 | 0.378  | 0.570 | 0.192 |

実証した結果興味深いコトに、SnapStart設定後の方が遅い結果になりました。個別単独での検証では効果がない結果なので、採用を見送る結果となりました。一方で1関数を捉えて実施しただけですので、SnapStart設定が有効ではないと一概には言えないとも考えております。引き続き今後のベストプラクティスをキャッチアップしながら、改善につなげていきたいと考えています。

以上です。
Flutterの太文字が反映されない問題

# 悩み
- FontWeight.w900とかにしても太さが反映されない

# 結論
- デフォルトのフォントファミリーには「normal(w3)」と「bold(w6)」しかない
- w900とかにも対応しているフォントファミリーを指定すれば反映される

# 解説
- iosのデフォルトフォントはHiragino Kaku Gothic ProN
- これはw3とw6しか存在しない
- Hiragino Sansを指定しておけばok

# よくわからん
- フォントファミリーに何も指定しないとw3とw6だけだけど、Hiragino Kaku Gothic ProNを改めて指定するとちゃんと反映される。なぜ？どういうこと？
AIアレルギー人材でもDifyを活用しツールを作成した話

# はじめに　
弊社、株式会社リンクアンドモチベーションでは生成AIを活用した生産性向上プロジェクトを2024年から本格的に行なっています。ChatGPTをはじめとするサードパーティツールを活用する一方、自社内での専用ツールの開発をDifyを活用して行っています。
# 前提
タイトルにもあります通り、私は元々事業部でコンサルタント業務を行っており、現在所属しているエンジニア組織に移動してきてからも、弊社サービスを導入してくださっているお客様を表彰するイベントの運営を行っており、エンジニア組織に所属しているにも関わらず、AIやテクノロジーには全く触れてきませんでした。　
そのような私が10月からミッションが変わり、今では苦戦しながらもDifyを活用し、ツールを作成できるようになった過程をお伝えできればと思います。本記事を通じて、「AIなんて今まで触ったことないから無理だよ」と思っている方や「新規ジョイン者のオンボーディング」時の一助になれば幸いです。
# 学びのステップ：Difyの習得方法　
**STEP①：プロンプトエンジニアリングを学ぶ**
Difyを活用する前提として、プロンプトエンジニアリングは一定できるようになっておいた方が実現できることは増えます。　
インプット：プロンプトエンジニアリングについては、本やnoteなど数多くありますので、1～2冊読めば大枠は理解できると思います。また大枠だけ理解できても実際の活用例があった方が分かりやすいと思いますので、[デジタル庁プロンプト](https://www.digital.go.jp/assets/contents/node/information/field_ref_resources/19c125e9-35c5-48ba-a63f-f817bce95715/900a2e3b/20240510_resources_ai_prompts.csv)は参考になります。
アウトプット：学んだことをアウトプットしないとできるようにはなりません。まずは毎日ChatGPTを活用することを心掛け、使用したプロンプトをシートに記載し、同僚からFBをもらうことを行っておりました。幸いそのような環境があったから実現できましたが、ChatGPTにFBしてもらえば同じことが実現できると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3930538/e8f8852e-46cc-b7a4-1b49-07fac5d20533.png)　


**STEP②：Difyの基本を愚直に学ぶ**
ノーコードツールといってAIアレルギーの私からするとかなりハードルがありました。まずは、youtubeなどで操作説明をしている動画がありますので、それを観ながら同じ作業を行いました。また弊社では既にDifyで作成したツールがあったので、全く同じものを作成してみました。　
作成した後に、1つ1つのフローでどのような処理が実行されているかをノートに書き出し、理解を深めました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3930538/c0f5b393-d766-774d-5baa-88d2ff29210b.png)

# 実際のプロダクト開発　
**作成したプロダクト概要**　
弊社コンサルタントがお客様の事業理解を深めるためのツールを作成しました。
有価証券報告書からお客様の事業に関する内容を抜き出し、その情報に対して競合情報を踏まえた上で、事業分析を行います。ベテラン社員であれば競合を踏まえた上で事業状況を分析することは可能ですが、若手社員では難しい内容もあり、最初のインプットとして役に立つという声ももらっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3930538/9ef29757-d12d-b2ae-12e7-fa985730c4b4.png)　

**工夫した点**　
ChatGPTやperplexityで事業情報を調べることは可能ですが、実際の売上や経常利益などは誤って出てくることがあります。事実情報として正確に抜き出す内容とChatGPTやperplexityなどを用いた仮説情報を分けるようにしました。

# AIアレルギーのあなたへ　
**学びのまとめ**　
Difyをマスターすることは簡単ではありませんが、一定使えるようには必ずなります。
そのためには、
①プロンプトエンジニアリングをまずは理解する
②とにかく真似ることから始め、フロー単体で理解する
③簡単なもので良いのでまずは最後まで作成してみる　
ことが重要になります。

**これからDifyを使うあなたへ**
これからさらにテクノロジーの進化は加速し、Difyなどのツールを用いて何かを作成することが"できて当たり前"の世の中になっていくと思います。ただ、私たちは今まで生きてきた中で「機械が思うように動いてくれない経験」を味わったことが圧倒的に少ないです。携帯も機種を変えても何となく操作できる。洗濯機を変えても操作が分かる。私はDifyを初めて使った時に、「機械が思うように動かない経験」を初めて味わいました。　AIアレルギー人材からすると非常にストレスですが、「機械は思うように動かないこともある」という前提を持っておくことも重要だと考えています。　

**サポート担当の皆様へ**
私がアレルギーを起こしたシーンをいくつかご紹介できればと思いますので、参考にしていただければと思います。
・チャットボットのチャットフローとワークフローの違いが分からない
・LLM、知識取得、質問分類器など数多くあるが用途が分からない
・if/elseとiterateの概念が分からない
・なぜerrorになっているか分からない
 エンジニアの方からすると当たり前の概念で躓くことが多くありますので、是非その際はサポートしてください。
ONNX入門


# ONNXとは

ONNX(Open Neural Network Exchange)とはさまざまなAIプラットフォームで開発されるモデルを統一的に表現できることを目指したフォーマット。

https://onnx.ai/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39647/5838a84d-0e5d-3c46-f68f-8869cbccbd0f.png)
引用: https://docs.ultralytics.com/ja/integrations/onnx/

# AIアクセラレータとONNX

HaloやBlaizeなどのいわゆるAIアクセラレータは専用ハードウェアのためにコンパイルされた形式のファイルを実行するケースが多い。
その際コンパイル元としてONNXフォーマットが使用されることが多い。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39647/f6d50d73-b4e9-89a1-aa6b-82ff96097985.png)

引用: https://docs.ultralytics.com/ja/integrations/onnx/

## ONNX Runtimeについて

ONNXフォーマットはプラットフォームやフレームワーク間の中間形式として使用されることが多いが、ONNX Runtimeを使用することでONNXフォーマットを用いて直接推論や学習を行うことも可能である。

# PythonでのONNXファイル操作例

ここではpythonのonnxモジュールを用いてONNXフォーマットを操作する様子を例示する。

## pytorchモデルのONNXフォーマットexport

```py

torch_model # PyTorch model
onnx_path = 'model.onnx'

torch.onnx.export(traced_model, inp[0], onnx_path,
                  export_params=True,
                  training=torch.onnx.TrainingMode.EVAL,
                  opset_version=18)
```

## ONNXフォーマットファイルからモデル読み込み

```py
onnx_model = onnx.load('model.onnx')
```

## モデルのノード情報列挙

```py
for node in model.graph.node:
    print("node name:", node.name)
    print("node input:", node.input)
    print("node output:", node.output)
    print("node attribute:", node.attribute)
```

## ノードの編集

実際業務で用いた例。ノードに異常な値が入力されているのが見つかったため異常な入力値を取り除いた。（Padノードの仕様として取り除かれた入力にはデフォルト値が与えられる）

```py
    for node in onnx_model.graph.node:
        if node.op_type == 'Pad':
            node.input.remove(node.input[2])

onnx.save(onnx_model, 'model_fixed.onn') # 修正モデルをファイル保存
```

## ONNX Runtimeによるモデル推論実行

```py
session = onnxruntime.InferenceSession('model.onnx')

input_dic = {input.name: None for input in session.get_inputs()}
output_names = [output.name for output in session.get_outputs()]

dummy_input = np.random.rand(1,3,640,640).astype(np.float32)
input_dic['input.1'] = dummy_input

result = session.run(output_names, input_dic)
```

# ONNXファイルの可視化

デモ

https://netron.app/
Java Scriptで電卓システムを作ろう

# はじめに
　なぜ今回、電卓システムをJavaScriptで作るに至ったかというと、私は以前、C＃の方で電卓システムを作り、難しかった記憶があり、それを私はC＃の経験をもとに、JSで新しい挑戦してみたいと思い、この計画を立てました。今回は簡易なボタン認識と四則演算のシステムを作っていこうと思います。
 　小数の計算については、うまくいかなかったので省かせていただきます。ご了承ください。

完成形
![完成形電卓.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943858/0709e960-b1d6-5464-6730-2f5033b83c98.jpeg)

codepen 
https://codepen.io/black-lacksun/pen/pvzPzOE

# HTML
 まず最初にHTMLのプログラムを紹介をします。（headの説明は省略）
 ![index_HTML.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943858/94c3c5df-ca71-a311-d37b-642628fa80d6.jpeg)

### class
"calculator" 
　電卓全体を囲むコンテナ
"buttons"
　ボタンを配置するエリア
"button"
　各ボタンの定義
appendNumber   ０～９の数字
chooseOperator 四則演算
clearDisplay   クリア
calculate      イコール
 ### id
 "expretion"  
　計算式を表示するエリア（０は初期値）
"display"    
　計算結果を示すエリア（０は初期値）

# Java Script
　次にJSのプログラムを紹介します。
 ### 変数の初期化
![qiita0.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943858/e179480e-e07a-2979-bab4-4175569ffc38.jpeg)
ここでは、それぞれの変数を初期化しています。
### 関数
![qiita1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943858/debfbc78-ce01-b971-c9c5-1c6d46d52071.jpeg)
　まず１つ目の関数は、数字を押されたときに呼ばれる関数です。
　引数numberに押された数字が渡され、currentNumberに押された数字を追加し、updateDisplay関数を呼び出してディスプレイを更新します。
 
 　次に２つ目の関数は、演算子ボタンが押されたときに呼ばれる関数です。
　引数selectOperatorに押された演算子が渡され、currentNumberが空でない場合に処理を行います。
　また、previousNumberが空でない場合に、calculate関数を呼び出して計算します。
 　operatorに選択された演算子を設定し、previousNumberにcurrentNumberを設定します。
　最後にexpressionを更新し、currentNumberをリセットしてディスプレイを更新します。
　![qiita2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943858/488271a9-15b0-5d9b-bb76-f83e9b11be3a.jpeg)

　３つ目の関数は、計算を実行する関数です。
 　previousNumberとcurrentNumberを整数に変換し、演算子に応じて計算を行い、結果をcalculationに格納します。
　そして、計算式をexpressionに更新し、currentNumberに計算結果を設定します。
　最後に演算子とpreviousNumberをリセットし、ディスプレイを更新します。
 
![qiita3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943858/69c1ee11-8c70-e779-2224-0775012a39f2.jpeg)

　４つ目の関数はディスプレイをクリアする関数です。
　すべての変数を初期化し、ディスプレイを更新します。

　５つ目の関数はディスプレイを更新する関数です。
　ディスプレイび現在の数値や、計算式を表示したり、currentNumberが空の場合は０を表示します。

# CSS
　最後にCSSのプログラムを紹介します。
 ![sscccsss.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943858/ab771b47-7c87-08e3-852e-d318fbbee09f.jpeg)

### body
　全体のスタイルを設定しています。
　背景色を薄いグレーにし、ディスプレイをフレックスボックスにして、中央配置にしています。
### .calculator
　電卓全体のスタイルを設定しています。
　背景色を白にして、パディング（余白）を追加し、角を丸くし、影を付けました。
### .display  .expression
　計算結果と計算式を表示するエリアのスタイルを設定しています。
 　フォントを大きくし、右揃え、境界線と丸みを追加しています。
  計算式エリアの文字は少し小さく灰色になるように設定を追加しています。
###.button, .buttons
　グリッドレイアウトなるものを使用しボタンの列を4列に設定したり、幅を均等にしています。
　ここでも、フォントサイズ、背景色、丸みなどを設定しています。
# まとめ
　作ってみての感想ですが、システム自体はC＃より単純にできたような感じがします。しかしながら、ボタンの配置について、C＃はカーソルでボタン配置ができていたのでCSSの大変さが身に沁みます。今後はもう少しJSなどの言語を勉強してこれより良い電卓システムを作ってみたいものです。
システム障害のふりかえり方

GLOBIS Advent Calendar 2024 20日目の記事です。

グロービスでスクラムマスター、テックリードなどをしている[@tom_bo_megane](https://x.com/tom_bo_megane)といいます。
昨年は[普段の仕事のふりかえり](https://qiita.com/tom_bo_megane/items/979fe3ea365e5076ae47)について書きました。
今回はシステム障害のふりかえり方法「ウォークスルー」を紹介します。
プログラムレビューを行う方法としてよく聞く言葉ですが、作業プロセスをチェックする方法としても有効です。ひな型画像も載せたので、参考にしていただければ。

# システム障害の分類

システム障害は内的要因と外的要因に分類されます。
- 内的要因：プログラムバグ、オペレーションミス、設定不備など
- 外的要因：自然災害、利用者環境など

システム開発・運用を担当するチームが、改善を行って防止したり減少したりできるのが内的要因になります。そのためふりかえりも内的要因のケースを取り扱って行うことが多いかと思います。

内的要因の代表的なケースを挙げます。
- プログラムバグ
  - 開発したプログラムにバグが混入し、リリース後にシステム障害を伴ったケース
  - 例：金額処理の仕様相違によるバグで誤った金額が計算される
- オペレーションミス
  - 本番環境へのリリース作業やメンテナンス作業などで、操作ミスや想定外事象によりシステム障害になったケース
  - 例：本番環境のリリース作業で操作手順を行ったが、成否判断が行わなかったためエラー発生に気づかなかった
- 設定不備
  - 本番動作に関係する設定内容の不備によりシステム障害になったケース
  - 例：開発環境の設定内容を含んだ設定ファイルを本番環境に反映してしまい一部の機能が動かなくなった

では、「プログラムバグのケース」、「オペレーションミスと設定不備のケース」について、ウォークスルーを活用したふりかえり方法に入っていきましょう。

# プログラムバグのケース

プログラムのバグが減らない、そもそも開発のすすめ方のどこに品質低下の原因があるかを探す例です。
プログラム開発の作業プロセスでよく使われるV字モデルがあります。ウォーターフォールやスクラム、内製や外注など、開発スタイルに合わせてチューニングしやすいので、僕はV字モデルをふりかえりのひな型として使っています。

### やり方

品質低下の原因探しをする場合、V字モデルが対象に役割分担されているか、各工程のインプットとアウトプットに矛盾はないかなどを観点に、作業プロセスをふりかえりの場で確認していきます。普段の開発のすすめ方を確認していくと、サンプルのシートのようになります。
![sample1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724435/00b3cd39-0da1-ea45-9bb3-3c77a0a2aca5.png)
![sample2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724435/7f2f0e2f-02ac-5ca7-65c5-ec9ff2a8f0b6.png)

あえてサンプルとしてわかりやすくしていることもありますが、以下のような矛盾に気づきます。
- 記憶を頼りにテストケースを作成している
- テストされる側のプログラムをもとにテストケースを作成している

単体テストのインプットを見直すため、手書きの写真でもよいので仕様検討したもの詳細設計として残すようになりました。

# オペレーションミスと設定不備のケース

本番環境への作業はすべて本番リリース作業と同等を原則として、「準備・リハーサル・本番実施」の工程のすすめ方の確認をします。運用されているシステムの開発時期や稼働状況に合わせられるように、以下のパターンごとに皮切り質問をひな型として用意しています。
- CI／CDのように自動化されている
- 手動実行であるが、ツール化されている
- すべて手動操作を行っている

### やり方

文末のひな型で載せたシートを見ながら読みすすめていただけるとわかりやすいかと思います。関係者で上記3パターンのうち、当てはまるものについて「準備・リハーサル・本番実施」ごとの皮切り質問に回答します。そこから実際に使用した手順書やスクリプトなどを共有しながら、状況を確認していきます。

これまでのふりかえりを思い返すと、以下のような改善ポイントがみつかってきます。
- リハーサルが行われていなかった
- 手動操作だがダブルチェックで行っていなかった
- 手順書はあるが、成否確認と確認内容が書かれていなかった
- 手順書が担当者単位で作成されて、内容がバラバラだった
- 手動ツールの仕様を知らずに利用していた

システム運用を行っていると、ある程度のプラクティスやベースとなる考え方は心得ているかと思います。でもミスは、忙しい中でも対応しないとという責任感から起こってきます。そのためふりかえりで尋問や詰問のような雰囲気にならないように、皮切り質問を書くようにしました。作業プロセスを客観的に確認していく上で効果があると感じています。

# ひな型

ここまで紹介したケースで使っているひな型です。大前提は、「客観的に作業プロセスを確認して、システム障害原因のポイントを探すウォークスルーを行うこと」です。犯人探しや責任の押し付けあいはご法度です。
次の１歩となる改善に役立てていただければ幸いです。

### プログラムバグのケース
![hinagata1_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724435/52addd11-04a2-a27b-37e0-27bf685b33fb.png)
![hinagata1_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724435/e5a4306f-20a2-74d5-4b30-46a255eb4427.png)

### オペレーションミスと設定不備のケース
![hinagata2_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724435/68c82876-b44c-7654-73fa-05a88af47326.png)
![hinagata2_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724435/df6338c7-a76e-595f-67e3-0962b40373bc.png)
![hinagata2_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724435/a83f21cb-cbb1-c4fa-458c-e31e26c2b196.png)
【PowerShell】kabuステーションAPIからトークンを取得する関数を作る【kabuステーション】

auカブコム証券では専用のツール（kabuステーション）を通してAPIで株取引を行うことができ、公式サイトでExcelマクロやJavaScriptのサンプルコードが公開されている。
本稿ではGPT-4の補助の元、PowerShellでトークン取得までを作成した。

## 事前準備
kabuステーションAPIを使用するには、事前にkabuステーションをインストールし、各種設定を済ませて起動しておく必要がある。詳細については公式サイトを参照してほしい。

https://kabucom.github.io/kabusapi/ptal/howto

### auカブコム証券のプランについて
APIの利用にはProfessionalプラン (旧Fintechプラン) 以上の適用が必要だが、2024年6月よりプランの条件が緩和されている。
以前は信用取引口座か先物オプションプラン取引口座の開設に加え、「前月で当社全取引における約定が1回以上」が必要だったが、これが「前々々月～前営業日で当社全取引における約定が1回以上」に変更された。
単純に期間が伸びた上、月の途中でも取引を行えば翌営業日からは利用できるようになる。筆者は月末近くまで取引しなかった場合はAPI適用のために適当に株を買って即売ったりしていたが、緩和後の条件であれば自然に条件を満たせそうである。

https://kabu.com/company/pressrelease/20240430_4.html

## コード
```PowerShell: Get-KabuAPIToken
function Get-KabuAPIToken {
    param (
        [string]$ApiPassword
    )

    # kabuステーションAPIの設定
    #$baseUrl = "http://localhost:18080/kabusapi" #本番用
    $baseUrl = "http://localhost:18081/kabusapi" #検証用
    $tokenEndpoint = "$baseUrl/token"

    # トークン取得のリクエストボディ
    $body = @{ "APIPassword" = $ApiPassword }

    # HTTPリクエストオプションの設定
    $headers = @{ "Content-Type" = "application/json"; "Accept" = "application/json" }

    # トークン取得リクエストを送信
    Write-Host "トークン取得リクエストを送信中..."
    try {
        $response = Invoke-RestMethod -Uri $tokenEndpoint -Method POST -Headers $headers -Body ($body | ConvertTo-Json -Depth 1)
    } catch {
        Write-Host "トークン取得中にエラーが発生しました: $($_.Exception.Message)"
        return $null
    }

    # トークン取得成功時の処理
    if ($response.ResultCode -eq 0) {
        $apikey = $response.Token
        Write-Host "トークン取得成功"
        return $apikey
    } else {
        Write-Host "トークン取得に失敗しました: 結果コード $($response.ResultCode)"
        return $null
    }
}

# 関数を使用してトークンを取得
$appPassword = "ここにAPIパスワードを設定"
$apiToken = Get-KabuAPIToken -ApiPassword $appPassword

if ($apiToken) {
    Write-Host "取得したトークン: $apiToken"
} else {
    Write-Host "トークンの取得に失敗しました。"
}
```

取り回ししやすいように関数で定義している。
ここで取得したトークンを使い各種リクエストを行うのだが、本稿ではここまで。

## 参考
https://qiita.com/hmdsg/items/c6842fe87ec4e0365241

https://qiita.com/OstrichFarmLtd/items/c0a61514cfc0242ff01b

https://qiita.com/uedatakeshi/items/2fd222b87be12e829024