OmniAICreator/Qiita-1.07M huggingface dataset:
faissで総当たりコサイン類似度検索実装

ANN(Approximate Nearest Neighbor)のPythonパッケージである [**faiss**](https://github.com/facebookresearch/faiss)でコサイン類似度での検索をインデックス`IndexFlatIP`で実装しました。少しだけ面倒だったので、記録しておきます。

公式の方法に準拠しています。

https://github.com/facebookresearch/faiss/wiki/MetricType-and-distances#how-can-i-index-vectors-for-cosine-similarity

以前の関連記事です。

https://qiita.com/FukuharaYohei/items/5beceec0d2c6023ab129

# 環境
Google Colabで動かしています。`pip`で`faiss-cpu`をインストールしています。

|種類|バージョン|備考|
|:-:|:-:|:--|
|Python|3.10.12||
|faiss-cpu|1.8.0|CPUで動かしいます|
|numpy|1.25.2||
|pandas|2.0.3|必須でないけど私が慣れているので|

# プログラム
## パッケージインポート
何の変哲もないインポート。

```python
import numpy as np
import faiss
import pandas as pd
```

## テストデータ作成
2次元×3行のテストデータを作成。デフォルトのfloat64では後続プロセスの`faiss.normalize_L2`でエラーが起きたのでfloat32にしています。
float64で後続処理をする方法は調べていないです。

```python
df = pd.DataFrame({'D1': [.1, .2, .3],
                   'D2': [.2, .3, .4]}, dtype='float32')
```

データの中身です。

```python
    D1   D2
0  0.1  0.2
1  0.2  0.3
2  0.3  0.4
```

## データのL2で正規化
あまり意味がわかっていない部分もあるのですが、配列をL2正規化します。

```python
# Convert the DataFrame to a NumPy array
df_array = df.to_numpy()

# Make the array C-contiguous
df_array = np.ascontiguousarray(df_array)

# Normalize the array using the faiss library
faiss.normalize_L2(df_array)
print(df_array)
```

各行単位でL2正規化されているのがわかります。L2で正規化されているので、検索時のスコアが内積でそのままコサイン類似度になります。

```:df_array
[[0.44721362 0.89442724]
 [0.5547002  0.8320503 ]
 [0.6        0.8       ]]
```

## インデックス構築
インデックスを`IndexIDMap2`で構築します。

```python
quantizer = faiss.IndexFlatIP(2)

# IDのマッピング
index = faiss.IndexIDMap2(quantizer)

index.train(df_array)

# [1, 2, 3]はID
index.add_with_ids(df_array, [1, 2, 3])
```

## 検索
`[1, 1]`に近いものを探します。ベクトルをL2正規化してから検索。

```python
query = np.array([[1, 1]], dtype='float32')
faiss.normalize_L2(query)
print(qeury)
distance, ind = index.search(query, 2)
print(f'{distance=}')
print(f'{ind=}')
```

3番と2番が検索できていて、正しさを確認。コサイン類似度も1に近くて(計算していないですが)正しいでしょう。

```
[[0.70710677 0.70710677]]
distance=array([[0.9899495, 0.9805807]], dtype=float32)
ind=array([[3, 2]])
```
Unity でscriptがよくわからない

練習で、ブロック崩しをUnity で作っています。
参考にhttps://hu-gsd.com/lecture/unity-block-2/
をみながら作っているのですが、ゲームオーバー時には「Game Over」に変更するの欄がよくわからず失敗します。
もしかしたらscriptの書き方が間違っているのかもしれないのですが、『Textゲームオブジェクトを指定しましょう。』と言っていることがよくわからないです。



![スクリーンショット 2024-05-29 062328.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953457/b27d4c5d-8988-1949-627d-d4d2ddad0f9d.png)
↑次はこのようにしなければいけないらしいのですが

using UnityEngine;

class GameOver : MonoBehaviour
{
    // 衝突時に呼ばれる
    void OnCollisionEnter(Collision collision)
    {
        // 当たったゲームオブジェクトを削除する
        Destroy(collision.gameObject);
    }
}
↑のようなコードから何かしらの方法で書き換えなければいけません。
書き手の言ってることが理解できず、行き詰っています。
React Router v6におけるルーティング 〜RoutesとRouteとOutlet〜

## はじめに
UdemyでReactの講座を購入したのだが共通レイアウトを使用する際にReact Router v5における記法だったためReact Router v6ではどう書くのか詰まった。
今回はその方法をまとめる。

## 問題点
一部のコンポーネント（今回はTopとUser）で共通レイアウトを使用する際v5では以下のような方法だった。
```Router.jsx
import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Layout from './Layout'; // 共通レイアウトコンポーネント
import Top from './Top'; // トップページコンポーネント
import Users from './Users'; // ユーザーページコンポーネント
import NoPage from './NoPage'; // 404ページコンポーネント

export const Router = () => {
  return (
    <BrowserRouter>
      <Switch>
        {/* トップページとユーザーページは共通のレイアウトを使用 */}
        <Route exact path="/">
          <Layout>
            <Top />
          </Layout>
        </Route>
        <Route path="/users">
          <Layout>
            <Users />
          </Layout>
        </Route>
        {/*404ページは共通のレイアウトを使用しない */}
        <Route path="*">
          <NoPage />
        </Route>
      </Switch>
    </BrowserRouter>
  );
};
```
しかしv6では`<Switch>`の代わりに`<Routes>`を使用し、共通レイアウトを提供するLayoutコンポーネントは`<Outlet>`を使用してネストされた`<Route>`の内容を表示する書き方になった。
つまり以下のようになった。

## 解決策
TopとUserにLayoutコンポーネントで共通レイアウトを適用させたい場合は以下のようにする。
```Router.jsx
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Layout from "./Layout"; // 共通レイアウトコンポーネント
import Top from "./Top"; // トップページコンポーネント
import Users from "./Users"; // ユーザーページコンポーネント
import NoPage from "./NoPage"; // 404ページコンポーネント

export const Router = () => {
  return (
    <BrowserRouter>
      <Routes>
        {/* 共通のレイアウトを適用するRoute */}
        <Route path="/" element={<Layout />}>
          <Route index element={<Top />} /> {/* インデックスルート （"/"のパスではTopの内容が表示される）*/}
          <Route path="users" element={<Users />} /> {/* /users */}
        </Route>
        {/* 共通のレイアウトを適用しないRoute */}
        <Route path="*" element={<NoPage />} /> {/* その他の全てのパス */}
      </Routes>
    </BrowserRouter>
  );
};
```
共通コンポーネントでは`<Outlet />`を使用する。そうすることによってネストされたコンポーネントの内容が表示される。
```Layout.jsx
import { Footer } from "../atoms/layout/Footer";
import { Header } from "../atoms/layout/Header";
import { Outlet } from "react-router-dom";

export const Layout = () => {
  return (
    <>
      <Header /> {/* ヘッダー */}
        <Outlet /> {/* ここにネストされたルートの内容（Topの内容）が表示される */}
      <Footer /> {/* フッター */}
    </>
  );
};

```

## 終わりに
学習中のためまだまだ把握しきれていないこともあり間違っている場合もあるのでその際はご連絡ください。
SAP Build Appsを有効化したら、IASでしかログインできなくなった

## 経緯
トライアルアカウントでSAP Build Appsを使うため、ブースターを実行してサービスを有効化しました。この後、SAP Build Apps以外のサービスを利用しようとしたときも、IASによる認証を求められるようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/bc0dacb1-a95c-257a-6675-f903eab7f966.png)

## 原因
ブースターによってCustom IASテナントが登録されたとき、Default identity providerの"Available for User Login"のチェックが外れていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/c9e2c209-b930-14c9-2929-23dd3cd83eb4.png)

## 対応
"Available for User Login"のチェックをつけます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/e8c4c7ad-2dde-033f-6ee8-5ea5d5e3d1dd.png)

## 結果
ログイン時、IAS（上）とDefault identity providerが選択できるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/c7af9787-bb7d-c0d8-8527-ce0a678d0eb3.png)
【GitHub Copilot Workspace】「Git Repository is empty.」の解決方法

# 発生するエラー
Copilot Workspaceでsessionを開始しようとすると「Git Repository is empty.」と表示されて開始できない
![スクリーンショット 2024-05-29 3.56.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188242/c65edff7-db7a-f07c-cd1e-79147dffb034.png)

# 原因
リポジトリ内にファイルが存在しない

# 解決方法
ファイルを1つ以上コミットして追加しておく
`README.md`でも良い
ホームディレクトリのフォルダ名の表記言語の切り替え


