OmniAICreator/Qiita-1.07M huggingface dataset:
Bubingaアプリを始めよう：初心者向けチュートリアル

Bubingaは、多機能で使いやすいオンライン取引アプリです。初心者でも簡単に取引を開始できるように設計されており、幅広い取引オプションとツールを提供しています。本記事では、Bubingaアプリの基本的な使い方を初心者向けに解説し、スムーズに取引を始めるためのステップバイステップガイドを提供します。

Bubingaアプリの基本設定
1. アカウントの登録
まずはBubingaアプリをダウンロードし、アカウントを作成します。

アプリのダウンロード：Bubinga https://bubinga-bo.com/bubinga-app/ アプリは、iOSとAndroidの両方で利用可能です。App StoreまたはGoogle Playストアからダウンロードしてください。
アカウント作成：アプリを開き、「新規登録」ボタンをタップします。名前、メールアドレス、電話番号などの基本情報を入力し、アカウントを作成します。
認証：登録したメールアドレスに認証メールが送信されるので、メール内のリンクをクリックして認証を完了させます。
2. アカウントのセットアップ
アカウント作成後、次のステップに進みます。

プロフィール設定：個人情報を入力し、プロフィールを完成させます。
入金：取引を開始するために、銀行振込やクレジットカード、電子ウォレットなどの方法でアカウントに入金します。
Bubingaアプリの基本操作
1. ダッシュボードのカスタマイズ
Bubingaアプリのダッシュボードは、自分の取引スタイルに合わせてカスタマイズできます。

ウィジェットの追加：マーケットデータ、ニュース、ポートフォリオのウィジェットを追加して、重要な情報に素早くアクセスできるようにします。
テーマの選択：アプリのテーマを変更して、見やすいデザインに設定します。
通知の設定：価格アラートやニュース更新の通知を設定し、リアルタイムで情報を受け取ることができます。
2. 取引の基本
Bubingaアプリで取引を始めるには、次の手順を踏みます。

取引する資産の選択：株式、為替、暗号通貨など、取引したい資産を選びます。
注文の発注：選んだ資産の取引画面で、「買い」または「売り」を選択し、数量と価格を入力します。注文の種類（成行注文、指値注文、逆指値注文など）も選択できます。
注文の確認：注文内容を確認し、問題がなければ発注します。発注後、取引履歴で注文のステータスを確認できます。
3. 技術指標の利用
Bubingaアプリでは、さまざまな技術指標を利用して市場分析を行えます。

移動平均線（SMA、EMA）：価格トレンドを確認するために、単純移動平均線（SMA）や指数平滑移動平均線（EMA）をチャートに追加できます。
相対力指数（RSI）：資産が買われすぎか売られすぎかを判断するための指標です。チャートにRSIを追加して、市場の勢いを把握します。
ボリンジャーバンド：価格の変動範囲を視覚化し、価格の反転ポイントを見つけるのに役立ちます。チャートにボリンジャーバンドを追加して、価格のボラティリティを確認します。
効率的な取引のためのヒント
1. リスク管理
リスク管理は、成功するトレーダーにとって不可欠です。

損切り注文：損失を最小限に抑えるために、損切り注文を設定します。
ポートフォリオの分散：リスクを分散させるために、複数の資産に投資します。
2. 学習と改善
取引は継続的な学習が重要です。

チュートリアルとガイド：Bubingaアプリには、取引の基本から高度な戦略までをカバーするチュートリアルとガイドがあります。
デモアカウントの利用：実際の資金を使わずに取引の練習をするために、デモアカウントを活用します。
3. 市場分析
市場を分析し、情報に基づいた取引を行います。

ニュースと市場データ：最新のニュースと市場データを追跡し、取引の意思決定に役立てます。
技術分析：チャートと技術指標を使用して、市場の動向を予測します。
まとめ
Bubingaアプリは、初心者から上級者まで幅広いトレーダーに対応した強力な取引プラットフォームです。アカウントの設定から取引の基本、技術指標の利用まで、このチュートリアルを参考にして、スムーズに取引を始めましょう。リスク管理と継続的な学習を心がけ、Bubingaアプリでの取引を最大限に活用してください。
Excelでのタスク管理方法

こんにちは、小磯と申します。
課題が発生した際、客先や環境により様々なツールで管理していると思いますが、今回はExcelでのタスク管理方法について纏めようと思います。
管理者やPM(PMO)が始めての方へ参考になればと思います。

### Excelでのタスク管理方法

課題が発生した際、Excelへ記載しタスク管理をしていると思いますが、
タスク期限や完了した場合、目視で行っている場合はケアレスミスやヒューマンエラーが起きるため、
設定することで確認漏れやミスの防止に繋がればと思います。

## 1.課題の項目
プロジェクトや管理する方によって項目が違うと思いますが、私が必要と思われる項目は以下になります。
- No
- 分類
- 課題
- 起票者
- 起票日
- 担当者
- 対応期限
- 詳細
- 対応完了日
- 備考


## 2.課題項目の詳細
項目を設定しましたが何を記載するのかですが、詳細は以下です。
- No
→作成時に振り分け、管理をする。
- 分類
→プロジェクトの工程を記載。
- 課題
→課題、障害、宿題事項を記載。
- 起票者
→課題を記載した方の名前を記載。
- 起票日
→課題を記載した日付を記載。
- 担当者
→課題への対応者を記載。
- 対応期限
→完了可能な期限を決め記載。
- 詳細
→課題への進捗があった場合に記載。
- 対応完了日
→課題への解決、完了した日付を記載。
- 備考
→詳細への記載が難しい内容を記載。
　資料格納場所やURL等。


## 3.条件付き書式の利用
対応期限が近付いている課題がある場合、目視だと期限切れが発生する可能性があります。
条件付き書式を利用することで、確認漏れを防ぐことが可能です。
期限が1週間前、当日、超過した場合の条件付き書式の設定内容を説明します。
### 期限が1週間前の場合
①対応期限の日付入力したセルを選択
②メニューより「ホーム」-「条件付き書式」-「新しいルール」を選択
③書式ルールの編集画面にあるルールの種類に「指定の値を含むセルだけを書式設定」を選択
④ルールの内容に以下を設定
　「セルの値」「次の値より小さい」「セルの値+7(例：= I3+7)」
⑤プレビューより「書式」を選択し、セルの書式設定画面より「塗りつぶしの色」「フォントの色」を選択し「OK」を押下
　（例：「黄色塗りつぶし」「黒文字」）
⑥書式ルールの編集画面に「OK」を押下
⑦条件付き書式ルールの管理画面より「OK」を押下

### 期限が前日の場合
①対応期限の日付入力したセルを選択
②メニューより「ホーム」-「条件付き書式」-「新しいルール」を選択
③書式ルールの編集画面にあるルールの種類に「指定の値を含むセルだけを書式設定」を選択
④ルールの内容に以下を設定
　「日付」「明日」
⑤プレビューより「書式」を選択し、セルの書式設定画面より「塗りつぶしの色」「フォントの色」を選択し「OK」を押下
⑥書式ルールの編集画面に「OK」を押下
⑦条件付き書式ルールの管理画面より「OK」を押下

### 期限が過ぎている場合
①対応期限の日付入力したセルを選択
②メニューより「ホーム」-「条件付き書式」-「新しいルール」を選択
③書式ルールの編集画面にあるルールの種類に「指定の値を含むセルだけを書式設定」を選択
④ルールの内容に以下を設定
　「セルの値」「次の値より小さい」「セルの値(例：=I3)」
⑤プレビューより「書式」を選択し、セルの書式設定画面より「塗りつぶしの色」「フォントの色」を選択し「OK」を押下
　（例：「赤色塗りつぶし」「黒文字」）
⑥書式ルールの編集画面に「OK」を押下
⑦条件付き書式ルールの管理画面より「OK」を押下

4.課題が完了した場合の条件付き書式の利用
課題が完了した際、色分けをすることにより課題状況の見分けがつきます。
課題完了時について条件付き書式の設定内容を説明します。
①対応期限の日付入力したセルを選択
②メニューより「ホーム」-「条件付き書式」-「新しいルール」を選択
③書式ルールの編集画面にあるルールの種類に「数式を使用して、書式を設定するセルを決定」を選択
④ルールの内容に以下を設定
「セルの値(例：=L5<>"")」
⑤プレビューより「書式」を選択し、セルの書式設定画面より「塗りつぶしの色」「フォントの色」を選択し「OK」を押下
　（例：「灰色塗りつぶし」「黒文字」）
⑥書式ルールの編集画面に「OK」を押下
⑦条件付き書式ルールの管理画面より「適用先」の範囲を設定
　（1.課題の項目に提示した範囲を選択します。　例：=B5:M5）
⑧条件付き書式ルールの管理画面より「OK」を押下

## まとめ
課題管理をするにあたり色分けをすることにより、確認の時間短縮になります。
また、期日が近い課題に対してのタスク管理もしやすいと思います。
期限超過した課題についても、反省点や今後の対策に繋がると思います。

以上、小磯でした。
テーブルを追加したらコンパイルエラーでビルドできなくなった話

こんにちは、サーバエンジニアの池脇と申します。
今回は私が実際に経験した失敗談とそこから得た学びについてまとめようと思います。
どなたかの参考になれば幸いです。

## テーブルを追加しただけでコンパイルできなくなった！？
JavaのSpringBootを使って新規テーブルを追加する作業は開発者にとって日常的な作業です。
しかし、ある日新規テーブルを追加し、いつものようにコードの自動生成を走らせてビルドを行ったところまさかのコンパイルエラーに直面しました。
エラーの内容は
```
パラメータが多すぎます。(too many parameters)
```
というものでした。

## なぜコンパイルエラーが起きたのか
上記エラーの内容と発生箇所から、これはコンパイラが受け付けるコンストラクタのパラメータ数が上限を超えていることが原因ということはわかりました。
しかしなぜエラーが発生したのか……？

