OmniAICreator/Qiita-1.07M huggingface dataset:
【おいしいラズベリーパイのせかい。】ラズベリーパイの下準備

# はじめに
この記事では、ラズベリーパイ(Raspberry Pi)のOSインストールから使い始めるまでをまとめました。

# 材料の用意
ラズベリーパイを調理するのに必要なものを用意しましょう。
- Raspberry Pi4 4GB (今回利用するもの。Pi3・Pi5でも可)
- microSDカード (32GB以上を推奨)
- 電源ケーブル (USB Type-Cのスマートフォン用充電器でも可)
- パソコン (Windows・macOS・Linuxなんでも可)

# 「Raspberry Pi Imager」をダウンロードしよう
まず、「[Raspberry Pi Imager](https://www.raspberrypi.com/software/)」をパソコンにダウンロードします。

URLにアクセスして、少しスクロールすると ↓ が出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628341/d12370e0-1aa8-153d-2dbe-8afd155ed199.png)

ここで自分のパソコンにあった「Raspberry Pi Imager」をダウンロードします。

ダウンロードして、起動すると、こんな画面が出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628341/719f9860-0aed-3183-da6f-49c28ee4c349.png)

:::note info
このソフトを使って、OSをインストールします！
:::

# OSをインストールしよう
さっきダウンロードしたソフトを使って、ラズベリーパイのOSをインストールします。
パソコンにmicroSDカードを接続したら、以下のように選択していきます。
- Raspberry Piデバイス
使いたいデバイスを選択しましょう。「No filtering」でもOK (たぶん)
- OS
UbuntuとかRetroPieとかいろいろあります。
ここでは、「Raspberry Pi OS (64bit)」を選択します。
- ストレージ
接続したmicroSDカードを選びます。

全部選択して、「次へ」をクリックすると`Would you like to apply OS customization settings?`とでてきます。

ここで「設定を編集する」を選択すると、↓ が出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628341/5c34086d-cb4f-6918-af3f-5c360da2872b.png)
ホスト名・ユーザー名・パスワード・Wi-Fiが設定できます。

ホスト名は、SSHで接続するときにわかりやすい名前を設定しておきましょう。
ユーザー名・パスワードは、デフォルトのPiから変更することを推奨します。
Wi-Fiはあとからでも設定できますが、ここでやっておくと楽です。

:::note warn
SSHを使う方は、サービスタブから「SSHを有効化する」にチェックを入れておきます。
鍵の設定もここからできる！
:::

:::note indo
設定が終わったら、「保存」！
:::

## OSのインストール開始
いろいろな設定を終えたら、いよいよOSのインストール開始です。
設定の保存をしたら、`Would you like to apply OS customization settings?`にまた戻ります。
OSのインストールを開始するには「はい」をクリックしましょう。
「SDカードのデータがすべて消えるけれどいいの？」を聞かれるので良ければ「はい」を選択。

:::note info
OSのインストールが始まりました！
:::

# ラズベリーパイを起動させよう
OSのインストールが終わると、microSDカードが取り外せるようになります。
取り外したらラズベリーパイのUSBポートの反対側にmicroSDカードを入れます。

セットできたら電源ケーブルを挿します。

:::note info
ラズベリーパイ本体のランプが点灯して、起動しました！
:::

# 下準備の完了
あとは、キーボード・マウス・ディスプレイに繋げたり、SSH接続したりして好きなように調理しましょう！

# おまけ：ラズベリーパイにSSH接続してみる
パソコンからラズベリーパイにSSH接続をしてみます。
SSH接続する前に、パソコンとラズベリーパイが同じネットワークに接続されているか確認します。違ったら接続できません。

- SSH接続するためのターミナルを起動します。
Windowsの場合：「Winロゴ+R」を押し、「cmd」を入力
macOSの場合：Launchpadから「ターミナル」を起動

起動したら、以下のコマンドを実行します。
```shell
ssh user@host
```
`user`部分には、「OSをインストールしよう」で設定した「ユーザー名」を入れます。
`host`部分には、「ホスト名」を入れます。

実行すると、英文が出てきます。怖くないので「yes」を入力しましょう。