# ホームディレクトリのフォルダ名の変更
ホームディレクトリには、ユーザーがダウンロードしたり、文書や音楽を保存するためのフォルダが標準的に用意されています。
その名称を日本語または英語に変更します。(ダウンロード <-> Downloads など)

## 英語へ変更
再ログイン時に、フォルダ名を元に戻すか確認されないためには「Don’t ask me this again」または「次回から表示しない」にチェックをいれて実行しましょう。
```sh
LANG=en_US.UTF-8 xdg-user-dirs-gtk-update
```
上記コマンドが動作しない場合
```sh
LANG=en_US.UTF-8 xdg-user-dirs-update --force
```

```
Moving DESKTOP directory from デスクトップ to Desktop
Moving DOWNLOAD directory from ダウンロード to Downloads
Moving TEMPLATES directory from テンプレート to Templates
Moving PUBLICSHARE directory from 公開 to Public
Moving DOCUMENTS directory from ドキュメント to Documents
Moving MUSIC directory from 音楽 to Music
Moving PICTURES directory from 画像 to Pictures
Moving VIDEOS directory from ビデオ to Videos
```
### ファイルの移動
フォルダ名が変更されても、もともとのフォルダに存在するファイルは移動されません。
そこで`cp`コマンドでハードリンクとしてコピーします。ハードリンクとしてコピーするとファイルの実体は同じものとして扱われるので、コピーに時間がかかりません。[^1]
```
cp -al ~/デスクトップ/* ~/Desktop/
cp -al ~/ダウンロード/* ~/Downloads/
cp -al ~/テンプレート/* ~/Templates/
cp -al ~/公開/* ~/Public/
cp -al ~/ドキュメント/* ~/Documents/
cp -al ~/音楽/* ~/Music/
cp -al ~/画像/* ~/Pictures/
cp -al ~/ビデオ/* ~/Videos/
```
[^1]: 言語を切り替えた時点で、元フォルダが空の場合には、元フォルダが削除されているのでエラーになりますが、スルーしてください。

#### 元のフォルダを削除
問題なくファイルがコピーされたら、元フォルダを削除しておきましょう。[^1]
```
rm -ir ~/デスクトップ
rm -ir ~/ダウンロード
rm -ir ~/テンプレート
rm -ir ~/公開
rm -ir ~/ドキュメント
rm -ir ~/音楽
rm -ir ~/画像
rm -ir ~/ビデオ
```

## 日本語へ変更
再ログイン時に、フォルダ名を元に戻すか確認されないためには「Don’t ask me this again」または「次回から表示しない」にチェックをいれて実行しましょう。
```sh
LANG=ja_JP.UTF-8 xdg-user-dirs-gtk-update
```
上記コマンドが動作しない場合
```sh
LANG=ja_JP.UTF-8 xdg-user-dirs-update --force
```
```
Moving DESKTOP directory from Desktop to デスクトップ
Moving DOWNLOAD directory from Downloads to ダウンロード
Moving TEMPLATES directory from Templates to テンプレート
Moving PUBLICSHARE directory from Public to 公開
Moving DOCUMENTS directory from Documents to ドキュメント
Moving MUSIC directory from Music to 音楽
Moving PICTURES directory from Pictures to 画像
Moving VIDEOS directory from Videos to ビデオ
```
### ファイルの移動
```sh
cp -al ~/Desktop/* ~/デスクトップ/
cp -al ~/Downloads/* ~/ダウンロード/
cp -al ~/Templates/* ~/テンプレート/
cp -al ~/Public/* ~/公開/
cp -al ~/Documents/* ~/ドキュメント/
cp -al ~/Music/* ~/音楽/
cp -al ~/Pictures/* ~/画像/
cp -al ~/Videos/* ~/ビデオ/
```

#### 元のフォルダを削除
問題なくファイルがコピーされたら、元フォルダを削除しておきましょう。[^1]
```sh
rm -ir ~/Desktop
rm -ir ~/Downloads
rm -ir ~/Templates
rm -ir ~/Public
rm -ir ~/Documents
rm -ir ~/Music
rm -ir ~/Pictures
rm -ir ~/Videos
```
TestPlanを新しく作りたくなかったから無理やりねじ込んだ話

# 開発環境
Xcode 15.4
Swift 5.10

# 話の概要
iOS のプロジェクトを作成するとき、"Include Test" を選択すると、自動的に Test Plans が作成されます。

スキーママネージャを確認すると、次のように表示されます。
```sh
[プロジェクト名](Autocreated)
```

![image.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/707293/e0905327-7b2b-13e0-eac6-43ec491ad496.jpeg)

しかし、このスキーマを削除した場合、Test Plans を手動で作成する必要があります。そのため、作成した Test Plans ファイルをプロジェクト内に配置する必要があります。

## Test Plans とは
Xcode 11 から追加されたテストに関する機能です。
Test Plan を利用すると、さまざまなテストの設定を1つのJSONファイル(`.xctestplan`)に書いておき、実行時にまとめて実行することができる優れものです。


# 今回やったこと
誤ってスキーマを削除してしまったため、手動で Test Plans を作成することになりました。
しかし、新しいファイルを作成するのは避けたかったので、自動的に作成された Test Plans と同様にプロジェクトファイルを編集する方法を選びました。

今回はその知見を共有します。

## 設定ファイルの場所
自動生成されたテストプランは、`.xcodeproj/xcschemes/[プロジェクト名].xcscheme` に保存されています。
この中の `<TestAction>` セクションに記述する必要があります

## AutocreateTestPlan の追記
`<TestAction>` セクション内に `shouldAutocreateTestPlane` の設定がない場合、以下のように追記します。
```diff_shell
   <TestAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      shouldUseLaunchSchemeArgsEnv = "YES"
+      shouldAutocreateTestPlan = "YES">
```
これにより、スキーマ名が
```sh
[プロジェクト名](Autocreated)
```
の `(Autocreated)` 部分に反映されます。

## ビルド対象の設定
ユニットテスト、UIテストを実行するように設定するため、以下のように設定します。
ユニットテストおよび UI テストを実行するように設定するため、以下のように `<Testables>` 

```shell
      <Testables>
         <TestableReference
            skipped = "NO"
            parallelizable = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "3F91F191F191F191F191F1"
               BuildableName = "[プロジェクト名]Tests.xctest"
               BlueprintName = "[プロジェクト名]Tests"
               ReferencedContainer = "container:[プロジェクト名].xcodeproj">
            </BuildableReference>
         </TestableReference>
         <TestableReference
            skipped = "NO"
            parallelizable = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "3F91F1762BBA1762BBA1762BBA"
               BuildableName = "[プロジェクト名]UITests.xctest"
               BlueprintName = "[プロジェクト名]UITests"
               ReferencedContainer = "container:[プロジェクト名].xcodeproj">
            </BuildableReference>
         </TestableReference>
      </Testables>
```

`BlueprintIdentifier` はユニットテスト、UIテストで異なるので注意してください。

# 参考資料

https://techblog.timers-inc.com/entry/test_plan_methods

https://qiita.com/akatsuki174/items/286d2c9a99385b4a222b
【Fortran】macOS + Docker + VScode を用いたFortranの実行環境構築

# 概要
本記事により、VsCode、Docker、gfortran を使用して Fortran の実行環境の構築することができます。

本環境を構築することにより、静的コード解析、ソースコードの自動整形、シンタックスハイライト、入力補完、等を利用することができます。

また、OSに依存せず同じ手順で環境を構築することができます。

:::note info
本記事は環境構築の手順に重きを置いているため、各ソフトウェアの概要や設定内容の説明は省略します。
:::


# 動作環境
intel mac、apple silicon macのどちらでも可能です。
本記事では以下の環境で操作を確認しています。

|PC|OS|CPU|
|--|--|---|
|MacBook Air 2020|macOS Sonoma 14.5|M1|



# 手順
### 1. Docker Desktopをインストールする

https://www.docker.com/ja-jp/products/docker-desktop/

### ２. VScodeをインストールする

https://code.visualstudio.com/Download


### ３. Vscodeの拡張機能をインストールする
Vsccodeのアクティビティーバーから、以下の拡張機能をインストールします。

>1.　Docker
>2.　Remote Development
>3.　Japanese Language Pack for Visual Studio Code

拡張機能のインストールは、以下の手順で行います。
>1. アクティビティーバーにある拡張機能のボタンをクリックする。
>2. 検索ボックスで拡張機能を検索する。

![スクリーンショット 2024-05-13 23.43.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3259514/55971ef0-b80d-1c5e-8bde-8ec19dea41cd.png)

