OmniAICreator/Qiita-1.07M huggingface dataset:
うまトマを食べに行く！！

## はじめに
友人とうまトマを食べに行きたい！
私たちの中間のうまトマを探しに行く...
## 住所のリストを取得
以下がうまトマ店舗一覧です。

店舗一覧 | 店舗案内｜松屋フーズ
https://pkg.navitime.co.jp/matsuyafoods2/spot/list?c_campain15=1&dc=%7B%27c_campain15%27%3A%271%27%7D

店舗の住所一覧をクリップボードにコピーするため、以下のスクリプトをコンソールで実行しました。

![スクリーンショット 2024-04-04 21.36.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1506140/d29ac934-e1a4-1093-93ae-9cac9ccffa7a.png)

```javascript

// クリップボードにコピーする関数
function copyToClipboard(text) {
  const textarea = document.createElement('textarea');
  textarea.value = text;
  document.body.appendChild(textarea);
  textarea.select();
  document.execCommand('copy');
  document.body.removeChild(textarea);
}

// IDが"w_7_searchresult_1_1-widget-body"の要素を取得
const widgetBody = document.querySelector("#w_7_searchresult_1_1-widget-body");

// 該当する要素のXPath
const xpath = '//*/div/dl/dd[1]';

// XPathを使用して該当する要素のリストを取得
const elements = document.evaluate(xpath, widgetBody, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);

// 該当する要素の数を表示
console.log(`該当する要素の数: ${elements.snapshotLength}`);

// 該当する要素をすべて表示
let str = "";
for (let i = 0; i < elements.snapshotLength; i++) {
  const element = elements.snapshotItem(i);
  console.log(element.innerHTML);
  str += element.innerHTML.trim()
  str += '\n'
}
copyToClipboard(str)
```

## Google Mapにピンを立てる
スプレッドシートを開き、先ほどクリップボードにコピーした住所一覧をペーストする。![スクリーンショット 2024-04-04 21.40.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1506140/94837f06-a491-8ad3-1f3a-885f3c246dfe.png)

mymapを新規作成し、先ほどのスプレッドシートをインポート。

![スクリーンショット 2024-04-04 21.41.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1506140/1455efdb-957e-72ae-e60c-9f40833e13d2.png)
![スクリーンショット 2024-04-04 21.42.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1506140/45e20fa2-685c-cde3-7fad-7c0b6887cec9.png)