エラーの発生に至った背景を探ると次のことが明らかになりました。
私のプロジェクトでは、マスタデータのキャッシュを暖気するためのクラスを自動生成していました。このクラスは `private final xxxDao`といったfinalフィールドをテーブルの数分自動生成によって宣言し、`@RequiredArgsConstructor`の特性を利用してコンストラクタの生成を行なっていました。
```java
@RequiredArgsConstructor
public class CacheWarmUpController {
    private final FooDao fooDao;
    private final BarDao barDao;
    // ...
    private final BazDao bazDao;
```
しかし、新しいテーブルを追加したことで、この`xxxDao`の数が255個を超えてしまい、生成されたコンストラクタのパラメータ数がJavaの上限を超えたためにコンパイルエラーが発生しました。

## どう対処したのか
今回は各マスタデータ用の`xxxDao`を直接`ApplicationContext`から`getBean`する方法を選択しました。
これによりコンストラクタ内で大量の`xxxDao`を直接受け取る必要がなくなり、コンパイルエラーを回避することができました。
```java
@RequiredArgsConstructor
public class CacheWarmUpController {
    private final ApplicationContext applicationContext;

    public String warmUpMasterCache() {
        FooDao fooDao = applicationContext.getBean(FooDao.class);
        BarDao barDao = applicationContext.getBean(BarDao.class);
        // ...
        BazDao bazDao = applicationContext.getBean(BazDao.class);
```

## 今回の失敗から得た学び
- **動的に変化する要素に対する注意**
  自動生成の際に動的に増減する要素（今回であればテーブル数）が上限を超えないよう、慎重に設計と管理を行う必要があります
- **使用しているアノテーションの詳細について把握**
  `@RequiredArgsConstructor`等のアノテーションを使用する場合は、そのアノテーションが何をするものなのか把握した上で影響範囲をしっかりと確認しなければいけません

## まとめ
今回の失敗からは普段使用しているものの制限や上限等を把握しておくこと、またそこに抵触する際の対処法を検討しておくことの大切さを学びました。
特にコード自動生成の領域では、プロジェクトの規模や複雑さが増すにつれて思わぬところで上記のような問題が発生するかと思います。今回のような失敗談は決して珍しくなく、他の開発者たちも同様の課題に直面することもあるでしょう。この経験を共有することで、より良いプログラム設計や問題解決のアプローチにつながることを期待しています。
プログラミング言語で動く音楽用シーケンサの仕様。

### 概要

プログラミング言語を書くと演奏できるシーケンサを作成中です。
とりあえず音が鳴る部分まで作っている状態だが、仕様が固まってきたのでこういうところに記載を残すもの。

#### 動いてるところ
https://x.com/MachiaWorx/status/1815080679572734196

### 詳細

発音はminiaudioを利用。

#### 公式
https://miniaud.io/

#### これで何をするか
オーディオ再生を行いたい。
自分の場合はシンセサイザーを作成したい。
ついでにMIDI出力を組み合わせたい。

#### 実装リファレンス
https://miniaud.io/docs/manual/index.html
1.1のLow Level APIを使う。
もちろんHighLevelAPI使うのでもいいんだけど、エンジンの都合により再生システムを変更することが往々にして存在するので、低レベル部分に手が出せるようにする。
実際、LowLevelAPIで作ろうとした時点で不都合が起きたので、LowLevelAPIを参考に改造して同様の機能を持つAPIを作成した上で動作させた。

IFを利用して定型的な処理としてオーディオを流すようにしているが、最初から用意されているものについてはLowLevelAPI上に1音程度鳴る想定のものしかない。
（おそらくHighLevelAPIで複数の音を鳴らす想定なのかと）

あまりAPIに依存してしまうと波形アクセスが困難なケースに遭遇してしまう可能性が高くなるため、LowLevelAPIとして複数波形にアクセス可能とした。
よって自分が作ったAPIだと、LowLevelAPIだけどシンセサイザー＋サンプリングの音が複数発音可能になっている。
ついでに後述するとMIDI再生も同期するようにしている。

なお、WASAPIのみ想定。
（レイテンシー減少はそれほど求めない）

#### MIDI再生

PortMidiを利用。
https://portmidi.github.io/portmidi_docs/index.html

シーケンスは別途登録して流すが、miniaudioのコールバック関数上でMIDI再生（NoteOn/NoteOFF）を起動できるようにした。
元々別にスレッドを立ててシーケンスを再生しようとしたが、計算タイミングの違いにより同期が困難だったため、コールバック関数上でMIDI関連のメッセージ送信を行うこととした。
PortMidiの関数で「現在時刻＋秒数」で発音指定ができる命令があるのでそれを使う。
デバイス切り替えの時間やそれに伴う処理待ち等が入るかと思ったがそうでもなかった。
例：Printfで出力先を指定する場合、コールバックを阻害する可能性あり。

結果としてドライバがコールバックを阻害することなく、かつデータ量も抑えて送信することができるようになった。
副次的な効果として、オーディオとMIDI再生がほぼ同期するようになった。

#### シーケンス
MiniScriptのリスト構造を読んで、現在再生中の秒数が全体のうちの何割かを求めて、その位置に該当するリストの値を検知、これを再生する譜面としてオーディオ・MIDI出力・サンプリング再生のコールバック関数に渡すこととした。
コールバックのバッファ処理バイト数から進んだシーケンスの時間を導出して反映し、そこからシーケンスの時間を求めることにした。

MiniScript
https://miniscript.org/

最初はdouble変数で計算精度や速度に問題でないかなー？と思っていたが、常用に問題ないことを確認したため、実装では全体的にdouble/longサイズの変数を利用している。

### 終わりに
11月くらいには公開予定なので興味のある方は使ってみてください。
facefusionをpaperspaceのGradientで実行するときの注意点

facefusionをM2Macローカルで動かしてみたが、NvidiaのGPUだとどれくらい早くなるのか気になってpaperspaceのGrowthプランを契約しちゃいました。

ここでは、色々とハマったポイントと注意点を書いておきます。

## SSHトンネリングは禁止

最初Ngrokを使ったらアカウントが凍結されました。
メールしたらすぐに解除してくれたけど、メールでSSHトンネリングは禁止だと言われました。

そして、最初はLocaltunnelを使っていたのですが、何故かうまく動かなくなったので、Gradioのlive機能を使うことでこれを回避しました。

## 解決策

facefusionをインストールした後、以下のファイルのrun関数を修正します。

### facefusion/facefusion/uis/layouts/default.py

### 修正前
```
def run(ui : gradio.Blocks) -> None:
	concurrency_count = min(8, multiprocessing.cpu_count())
	ui.queue(concurrency_count = concurrency_count).launch(show_api = False, quiet = True, inbrowser = facefusion.globals.open_browser)
```
### 修正後
```
def run(ui: gradio.Blocks) -> None:
    concurrency_count = min(8, multiprocessing.cpu_count())
    ui.queue(concurrency_count=concurrency_count).launch(
        show_api=False, 
        quiet=True, 
        inbrowser=facefusion.globals.open_browser, 
        share=True  # ここに `share=True` を追加します
    )
```

これで、垢バンされずにWebUIが使えるようになりました。
paperspaceのWebUIだと死ぬほどアップロード遅いのどうにかしてほしいんだがなぁ。
ローカルマシンからのUPは遅くてwgetとか使えば早いらしいが、結構めんどくさい。

このサイトでおすすめされてるラットホール方式やるかなぁ。
https://gist.github.com/Cyberes/f050b03e59ccdf232527751f17f7ae4e

とりあえず、今はjupyter notebookのアップローダーでinput imageとtarget videoを上げておいて、リネームしてfacefusion.iniにパスを書く方法で対応中。
Windows11でDockerを使用できるようにする

# Dockerとは
Dockerとはコンテナ型の仮想環境を構築するためのツールです。Dockerを使うと、開発者は面倒な環境構築や管理を行わずに、どこでもアプリケーションを構築、共有、実行、検証できるようになります。
コンテナを配布することにより、異なる場所でも同じ環境で開発や運用を行うことができます。
WindowsやMac、はたまたLinux上に仮想環境を構築しその上で開発を行います。
コンテナには、アプリケーションやフレームワーク、ベースとなるオペレーティングシステムに至るまで、コードを実行するために必要なものがすべて用意されています。

# Dockerのインストール手順
今回はWindows11(23H2)にDockerをインストールしていきます
手順は以下ページを参考にしています。

https://docs.docker.com/desktop/install/windows-install/


Docker Desktopをインストールするシステム要件は以下のとおり

* Windows 64ビット
* WSL2機能
* 4GB以上のシステムRAM
* BIOSでハードウェア仮想化が有効になっていること

もし BIOS/UEFI で無効になっていれば、有効化が必要です。

### 使用しているPC

* OS：Windows11 Pro (23H2)
* CPU：intel core-i7 14700f
* メモリ：32GB

# 1. Docker Desktopのダウンロード
公式サイトからDocker Desktopのインストーラをダウンロードします。

* [Docker Desktop for Windows](https://docs.docker.com/desktop/install/windows-install/)のページにアクセス
* 「Docker Desktop for Windows - x86_64」ボタンをクリックしてインストーラをダウンロードする
* ダウンロードしたインストーラをダブルクリックしてインストールを実行
    * Dockerをインストールするコンフィグレーションのチェックを選択
    * ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604944/488096e1-7573-fb05-8548-baf91e1aaf3b.png)
        * 今回はHyper-VではなくWSLを使用する
        * デスクトップへのショートカットは不要なのでチェックを外す。必要な方はチェックを付けて先に進む
* 「OK」をクリックしてインストールが実行されます。WSLが入っていない場合は自動でインストールもしてくれます
* しばらく待つとインストールが完了します。インストールに成功すると、「Installation succeeded」（インストール成功）が表示されるはずです。
    * ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604944/e426658a-6042-5ba3-7776-f6287d293cfe.png)