</details>


### ４. 作業フォルダを作成、設定ファイルの保存
#### 4.1 作業フォルダの作成
作業フォルダを作成します。
作成したフォルダがFortranのプログラムを格納する場所になります。
作成場所はどこでも問題ありません。

#### 4.2 設定ファイルの保存
以下のリポジトリから設定用のファイルダウンロードします。
保存場所は作業フォルダのルートディレクトリとします。

https://github.com/onodera-g/Fortran_Docker_Setting

### ５. Dockerコンテナの作成
Fortranの実行環境をインストールします。

実行環境のインストールは以下の手順で行います。
>1. ステータスバーから「リモートウィンドウ」を開く。
>2. コンテナーでフォルダを開く」を選択する。開くフォルダは、「4.1 作業フォルダの作成」で作成したフォルダを指定します。
>3. 実行環境のインストールが始まりますので待ちます。**インターネット環境が必要になります。**

![スクリーンショット 2024-05-26 16.09.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3259514/102bf6a1-8117-b20b-7097-81bef8c43820.png)

![スクリーンショット 2024-05-26 16.56.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3259514/7fda17ad-4dd8-4d6a-786d-398ea64ad401.png)



# 使い方
作業フォルダ内に保存されてある**test.f95**を例に使い方を説明します。

>1. 「サイドバー」にあるファイルを選択することで、「エディター」にファイルを表示します。
>2. 「上書き保存(Command+S)」することで、静的コード解析、リファクタリングが行われます。
>3. 「Shift+Command+B」でコンパイルを行います。
>4. 「エディター」の数字の行番番号をクリックすることで、任意の箇所のブレークポイントを設定できます。
>5. 「F5」でプログラムを実行します。
>6. ブレークポイントを設定している場合には、「アクティビティーバー」の「実行とデバッグ」から、プログラム実行中の各変数の値を見ることができます。



# ２回目以降の実行環境の起動、終了方法
### 1. 起動方法
起動は「アクティビティーバー」の「リモートエクスプローラー」から行います。

![スクリーンショット 2024-05-29 1.50.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3259514/19f8d416-d74b-c4c1-8915-f5a9d0b857d7.png)

### 2. 終了方法
終了は「ステータスバー」の開発コンテナーより、「リモート接続を終了する」を選択して終了します。

![スクリーンショット 2024-05-29 1.53.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3259514/33fb0ea1-aaab-184a-65ad-aa5375e954f5.png)


##### 参考にしたサイト
https://qiita.com/implicit_none/items/ee4d3fed0ac6f974d40e
CentOS 各種コマンドメモ

# OS

### バージョン確認
```
cat /etc/redhat-release
```

### ユーザー一覧
```
cat /etc/passwd
```

### グループ一覧
```
cat /etc/group
```



# Subversion

### インストール確認
```
yum list installed | grep subversion
```

### インストール情報確認
```
yum info subversion
```

### サービス確認
```
systemctl status svnserve
```

### サービス自動起動 設定確認
```
systemctl is-enabled svnserve
```

### サービス自動起動 設定
```
systemctl enable svnserve
```

### サービス自動起動 設定解除
```
systemctl disable svnserve
```

### サービス開始
```
systemctl start svnserve
```

### サービス停止
```
systemctl stop svnserve
```

### サービスファイル
```
cat /usr/lib/systemd/system/svnserve.service
```

### バージョン確認
```
svnserve --version
```

### 設定ファイル
```
cat /etc/sysconfig/svnserve
```



# SSH

### インストール確認
```
yum list installed | grep ssh
```

### サービス確認
```
systemctl status sshd.service
```

### サービス自動起動 設定確認
```
systemctl is-enabled sshd.service
```

### サービス自動起動 設定
```
systemctl enable sshd.service
```

### サービス自動起動 設定解除
```
systemctl disable sshd.service
```

### サービス開始
```
systemctl start sshd.service
```

### サービス停止
```
systemctl stop sshd.service
```

### サービスファイル
```
cat /usr/lib/systemd/system/sshd.service
```

### 設定ファイル
```
cat /etc/ssh/sshd_config
```
Flutterの開発環境を構築（Windows編）

Android Studio環境でのFlutter開発環境の構築について。
Android Studioの環境構築に関しては[Android StudioをWindowsへインストール](https://qiita.com/sacred-sanctuary/items/8e5de35dc34fd228a471)を参照してください。

# 1. Flutter SDK
[Start building Flutter Android apps on Windows](https://docs.flutter.dev/get-started/install/windows/mobile?tab=download)の
[Download then install Flutter](https://docs.flutter.dev/get-started/install/windows/mobile?tab=download#download-then-install-flutter)からFlutter SDKをダウンロードする。
[Flutter SDK archive](https://docs.flutter.dev/release/archive?tab=windows)に過去のバージョンもあります。

# 1.1. Flutter SDKの展開
適当な場所にダウンロードしたflutter_windows_3.22.1-stable.zipファイルを展開する。
例：`C:\Flutter\3.22.1`

# 2. 環境変数
Windowsの環境変数を設定する。

## 2.1 環境変数
新しいユーザー変数の追加で変数名をFLUTTER_HOMEで、変数値を1.1 Flutter SDK を展開したPATHにする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170755/884a3e42-b8b9-7f5d-4d6a-4ffbb0dd8c3c.png)

## 2.2 システム環境変数
システム環境変数のPathを編集して、Flutter SDK内のbinのパスを追加する。

例：
C:\Flutter\3.22.1\flutter\bin


# 3. flutter doctor
## 3.1. flutter doctorの確認
コマンドプロンプトを起動して`flutter doctor`コマンドを実行する。
※おそらく下記のような内容になるかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170755/39d27979-e1a2-bdf1-d720-6bc8b0991211.png)

## 3.2. flutter doctor --android-licensesの確認
3.1.の結果に従い`flutter doctor --android-licenses`コマンドを実行し、
下記のように何度か`Accept?`と聞かれるので`y`を打ちこむ。
`All SDK package licenses accepted`となればOK。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170755/5efbcf27-e1cc-bcb1-b6b8-0244fede089f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170755/1ec04ed2-0033-c887-56a8-ebe9bf65d3bc.png)

## 3.3. 再度flutter doctorの確認
再度`flutter doctor`コマンドを実行し問題がないことを確認する。
※Android Studioでの環境構築を考えているため、Visual Studio - develop Windows appsのエラーは放置します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170755/365e1939-c7ea-f2d9-2592-4b800663cfb9.png)

# 4. Plugins
# 4.1 Flutter Plugins
Android Studioを起動してPlaginsを選択してFlutterをインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170755/38694a65-611a-5244-7944-d274a97826e9.png)

# 4.2 Dart Plugins
Android Studioを起動してPlaginsを選択してDartをインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170755/fe9295c5-893f-7e0b-02df-0df162653aad.png)


# 5. Android StudioでFlutterプロジェクトを作成
# 5.1 New Flutter Project
Android StudioのスタートメニューからNew Flutter Projectを選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170755/bdd5a85e-4b45-1116-4992-896442705e40.png)

# 5.2 Flutter SDK path
Flutter SDK pathに1.1. Flutter SDKの展開で展開したpathを選択してNextを選ぶ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170755/d7727a31-1e56-a55e-0fe2-4b992cd47e2d.png)

# 5.3 Flutterプロジェクトを作成
Project name、Project location等を設定してCreateを選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170755/49fd10b1-ed23-9f0a-7561-ed264d043ed6.png)

# 5.4 Flutterプロジェクトを実行
Runを選択してプロジェクトを実行する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170755/7603faab-0d01-e4ec-360f-28d97f1d2061.png)

これでWindows環境でFlutterプロジェクトの実行ができる様になるかと思います。
itaiji-node を作成した


## はじめに

タイトルの通り、itaiji-node が必要になったので作成した。
異体字を正体字に変換するためのパッケージ。

https://www.npmjs.com/package/itaiji

https://github.com/mziyut/itaiji-node/

## なぜ作成したか

元々 Ruby(Gem) には変換ライブラリが存在する事は認識していたが Node.js/npm パッケージとして存在していなかった。無いなら作るかくらいの気持ちでさっと作りました。

https://github.com/camelmasa/itaiji

ちなみに、 Ruby 以外に Rust/Python/PHP も存在しています。

https://github.com/camelmasa/itaiji-rust

https://github.com/yamamotoj/itaijipy

https://github.com/masanork/ikc

https://github.com/xearts/itaiji-converter

## 使い方

npm や yarn 等のパッケージマネージャから ijaiji を install