完成！！
[独自うまトママップ](https://www.google.com/maps/d/u/0/edit?mid=1ZoG9rLbZ-9dzJlo9cweFmt6ymJn16bI&usp=sharing)

## 最後に
うまトマが楽しみです！！

## 参照

https://forest.watch.impress.co.jp/docs/serial/googlesps/1231663.html
シンボリックリンクとハードリンク【macOS Linux】

# はじめに

https://qiita.com/kohki_takatama/items/14517d8c38054c1e8033

>3. `bash`などの「現在使用されているシェル」への「ハードリンク」「シンボリックリンク」としての`sh`  
    例：（設定されていれば）"`docker compose exec web /bin/sh` = `docker compose exec web bash`" である。

以前書いた記事で、「シンボリックリンク」「ハードリンク」という語句を使ったのですが、その違いを説明できませんでした。

今回、[エンジニアなら知っておきたいmacOS環境のキホン](https://www.amazon.co.jp/%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AA%E3%82%89%E7%9F%A5%E3%81%A3%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84macOS%E7%92%B0%E5%A2%83%E3%81%AE%E3%82%AD%E3%83%9B%E3%83%B3-%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%83%BBDocker%E3%83%BB%E3%82%B5%E3%83%BC%E3%83%90%E3%81%AA%E3%81%A9%E3%82%92%E3%82%A4%E3%83%81%E3%81%8B%E3%82%89%E8%A7%A3%E8%AA%AC-%E5%A4%A7%E6%B4%A5-%E7%9C%9F/dp/4295015032)のおかげでその違いがわかったので、記事にしていきます。


# シンボリックリンクとは

簡単に言えば、Windowsの「ショートカット」
具体的に言うと、「特定のファイルやフォルダまでのパスを保存したもの（ショートカット）です。

# ハードリンクとは

簡単に言えば、「別名」
具体的に言うと「同じデータを指す異なるエントリ（名前）」です。

# シンボリックリンクとハードリンクの違い

まずはポイントからいきましょう。
<font color="LimeGreen">「シンボリックリンクの方が便利でよく使われる」</font>
です。

シンボリックリンクは、ハードリンクと比較し以下のメリットを持ちます。

- リンク先がわかりやすい（`ls -l`コマンドで確認できる）
- ディレクトリへのリンクも作成可能
- 異なるディスクボリューム上のファイルへのリンクが作成できる

一方、ハードリンクは

- 同じディスクボリューム上であれば、もととなるファイルの移動に対応できる
- というか、もととなるファイルと全く同じデータを指すので、例えば「もととなるファイル」を削除しても大丈夫

というメリットを持ちますが、基本的にはあまり使い所がないです。

# シンボリックリンクの便利な使い方

最近の悩み「作業ファイルを開くためのネストが深い」を解決していきましょう。

1. ホームディレクトリで`mkdir tmp`
   作業中のディレクトリ・ファイルへのリンクを保存する場所を作ります。
2. 目的のディレクトリまで移動し、`ln -s "$(pwd)" ~/tmp/sl_name`
   `sl_name`は「シンボリックリンクの名前」という意味です。自分で設定してください。

これで、これからは`~/tmp`を見れば作業が始められます！
使わなくなったり、ディレクトリのパスが変わったら`rm sl_name`するだけです。良いですね！

# おわりに

ちょっと駆け足になりましたので、ご質問あればコメントにお願いします。

次は何を書こうかしら・・・

# 参考

[エンジニアなら知っておきたいmacOS環境のキホン コマンド・Docker・サーバなどをイチから解説 | 大津 真 |本 | 通販 | Amazon](https://www.amazon.co.jp/%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AA%E3%82%89%E7%9F%A5%E3%81%A3%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84macOS%E7%92%B0%E5%A2%83%E3%81%AE%E3%82%AD%E3%83%9B%E3%83%B3-%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%83%BBDocker%E3%83%BB%E3%82%B5%E3%83%BC%E3%83%90%E3%81%AA%E3%81%A9%E3%82%92%E3%82%A4%E3%83%81%E3%81%8B%E3%82%89%E8%A7%A3%E8%AA%AC-%E5%A4%A7%E6%B4%A5-%E7%9C%9F/dp/4295015032)
OAuth、OAuth2、OpenID Connect(OIDC)について簡単にまとめてみた

## 認証・認可はわかりづらい
最近認証・認可について調べることがあり、名前とどんなものかはざっくりと知っている状態でした。
ただ、誰かに説明して、と言われると自信がないのでまとめてみようと思いました。

今回は認証・認可のプロトコルについてです。

この内容について説明されているサイトや記事をいろいろ見たのですが、説明文がながーくて、読んでるだけで眠くなりそうでした・・・笑

ということで簡単に説明したほうがいいなと感じたので、箇条書きで特徴を書いてみました。
説明不足と感じるかもしれないけど、とっかかりとしてはいいのではと思います。

## 共通点

- どれも認証・認可のためのプロトコル
## OAuth

OAuth2との混同防止のため、OAuth1と書いているところもある。

- MAC-SHA1署名方式
- HTTPSは推奨
- 古い形式でOAuth2よりも複雑と言われている

## OAuth2

OAuthの進化系

- トークンベース方式
- HTTPS必須
- 下記の認証フローがある
    - Authorization Code Flow　（認可コード付与）
    - Implicit Flow　（暗黙的な付与）
    - Client Credentials Flow　（クライアントシークレット）

## OpenID Connect (OIDC)
OAuth2の拡張版

- アクセストークンに加えて、IDトークンというトークンの中身に住所、名前などの属性情報が追加できる
- OAuth2よりも高度なセキュリティを提供する
- OAuth2と同様の認証フローを選択できる
- SSOがつかえる*

*こちら厳密にいうと、SSOが使えない場合もあります。
OpenID Connectの標準仕様に沿っているサービスであれば使用することができる。

## さいごに
大雑把にまとめるとOpenID Connectが一番新しくてセキュアなプロトコルで拡張性もあるということです！
認証・認可はトークンのやりとりや暗号化などフローが複雑だったり、専門用語が乱立しているのでわかりづらいのだと思います。

この辺なんとかわかりやすく解説できないかなって考えたんですが、噛み砕いて説明している記事とかも結構あってみてみても私自身わかりづらかったです。

そして自分の中の結論はわかりづらいのは「慣れていないから」

慣れていないからどんな解説をみても理解が難しいのだと思います。
なので、プログラミング同様実際に手を動かして覚えるしかないのだと思いました。

認証・認可系のサービスはいろいろあるので、以下に代表的なサービスをあげておきます。

- Amazon Cognito
- Google Identity Platform
- Auth0
- KeyCloak

上記いずれも無償で使える枠があったと思うので、試してみてください。
[マイグレーション]Mysql2::Error: BLOB, TEXT, GEOMETRY or JSON columnの原因と解決策

# エラー文
テーブル作成のため、モデルとともに作成されたマイグレーションファイルに、型とカラム名を書き、`rails db:migrate`を実行した。

するとターミナルが以下のようなエラーを吐き出した。
```terminal
xxxxxx@yyyyyy testApp % rails db:migrate
== 20240404111608 DeviseCreateUsers: migrating ================================
-- create_table(:users)
rails aborted!
StandardError: An error has occurred, all later migrations canceled: (StandardError)

Mysql2::Error: BLOB, TEXT, GEOMETRY or JSON column 'profile' can't have a default value
/Users/code/Desktop/xxxxx/project_2.0/testApp/db/migrate/20240404111608_devise_create_users.rb:5:in `change'

Caused by:
ActiveRecord::StatementInvalid: Mysql2::Error: BLOB, TEXT, GEOMETRY or JSON column 'profile' can't have a default value (ActiveRecord::StatementInvalid)
/Users/code/Desktop/xxxxx/project_2.0/testApp/db/migrate/20240404111608_devise_create_users.rb:5:in `change'

Caused by:
Mysql2::Error: BLOB, TEXT, GEOMETRY or JSON column 'profile' can't have a default value (Mysql2::Error)
/Users/code/Desktop/xxxxx/project_2.0/testApp/db/migrate/20240404111608_devise_create_users.rb:5:in `change'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
```

# エラー内容と原因
### エラー内容
一文目
```terminal
rails aborted!
StandardError: An error has occurred, all later migrations canceled: (StandardError)
```
これは、Railsのマイグレーション実行中に標準エラー(StandardError)が発生したことを意味しており、それによってマイグレーションが中断され、以降のマイグレーションがキャンセルされた状態を示している。

### 原因
以降を見てみよう。
```terminal
Mysql2::Error: BLOB, TEXT, GEOMETRY or JSON column 'profile' can't have a default value
```
エラーの原因は、MySQLではBLOB, TEXT, GEOMETRY, または JSONタイプ(型)のカラムにデフォルト値を設定することができないが、設定されているということだ。

# 解決策
マイグレーションファイルを見てみよう。
```db/migrate/20240404111608_devise_create_users.rb
# frozen_string_literal: true

class DeviseCreateUsers < ActiveRecord::Migration[7.0]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""
      t.string :name,               null: false, default: ""
      t.text   :profile,            null: false, default: ""
      t.text   :occupation,         null: false, default: ""
      t.text   :position,           null: false, default: ""     

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

# 省略
```

textタイプ(型)に、`null: false, default: ""  `とデフォルト値が設定されていた。

従って、以下のようにtextタイプ(型)から、`null: false, default: ""  `を削除すれば良い。

```db/migrate/20240404111608_devise_create_users.rb
# frozen_string_literal: true

class DeviseCreateUsers < ActiveRecord::Migration[7.0]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""
      t.string :name,               null: false, default: ""
      t.text   :profile
      t.text   :occupation
      t.text   :position

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

# 省略
```
このように、デフォルト値を指定しない記述に変更すれば解決する。

修正後は`rails db:migrate`コマンドでマイグレーションを実行すればクリア。
新卒1年目でデータベーススペシャリストに合格した学習法


こんにちは。2024年4月現在、IT上場企業でエンジニアとして働いている、sirroと申します。
現在の会社には昨年4月に、新卒入社しました。高卒なので、現在19歳です。

今更ですが、昨年の10月に受けたデータベーススペシャリスト試験に合格しましたので、その時の学習法について覚えている範囲で記していきます。

# 学習開始時のスペック
・基本情報技術者試験合格。
・応用情報技術者試験あと2点足りず不合格。
・基本情報、応用情報いずれもデータベースの分野は点数が高かった。(応用情報は自己採点)
・データベースに関する知識は、単純なSQL(SELECT、UPDATE、DELETE、INSERT)が書けて、内部結合、外部結合、主キー、外部キー、各種制約についてある程度分かるレベル。

# 学習期間
学習開始時期は2023年6月ごろ。最初の2ヶ月は1日平均1時間程度の学習をしていたと記憶している。(正直あまり覚えていない)試験前の8、9月は平日1〜2時間、休日平均6時間程度。

# 使った参考書
「徹底攻略 データベーススペシャリスト教科書 令和5年度/瀬戸美月」
https://x.com/DB_sirro_SE/status/1779871059539624183

# 学習法
最初は参考書で基礎を固め、午前II試験の対策。参考書を2周ほどしたら、過去問道場で午前II試験の問題を解いた。
そこで合格点が安定して取れるようになったら、午後試験の対策を開始。
この参考書は量としては少ないが午後試験の解説も行っているので、午後試験の基礎固めもこの参考書を利用。
基礎固めが完了したら、あとはひたすら過去問を解いた。
午後I試験は3問中2問、午後II試験は2問中1問を選ぶ問題形式となっており、午後I試験はDB設計系の問題1問、SQL系1問、性能設計系1問という傾向。元々知識のあるSQL系、点数が取りやすいDB設計系の過去問を重点的に学習。
過去問を解く際は、最初は時間を全く気にせず取り組んでいたが、慣れてからは本番仕様に合わせ、午後I試験は90分(1問45分)、午後II試験は120分という制約の中で取り組んだ。
最終的には、DB設計系の問題では平均約7割、それ以外の分野では平均5〜6割程度取れるようなレベルまで達した。
本番約1ヶ月前くらいから、午前I試験の学習を開始(免除権利がないため)。午前I試験は追加の参考書などは必買わず、基本情報、応用情報の学習で定着している基礎に加えて、過去問道場で応用情報技術者試験の過去問を解くことで対策。

# 試験当日
午前I試験については、解いている際はちょっと焦った。時間配分は破綻していても問題ないが、時間をかければ解けるような問題は少ない。結果的にはかなり余裕だったのだが、本番ヒヤヒヤしたくなければ午前I免除の状態で臨むことをおすすめする。

午前II試験については、かなり余裕というのが、解きながらわかった。参考書が効いた。

午後I試験にて、幸運なことに、DB設計系の問題が2問出題された。迷わずどちらもDB設計系の問題を選択し、時間的にも余裕を持って回答できた。

午後II試験でも、DB設計系の問題を選択。120分という長時間の戦いで、途中30分ほどボーッとしてしまった気がするが、問題自体はそこまで難しくなく、ある程度時間に悩まされることなく回答できた。

# 試験結果
午前I → 81.6点。
午前II → 76点。
午後I → 78点。
午後II → 65点。

午後IIがちょっと危なかったが、それ以外はかなり余裕だったのではないか。IPAの高度試験はまだこれしか受けていないが、一番とりやすいのは間違いなくデータベーススペシャリストだと思う。

# 結論
データベーススペシャリストは新卒でも受かるし、独学でも受かる。

以上となります。Twitter(X)の方でも有益な情報を呟いているつもりですので、フォローお願いします。
↓
https://twitter.com/DB_sirro_SE


# 追記(2024/04/22)
Twitterで予想以上に拡散され、この質で記事を書いているのが恥ずかしくなりました。
「学習法」ではなく単なる合格日記になってしまっているので、改訂版を後ほど公開したいと思います。
それまでTwitter、Qiitaをフォローしてお待ちいただけると幸いです。
ExcelのPower Queryで、SAP API Business Hubにアクセスしてデータを取得する方法

# ExcelのPower Queryで、SAP API Business Hubにアクセスしてデータを取得する方法

## 手順

### Power Queryのエディタを起動

リボンにあるデータの取得ボタンより空のクエリを作成する。ODataのクエリを作るためであるが、Power Queryの標準の方法では認証方法がうまくいかない。M言語を使うため、空のクエリから作成を行う。

>**[操作]**
>Excel → データ → データの取得 → その他のデータソース から → 空のクエリ

上記操作の結果、Power Queryのエディタが起動する。

### APIキーをパラメータに設定

クエリ本体とAPIキーを分離して管理したい。APIキーをパラメータに設定し、クエリからパラメータを介してAPIキーにアクセスする。APIキー用にパラメータを新規に作る。

>**[操作]**
> リボン → パラメータの管理 → 新しいパラメータ → パラメータにAPIキーを設定 → 保存

パラメータ登録画面には、名前と現在の値を入力する。名前は変数名となり、現在の値には実際のAPIキーを入力する。

| 名前       | 現在の値     |
| -------- | -------- |
| `APIKey` | 実際のAPIキー |

### クエリの編集

クエリが空の状態なので、クエリをM言語で作成する。クエリは詳細エディタより編集できる。

>**[操作]**
> ナビゲーションペイン → クエリ1 （右クリック）→ 詳細エディタ → ソースコード（M言語）  → 完了 

#### 編集前
`let`と、`in`が初期状態から存在する。`let`で変数に値を束縛し、`in`で用いる。以下は、変数`ソース`に、空文字列を束縛し、`in`によってクエリの結果を使う（が、空文字列なので結果は見えない）。
```M
let
    ソース = ""
in
    ソース
```

#### 編集後
空文字列の代わりに、`OData.Feed`関数を右辺に置く。3つ引数をとり、順にサービスURI `serviceUri`、ヘッダ`headers`、オプション`options`。オプションは省略可能なので、下記にはない。サービスURIにはSAP Business Accelerator HubのAPIのURLをダブルクオーテーションで囲む。ヘッダにはAPIキーを指定する。

ヘッダは、`[]`で囲む。ヘッダのKeyとValueをイコール `=` で結ぶ。`[]`の中にヘッダのKeyとValueを複数指定できる。複数指定する場合にはカンマ`,` で区切る。`APIKey = APIKey` の左辺はヘッダのKeyで、右辺はヘッダのValueで先ほど登録したパラメータ。

```M
let
    ソース = OData.Feed("https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap/API_OPLACCTGDOCITEMCUBE_SRV/A_OperationalAcctgDocItemCube?%24inlinecount=allpages&%24top=50", [APIKey = APIKey])

in
    ソース
```

>**[note]**
> [リファレンス](https://learn.microsoft.com/en-us/powerquery-m/odata-feed)によると、`OData.Feed`の第3引数となるオプションにとることができるキーとして、`ApiKeyName`がある。指定するとクエリ登録時にWeb API キーを認証情報として登録できる。この方法で登録したAPIキーは、URLに追加される。SAPのAPIではヘッダにAPIキーをセットするので、この`ApiKeyName`は**使わない。**

### 認証設定

認証は、「匿名」を用いる。ヘッダに認証情報を入れているので、他の認証情報は不要。
随時更新予定: BSPのビルド方法を集めてみた

# はじめに
- 各ボードベンダが提供しているBSP (Board Support Packages) のビルド方法をまとめてみました。

# AMD
## QEMU (仮想化環境)
- https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/821854264/Launching+QEMU+Using+Xilinx+Yocto+toolchains
### 関連記事
- [PetaLinux (rel-v2023.2) をビルドしてQEMUで動かしてみた](https://qiita.com/fukunagt/items/859fab0bb151c8456d6d)

# NXP
## i.MX
- https://www.nxp.com/docs/en/user-guide/IMX_YOCTO_PROJECT_USERS_GUIDE.pdf
- https://github.com/nxp-imx/meta-imx

### 関連記事
- [i.MX6UL Evaluation KitをQEMUで動かしてみた](https://qiita.com/fukunagt/items/7cc9575245346212a818)

# Texas Instruments
## AM62Ax
- https://software-dl.ti.com/processor-sdk-linux/esd/AM62X/09_02_01_10/exports/docs/devices/AM62X/linux/Overview/Download_and_Install_the_SDK.html#download-install-the-sdk-installer-inside-a-container
- https://github.com/TexasInstruments/ti-docker-images?tab=readme-ov-file#steps-to-run-yocto-kirkstone-based-builds-inside-a-container
- Proxyサーバがある場合、コンテナにログイン後、環境変数およびgitコマンドにproxyを設定する必要がありました。
  ```sh
  export http_proxy=http://your-proxy-server.com:80
  ```
  ```sh
  export https_proxy=http://your-proxy-server.com:80
  ```
  ```sh
  git config --global http.proxy http://your-proxy-server.com:80
  ```
  ```sh
  git config --global https.proxy http://your-proxy-server.com:80
  ```


<!--
- https://software-dl.ti.com/processor-sdk-linux/esd/AM62AX/09_00_01/exports/docs/linux/Overview_Building_the_SDK.html
-->
ターミナルで実行した履歴を確認する方法

ターミナルで実行した履歴を確認する方法は

$ history

を実行する。

```
$ history

・
・
・
258  rbenv versions
259  rbenv global 3.0.0
260  rbenv global 3.3.0
261  ruby -
262  ruby -v
263  history
```

また、オプションで-〇〇(数字)のように任意の数を指定することで、その数だけ履歴を表示することができる。

```
$ history -20

244  ruby -v
.
.
.
258  rbenv versions
259  rbenv global 3.0.0
260  rbenv global 3.3.0
261  ruby -
262  ruby -v
263  history
```
配列関数

## はじめに

配列に対する操作を担う関数を整理する。

## count

要素の数を取得する

```php:count.php
$data = ['山田', '掛谷', '日尾', '本多', '矢吹'];
print count($data); // 5
```

## array_merge

指定された配列要素を連結する

```php:array_merge.php
$arry1 = [1, 3, 5];
$arry2 = [2, 4, 6];
$result = array_merge($arry1, $arry2);
print_r($result); // [1, 3, 5, 2, 4, 6]

print count($data); // 5
```

## implode

要素を結合した結果文字列を返す

```php:implode.php
$data = ['PHP', 'Perl', 'Ruby', 'Python', 'Javascript'];

print implode(',', $data); // PHP,Perl,Ruby,Python,Javascript
```
## array_push, array_pop, array_shift, array_unshift

array_push：　末尾に追加
array_pop：　末尾から削除
array_unshift：　先端に追加
array_shift：　先端から除去

```php:array.php
$data = ['高江', '青木', '片渕'];

print array_push($data, '山田', '土井'); // 5
print $data; // ['高江', '青木', '片渕', '山田', '土井']

print array_pop($data); // 土井
print $data; // ['高江', '青木', '片渕', '山田']

print array_shift($data); // 高江
print $data; // ['青木', '片渕', '山田']

print array_unshift($data, '掛谷', '横塚', '上垣'); // 6
print $data; // ['掛谷', '横塚', '上垣', '青木', '片渕', '山田']
```
・・・
まだまだあるので追記予定
さくらvpsでssh接続する方法 CentOS

# 初めに
さくらvpsでssh接続をする際にかなり苦戦したので、その方法をまとめました。

# OS
CentOS Stream 9 x86_64

# 1. OSのインストール
![スクリーンショット 2024-04-04 20.13.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682713/83f72ed7-cbae-26fa-765b-457dfb854508.png)

画像にある通り、使いたいOSとバージョン、サーバーの管理パスワードを設定しておきます。

<font color="Red">
ここで設定したパスワードはメモしておいてください。
今後使います。
</font>

# 2. ssh接続をする
次にターミナルを開いてもらって、
```
ssh ユーザー名@サーバーのIPアドレス
```
このコマンドを打つとssh接続ができます。

## ユーザー名
ユーザー名はインストールしたOSによって変わってくるので、確認してください。

![スクリーンショット 2024-04-04 20.28.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682713/d64a30b8-6bfe-4fb2-ad78-6a40fa6e6bb3.png)

ちなみにCentOS Stream 9の管理ユーザー名はcentosなので今回はこちらを使います。

<font color="Red">
この管理ユーザー名を間違えるとssh接続がうまくできないので注意してください。
僕はここで間違えて沼にハマりました。
</font>

## サーバーのIPアドレス
サーバーのIPアドレスは
![スクリーンショット 2024-04-04 20.33.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682713/ede4ce67-f91c-5985-8fdc-8597b1a3eeaf.png)

サーバーの基本情報からIPv4の部分をコピー&ペーストしてください。

# 3.パスワード入力
```
ssh ユーザー名@サーバーのIPアドレス
```
のコマンドを叩くとパスワードの入力を求められるので、OSのインストール時に設定したパスワードを入力してください。
これでssh接続は完了です。
お疲れ様でした。

# 終わりに
さくらvpsのssh接続で困っている方の助けになれば幸いです!

# 参考文献
https://vps-one.site/ssh-sakura-vps/

VPS ONEさんのさくらのvpsでssh接続する方法を紹介します。

この記事はとても参考になりました。
ありがとうございました。
WordCloudで日本語文字が豆腐になる問題を解決する

# TL;DR

WordCloudで日本語が豆腐になる場合には　`WordCloud(font_path="/path/to/my-font.ttf")` というように `font_path` を指定する。

# 問題

WordCloudを使用して日本語の単語をプロットしようとすると、豆腐（文字化け状態）になることがある。作り込んだ環境では特に意識せずとも正しく表示されるかもしれないが、Google Colab利用する場合など新たに立ち上げた環境においてはよく発生するトラブルである。

たとえばColab上でこのコードを実行すると、日本語の文字は豆腐になる。

```python:
from wordcloud import WordCloud

wordcloud = WordCloud().generate(" ".join(["hoge", "fuga", "piyo", "ほげ", "ふが", "ぴよ"])
```

![wc_bad.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127680/f94c788e-4ec7-d8d7-6668-2e3556342b94.png)

こういう場合のよくあるプラクティスは `japanize_matplotlib` を使うことや `plt.rcParams['font.family']` を設定することだが、これではタイトルや軸ラベルは日本語になってもWordCloudでプロットされる単語は豆腐になってしまう。

# ならどうするか？

`WordCloud`　オブジェクトを作成する際 `font_path` 引数に使用するフォントファイルのパスを与えてやればいい。

具体的にはこうする。

```python
from wordcloud import WordCloud

wordcloud = WordCloud(
    font_path="NotoSansJP-Regular.ttf"
).generate(" ".join(["hoge", "fuga", "piyo", "ほげ", "ふが", "ぴよ"])
```

![wc_good.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127680/75a058eb-bf60-5dd2-70bb-d6727f7e31f3.png)

この例だとカレントディレクトリに直接フォントファイルを置いてしまっているが、環境によって適切なフォントファイルの置き場があるので、適宜パスは書き換えると良い。

ちなみにサンプルで利用したNoto Sans JPは[ここ](https://fonts.google.com/noto/specimen/Noto+Sans+JP)からダウンロードできる。

ふりかえってみると単純な話だけど、原因がどこにあるのかを特定するまでが結構大変な問題だった。フォント周りの設定なのか、パッケージの問題なのか、色々と試して時間を使ってしまった。またいつか突発的にWordCloudを使って困ることがあると思うので備忘録代わりに残しておく。

---

本記事は https://tech-blog.yayoi-kk.co.jp/entry/2024/04/09/110000 と同じ内容です。
アクセス解析を目的としてマルチポストしています。
Rubyのバージョンをアップグレードする方法

# はじめに
Rubyのバージョンをアップグレードする方法を記述します。
使用しているOSはMacOSです。
今回はHomebrewのインストールから、rbebvをインストール、それを用いてRubyのバージョンをアップグレードします。

# Homebrewをインストール
```
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
```
わたくしの場合はここで２つのコマンドを実行しろと言われたので実行しました。

```
＄　echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/◯◯◯/.zprofile
＄　eval "$(/opt/homebrew/bin/brew shellenv)"
```

brew -v で確認してみると、
```
$ brew -v
Homebrew 4.2.16
```
インストール完了。

お次はrbenvをインストール。

```
$ brew install rbenv ruby-build
```
rbenv -v で確認。

```
$ rbenv -v
rbenv 1.2.0
```

完了。

rbenvを使いRubyをインストールしたいところですが、実行環境を確認し、rbenvの設定を終わらせます。

```
$ echo $SHELL
```

実行結果が

/bin/bashの場合こちらのコマンドを打ち込む。

```
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile
```

または実行結果が

/bin/zshの場合こちらのコマンドを打ち込む。

```
$ echo 'eval "$(rbenv init -)"' >>  ~/.zshrc
$ source ~/.zshrc
```

いよいよ待ちに待ったRubyのインストール。
以下のコマンドを入力することで、インストールできるリストを確認する。

```
$ rbenv install --list
```
その中から任意のバージョンを選び、インストール。

```
$ rbenv install 3.3.0
```

インストールが成功したら、以下コマンドで環境内にあるRubyのバージョンを確認。

```
$ rbenv versions
```

先ほどインストールしたバージョンがあれば、以下のコマンドで使用するバージョンを指定します。

```
$ rbenv global 3.3.0
```

最後にRubyのバージョンを確認して、適用されていれば完了。

```
$ ruby -v
ruby 3.3.0
```


zshを用いてるので、実際は"$"ではなく"%"なのは触れないでください笑
【Go】swap関数の作成を通してポインタについて学ぶ

## 問題

2つの数字を入れ替えるswap関数を実装します。
swap関数の引数として、2つの数字のメモリアドレスが渡されるものとします。

```go
package main
import "fmt"
func main() {
    num1, num2 := 1, 2
    swap(&num1, &num2)
    fmt.Println(num1, num2) // 2, 1
}
```

:::note info
本記事ではポインタそのものに関する解説はしません。
ポインタに関しては以下の記事が参考になります。
:::

https://qiita.com/gold-kou/items/0d1585fb8d687061c890

## 誤答

私が最初に考えた答えは以下の通りです。何が誤りなのか考えてみてください。

```go
func swap(a, b *int) (a2, b2 *int) {
    a2, b2 = b, a
    return
}
```

### 誤っている点

#### 1.  返り値がある

`swap(&num1, &num2)`のように呼び出しており返り値を受け取る形式ではないのに、返り値として`x2`, `y2`を返してしまっています。

#### 2.  ポインタを使用していない

swap関数の引数として与えられた`a`, `b`に格納されているのは、**メモリアドレス（値が格納されている場所）のコピー**にすぎません。

なので`a2, b2 = b, a`としても、`a2`,  `b2`に`b`, `a`の値を代入しているだけで、元の値が変更されるわけではありません。

**元の値を変更するにはポインタを使用する必要があります。**

簡単な例を挙げます。

```go
package main

import "fmt"

func modify(ptr *int) {
    // *ptrはポインタなので変更される
    *ptr = 100
    // ptrはコピーされた値なので、メモリアドレスは変更されない
    ptr = nil
}

func main() {
    x := 10
    ptr := &x

    fmt.Printf("ptr:%v, *ptr:%v\n", ptr, *ptr) // ptr:0xc0010e010, *ptr:10
    modify(ptr)
    fmt.Printf("ptr:%v, *ptr:%v\n", ptr, *ptr) // ptr:0xc0010e010, *ptr:100
}
```

## 正答

以上を踏まえて、正しい答えは以下の通りです。
`*a, *b = *b, *a`とすることで、**コピーされたメモリアドレスではなく、ポインタが指す実際の値を変更**できます。

```go
func swap(a, b *int) {
	*a, *b = *b, *a
	return
}
```
VirtualBoxのLinux Mintの解像度が変更できない

## はじめに
[前回の記事](https://qiita.com/cnysntry/items/4ad31049b4b5a5310e20)でVirtualBoxにLinux MintをゲストOSとしてインストールしてみたものの、解像度が800x600固定となっており、とても見づらいです。
以下の方法によりこの問題を解決できるようです。

## 解像度変更手順
Linux Mintをインストール後、起動してみると、なぜかデフォルトで仮想スクリーン1の解像度が800x600になっています。
![linuxmint_screensize.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3750854/d38abf78-e7e0-535d-3cf6-0686ae0f0adb.png)
この図のように800x600がデフォルトで選択されており、他の解像度は無効化されて選択できないようになっています。

VirtualBoxのデバイスメニューから[Guest Additions CDイメージの挿入...]を選択してGuest Additionsツールをインストールします。
![guestadditions.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3750854/11cb2226-e7aa-b92a-e26c-2705df4d1a50.png)

これによりLinux Mintの解像度を変更することができるようになります。解像度を変更する場合は表示メニューの[仮想スクリーン1]を選択し、表示された解像度から好みの解像度に変更することができます。
![linuxmint_screensize2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3750854/f5f48113-2823-5855-b61d-7978be968c9c.png)
EC2(MySQL)からAurora(MySQL)への移行作業

# はじめに
EC2で運用していたMySQLをAuroraへ移行するための作業を行いました。
EC2は、Web,アプリケーションサーバーです。
作業中にさまざまな事象が発生したので、移行を検討されてる方は、ご参考にしていただければ幸いです。

![4cc00b45-80b3-477d-877c-2b3e3a441358.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263017/b2963c8b-50e6-a08f-31c2-817b52586735.png)

# 1. バックアップ
移行作業前に、EBSバックアップの取得を忘れないようにしてください。

# 2. メンテナンスモード
EC2の停止はできないため、メンテナンスモードなどの実施を行い、アプリの利用ができないようにした方が良いです。

# 3. DMSの構築
移行作業を行うために、DMSインスタンスの作成を行います。

1. サブネットグループの作成
1. レプリケーションインスタンスの作成
1. ソースエンドポイントの作成 → 作成後にエンドポイントの機能の一部である接続テストを実施
1. ターゲットエンドポイントの作成 → 作成後にエンドポイントの機能の一部である接続テストを実施

**※注意**
ターゲットエンドポイントの設定項目より、「Initstmt=SET FOREIGN_KEY_CHECKS=0」の設定をお勧めします。
これは、外部キーの影響で、転送に失敗する可能性があるためです。

# 4. LOB型のカラムをNULL許容に変更
LOB型のカラムが、NOT NULLの場合、DMSを利用した移行ができない仕様となってます。
データソース元(EC2のMySQL)のLOB型のカラムをNULLに許容するための形式に変換します。

# 5. 空テーブルの作成
DMSにより自動的にターゲット先へテーブルは作成されますが、さまざまなエラーが発生してしまい、解決できませんでした。
移行作業の前に、ターゲット先のテーブルへ空のテーブルを作成することにしました。
この際に、DEFINERが理由で空テーブルが作成できない事象が発生したため、DEFINERを削除しました。

実行例
```sh
# 空テーブル構築ようのsqlファイルを作成
mysqldump --defaults-group-suffix=_ec2 --no-data --databases db01 --set-gtid-purged=OFF > table01.sql

# DEFINERを削除
sed -i.bak -e 's/\/\*!50013 DEFINER=`db01`@`localhost` SQL SECURITY INVOKER \*\/[ ]*//g' -e 's/\/\*!50017 DEFINER=`user01`@`localhost`\*\/[ ]*//g' table01.sql

# テーブル作成
mysql --defaults-group-suffix=_aurora < table01.sql
```

# 6. MySQLユーザーの作成
データソース元のユーザーと同じ名前,権限で、Auroraへユーザーを作成します。

# 7. データベース移行タスク
データベース移行タスクの作成を行った後に、下記の順番で作業します。

**※注意**
MySQLにデフォルトで存在する「information_schema」「performance_schema」「mysql」「sys」データベースは、対象外としてください

## 7.1. データベース移行評価
移行を実施する前に、テストを実施してください。

## 7.2. 再開
移行を開始してください。

## 7.3. 移行結果の確認
データベース移行タスクを実行した結果より、整合性が取れなかったり、エラーが発生するテーブルが存在したため、それらはmysqldupで移行を実施しました。
その際、hash化などしてデータソース元と、ターゲット先のテーブルの値が一致してるかどうかの検証まで行いました。

# 8. LOB型のカラムをNOT NULLに変更
データソース元でNULLを許容したカラムは、Aurora側では、NOT NULLになるよう変更しました。

# 9. DB情報の変更
バックエンドのConfigファイルや環境変数に、AuroraのDB情報に変更して、完了です。

# 10. ログ情報やエビデンスの保管
移行作業完了後は、DMSは削除となります。
そのため、ログや設定項目のエビデンスなど、トラブルシューティングに役立つ可能性があるため、取得しておきました。

# さいごに
検証中は、ひたすらエラーとの戦いで、テーブル数が多いため体力勝負みたいなところもありました。
移行作業はとても工数がかかるタスクでしたが、DB移行のスキルが向上したので、とても良い経験ができました。
Guide for Python

# 1. Initial Setting
https://qiita.com/m20027/items/abd55a925e93907b1c0e

# 2. How to Write

* Nomenclature

https://qiita.com/shiracamus/items/bc3bdfc206b39e0a75b2

* Framework

https://qiita.com/karaage0703/items/e4328dade983e830748a

* Traps

https://qiita.com/python_academia/items/c71fdd6c08c27a3cf2e0

* Writing methods

https://qiita.com/_masa_u/items/b21c493a82e8aba8993f#0%E3%81%A8%E3%81%AE%E6%AF%94%E8%BC%83

* Speeding up

https://qiita.com/m20027/items/17ba706a13df52e906b2


# 3. Handle Data
* Pandas DataFrame $\leftrightarrow$ JSON

https://qiita.com/Yuricst/items/1abd9d643ec10ada1e38

# 4. Test
* unittest

https://docs.python.org/ja/3/library/unittest.html

Under construction
【イベントレポート】mtx2sさん・ログラス飯田さんと考える！コード品質が及ぼすビジネスへの影響

## はじめに

◆この記事は何？
イベント[「mtx2sさん・ログラス飯田さんと考える！コード品質が及ぼすビジネスへの影響」](https://findy.connpass.com/event/313471/)のレポートです。

◆対象は？
コード品質に興味がある方

◆この記事のねらい
コード品質とビジネスがつながることを紹介する


## イベント概要
◆イベント名
「mtx2sさん・ログラス飯田さんと考える！コード品質が及ぼすビジネスへの影響」

◆日程
2024年4月4日(木)

◆場所
オンライン

◆コンセプト
イベントページで次のように紹介されています。
> 本イベントではコード品質がビジネスに与える影響を紐解いた上で、ご登壇者の所属企業では実際どのようなコード品質向上のための取り組みを行っているのか、またそれらを経営陣やビジネスサイドとどうコミュニケーションを取れば良いのかを考えられる場を目指します。


イベントハッシュタグ
[#コード品質_findy](https://twitter.com/search?q=%23%E3%82%B3%E3%83%BC%E3%83%89%E5%93%81%E8%B3%AA_findy&src=typed_query)


## 「ビジネスとエンジニアリングの接合点、そしてコード品質がそこに及ぼす影響（v1.1）」

◆スピーカー
[松本成幸(mtx2s)さん](https://twitter.com/mtx2s) 
LINEヤフー株式会社 エンジニアリングマネージャー

◆資料

https://speakerdeck.com/mtx2s/the-intersections-of-business-and-engineering-and-the-impact-of-code-quality-there-v1-dot-1

◆印象に残ったポイント
質疑応答が印象に残っています。

「コード品質を上げるためにどうするか？」という質問に対して、
「テスト容易性を重視する」という回答でした。

メトリクスは互いに影響しあっています。
テスト容易性を重視することで、相互に良い影響を与えます。
また、テストは、たとえば網羅率などで計測しやすいです。

私は可読性を重視するため、テスト容易性を重視するという考え方は参考になりました。

◆感想

松本さんの言語化力の高さに驚きました。
ロジカルな発表を聞きながら、なんとなく思っていたことが次々と言語化されていきました。

これまでプロダクト中心で、コード品質を考えてきました。
お話を聞いて、ビジネスと繋げるための方法を知ることができました。

コードとビジネスを繋げるときにはこの資料に戻ってくると思います。

## 「ログラスにおけるコード品質でビジネスに貢献する仕組み・カルチャー」

◆スピーカー
[飯田意己さん](https://twitter.com/ysk_118)
株式会社ログラス シニアエンジニアリングマネージャー

◆資料

https://speakerdeck.com/yoshikiiida/a-system-and-culture-that-contributes-to-business-through-code-quality-in-loglass

◆印象に残ったポイント
 「1日リファクタリングすれば、今後の開発速度がX%向上する」という約束はせずに結果を約束する、という考え方は参考になりました。
 
そこに到るプロセスをエンジニアに任せてもらうことで、コード品質を向上する機会を得ることができます。

また、ビジネスサイドの方へのアンケート結果が印象に残りました。

アンケート結果から、ビジネスサイドの方が、コード品質に理解があるとわかりました。
ただ理解しているだけでなく、かなり解像度が高いと感じました。



## おわりに

この記事では、「mtx2sさん・ログラス飯田さんと考える！コード品質が及ぼすビジネスへの影響」についてレポートしました。

コード品質とビジネスがつながるイベントでした。

それでは。
おまえら、RAG 使うときも Fine-Tuning しろよ

# 俺は RAG を使えるぜ！

ちょっと前に LLM 関連のイベントに行ってきました。
イベントブースでは、AI 関連の企業が自社のサービスに関して展示を行っていたのですが、見事に RAG 一色でした。

RAG を利用する際の各社の情報検索の工夫に関しては勉強になりましたが、どれも似たようなシステムばかりで「**あぁ、またか。。。**」という感じがありました。

もちろん、RAG はかなり便利なので、LLM をビジネスで利用する場合は RAG が利用されることが多いと思っています。

普通の ChatGPT を利用するだけでなく、RAG を使ってシステムを作成する理由は単純です。
- ChatGPT をそのまま使っても社内の情報を持っていないから、何かしら情報を入れ込む手法が必要
- 手法はいくつかあるけど、簡単に実装できる RAG さえ使っておけば、ある程度簡単にそれっぽいことができるから

なので、これまでは機械学習に詳しくなくても、ちょちょっと RAG を作って「**俺は RAG を使えるぜ！AI 詳しいんだ！**」という顔ができたのですが、
そんな RAG も Fine-Tuning をしないと周りのシステムと競争できない時代がやってきそうです。

ということで、今回は RAFT という RAG 用のモデルの Fine-Tuning 手法を紹介していきます。

# RAG の問題点 / なぜ Fine-Tuning が必要か？

## 情報検索精度が低い

RAG を使うときは、LLM が持っていない情報を RAG で補足するために利用します。

が、「この LLM が持っていない情報を補足するために使う」というのが非常に重要なポイントで、
- だから RAG を利用する
- けど、LLM が持っていない知識だから情報検索の精度が低い

という問題が出てくるのです。

（実際、私が使った時も同様の問題にハマり、学習が必要だという結論になりました。）

また、RAG に利用するモデルが、そもそも RAG 用のチューニングをしていない可能性も高いです。

# RAFT; Retrieval Augmented Fine Tuning

## RAFT のやり方

以下のようなプロンプトを用意して Fine-Tuning を行います。
```
質問: オベロイ家は、本社がどの都市にあるホテル会社の一員ですか？
コンテキスト: [オベロイ家は、オベロイ・グループを通じてホテル業界に関わっていることで有名なインドの家族です]...[ジャカルタの市中心部、メガ・クニンガン近く、姉妹ホテルであるJWマリオット・ホテルに隣接して位置しています。これはリッツ・カールトン・ホテル・カンパニーによって運営されています。この複合施設には、それぞれホテルとアイランガ・アパートメントを含む2つのタワーがあります]...[オベロイ・グループは、本社がデリーにあるホテル会社です。]
指示: 上記の質問、コンテキスト、および回答を元に、その回答のための論理的な推論を提供してください。フォーマットは ##理由: {理由} ##回答: {回答} を使用してください。

チェーンオブソート（CoT）回答: ##理由: 文書 ##begin_quote## オベロイ家は、オベロイ・グループを通じてホテル業界に関わっていることで有名なインドの家族です。##end_quote## はオベロイ家がオベロイ・グループに関与していることを示しており、文書 ##begin_quote## オベロイ・グループは、本社がデリーにあるホテル会社です。##end_quote## はオベロイ・グループの本社がデリーにあることを示しています。したがって、オベロイ家は本社がデリーにあるホテル会社の一員です。##回答: デリー
```

ポイントは
- 不必要な引用も入れる
    - プロンプトのコンテキストに、回答に関連しない情報を含む文書を使うことでモデルが不要な情報を無視する能力を訓練する
- Chain-of-Thought (CoT) スタイルの回答
    - 回答のプロセスをステップバイステップで説明しつつ、オラクルドキュメントからの直接の引用を含めることで、モデルが関連する情報をどのように抽出して回答に利用するかを理解し、推論能力が向上する
    - CoT を入れた方がいれないよりも性能が上がるという結果がある

## RAFT のメリット
- ドメイン固有知識の学習と利用の向上
    - RAG 実装時に検索対象となる文書で SFT すると、オープンなモデルをそのまま使うよりも、想定されるドメイン固有の知識が深まり、その知識を利用して質問に回答する能力を向上する
- 不必要な文書の無視
    - 手法のようなプロンプトで学習すると、質問に必要ない文書を無視し、必要な部分だけで回答を作ってくれるようになる。また、これによって不正確な検索結果に対するロバスト性も向上する
- チェーンオブソートによる推論能力の強化
    - CoT スタイルの応答により、モデルの推論能力が向上する


## RAFT の結果
RAFT によって以下のような性能向上が見られたようです。
LLaMA2-7B で GPT-3.5 に勝てるというのは素直にすごいですね。

```plantuml
@startuml
<style>
root {
  Padding 0
  Margin 0
}
footer {
  FontColor black
  FontSize 17
}
</style>
footer  RAFT のスコア\n(出典：RAFT: Adapting Language Model to Domain Specific RAG)
title <img:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758571/ac599ac7-d7da-3875-d676-aba9490f1fee.png>
@enduml
```


# まとめ

以上です。
データを作るところが結構しんどそうですが、チューニングの価値がありそうです。今度私も試してみたいですね。
UbuntuのEC2にJMeterをインストールし、CLI上で負荷試験を実行するまで

## この記事について

- JMeterを利用する機会があったので、必要最低限の実施事項を記載します
- EC2の立ち上げや、シナリオの作成については省略します

## 利用するAMI

- Ubuntu 22.04を利用します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411902/c88c1eab-b284-34ea-a843-a8aec679cca8.png)

## 起動後

### JDKのインストール

```bash
cd /home/ubuntu
# install JDK
wget -O - https://apt.corretto.aws/corretto.key | sudo gpg --dearmor -o /usr/share/keyrings/corretto-keyring.gpg && \
echo "deb [signed-by=/usr/share/keyrings/corretto-keyring.gpg] https://apt.corretto.aws stable main" | sudo tee /etc/apt/sources.list.d/corretto.list
sudo apt-get update; sudo apt-get install -y java-17-amazon-corretto-jdk
```

参考：[Amazon Corretto 17 Installation Instructions for Debian-Based, RPM-Based and Alpine Linux Distributions](https://docs.aws.amazon.com/ja_jp/corretto/latest/corretto-17-ug/generic-linux-install.html)  

### JMeterのインストール

```bash
# install JMeter
wget https://downloads.apache.org//jmeter/binaries/apache-jmeter-5.6.tgz
tar -xvzf apache-jmeter-5.6.tgz
```

参考：[Download Apache JMeter](https://jmeter.apache.org/download_jmeter.cgi)

## 任意の実施事項

### ヒープメモリの設定

- `Uncaught Exception java.lang.OutOfMemoryError`となる事があるので、場合によっては調整が必要
- jmeterインストールディレクトリ（今回だと`/home/ubuntu/apache-jmeter-5.6/bin`）内の`jmeter`ファイルの以下を編集
  
```bash
# system's memory availability:
: "${HEAP:="-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m"}"
```

:::note info
Windowsの場合は`jmeter.bat`、Linuxの場合は`jmeter`ファイルの修正が必要です。
:::

参考：[1.4 Running JMeter](https://jmeter.apache.org/usermanual/get-started.html#running)

※実際にJMeter起動中に`top`コマンドを叩くと、`VIRT`が増えている事が確認できます

### テスト用ディレクトリの作成

- GUIで作成した`test.jmx`ファイルと、ログファイル用にディレクトリを作成
- スレッド数など、適宜`test.jmx`ファイル内の記載は調整

```bash
cd /home/ubuntu
mkdir load-test
```

## 負荷試験を実行

```bash
cd /home/ubuntu/apache-jmeter-5.6/bin
./jmeter -n -t /home/ubuntu/load-test/test.jmx -l /home/ubuntu/load-test/test-log.jtl
```

### CLIモードのオプション

- `-n`
  - JMeterがcliモードで実行されることを指定
- `-t`
  - 実行ファイル名を指定
- `-l`
  - サンプル結果を記録するファイルを指定

参考：[1.4.4 CLI Mode (Command Line mode was called NON GUI mode)](https://jmeter.apache.org/usermanual/get-started.html#non_gui)
Pythonで「日付や時刻の値への加算・減算と値の比較」の動作を確認してみた

# 概要

Pythonで「日付や時刻の値への加算・減算と値の比較」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/python/date/index8.html

# 実装

以下のファイルを作成しました。
```sample.py
import datetime
d1 = datetime.date(1999, 12, 1)
print(d1)
print(d1 + datetime.timedelta(days=31))
print(d1 + datetime.timedelta(days=-2))

import datetime
d1 = datetime.date(2020, 7, 21)
d2 = datetime.date(2020, 5, 12)
print(d1)
print(d2)
td = d1 - d2
print(td)
print(td.days)

import datetime
d1 = datetime.date(2020, 7, 21)
d2 = datetime.date(2020, 5, 12)
print(d1)
print(d2)
print(d1 > d2)
t1 = datetime.time(6, 12, 30, 551)
t2 = datetime.time(8, 4, 17, 32814)
print(t1)
print(t2)
print(t1 > t2)
```

以下のコマンドを実行しました。
```
$ python3 sample.py 
1999-12-01
2000-01-01
1999-11-29
2020-07-21
2020-05-12
70 days, 0:00:00
70
2020-07-21
2020-05-12
True
06:12:30.000551
08:04:17.032814
False
```

# まとめ

何かの役に立てばと。
マウスホイールのチャタリングを解消する(分解なし)

## 動機

2~3年使った[Razer Naga x](https://www.razer.com/jp-jp/pc/gaming-mice/naga-line)のマウスホイールが不調だったので  

## 用意するもの

エアダスター(風力の強いものがおすすめ)

## 方法

1. 画像のようにエアダスターの先を当てます<br/><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120432/fd7ab07c-7291-1fb6-0da3-a3460924bdd3.jpeg" width="300">
2. 空気を送り込む
3. マウスホイールを少し動す  
4. マウスホイールが一周するまで2~3を繰り返します
5. 最後に、PCとマウスを接続しチャタリングが起きていないか確認します。  

### 解消しない場合

以下をためしてみてください

1. エアダスターの先をマウスホイールの反対側に当てて、2~4を試してみてください。  
1. マウスホイール付近のパーツの間にエアダスターで空気を送り込みます
    1. いろいろな角度や場所を試してみると良いかもしれません  

### それでも治っていなければ

また別の原因かもしれません  

私は試していませんが、他にできることを下記のブログでまとめられているので  
そちらに飛んで見るものおすすめです。  
マウスホイールの構造なども知ることができる、良いブログだと思います  
https://www.excellencive.jp/blog/periferal-equipment/mouse-trouble-dust

## 経緯

2~3年使った[Razer Naga x](https://www.razer.com/jp-jp/pc/gaming-mice/naga-line)のマウスホイールがチャタリングを起こすようになってしまったので  
なんとか修理できないものかとネットの海をただよっていました  
そこで見つけたのが株式会社エクセレンシブさんの[ブログ](https://www.excellencive.jp/blog/periferal-equipment/mouse-trouble-dust)を発見しました。ありがたい限りです。  
すでに保証期間も過ぎ、自己責任でも分解清掃はハードルが高かったので....
データ加工してからIoT SiteWiseにデータ転送する方法、、

# はじめに
IoT SiteWiseを使ったデータ収集や可視化、閾値通知をしたいんやけど、IoT SiteWiseへデータ転送する前にデータを加工したい時ってありませんか？
ありますよね？
そう。あるんですよ。

でもこの辺の情報ってあまりまとめられているサイトが無いのでちょっとまとめてみます。って感じです。

# なぜエッジでデータ加工をするか
簡単にまとめると以下のようなメリットがあります。（要件次第ですが）
* AWSまでの帯域が細い場合の容量圧縮
* 機密情報等、クラウドに送信したくない情報のマスキング
* クラウドで保管されるデータを少なくすることによる課金額抑制


# エッジでデータ加工してからIoT SiteWiseにデータ転送する方法、、、
エッジにはGreengrassを導入するものとして簡単に比較してみます。
エッジからデータをIoT SiteWiseにデータ転送する方法として、以下3パターンが挙げられます。

|| 使用方法 | メリット |デメリット|
|:-:|:-:|:-:|:-: |
| SiteWise API  |コードにBoto3をインストールして「client.batch_put_asset_property_value」でデータ転送|Greengrass以外からでも転送可能|帯域の制御や切断時の処理等を自分で設定する必要がある|
| Greengrass Stream Manager  |Greengrassのコンポーネントとしてデプロイ|帯域の制御や切断時の処理等が自動で行われる|Greengrassの利用が必須|
| SiteWise Gateway  |Greengrassのコンポーネントとしてデプロイ|簡単にデータを転送可能|データ加工ができない|

※「SiteWise Gateway」でもデータ処理パック（200USD/月）をインストールすればデータ加工は可能かも
　ただエッジで分析や機械学習を行う場合は有用ですが、データ加工のみと考えるとオーバースペックかと

# どの方法が良いのか
データ加工が必要なければ「SiteWise Gateway」が設定も簡単で良いでしょう。
参考：[IoT開発検証 ~センサデータ収集監視と閾値超過通知~](https://qiita.com/bakuchiku/items/62abc7102cec38272a95)

データ加工を行いたい場合「SiteWise API」or「Greengrass Stream Manager」になりますが、特に参考になりそうなブログ等がありませんね、、、
ただエッジでデータ加工してIoT SiteWiseにデータを転送したい場合は「Greengrass Stream Manager」経由で転送する必要がありそうです。
一応AWS公式資料の参考です↓
[AWS IoT SiteWise API を使用したデータの取り込み](https://docs.aws.amazon.com/ja_jp/iot-sitewise/latest/userguide/ingest-api.html)
[StreamManagerClient を使用してストリームを操作する](https://docs.aws.amazon.com/ja_jp/greengrass/v2/developerguide/work-with-streams.html)

# おわり
エッジでデータを加工してからIoT SiteWiseにデータ転送する方法について簡単にまとめてみました。
なんとなく方法はわかるにしても、実装するにはどうすれば良いかの情報が少なかったですね。
次は実際にGreengrass Stream Managerを利用してデータ加工＆転送をする手順についてまとめようと思います。
↓↓こちらでまとめました！！↓↓
[AWS IoT Greengrassによるエッジでのデータ加工＆IoT SiteWiseへの転送](https://qiita.com/bakuchiku/items/84b4928678b3c5882e9e)
gradleでの依存関係の管理でハマったこと

# はじめに

私が保守を担当しているプロダクト（`our-product`）では、依存関係の管理にgradleを利用しています。特徴として、3rdPartyのライブラリだけではなく、社内の別プロダクト（`other-product`）とも依存関係があります。
別プロダクトとの依存関係を定義しつつ、自分たちが利用しているライブラリも正しく管理したいのですが、その際にハマったことがあるのでまとめます。

# ハマったこと

別プロダクトの成果物（other-product-1.0.0.jar）が参照しているライブラリを、build.gradleのdependenciesに定義しなくてもコンパイルが成功してしまったことです。

例えば、`commons-lang:commons-lang:2.6`と`other-product-1.0.0.jar`を参照している場合、dependenciesには下記のように記載する必要があります。

```gradle
dependencies {
  implementation "commons-lang:commons-lang:2.6"
  implementation "jp.co.qiita:other-product:1.0.0"
}
```

しかし、`other-product-1.0.0.jar`が`commons-lang:commons-lang:2.6`を参照していた場合、下記の記述でもコンパイルが成功してしまいます。

```gradle
dependencies {
  implementation "jp.co.qiita:other-product:1.0.0"
}
```

ただ成果物を作りたいだけならこれでもいいのですが、**自分たちのプロダクトで利用しているライブラリは、そうとわかるように管理したい**のでこれだと困ります。

# なぜこの状態でコンパイルが成功してしまうのか

おそらくcompileClassPathに`commons-lang:commons-lang:2.6`が含まれているためだと思います。dependencyを出力すると下記のようになりました。

```
\--- jp.co.qiita:other-product:1.0.0
     \--- commons-lang:commons-lang:2.6
```

`jp.co.qiita:other-product:1.0.0`の推移的な依存関係で追加されているため、ためしに`commons-lang:commons-lang`をexcludeしてみます。

```gradle
dependencies {
  implementation ("jp.co.qiita:other-product:1.0.0") {
    exclude group: "commons-lang", module: "commons-lang"
  }
}
```

予想通りコンパイルは失敗しました。最初にコンパイルが成功してしまったのは推移的な依存関係で`commons-lang:commons-lang`が追加されたからというのは間違いなさそうです。

# この状態で発生するリスク

コンパイルできるならこのままでもいいのではないかと思ってしまいそうですが、そうではありません。下記のようなことが起こってしまいます。

1. 開発者が意識せずに`jp.co.qiita:other-product`が推移的に依存しているライブラリを利用してしまう
1. コンパイル時にエラーとならないため、開発者はそれに気づくことができない
1. `our-product`のbuild.gradleで管理できていないライブラリが利用されている状態となる
1. とあるライブラリで重大な脆弱性等が発生した場合に、`our-product`でそのライブラリを利用しているのかをbuild.gradleから正確に判断できない

`our-product`の依存関係を出力すると、`our-productが直接利用しているもの`と`other-productが推移的に利用しているもの`が出力されます。そのライブラリがどちらにあたるのか、依存関係を出力したらすぐに判断できるようになっていなければなりません。

# 考えられる解決策

build.gradleで直接管理できていないライブラリを意図せず利用してしまう問題の解決策として考えられるものを記載します。

### transitive= falseにしてしまう

推移的な依存関係を解決しないように、`transitive = false`として管理するという方法が考えられます。

```gradle
dependencies {
  implementation "commons-lang:commons-lang:2.6"
  implementation ("jp.co.qiita:other-product:1.0.0") {
    transitive = false
  }
}
```

こうすれば、`jp.co.qiita:other-product`の直接的な依存関係しか解決されないため、この問題は解決しそうです。しかし、この方法にも問題があります。

`our-product`と`other-product`は同じサーバー上で動くことがあります。よって双方が利用している3rdPartyのライブラリは同じバージョンになっていなければなりません。この問題を解決するために、定期的に`our-product`のdependenciesを出力し、バージョンにずれがないかをツールでチェックしています。`transitive = false`で依存関係を定義してしまうと、この仕組みが意味をなさなくなってしまいます。

### transitiveを外から渡せるようにする

下記のように記述し、ビルドするときは`./gradlew -Ptransitive=false jar`のように外側から情報を渡せるようにします。

```gradle
ext {
  TRANSITIVE = findProperty('transitive') ?: "true"
}

dependencies {
  implementation "commons-lang:commons-lang:2.6"
  implementation ("jp.co.qiita:other-product:1.0.0") {
    if ("${TRANSITIVE}" == "false") {
      transitive = false
    }
  }
}
```

利用ライブラリのバージョンチェックを実施するときは`transitive=true`とし、PRのプレマージのチェックでは`transitive=false`でコンパイルが成功するかを確認します。
こうすれば、やりたいことは実現できそうですが、dependenciesの中に条件分岐が入ってなんか嫌だなという感じはします。

# 最後に

おそらく`our-product`は建付けがやや特殊なんだろうなと思います。gradleのオプションでうまくできるといいなと思っていたのですが、私が調べた限りではちょうどよいものはありませんでした。
【Python】指定したデリミタで文章を分割し、リストの要素としてそれぞれ追加する方法


# 概要
句点で区切られている文章を、句点ごとに区切ってリストに変換する方法を紹介します。

複数の文からなる文章を指定したデリミタ（句点など）で分割し、それぞれの部分にデリミタを追加するという処理を行います。

# サンプルコード

例えば、
```
'私はりんごが好きです。また、バナナも良いですよね。皆さんの好きなフルーツ教えてください。'
```
という文章を「。」ごとに区切る関数を作成しました。
「。」だけでなく、「♪」や「！」の場合も同様に以下の関数で可能としています。

```py
def split_paragraph_into_sentences(paragraph, delimiters):
    sentences = [paragraph]

    for delimiter in delimiters:
        sentences = [part + delimiter for sentence in sentences for part in sentence.split(delimiter)[:-1]] + [sentence.split(delimiter)[-1] for sentence in sentences]
        sentences = list(filter(None, sentences))

    return sentences

delimiters = ['♪', '！', '。']
paragraph = '私はりんごが好きです♪また、バナナも良いですよね♪皆さんの好きなフルーツ教えてください♪'
sentences = split_paragraph_into_sentences(paragraph, delimiters)
print(sentences)
# ['私はりんごが好きです♪', 'また、バナナも良いですよね♪', '皆さんの好きなフルーツ教えてください♪']

paragraph2 = '私はりんごが好きです！また、バナナも良いですよね！皆さんの好きなフルーツ教えてください！'
sentences = split_paragraph_into_sentences(paragraph2, delimiters)
print(sentences)
# ['私はりんごが好きです！', 'また、バナナも良いですよね！', '皆さんの好きなフルーツ教えてください！']

paragraph3 = '私はりんごが好きです。また、バナナも良いですよね。皆さんの好きなフルーツ教えてください。'
sentences = split_paragraph_into_sentences(paragraph3, delimiters)
print(sentences)
# ['私はりんごが好きです。', 'また、バナナも良いですよね。', '皆さんの好きなフルーツ教えてください。']
```

ちょっと何しているかわかりづらいコードですね...
以下でも同じように結果が得られます。

```py
def split_by_delimiter(paragraph, delimiters):
    sentences = [paragraph]

    for delimiter in delimiters:
        new_sentences = []
        for sentence in sentences:
            parts = sentence.split(delimiter)
            new_parts = [part + delimiter for part in parts[:-1]] + [parts[-1]]
            new_sentences.extend(new_parts)
        sentences = new_sentences
    if sentences and sentences[-1] == '':
        sentences.pop()

    return sentences
```

## 注意点１
まず、一つ目のコードで言う`sentences = list(filter(None, sentences))`や二つ目のコードの`if sentences and sentences[-1] == '':`など、`''`のものを除去している部分があります。

なぜか、というと、`split()`関数は、指定したデリミタ文字列で文字列を分割します。
今回で言うと、「。」が文字列の末尾にある場合、`split()`関数はその後に空の文字列を追加します。

https://docs.python.org/ja/3/library/stdtypes.html

公式ドキュメントにも記載がありますが、以下の通り、デリミタを基に文字列を分割する際、デリミタの後に何もない場合は空の文字列を追加するのです。

```
>>> '1,2,,3,'.split(',')
['1', '2', '', '3', '']
```

なので、上記サンプルコードでは、空の文字列を除去するコードを入れています。

ただし、二つ目に指定したサンプルコードでは、リストの最後の要素だけをチェックしています。リストの中間に空の文字列がある場合は別のコードを使用する必要があります。

## 注意点2

これは、`split()`関数自体における注意点ですが、デリミタが文字列に存在しない場合、元の文字列を含むリストを返します。

例えば、以下のように文字列に存在しないデリミタ（以下で言えば「`!`」）を選択すると、元の文字列がそのまま返ってきます。


```py
sentence = '私はりんごが好きです。'
new_sentence = sentence.split('!')
print(new_sentence)
# ['私はりんごが好きです。']
```

また、`split()`関数は、常にリストを返す、と言うのも重要な点ですね。
Elixirで言語処理100本ノックやってみた！

こんにちは！
ElixirSchool教育事業部、事業責任者のこーへーです。

私は、30代になってから今までの仕事を捨て去り、「将来稼げるスキルが欲しい」、「もっと自分の市場価値を上げた」と闘志を燃やしながらプログラミングえ選び、奇跡的にElixirに出会いました。

当時を振り返ると、無知だったことが幸いしましたが、もしオブジェクト指向から学んでいたなら挫折していたことでしょう。

Elixirよ私の元に、舞い降りてきてくれて誠にありがとう。

ということで、今からプログラミングを始める人は絶対Elixirをやった方が良いので（日本での案件もどんどん増えてるし、そもそも海外でめっちゃ人気の言語だから今後案件増えないはずない。）こんな脳筋の私でもできたElixirでプログラミングをしている様子をお届けましょう。

[100本ノックの記事はこちら](https://nlp100.github.io/ja/ch01.html)

### 言語処理100本ノックの記事を上から順にやっていく 
#### 01.  「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ

まずは、text変数に文字列「パタトクカシー」を束縛（代入じゃないですよ）
```
iex> text = "パタトクカシーー"
"パタトクカシーー"
```

String.codepoints関数を使って、各文字列を分割
```
iex> text_list = String.codepoints(text)  
["パ", "タ", "ト", "ク", "カ", "シ", "ー", "ー"]
```

Enum.take_every関数を使って、「パ・ト・カ・ー」を抽出
```
iex> text_extraction =　Enum.take_every(text_list, 2)
["パ", "ト", "カ", "ー"]
```

Enum.join関数を使って、それぞれの文字を結合
```
iex> text_extraction =　Enum.join(text_extraction) 
"パトカー"
```

|> (パイプ)で、それぞれの処理をつなげることで、一発でパトカーとすることが出来ました。
```
iex> "パタトクカシーー" |> String.codepoints |> Enum.take_every(2) |> Enum.join                       
"パトカー"
```
コーディングテスト頻出の内部関数 まとめ（その２ - 数値処理関数）[PHP] 


## この記事の目的
未経験エンジニアが転職活動をする際、最初の難関となるのがコーディングテストです。ここを突破しないと面接にすら進めません。
極度のプレッシャーの中、素早く正確に問題を解くためには、**「自分が使っている言語にどのような内部関数があるのか」「どうやって使うのか」など**を事前に把握しておくことが必須と言えます。

そこで、コーディングテスト頻出の内部関数の使い方を、使用例を交えてわかりやすく正確にまとめることにしました。
本記事では、**数値処理のための内部関数**のみを取り上げます。その他の内部関数については、現在に別記事として執筆中です。
（※言語は全てPHPになります）

<br>


##  はじめに
早速ですが、本記事に登場する関数の一覧です。全部で5個の関数を取り上げます。
```
1. min     最小の値を返す
2. max     最大の値を返す
3. round   浮動小数点数を丸める
4. ceil    端数を切り上げる
5. floor   端数を切り捨てる
```

<br>


## 本題
それでは、１つずつ順に解説していきます。
<br>

### 1. min : 最小の値を返す
![スクリーンショット 2024-04-04 17.59.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3486417/52d08681-3e32-333e-7b86-8a5af7f384b5.png)
```php
echo min(2, 3, 1, 6, 7);  // 1
echo min(array(2, 4, 5)); // 2
```

<br>

### 2. max : 最大の値を返す
![スクリーンショット 2024-04-04 18.03.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3486417/f280454d-5f5b-d3a4-a2fd-8b2a335846e8.png)
```php
echo max(2, 3, 1, 6, 7);  // 7
echo max(array(2, 4, 5)); // 5
```

<br>

### 3. round : 浮動小数点数を丸める
![スクリーンショット 2024-04-04 18.15.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3486417/92d82303-d7ae-b212-1cd4-bff4fc634f54.png)

第３引数 `$mode`について　↓
![スクリーンショット 2024-04-04 18.17.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3486417/d640ccf3-8d05-383e-6f7c-aa83ee5d54b9.png)

```php
// 使用例
var_dump(round(3.4));  // float(3)
var_dump(round(3.5));  // float(4)
var_dump(round(3.6));  // float(4)
var_dump(round(3.6, 0));  // float(4)
var_dump(round(5.045, 2));  // float(5.05)  小数点以下第3位が四捨五入されて、小数点以下２桁に丸められる
var_dump(round(5.055, 2));  // float(5.06)
```

::: note warn
**戻り値について**
戻り値は常に浮動小数点数 (float) 型なので注意。
:::

::: note info
**第２引数 `$presicion` について**
`$presicion`に負の数を渡すことで、小数点より前の桁を丸めることができる。例えば、 -1 の場合は一の位を、 -2 の場合は十の位を丸めることができる。
```php
var_dump(round(345, -1));  // float(350)
var_dump(round(345, -2));  // float(300)
var_dump(round(345, -3));  // float(0)
var_dump(round(678, -2));  // float(700)
var_dump(round(678, -3));  // float(1000)
```
:::

<br>

### 4. ceil : 端数を切り上げる
![スクリーンショット 2024-04-04 18.46.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3486417/d90fa257-56a4-d530-df20-a85014d4acc8.png)

```php
// 使用例
echo ceil(4);      // 4
echo ceil(4.3);    // 5
echo ceil(9.999);  // 10
echo ceil(-3.14);  // -3
```
::: note warn
**戻り値について**
戻り値は常に浮動小数点数 (float) 型なので注意。
:::
<br>

### 5. floor : 端数を切り捨てる
![スクリーンショット 2024-04-04 18.52.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3486417/eff69ecf-9c7c-7413-0753-1a9054f7ee99.png)

```php
// 使用例
echo floor(4);   // 4
echo floor(4.3);   // 4
echo floor(9.999); // 9
echo floor(-3.14); // -4
```
::: note warn
**戻り値について**
戻り値は常に浮動小数点数 (float) 型なので注意。
:::
<br>

---

以上になります。
コーディングテストに頻出の内部関数について知っておくことは、スピーディに問題を解くために必要不可欠です。
今回紹介した5個の内部関数をしっかり覚えておきましょう！

別記事にて「文字列処理関数」「配列処理関数」についても解説してますので、そちらも参考にして下さい！

https://qiita.com/Sho-taro/items/07be3180149560ae6e2b

https://qiita.com/Sho-taro/items/5d035df0d57938bf6a98
[Stable Diffusion Web UI] WSL2 + Docker CE環境で動かす備忘録

## 環境
- Windows 11
- WSL2 Ubuntu-22.04
- Docker version 24.0.7

## GPU 周りの設定

1. NVIDIAのwindowsドライバのインストール
   - https://www.nvidia.com/Download/index.aspx
   - 以下のコマンドをWSL上で実行し、以下の様な結果が返ってくればOK
       ```bash:
       $ nvidia-smi
       ```
       ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34731/f4f91f6c-fe86-f524-eb9d-63e869fdc2ec.png)

1. 以下の手順に従って、NVIDIA Container Toolkitをインストール
    - https://learn.microsoft.com/ja-jp/windows/wsl/tutorials/gpu-compute#setting-up-nvidia-cuda-with-docker
        ```bash:
        $ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
        $ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-docker-keyring.gpg
        $ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-docker-keyring.gpg] https://#g' | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
        $ sudo apt-get update
        $ sudo apt-get install -y nvidia-docker2
        ```
    - コマンドプロンプト or PowerShell上でWSLを終了させる
       ```powershell:
       wsl --shutdown
       ```
## Stable Diffusion WebUI Docker のインストール

https://github.com/AbdBarho/stable-diffusion-webui-docker/wiki/Setup

上記のwikiを参考に。

```
$ git clone https://github.com/AbdBarho/stable-diffusion-webui-docker
$ cd stable-diffusion-webui-docker
$ docker compose --profile download up --build
$ docker compose --profile auto up --build
```

ターミナル上に Running on local URL:  http://0.0.0.0:7860 と表示されるので、
windows側のブラウザで http://127.0.0.1:7860 にアクセスをし表示されれば起動確認はOK

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34731/0abbd07a-71e6-524a-420b-7e96a8e00049.png)