```shell
user@host's password:
```
↑ が出てくるので、「[OSをインストールしよう](https://qiita.com/null8r/items/22f79f3558c5371599f5#os%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%97%E3%82%88%E3%81%86)」で設定したパスワードを入力。
文字を打っても画面には表示されませんが、そのまま打ってください。入力後は「Enter」。

![スクリーンショット 2024-08-03 193027.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628341/91f14ed6-b8ba-f60d-8a6b-0f883da10d98.png)

:::note info
画像のように`use@host:~ $`と表示されたら成功です！
:::
【音声抽出＆動画合成】フリーソフトでカンタンに動画を合成

# はじめに
以前に行った動画からの物体検出時に検出後の動画から音声抜けが発覚したため、今回は動画からの音声抽出と抽出した音声＋無音動画を合成するまでの手順をまとめてみました。

# 目標
物体検出したい動画からいかに簡単に音声抽出するか、そして無音になってしまった物体検出済の動画を合成して、元の音声が入った物体検出済の動画を合成します。

# 利用データ
地域の夏祭りの一部を撮影した動画
https://youtu.be/gseDi9joSMY


# 実行環境
パソコン：Windows 11
使用ツール：
（音声の抽出）⇒フリーのオンライン音声変換ツール「Notta」
（動画の合成）⇒Windows ムービーメーカー


# 作業手順
動画に対して物体検出処理を行うと音声がなくなってしまったため、検出をかけた元の動画から音声の抽出と、物体検出を行った動画との合成が必要となりました。
そこで今回は、
元の動画から音声を抽出⇒物体検出した動画と合成
する手順によって、音声が入った完全な物体検出処理済動画を作っていきます。

### 手順(1) 元の動画から音声を抽出
フリーのオンライン音声変換ツール「Notta」を使用し、音声抽出をかけます。

https://www.notta.ai/tools/online-audio-converter

![音声抽出ソフト.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806184/39743260-54bc-ba1c-65dd-4d3bce2705ca.jpeg)

①この画面上で音声を抽出したい動画を選択します。

![音声抽出ソフト-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806184/e95b5cf6-e9d3-14b2-4520-44a1138cfb0f.jpeg)

②動画を選択し、出力したい形式（今回はMP3を選択）を選択してから「変換」をクリックすると、ダウンロード画面が表示されるので、「ダウンロード」を選択します。
すると抽出された音声が自動的に保管されます。

![音声抽出ソフト-3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806184/414c6058-cf77-a35d-971d-ec23f006f127.jpeg)

### 手順(2) 抽出した音声と音声なしの動画(物体検出済)を合成

①ムービーメーカーを起動し、音声を追加したい動画を追加します。

![動画合成ソフト.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806184/d946b397-66ee-326d-690d-44302eb79ef4.jpeg)


②動画ファイルを右側のエリアにドラッグ&ドロップして追加もしくは、画面の左上にある「ビデオ及び写真の追加」をクリックすると、このように画面上に表示されます。

![動画合成ソフト-2(音を追加したい動画を選択).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806184/c4571c5e-d91e-e7fb-2bf7-b30fa5c1da66.jpeg)

③画面の左上にある「音楽の追加」をクリックし、抽出した音声を追加すると、右側の画面の動画の下に黄緑色のエリアが表示されます。

![動画合成ソフト-2(合わせたい音楽を選択).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806184/57236fe2-bce5-809a-137d-44d75d1fd783.jpeg)

④音声を追加したい動画と音声を選択後、どこから動画を合成するのか、画面上で開始時間と動画の停止時間を入力します。
もし全部を合成したい場合はそのままで大丈夫です。

![動画合成ソフト-4(トリミングしたい場所などを編集).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806184/6bed95b7-838b-06f0-dc1d-7965714a2515.jpeg)

⑤編集完了後に、メニューから「ファイル < ムービーの保存」の順にクリックして、保存したい設定を選択し、動画ファイルを保存します。
（今回は、「このプロジェクトの推奨設定」で保存しました。）

![動画合成ソフト-6(編集後の保存方法).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806184/4d460ff1-d225-9e8d-dfbe-a89bed78c15f.jpeg)

これで音声が入った動画の合成が終わりました。

# 最終結果

物体検出処理した動画（無音）と元の動画から抽出した音声を合成した完成動画はこちらです。
興味のある方はご覧ください。

※完成動画
https://youtu.be/7S5I2po4Ri4


# まとめ

今回音声抽出と動画の合成に初めてチャレンジしたのですが、思っていた以上に簡単に出来る事が分かりました。
今後は色々なアレンジをしながら動画を作ってみようと思います。
意外と使うエクセル関数メモ

# はじめに
最近単体試験の仕様書作成やらなんやらでエクセルを触る機会が増え、ショートカットキーなどなど調べていく内に普段使いするようになったものたちをご紹介します。

## ショートカットキー
※Windows版なので、悪しからず。

| 1 | 2 |
|:-:|:-:|
|Ctrl + 1|セルの書式設定|
|F2|セルの編集切替|
|Shift + Ctrl + スクロール|シートを横にスクロール|
|Ctrl + pg up|左のシートに移動|
|Ctrl + pg dn|右のシートに移動|

:::note info
F2とかはファンクションキーと一緒に押さないと機能しないので、fnキー + fn lockでファンクションモードになります。もう一回押せば解除されます。
:::


## 関数
### シート名を取得
#### そのまま全部取得
```
=REPLACE(RIGHT(CELL("filename",A1),LEN(CELL("filename",A1))-FIND("]",CELL("filename",A1)),1,0,"")
```

#### 切り抜いて取得
```
=REPLACE(RIGHT(CELL("filename",Al),LEN(CELL("filename",A1))-FIND("]",CELL("filename",A1))),1,2,"")
```
→2で開始箇所を指定

### ファイル名を取得
#### そのまま全部取得
```
=MID(CELL("filename",A1),FIND("[",CELL(filename"A1)),FIND("[",CELL("filename",A1))-FIND("[",CELL("filename",A1)))
```

#### 切り抜いて取得
```
=MID(CELL("filename",A1),FIND("[",CELL('filename",A1))+9,FIND("]",CELL("filename",A1))-FIND("[",CELL("filename",A1))-14)
```
→+9で開始位置を、-14で文字数を調整

また増えたら追記します。
docker compose build　考察

## はじめに
今更ですが。
いや過去にも調べたはずであろう`docker compose build`
このコマンドは具体的に何をしていたのか改めて調べたのでアウトプットしようと思います

## docker compose build
Docker Composeを使ってアプリケーションのサービスをビルドするためのコマンドになります。このコマンドを実行すると、Dockerfileに基づいてコンテナイメージが生成されます。
より詳しく解説すると、依存関係のインストールや設定が行われています。単にインストールするだけじゃなく、アプリケーションを動かすためのイメージを作成するプロセスです。

#### 1：具体的に何をしているのか
**イメージのビルド**: docker-compose.ymlで定義されたサービスごとに、指定されたDockerfileを参照してコンテナイメージを作成する

#### 2：参照ファイルについて
**docker-compose.yml**: このファイルには、サービス（コンテナ）の設定情報が記載されている。どのイメージを使うのか、どのポートを公開するのか、環境変数などが設定される

#### 簡単な例
```
#docker-compose.yml
version: '3'
services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
```
上記設定では、webサービスがDockerfileを使ってビルドされる。
contextはビルドする際に参照するディレクトリを指定している

## 勘違いしていたこと
- Rails をインストールするのは、docker compose build コマンドの後に行われる作業
- `docker compose build`はあくまでイメージのビルドだけで、具体的なファイル生成は行わない！
- 「イメージのビルド」は「アプリケーションを動かすためのパッケージを作ること」

#### イメージのビルドをもっと簡単に言うと料理！？
例えば、お菓子を作ることを考えてみる。お菓子を作るためには、レシピ（材料や作り方）が必要になります。このレシピが、Dockerでは`Dockerfile`になります。

1：レシピを用意する: お菓子を作るための材料や手順をまとめたレシピを作る。

2：材料を集める: レシピに従って、必要な材料を集める。これが、Dockerfileに記載された内容をもとに、必要なソフトウェアをインストールするプロセスになります。

3：お菓子を作る: 材料を混ぜて焼いて、お菓子が完成する。この完成品が、Dockerの「イメージ」！

まとめ
つまり、「イメージのビルド」は、お菓子を作るためのレシピに従って、必要な材料を集めて、最終的にお菓子（イメージ）を完成させる作業ということになります。これによって、アプリケーションを動かすための環境が整います

## さいごに
学ぶ量が多いと様々な内容が混同してしまう。少しずつ整理していこうと思います
Swift タイプエイリアス（typealias）を徹底解説

## 概要
Swiftのタイプエイリアス（typealias）について理解していますか？　
 この記事では、タイプエイリアスとは何か、その使い方と利点、具体的な利用例について詳しく解説します。

## タイプエイリアスとは？
タイプエイリアス（typealias）は、既存の型に別名を付けることができるSwiftの機能です。これにより、コードの可読性が向上したり、複雑な型の名前を簡略化したりすることができます。

## 基本構文
```swift:Swift
typealias 新しい名前 = 既存の型
```

## 基本例
```swift:Swift
typealias Age = Int

let myAge: Age = 30
```

この例では、AgeはIntの別名として定義されています。これにより、コード内でIntの代わりにAgeを使うことができます。

## タイプエイリアスの利用例
### 1. より意味のある名前を付ける
複雑な型に対して意味のある名前を付けることで、コードの可読性が向上します。

```swift:Swift
typealias CompletionHandler = (Bool, String) -> Void

func performTask(completion: CompletionHandler) {
    // タスクを実行して、完了時にcompletionを呼び出します
}
```
この例では、CompletionHandlerは(Bool, String) -> Void型の別名として定義されています。これにより、関数の引数としてより意味のある名前を使うことができます。

### 2. 複雑な型の簡略化
ジェネリック型やクロージャの型が複雑な場合、それを簡略化するためにタイプエイリアスを使うことができます。

```swift:Swift
typealias StringDictionary = [String: String]

let userInfo: StringDictionary = ["name": "John", "age": "30"]
```
この例では、StringDictionaryは[String: String]の別名として定義されています。これにより、辞書型の定義が簡略化されます。



## タイプエイリアスの利点
***1. 可読性の向上*** - より意味のある名前を使うことで、コードの意図が明確になります。
***2. 保守性の向上*** - 複雑な型の定義を簡略化することで、コードの変更が容易になります。
***3. 再利用性の向上*** - タイプエイリアスを使うことで、同じ型定義を複数の場所で再利用できます。

## 注意点
タイプエイリアスは元の型の完全な別名であり、型そのものを変更するわけではありません。
タイプエイリアスを使う際は、元の型と混同しないように注意する必要があります。

## まとめ
Swiftのタイプエイリアスは、コードの可読性と保守性を向上させるために非常に有用な機能です。適切に活用することで、複雑な型定義を簡略化し、より明確で理解しやすいコードを書くことができます。
まだまだ勉強中のため、誤りがあればご教示ください🙇
Wio Tracker1110をTTNにつなぐとtime syncから先に進まないので書く

# Wio Tracker1110をTTNにつなぐとtime syncから先に進まない
Seeed-StudioのWio Tracker1110 のデフォルトファームウェアは、同社のSenseCAPサーバに接続するためのものです。Wio Tracker1110はTTNにJoinしてすぐにSenseCAPサーバに時刻取得要求のuplink (payload例"17011f00000010")を投げ、該当するdownlinkが受信できるまで繰り返し要求し続け、センサーデータのuplinkを行いません。
```
<console log>
[2024-07-27 00:00:06.536] ----- Reset LR1110 to start Join the network -----
[2024-07-27 00:00:06.536] Request for Join the LoRaWAN network
[2024-07-27 00:00:19.525] ----- JOINED -----
[2024-07-27 00:00:19.525] Send uplink packet to request current time from Cloud.
      :
[2024-07-27 00:03:09.256] ----- Timer for 10s -----
[2024-07-27 00:03:09.256] ReSend uplink packet to request current time from Cloud.
```
```
<TTN Live Data>
      :
00:03:12 アップリンクデータメッセージの転送 err 0 messages[…] payload"17011f00000010" valid true 17011F00000010 FPort 199
```

# time sync無しで状態を進めるようファームウェアを書き換え
今回のシステムは、温度・湿度だけが必要で位置情報は必要ないため、おそらく時刻同期は不要と判断(この点、問題あればご指摘くださると助かります)。時刻同期できるまで待たせているコードを書き換えます。
![ttn_w1110.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6824/8cd2eadb-fe6e-bf69-5c4b-042b996c5b20.png)

https://github.com/fknaopen/Wio_Tracker_1110_Examples/blob/main/examples/LoRaWAN/TheThingsNetwork/W1110_TTN_AirTemp/W1110_TTN_AirTemp.ino

・"wm1110_geolocation.time_sync_flag== true"の処理を外します

これだけだと、時刻取得要求のuplink (payload例"17011f00000010")を投げ続ける処理は止らないので、行儀が悪いですがWM1110_Geolocationライブラリを書き換えて使います。

https://github.com/fknaopen/WM1110_Geolocation/tree/main/src

https://github.com/fknaopen/WM1110_Geolocation/commit/b305882e4afc915b1dcf0b6a33c0582dc3584bde

また、TTNのペイロードフォーマッター>アップリンク>デコーダーを書きましたので共有しておきます。ご参考になれば。

https://github.com/fknaopen/SenseCAP-Decoder/blob/main/WM1110/TTN/WM1110_TTN_NormalizeDecoder.txt

```
<デコード例>
// for Wio Tracker 1110 Dev Board     2024/8/7
//
// test data : 18000000000000000114328000008000800080008000002fffb103c4
//{
//  "0": {
//    "data": {
//      "accelerometer": {
//        "x": 0.47,
//        "y": -0.79,
//        "z": 9.64
//      },
//      "air": {
//        "humidity": 50,
//        "temperature": 27.6
//      }
//    }
//  }
//}
```
---
以上
SystemParametersInfoに指定するパラメータには気を付けよう

使い方に苦戦したので供養として書きます🙏

初投稿なのでご容赦を！

# 記事を書いたきっかけ
Steamのゲームを遊んでいて、マウスの移動速度をゲーム内設定で変更出来ない事に気づきました。
「マウスの移動速度をゲームやる度に変えるのはめんどいな～」と思ったので、バッチファイルか何かでマウスを使わずに移動速度の変更&復元をしようと思い立ちました。

そうなったら、コマンドかあるいはWindowsを使っているのでWin32ApiだよねとなりSystemParametersInfoを見つけました。

そうして公式ドキュメントを見ながらコーディングしていたのですが…なぜかマウスの移動速度が変更出来ない。
結論から言えば使い方を間違えていたのですが、他の人も間違いそうだと思ったので記事にしようと思いました。

# SystemParametersInfoとは？
WindowsOSで提供されているシステム全体のパラメータを取得/設定する関数です。
https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-systemparametersinfoa

冒頭に書いたマウスの移動速度もパラメータに含まれています。

# SystemParametersInfo関数の詳細

```c++
BOOL SystemParametersInfoA(
  [in]      UINT  uiAction, // パラメータの種類
  [in]      UINT  uiParam,  // 「パラメータの依存するパラメータ」らしい。詳細は知りません
  [in, out] PVOID pvParam,  // 取得/設定する為のデータ指定
  [in]      UINT  fWinIni   // ユーザプロファイルの更新/通知をするかどうか
);
```

パラメータを取得したい時は、対応した変数のアドレスをpvParamに渡す訳ですね。
設定をしたい時も同様に…という訳にはいきませんでした。

# マウスの移動速度の取得
```c++
int speed = 0;
BOOL ret = SystemParametersInfo(
    SPI_GETMOUSESPEED,
    0,
    reinterpret_cast<PVOID>(&speed),
    0
);
```

これでspeed変数にマウスの移動速度を取得出来ます。

Windowsのバージョンやハード構成によって変わるのかもしれませんが、筆者の環境のWindows10では以下の値が取得されていました。
設定>デバイス>マウス>カーソル速度

# マウススピードの設定
次はいよいよマウススピードの変更です。
```c++
int speed = 20; // 最大スピードに変えたい！
BOOL ret = SystemParametersInfo(
    SPI_SETMOUSESPEED,
    0,
    reinterpret_cast<PVOID>(&speed),
    SPIF_UPDATEINIFILE | SPIF_SENDCHANGE // システム全体への設定項目の変更と通知を行う
);
```

おや、マウスの移動速度が変わりませんね？
なぜでしょう？

筆者はここから色々と「パラメータの種類が間違っていたのではないか？」とか「他の引数に何か指定する必要があるのではないか？」と試行錯誤をしていましたが、他の人に苦労して欲しくないので正解を記します。

# マウススピードの設定(正解)
正解はこうです。
```c++
int speed = 20; // 最大スピードに変えたい！
BOOL ret = SystemParametersInfo(
    SPI_SETMOUSESPEED,
    0,
    reinterpret_cast<PVOID>(speed),
    SPIF_UPDATEINIFILE | SPIF_SENDCHANGE // システム全体への設定項目の変更と通知を行う
);
```

どこが変わったと思いますか？
第3引数のspeedの渡し方を変えました。
アドレスではなく変数の値そのものを渡しています。

ドキュメントのSETMOUSESPEEDにもしっかりと指定方式が書かれてあるのですが、私は間違いました…
```
現在のマウス速度を設定します。
pvParam パラメーターは、1 (最も遅い) ~ 20 (最速) の整数です。 既定値は 10 です。
この値は通常、マウス のコントロール パネル アプリケーションを使用して設定されます。
```

# なぜ間違えたか？
pvParamの型であるPVOID[^1]にはアドレスを渡すのだという先入観がありました。
しかし、実際はアドレスではなく値を渡すべきでした。
よく見ないままに「取得する時と同じように設定すれば良いんだ！」となったのが敗因です。

## 豆知識
あまり普通は使わない知識だと思うのですが、ポインタ型の変数はポインタのサイズに収まる範囲(64bitOSなら8バイト)ならスカラー型[^2]の値を保持させる事が出来ます。
[^1]: voidポインタ
[^2]: intやdoubleなどの単一の値を表す型

```c++
// 常識的な範囲でのポインタの使い方
int speed = 10;
void* ptr = (void*)&speed; // speedのアドレスを渡す
int value = *(int*)ptr;    // speedのアドレスからintの値を取ってくる
```

```c++
// スカラー型を保持するポインタの使い方
int speed = 10;
void* ptr = (void*)speed; // speedの値(10)を渡す
int value = (int)ptr;    // ptrに格納されたspeedの値(10)
```

アドレスとスカラー型両方をvoid*で受け取れてしまう訳ですね。
もはやポインタというよりか「何でも型」

こういった何でも取り扱えるポインタは、ライブラリで一つのインタフェースで色々な事をしたい時によく使われている印象です。

一言言い訳させてもらうなら、何でも取り扱えるポインタを使うならなるべく間違わないようにドキュメント書いて…！

# 結論
・設定と取得は同じ方法になるはずという先入観を捨てよう
・何でも取り扱えるポインタには注意しよう

南無🙏
HonoでAPIを作成し、Cloudflareにデプロイする。

## はじめに
[前回](https://qiita.com/koji0705/items/f184b09915fb72aca193)の続きです。CloudflareのAPIを作成した記事を見ていると、Honoのフレームワークをよく見かけます。たまに記事で見かけると思ってたので、今回Cloudflareを触るのをきっかけにHonoも実装していこうと思います。

https://qiita.com/koji0705/items/f184b09915fb72aca193

## そもそもHonoって何？？
Cloudflare社の和田裕介さんが開発したWebフレームワークです。Web標準に基づいて構築されているため、あらゆるJavaScript ランタイムで動作するのが特徴です。
(e.g.　Cloudflare Workers、Fastly Compute、Deno、Bun、Vercel、Netlify、AWS Lambda、Lambda@Edge、Node.js など)

https://hono.dev/

:::note info
小話：元々、和田さんはCloudflare社でHonoを作っていたわけではなく、Honoを作っていたらCloudflare社にスカウトされたようです。いいOSSを作成してればBigTech企業から声がかかってきたんですね。おもしろい。
今では、cloudflareのstarter　frameworkにhonoが選べるのがまたいいですね！
:::

https://findy-code.io/engineer-lab/yusukebe

## プロジェクト作成

```
~/develop/cloudflare_api (HEAD)$ npm create cloudflare@latest
Need to install the following packages:
create-cloudflare@2.23.0
Ok to proceed? (y) y


> npx
> create-cloudflare


using create-cloudflare version 2.23.0

╭ Create an application with Cloudflare Step 1 of 3
│ 
├ In which directory do you want to create your application?
│ dir ./young-moon-ae78
│
├ What would you like to start with?
│ category Framework Starter
│
╰ Which development framework do you want to use?
  ○ Analog
  ○ Angular
  ○ Astro
  ○ Docusaurus
  ○ Gatsby
  ● Hono
  ○ Next
  ○ Nuxt
  ○ Qwik
  ○ React
  ○ Remix
  ○ Solid
  ○ Svelte
  ○ Vue
```

:::note info
何回かエンターを押していくとstarterの状態でデプロイまで実施されURLが発行されます。
:::


## プログラム
```ts:src/index.ts
import { Hono } from 'hono'

type Bindings = {
  [key in keyof CloudflareBindings]: CloudflareBindings[key]
}

const app = new Hono<{ Bindings: Bindings }>()

app.get('/', (c) => {
  return c.text('Hello Hono!')
})

export default app
```
→これだけだと発展性がないので、DB接続まで実施したいですね。
MySQLで論理削除とユニーク制約を両立させる

# 背景
論理削除とユニーク制約の両立ができていないと、退会したユーザーが同じメールアドレスで再登録できないですよね。
この問題を解決するために、論理削除されたレコードを除外したユニーク制約の設定方法を紹介します。

# Generated Columnを利用した両立方法
論理削除とユニーク制約を両立させるための解決策として、Generated Columnを利用します。
Generated Columnを用いることで、論理削除されたレコードを除外したユニーク制約を設定することが可能です。


:::note info
### *Generated Columnとは*
*「Generated Column」は、データベース内の他のカラムの値に基づいて動的に計算されるカラムです。生成カラムには以下の2種類があります。*
- ***Virtual** ： 値がデータベースに保存されず、参照時に動的に計算されるカラム。クエリ実行時に必要なタイミングで計算されるため、ストレージを節約することができる。しかし、クエリのたびに計算が発生するため、頻繁に使用される場合はパフォーマンスに影響を与えることがある。*
- ***Stored**： 値がデータベースに保存され、挿入または更新時に計算されるカラム。値が一度計算されて保存されるため、後のクエリでは計算が不要となり、パフォーマンスが向上する。ただし、ストレージの使用量が増える可能性がある。*
:::



論理削除とユニーク制約を両立させたいテーブルにGenerated Columnを追加し、ユニーク制約を適用するカラムとの複合ユニーク制約を設定します、
以下のコードではGenerated Columnで追加したカラム名を`exist`としています。


:::note warn
下記のコードはLaravelのマイグレーションファイルです。
:::
```php:2024_08_02_122550_add_column_exist_to_users_table.php

Schema::table('users', function (Blueprint $table) {
    $table->unsignedTinyInteger('exist')->virtualAs('IF(ISNULL(deleted_at), 1, NULL)')->nullable();
    $table->unique(['email', 'exist']);
});
```
Generated Columnで追加した`exist`カラムは、`deleted_at`がNULL（論理削除されていない場合）なら1を返し、`deleted_at`に値があれば（論理削除されている場合）はNULLを返します。
MySQLの複合ユニーク制約では、**設定しているカラムのいずれかがNULLの場合はユニーク制約のチェックから除外される**という性質があります。
したがって、論理削除されたレコード（`exist`がNULLのレコード）はユニーク制約のチェックから除外されるため、同じ`email`を持つ新しいレコードを挿入することが可能になるわけです。


そのため`email`と`exist`の複合ユニーク制約の設定により、論理削除されたレコードを除外したユニーク制約となります。

## 最後に
MySQLで論理削除を行うテーブルにユニーク制約を設定する際は、くれぐれも両立のし忘れにご注意ください。

## 参考文献
https://gihyo.jp/dev/serial/01/mysql-road-construction-news/0150
Shopify Liquid でカスタムフィールドを追加してコレクションページに表示する備忘録

大まかな手順は以下の通り。

1. `設定` > `カスタムデータ` > `コレクション` > `定義を追加する`
2. Liquidテンプレートの編集



## 1. `設定` > `カスタムデータ` > `コレクション` > `定義を追加する`

タイトル通り。「単一行テキスト」から「Json」まで多様な形式を選択可能。
ただし、Jsonを選択した場合、パースの処理が結構だるかったです。

今回追加したのは`brand_history_and_features`（一行テキスト）と`brand_popular_models`（json）。

## 2. Liquidテンプレートの編集

当該テンプレートを探すのが大変だったので、`tree`コマンドの結果をchatGPTに投げて聞きましたがうまくいかず。`collections.json`をコピペすると当該のテンプレートを教えてくれました。

`collection.metafields.custom.HOGE`と記入するとカスタムフィールドからデータが渡ってくるようです。

```liquid
{% assign brand_history_and_features = collection.metafields.custom.brand_history_and_features %}
{% assign brand_popular_models_raw = collection.metafields.custom.brand_popular_models %}

...

<p>{{ brand_history_and_features }}</p>

...

<div id="brand-popular-models-container"></div>
<script>
    document.addEventListener("DOMContentLoaded", function() {
      try {
        var rawData = '{{ brand_popular_models_raw | replace: "'", "&#39;" | replace: '"' | replace: "\n", "" | replace: "\r", "" }}';
        rawData = rawData.replace(/&quot;/g, '"').replace(/&#39;/g, "'");
        var models = JSON.parse(rawData);
        console.log("Parsed models:", models);

        var collectionTitle = '{{ collection_title | escape }}';

        if (models && models.length > 0) {
          var container = document.createElement('div');
          var htmlContent = '<h2 class="p-brand_popular_models__heading-two">' + collectionTitle + 'の人気モデル紹介</h2>';
          models.forEach(function(model) {
            if (model.title && model.image && model.description) {
              htmlContent += '<section>';
              htmlContent += '<h3>' + model.title + '</h3>';
              htmlContent += '<div>';
              htmlContent += '<img src="' + model.image + '" alt="' + model.title + '">';
              htmlContent += '<p>' + model.description + '</p>';

...

              htmlContent += '</section>';
            }
          });
          container.innerHTML = htmlContent;
          document.getElementById('brand-popular-models-container').appendChild(container);
        } else {
          console.log("No models found or models array is empty.");
        }
      } catch (e) {
        console.error('ブランドの人気モデルのパースに失敗しました。', e);
      }
    });
  </script>
```

## 最後に

Jsonのパースは絶対にもっと良い方法があると思う。
Pythonの破壊的，非破壊的な操作

## 破壊的な操作
破壊的な操作とは，元のオブジェクト自体を変更する操作のことです．元のオブジェクトの内容が変更され，元の状態を保持しません．

#### 例1：append()
``` python
# 破壊的な操作の例
my_list = [1, 2, 3]
my_list.append(4)
print(my_list)  # 出力: [1, 2, 3, 4]
```

appendは，もとのリスト(my_list)自体を壊し，数を追加しています．
my_list.append(4)が行われた時点で，もうmy_listはもとの状態と同じではないのです．


#### 例2 sort()
``` python
# 破壊的な例:sort()メソッド
my_list=[9,3,5,1]

my_list.sort()

print(my_list) # 出力　[1, 3, 5, 9]
```

もとのリストを変更しているので，破壊的な操作です．

## 非破壊的な操作
指定した操作を行っても，もとのオブジェクトの原型はとどめる操作です．

#### 例1：+演算子
``` python
original_list = [1, 2, 3]
new_list = original_list + [4]
print(original_list)  # 出力: [1, 2, 3]
print(new_list)       # 出力: [1, 2, 3, 4]
```


#### 例2：sorted()
``` python
# 非破壊的な例:sorted()メソッド
my_list=[9,3,5,1]

sorted_list=sorted(my_list) 

print(my_list) # 出力[9, 3, 5, 1]
print(sorted_list) # 出力[1, 3, 5, 9]
```

もとのリストは変更（破壊）されていないことが分かります．


### 復習
最後に問題です．
こちらは，破壊的でしょうか，それとも非破壊的でしょうか．

``` python
my_list=[9,3,5,1]

my_list.pop(0)

print(my_list) 
```
ちなみに，pop(0)は，0番目の要素を削除します．



### 答えはこちら↓
<details>
  <summary> 答え　</summary>
  
  破壊的な操作です．
        出力は，
```
[3, 5, 1]
```

となります．
</details>
備忘録　Teams用の便利キーボードを作る　　03

## BLE化
自作キーボードはある程度快適なのですが、USBケーブルが思った以上に邪魔です。
ノートPCで使っているので、会議とかでPC持って移動すると結局電話持って動いているようなものです。
そこで、無線化を検討します。
## ESP32でBLEキーボード
![IMG20240803184202.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2876479/84d90957-f918-7ec4-1e99-df32ab3a9d6c.jpeg)

こちらも同じようなことを考えている人は世界にいるようで、ESP32でBLEキーボードのライブラリがあります。
これやら、ネット上の情報を見ながら見様見真似で作ってみました。

とりあえず、試作しています。
写真はケーブルつながっていますが、ちゃんとBLEキーボードで認識されています。
もう少し時間をかけて使い合点を試してみます。


BleKeyboard.h
https://github.com/T-vK/ESP32-BLE-Keyboard

:::note warn
これが肝になるヘッダなのですが、今これをArduino IDE2.0の最新のもので動作させようとするとコンパイルすらうまくいきません！
BLEでの接続もできません！

古いIDE1.8系で作業すると動きます。
:::

へたくそですけど試作中のソースコードおいておきます。


```
#include <BleKeyboard.h>

BleKeyboard bleKeyboard("BLE_key");  

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");
  bleKeyboard.begin();

  pinMode(16, INPUT_PULLUP);  // GPIO16(pullup)
  pinMode(17, INPUT_PULLUP);  // GPIO17(pullup)
  pinMode(18, INPUT_PULLUP);  // GPIO18(pullup)
  pinMode(19, INPUT_PULLUP);  // GPIO19(pullup) shift
}

void loop() {
  if (bleKeyboard.isConnected()) {  // Check to see if they are connected.

    if (digitalRead(16) == LOW) {   // If GPIO16 change to LOW Ctrl + Shift + S
      Serial.println("CTRL+SHIFT+s");
      bleKeyboard.press(KEY_LEFT_CTRL);
      bleKeyboard.press(KEY_LEFT_SHIFT);
      bleKeyboard.press('s');
      delay(200);
      bleKeyboard.releaseAll();
    }
    if (digitalRead(17) == LOW) {        // If GPIO17 change to LOW
      Serial.println("CTRL+SHIFT+a");
      bleKeyboard.press(KEY_LEFT_CTRL);  // Ctrl + Shift + A
      bleKeyboard.press(KEY_LEFT_SHIFT);
      bleKeyboard.press('a');
      delay(200);
      bleKeyboard.releaseAll();
    }
    if (digitalRead(18) == LOW) {        // If GPIO18 change to LOW Ctrl + Shift + H
      Serial.println("CTRL+SHIFT+h");
      bleKeyboard.press(KEY_LEFT_CTRL);  // Ctrl + Shift + A
      bleKeyboard.press(KEY_LEFT_SHIFT);
      bleKeyboard.press('h');
      delay(200);
      bleKeyboard.releaseAll();
    }

    if (digitalRead(19) == LOW && digitalRead(16) == LOW) {  // If GPIO19 change to LOW KEY_LEFT_GUI
      Serial.println("win+ALT+1");
      bleKeyboard.press(KEY_LEFT_GUI);                       // win KEY
      bleKeyboard.press(KEY_LEFT_ALT);
      bleKeyboard.press(1);
      delay(500);
      bleKeyboard.releaseAll();
    }
    if (digitalRead(19) == LOW && digitalRead(17) == LOW) {  // If GPIO19 change to LOW KEY_LEFT_GUI
      Serial.println("win+ALT+4");
      bleKeyboard.press(KEY_LEFT_CTRL);                      //
      bleKeyboard.press(4);
      delay(500);
      bleKeyboard.releaseAll();
    }
  }
}

```
アライドテレシス X/SHシリーズコマンド早見表

従来（といってそGS924Mなどの昔のモデル）と違って業界標準（というなのIOSコマンド）互換となっている、Allide ware plusのよく使うコマンドをまとめました。
iOS互換といえども、vlan databaseとかwrite memなど古いIOSの互換コマンド体系な部分があります。
（保存は、copyコマンドも通ります）


## 特権モード
```
enable
```

## 設定モード
```
configure terminal
#または
conf t
```

## 設定モードでshowなどのコマンドを実行
```
#doコマンドを頭に付ける
do show run
do copy run start 
```

## 設定保存
```
copy running-config startup-config
#または
write mem
```

## タイムゾーン設定
```
clock timezone  JST plus 9
```

## NTPサーバー指定
```
ntp server pool.nto.org prefer version 4
```

## 装置名称設定
```
hostname xs916-01
```


## ファームウェア更新
予めtftpサーバにファイルを配置しておく
```
configure terminal
do copy tftp://TFTPサーバのIP/XS900-5.5.4-0.1.rel flash:/
boot system flash:/XS900-5.5.4-0.1.rel
```

## Web GUIを有効化する
予めWebGUI用のファイルをtftpサーバに配置する
```
copy tftp://TFTPサーバのIP/awplus-gui_554_32.gui flash:/
```
Webアクセス用設定を行う
```
configure terminal
username admin privilege 15 password XXXXXXXX ↓
no service http
service http
```

## 再起動
```
reload
```

## スタックポート設定
```
configure terminal
interface port1.0.15-1.0.16
stackport
```

## SSH有効化
```
ssh server allow-users manager
service ssh
```

## VLANを作る
```
vlan database
vlan <vid>
vlan <vid> name 名称
vlan <vid> state enable
```

## インターフェースの指定
```
interface port1.0.1
swithchport

#Accessポート
switchport mode access
switchport access vlan <vid>

#Trunkポート
switchport mode trunk
switchport trunk allowed vlan all #全てのVLANを通す
switchport trunk native vlan 1 #アンタグで流すVLAN
```

## IPを付与する
```
interface vlan1
ip address 192.168.1.254/24
```

## 静的LAG 静的LAGは、saインターフェースで指定
```
interface port1.0.9-port1.0.10
static-channel-group 1
exit

interface sa1
switchport
switchport mode trunk #必要に応じて
```

## LACP構成
```
interface port1.0.9-port1.0.10
channel-group 2 mode active
exit

interface po2
switchport
switchport mode trunk ##必要に応じて
```

## 初期化
```
erase factory-default
```
備忘録　Teams用の便利キーボードを作る　　02

## 自作キーボード
![IMG_20240114_213749.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2876479/4058dc9d-e93f-d039-7d74-ba59c9b0fc81.jpeg)
https://shop.yushakobo.jp/products/834?_pos=10&_fid=303be1d12&_ss=c

https://shop.yushakobo.jp/

まず、自作キーボードというものにニーズがあるようで、こういうお店が存在していました。
一番安いものを買い込んで試してみます。

このキーボード設定が簡単です。
ブラウザ上で「Remap」というものでキーマップを書き換えできます。

ここでどういうボタン配置がいいか検討を進めます。

半年運用していましたが。。結局・・・
1番目　電話とる
2番目　(考え中)
3番目　電話切断

4+1番目　Teamsアプリ呼び出し
4+2番目　メールアプリ呼び出し
4+3番目　Teamsの電話ウィンドウ呼び出し

こんな感じになりました。
Chrome拡張機能をChromeウェブストアに公開してみた話（ゼンゼロ用のChrome拡張機能作りました）

7月にリリースされたゼンレスゾーンゼロというゲームがあるんですが、ハマりすぎてChrome拡張機能作りました！
初めてストアへのリリースまで行ったので、その話をしようと思います

# 作ったもの

ZZZ Score Calculator

https://chromewebstore.google.com/detail/zzz-score-calculator/ibbbkbnhocldehlkbemmlgkmdlbckjmn?authuser=0&hl=ja

HoYoLab公式の戦績ツール上でドライバの詳細データとそのスコアを表示するための拡張機能です。


# リリースまでにやったこと

## プロジェクトの作成

### ChatGPTにひな形を作成してもらった

Chrome拡張機能の知見がないので、ひな形をChatGPTに作成してもらいました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/08a4bbd5-d509-b940-a864-341f85bb8d79.png)

必要なファイルを作成してくれました

- プロジェクト
  - manifest.json　⇒　拡張機能の定義
  - popup.html　⇒　拡張機能起動時に表示されるHTML
  - popup.js　　⇒　拡張機能側で実行されるJS
  - content.js　⇒　表示中画面（HoYoLab）側で実行されるJS


### ローカルで確認

Chrome拡張の管理から「パッケージ化されていない拡張機能を読み込む」から取り込んでローカルで確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/a839d6f2-c857-c146-fc85-2b49dc13e0d2.png)