```sh
npm install itaiji
# or
yarn install itaiji
```

それぞれ読み込んで使うだけにしてあります。

```js
var itaijiNode = require('itaiji');

itaijiNode.seijitai('亞'); // -> "亜"
```

```js
import { seijitai } from 'itaiji';

seijitai('亞'); // -> "亜"
```

参考にした Ruby で作られている `camelmasa/itaiji` は、正字体 から 異体字 への変換もサポートしていますが、 ijaiji-node はサポートしていません。必要になったら作ります。

## Ref

https://camelmasa.hatenadiary.org/entry/20140630/1404142161
【GitHub Copilot Workspace】Workspaceが作成したPRに自動的にラベルをつける

## やったこと

### ラベル作成

プルリクのラベル画面にて`copilot workspace`のラベルを追加
https://github.com/{YOUR_NAME}/{YOUR_REPOSITORY}/labels
![スクリーンショット 2024-05-29 1.19.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188242/fd840b78-0f83-6701-b06c-9670172ef1c2.png)


### ファイル追加
以下の2ファイルをリポジトリに追加
```.github/workflows/label-copilot-pr.yml
name: Label PR

on:
  pull_request_target:
    types: [opened, synchronize, reopened]

permissions:
  contents: write
  pull-requests: write

jobs:
  label:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v2

    - name: Label PR
      uses: actions/labeler@v3
      with:
        repo-token: ${{ secrets.GITHUB_TOKEN }}
```

```.github/labeler.yml
# .github/labeler.yml

copilot workspace:
  - '**/*'
```

### リポジトリのWorkflow permissionsを変更
Settings -> Actions -> Generalに遷移
Workflow permissionsのRead and write permissionsをクリックしてSave
https://github.com/{YOUR_NAME}/{YOUR_REPOSITORY}/settings/actions

## 結果
Copilot Workspaceが作ったプルリクに`copilot workspace`ラベルがつけられる

![スクリーンショット 2024-05-29 1.15.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188242/0088153b-38b4-01ac-4e43-f7920865d80a.png)
Swaggerでエンドポイントを分類したい！

# 概要
FasAPIにはSwaggerUIという便利な機能が付いており、エンドポイントを簡単に叩くことができるため、開発にと手も便利です。
ですが、エンドポイントが増えてくると目的のエンドポイントが見つからなかったり、カテゴリごとに表示して可読性を高くしたいなんてことがあると思います。

今回は、Swaggerでエンドポイントを分類して表示する方法について記載していきます。

# BeforeとAfter
- Before
作成したエンドポイントが並んでいるが、ぱっと見でどれがどんな機能を持っているのかがわかりにくい。
![スクリーンショット 2024-05-29 0.39.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987584/73ae72f8-771c-2f7b-13cb-60f9ff5ebb09.png)

- After
各エンドポイントにタグをつけることで、分類して表示することができる。また、各エンドポイントの説明もあるため、どのような動きをするのかがわかりやすい。
![スクリーンショット 2024-05-29 0.48.16（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987584/8ded0d38-bed2-35da-3392-46b6849eb8dc.png)

# 設定方法
設定方法は単純で各エンドポイントに`tags`、`summary`を設定するだけでOKです。

```python
@router.get("/hello", tags=["ハロー"], summary="ハローを表示する", description="ここにエンドポイントの説明を記載する")
```

`tags`はエンドポイントにつける「タグ」の名称を指定します。ここで指定したタグがグループ化されて表示されます。
`summary`はエンドポイントの詳細を簡潔に記載します。似たようなもので`description`がありますが、こちらはより詳細にエンドポイントのについての説明事項を入力することでエンドポイントのリストビューで確認することができます。
![スクリーンショット 2024-05-29 0.56.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987584/d5a00fce-efa1-b958-b1fd-80de22cfc537.png)

# まとめ
swaggerUIは非常に便利で特に設定をしなくてもエンドポイントのドキュメントとして役に立つので、タグ付けやエンドポイントの詳細を記載しておくことでチーム開発時に新規メンバーがキャッチアップする時にも非常に強力なドキュメントとなるので、手間を惜しまずに記載しておくと良さそうですね。
java。spring。HttpHeaders型。ループで表示

Spring FrameworkのHttpHeaders型のインスタンスを作成し、そのヘッダーをループで表示する方法について説明します。HttpHeadersクラスは、HTTPリクエストおよびレスポンスのヘッダーを管理するためのクラスです。

以下は、HttpHeadersインスタンスにいくつかのヘッダーを追加し、それをループで表示するサンプルコードです。

```java
import org.springframework.http.HttpHeaders;

public class HttpHeadersExample {
    public static void main(String[] args) {
        // HttpHeadersのインスタンスを作成
        HttpHeaders headers = new HttpHeaders();

        // ヘッダーを追加
        headers.add("Content-Type", "application/json");
        headers.add("User-Agent", "Mozilla/5.0");
        headers.add("Accept", "application/json");
        headers.add("Authorization", "Bearer some_token");

        // ヘッダーをループで表示
        for (String headerName : headers.keySet()) {
            System.out.println(headerName + ": " + headers.get(headerName));
        }
    }
}
```

このコードでは、以下の手順を踏んでいます：

HttpHeadersのインスタンスを作成します。
addメソッドを使用して、いくつかのヘッダーを追加します。
keySetメソッドを使用して、すべてのヘッダー名を取得し、それをループで表示します。
HttpHeadersクラスのgetメソッドは、指定されたヘッダー名に対応するすべての値をリストとして返します。したがって、出力は各ヘッダー名とその値のリストとなります。

必要に応じて、以下のようにしてヘッダーの値をさらに詳細に表示することもできます：

```java
import org.springframework.http.HttpHeaders;
import java.util.List;

public class HttpHeadersExample {
    public static void main(String[] args) {
        // HttpHeadersのインスタンスを作成
        HttpHeaders headers = new HttpHeaders();

        // ヘッダーを追加
        headers.add("Content-Type", "application/json");
        headers.add("User-Agent", "Mozilla/5.0");
        headers.add("Accept", "application/json");
        headers.add("Authorization", "Bearer some_token");

        // ヘッダーをループで表示
        for (String headerName : headers.keySet()) {
            List<String> headerValues = headers.get(headerName);
            System.out.println(headerName + ": " + String.join(", ", headerValues));
        }
    }
}
```

このバージョンでは、各ヘッダーの値のリストをString.joinを使用してカンマ区切りの文字列に変換して表示しています。これにより、複数の値を持つヘッダーも見やすくなります。
Ruby on rails の環境構築方法（初心者用）

# Ruby on rails の環境構築方法
（初心者向け）自身の備忘としてアウトプットしています。

###  1.環境構築の準備
ターミナルにて環境構築の準備を行います。
Command(⌘)とスペースバーを同時に押すと、以下のようなSpotlightというウインドウが開くので、「ターミナル」と検索してアプリを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984055/fc6e9eda-4266-a1fc-d9fe-4e647124abca.png)