* 「Close and restart」をクリックしPCの再起動を行います。消えて困るファイルや他の作業中であれば作業を終えてから再起動してください。

# 2．Dockerのセットアップ
再起動が終わると自動的にDockerの画面が起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604944/795cfa41-3d92-0089-067e-9922a91bb502.png)

Dockerのサブスクリプションの同意について書かれています。
Acceptを押すとサブスクリプションサービスの同意とともにデータプロセッシングの同意とプライバシーポリシーに同意したことになります。

従業員が250人以上の企業、もしくは売り上げが1000万ドル（＄10million）以上の場合はサブスクリプションの支払いが必要となります。
今回は個人の仕様で、かつ商用ではないので無料で使用します。

___

次にDockerの設定を行います。
ここで聞かれる内容はWSL2のアップデートについてです。

`Use advanced settings`を選択すると手動でアップデートを行う設定になります。
特に理由がなければ上の`Use recommended settings`でよいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604944/7b56cf2f-fe49-e429-8bf0-c7b398683425.png)

ここまででDocker Desktopのインストールが完了します。

この後はDockerのアカウントでログインし、Dockerを使用することができます。

# 最後に






















以前書いたLinux（Ubuntu24.04）へのDockerインストールもご覧ください。

https://qiita.com/Marron-chan/items/570c7c7baaae3b4d6b11
【Power Apps】じゃんけんゲーム作成の軌跡①

### Power Appsでタイマーを勉強しようとした時、ふと思った。
じゃんけんゲームを作ろうと・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3737462/44a065ed-04dc-e399-b6e3-2f0b126848e3.png)
こんなの作れないかなと思い、とりあえず「icooon mono」でそれっぽいアイコンをダウンロード
https://icooon-mono.com/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3737462/d928ef98-a393-d4fe-2961-10e3ea1c2186.png)

頭の中で仕様をイメージ
①機械側：タイマー走らせてModで3で割って数値0,1,2を取り出してグー、チョキ、パーの判定　Context関数に入れる
②自分側：グー、チョキ、パーに数値を振り当てContext関数に入れて
③判定：①と②で変数を比較　勝ちor負けorあいこ判定
④勝ちor負けの場合は終了あいこの場合は一定時間止まって再度じゃんけんが始まる
⑤＋α機能つける（文字表示、コイン払い出しルーレット、声、所持コイン枚数表示・・・）

とりあえず今回は①～④までやってみる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3737462/a3c7ab1f-e857-1b41-4cb4-369498c52681.png)
雑にコントロールトセット

<dt>機械側のイメージコントロール</dt>
Visible：If(Mod(timJankenJanken.Value,3)=0,true,false)

動き：これでじゃーんけーんって言っている間はグーチョキパーがピコピコ変わる

<dt>じゃんけんスタートボタンコントロール</dt>
onSelect:UpdateContext({locReset:true});
         UpdateContext({locReset:false});
　　　　 UpdateContext({locStart:true});

動き：なんか適当に色々リセットした後に
    　タイマー１のスタートの値をtrueにしてじゃんけんがスタートする

<dt>自分側のイメージコントロール</dt>
OnSelect：UpdateContext({locResult:2,
                         locStart:false,
　　　　　　　　　　　　locAikohantei:Mod(timJankenJanken.Value,3
                                          )
                        })
                        
動き：locResultが自分、locAikohanteiが機械側　それぞれContext関数に入れる
　　　機械側のピコピコ変わるのを止めるためにlocStartをfalseに変更

ここまでで終了ですがあいこの場合タイマー２を起動させる

<dt>タイマー２のタイマーコントロール</dt>
Start：If(locResult=locAikohantei,true,false)

動き：上記２つの変数が同じ（＝あいこ）の場合trueになるのでタイマースタート
　　　この時間はフリーズ時間
　　　ここでプレイヤーはあいこを確認する
OnTimerEnd：UpdateContext({locStart:true,
　　　　　　　　　　　　　　locAikohantei:Blank()});
　　　　　　UpdateContext({locReset2:true});
 　　　　　　UpdateContext({locReset2:false})

動き：フリーズ時間が終了したらタイマー１を動かし、機械側の変数をBlankにしたのち
　　　タイマー２をリセットするためにlocReset2をカチカチする

これでいったんじゃんけんはできるようになりました
ただし最初画面表示時にタイマー２のStart条件
If(locResult=locAikohantei,true,false)がtrueとなってしまうため
falseとなるようlocResultを適当に変数の値を入れておきます

次回は「じゃんけん」「あいこで」「勝ち」「負け（ズコー）」の表示が出るようにしたいと思っています
paizaの問題をPowerShellで解いてみた 【本の整理 (paizaランク A 相当)】

この記事はpaizaのプログラミング問題をPowerShellで解いてみようという試みの記事です。

## paizaのプログラミング問題とは？
ブラウザ上でコードを書いて実行できる、無料プログラミング練習問題集です。
1. 難易度別に問題を選ぶ
2. 問題文を読んで、解答コードを書く
3. 提出するとテストケースが実行されて結果をわかる
正解・不正解だけではなく、解答コード例や解説も見ることができるので、プログラミングの習得から復習まで活用できます

## こんな人におすすめ
- プログラミングスキルの腕試しをしたい方
- プログラミングのスキルアップしたい方
- 新しい言語にチャレンジをしたい方

###

通常は問題をc言語やJavaなどで解くのですがこの記事ではPowerShellで解いてみます。

## 問題

本の整理 (paizaランク A 相当)

https://paiza.jp/works/mondai/real_event/book_sort

あなたはパイザ図書館で働く図書館員です。

パイザ図書館には N 冊の蔵書があります。この蔵書はすべて 1 段からなる本棚で管理されています。そして、それぞれの本には 1 から N までの相異なる整数の ID がついています。本棚の本は ID 順に並んでいます。

しかし、ある日、あなたが蔵書の点検をしていると、本棚の本がバラバラに並べられていることに気づきました。

そこで、あなたは、次のルールに従って本を並び替えることにしました。

次の手順を N 回繰り返す。

1. i (1 ≦ i ≦ N) 回目の手順では、まず本棚の左から i 番目の位置に立つ。
2. 左から i 番目の位置にある本から、本棚の右端にある本までのうち、最も ID が小さい本の位置を歩きながら見つける。この位置を j とする。
3. i = j なら、何もしない。 i ≠ j なら、i 番目の本と j 番目の本を入れ替える。


本を取り出して入れ替えるのには時間がかかります。そこで、このルールに従って本を整理するときに、何回本を入れ替える必要があるのかを計算してください。



#### 解き方:
問題文にあるようにn回ループしてi番目の本を順に交換して交換回数を出力します。


#### コード:

~~~
# 本の初期位置入力
$n = [int](read-host)

$shelf = @()
foreach($i in (read-host).split()){
    $shelf+=([int]($i)-1)
}

# 各本の位置を記録する配列を用意
$pos = @()
(1..$n) | %{$pos+=-1}
(0..($n-1)) | %{$pos[$shelf[$_]]=$_}

# 解答用変数　本の交換回数
$swapcnt = 0

# 本を並び替える
(0..($n-1)) | %{
	# 既に正しい位置にある本はスキップ
	if($shelf[$_] -ne $_){
	    # 交換回数カウントアップ
	    $swapcnt += 1
	
	    # i番目の本と現在の位置の本を交換
	    $shelf[$pos[$_]] = $shelf[$_]
	    $pos[$shelf[$_]] = $pos[$_]
	}
}

write-host $swapcnt
~~~


#### コードの説明:
- 標準入力から本の初期位置を読み込む:
~~~
$n = [int](read-host)

$shelf = @()
foreach($i in (read-host).split()){
    $shelf+=([int]($i)-1)
}
~~~
配列shelf に入力値を格納する際にプログラム内で扱いやすいように本のID を -1 しています。


- 標準入力から本の初期位置を読み込む:
~~~
# 各本の位置を記録する配列を用意
$pos = @()
(1..$n) | %{$pos+=-1}
(0..($n-1)) | %{$pos[$shelf[$_]]=$_}
~~~
計算用の配列posを用意して初期値をセットします。
(1..n)と書くとn回ループ、ループ変数は$_


- 本の交換回数を保存する変数を用意
~~~
# 解答用変数　本の交換回数
$swapcnt = 0
~~~

- 本を並び替える
~~~
# 本を並び替える
(0..($n-1)) | %{
	# 既に正しい位置にある本はスキップ
	if($shelf[$_] -ne $_){
	    # 交換回数カウントアップ
	    $swapcnt += 1
	
	    # i番目の本と現在の位置の本を交換
	    $shelf[$pos[$_]] = $shelf[$_]
	    $pos[$shelf[$_]] = $pos[$_]
	}
}
~~~
本の位置が正しい場合はスキップ、違う場合は位置交換を行い、交換回数をカウントアップしていきます。

- 解答の出力
~~~
write-host $swapcnt
~~~