ただ、エラーになったので、ChatGPTにエラーそのまま張り付けて改善してもらうということを何回か繰り返したら動くようになりました

### 作りこみ

細かいところは自分で作りこんで完成させます


## リリースの準備

### デベロッパー登録

ストアへリリースするためにChromeウェブストアデベロッパーダッシュボードへ登録を行います。
初回の登録時に$5（執筆当時で750円くらい）かかります。


### プライバシーポリシー作成

特に外部アクセスやデータの収集はないので、すごいシンプルなポリシーを作成しました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/eb39b380-d4a9-41c5-1006-bdd70032e9c1.png)

これもChatGPTにすごいシンプルなプライバシーポリシー作って！お願いして書いてもらいましたｗ


### 画像の用意

以下の画像が必須だったため、急ぎで用意しました

- ショップアイコン（128px x 128px）
- スクリーンショット（1280x800 または 640x400で1枚～5枚）

### プロジェクトのZIP

プロジェクトをZIPに圧縮してアップロードする必要があります。
自分はGitHubからZIPでダウンロードしてそのままアップロードしました。




## 審査

準備が出来たら審査に出します！
数日かかるかと思ったんですが、数時間で結果が返ってきました。


### 却下された。。。

#### 不要なポリシーが定義されている

manifest.jsonに余計なポリシーが記載されていたため削除しろと言われました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/ec743c6a-b4fa-23e3-1681-7b51d3f41379.png)