### 2.Rubyのバージョンを確認する。
Rubyのバージョンを確認してみましょう。ターミナルを開き、以下のコマンドを実行してください。
```
rbenv versions
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984055/d13dd8fa-0b55-804d-42b9-93e2625121a0.png)


### 3.Rubyのバージョンを最新バージョンに更新する
Rails 7系はRuby 2.7以上が必要なので、アップデートします。以下のコマンドを入力して、最新バージョンに更新ください。
```
rbenv install 3.1.2
```
インストールが終わったら、以下のコマンドを実行してみてください。
このコマンドでは、現在インストールされている Ruby を一覧で確認することができます。この一覧に、3.1.2 が表示されていれば、ちゃんとインストールできたことが確認できます。
```
rbenv versions
```
以下のコマンドを実行して、今回インストールしたバージョンのRubyを使用するように設定を変更しましょう。
```
rbenv global 3.1.2
```
最後にもう一度バージョンを確認して更新されていれば完了です。
```
ruby -v
```
完了です。次はRuby on Railsの設定に移ります。

### 4.Ruby on Railsをインストールする。
以下のコマンドを実行してください。
```
gem install rails -v 7.0.3
```
インストールが完了したら、Railsのバージョンを確認してみましょう。
以下のコマンドを実行してください。
```
rails -v
```
Rails 7.0.3 と表示されれば、Railsのインストールは完了です！

### 5.Railsアプリケーションの作成
アプリケーションの新規作成には以下のコマンドを使用します。
```
rails new アプリケーション名（例：eastdogs_app）
```
以下のコマンドにて、アプリケーションフォルダが作成されていることを確認してみましょう。
```
ls
```
アプリケーション名が並んでいればOKです。

### 6.ローカルでRailsサーバを立てる
Railsサーバを立てて、ローカルでアクセスしましょう。
まずは先程作成したフォルダ（例：eastdogs_app）に以下のコマンドを使用して移動しましょう。
```
cd eastdogs_app
```
以下のように、%の前にアプリケーション名が表示されていると、問題なく移動できています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984055/5dfcb5da-4662-adbf-4123-4a0a494baedf.png)


Railsのサーバを立てる時には以下のコマンドを実行します。
```
rails s
```
ブラウザを開いてURLの場所に以下のように入力ください。
```
localhost:3000
```
以下の画像が出れば、Railsサーバが立っていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984055/13c45cf4-42c5-1b2f-bdc6-f6f29c62e58b.png)

Railsサーバを止めたい時には以下のようにキーボードを入力すると、サーバが止まります。
```
control + c
```
ここまでが、Ruby on rails の環境構築方法でした。

以上
Ollamaのダウンロードしたモデルをすべて更新する

Ollamaで使えるモデルは更新されることがあります．どれが更新されているか確認するのも面倒ですし，ダウンロードしたモデルをすべて一つ一つ更新するのも面倒です．次のone-linerでダウンロードしているすべてのモデルを一気に更新できます．

```
ollama list | tail -n +2 | awk '{print $1}' | xargs -n1 ollama pull
```

参考サイト
https://github.com/ollama/ollama/issues/803
customtkinterでGUIアプリ作成した話

# customtkinterでGUIアプリ作成した話

Pythonを利用する場合、データ処理に活用するのでjupyterで開いて、セル単位で実行みたいな人が多いと思います。
ただ、PythonでもGUIのツールが作成できるし、人に使ってもらうために配るならこの形式の方がとっつきやすいと思います。

というわけで、今回はGUIのツールをcustomtkinterを使用して作成してみました。

題材は、最近TeraTermでの作業が必要になったのでTeraTerm経由でのサーバアクセスを補助するツールです。


# 今回作成したツールのリポジトリ

https://github.com/ardnico/ForTeraterm

# 大まかな構成

今回お世話になったのは「Akascape」さんの[CTkMenuBar](https://github.com/Akascape/CTkMenuBar)です。

ツールっぽく見せられるかつ、編集も楽で使い勝手が良かったです。

まずは画面上部のメニューを大項目としてとらえて、
大項目単位でフォルダを作成しました
※命名規則は"Window" ＋ 項目名

```
ForTeraterm/
　├ WindowAction/
　├ WindowSettings/
  ├ __init__.py
  └ main_menu.py # メニュー画面担当

```

そして各メニューに合わせてその配下にクラスファイルを配置しています。
今回は設定に関連するものも「WindowSettings」配下に配置しました

```
ForTeraterm/
　├ WindowAction/
  │            ├ __init__.py
  │            ├ editmacro.py
  │            ├ serveraccess.py
  │            └ serverregist.py
　├ WindowSettings/
  │            ├ __init__.py
  │            ├ edit.py
  │            ├ image.py # 画像ファイルを扱う
  │            ├ theme.py # 色を扱う
  │            └ conf.py # 設定ファイルを扱う
  ├ __init__.py
  └ main_menu.py 

```
ここまで出来たら、あとは小項目のクラス内で、各画面をどのようにしたらいいのかを記載します。
記載ができたら「main_menu.py」から呼んであげることで、
ウィンドウの各メニューをクリックしたときに各メニューが呼び出されるようになります。
※本当は片づけように、呼び出した後のオブジェクトの初期化用のメソッドも準備しておけば、メニューを切り替えたときに、お残しなく画面遷移させられるのですが
面倒なのでそのうち実装します


これをしてあげたら、あとは処理部分を記載してあげればツールとして出来上がります。

# 結

結構規則を意識しつつ記載していたので、いい感じにまとめればガワを作るためのものもかけそうだとは思いつつ、気力が尽きたのでその気になったらやるかもしれません。




おやすみ
(調査中)Javaでhttpclientでファイルをレスポンスとして受け取り、NASサーバーに保存

JavaでHttpClientを使用してファイルをレスポンスとして受け取り、NAS（ネットワークアタッチトストレージ）サーバーに保存する方法を以下に示します。ここでは、ファイルをレスポンスとして受け取った後に、NASサーバーの共有フォルダに保存する方法を説明します。

NASサーバーにファイルを保存するためには、事前にNASの共有フォルダがマウントされているか、アクセス可能である必要があります。以下の例では、NASの共有フォルダがローカルファイルシステムのパスとして利用可能であることを前提としています。

#### 前提条件
NASの共有フォルダがローカルファイルシステムにマウントされていること（例: //nas-server/shared が Z:\shared としてマウントされている）。
#### コード例
以下のコードでは、HttpClientを使用してファイルをダウンロードし、そのファイルをNASの指定されたパスに保存します。

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;

public class HttpClientDownloadToNAS {
    public static void main(String[] args) {
        // ダウンロードするファイルのURL
        String fileUrl = "https://example.com/path/to/file";
        
        // NASの保存先パス (Windowsのネットワークドライブの例)
        Path nasFilePath = Paths.get("Z:/shared/path/to/save/file");

        // HttpClientを作成
        HttpClient client = HttpClient.newHttpClient();

        // HttpRequestを作成
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(fileUrl))
                .build();

        try {
            // HttpResponseを取得し、レスポンスをファイルとして保存
            HttpResponse<Path> response = client.send(request, HttpResponse.BodyHandlers.ofFile(nasFilePath));

            // レスポンスのステータスコードをチェック
            if (response.statusCode() == 200) {
                System.out.println("File downloaded successfully to " + nasFilePath);
            } else {
                System.out.println("Failed to download file. HTTP status code: " + response.statusCode());
            }
        } catch (IOException | InterruptedException e) {
            System.err.println("Error occurred: " + e.getMessage());
        }
    }
}
```

## コードの説明
#### URLとNASの保存先パスの設定:

fileUrlにはダウンロードしたいファイルのURLを指定します。
nasFilePathにはNASの保存先のパスを指定します。
#### HttpClientの作成:

HttpClient.newHttpClient()でHttpClientのインスタンスを作成します。
#### HttpRequestの作成:

HttpRequest.newBuilder().uri(URI.create(fileUrl)).build()でHttpRequestのインスタンスを作成します。
#### HttpResponseの取得とファイル保存:

client.send(request, HttpResponse.BodyHandlers.ofFile(nasFilePath))でHTTPリクエストを送信し、レスポンスを指定されたNASのパスに保存します。
#### レスポンスのステータスコードをチェック:

ステータスコードが200（HTTP OK）であることを確認し、成功時にはファイルの保存先を出力します。
エラー発生時には適切なメッセージを表示します。
このコードを使用することで、指定されたURLからファイルをダウンロードし、そのファイルをNASの共有フォルダに直接保存することができます。NASの共有フォルダがローカルファイルシステムとして認識されていれば、このアプローチは簡単に実装可能です。
文字を連結するエクセルマクロ

# はじめに
文字を連結するエクセルマクロを作成しました。エクセル関数でも単純なものならいいのですが、複雑な場合よく分からなくなるのでその時用です。

先頭文字を大文字にして返却する関数も途中で入れています。
エクセル標準の「PROPER」関数は英字の先頭を大文字にしますが、2文字目以降を小文字に変換してしまうので使用しませんでした。


# ソース
```MojiRenketu.txt
Sub MojiRenketu()

    Dim kansei As String: kansei = "" '完成形
    Dim outCount As Long: outCount = 0  '出力数
    Dim rowCount As Long: rowCount = 0  '列数
    
    
    '出力数カウント
    Do
        '// セル値が未設定の場合
        If Cells(outCount + 1, 1).Value = "" Then
            '// ループを抜ける
            Exit Do
        End If
        
        '// ループカウンタを加算
        outCount = outCount + 1
    Loop
    
    '列数カウント
    Do
        '// セル値が未設定の場合
        If Cells(3, rowCount + 1).Value = "" Then
            '// ループを抜ける
            Exit Do
        End If
        
        '// ループカウンタを加算
        rowCount = rowCount + 1
    Loop
    
    
    For i = 1 To outCount
    
        kansei = ""
    
        kansei = kansei & "最初の文字/"
        kansei = kansei & Cells(i, 1).Value
        kansei = kansei & "/AB間/"
        kansei = kansei & oomoji(Cells(i, 2).Value)
        kansei = kansei & "/BC間/"
        kansei = kansei & oomoji(Cells(i, 3).Value)
        kansei = kansei & "/最後の文字"
        
        '完成形を出力
        Cells(i, rowCount + 1).Value = kansei
    Next i

    

End Sub

'先頭文字を大文字にして返却する
Function oomoji(ByVal moji As String) As String
    oomoji = UCase(Left(moji, 1)) & Mid(moji, 2)
End Function



```