### 終わりに
noteにPowerShellのサンプルコードの記事を書いています。そっちも見てね
[PowerShellまとめ](https://note.com/mahalo_/m/m421b17a881c8)

https://note.com/mahalo_/m/m421b17a881c8
Python Selenium [ docker: no matching manifest for linux/arm64/v8 in the manifest list entries. ] の解決方法

# 背景
Raspberry Pi を使って Selenium を実行しようとしたところ、エラーが出たので解決策を残しておきます。
<br>
# 今回解決できたエラー
+ docker: no matching manifest for linux/arm64/v8 in the manifest list entries.
<br>

# 解決策
結論から言うと、使おうとしたDockerイメージがアーキテクチャにあってないから出たエラーでした。
なので、アーキテクチャにあったイメージを使えば解決できました。

### Docker run
```bat
docker run -d -p 4444:4444 -p 7900:7900 --shm-size="2g" seleniarm/standalone-chromium:latest
```

https://hub.docker.com/r/seleniarm/standalone-chromium

このイメージを使うことで正常に動くはずです。

### Python code
```python
from selenium import webdriver
from selenium.webdriver.common.by import By
import time

driver = webdriver.Remote(
    command_executor = "http://192.168.0.***:4444/wd/hub",
    options = webdriver.ChromeOptions()
)

url = "https://www.hoge/any-url"

driver.implicitly_wait(10)

driver.get(url)

class_elm = driver.find_element(By.CLASS_NAME, "class_name")

time.sleep(5)

print(class_elm)

driver.quit()
```

<br>

# 最後に
seleniumの基本的な使い方は下記が参考になりました。

https://kuku81kuku81.hatenablog.com/entry/2023/03/20_python_selenium_how_to_find_elements

参考になれば幸いです。

動的スクレイピング遅すぎる...
ブビンガのEMAとSMAの紹介

ブビンガ https://bubinga-bo.com/ Bubinga）は、多くのトレーダーにとって信頼できるオンライン取引プラットフォームとして知られています。さまざまな技術指標が提供されており、その中でも特に重要なものが移動平均線（MA）です。移動平均線には、単純移動平均線（SMA）と指数平滑移動平均線（EMA）の2種類があります。本記事では、ブビンガプラットフォーム上で利用できるSMAとEMAの特徴、使い方、およびそれぞれの利点について詳しく紹介します。

移動平均線（MA）とは？
移動平均線は、特定の期間にわたる価格の平均値を計算し、チャート上に描画することで価格のトレンドを視覚的に捉えるための指標です。価格の変動を平滑化し、市場のノイズを除去することで、トレーダーがトレンドの方向性を確認しやすくします。

単純移動平均線（SMA）
**単純移動平均線（SMA）**は、特定の期間内の価格の平均を計算し、その値を連続してプロットすることで形成されます。例えば、10日間のSMAは、過去10日間の終値を合計して10で割った値です。SMAはそのシンプルさゆえに、トレンドの基本的な把握に役立ちます。

指数平滑移動平均線（EMA）
**指数平滑移動平均線（EMA）**は、SMAと異なり、最新の価格により大きなウェイトを置くことで、価格変動に対する応答性を高めた指標です。EMAは最近の価格データを重視するため、急な価格変動に対して敏感に反応します。これにより、トレーダーはより迅速にトレンドの変化を捉えることができます。

ブビンガでのSMAとEMAの使い方
ブビンガプラットフォーム上でSMAとEMAを設定する方法は非常に簡単です。以下に、基本的な手順を紹介します。

1. プラットフォームにログイン
まず、ブビンガのアカウントにログインします。アカウントがない場合は、簡単な手続きで新規登録を行ってください。

2. チャートを表示
ログイン後、取引したい銘柄のチャートを開きます。チャートの上部またはサイドバーにある「インジケーター」ボタンをクリックします。

3. インジケーターの追加
インジケーターリストから「SMA」または「EMA」を選択します。選択すると、設定ウィンドウが表示されます。

4. パラメーターの設定
設定ウィンドウで、期間（例：10日、20日、50日など）を入力し、適用します。また、表示する線の色やスタイルをカスタマイズすることもできます。

5. チャートへの適用
設定が完了したら、チャートにSMAまたはEMAが表示されます。これで、トレンドの分析が可能になります。

SMAとEMAの利点
SMAの利点
シンプルで分かりやすい: 計算方法がシンプルで、初心者にも理解しやすい。
長期トレンドの確認: 長期間のトレンドを確認するのに適しており、ノイズが少ない。
EMAの利点
応答性が高い: 最新の価格変動に敏感に反応し、短期的なトレンドを迅速に捉えることができる。
トレンド転換の早期発見: 価格の急激な変化に対応しやすいため、トレンドの転換点を早期に発見しやすい。
SMAとEMAの使い分け
トレード戦略によって、SMAとEMAを使い分けることが重要です。

長期トレード: 長期間のトレンドを把握するために、SMAが適しています。50日や200日のSMAは、主要なサポートやレジスタンスレベルを確認するのに役立ちます。
短期トレード: 短期的な価格変動を捉えるためには、EMAが有効です。10日や20日のEMAは、短期的なエントリーやエグジットのシグナルとして活用できます。
結論
SMAとEMAはどちらもトレーダーにとって重要なツールです。それぞれの特徴と利点を理解し、適切に使い分けることで、トレードの精度と成功率を高めることができます。ブビンガプラットフォーム上でこれらの移動平均線を効果的に利用し、より良いトレード判断を下すためのスキルを磨いてください。トレードの成功には、適切なツールの選択とその効果的な活用が欠かせません。
Go構造体のバリデーション: スペースの落とし穴

# はじめに
ウェブアプリケーションを開発する際、HTTPメッセージボディのデータの検証を行う場合があります。
例えば、ユーザーが入力した情報が必須項目を満たしているか、数値が適切な範囲に収まっているかなど。
Go言語でバックエンド開発を行うときには、構造体を使用したバリデーションが一般的です。

## Go言語でのバリデーション
Go言語では構造体を定義しそのフィールドに対してバリデーションルールを設定することができます。これにより、データの一貫性と正確性を確保し、エラーを未然に防ぐことができます。

``` struct.go
type Person struct {
    Name string `json:"name" binding:"required,min=3"`
    Age int    `json:"age" binding:"required,min=0,max=100"`
}
// required: `Name`, `Age`共にフィールドは必須で、空の値は許可されない
// min=3: `Name`フィールドの値は最低でも3文字以上でなければならない
// min=0: `Age`フィールドの値は0以上でなければならない
// max=100: `Age`フィールドの値は100以下でなければならない
```

このPerson構造体では、NameとAgeのフィールドに対してバリデーションルールを設定しています。これにより、フォームから送信されたデータが自動的にチェックされ、これらの条件を満たしていない場合はエラーが発生します。

# バリデーション記述での落とし穴
バリデーションタグにスペースが含まれていると、期待通りに動作しないことがあります。例えば、以下のようにスペースを含めるとエラーが発生します。

``` struct.go
type Person struct {
    Name string `json:"name" binding:"required, min=3"`
    Age int    `json:"age" binding:"required, min=0, max=100"`
}
```

この例では、bindingタグ内のや`min=*`や`max=*`の前にスペースが入っています。このようなスペースがあると、バリデーションはタグを正しく解釈できず、エラーとなってしまいます。

# まとめ
Go言語での構造体バリデーションは便利ですが、タグ内のスペースに注意する必要があります。スペースがあるとバリデーションが正しく行われず、予期しないエラーが発生する可能性があります。正確なタグを使用して、確実にバリデーションが機能するようにしましょう。
学習記録アプリ

## はじめに
Reactの学習を始めて2か月。ここ最近、会社の設立準備をしていることもあり学習に時間がとれていなかったのですが、ようやく課題を1つ終えることができ、学習記録アプリを作るという課題を終えることができました。この開発を通じて学んだことをまとめておきます。


## 作ったもの
![5085f80a-5d81-05f5-d20c-80bdbfe116f2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3502843/d6d8df6f-d742-865b-556c-a8efa740db71.gif)

##　開発を通じて学習したこと


・Viteでの開発環境の構築
・Supabaseの利用
・Chakra UIの活用
・Firebaseデプロイ
・Makeデプロイ
・CI/CD
・Jestによるテスト
・READMEの作成

## 感想
webアプリの開発が初めて、CI/CDも初めて、テストもほとんど経験なし　という状態だったのでほぼすべてゼロから調べて取り組んだので、時間はかかりましたが、まったくやったことのないことに取り組めたので、アウトプット以上に学びがありました。
個人事業主として働いていて、同僚にエンジニアがいない状態で、この先もしばらくそれが続くのでできるだけ人に頼らず学習をしているのですが、一度も質問せずにすべてやりきることができました（そう決めてやっているわけではないのですが、結果的に質問しなかった）。AIによる開発支援を使いまくったからできました。非エンジニアのAI活用によるプログラミング法は、どこかでまとめて記事にしたいと思います。

またここからさらに課題の難易度が上がってくる様なので、引き続き頑張っていきたいと思います。

## JISOUについて
プログラミングコーチングJISOUではメンバーを募集していて、HPからライン登録することができます👇
とてもいいコミュニティなのでお勧めです。
https://projisou.jp
【備忘録】初めてのiOSアプリ開発 第8回 アノテーション

## アノテーションとは
・コードに注釈を追加する機能のこと
コードに付加情報を提供するためのラベルやマークのようなもので、特定の部分に追加の情報や意味を持たせることができる

### アノテーション
・コンパイラの挙動を制御する。
・コードの意図を明確にする。

## アノテーションの役割
・特定のコード部分のコンパイル方法を変更
・特定の最適化を適用

コードの文書化
・コードの意図や使用方法を明確にするための情報を提供する

警告やエラーの生成
・あるコード部分が非推奨であることや、特定の状況下での使用を避けるべきであることを表す

## アノテーション（属性）の種類
<foo>@</foo>IBOutlet 
Interface Builderでユーザーインターフェース要素とコードを接続するために使用されます。通常、IBOutletはビューコントローラーのプロパティに付けられます。

<foo>@</foo>IBAction
Interface Builderでアクションを接続するために使用されます。ボタンなどのユーザーインターフェース要素がタップされたときに呼び出されるメソッドに付けられます。

## 参考サイト
https://jp-seemore.com/app/15184/

https://youtu.be/03qEuwGod8E?si=gR58BMHoe-7gg-28
Vite環境でJest使おうとするとSyntaxError: Cannot use 'import.meta' outside a moduleが出る

# はじめに
Vite環境でJestを使う際に色々エラー出たので解決策を書いておきます。

# 問題１
npm run testした際に以下のエラーが出る。
```
SyntaxError: Cannot use 'import.meta' outside a module
```
# 解決策
ネットで色々調べたところ、import.metaはviteによって提供される機能なため、デフォルトではjestやnode.jsでは認識されないみたいです。なのでviteでimport.metaではなくprocess.envを使えるようにしてあげる必要があります。今回はsupabaseから環境変数を利用しているため以下のように修正します。

```diff_javascript
/*---vite.config.js---*/
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
+ import env from "vite-plugin-env-compatible";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react(),
+    env({ prefix: "VITE",  mountedPath: "process.env" }) 
  ],
})
```
```diff_javascript
/*---supabase.js---*/
import { createClient } from '@supabase/supabase-js';

- const SUPABASE_URL = import.meta.env.VITE_SUPABASE_URL;
+ const SUPABASE_URL = process.env.VITE_SUPABASE_URL;

- const SUPABASE_ANON_KEY = import.meta.env.VITE_SUPABASE_ANON_KEY;
+ const SUPABASE_ANON_KEY = process.env.VITE_SUPABASE_ANON_KEY;

export const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
```
# 問題２
これで解決したと思ったら今度は以下のエラーが出る。
```
Configuration error:
    
Could not locate module ./App.css mapped as:
identity-obj-proxy.
    
Please check your configuration for these entries:
{
  "moduleNameMapper": {
    "/\.(css|less)$/": "identity-obj-proxy"
  },
  "resolver": undefined
}
```
# 解決策
gptさんに尋ねたところ、identity-obj-proxyがCSSファイルをモックするための設定が必要だが現在の設定でそれが見つかっていないとしてエラーが出ているとのことでした。
```js
/*---jest.config.mjs---*/
export default {
  testEnvironment: "jsdom",
  // CSSファイルをモックするための設定をここでできている
  moduleNameMapper: {
    "\\.(css|less)$": "identity-obj-proxy"
  },
  setupFilesAfterEnv: ["./jest.setup.js"]
};
```
コードは問題なさそうです。シンプルにdentity-obj-proxyパッケージがインストールされてなかったのが原因でした。これをインストールしたら無事テストが通りました。
```
$npm install --save-dev identity-obj-proxy
```
jestの設定周りは意外と大変ですね。
# おわりに
vite環境でjest使う際は多くの方がこのエラーに遭遇するのではないでしょうか？少しでも参考になりましたら幸いです。

# 参考
vite jest envと調べると色々出てきます。

https://scrapbox.io/diskszk/Vite%E3%81%A7%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E3%83%86%E3%82%B9%E3%83%88

# JISOUのメンバー募集中
プログラミングコーチングJISOUではメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？

気になる方はぜひHPからライン登録お願いします:point_down:

https://projisou.jp
「自分らしいキャリアを築くために：価値観と夢の見つけ方」

![title](https://raw.githubusercontent.com/legitwhiz/legitwhiz.github.io/master/technology_memo/images/1000007638.jpg)

#  「自分らしいキャリアを築くために：価値観と夢の見つけ方」

## こんな状況に陥ってないですか？

スキルアップやキャリアアップを目指して頑張ろうと思っても、いざ動き出そうとすると「どんな点に気をつければいいんだろう？」「何から始めればいいかな？」と、いきなり壁にぶつかることはありませんか？それは「目的」も「主体性」もないからではないでしょうか？

## どうしたら自分らしくいられるか

会社の上司に言われたからとか、周りに触発されたからではなく、自分が「何をしたいか」、「どうなりたいか」を考えてみてください。それは自分の「将来」や「夢」なのだから、自分で考え行動に移すべきです。

その前に、自分が「生きていく上で重視すること」や「これだけは絶対に譲れないこと」を考えてみてください。それは自分の「価値観」や「生き方」、そして「生きる目的」なのではないでしょうか？

## 夢の見つけ方

自分の心の中にある様々な「思い」を文字にして、自らの意思をしっかり確認してください。なぜなら、それによって目指す方向が大きく異なってくるからです。

「将来は起業して会社の社長になりたい」という人と、「技術者として社会に貢献したい」という人では、そもそも「すべきこと」が全く違いますよね？

ですから、最初にすべきことは「価値観」や「生き方」を確認することであり、「将来」や「夢」を明確にすることです。

「木」に例えるなら、土壌は「価値観」や「生き方」であり、「将来」や「夢」は幹であり、葉や枝は「技術」です。土壌や幹がしっかりしていないと葉は育ちませんよね！

自分の価値観やビジョンに基づいて、自分らしく「やりたいことをやる」。やりたいことなので楽しく続けられますし、「好きこそものの上手なれ」ということわざもありますから。

壁にぶち当たったら、自分に「本当はどうなりたい？」、「本当は何がしたい？」と問いかけてみてください。

周りの言動に振り回される「軸なし」ではなく、「軸あり」ならやりたいことが次々と出てくると思いませんか？

## 間違った努力をすると

失敗する例を挙げると、優秀な管理職になりたいと思う人が、人との付き合い方や具体的な問題・課題の達成方法など、技術的な勉強ばかりしていることがあります。

いくら小手先のスキルを磨いても、その裏に真摯さや誠実さがなければ、一時的にはうまくいったとしても、継続的に成功し続けることはできません。
AWSアカウント間でS3バケットへのアクセス権限のみを共有する方法

Amazon S3（Simple Storage Service）は、データの保存と管理のためのスケーラブルなオブジェクトストレージサービスです。異なるAWSアカウント間でS3バケットを共有する方法を紹介します。


### バケットポリシー編集

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowListAndGet",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::{ACCOUNT_ID}:user/{USER_NAME}"
            },
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": "arn:aws:s3:::{YOUR_BUCKET_NAME}"
        },
        {
            "Sid": "AllowGetObject",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::{ACCOUNT_ID}:user/{USER_NAME}"
            },
            "Action": [
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::{YOUR_BUCKET_NAME}/*"
        }
    ]
}
```

このポリシーは、アカウント`{ACCOUNT_ID}`に対して特定のS3バケットのオブジェクトをリストし、取得する権限を付与します。`{YOUR_BUCKET_NAME}`を実際のバケット名に、`{ACCOUNT_ID}`をAWSアカウントIDに置き換えてください。


### アクセス確認

1. バケットの内容をリスト：

```sh
aws s3 ls s3://{YOUR_BUCKET_NAME} --profile {ACCOUNT_ID}-profile
```

2. オブジェクトを取得：

```
aws s3 cp s3://{YOUR_BUCKET_NAME}/your-object-key ./{local-directory} --profile {ACCOUNT_ID}-profile

```

AWSアカウント間でS3バケットを共有する際、LISTとGETの権限を適切に設定することで、安全かつ効率的にデータを共有することができます。
【備忘録】初めてのiOSアプリ開発 第7回 プロトコル

## プロトコルとは
・あるデータ型オブジェクトが何かを実行するときのルール
プロトコルでは定義のみを行い、メソッドやプロパティ、イニシャライザなど実装は記述しない。
・実装はプロトコルを「採用した」クラスの中で記述する。
・複数継承させることができる。
・プロトコルがプロトコル自体を継承できる。


### 型のインターフェースを定義するもの
・インターフェースを定義し、抽象化する。
・複数の型で共通の機能を実装することができる。
・クラス、構造体、列挙型などで使われる。
 
プロトコルのインターフェースを満たす型は、「プロトコルに準拠している」と言われる。
プロトコルを使うことを「採用する」「適合する」という。

## 参考サイト
https://www.sejuku.net/blog/35550

https://youtu.be/nBsB-jzpJhU?si=bepWzclpu8xg8Xrt

https://dotinstall.com/lessons/basic_swift_v2/39126

https://memoriainc.com/2024/01/30/%E3%80%90ios%E3%80%91swift%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%97%E3%83%AD%E3%83%88%E3%82%B3%E3%83%ABprotocol%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E6%B7%B1%E3%81%8F%E7%90%86%E8%A7%A3%E3%81%99/
お前らがlogrotate書いてる時に俺はnewsyslogを書いてる

FreeBSD最高機能であるZFSやjails, セキュリティ機能だけがピックアップされがちですが
こういった日常的に使える地味な機能も良いゾってハナシ

機能としてはlogrotateと大差ないけど、直感性が違う

では、一般的な例として
Nginxのaccess|error.logを24時間ごとにローテーションして7世代で圧縮保存後、シグナル送ってログファイルを再オープンするって設定をする。

という設定を行うとすると

logrotate
```sh
/var/log/http-*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 0640 root wheel
    sharedscripts
    postrotate
        [ -s /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
    endscript
}
```
これだけで完結せず、cronで間隔を設定する必要がある...
もぅﾏﾁﾞ無理

newsyslog
```sh
/var/log/http-*.log  root:wheel  640  7 *  $D00  ZB  /var/run/nginx.pid 10
```

これよ...
間隔の設定ここでしたいんよ...
システムデーモンとして設定されてるのでcron不要なんよ...

Macでも/etc/newsyslog.d以下に設定書けるから明日から使っていこうな！
yukicoder No.32 貯金箱の憂鬱　解説

[問題文](https://yukicoder.me/problems/no/32)
# 解説
まずは、使う小銭・札を見てみよう。
・$1000mod100=0$
・$100mod25=0$
・$25mod1=0$
つまり、この問題は**貪欲法が使える**。
できるだけ小銭の数を小さくするため、下から両替をできるだけする。
最終的に札は数えないことに注意。
# 解答例
```C++
#include <bits/stdc++.h>
using namespace std;

int main(){
  int l,m,n;cin>>l>>m>>n;
  m+=n/25;
  n%=25;
  l+=m/4;
  m%=4;
  l%=10;
  cout<<n+m+l<<endl;
}
```
How to get started with TestRail

API Testing について。

Playwright [^3] で API Testing を組み立てており、 TestRail [^1] と連携させる。

Playwright は複数の Report 機能 [^4] があり、それを TestRail に表示させることができる。

最近は E2E の実践のために、本を読みながら Playwright で遊んでいる。

AWS CDK との格闘の合間の休憩として 🍵

https://gihyo.jp/book/2024/978-4-297-14220-9

本の購入は `BENTO` にお世話になっている。thank you kubell

https://prtimes.jp/main/html/rd/p/000000247.000013602.html

## 前提

- テスト管理ツールとして TestRail を利用している。
- VS Code の Dev Containers を利用している。
- 開発言語は TypeScript である。

## Installation

- TestRail の CLI は Python が必要。
- TypeScript に Python を追加しているため、 Python を仮想化する。
- `Python 3.11.2`
- `TestRail CLI v1.9.5`

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install trcli
```

- Playwright のテスト結果出力時の `name` を設定する。

```bash: .env
PLAYWRIGHT_JUNIT_SUITE_NAME="Automated API Tests Run"
```

- Playwright でのテストはこちら。

https://zenn.dev/dannya/articles/826056c6dc72c6

- TestRail の Parameters を定義する。Command Line の Option として渡すこともできる。

```yml: config.yml
host: https://fakename.testrail.io/
project: My TestRail Project
project_id: 1
username: myuser@name.com
password: StrongP@ssword
file: ./test-results/junit-report.xml   # 相対パス
title: Playwright Automated Test Run
```

## Here we go!!

```bash
trcli -y -c ./config.yml parse_junit
```

```bash: Logs
(.venv) root ➜ /workspaces/hogehoge/web-api-tests (BPD-493) $ trcli -y -c ./config.yml parse_junit
TestRail CLI v1.9.5
Copyright 2024 Gurock Software GmbH - www.gurock.com
Parser Results Execution Parameters
> Report file: ./test-results/junit-report.xml
> Config file: ./config.yml
> TestRail instance: https://mycompany.tmxtestrail.com/ (user: daisuke.yamamoto@example.com)
> Project: My Poroject
> Run title: Playwright Automated Test Run
> Update run: No
> Add to milestone: No
> Auto-create entities: True
Parsing JUnit report.
Processing JUnit suite - Automated API Tests Run
Processed 1 test cases in section customer-companies.spec.ts.
Checking project. Done.
Creating test run. Test run: https://mycompany.tmxtestrail.com/index.php?/runs/view/5
Adding results: 1/1, Done.
No attachments found to upload.
Submitted 1 test results in 2.9 secs.
(.venv) root ➜ /workspaces/hogehoge/web-api-tests (BPD-493)
```

![cafe](/images/0571b69a780dd4-a.jpg)

## Conclusion

「みんなが心地良いペースで働いてはいけない」

https://note.com/y_matsumoto_0907/n/n128620546564?sub_rt=share_b

10年以上 JTC にいた身からすると、「速さ」に違和感を感じることもあった。

ベンチャーに身を置くようになり、成功かどうか分からないものを確かめる「速さ」が重要だと思うようになった。

なぜなら、どれだけ綺麗に作ったものでも価値が無ければただの自己満足に過ぎないと思うからだ。

そして、「速さ」の中でも一定の品質のものを作るのが Professional だと思う。

コミュニケーションのコストを抑えて速く作るなら、極論一人で作った方が速い。

一方で、作ったものに価値があるとわかった時に、それを成長させるならチームが必要だと思う。

100 個の挑戦を「時計を支配」しながら進めることができる manager を集めることができれば、そのうち 1 つは成功を掴めるかもしれない。

そんな環境に身を置いているという自覚を先週の出張で感じ取ることができた。

[^1]: https://www.testrail.com/

[^2]: https://zenn.dev/dannya/articles/826056c6dc72c6

[^3]: https://playwright.dev/

[^4]: https://playwright.dev/docs/test-reporters#junit-reporter
Stripe APIで tax_rates リスト確認する

# Stripeの tax_rates ってどこで確認できるの？
- Stripeの tax_rates は "txr_123khdsbvsbfvjsvsvnsfvs456" のような形式を指します
- この値はどこからどのように取得したいかわからないという人向けです

# Stripe API で取得できます

curlコマンドを使用して税率を取得します。

```shell:shell
curl https://api.stripe.com/v1/tax_rates \
-u sk_test_*****: 
```
- テスト環境用のAPIキーを用意します。通常、sk_test_で始まるキーを使用します。
- curlコマンドを使用して税率を取得:


```diff_shell:shell
curl https://api.stripe.com/v1/tax_rates \
- -u sk_test_*****: sk_test_1255217ijvsjfkvfskgvjfjvfvlsfhvjslsl
+ -u sk_test_*****:

```
コロンの後は何も入力しなくていいです。

# 取得結果は Json で返ってきます
```json:tax_lists.rb
{
  "object": "list",
  "data": [
    {
      "id": "txr_123khdsbvsbfvjsvsvnsfvs456",
      "object": "tax_rate",
      "active": true,
      "country": "JP",
      "created": 0000000000,
      "description": null,
      "display_name": "消費税",
      "effective_percentage": 10.0,
      "inclusive": true,
      "jurisdiction": null,
      "jurisdiction_level": null,
      "livemode": false,
      "metadata": {},
      "percentage": 10.0,
      "state": null,
      "tax_type": null
    },
    {
      "id": "txr_123khdsbvsbfvjsvsvnsfvs456",
      "object": "tax_rate",
      "active": true,
      "country": "JP",
      "created": 0000000000,
      "description": null,
      "display_name": "消費税",
      "effective_percentage": 10.0,
      "inclusive": true,
      "jurisdiction": null,
      "jurisdiction_level": null,
      "livemode": false,
      "metadata": {},
      "percentage": 10.0,
      "state": null,
      "tax_type": null
    }
  ],
  "has_more": false,
  "url": "/v1/tax_rates"
}
```

# 一言
- わぁ、便利〜。
Django カスタムメソッドでシリアライズして返す方法 そしてmany=Trueとは

# TL;DR
* **many=True**が指定されると、Serializerクラスの__new__メソッドでそれが確認され、ListSerializerのインスタンスが生成されます。
* ListSerializerはリスト内の各オブジェクトをシリアライズするために使用されます。
* ListSerializerは**BaseSerializer**およびSerializerクラスから**自動的**に呼び出されます。

```rest_framework/serializers.py
class BaseSerializer(Field):
    # ~~ 省略 ~~
    def __new__(cls, *args, **kwargs):
        # We override this method in order to automatically create
        # `ListSerializer` classes instead when `many=True` is set.
        if kwargs.pop('many', False):#こいつだ！！！
            return cls.many_init(*args, **kwargs)
        return super().__new__(cls, *args, **kwargs)
```


## カスタムメソッド

```models.py
from django.db import models
class Books(models.Model):
    hcode = models.CharField(primary_key=True, max_length=13)
    hname = models.CharField(max_length=30, blank=True, null=True)
```

```views.py
from django.shortcuts import render
from rest_framework.decorators import action
from rest_framework import viewsets,response
from .models import Books
from .serializers import BookSerializer

class BooksAPIView(viewsets.ModelViewSet):
    queryset = Books.objects.db_manager("sqlserver").all()
    serializer_class = BookSerializer

    # カスタムアクション
    @action(detail=False, methods=['get'])
    def custom_action(self, request):
        hcode :str = request.GET.get('hcode', None)
        fmthcode :str = ('5'+(('000000000000'+hcode)[-12:]))
        d = Books.objects.db_manager("sqlserver").filter(hcode=fmthcode)
        s = BookSerializer(d,many=True) # filterやallにより戻り値がListの場合はmany=Trueを指定する
        return response.Response({"data": s.data})
```
```urls.py
from django.urls import path,include
from rest_framework import routers
from .views import BooksAPIView

router = routers.DefaultRouter()
router.register('books', BooksAPIView)

urlpatterns = [
    path('', include(router.urls)),
    # 他のルートもここに追加する場合があります
]
```

* ```http://127.0.0.1:8000/api/books/```:通常このアドレスにアクセスすると一覧が取得される（Listが帰ってくる）
* ```http://127.0.0.1:8000/api/books/custom_action?hcode=30000```：このアドレスにアクセスするとCRUD以外の```views.py```で定義したアクションを呼び出す事ができる


## シリアライズしてレスポンスを返す方法

### querysetの結果が一つの場合
```views.py
queryset = Books.objects.db_manager("sqlserver").get(pk=1)
result = BookSerializer(queryset)
return response.Response({"data": result})
```

### 複数の場合
* よくわからない引数をシリアライザに渡している...
```views.py
queryset = Books.objects.db_manager("sqlserver").all()
result = BookSerializer(queryset,many=True)# many = Trueとはなんだ？
return response.Response({"data": result.data}) # .dataが必要だよ
```
* そこで調べてみると・・・```rest_framework/serializers.py```の中にいました。

```rest_framework/serializers.py
class BaseSerializer(Field):
    # ~~ 省略 ~~
    def __new__(cls, *args, **kwargs):
        # We override this method in order to automatically create
        # `ListSerializer` classes instead when `many=True` is set.
        if kwargs.pop('many', False):#こいつだ！！！
            return cls.many_init(*args, **kwargs)
        return super().__new__(cls, *args, **kwargs)
```
yukicoder No.29 パワーアップ　解説

[問題文](https://yukicoder.me/problems/no/29)
# 解説
まずこの問題で気づくべきことは
**4個パワーアップに同じものを4個使うよりも、2個パワーアップに同じものを二つ使った方がいい**
ということである。
まず、以下の配列を用いる。
$item_i$=$i$個目のアイテムが何個あるか
毎回ループを回すごとに$item_{A_i}$,$item_{B_i}$,$item_{C_i}$を一増やす。
あとは、2個パワーアップの回数を数え、それに4個パワーアップができる回数を足す。
# 解答例
```C++
#include <bits/stdc++.h>
using namespace std;

int main(){
  int n,ans=0;cin>>n;
  vector<int> item(11,0);
  for(int i=0;i<n;i++){
    int a_i,b_i,c_i;cin>>a_i>>b_i>>c_i;
    item[a_i]++;
    item[b_i]++;
    item[c_i]++;
  }
  for(int i=1;i<=10;i++){
    ans+=item[i]/2;
    item[i]%=2;
  }
  int sum=0;
  for(int i=1;i<=10;i++)sum+=item[i];
  cout<<ans+sum/4<<endl;
}
```
OpsRamp - webhookでアラートを取り込む方法

本記事では、webhookを使用してOpsRampにアラートとして取り込む方法について説明します。

# 概要
OpsRampでは、サードパーティーシステムからwebhookを送信し、アラートとして取り込むことができます。NewrelicやAppDynamicsなどOpsRamp社が提供しているインテグレーションに加え、独自のカスタムインテグレーションとして設定することも可能です。

# 設定方法
カスタムインテグレーションにおけるwebhook設定について説明します。NewrelicやAppDynamicsなどのOpsRamp社が提供しているインテグレーションでも基本的には設定は同じにあります。
カスタムインテグレーションは、Setup > Account > IntegrationsからCustomを選択することで追加できます。
Install時の項目では、CategoryにMonitoring、Alert SourceにCustomを選択します。
![custom-integration-webhook1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/97c57db8-899a-e5e0-3cd2-dba67aba92a9.png)
Authetication TypeにWEBHOOK、Roleに任意のロールを選択します。(ロールは、アラート管理権限が必要です。) 
![custom-integration-webhook2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/834866c8-648f-c862-0951-75e9fe806486.png)
Autheticationの設定を行うと認証トークンが発行されますので、保存ください。(この画面を離れると参照できなくなり、再生成が必要になります。)
Map Attributesでは、webhookで送信されたJSONデータとOpsRampで扱えるアラートデータ(アラートの件名、説明、リソース名など)のマッピングを設定します。
![custom-integration-webhook2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/dcd5e464-825e-a077-6e02-4257234a8c19.png)
マッピングするアラートデータを選択し、それに対応するJSONデータを選択します。
![custom-integration-webhook3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/864a873f-43e5-d26b-95c9-d09652b825d5.png)

設定完了後、1. Autheticationで取得した認証トークン付きURLにJSONデータを送信することでOpsRamp上にアラートを生成できます。

---------------------------------------
[<img width = 250 height = 200 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/111de30a-4d33-aa33-5c7d-83d9015093e6.png">](https://www.vistanet.jp/knowledge-base/)
情報の外在性。小さいコンピュータシミュレーションモデル

情報の外在性。
人間は生まれたとき、何にも知らない状態で生まれてきて、成長をするごとに情報を得たり失ったりします。
このプログラムは誕生したばかりの人間が初めての情報を得る瞬間をシミュレーションしています。
これは、実存主義の情報版です。
なーんて、偉そうに書いてますが、やってることは、乱数で2つの内から一方を選んでselfという変数に代入しているだけです。

pythonで書かれています。`./io.py`で実行して下さい。
拙作のtruerandモジュールを使います。

https://qiita.com/fygar256/items/657719d5670f4534401f

```io.py
#!/usr/bin/python3
import truerand
def main():
    self=None
    print(f"information source is /dev/random")
    print("self will get information")
    print(f"state of no information self={self}")
    print("self don't know anything.")
    i=truerand.rand(1)%2
    print(f"information source is {i}")
    self=i
    print(f"self has been given information")
    print(f"now, self got informatiom self={self}")

if __name__=="__main__":
    main()
    exit(0)
```

実行結果
```
$ io.py
information source is /dev/random
self will get information
state of no information self=None
self don't know anything.
information source is 1
self has been given information
now, self got informatiom self=1
$
```

このことから、情報が全く無い時に、向こうから来る人がプログラマである確率が50％50％であるという仮定は誤っていると言えます。このプログラムでは、iの決定の確率がselfより外在しているからです。
これは、客観的客観です。情報の客観性です。

真性乱数と完全乱数は、同じものとして扱って構いませんが、真性乱数は完全乱数ではないので、iの決定の確率は、正確に1/2,1/2ではないでしょう。真性乱数は/dev/random/がプールする、環境ノイズからの乱数ですので、その値は、正確に言うとハードが置かれている環境の影響を受けます。良質な乱数ですので、完全乱数として扱えます。

情報哲学でこんな理論はあったらしい。
実存主義を簡単に言ったら、「別」。

実存主義はあんまり良くないと思いますが、これも事実なのかなと思い、載せてみました。
実存主義と実存思想とは違います。僕は本質主義で、何事も本質が大事だと思います。サルトルは間違ってる。
誕生の逆の死は、selfにNoneを代入したらいいです。復活は、selfにまた情報を代入したらいいです。
死と復活をテーマに作ってみました。

```dr.py
#!/usr/bin/python3
import time
def main():
    self=1
    print("self is living but about to die.\n")
    print(f"state of information self={self}")
    print("for a while self living.")
    time.sleep(3)
    print("")
    self=None
    print(f"self has died. state of information self={self}")
    print("for a while self is dead.")
    print("self will revive.\n")
    time.sleep(3)
    self=1
    print(f"self revived. state of information self={self}")
    print("end")

if __name__=="__main__":
    main()
    exit(0)
```

実行結果
```
$ dr.py
self is living but about to die.

state of information self=1
for a while self living.

self has died. state of information self=None
for a while self is dead.
self will revive.

self revived. state of information self=1
end

```
なあんちゃって。

インターネットにも情報の外在性があって、インターネット全体を見てみても、情報は、それ以外にも存在し、インターネットが全てではないことが分かります。インターネット全体は、一応開放系ですが、サイト1つを取ってみると閉鎖系と言ってもいいような息苦しいところもあります。
一般に、情報の外在性は存在し、開放系の情報の総量は無限大です。

雪猫や私何にも知りません　公太郎

古典的確率論では一回のコイントスで、表が出る確率と裏が出る確率は等しく1/2だとする仮定が正しいです。

マルチプルチョイス：

情報のないところで、範囲を限られてたら、当たりが１個あって、大爆死が1個あって、選択肢がｎ個あったら、トライしないほうがマシ。当たりの確率は1/n、大爆死の確率は1/n。大爆死したら取り返しがつかないので。
大爆死の可能性があったらゲームに参加しないほうがマシ。故にギャンブラーは愚かである。

以上、簡単なことを難しく書いただけ。
Windows11 RTX4070Ti SUPER に tensorflow2.10 cuda cudnn の環境構築をcondaで。

## はじめに
自作PCにWindows11を入れたところまではよかったのだけど、GPUでtensorflowを動かすのに5時間くらい時間を溶かしてしまった。いろいろ試して最終的にうまくいった方法を備忘のために記録しておく。（2024/7/24）

## 前提の環境
- Windows11 professional
- GPU : RTX4070ti SUPER
- Nvidia Driver Version: 560.70
- conda --version : 24.5.0

## うまくいった方法
### condaの環境作成・諸々インストール
1. conda create -n py310 python=3.10
2. conda activate py310
3. conda install -c conda-forge cudatoolkit=11.2 cudnn=8.1.0
4. python -m pip install "tensorflow==2.10"

### その後、システム環境変数のPathに以下を追加。
C:¥Users¥{username}¥.conda¥envs¥py310¥Library¥bin


### Pathに追加したら再起動し、以下でGPUを認識できるか確認。

import tensorflow as tf
tf.config.list_physical_devices('GPU')

### Numpy関連のエラーが出るのでNumpyバージョンをダウングレード
tensorflowのimportにおいて、Numpyのバージョンが新すぎるということでエラーが出たので、下で古いNumpyを入れ直したところちゃんと動いた。
pip install numpy==1.26.4

### うまくいくと下の表な表示が出る。
tf.config.list_physical_devices('GPU')
→[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]


## その他
cuda11系をGUI付きのインストーラでインストールしようとしたら、システムとの互換性がないというエラーになりインストールできず諦めかけたが、上記の方法でconda installでcudatoolkitを入れて、Pathを設定したら動いた。

他に以下の2つのやり方も試したが、なぜかconda環境のcreateでエラーが出てしまった。
https://qiita.com/ktokey/items/7ee9c112198a6b0b5709
https://qiita.com/yusuke_s_yusuke/items/dbe530ff7687603a81f6

## 参考資料
https://youtu.be/QUjtDIalh0k?si=5EE_-ImpG8LxetWv
【Unity】Cinemachineカメラ制御とある不具合についての記録

実装したい内容：
三人称カメラ（CinemachineVirtualCamera）から一人称カメラ（CinemachineFreeLook）のカメラワークを発生させて、スクリプトでCinemachineFreeLookのAim属性を「Do nothing」で設定すること。
＊一人称カメラを別途で制御したいため、一旦Cinemachine制御から外すことは目的です。

例：
三人称カメラ（CinemachineVirtualCamera）からとあるキューブを注目している一人称カメラ（CinemachineFreeLook）の遷移ワーク。

すると、望まない動作が発生しました。
画面はこうなりました：
![スクリーンショット 2024-07-24 17.56.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757569/4b8e2b65-6951-918a-ceb2-3b6bd59313b3.png)
↑カメラの動きが何故か完成していない、「Look At」に設定されたキューブは画面の中心になっていません。

解決策：
一旦カメラワークを待つ、動きが終わったら、「Aim」を設定します。

![スクリーンショット 2024-07-24 18.03.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757569/f822951d-6bf6-4d99-15d7-46cbbc8fe608.png)
↑カメラの動きは期待通りになりました。

関連ソースコードは以下になります。
*ここは便宜のため、UniTaskを使わせていただきます。m（_　_）m

```c＃:CameraTest.cs
using Cinemachine;
using UnityEngine;
using Cysharp.Threading.Tasks;
using System;

public class CameraTest : MonoBehaviour
{
    //カメラワークの時間を取得のためだけ
    public CinemachineBrain cinemachineBrain;
    //三人称カメラ
    public CinemachineVirtualCameraBase mainCamera;
    //キューブ注目カメラ
    public CinemachineFreeLook freelookCamera;
    //LookAtのキューブ
    public Transform testLookAt;
    
    public void ChangeCam()
    {
        changeCamAsync().Forget();
    }

    public async UniTask changeCamAsync()
    {
        bool isChangeToFree = mainCamera.gameObject.activeSelf;
        mainCamera.gameObject.SetActive(!isChangeToFree);
        freelookCamera.gameObject.SetActive(isChangeToFree);
        
        if (isChangeToFree)
        {
            //一人称カメラのパラメータ設置
            freelookCamera.m_BindingMode = CinemachineTransposer.BindingMode.LockToTargetWithWorldUp;
            freelookCamera.Follow = testLookAt;
            freelookCamera.LookAt = testLookAt;
            //肝心なカメラワーク待つロジック
            await UniTask.Delay(TimeSpan.FromSeconds(cinemachineBrain.m_DefaultBlend.m_Time));
            //下記の三行コードの挙動とは、属性「Aim」を「Do nothing」で設定するとは同じです。
            //「Do nothing」設置開始
            var nowRig = freelookCamera.GetRig(1);
            var cinemachineComponent = nowRig.AddCinemachineComponent<CinemachineComposer>();
            cinemachineComponent.enabled = false;
            //「Do nothing」設置完了
        }
        else
        {
            //属性「Aim」を「Do nothing」から「Composer」戻ります
            var nowRig = freelookCamera.GetRig(1);
            var cinemachineComponent = nowRig.AddCinemachineComponent<CinemachineComposer>();
            cinemachineComponent.enabled = true;
        }
    }
}

```
Node.jsについて

自分の得た情報を整理した記事です。
間違った情報を載せていたらご指摘お願いします。

# Node.jsとは
### JavaScriptをサーバ側で動作させる開発環境のこと（実体はない。概念）



## package.json
### パッケージを管理するために使われるファイル
“scripts”にはシェルスクリプト（コマンド）のエイリアスを記述できる。
npm initでそのディレクトリ内にpackage.jsonを配置（初期化）できる。

## npm
### Node.jsで外部パッケージをローカルにインストールして実行するためのマネージャー

#### インストールコマンド→npm i (-g) （任意のパッケージ名）
#### 実行コマンド→npm run （package.jsonの"scripts"内に記述したシェルスクリプトのエイリアス）
（このコマンドで何かを実行するにはpackage.jsonの"scripts"内にシェルスクリプトのエイリアスとその定義を記述しなければならない）

## npx
### インストールされていないパッケージを実行（インストール→実行→削除）することができるマネージャー
GitHubから直接コードを実行することもできる


#### cowsayという牛のアスキーアートを標準出力してくれるコマンドを利用した場合
cowsayがインストールされていない状態でのスタート
例：

1  npm cowsay wow →失敗

2 npx cowsay wow →成功

3 npm i cowsay →（cowsayのインストール）

4 npm cowsay wow →失敗

（package.jsonの”script”に"test": "cowsay wow”を入力)

5 npm test →成功

6 npx test →失敗

7 npx cowsay wow →成功
【Tips】Railsのバージョンアップ時にload_defaultsを更新し忘れる問題に気付きやすくする

## 解決したい問題
既存のRailsアプリケーションをバージョンアップする場合、`config/application.rb`で`config.load_defaults`も（どこかのタイミングで）更新する必要があります。

```diff_ruby:config/application.rb
   class Application < Rails::Application
     # Rails 7.0から7.1にバージョンアップする
-    config.load_defaults 7.0
+    config.load_defaults 7.1
```

しかし、この設定をうっかり更新し忘れて「よし、Rails 7.1にアップデートできたぞ！🙌」と喜んでいたら、実は`load_defaults`が7.0のままだった😱という問題が起こる可能性があります。

というか、僕は先日やらかしました、はい😂 （再度Rails 7.1向けのプログラム修正と動作確認を余儀なくされました……）

## 改善策
この問題に気付きやすくするように、`config/application.rb`に以下のコードを追加しました。

```diff_ruby:config/application.rb
 config.load_defaults 7.1
+unless config.loaded_config_version.to_f == Rails::VERSION::STRING.to_f
+  warn "Current Rails version is #{Rails::VERSION::STRING}, but loaded config version is #{config.loaded_config_version}"
+end
```

こうするとアプリケーションの起動時やテストの実行時に以下のような警告が出力されて更新し忘れに気付きやすくなります。

例： Rails 7.1にアップデートしたのに`config.load_defaults`が7.0のままだった場合

```
Current Rails version is 7.1.3.4, but loaded config version is 7.0
```

## この対応の考慮点
`config.load_defaults`はRailsのバージョンを上げたら必ず同時に上げないといけないものではありません。
状況によってはRails 7.1でもあえて`config.load_defaults`は7.0のまま本番リリースし、しばらく運用してから7.1に変更する、というケースもありえます。

https://railsguides.jp/upgrading_ruby_on_rails.html#%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF%E3%81%AE%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B

その場合は「あえて古いバージョンにしているのに毎回警告が出てうっとうしい」というデメリットが発生します。

とはいえ、そのうっとうしさよりも、うっかり更新し忘れる問題の方が怖いので僕はこの設定を入れるようにしました。

## まとめ

というわけでこの記事ではRailsのバージョンアップ時にload_defaultsを更新し忘れる問題に気付きやすくするTipsを紹介しました。

僕みたいにうっかり更新し忘れるのはイヤだ！という人は参考にしてみてください。

### おまけ
最初は「この警告をRails自身が出してくれたら嬉しいのに」と思いpull requestを送ってみましたが、考慮点に書いたように「あえて古いバージョンを指定するケースもある（というか、その手順が推奨）なのでNG」となりました。残念😭

https://github.com/rails/rails/pull/52399
ディフィー・ヘルマン鍵共有（Diffie-Hellman key exchange、DH）

ディフィー・ヘルマン鍵共有（Diffie–Hellman key exchange、DH）とは、二者間で安全に共通の秘密鍵を生成するための暗号プロトコルです。これにより、公開されたパラメータを使用して秘密鍵を共有し、暗号化通信を行うことができます。

# 1. 全体概要

AさんとBさんで共通鍵を共有したい場合、ディフィー・ヘルマン鍵共有は上記図の流れとなります。

全体図
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292434/e64436c7-a14e-6cdf-f554-30d7a7b36146.png)

(1-1) Aさんは自分だけしか知らないDH秘密鍵「`a`」を用意する
(1-2) Bさんも自分だけしか知らないDH秘密鍵「`b`」を用意する

(2-1) Aさんが公開パラメータの「`p`（大きな素数）」と「`g`（基数：`p`より小さい自然数）」を用意する
(2-2) Aさんが、AさんのDH公開鍵「`A`」を計算する
計算式：`A = g^a mod p`

(3-1) AさんがBさんへ 「`p`（大きな素数）」、「`g`（基数：`p`より小さい自然数）」、AさんのDH公開鍵「`A`」を渡す

(4-1) Bさんが、BさんのDH公開鍵「`B`」を計算する
計算式：`B = g^b mod p`

(5-1) BさんがAさんへBさんのDH公開鍵「`B`」を渡す

(6-1) Aさんが共通鍵を算出する
計算式：`K = B^a mod p`
(6-2) Bさんが共通鍵を算出する
計算式：`K = A^b mod p`

# 2. 実際に簡単な数値で計算

実際に簡単な数値で計算してみると以下のようになります。

全体図
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292434/d440893d-c692-e188-018e-fec056afd79f.png)


(1-1) Aさんは自分だけしか知らないDH秘密鍵「`a = 4`」を用意する
(1-2) Bさんも自分だけしか知らないDH秘密鍵「`b = 5`」を用意する

(2-1) Aさんが公開パラメータの「`p = 7`（大きな素数）」と「`g = 5`（基数：`p`より小さい自然数）」を用意する
(2-2) Aさんが、AさんのDH公開鍵「`A`」を計算する
計算式：`A = g^a mod p`
　　　　　` = 5^4 mod 7`
　　　　　` = 625 mod 7`
　　　　　` = 2`

(3-1) AさんがBさんへ 「`p = 7`（大きな素数）」、「`g = 5`（基数：`p`より小さい自然数）」、AさんのDH公開鍵「`A = 2`」を渡す

(4-1) Bさんが、BさんのDH公開鍵「`B`」を計算する
計算式：`B = g^b mod p`
　　　　　` = 5^5 mod 7`
　　　　　` = 3125 mod 7`
　　　　　` = 3`

(5-1) BさんがAさんへBさんのDH公開鍵「`B = 3`」を渡す

(6-1) Aさんが共通鍵を算出する
計算式：`K = B^a mod p`
　　　　　` = 3^4 mod 7`
　　　　　` = 81 mod 7`
　　　　　` = 4`

(6-2) Bさんが共通鍵を算出する
計算式：`K = A^b mod p`
　　　　　` = 2^5 mod 7`
　　　　　` = 32 mod 7`
　　　　　` = 4`

# 3. 後書き

以前はRSA等の公開鍵暗号方式で、共通鍵を暗号化して渡すこともあったのですが、暗号化されているとはいえ共通鍵が第三者に見られることは避けたい、といった背景があります。
ディフィー・ヘルマン鍵共有だと、通信で流すのは公開パラメータとDH公開鍵と第三者に見られても問題がない値のみなので、鍵交換プロトコルとして使用されています。
最近では「楕円曲線ディフィー・ヘルマン鍵共有（Elliptic curve Diffie–Hellman key exchange, ECDH）」も使用されているようです。

---

以上