### ついに公開！！！

何回かの却下をうけてようやくリリースされました！！🎉

    
その後、何回かアップデートしたんですが、審査は15時～21時くらいに結果が返ってくる印象でしたね🤔


# 最後に

自分が作ったものがGoogle公式のストアで出てくるって良いですねｗ
思ったよりやること少なくて開発終わってから数時間で審査までいけたので、こんなもんで良いんだ😲って感じでした。
せっかくデベロッパー登録したので、今後も新しい拡張機能作っていけたら良いな～と思います
マインドマップから始めるソフトウェアテストの感想

# 始めに

「マインドマップから始めるソフトウェアテスト」と言う本を完走した感想を書いていきます。

ですが最後に読んだのが1ヵ月前なので記憶があいまいで変な内容になってい琴葉お許しください………

[www.amazon.co.jp/dp/4297105063](http://www.amazon.co.jp/dp/4297105063)

# この本って何？

簡単に言うと`ソフトウェアテストを通してマインドマップの使い方を学ぶ本です。`

実はタイトルとは逆の内容になっております。。。。。

# 本書構成

## 第1部

まず前半はソフトウェアテスト活動の概要について解説しています。

いわゆるV字モデルや各種テスト工程の解説をしています。

後半はマインドマップそのものについて解説をしています。

## 第2部

各テスト種類や行程でマインドマップをどう使うかの解説をしています。

またマインドマップだけではなくテスト設計についても簡単な解説をしています。

なかには負荷テストについての解説もありました。

## 第3部

本書で解説したテスト用語について解説しています。

なのでこの部ではマインドマップの解説はしてません。

JSTQBの解説書よりも簡易的にまとまっているので初心者にはやさしいかもしれません。

しかし本格的にソフトウェアを学ぶ場合はJSTQBの解説書よりかなり物足りないです…..

# 最後に

恐らく業界未経験者の人やソフトウェアテストを知っている人がマインドマップを使う本としてはいいと思います。

しかしソフトウェアテストそのものを学ぶという観点点は物足りなさを感じる内容でした。
pod installでエラーが出た(M2 Mac)

macでpod installをするときに長文でエラー吐かれたのですが、調べた感じM2モデルのMacで出るエラーのため対策法をまとめます

## Rubyの最新バージョンをインストールする

やり方は任せますが、今回はrbenvを用いてRubyをダウンロードしました

Rubyのインストールできるバージョンを確認

```sh
rbenv install -l
```

最新バージョンをインストール

```sh
rbenv install <バージョン>
```

バージョン確認

```sh
ruby -v
```

※Rubyのバージョンが古い場合には、参照先を切り替えてください

```sh
vi ~/.bash_profile
export PATH="~/.rbenv/shims:/usr/local/bin:$PATH"
eval "$(rbenv init -)"
source ~/.bash_profile
```

## 必要なモジュールのインストール

cocoapodsをインストールする
どのコマンドでも先頭に「arch -x86_64」をつける必要がある(これが何者なのかはあまりわかってない。。。)

```sh
arch -x86_64 sudo gem install cocoapods
```

ffiをインストールする

```sh
arch -x86_64 sudo gem install ffi
```

pod installする

```sh
arch -x86_64 pod install
```

以上で、Podsフォルダに対象のフォルダが作成されてたら成功です


## 参考

[Rubyのバージョンが切り替わらない時の対処法！](https://qiita.com/opiyo_taku/items/3312a75d5916f6cd32b1)

[Got error while trying pod install ](https://github.com/CocoaPods/CocoaPods/issues/10220)

[macOSで最新バージョンのRubyをインストールする方法](https://qiita.com/gostachan/items/c3c9b88f120d0c2dce96)
テストに対する異なる視点

IT業界が成長するにつれて、さまざまなツールや技術が登場し、ソフトウェアの生態系はさらに動的に変化しています。 産業とビジネスは、それに合わせてより迅速に変化します。 IT組織は成長するにつれて、分裂と統合を繰り返し、さらに複雑になります。 このような変化の中で、ソフトウェアはMSAとともに小さな単位に分離され、変化するチームによって主を失い、snowflake serverのような状態になってしまいます。

[Googleエンジニアはこう言う]では、成長する組織のためにはチームメンバー一人一人が常に離れることができる状態(Always Be Leaving)を維持しなければならないそうです。 [チームトポロジ]では、テック組織は周期的に6ヶ月~12ヶ月以内に人員を変更しなければならないと述べています。 戦術的な方法なので、このように聞くと手が届かないかもしれませんが、戦略的にこれらの行為は結局、「組織構成員の変更がビジネスに影響を及ぼさない状態を維持する」という共通の目標が見えてきます。 組織構成員の何人が問題になったときにビジネスに影響が出るかについての指標であるBus Factorというものも存在します。

ソフトウェアを開発する人材が変更されても、ソフトウェアの生産性に影響がないようにするには何が必要でしょうか？ まず、人材が変更された時に開発者の生産性が低くなる理由を簡単に考えてみると、変更された人員が担当ソフトウェアに対する知識が既存の人材より少ないためです。 それなら、私たちは意識的にこれらを減らすことができるようにしなければなりません。 ソフトウェア開発に必要な知識を単純に羅列してみると、次のようなものがあると思います。

- ソフトウェアが解決しようとしている問題のドメイン
- ソフトウェアを測定できる指標（技術的であれ、ビジネスの成長であれ）
- ソフトウェアを構成している技術的基盤（言語、フレームワーク、データベース、インフラなど）

上記の内容のうち、ドメインに関する知識を除いては「一貫性」を守ることができる項目です。 ビジネス指標の場合は、ソフトウェアごとに重要視するものが異なる場合がありますが、最小限の一貫したガードレール指標は生成して管理することができます。 技術的な指標の場合、ほとんどのソフトウェアが速度と安定性、最近ではDevOps DORAなどの指標を重要視するでしょう。 最後に、ソフトウェアを構成している技術的な基盤は、テックに関連するガバナンス組織によって管理できます。

それでは、各チームが開発しているソフトウェアは、上記の項目の一貫性をどのように維持させることができますか？ まず、開発者は通常、コードレビューを通じて担当ソフトウェアの一貫性を守ろうとします。 しかし、コードレビューはレビューアーの個人的な力量と状況に非常に依存的な行為で、もしビジネス日程が急迫してレビューができなかったり、レビューが慣れていないレビューアーの場合には、コードレビューの品質が落ちたり、コードレビューにあまりにも多くの費用を支払わなければならないかもしれません。

所属メンバーが一貫したレベルのレビュー/フィードバックを着実に受け、ソフトウェアの一貫性を維持するためには、個人の力量に依存しない方法が必要です。 教育を通じて構成員の力量を全て引き上げるならば、ある程度解消されることができますが、本質的な問題解決ではありません。 つまり、自動化されたシステム構築が必要であり、この自動化されたシステムは、ソフトウェアのアーキテクチャ、コード品質、バグ、セキュリティ、スペックなどの一貫性を守り、維持させることができなければなりません。 そして、このようなことをよく"テスト"と呼びます。
Zero-Downtime AWS Cross-Region Migration : Application Cluster

こんにちは。今回のポストでは、AWS Cross-Region Multi VPC環境で、無停止でアプリケーションサービスクラスターをMigrationした事例を共有したいと思います。

### Context
[1] A社は大韓民国でB2Cサービスを提供している会社で、AWSソウルリージョンができる以前からAWS Cloud基盤のインフラを構築し、開発していました。

[2] サービスが大きくなるにつれ、A社もアプリケーションを複数のサービスに分離し始め(MSA)、生まれたAWSソウルリージョンにより、新しいサービスはソウルリージョンでプロビジョニングされていました。

[3] MSAによって分離されたサービス間のInternal通信が生まれ、ソウルリージョンと東京リージョンVPCをVPC Peeringにまとめて使用していました。

[4] A社はドメインをいくつか使っていて、ドメインAは東京リージョンにあるLBにつながり、様々なサービスをL7 Path Routingを通じてサービングしていました。

### Problem
[1] サービスが次第に大きくなり、ソウルと東京リージョンに分かれたサービス間のInternal通信が多くなり、A社のサービスは応答速度低下問題を経験するようになりました。

[2] ドメインAとつながっているLBのサービスが多く、点検または中断環境ですべてのサービスを一度にマイグレーションするのは危険負担が大きく、漸進的なリージョンマイグレーションが必要でした。

### Solution
[1] 東京リージョンにTLSが適用されていない新しいLBをPrivate Subnetにプロビジョニングし、既存のAドメインと同じPath Routingルールを適用します。 そしてNLBとVPC Endpointを利用してこのALBのEndpointを生成します。 最後に、ソウルリージョンにTLSが適用された新しいLBをプロビジョニングし、上記で生成したEndpointにルーティングします。

[2] 既存ドメインAをソウルリージョンのLBをResolveするように変更します。 AWS Route53のWeighted Routingなどの戦略を利用することができます。

[3] ソウルリージョンに既存のサービスを一つずつマイグレーションし、ソウルリージョンLBのPathルールを変更して接続します。 このプロセスを繰り返し、東京リージョン全体のサービスを移行します。

### Visualization

![Screenshot 2024-08-03 at 6.13.08 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3797109/fcfd6e17-5290-c4b6-3b3e-bfd0e50a2ef5.png)
![Screenshot 2024-08-03 at 6.13.15 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3797109/7c10aca8-4f04-e6f4-67be-027eabfb43ab.png)
![Screenshot 2024-08-03 at 6.13.21 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3797109/f022ce42-26f9-37df-07d8-fd335d4ab288.png)
![Screenshot 2024-08-03 at 6.13.31 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3797109/9de7c7f1-9c5e-1799-3dd0-a8c00935d0a0.png)
インターン参加記録(株式会社エイチーム)

# はじめに

2024年の6月15日から7月31日までの1ヶ月半の期間で週2回の就業型インターンに参加しました。同じタイプのインターンに参加している他の方もいるらしいので、ネタバレにならない範囲で体験記を書こうと思います。

# インターン概要

就業型インターンとして、株式会社エイチームライフデザインに入社し、インターンを行いました。
場所は大阪梅田のWeWorkオフィスです。
水曜日と金曜日の週に2回、10:00~19:00の時間で参加しました。
使用言語はTypeScriptで、Reactを使って開発をしました。

# どのようなインターンだったか

インターンは、社内のシステムについての開発でした。
実際のシステムからgitで自分用のブランチを切り、そのブランチに対して開発を行なっていくといった形のインターンでした。
あらかじめ低難易度、中難易度、高難易度の3つの難易度でいくつかのissueが用意されており、メンターさんと相談しながら自分のペースでissueに取り組んでいくことができました。

# インターンに行って良かったこと

このインターンに参加して良かったことについて大きく分けて4つあります。

1つめは、エンジニアとしての基礎技術を得られたことです。
上記の通り、インターンは自分のペースで取り組むものでした。そこで、普段「技術については勉強したけど使いこなせるレベルではないし、あんまり自分のシステムでは使わないなぁ」と後回しになっていた技術にチャレンジできました。チャレンジする際に、メンターさんに相談できるため良い環境でした。

2つめは、gitやGitHubについて詳しくなれたことです。
今回のインターンはgitで開発を管理していました。そのため、基本的な機能だけではなく、さまざまなコマンドを使うようになりました。また、個人で開発する際には意識していなかったことについて知れました。たとえば、Githubでプルリクを出す際にどのような設定をするのか、プルリクに対してレビュアーさんはどのような返事をするのか。レビュアーさんが読みやすいプルリクはどのようなものかなどが知れました。

3つめは、中~大規模なシステムの開発ができたことです。
ライブラリのアップデートなど、普段の自分のシステムでは行わない体験を行うことができました。規模の大きなシステムであるため、ライブラリの数が多く、依存関係によって問題が起きたりもしました。

4つめは、会社の雰囲気について知れたことです。
仕事をする場所は、他の社員がいらっしゃるオフィスでした。そのため、社内の雰囲気を知ることができました。また、お忙しい中、メンターさんに何度か質問をしたのですが嫌な顔ひとつせず教えてくださり、すごくありがたかったです。

# 終わりに

このインターンは日程が早かったですが、大学の研究室や授業の予定なども踏まえて参加できるよう、メンターさんや人事の方にサポートしていただきました。また、git/GitHubなどのエンジニアの基礎技術を身につける上でも参加することに意味のあるインターンでした。参加して良かったです。ありがとうございました。
備忘録　Teams用の便利キーボードを作る　　01

## 序章
会社の電話がすべてTeamsになってはや3年。
しかし、いまだ慣れません。
私もすっかり定年前のおじさんになってしまい「使えないおじさん」だからなのか？
周囲見渡すと、私以外も電話の切断すらできなくて苦労している人がいます。
というわけでなんとか「改善」を考えます。

## 分析
このTEAMS電話。
会話ができるのだけど、何が不自由なのか？
1. 掛かってきた電話を取る、切断という動作が過去の電話機では「定位置にある受話器を取る」、「定位置に受話器を置く」という「目視出来て」、「直感的なワンアクション」ができない。（ガチャ切りできない）
2. PCの画面は狭いし探せない→一覧性の乏しさが辛い。
   資料見ながら会話してると、あの赤い切断ボタンを探す行為がすぱっといかない。
3. そのややこしさからか、電話前に「電話をしてよろしいでしょうか？」というチャットを送るマナーができてしまい、なんだかコミュニケーションを阻害している。
## 解決の方策
1. Teams電話機を用意する
   調べるとAndroidのOSが入った電話機が存在するらしい・・・が個人でほいっと買える値段ではなさそう・・・
2. 一部だけでもなんとか改善する
  ・ ドンキで売ってる受話器→　びっくりするほど使いやすい。でも一発で取れない、切れない。
  ・自作キーボードでショートカット機能を使って一部だけでも実現→取る、切るをなんとかするだけでも、違うかも。

→とりあえず、一番つらい、「電話をとる」「電話を切る」を自作キーボードで対応してみます。
ALB(Application Load Balancer)

## はじめに

この記事はAWS SAA試験勉強のための、ALBに関する知識のまとめです。


## ALBとは
通常のHTTPSアクセスを利用するWEBアプリケーションにおいて、複数のEC2インスタンスへのトラフィックを分散処理するために利用します。

## ALBの基本的性質
- Application Load Balancer のリスナールールを使用して、HTTP リクエストを HTTPS に**リダイレクト**するような設定が可能。(変換するわけではありません。)

- L7(アプリケーション層)で負荷分散。(CLBより高性能。)

- **URLパス**(`http://example.com/a/*`など)やヘッダーに基づいたルーティング、セッションの維持、WebSocketなどのプロトコルをサポートしています。１つのALBで複数のサーバー群にわけてトラフィック制御をすることができます。

- WAFを適用できます。

- デフォルト設定では、Application Load Balancer は登録解除プロセスが完了するまで <font color="red">**300**</font> 秒待機して、ターゲットへ処理中のリクエストを完了しやすくします。

- ターゲットグループでのヘルスチェックが可能
- ALBはEC2インスタンスを複数のAWSリージョンに分散させるトラフィック分散は実施できません。1つのリージョン内において<font color="red">**複数のアベイラビリティゾーンに**</font>トラフィックを分散します。
- プライベートサブネット内のインスタンスへの通信のためにはALBはプライベートサブネットではなく、<font color="red">**パブリックサブネットに配置する必要があります。**</font>

## アクセスログ

ALBのアクセスログを有効化することで、クライアントの接続情報を5分ごとに取得することができます。

## SNI証明書

ALBでは、Server Name Indication(SNI)を使った複数のTLS/SSL証明書をサポートしています。この機能により、ALBの背後に、別の証明書を持ったセキュアなアプリケーションを複数配置することができます。

## 他のアプリとの連携

Amazon ECSと組み合わせて使用されることが多いです。
Ollama-MMLU-Proを動かすまで

## Ollama-MMLU-Proとは
https://github.com/chigkim/Ollama-MMLU-Pro
LLMの新しいテストの一つのMMLU-Proをvllmやgeminiではなく、Ollamaでテストを実行するためのもの。ChatGPT互換なのでgroqでも動く（tokenが制限に引っかかります)

### インストールと実行
```
git clone https://github.com/chigkim/Ollama-MMLU-Pro
pip install -r requirements.txt
```
#### 追加で必要なこともある
```
pip install --upgrade datasets
```
これをしないと以下エラーが出ることがある。phindに聞けば教えてくれるけど
```
1284, in generate_from_dict
    return Sequence(feature=generate_from_dict(obj["feature"]), length=obj["length"])
KeyError: 'length'
```
### 実行
設定ファイルの config.tomlを好きなモデルに修正
```
model = "llama3.1:8b-instruct-q8_0"
```
モデルをダウンロードしておく。ちなみにダウンロード先は
Linux: /usr/share/ollama/.ollama/models
https://github.com/ollama/ollama/blob/main/docs/faq.md
```
ollama pull llama3.1:8b-instruct-q8_0
```

あとは実行するだけ
```
python run_openai.py 
```
ただ、一つのカテゴリーでA4000でも数時間ぐらいかかる。
どうも、１問ごとに保存しているだけあって、途中で終わっても、再開できるみたいだ。（最後までテスト終わってない)

テスト結果で気をつけるべきは、無回答の場合、randomで答えを割り振るみたいです。結果を見るとき注意が必要
【書評】つくって、壊して、直して学ぶ Kubernetes入門

## 読んだ本

https://www.shoeisha.co.jp/book/detail/9784798183961

## 概要

k8sは昔軽く触ってみた程度で、そろそろしっかり入門しないとと思っていたところに易しそうな本が出ていたので思わず購入しました。
イラスト込みでわかりやすいという点と、壊れた状態からどう直すかという進め方が新鮮でわかりやすかったです。
それにしても用語などが理解しずらく、色々調べながらようやくある程度理解できたかなという感じです。

- Part 1：つくってみようKubernetes
  - Chapter 1　Dockerコンテナをつくってみる
  - Chapter 2　Kubernetesクラスタをつくってみる
  - Chapter 3　全体像の説明
  - Chapter 4　アプリケーションをKubernetesクラスタ上につくる
- Part 2：アプリケーションを壊して学ぶKubernetes
  - Chapter 5　トラブルシューティングガイドとkubectlコマンドの使い方
  - Chapter 6　Kubernetes リソースをつくって壊そう
  - Chapter 7　安全なステートレス・アプリケーションをつくるために
  - Chapter 8　総復習：アプリケーションを直そう
- Part 3：壊れても動くKubernetes
  - Chapter 9　Kubernetesの仕組み、アーキテクチャーを理解しよう
  - Chapter 10　Kubernetesの開発ワークフローを理解しよう
  - Chapter 11　オブザーバビリティとモニタリングに触れてみよう
  - Chapter 12　この先の歩み方

## おすすめの人

- k8sにこれから入門したい人
- k8sを業務で触っているが、何となくやっていて不安な人

## 次に読むなら

- k8sのもっと詳しい本でしょうか。オススメがあったら教えて下さい

## 感想

メモ

- コンテナ、ボリューム < Pod < Node < namespace < Cluster
- リソースとは
  - Pod:
  - Deployment: strategytypeを指定できる
  - ReplicaSet: 
  - Service: LB的なもの
  - ConfigMap: 環境変数など設定
  - CronJob: 定期的にPodを作って実行する
- スケジュールは、kubeletがpodを稼働させるためにnodeを割り当てること
modprobe  Key was rejected by service エラーや Your system has UEFI Secure Boot enabled が出るようになった

VirtualBox の仮想マシンが突然起動しなくなった。「Kernel driver not installed (rc=-1908)」とエラーメッセージが出ている。

# VirtualBox の症状

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/47d8e126-de1c-a423-5033-bef3bb2cc9dd.png)

これは意図せずに BIOS 設定を UEFI Secure Boot に変更したことによる影響。

これの他に、以下のような症状も発生した。

# apt での症状

```
$ sudo apt update
```

すると、

`Your system has UEFI Secure Boot enabled.`
の表示が出てキャンセルできない。進めていき、その次の起動時にパスワード入力を求められた。




# 環境

- Ubuntu 24.04 LTS
- Lenovo X1 Carbon

# ドライバの確認


```
$ sudo modprobe vboxdrv
```
とすると
```
modprobe: ERROR: could not insert 'vboxdrv': Key was rejected by service
```
となる。
念の為モジュールの確認
```
$ sudo modinfo -n vboxdrv
/lib/modules/6.5.0-44-generic/updates/dkms/vboxdrv.ko
```

# BIOS設定

調べてみると、 UEFI Secure Boot が有効になるとこのようなことになるらしい。

## UEFI Secure Boot の解除

X1 Carbon は 起動時に F1 キーで BIOS設定に入ります。
「Setting」 → 「Security」 → 「Secure Boot」 を 「Disable」 に設定しました。

 そういや Fn キーの挙動を変更する時に、 BIOS 設定に入って Default Setting 値をロードしてしまっていたかな。それで Secure Boot が有効になったぽい。
 
 ちょっと慌てました。
JSONとは何か？ ～非エンジニア向けガイド～

### 1. JSONとは何か？

#### JSONの概要

JSON（JavaScript Object Notation）は、データを構造化して保存・送受信するためのフォーマットです。JSONは人間が読めるテキスト形式であり、データをキーと値のペアで表現します。この形式は特にウェブ開発やAPI通信で広く使われており、シンプルでありながら柔軟性があります。

#### JSONが使われる場面

- **ウェブアプリケーションのデータ通信**: サーバーとブラウザ間でデータをやり取りする際に使われる。
- **設定ファイル**: アプリケーションの設定を記述するファイルとして使用されることが多い。
- **データストレージ**: シンプルなデータベース代わりに、JSONファイルにデータを保存するケースもある。

### 2. JSONの構造

#### 基本構造

JSONの基本構造は、キーと値のペアをカンマで区切ったもので、値は文字列、数値、オブジェクト、配列などが使えます。オブジェクトは `{}` で囲み、キーと値を `:` で区切ります。配列は `[]` で囲み、複数の値をカンマで区切ります。

#### シンプルな例

```json
{
  "name": "太郎",
  "age": 25,
  "isStudent": true,
  "courses": ["数学", "物理", "化学"]
}
```

この例では、名前、年齢、学生かどうか、そして受講しているコースのリストが含まれています。

### 3. JSONが使われる理由

#### 人間にもコンピュータにも分かりやすい
JSONは簡潔で読みやすいため、プログラマーだけでなく、非エンジニアの方でも理解しやすいのが特徴です。また、JavaScriptをはじめとする多くのプログラミング言語で自然に扱える形式であるため、データのやり取りがスムーズに行えます。

### 4. JSONと他のデータ形式の比較

#### JSON

- **特徴**: 軽量で読みやすいテキスト形式。ネストされたデータ構造を簡単に表現でき、API通信や設定ファイルでよく使用される。
- **サンプル**:
  ```json
  {
    "title": "JSONの例",
    "author": "山田太郎",
    "published": true,
    "tags": ["プログラミング", "データ", "JSON"]
  }
  ```

#### XML

- **特徴**: タグベースのマークアップ言語で、データを階層的に構造化する。より複雑なデータ表現が可能だが、冗長になることがある。特にドキュメント型データや設定ファイルに使われることが多い。
- **サンプル**:
  ```xml
  <book>
    <title>XMLの例</title>
    <author>山田太郎</author>
    <published>true</published>
    <tags>
      <tag>プログラミング</tag>
      <tag>データ</tag>
      <tag>XML</tag>
    </tags>
  </book>
  ```

#### CSV

- **特徴**: コンマで区切った値の形式で、テーブル形式のデータを簡単に表現できる。シンプルで使いやすいが、複雑なデータ構造には向かない。主にスプレッドシートやデータのインポート・エクスポートに使用される。
- **サンプル**:
  ```
  title,author,published,tags
  "CSVの例","山田太郎",true,"プログラミング,データ,CSV"
  ```

### 5. データを構造として管理するメリットとデメリット

#### メリット

- **データの一貫性**: 構造化されたデータは、一貫した形式で管理されるため、データの整合性が保たれやすい。
- **可読性と保守性**: 構造が明確であるため、データを理解しやすく、変更や修正も容易。
- **クエリと解析の容易さ**: 構造化されたデータは、SQLのようなクエリ言語を使って簡単に検索・解析が可能。
- **データの再利用性**: 明確な構造があることで、同じデータを異なるコンテキストで再利用しやすい。

#### デメリット

- **複雑さの増加**: データが複雑になりすぎると、管理や理解が難しくなる可能性がある。
- **データ量の増加**: 構造化によって、データのメタ情報が追加されるため、ファイルサイズが大きくなることがある。
- **柔軟性の制限**: あらかじめ定義された構造にデータを合わせる必要があるため、柔軟なデータ管理が難しくなることがある。
- **学習コスト**: データを構造化して管理するには、特定のフォーマットやツールの知識が必要になるため、学習コストがかかる。

### 6. まとめ
JSONは、データをシンプルかつ柔軟に管理・送受信するための便利なフォーマットです。XMLやCSVと比較しても、その読みやすさや扱いやすさが際立っています。データを構造化することにはメリットも多いですが、使用するデータの性質や目的に応じて、適切なフォーマットを選ぶことが重要です。
[Python]状態空間の時間応答を計算するスクリプト（２入力系）

・ 時間応答はStep応答やインテンシャル応答ではない、任意の入力に対する応答。lsimを使用して計算する。
・ 状態空間表現（状態空間モデル）はssを使用する。

```a01_Contorol_test2.ipynb
from control.matlab import*
import numpy as np
import matplotlib
import matplotlib.pyplot as plt

# システム行列
A = np.array([[0, 1], [-4, -5]])
B = np.array([[0, 1], [1, 0]])
C = np.array([[1, 0], [0, 1]])
D = np.array([[0, 0], [0, 0]])

# 状態空間モデル
sys = ss(A, B, C, D)

# シミュレーション時間
t = np.linspace(0, 5, 1024)

# 正弦波入力と余弦波入力
freq1 = 1.0
freq2 = 0.1
amp1 = 1.0
amp2 = 0.5
u1 = amp1 * np.sin(2 * np.pi * freq1 * t)
u2 = amp2 * np.cos(2 * np.pi * freq2 * t)

# 同時入力
u_combined = np.vstack((u1, u2)).T  # Transpose to match the expected shape

# lsimで応答計算
x, _, _ = lsim(sys, U=u_combined, T=t)

# グラフ表示
plt.figure(figsize=(10, 6))

plt.subplot(2, 1, 1)
plt.plot(t, x[:, 0], label="State 1")
plt.plot(t, x[:, 1], label="State 2")
plt.xlabel("Time")
plt.ylabel("State Variables")
plt.title("System Response to Sinusoidal and Cosine Inputs (States)")
plt.legend()
plt.grid(True)

plt.subplot(2, 1, 2)
plt.plot(t, u1, label="Input 1 (sin input)")
plt.plot(t, u2, label="Input 2 (cos input)")
plt.xlabel("Time")
plt.ylabel("Input Signals")
plt.title("Input Signals (Sinusoidal and Cosine)")
plt.legend()
plt.grid(True)

plt.tight_layout()
plt.show()
```

実行結果
![出力例2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111514/feefbef2-cac1-d80f-ecde-224213091486.png)
vallex で 音声を生成

# 音声を生成

https://github.com/Plachtaa/VALL-E-X?tab=readme-ov-file

# 環境構築

参考
https://qiita.com/yuuuka/items/953ad06a7bf4419df875

python 3.1 でしか動かないので、pythonを切り替えられるようにする。
https://pythonlinks.python.jp/ja/index.html

こっから3.1をもらってくる。


```
PS C:\Users\h\OneDrive\デスクトップ> py --list
Installed Pythons found by C:\Windows\py.exe Launcher for Windows
 -3.12-64 *
 -3.10-64
 -3.9-64

```

とりあえず、切り替えができるようになっていたら次へ

```
git clone https://github.com/Plachtaa/VALL-E-X.git
cd VALL-E-X
py -3.10 -m pip install -r requirements.txt
py -3.10 -m pip install IPython
```

checkpointsフォルダを作成し、vallex-checkpoint.ptを入れる
whisperフォルダを作成し、medium.ptを入れる

# 生成

utf-8 で作る

```hoge.py

from utils.generation import SAMPLE_RATE, generate_audio, preload_models
from scipy.io.wavfile import write as write_wav
from IPython.display import Audio

# download and load all models
preload_models()

# generate audio from text
text_prompt = """今日はとても暑いですね。みんなが笑顔になりますように"""
audio_array = generate_audio(text_prompt)

# save audio to disk
write_wav("vallex_generation.wav", SAMPLE_RATE, audio_array)

# play text in notebook
Audio(audio_array, rate=SAMPLE_RATE)

```

実行

```
 py -3.10 hoge.py
```

vallex_generation.wavができあがる

# 応用
声を変えて、さらにファイル名を連番にする

```hoge.py
import time
from utils.generation import SAMPLE_RATE, generate_audio, preload_models
from scipy.io.wavfile import write as write_wav
from IPython.display import Audio

# download and load all models
preload_models()

# generate audio from text
text_prompt = """今日はとても暑いですね。みんなが笑顔になりますように"""
audio_array = generate_audio(text_prompt,prompt="esta")



timestamp = int(time.time())
filename = f"vallex_generation_{timestamp}.wav"

# save audio to disk
write_wav(filename, SAMPLE_RATE, audio_array)

# play text in notebook
Audio(audio_array, rate=SAMPLE_RATE)
```
Windows 11 Homeでスリープからの復帰時にプログラムを実行する方法(の代替案)

# 概要
Windows 11 Home でスリープ復帰時にプログラムを実行する代わりに、アンロック時のプログラム実行を設定しました

# トリガー問題
Windows でスリープ復帰時にコマンドを実行するには、タスクスケジューラを使う方法があります。
トリガーとしては以下のイベントが知られています。
* タスクの開始: イベント時
* ログ: システム
* ソース: Power-Troubleshooter または Microsoft-Windows-Power-Troubleshooter
* イベント ID: 1

しかし Windows 11 Home の場合、Power-Troubleshooter が標準では使えません。そもそも [deprecated だという話](https://support.microsoft.com/en-us/windows/deprecation-of-microsoft-support-diagnostic-tool-msdt-and-msdt-troubleshooters-0c5ac9a2-1600-4539-b9d0-069e71f9040a)もあります。

ほかに以下のイベントが使えるという説もあります。実際イベントビューアを見ると来てはいるようですが、タスクスケジューラでうまく取れませんでした。
* ソース: Kernel-Power
* イベント ID: 566

# 代替案

スリープ復帰時にアンロックする設定なら、アンロックをトリガーにできます。
* タスクの開始: ワークステーション アンロック時

スリープせずにロックだけかかった場合にも実行されて問題なければ、これで代替できます。


# 今回の使い道

WSLg で、setxkbmap で設定したレイアウトがスリープ復帰時に書き換わってしまうという問題の回避に使いました。以下を入れたバッチファイルを実行しています。
```
start /min wsl.exe -u hideki /usr/bin/setxkbmap us
```
すぐ実行するとうまく動かないようなので、「遅延時間を指定する」で最小の30秒間を指定しています。
[Python]伝達関数の時間応答を計算するスクリプト


時間応答はStep応答やインテンシャル応答ではない、任意の入力に対する応答。lsimを使用する。

```a01_Contorol_test1.ipynb
from control.matlab import*
import numpy as np
import matplotlib
import matplotlib.pyplot as plt

# 初期条件
x0 = [0, 0]

# 時間配列
t =  np.arange(0, 3, 0.01)

# 正弦波入力
freq = 0.5
amp = 1.0
u = amp * np.sin(2 * np.pi * freq * t)

# 伝達関数モデル
s = tf('s')
P = 1/(s**2+2*0.3*s+1)

# lsimで応答計算
(y1a, T1a, x1a) = lsim(P, U=u, T=t, X0=x0)

# グラフ表示
plt.axhline(0, color="b", linestyle="--")
plt.plot(T1a, u, label="Input")
plt.plot(T1a, y1a, label="Output")
plt.xlabel("Time (s)")
plt.ylabel("Displacement")
plt.title("Response to Sinusoidal Input")
plt.legend()
plt.grid(True)
plt.show()
```

実行結果
![出力例.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111514/644d1c7e-c8f5-1656-c763-9d7b400b9890.png)