# 使い方
連結したい文字を入力する。連結前後に入れたい文字列はソースを直接いじって入れる。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3621123/47b4667e-6de8-171b-0dda-c05d62711250.png)



マクロを実行すると、最後の列の次の列（この例だとD列）に連結された文字列が生成されます。ローマ字は先頭のみ大文字になります。
【DeviseTokenAuth】パスワード変更時に変更通知メールを送信する方法

## 設定を記述

設定を記述する。

```rb:config/initializers/devise.rb
Devise.setup do |config|
  # ...
  config.send_password_change_notification = true
end


```

## メール内容の変更

メール内容を変更する。

```erb:app/views/devise/mailer/password_change.html.erb
<p><%= t(:hello).capitalize + '、' + @resource.name %>さん。</p>

<p><%= @resource.email %>のパスワードが変更されました。</p>

```

## 参考ページ

https://github.com/heartcombo/devise/blob/a259ff3c28912a27329727f4a3c2623d3f5cb6f2/lib/generators/templates/devise.rb#L134

https://github.com/heartcombo/devise/blob/a259ff3c28912a27329727f4a3c2623d3f5cb6f2/app/views/devise/mailer/password_change.html.erb
【Laravel】独自の単位でリクエスト制限を設定する

この記事では、Laravelアプリケーションで独自のID単位でリクエスト制限を設定する方法を説明します。

デフォルトでは、LaravelはIPアドレスやユーザーID単位でリクエストを制限しますが、特定のシステムIDやユーザーセッションIDに基づいてリクエストを制限することで、より細かな制御が可能になります。

今回は、セッションIDを単位で1分間に10回のリクエスト制限を設定する例を用いて具体的に解説します。

## コードの説明

### 1. **カスタムミドルウェアの作成**

まず、特定のID（例としてセッションID）に基づいてリクエストを制限するためのカスタムミドルウェアを作成します。

   ```php
   namespace App\Http\Middleware;

   use Illuminate\Routing\Middleware\ThrottleRequests;

   class ThrottleRequestsByCustomID extends ThrottleRequests
   {
       protected function resolveRequestSignature($request)
       {
           // ここで独自のIDを取得するロジックを追加します。例としてセッションIDを使用
           return $request->session()->getId();
       }
   }
   ```

このカスタムミドルウェアは、`resolveRequestSignature`メソッドをオーバーライドして、独自のID（この例ではセッションID）をリクエストの識別子として使用します。必要に応じて、セッションID以外の任意のIDに変更できます。

### 2. **デフォルトのThrottleRequestsミドルウェアの解説**

Laravelのデフォルトの`ThrottleRequests`ミドルウェアでは、ユーザーIDやIPアドレスを使用してリクエストを制限しています。以下がその`resolveRequestSignature`メソッドのコードです。

   ```php
   protected function resolveRequestSignature($request)
   {
       if ($user = $request->user()) {
           return $this->formatIdentifier($user->getAuthIdentifier());
       } elseif ($route = $request->route()) {
           return $this->formatIdentifier($route->getDomain().'|'.$request->ip());
       }

       throw new RuntimeException('Unable to generate the request signature. Route unavailable.');
   }
   ```

このメソッドは、以下の順序でリクエストの識別子を生成します：
- 認証されたユーザーがいる場合は、そのユーザーIDを使用します
- 認証されたユーザーがいない場合は、ルートのドメインとリクエストのIPアドレスを使用します
- どちらも利用できない場合は、例外をスローします

### 3. **ミドルウェアの登録**

次に、カスタムミドルウェアをアプリケーションに登録します。`app/Http/Kernel.php`ファイルを開き、`$routeMiddleware`にカスタムミドルウェアを追加します。

   ```php
   protected $routeMiddleware = [
       // 他のミドルウェア
       'throttle.custom' => \App\Http\Middleware\ThrottleRequestsByCustomID::class,
   ];
   ```

この設定により、`throttle.custom`というエイリアスでカスタムミドルウェアを使用できるようになります。

### 4. **デフォルトのミドルウェア設定を変更**

全てのルートに対して独自のIDに基づくリクエスト制限を適用するために、`$middlewareGroups`にカスタムミドルウェアを追加します。

   ```php
   protected $middlewareGroups = [
       'web' => [
           // 他のミドルウェア
           \App\Http\Middleware\ThrottleRequestsByCustomID::class,
           'throttle:10,1', // 1分間に10回
       ],

       'api' => [
           \App\Http\Middleware\ThrottleRequestsByCustomID::class,
           'throttle:10,1', // 1分間に10回
       ],
   ];
   ```

この設定により、`web`および`api`のミドルウェアグループ内のすべてのルートに対して、1分間に10回のリクエスト制限が独自のID単位で適用されます。

# まとめ

この記事では、Laravelでセッション単位または独自のID単位のリクエスト制限を設定する方法を解説しました。

カスタムミドルウェアを作成し、それをアプリケーションに登録することで、特定のIDに基づくリクエストの頻度を制御できるようになります。

この設定により、過剰なアクセスを防ぎ、アプリケーションのパフォーマンスとセキュリティを向上させることができます。
必要に応じて、任意のIDに変更することで、システムの要件に柔軟に対応できます。
双方向リストの初期化とダミーヘッド・ダミーテイルについて


## 双方向リストの基本構造

双方向リストは、各ノードが前後のノードへの参照を持つデータ構造です。これにより、リスト内のノードを両方向にたどることができます。

### ノードの構造

まず、ノードの構造は以下のようになります：

```java
class Node<K, V> {
    K key;
    V value;
    Node<K, V> prev;
    Node<K, V> next;

    public Node(K key, V value) {
        this.key = key;
        this.value = value;
        this.prev = null;
        this.next = null;
    }
}
```

- `key`：ノードのキー
- `value`：ノードの値
- `prev`：前のノードへの参照
- `next`：次のノードへの参照

### ダミーヘッドとダミーテイル

双方向リストを簡単に管理するために、ダミーヘッド（head）とダミーテイル（tail）という特別なノードを使用します。これにより、リストの先頭や末尾の操作が容易になります。

### リストの初期化

ダミーヘッドとダミーテイルを使ったリストの初期化は次のように行います：

```java
class DoublyLinkedList<K, V> {
    private final Node<K, V> head;
    private final Node<K, V> tail;

    public DoublyLinkedList() {
        this.head = new Node<>(null, null); // ダミーヘッド
        this.tail = new Node<>(null, null); // ダミーテイル
        head.next = tail;
        tail.prev = head;
    }
}
```

ここで `head.next = tail;` と `tail.prev = head;` は以下のような意味を持ちます：

1. **`head.next = tail;`**:
    - ダミーヘッドの `next` フィールドがダミーテイルを指します。
    - これにより、リストの先頭に要素がない場合、ダミーヘッドの `next` は常にダミーテイルを指すことになります。
    - リストが空の状態では、ヘッドの次がテイルとなります。

2. **`tail.prev = head;`**:
    - ダミーテイルの `prev` フィールドがダミーヘッドを指します。
    - これにより、リストの末尾に要素がない場合、ダミーテイルの `prev` は常にダミーヘッドを指すことになります。
    - リストが空の状態では、テイルの前がヘッドとなります。

### リストの初期状態

上記の設定により、リストの初期状態は次のようになります：

```
head <-> tail
```

- `head.next` は `tail` を指し、
- `tail.prev` は `head` を指します。

この構造により、双方向リストの操作（ノードの追加や削除）が簡単になります。

### ノードの追加例

新しいノードをリストに追加する場合、例えば先頭にノードを追加する操作は次のように行います：

```java
public void addFirst(Node<K, V> node) {
    node.prev = head;
    node.next = head.next;
    head.next.prev = node;
    head.next = node;
}
```

この操作により、リストは以下のように更新されます：

1. 新しいノード `node` の `prev` を `head` に設定します。
2. 新しいノード `node` の `next` を現在の最初のノード（`head.next`）に設定します。
3. 元の最初のノードの `prev` を `node` に設定します。
4. `head.next` を `node` に設定します。

結果として、リストの先頭に新しいノードが追加されます。

### ノードの追加後の状態

```
head <-> node <-> tail
```

このように、ダミーヘッドとダミーテイルを使うことで、リストの先頭や末尾に要素を簡単に追加・削除することができるようになります。

### 実際の応用例

例えば、LRUキャッシュの実装では、双方向リストを使用してキャッシュ内の要素を管理します。この方法により、最も古い要素を効率的に削除し、最新の要素を簡単に追加できます。双方向リストの管理が簡単で、O(1)の時間複雑度で操作が行えるため、パフォーマンスが向上します。
Web ターミナルから Databricks CLI を使ってシステムテーブルスキーマを有効化する

パブリックプレビュー中（2024/5 時点）である Azure Databricks のシステムテーブルを確認してみたかったので有効化してみました。

https://learn.microsoft.com/ja-jp/azure/databricks/admin/system-tables/

また、有効化のためにcurl コマンドを使用する必要があるのですが、Databricks Runtime 15.1を使用すると、ノートブックの Web ターミナルから Databricks CLI を使用できるようになったのでこちらを使ってみました。

https://learn.microsoft.com/ja-jp/azure/databricks/release-notes/runtime/15.1#databricks-cli-now-available-in-the-web-terminal

## 前提
システムテーブルスキーマを有効化するにはUnity Catalog が必要となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/9d3a63d9-6167-63dd-4d53-006f55296ec6.png)

有効化前は `system` カタログには `information_schema` しか見えていないはずなので、`access`, `billing`, `compute` スキーマを見えるようにしていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/af3f5799-1f76-3857-54f0-bc222b2bf58a.png)

## Web ターミナルから Databricks CLI を使用

ノートブックに Runtime のバージョンを 15.1 に設定したクラスターをアタッチします。
Web ターミナルから Databricks CLI を使用するための要件は下記となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/977af03f-210b-c5ae-5b97-7b20cfacedfc.png)

https://learn.microsoft.com/ja-jp/azure/databricks/notebooks/notebook-ui#cli

Web ターミナルを開くには、右側のサイドバーの下部にあるアイコンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/4e8994ee-2df6-4fb7-8732-adc22dd9f4fb.png)

下図のようなターミナルが起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/e2ffca48-31b3-1d70-bb06-ac70d80b4675.png)

## システムテーブルスキーマを有効にする

https://learn.microsoft.com/ja-jp/azure/databricks/admin/system-tables/#--enable-system-table-schemas

### 使用可能なシステムテーブルスキーマを表示する
まずは使用可能なシステムテーブルスキーマを表示してみました。
```
curl -v -X GET -H "Authorization: Bearer <PAT Token>" "https://adb-<xxx>.azuredatabricks.net/api/2.0/unity-catalog/metastores/<metastore-id>/systemschemas"
```
- PAT Token：パーソナルアクセストークン（作成時に表示される文字列）
- adb-xxx.azuredatabricks.net：対象のワークスペースのURL（Azure Portalから確認可能）
- metastore-id：メタストアID（カタログエクスプローラーの歯車マークから確認可能）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/99d4e90b-6b4f-94c2-431e-10d4db52f207.png)

ターミナルで上記コマンドを実行すると、下記のような表示があります。

```
{"schemas":[{"schema":"operational_data","state":"UNAVAILABLE"},{"schema":"access","state":"AVAILABLE"},{"schema":"billing","state":"AVAILABLE"},{"schema":"compute","state":"AVAILABLE"},{"schema":"marketplace","state":"AVAILABLE"},{"schema":"lineage","state":"UNAVAILABLE"},{"schema":"information_schema","state":"EnableCompleted"}]}`
```

`state:AVAILABLE`：スキーマは使用できるが、まだ有効化されていない
`state: EnableCompleted`：スキーマは有効化され、カタログエクスプローラーに表示される

### システムテーブルスキーマを有効化する
有効化するには下記のコマンドを実行します。
```
curl -v -X PUT -H "Authorization: Bearer <PAT Token>" "https://adb-<xxx>.azuredatabricks.net/api/2.0/unity-catalog/metastores/<metastore-id>/systemschemas/<SCHEMA_NAME>"
```
`SCHEMA_NAME` を `access`, `billing`, `compute` に変更して実行することで `state: EnableCompleted` となり、カタログエクスプローラーに表示されます。
Pythonで年初来安値一覧から利回りの高い株の銘柄を抽出する（Webスクレイピング）

## 概要
pythonの練習がてらWebスクレイピングを用いて株の銘柄を検索して表示する機能を作りました。

## 背景
2024年から新NISAとなり、個別株含めて投資熱が高まってきました。

しかし、日々仕事しながら株価見るのはしんどい、、、できれば買ったら放置したい、、、

ということで以下のターゲットを絞って株の銘柄を検索してみることにします。
* 株価が安くなっている
* 利回りが高い

上記2点を満たす銘柄として、年初来安値一覧の中から、利回り4%以上の銘柄を表示する機能を作ります。

## 実装
まずは必要なライブラリをインポートします
```python
import requests
from bs4 import BeautifulSoup
```
受け取ったURLから年初来安値一覧のテーブルを取得し、必要な情報を抽出して表示するメソッドを作成します。
今回はかぶたんの年初来安値一覧から抽出する前提で作成しています。
```python
def main(url):
    stocks = []
    # ページをリクエスト
    response = requests.get(url)
    response.encoding = 'utf-8'

    # BeautifulSoupでHTMLをパース
    soup = BeautifulSoup(response.text, 'html.parser')

    # 年初来安値一覧のテーブルを見つける
    table = soup.find('table', {'class': 'stock_table'})

    # テーブルから銘柄情報を取得
    for row in table.find_all('tr')[1:]:  # ヘッダー行をスキップ
        columns = row.find_all((["td", "th"]))
        if columns and len(columns) > 5:  # 必要なカラムが存在するか確認
            code = columns[0].text.strip()
            name = columns[1].text.strip()
            price = columns[5].text.strip().replace(',', '')
            yield_percent = columns[12].text.strip().replace('%', '')
            try:
                yield_percent = float(yield_percent)
                if yield_percent >= 4.0:  # 利回りが4%以上の銘柄をフィルタリング
                    stocks.append({
                        'コード': code,
                        '銘柄名': name,
                        '株価': price,
                        '利回り': yield_percent
                    })
            except ValueError:
                continue  # 利回りが数値でない場合はスキップ

    # 結果を表示
    for stock in stocks:
        print(f"コード: {stock['コード']}, 銘柄名: {stock['銘柄名']}, 株価: {stock['株価']}, 利回り: {stock['利回り']}%")
```
最後に、urlを指定してメソッドを呼び出します。
テーブルのページングを考慮してURLクエリのページ番号をループしています。
余裕をもって20と実装していますが、「レスポンスが404になるまでループする」というような実装だともっと無駄がないと思います。
```python
# かぶたんの年初来安値一覧ページのURLを指定
page_number = 0
for i in range (20):
    page_number = page_number + 1
    url = 'https://kabutan.jp/warning/?mode=3_4&market=0&capitalization=-1&stc=&stm=0&page=' + str(page_number)
    main(url)
```

実行結果
```text
コード: 2107, 銘柄名: 東洋糖, 株価: 1699, 利回り: 4.12%
コード: 2499, 銘柄名: 日本和装, 株価: 320, 利回り: 4.06%
コード: 2993, 銘柄名: 長栄, 株価: 2075, 利回り: 4.34%
コード: 3245, 銘柄名: ディアライフ, 株価: 862, 利回り: 5.34%
コード: 3475, 銘柄名: グッドコムＡ, 株価: 646, 利回り: 5.57%
コード: 4516, 銘柄名: 日本新薬, 株価: 2874.0, 利回り: 4.31%
コード: 6089, 銘柄名: ウィルＧ, 株価: 951, 利回り: 4.63%
コード: 6369, 銘柄名: トヨカネツ, 株価: 3860, 利回り: 4.22%
コード: 6539, 銘柄名: ＭＳジャパン, 株価: 1013, 利回り: 5.53%
コード: 7059, 銘柄名: コプロＨＤ, 株価: 1454, 利回り: 4.13%
コード: 7278, 銘柄名: エクセディ, 株価: 2588, 利回り: 4.64%
コード: 7791, 銘柄名: ドリムベッド, 株価: 744, 利回り: 4.3%
コード: 7879, 銘柄名: ノダ, 株価: 1091, 利回り: 4.12%
コード: 7944, 銘柄名: ローランド, 株価: 3970, 利回り: 4.28%
コード: 7995, 銘柄名: バルカー, 株価: 3715, 利回り: 4.04%
コード: 8996, 銘柄名: フリーダム, 株価: 773, 利回り: 5.17%
コード: 9268, 銘柄名: オプティマス, 株価: 588, 利回り: 4.08%
コード: 9446, 銘柄名: サカイＨＤ, 株価: 499, 利回り: 4.01%
```
表示できた。

## 最後に
Pythonを書くのはほぼ初めてだったため、ChatGPTの力を借りながらとりあえず完成させました。

改善点等はあるかと思いますが、まずは色々作って学習していきたいです。
【Spring Boot】flyway-database-mongodbでMongoDBに対してマイグレーションを行う

## 概要
Spring Bootでは、[SpringBoot x Flywayで DBマイグレーションを行う](https://tech.excite.co.jp/entry/2023/03/07/122028)の記事にある通り、Flywayでマイグレーションを行う設定ができるのですが、MongoDBに対してマイグレーションを行う際に少しハマったので内容をメモ書きします。

## 前提
* 使用した言語はJavaになります。（Kotlinでもほぼ同様の設定で大丈夫と思いますが）
* 使用した`flyway-database-mongodb`のバージョンは`10.13.0`になります。
* ビルドツールはgradleを使用します。

## 設定内容
設定の概要等は、redgateというツールの[MongoDB](https://documentation.red-gate.com/fd/mongodb-225608320.html)の部分を参考にしました。こちらはSpringBootの設定ではないようですが、ほぼこの内容に沿った形になります。

### 1. gradleの設定
留意点としては、今回使用した`flyway-database-mongodb`で使用している`com.github.kornilova203:mongo-jdbc-driver`のjarを別途ダウンロードする必要がある点です。（今回は1.19のバージョンのjarを使用しています）
事前準備として[こちら](https://github.com/DataGrip/mongo-jdbc-driver/releases)からjarをダウンロードして、`mongo-jdbc-driver-1.19.jar`にリネームの上プロジェクトのどこかに配置します。（今回はlibs配下に配置）

以下がgradleで設定を追加した部分です。

```gradle
repositories {
	mavenCentral()
	maven { url 'https://repo.spring.io/milestone' }
	maven { url 'https://repo.spring.io/snapshot' }
	flatDir {
		dirs 'libs'
	}
}

dependencies {
	implementation group: 'org.springframework.boot', name: 'spring-boot-starter-jdbc', version: '3.2.5'
	implementation 'com.github.kornilova203:mongo-jdbc-driver:1.19'
	implementation 'org.flywaydb:flyway-database-mongodb:10.13.0'
}
```


### 2. application.propertiesの設定
以下が設定を追加した部分です。

```properties
spring.datasource.url=jdbc:mongodb://localhost:27017/sample_db
spring.datasource.driver-class-name=com.dbschema.MongoJdbcDriver
spring.flyway.sqlMigrationSuffixes=.js
spring.flyway.baseline-version=0
spring.flyway.enabled=true
spring.graphql.graphiql.enabled=true
```

### 3. マイグレーション用のjsファイル
マイグレーションで標準のパス、[resources]-[db]-[migration]配下にjsファイルを配置します。
今回は`user_accounts`というドキュメントに対して、indexの設定を行ってます。

```js
db.user_accounts.createIndex( { user_setting_id: 1 }, { unique: true } );
db.user_accounts.createIndex( { email: 1 }, { unique: true } );
```

## その他参考
* [Problem with Spring Boot 3.2.3 and Flyway 10.10.0 for MongoDB 7.0.6](https://github.com/flyway/flyway/issues/3856)
最新のAzure OpenAI情報リンクまとめ：新機能、モデル廃止情報、APIバージョンなど

# 概要
Azure OpenAIではモデルバージョンの廃止や新機能のリリースなど、情報の更新が非常に速いです。また、廃止に関する情報が複数の場所に記載されることもあります。ここでは、関連するリンクをまとめました。以下のリンクを参考にすることで、Azure OpenAIの最新動向を把握できます。英語の情報は日本語より早く更新されるため、英語のリンクを掲載しています。

皆さんが他に参考になる情報をお持ちでしたら、ぜひ共有してください。こちらでも更新いたします。

# Azure OpenAI全体の最新情報
- Azure OpenAI Service の新機能：https://learn.microsoft.com/en-us/azure/ai-services/openai/whats-new
- AI - Azure AI services Blog：https://techcommunity.microsoft.com/category/ai/blog/azure-ai-services-blog
    - 例、GPT-4oの更新：https://techcommunity.microsoft.com/blog/azure-ai-services-blog/announcing-multimodal-innovations-in-generative-ai-with-azure-openai-service-mic/4146804


# モデルおよびモデルバージョン

- 利用可能なモデルとモデルバージョン
  - https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#model-summary-table-and-region-availability

- モデルとモデルバージョン廃止情報
  - 確認方法1：https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/model-retirements#deprecated-models
  - 確認方法2：各モデルに記載されることがあります。
    - 例
        - GPT-4 and GPT-4 Turbo models：https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#gpt-4-and-gpt-4-turbo-models
        - ![截圖 2024-05-28 晚上10.43.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596658/2c08080a-fdd6-69b9-8a3c-516445835e29.png)


  - 確認方法3：Azure OpenAI Studioでデプロイ済みのモデルの「Model deprecation date」を確認可能
    - https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/working-with-models?tabs=powershell#viewing-retirement-dates
    - ![Azure OpenAI Studio.png](https://learn.microsoft.com/en-us/azure/ai-services/openai/media/models/deployments.png#lightbox)



# APIバージョン

- 廃止予定APIバージョンやGA(安定版)のAPIバージョン、新機能と対応するAPIバージョンなどの情報
  - https://learn.microsoft.com/en-us/azure/ai-services/openai/api-version-deprecation
- PreviewのAPIバージョン一覧
  - https://github.com/Azure/azure-rest-api-specs/tree/main/specification/cognitiveservices/data-plane/AzureOpenAI/inference/preview
- GA(安定版)のAPIバージョン一覧
  - https://github.com/Azure/azure-rest-api-specs/tree/main/specification/cognitiveservices/data-plane/AzureOpenAI/inference/stable

# その他: モデルトークン数制限、TPM/RPM制限、料金
- モデルトークン数制限
  - GPT-4 and GPT-4 Turbo models：https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#gpt-4-and-gpt-4-turbo-models
  - GPT-3.5：https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#gpt-35
  - Embeddings：https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#embeddings

- RPM/TPM上限(地域とモデルとモデルバージョンごと)
  - https://learn.microsoft.com/en-us/azure/ai-services/openai/quotas-limits#regional-quota-limits

- 料金
   - https://azure.microsoft.com/en-us/pricing/details/cognitive-services/openai-service/#pricing

- Azure OpenAIのデータ取り扱いについて
  - 機密情報の漏洩を心配されるかもしれませんが、Azure OpenAI では利用者のデータが学習に使用されることはなく、他の顧客や OpenAI に共有されることもありません。詳細は以下の URL でご確認できます。
  - https://learn.microsoft.com/en-us/legal/cognitive-services/openai/data-privacy?tabs=azure-portal

# 結論
Generative AIの世界は非常に動きが早いです。Azure OpenAIも常にOpenAI本家の更新により更新しているので、最新情報を簡単に確認できるようにしておくことが重要だと思います。
WindowsPE起動時に、ファイル読込の進捗状況をプログレスバーで表示する方法

## 結論
bcd の bootmenupolicy の値が Legacy になっていれば良い。
 
## bcd の内容の確認及び変更方法
Windows PE 起動USBメモリがDドライブになっているとき、
1. コマンド プロンプトを管理者として起動する。
2. 次のコマンドを実行する。
   - MBR なら
      ```bat
      bcdedit /store "D:\Boot\BCD"
      ```
   - UEFI なら
      ```bat
      bcdedit /store "D:\EFI\Microsoft\Boot\BCD"
      ```
3. 実行結果をスクロールして、下から４行目の bootmenupolicy の値が Standard、Legacy のどちらになっているか確認する。
4. bootmenupolicy の値が Standard だったら、次のコマンドを実行する。
   - MBR なら
      ```bat
      bcdedit /store "D:\Boot\BCD" /set {default} bootmenupolicy legacy
      ```
   - UEFI なら
      ```bat
      bcdedit /store "D:\EFI\Microsoft\Boot\BCD" /set {default} bootmenupolicy legacy
      ```
5. 「この操作を正しく終了しました。」と表示される。
6.  再度 2. を実行して bootmenupolicy の値が Legacy になっていることを確認する。
7.  Windows PE 起動USBメモリから起動して、ファイル読込の進捗状況がプログレスバーで表示されることを確認する。