OmniAICreator/Qiita-1.07M huggingface dataset:
DeSmuMEで組み込まれているLua用API　非公式リファレンス　～soundライブラリ～

この記事はニンテンドーDS向けエミュレータの一つである「DeSmuME」（以降Desmume）のLua用APIの非公式日本語リファレンスです。今回はsoundライブラリについてのリファレンスです。

:::note warn
このリファレンスは非公式の日本語リファレンスです。そもそも英語のリファレンスも公式のリファレンスもありません。
さらに詳細の仕様を確認したい場合はDesmumeのソースコードを参照することを推奨します。
→https://github.com/TASEmulators/desmume/blob/master/desmume/src/lua-engine.cpp
:::

---

`sound.clear()`
ゲーム音をミュートさせます。

<details><summary>引数</summary>

無し　nil

</details>

<details><summary>戻り値</summary>

無し　nil

</details>

``` lua: example.lua
local function Fn()
sound.clear()
end
gui.register(Fn)
```

---
AWSの負荷試験にFISを使わなかった話

AWSには、負荷テストのためのマネージドサービスとしてAWS Fault Injection Service（AWS FIS）というものがあります。

>AWS Resilience Hub の一部である AWS Fault Injection Simulator Service (FIS) は、アプリケーションのパフォーマンス、オブザーバビリティ、回復性を向上させるために、フォールトインジェクション実験を実行するためのフルマネージドサービスです。FIS は、さまざまな AWS のサービス全体でコントロールされたフォールト挿入実験をセットアップして実行するプロセスを簡素化するため、チームはアプリケーションの動作についての確信を深めることができます。

https://aws.amazon.com/jp/fis/

先日AWS上のサーバに対して負荷試験を行う必要があったのですが、このFISを利用しなかったため、その理由について残したいと思います。
（AWSやFISのネガキャンではなく、FISをより使いやすいサービスにしてもらうための改善要望という意味で書いています。）

# 結論
FISはJMeter等のように、「Webアプリケーションに対して大量のリクエストを送信し、レスポンス時間を確認する」といった使い方ができませんでした。

例えばAmazon ECSであればCPU使用率の負荷テストなどを実施できますが、Webアプリケーションの負荷テストには向いていないようです。
https://docs.aws.amazon.com/fis/latest/userguide/fis-actions-reference.html#ecs-actions-reference

つまりFISでCPU負荷を上げたうえで、別途サードパーティのツールを利用してアクセス時間の測定などをしないといけない、ということでしょうか。
いまいち痒い所に手が届いていない気がしてなりません。

# 最後に
ここまで書いてきましたが、もしFISや他のAWSサービスで上記のようなWebアプリケーションの負荷試験を実現できるよ、という場合はコメントで教えてください。
PNG vs webP OpenCVでの読み書き対決

# PNG vs webP 試してみました．

OpenCVでwebPの画像が扱えることを知ったので，試してみました．

+ OpenCV: 4.10.0

Image Size: (1080, 1440, 3)の以下の写真（大空スバルちゃん多め）

![syuba.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104675/f190b46a-86c6-4520-8112-8350b344b50f.jpeg)

試したこと：画像を10回連続保存して，保存した画像を10枚読み込む

```python
##
# coding: utf-8
##

import os
import time
import numpy as np
import cv2

def main():
    print(f"OpenCV: {cv2.__version__}")

    img = cv2.imread("syuba.jpg")

    print(f"Image Size: {img.shape}")
    print("画像を10回連続保存して，保存した画像を10枚読み込む")
    print(f"Write Time")

    o_dir = "output/png"
    os.makedirs(o_dir, exist_ok=True)
    st = time.time()
    for i in range(10):
        cv2.imwrite(os.path.join(o_dir, f"test_{i}.png"), img)
    print(f"  PNG Time: {time.time() - st:.3f} [s]")

    o_dir = "output/webp"
    os.makedirs(o_dir, exist_ok=True)
    st = time.time()
    for i in range(10):
        cv2.imwrite(os.path.join(o_dir, f"test_{i}.webP"), img)
    print(f"  webP Time: {time.time() - st:.3f} [s]")

    print(f"Read Time")

    o_dir = "output/png"
    os.makedirs(o_dir, exist_ok=True)
    st = time.time()
    for i in range(10):
        pimg = cv2.imread(os.path.join(o_dir, f"test_{i}.png"))
    print(f"  PNG Time: {time.time() - st:.3f} [s]")

    o_dir = "output/webp"
    os.makedirs(o_dir, exist_ok=True)
    st = time.time()
    for i in range(10):
        pimg = cv2.imread(os.path.join(o_dir, f"test_{i}.webP"))
    print(f"  webP Time: {time.time() - st:.3f} [s]")

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

```text:実行結果
Write Time
  PNG Time: 0.431 [s]
  webP Time: 4.873 [s]
Read Time
  PNG Time: 0.265 [s]
  webP Time: 0.238 [s]
```

保存はめっちゃ遅いが，表示はPNGよりも若干早いです．
10枚ずつ保存した画像ディレクトリの容量は以下のようになりました．

+ output/png:  24.5 MB
+ output/webp: 14.7 MB

# 結果

画像をwebPで保存しておいて，プログラムから読み込むことしかしなければ，webPのほうが早くて軽そう．
【WSL2】viteで起動したサーバに、外部端末からアクセスする方法

お疲れ様です。秋並です。

今回は、
- viteで起動したサーバに、外部IPからアクセスする方法 on WSL2

について解説します。

# package.jsonまたは、vite.config.tsの変更

最初に、デフォルトでviteを起動するとlocalhostからしかアクセスできないので、IPアドレスからアクセスできるようにpackage.jsonまたは、vite.config.tsを変更します。

手順については、下記を参考にしてください

https://qiita.com/Junpei_Takagi/items/3615505dcabd2e97f3e1

# .wslconfigの編集

次に「C:/ユーザー/<ユーザー名>」に.wslconfigを作成し、以下のように設定します。


```
[wsl2]
dnsTunneling=true
autoProxy=true
networkingMode=mirrored

[experimental]
hostAddressLoopback=true
```

::: note   
.wslconfigファイルは、隠しファイルになるのでエクスプローラーの「表示」タブから隠しファイルを表示できるように設定してください。

また、よくある間違いとして「.wslconfig.txt」のように余計な拡張子がついてしまっていることがあるので、同様に「表示」タブからファイルの拡張子を表示するようにし、拡張子がついていないことを確認してください。
:::

# ファイアーウォールの設定

最後にファイアーウォールの「受信の規則」で対象の外部端末のIPからのアクセスを許可します。

::: note warn  
ファイアーウォールの設定はセキュリティに影響するので、必要に応じて詳細に設定してください。
:::

<br>

ここまで設定出来たら、下記コマンドでwslを一度再起動してください（下記コマンドはpower shellなどで実行）。

```shell
wsl --shutdown
```

# viteでサーバーを起動

ここまでの手順が完了したら、viteでサーバーを起動してください（wsl2上で実行）。

サーバを起動すると、以下のように表示されると思います。

```
（前略）
  ➜  Local:   http://localhost:5173/
  ➜  Network: http://***.***.***.***:5173/
  ➜  Network: http://***.***.***.***:5173/ # こっちに外部端末のブラウザからアクセスできる
```

おそらく、Networkには上記のように2つアドレスが表示されると思いますが、2つ目のアドレスに外部端末からアクセスできるようになっているはずです。
IPアドレスとサブネットの考え方まとめ

## 1.IPアドレスの基本
・IPアドレスとは
　ネットワーク上の住所として、コンピュータやデバイスがデータを送受信するための識別番号です。IPv4では32ビット（4オクテット）で表現され、通常は「ドット区切り」の形式（例：192.168.1.100）で書かれます。
各オクテットは8ビットで、0～255の範囲を持ちます。

## 2.サブネットマスク
・サブネットマスクとは
　サブネットマスクは、IPアドレスがどの部分を「ネットワーク部」、どの部分を「ホスト部」にするかを決定するためのビットマスクです。
サブネットマスクのビットが1の部分はネットワーク部、0の部分はホスト部になります。

・サブネットマスクの例
　255.255.255.0（/24）
　・ネットワーク部: 24ビット
　・ホスト部: 8ビット

## 3.CIDR(Classless Inter-Domain Routing）
・CIDR表記
　サブネットのビット数を「/数字」の形式で表現します。例えば、192.168.1.100/24 の場合、サブネットマスクは 255.255.255.0 となり、最初の24ビットがネットワーク部、残りの8ビットがホスト部になります。

・CIDRとサブネットマスクの関係
　・/24 はネットワーク部が24ビット、つまりサブネットマスクが 255.255.255.0 です。
　・/26 だとネットワーク部が26ビットで、サブネットマスクは 255.255.255.192 となります。

## 4.サブネットアドレスの計算
・サブネットアドレスの決め方
　IPアドレスとサブネットマスクの論理積（AND演算）をとることで、そのIPがどのネットワークに属しているかがわかります。
例:
　192.168.1.100/24 と 255.255.255.0 の場合、論理積をとるとネットワークアドレスは192.168.1.0 になります。

・ネットワークアドレス、ホスト部、ブロードキャストアドレス
サブネット内で使用することができるアドレスは、ネットワークアドレスとブロードキャストアドレスを除いた範囲です。

　・ネットワークアドレス: サブネットの最初のIPアドレス（例: 192.168.1.0）
　・ブロードキャストアドレス: サブネットの最後のIPアドレス（例: 192.168.1.255）
　・使用可能なIPアドレス: それらの範囲外のIP（例: 192.168.1.1 ～ 192.168.1.254）

## 5.サブネットを分ける
・/26のサブネット分割の例
　10.0.0.0/24 を /26 に分割すると、1つのサブネットは64個のIPアドレスになります。
　各サブネットは次のように分割されます：
　・10.0.0.0 ～ 10.0.0.63
　・10.0.0.64 ～ 10.0.0.127
　・10.0.0.128 ～ 10.0.0.191
　・10.0.0.192 ～ 10.0.0.255
・CIDR表記とサブネット数の関係
　・/24 → 1サブネット = 256個のIP（使用可能IP 254個）
　・/25 → 1サブネット = 128個のIP（使用可能IP 126個）
　・/26 → 1サブネット = 64個のIP（使用可能IP 62個）
　・/27 → 1サブネット = 32個のIP（使用可能IP 30個）
　・/28 → 1サブネット = 16個のIP（使用可能IP 14個）

## 6.使用可能なホスト数の計算
・ホスト部のビット数を元に、使用可能なホスト数は次の式で計算できます。
使用可能なホスト数 = 2^(ホスト部のビット数) - 2（ネットワークアドレスとブロードキャストアドレスは除く）

・例:
/24 → ホスト部のビット数 = 8
使用可能なホスト数 = 2^8 - 2 = 254

## 7. まとめ
・IPアドレス と サブネットマスク は、ネットワークを構成するために欠かせない要素です。
・サブネットマスクは ネットワーク部 と ホスト部 を区別する役割を持ちます。
・CIDR表記（/24、/26 など）を理解すれば、サブネットの分割やホスト数の計算も簡単になります。
・サブネットごとの範囲（ネットワークアドレスからブロードキャストアドレスまで）を把握し、使えるIPアドレスを計算することが重要です。
Ruby オブジェクトの汚染とは？

## はじめに
Ruby学習にて今は使われてないが「<b>オブジェクトの汚染</b>」がよくわからなかったのでイメージをまとめてみました。

## 目次
1. [オブジェクトの汚染とは？](#オブジェクトの汚染とは)
2. [何が問題なの？](#何が問題なの)
3. [Rubyの対策💡](#rubyの対策)
4. [今のRubyでは使わない！](#今のrubyでは使わない)
5. [まとめ📝](#まとめ)

## オブジェクトの汚染とは？
「外部から取得したデータがRubyのオブジェクトに影響を与える可能性がある状態」のこと。

Rubyでは、外部からの入力（ユーザー入力、ファイル、ネットワーク経由のデータなど）を自動的に「怪しい！」と判定し、**汚染フラグ** (`taint`) を付けてくれる。


```ruby
str = "hello".taint   # 文字列を汚染する
puts str.tainted?      # => true  （汚染されている！）
```
👆 taint メソッドで汚染されると、```.tainted?``` で確認可能。

## 何が問題なの？
汚染されたオブジェクトをそのまま使うと、セキュリティ的に危険なことが起こる可能性がある！

例えば、eval を使って汚染された文字列を実行すると…？
```ruby
evil_input = "system('rm -rf /')".taint  # ユーザーが悪意あるコードを入力
eval(evil_input)  # 実行するとヤバい！
```
😨 危険！ ユーザーの入力がそのままシステムコマンドとして実行される可能性がある！

## Rubyの対策💡
Ruby 1.8 以前では $SAFE 変数を設定すると、汚染されたデータの使用が制限された。
$SAFE は、Ruby 1.8 以前のセキュリティ機能で、スクリプトの安全レベル（セーフレベル）を管理する特殊変数です。

```ruby
$SAFE = 1  # セーフレベルを設定（1以上で taint チェックが有効）

evil_input = "system('rm -rf /')".taint
eval(evil_input)  # セーフレベル1では例外が発生する
```
💡 $SAFE が 1 以上だと、汚染されたデータは危険なのでエラーに！
💡 Ruby 2.0 以降では $SAFE はほぼ無意味になり、Ruby 2.7 で完全に削除されました。

| $SAFE の値 | セキュリティレベル | 内容 |
|:-----------|:------------|:------------|
| 0（デフォルト）|制限なし|すべてのコードが実行可能|
| 1     | 危険なデータの制限|taint されたオブジェクトの操作が禁止|
| 2     | さらに厳しい制限|$LOAD_PATH の変更やディレクトリの書き込みが禁止|
| 3     | ほぼ読み取り専用|グローバル変数の変更が禁止される|
| 4     | 完全にサンドボックス化| Rubyのコード実行がほぼ禁止される|

## 今のRubyでは使わない！
taint および $SAFE は Ruby 2.7 では削除されたため、現在のコードでは使わない。
セキュリティ対策としては、taint ではなく、入力チェック・エスケープ処理・権限管理を適切に行うことが重要！

✅ ERB::Util.html_escape を使ってXSS対策
✅ プレースホルダ (? や bind_param) を使ってSQLインジェクション対策
✅ Shellwords.escape を使ってコマンドインジェクション対策
```ruby
require 'shellwords'
user_input = "rm -rf /"
safe_input = Shellwords.escape(user_input)

system("echo #{safe_input}")  # 安全にコマンド実行
```

## まとめ📝

* オブジェクトの汚染 = 外部データが怪しいフラグを持つ状態
* taint メソッド でオブジェクトを汚染できる
* 汚染されたデータを使うとセキュリティリスク（特に eval や system ）
* $SAFE 変数で汚染されたデータの使用を制限できた
* Ruby 2.7 以降は taint および $SAFE は削除となったので、今は使わない！
* 今のRubyでは $SAFE を使わず、適切なエスケープ処理や権限管理をするのが重要🚀

Rubyの柔軟性を活かしつつ、安全なコードを書いていこう！😆✨
【VSCode】shift+cmd+kで行削除ができなくなったぴえん

## 現象
VSCodeで行削除をしようとしてショートカットの`shift+cmd+k`を入力したが、何も起こらない。

## 環境

- チップ: Apple M1 Max
- OS: macOS Sonoma 14.6.1
- エディタ: Cursor 0.45.5
（VSCodeで検索することが多いと想定されるため、タイトルにはVSCodeを記載してます）

## 解決
1. Notionデスクトップを終了
1. エディタを再起動!

:::note info
その後Notionを起動しても行削除は問題なくできました。
:::

## 参考にした記事
https://www.reddit.com/r/vscode/comments/1e5t76s/shiftcmdk_does_not_work_on_vscode_anymore/?rdt=34748

> I have Notion desktop app installed, which has cmd+shift+k as a key. When I quit Notion, it started working in VSCODE. hope this helps.

１時間くらいVSCodeの設定とか拡張機能とか見直したのに😢

結局別のアプリのショートカットと競合していたという、、、ぴえん超えてぱおん超えてひひん超えてにゃー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668402/42c1ba38-8800-44e9-bacf-381f8927d52d.png)

コマンド検索の使用をOFFにして再起動って書いてますが、もともとOFFでした。

Notionを終了すれば、解決できます。
TechBoosterでGitHub Actionsがエラーになった件

# TechBoosterでGitHub Actionsがエラーになった件→リポジトリ修正済

:::note info
2025/03/22 追記
リポジトリの方が修正され、現在はエラーとならなくなりました。
以下、忘備録として残しておきます。
:::

こんばんは、かーでぃです。
5月末開始の技術書典18を控えて、そろそろ執筆活動に皆さん動き出す頃でしょうか？

RPACommunityでも先日、キックオフMTGを開催しました。
TechBoosterをCloneしてリポジトリを作成し、適当な文章入れてPushしたところ、GitHubActionsでエラーが発生してしまい、PDFが生成されず、ちょっと途方にくれていました。

誰に相談しようか悩んだあげく…
とりあえず、初心に返って「エラーメッセージからちゃんと見て行こう！」と思いまして、うだうだしてたら、なんとか無事に動かすことができました、というnote記事を書きましたので、リンクを置いておきます。

https://note.com/kerdy/n/n914a59583eed

これから、TechBoosterを使って技術書を書かれる方も多くなる時期だと思いますので、少し早めに情報展開しておきますね。
macOSのシステムデータ肥大化問題と解決策

![250304_mbp_opt.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/bf0b4180-d941-454f-82cd-03605383fc9e.jpeg)

## 背景

MacBook Pro 2021 (512GBストレージ) のストレージ使用量を確認したところ、「システムデータ」が191GBも占めており、ストレージ全体の約40%に達していました。一般的な「システムデータ」カテゴリの定義を調べても、ここまで大きくなる原因がわからず、解決策を探ることにしました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/4f068e8b-d058-4056-8197-2d4bd363a784.png" width=50%>

↑80GB削除後。システムデータが200GBほどになっていました。

## Appleサポートへの問い合わせ

解決の糸口を掴むため、Appleサポートに連絡しました。チャットおよび電話を通じて、以下の点が判明しました。

1. **「システムデータ」は分類されないデータの総称**

   - ユーザーの個人データやアプリのキャッシュなどが含まれています。
   - 具体的に何が含まれているかを一括で調べる方法はAppleの公開情報にはありません。

2. **Homebrewでインストールしたアプリや仮想マシンのデータも「システムデータ」に含まれる可能性**

   - Homebrewやその他の手動インストールしたアプリのデータは、ストレージ管理の「アプリ」カテゴリに入らず、「システムデータ」に分類されることが多いようです。
   - Parallelsの仮想マシン (`~/Parallels/*.pvm`) やUTMの仮想マシン (`~/Library/Containers/com.utmapp.UTM/Data/`) も「システムデータ」としてカウントされていました。

3. **有効なストレージ使用状況の調査方法**

   - Appleサポートから、容量の大きいフォルダをリストアップするコマンドを教えてもらいました。

## ストレージ使用状況の分析

以下のコマンドを実行し、ディスク使用量を調査しました。

```sh
sudo du --si -xct 1000000000 /System/Volumes/Data | tee >(grep -ve $'*	' > ~/Desktop/DiskSpace.txt) | sort -nr > ~/Desktop/SortedDiskSpace.txt
```

:::note
プライバシー設定でTerminalにフルディスクアクセスの許可を与える必要があります。
:::

その結果、 `~/Library/Containers/com.apple.mediaanalysisd/Data/Library/Caches/com.apple.mediaanalysisd/com.apple.e5rt.e5bundlecache/` に **80GB** ものキャッシュデータが蓄積されていることが判明しました。

また、Parallelsの仮想マシン (`~/Parallels/*.pvm`) やUTMの仮想マシン (`~/Library/Containers/com.utmapp.UTM/Data/`) も大量のストレージを消費していました。

## 解決策

不要なキャッシュデータを削除しました。

いったんリネームして再起動し、動作に異常がないことを確認した後、ゴミ箱に移動し、最終的にディスクから削除しました。

削除後も同フォルダが即座に再生成されていたため、何らかのプロセスが継続的にキャッシュを生成していると考えられます。

## おわりに

- 「システムデータ」は **「その他」を意味する** ことが判明しました。
- Appleサポートに問い合わせたことで、的確なコマンドを得ることができました。
- LLMでは有効なコマンドを見つけられませんでしたが、Appleのサポートを通じて適切な方法を知ることができました。

システムデータが異常に肥大化している場合、このようにディスクの現状把握ができると非常に助かります。

ウェブ検索したりLLMに聞いてもいい回答が得られず、長い間（半年〜1年）この問題に悩んでいました。ついに大きく前進できたことに感激しています。これ、私だけの問題でしょうか？

### 環境

- macOS Sequoia 15.2
- MacBook Pro (14-inch, 2021)
Terraform 入門：Terraformをモジュールで読み込むメリットとコードの再利用性について考えてみた

## はじめに
Terraformは、インフラをコードで管理できるInfrastructure as Code（IaC）ツールとして広く利用されています。Terraformを活用することで、インフラの構築・管理を自動化し、一貫性のある環境を実現できます。

:::note warn
***しかし、プロジェクトの規模が大きくなると、Terraformのコードが複雑になり、管理しづらくなることがあります。***
:::

そこで、Terraformのモジュールを活用することで、コードの再利用性を高め、スケーラビリティやメンテナンス性を向上させることができます。

本記事では、Terraformのモジュールを利用するメリットについて詳しく解説し、どのように活用すれば効率的なインフラ管理ができるのかを紹介します。

### Terraformをモジュールで読み込むメリットとは？

Terraformは、インフラをコードで管理できるInfrastructure as Code（IaC）ツールとして広く活用されています。

:::note info
**その中でも、モジュールを利用することで、より効率的かつ柔軟にインフラ管理を行うことができます。**
:::

本記事では、Terraformでモジュールを使用するメリットを詳しく解説します。

## 1. コードの再利用性を向上

Terraformのモジュールを使うことで、同じ構成を複数の環境やプロジェクトで再利用できます。

例えば、以下のようなケースで活用できます。

- 複数のAWSアカウントで同じVPC構成を作成
- 開発環境、ステージング環境、本番環境で同じ構成を適用
- チーム全体で統一されたネットワーク設定やセキュリティポリシーを共有

コードの重複を減らし、一度定義したモジュールを再利用できるため、メンテナンスコストが削減されます。

## 2. インフラ管理のスケーラビリティ向上

大規模なインフラ構成では、Terraformのファイルが膨大になり、管理が難しくなります。
モジュールを導入することで、構成を分割し、スケーラブルに管理できます。

### 例: AWS環境の管理

Terraformのディレクトリ構成をモジュール化することで、環境ごとに適用しやすくなります。

```
terraform/
│── main.tf
│── variables.tf
│── outputs.tf
│── modules/
│   ├── vpc/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   ├── ec2/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   ├── rds/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
```

このように、VPC、EC2、RDSなどを個別のモジュールとして管理すれば、変更が必要な部分のみを修正しやすくなります。

## 3. チーム開発における効率アップ

Terraformのモジュールを活用すると、チーム開発時の役割分担がしやすくなります。

- インフラチーム → ネットワーク（VPCやサブネット）やIAMポリシーの管理
- 開発チーム → アプリケーションのデプロイに必要なリソース（EC2やRDS）の管理

これにより、各チームが責任を持つ領域を明確にし、Terraformコードのコンフリクトを減らすことができます。

また、Terraform Registry（https://registry.terraform.io/）にある公式モジュールを活用すれば、高品質な構成をすぐに適用可能です。

## 4. メンテナンスが容易

Terraformモジュールを利用することで、特定のリソースに対する変更を一箇所で管理できます。

### 例: EC2インスタンスタイプの変更

従来の方法では、複数の環境にまたがるEC2のインスタンスタイプを変更する場合、各`.tf`ファイルを修正する必要がありました。

```hcl
resource "aws_instance" "web" {
  instance_type = "t3.micro"  # 変更前
}
```

モジュールを導入していれば、`modules/ec2/variables.tf` の変数だけを修正すれば全ての環境に適用できます。

```hcl
variable "instance_type" {
  default = "t3.small"  # 変更後
}
```

これにより、変更ミスのリスクを低減し、統一した管理が可能になります。

## 5. Terraformのベストプラクティスに準拠

Terraform公式ドキュメントでもモジュール化は推奨されています。
公式のベストプラクティスとして、以下の点が挙げられています。

- Infrastructure as Codeの原則を徹底
- 小さな単位での構成管理
- 標準化されたモジュールの利用

Terraformのモジュールを使うことで、より信頼性が高く、変更に強いインフラを構築できます。

## まとめ

Terraformをモジュール化することで、以下のようなメリットがあります。

- コードの再利用性向上 → 同じ構成を複数環境で適用可能
- スケーラビリティ向上 → 大規模なインフラ管理が容易
- チーム開発の効率アップ → 役割分担がしやすくなる
- メンテナンスが容易 → 変更管理が楽になる
- Terraformのベストプラクティスに準拠 → 標準的な運用ができる

Terraformを運用する際は、適切にモジュールを活用し、より効率的なインフラ管理を実現していきます！
ERROR [client internal] load metadata for docker.io

## 概要

Dockerを更新してから、`docker compose`コマンドを使うとエラーが出た時の対応メモ。

## 環境

- macOS Sequoia 15.3.1
- Docker version 27.5.1
- Docker Compose version v2.32.4-desktop.1 

## エラー

`docker compose up`実行時のエラー

```zsh
% docker compose up
[+] Building 0.8s (2/2) FINISHED                                                                                                                  docker:desktop-linux
 => [client internal] load build definition from Dockerfile                                                                                                       0.0s
 => => transferring dockerfile: 190B                                                                                                                              0.0s
 => ERROR [client internal] load metadata for docker.io/library/node:22.2                                                                                         0.7s
------
 > [client internal] load metadata for docker.io/library/node:22.2:
------
failed to solve: node:22.2: failed to resolve source metadata for docker.io/library/node:22.2: error getting credentials - err: exec: "docker-credential-desktop": executable file not found in $PATH, out: ``
```

## 対応

`~/.docker/config.json`にある、`credsStore`を`credStore`に変更する。

### コマンド

```zsh
sudo vi ~/.docker/config.json
```

### 変更内容

#### 変更前

```json
        "auths": {},
        "credsStore": "desktop",
        "experimental": "disabled",
```

#### 変更後

```json
        "auths": {},
        "credStore": "desktop",
        "experimental": "disabled",
```

## 参考
https://stackoverflow.com/questions/65896681/exec-docker-credential-desktop-exe-executable-file-not-found-in-path
Flutterのwidget一覧

## **基本ウィジェット**
- `Container`：コンテンツをラップし、装飾やレイアウト調整が可能
- `Text`：テキストを表示
- `RichText`：スタイルを適用した複数のテキストを表示
- `Image`：画像を表示
- `Icon`：アイコンを表示
- `ElevatedButton`：立体的なボタン
- `TextButton`：シンプルなボタン
- `OutlinedButton`：枠付きボタン
- `FloatingActionButton`：フローティングアクションボタン

---

## **レイアウト関連**
- `Column`：縦方向にウィジェットを並べる
- `Row`：横方向にウィジェットを並べる
- `Stack`：ウィジェットを重ねる
- `Expanded`：子ウィジェットを親の余ったスペースいっぱいに広げる
- `Flexible`：`Expanded`と似ているが、より柔軟な比率指定が可能
- `Padding`：余白を追加
- `Align`：子ウィジェットの位置を調整
- `Center`：中央揃え
- `SizedBox`：指定したサイズのボックス
- `Spacer`：`Row`や`Column`内でスペースを作る
- `Wrap`：折り返し可能なレイアウト
- `GridView`：グリッドレイアウト
- `ListView`：スクロール可能なリスト

---

## **ナビゲーション・ページ遷移**
- `Navigator`：画面遷移の管理
- `MaterialPageRoute`：マテリアルデザインの遷移
- `CupertinoPageRoute`：iOS風の遷移
- `PageView`：ページスワイプ
- `TabBar` / `TabBarView`：タブナビゲーション
- `Drawer`：サイドメニュー
- `BottomNavigationBar`：ボトムナビゲーション

---

## **フォーム・入力関連**
- `TextField`：テキスト入力
- `TextFormField`：バリデーション付きテキスト入力
- `Checkbox`：チェックボックス
- `Radio`：ラジオボタン
- `Switch`：スイッチ
- `Slider`：スライダー
- `DropdownButton`：ドロップダウンメニュー
- `Form`：複数の入力ウィジェットをグループ化

---

## **スクロール関連**
- `SingleChildScrollView`：単一のスクロールビュー
- `ListView.builder`：動的なリスト
- `ListView.separated`：区切り付きリスト
- `GridView.builder`：動的なグリッドビュー
- `PageView`：ページスワイプ
- `RefreshIndicator`：プルダウン更新

---

## **アニメーション**
- `AnimatedContainer`：アニメーション付きのコンテナ
- `AnimatedOpacity`：透明度のアニメーション
- `AnimatedAlign`：位置のアニメーション
- `AnimatedPadding`：余白のアニメーション
- `AnimatedPositioned`：Stackの子ウィジェットのアニメーション
- `AnimatedSwitcher`：ウィジェットの切り替えアニメーション
- `Hero`：画面遷移時のアニメーション
- `TweenAnimationBuilder`：カスタムアニメーション

---

## **状態管理**
- `StatefulWidget`：状態を持つウィジェット
- `Provider`：状態管理（`provider`パッケージ使用）
- `ChangeNotifier`：リスナーを通知するクラス
- `ValueListenableBuilder`：値の変化をリッスンするウィジェット

---

## **ダイアログ・モーダル**
- `AlertDialog`：アラートダイアログ
- `SimpleDialog`：シンプルなダイアログ
- `BottomSheet`：ボトムシート
- `SnackBar`：スナックバー（短時間の通知）

---

## **メディア関連**
- `VideoPlayer`：動画再生（`video_player`パッケージ使用）
- `AudioPlayer`：音声再生（`audioplayers`パッケージ使用）
- `WebView`：Webページの表示（`webview_flutter`パッケージ使用）

---

## **カスタム描画**
- `CustomPaint`：独自の描画
- `ClipRRect`：角丸のクリップ
- `ClipOval`：円形のクリップ
- `ClipPath`：カスタム形状のクリップ

---

## **プラットフォーム固有**
- `CupertinoButton`：iOS風のボタン
- `CupertinoSwitch`：iOS風のスイッチ
- `CupertinoNavigationBar`：iOS風のナビゲーションバー
- `CupertinoTabBar`：iOS風のタブバー
sudo cat のリダイレクトで permission denied になる

```bash:問題のコード
sudo cat << EOC >> /etc/containerd/config.toml
[proxy_plugins]
  [proxy_plugins.soci]
    type = "snapshot"
    address = "/run/soci-snapshotter-grpc/soci-snapshotter-grpc.sock"
EOC
```


```title:得たエラー
line 8: /etc/containerd/config.toml: Permission denied
```

/etc 配下だから sudo 付けてるのに、なぜだ
→ 原因: リダイレクトは現在のユーザーで実行されるため。
→ 解決策: `tee -a` を使う

```bash
sudo tee -a /etc/containerd/config.toml << EOC
  ...
EOC
```
AWS学習

<h2>EC2とは</h2>

https://www.youtube.com/watch?v=oKdkO_abZRw

https://qiita.com/Jerid/items/d5dd3a29ed9a0e374493

<h2>AMIとは</h2>

https://www.youtube.com/watch?v=JggEWcj-WlE

<h2>s3とは</h2>

https://www.youtube.com/watch?v=UsNPWKbh_30

https://www.aws-room.com/entry/s3-sqs-lambda

<h2>Route53</h2>

https://www.youtube.com/watch?v=L_7DmbRkcys

<h2>GuardDuty</h2>

https://www.youtube.com/watch?v=ExK6MJWT1y0

<h2>Secrets Manager</h2>

https://aws.amazon.com/jp/awstv/watch/31d4dc470a2/

<h2>Elastic File System</h2>

https://www.youtube.com/watch?v=mX518m-tF3k

<h2>AWS Cost Explorer </h2>

https://www.youtube.com/watch?v=lfG2yKr9pQw

<h2>Compute Optimizer<h2>

https://www.youtube.com/watch?v=h7YxsY2T_SY

<h2>AWS Pricing Calculator</h2>

https://calculator.aws/#/

<h2>AWS lambda</h2>


https://kacfg.com/aws-lambda-function-urls-basic/#API_Gateway_Lambda

<h2>AWS Backup</h2>


https://dev.classmethod.jp/articles/cross-region-backup-of-ec2-using-aws-backup/
FlutterFlowでGCP Schedulerを使用する手順

# FlutterFlowでGCP Schedulerを使用する手順

FlutterFlowとGoogle Cloud Platform(GCP)のCloud Schedulerを連携させる手順をまとめました。

## 前提条件
- FlutterFlowアカウント
- GCPアカウント
- Firebase Projectの設定完了

## 手順

### 1. GCPプロジェクトの設定

1. [GCPコンソール](https://console.cloud.google.com/)にログイン
2. プロジェクトを選択または新規作成
3. APIとサービスを有効化:
   - Cloud Scheduler API
   - Cloud Functions API
   - Cloud Pub/Sub API

### 2. Cloud Schedulerの設定

1. GCPコンソールから「Cloud Scheduler」にアクセス
2. 「ジョブを作成」をクリック
3. ジョブの詳細を入力:
   - 名前: わかりやすい名前（例: `flutterflow-daily-task`）
   - 説明: ジョブの目的
   - 頻度: cronスケジュール形式で入力（例: `0 8 * * *` - 毎日午前8時）
   - タイムゾーン: 適切なタイムゾーンを選択

4. ターゲットの設定:
   - ターゲットタイプ: `HTTP`
   - URL: FlutterFlowのAPIエンドポイントまたはCloud Functionのエンドポイント
   - HTTPメソッド: `POST`または必要なメソッド
   - ヘッダー: 必要に応じて認証ヘッダーを追加
   - 本文: 必要なパラメータをJSON形式で記述

5. 「作成」をクリック

### 3. FlutterFlowでのAPIエンドポイント作成

1. FlutterFlowプロジェクトを開く
2. 「Backend」→「API Endpoints」を選択
3. 「+ Create New Endpoint」をクリック
4. エンドポイントの設定:
   - Method: `POST`または必要なメソッド
   - Path: `/schedule-task`などわかりやすいパス
   - Auth Required: セキュリティ要件に応じて設定
   - Description: エンドポイントの目的

5. アクションの設定:
   - カスタムコードで処理する場合は「Code」セクションで実装
   - または必要なデータベース操作やその他のアクションを設定

6. 「Save」をクリック

### 4. Cloud Functionを使用する場合（代替方法）

1. GCPコンソールから「Cloud Functions」にアクセス
2. 「関数を作成」をクリック
3. 関数の設定:
   - 名前: わかりやすい名前
   - トリガータイプ: `HTTP`
   - 認証: セキュリティ要件に応じて設定

4. ランタイム環境の設定:
   - ランタイム: Node.js、Python など
   - エントリポイント: 関数名
   
注意（重要）：onRequest使うので、右側の設定を一切せずにdeployしてください。


5. コードを記述:
   ```javascript
   exports.scheduledFunction = functions.region('asia-northeast1')
      .https.onRequest(async (req, res) => {
     // FlutterFlowのAPIエンドポイントを呼び出すコード
     fetch('https://your-flutterflow-api-endpoint.com', {
       method: 'POST',
       headers: {
         'Content-Type': 'application/json',
         'Authorization': 'Bearer YOUR_TOKEN'
       },
       body: JSON.stringify({ /* パラメータ */ })
     })
     .then(response => response.json())
     .then(data => {
       console.log('Success:', data);
       res.status(200).send('Task executed successfully');
     })
     .catch(error => {
       console.error('Error:', error);
       res.status(500).send('Error executing task');
     });
   };
   ```

6. 「デプロイ」をクリック

### 5. セキュリティの設定

1. APIキーまたはJWTトークンによる認証を実装
2. IAMロールを適切に設定し、最小権限の原則に従う
3. Cloud Scheduler→Cloud Function→FlutterFlowの通信を暗号化

### 6. テストと監視

1. Cloud Schedulerジョブを手動で実行してテスト
2. Cloud Loggingでログを確認
3. 必要に応じてモニタリングとアラートを設定

## トラブルシューティング

- ジョブが実行されない場合:
  - cronスケジュールの形式を確認
  - タイムゾーンの設定を確認
  - IAM権限を確認

- APIエンドポイントにアクセスできない場合:
  - URLが正しいか確認
  - 認証情報を確認
  - ネットワーク設定を確認
FlutterFlowからFirebase Functionsを呼び出す際にレスポンスが遅い時の対策

# FlutterFlowからFirebase Functionsを呼び出す際にレスポンスが遅い時の対策

Cloud Functionsはコールドスタート問題が発生することがあり、特に初回実行時に5-15秒程度の遅延が生じることがあります(メモリのサイズによって異なります)。ウォームアップ対策を試してみました。

## ウォームアップ対策の手順

### 1. Cloud Schedulerを使用した定期的なウォームアップ

1. GCPコンソールで「Cloud Scheduler」にアクセス
2. 「ジョブを作成」をクリック
3. ウォームアップ用ジョブの設定:
   - 名前: `function-warmup`
   - 説明: 「Function warm-up job」
   - 頻度: `*/10 * * * *`（10分ごとに実行）
   - タイムゾーン: 適切なタイムゾーンを選択
   - ターゲットタイプ: `HTTP`
   - URL: 対象のCloud Function URL
   - HTTPメソッド: `GET`
   - ヘッダー: `{"Content-Type": "application/json"}`
   - 認証ヘッダー: 必要に応じて設定
4. 「作成」をクリック

### 2. 最小インスタンス数の設定

1. GCPコンソールで「Cloud Functions」にアクセス
2. 対象の関数を選択
3. 「編集」をクリック
4. 「ランタイム、ビルド、接続設定」を展開
5. 「ランタイム」タブを選択
6. 「最小インスタンス数」を1以上に設定（例: 1〜3）
7. 「次へ」→「デプロイ」をクリック

### 3. 関数コードの最適化

1. 関数のパフォーマンスを向上させるコード最適化:

```javascript
// グローバル変数を活用（関数外で初期化）
const admin = require('firebase-admin');
if (!admin.apps.length) {
  admin.initializeApp();
}
const db = admin.firestore();

// 実際の関数
exports.myFunction = async (req, res) => {
  try {
    // ビジネスロジック
    const result = await someProcess();
    res.status(200).send({ success: true, data: result });
  } catch (error) {
    res.status(500).send({ success: false, error: error.message });
  }
};
```

### 4. FlutterFlow側での対応

1. FlutterFlowプロジェクトを開く
2. バックエンドアクションを設定：
   - 「Backend」→「Actions」を選択
   - ウォームアップ用のアクションを作成(必要に応じて並列処理)

3. アプリ起動時にウォームアップリクエストを送信:
   ```dart
   // アプリ初期化時に実行するコード
   Future initializeApp() async {
     // 他の初期化コード
     
     // Cloud Functionsのウォームアップ
     try {
       await http.get(Uri.parse('https://your-region-your-project.cloudfunctions.net/yourFunction'));
       print('Function warmed up');
     } catch (e) {
       print('Warm-up request sent (error ignored)');
     }
   }
   ```

4. FlutterFlowのカスタムコードセクションに上記コードを追加

5. アプリの初期画面の「On Page Load」アクションでウォームアップを実行するよう設定

### 5. Firebase Functionsで直接設定する場合（Blaze計画が必要）

1. `firebase.json`ファイルを編集:
   ```json
   {
     "functions": {
       "source": "functions",
       "runtime": "nodejs16",
       "minInstances": 1
     }
   }
   ```

2. デプロイコマンドを実行:
   ```bash
   firebase deploy --only functions
   ```

### 6. リクエストのバッチ処理

1. 可能な場合、複数のリクエストをバッチ処理:
   - 個別の関数呼び出しをまとめる
   - バルク操作を実装する

2. FlutterFlowのカスタムコードで一括処理を実装:
   ```dart
   // 複数のアイテムを一度に処理
   Future processBatch(List<String> itemIds) async {
     final response = await http.post(
       Uri.parse('https://your-region-your-project.cloudfunctions.net/batchProcessor'),
       headers: {'Content-Type': 'application/json'},
       body: jsonEncode({'items': itemIds}),
     );
     return jsonDecode(response.body);
   }
   ```


## 注意点

- 最小インスタンス数の設定はコスト増加につながります
- ウォームアップ戦略はユースケースに合わせて調整してください
- Sparkプランでは最小インスタンス数の設定ができないためBlazeプランへのアップグレードが必要です

以上の対策+メモリサイズを1GBにしたら2〜3秒くらいになりました。
flutter flowでfunctionsでclaude sonnet 3.7にリクエスト

# Flutter Flow + Anthropic API リクエストガイド

## 前提条件
- Flutter Flowプロジェクト
- Firebaseプロジェクト
- Cloud Functions設定
- Anthropic APIキー

## ステップ1: Cloud Functionsの設定

### 依存関係のインストール
Cloud Functions の `package.json` に以下を追加:
```json
{
  "dependencies": {
    "@anthropic-ai/sdk": "^0.39.0"
  }
}
```

### Anthropic関数の作成
```typescript
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const { Anthropic } = require('@anthropic-ai/sdk'); 

export const anthropicRequest = functions.https.onCall(async (data, context) => {
  const anthropic = new Anthropic({
    apiKey: functions.config().anthropic.api_key
  });

  try {
    const response = await anthropic.messages.create({
      model: 'claude-3-7-sonnet-20250219',
      max_tokens: 300,
      messages: [
        {
          role: 'user',
          content: data.prompt
        }
      ]
    });

    return {
      success: true,
      message: response.content[0].text
    };
  } catch (error) {
    console.error('claude API エラー:', error);
    return {
      success: false,
      error: error.message
    };
  }
});

```
## ステップ2: Firebaseの環境変数を設定
```bash
 const apiKeyprocess.env["ANTHROPIC_API_KEY"]
 const anthropic = new Anthropic({
          apiKey: apiKeyprocess, 
});
```


## ステップ3: Cloud Functionをデプロイ
```bash
firebase deploy --only functions
```

## ステップ4: Flutter Flowでの設定

### アクションの作成
1. Flutter Flowの「アクション」に移動
2. 「クラウド関数を呼び出す」を選択
3. `anthropicRequest`関数を選択
4. プロンプトパラメータを渡す

### リクエストパラメータの例
```json
{
  "prompt": "Flutter開発をわかりやすく説明してください"
}
```

## セキュリティに関する注意点
- APIキーをクライアント側で公開しない
- Firebase Cloud Functionsをミドルウェアとして使用
- 適切な認証と承認を実装
Remix ファイル名ではなくフォルダを使ってURLを指定したい

## 概要

RemixにはURLの指定方法が2つ存在する。

- ファイル名を`.`を使って区切りURLの構造を指定
- フォルダを用いURLの構造を指定

今回「ファイル名を`.`を使って区切りURLの構造を指定」から「フォルダを用いURLの構造を指定」に変更したところ若干詰まったので記事にする。

## 前提

`.`を用いたURLの指定は下記のように実装されている。

```
app/
└── routes/
    ├── hoge.tsx
    └── hoge.fuga.tsx
```

ファイルパスとURLの関係をまとめる

| ファイルパス | URL |
| --- | --- |
| app/routes/hoge.tsx | /hoge |
| app/routes/hoge.fuga.tsx | /hoge/fuga |

この状態で`$ npm run dev`を実行し、ローカル開発環境で`/hoge`と`/hoge/fuga`にアクセスするとそれぞれ問題なく画面が表示される。

## あまり調べずに実装して詰まった方法

フォルダに共通化するということなのであまり調べず下記のようにしてみた。

```
app/
└── routes/
    └── hoge/
        ├── index.tsx
        └── fuga.tsx
```

この状態で`$ npm run dev`を実行し、ローカル開発環境で`/hoge`は表示される。`/hoge/fuga`は404になる。
その後も下記のパターンを試したが`/hoge`は表示され、`/hoge/fuga`は404になる症状は解消しない。

```
app/
└── routes/
    └── hoge/
        ├── index.tsx
        └── index.fuga.tsx
```

```
app/
└── routes/
    └── hoge/
        ├── index.tsx
        └── hoge.fuga.tsx
```

```
app/
└── routes/
    └── hoge/
        ├── index.tsx
        └── fuga/
            └── index.tsx
```

## 解消した方法

参考文献先の記事や公式ドキュメントを読んだところフォルダ名・ファイル名ともにの指定に誤りがあった。
どうやらフォルダ名で`.`を用いて階層構造を指定する必要があるらしい。
うまくいった構造を下記に記載する。

```
app/
└── routes/
    └── hoge._index/
        └── index.tsx
    └── hoge.fuga/
        └── index.tsx
```

この場合のファイルパスとURLの関係をまとめる

| ファイルパス | URL |
| --- | --- |
| app/routes/hoge._index/index.tsx | /hoge |
| app/routes/hoge.fuga/index.tsx | /hoge/fuga |

## なぜイケてない方法でも`/hoge`は表示されたのかの予想

確証に至ってない予想だが

フォルダ名の`._index`は省略可能である可能性が高い。

```
app/
└── routes/
    └── hoge._index/
        └── index.tsx
```

と

```
app/
└── routes/
    └── hoge/
        └── index.tsx
```

は同様の意味を持つのでは無いだろうか？
その裏付けとして下記のように定義しても問題なく`/hoge`も`/hoge/fuga`も表示出来た。

```
app/
└── routes/
    └── hoge/
        └── index.tsx
    └── hoge.fuga/
        └── index.tsx
```

ちなみに下記は`/hoge/fuga`が表示出来なかった。

```
app/
└── routes/
    └── hoge/
        ├── index.tsx
        └── .fuga/
            └── index.tsx
```

## まとめ

ファイル名とフォルダを使ったURL指定の方法を表でまとめると下記のようになった。

| ファイル名を使った場合<br>のファイルパス | フォルダを使った場合<br>のファイルパス | URL |
| --- | --- | --- |
| app/routes/hoge.tsx| app/routes/hoge._index/index.tsx | /hoge |
| app/routes/hoge.fuga.tsx| app/routes/hoge.fuga/index.tsx | /hoge/fuga |

まだなれていないのでファイルベースルーティングに苦戦しているが、慣れたら確実にわかりやすいと感じた。

## 参考文献

https://qiita.com/SoarTec-lab/items/fe91fcb0773b28ceccd3

https://remix.run/docs/en/main/file-conventions/routes#folders-for-organization
Pythonのappendメソッドの存在意義に気付いた

プログラミング初学者の発見と成長の記録です。
ある条件に合致する単語をリストに追加するコードを書いて学んだことをメモします。

**取り組んだ課題**

「入力された文字列から、 "a"を含む単語だけを抽出して表示するプログラムを作成する。
ただし、単語は半角スペースで区切られているものとする。」

**条件**

- 大文字・小文字は区別せずにチェックする（`a` と `A` を同じとみなす）
- "a" を含む単語がない場合は、「該当する単語はありません」と表示する


```python
#入力値の例
apple banana cherry
```

# 💡今回学べたこと

- Pythonで**文字列全体を1つの要素**としてリストに格納したい場合は**appendメソッド**が欠かせない
- 文字列の分割にはstr.split()メソッドを使う。任意の区切り文字を引数に指定。引数に指定がない場合はスペースを区切り文字とする
- in演算子は大文字と小文字を区別する。区別せずに演算したい場合は事前にlowerメソッドかupperメソッドで表記を揃える

今回の記事では、タイトルにもある通り「appendメソッドの存在意義」について扱います。

# リストへの追加で起きた想定外の挙動

appendを使わずに代入演算子`+=`でリストに代入しようとしたところ、想定外の結果を招きました

```python
# 入力フォームから文字列を受け取る
words = input("任意の文字列を入力してください: ")

# スペースを区切り文字として分割し、リストに格納
listed_words = words.split()

# "a"を含む単語を格納するリストを宣言
filtered_words = []

# 単語をチェックして順番にリストに格納
for word in listed_words:
    word = word.lower()
    if "a" in word:
        filtered_words += word # 問題の発生箇所

# 結果を出力
if filtered_words:
    for i in filtered_words:
        print(i)
else:
    print("該当する単語はありません")

```

チェックした単語を、代入演算子”+=”でリストに代入しようとしている。

## 期待していた結果

```python
apple 
banana
```

## 実際の結果

一文字ずつ出力された
```python
a
p
p
l
b
a
n
a
n
a
```

# どうしてこうなった？

理由は、Pythonが文字列をイテラブル(反復可能)なオブジェクトとして扱うからです。

例 :

```python
word = "apple"
for char in word:
    print(char)
```

結果

```python
a
p
p
l
e
```

このようにPythonの文字列ループの中では、文字列は一文字ごとに分割して扱われます。
このイテラブルな特性は便利で、これまでにも無意識に活用してきました。

しかし、先ほどのように`+=` した場合、一文字ずつ単独で取り出して格納する結果を招くことになります。
文字列全体を1つの要素としてリストに格納したい場合はappend()を使う必要があります。


# 文字列全体をリストに追加したければ、appendを使うべし
問題のあった箇所を修正します。

```python
# 単語をチェックして順番にリストに格納
for word in listed_words:
    word = word.lower()
    if "a" in word:
        filtered_words += word # 問題の発生箇所
```

```python
# 単語をチェックして順番にリストに追加
for word in listed_words:
    word = word.lower()
    if "a" in word:
        filtered_words.append(word)
```

# これってPython特有？

ほぼPythonしか触ったことがないのですが、ちょろっと遊びでphpをいじったときは、`+=`で文字列ごと代入できていました。
どうやらJavaScriptも+=で問題なくリストに追加できるようです。

Pythonでは文字列のイテラブルな特性により、`+=`の挙動が他の言語と異なります。

# おわりに

- 文字列全体をリストに追加したければ、appendを使う。
- str.split()はメソッドチェーンでまとめて書くこともできた

```python
words = input("任意の文字列を入力してください: ").split()
```


コーディング学習、一歩ずつ進んでいきます🦏
eye-candyなSDDMのテーマ【eucalyptus-drop】

# 設定後の見た目
背景の画像は、「ぼっち・ざ・ろっく！」の公式サイトから拝借しています。

https://bocchi.rocks/tv/special/present_ep12/

![Screenshot_20250304_210946.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3735823/85f2c35f-93e8-4df5-ab8a-8cd9f1318d75.png)
いい感じです。

# 環境
Arch Linux（カーネルバージョン：6.13.5.arch1-1）
SDDM 0.21.0-6
sddm-eucalyptus-drop 2.0.0-1

# 今回使うテーマ
eucalyptus-dropという名前のテーマです。「drop」という名前から連想できるように、eye candy（目の保養）を重視したテーマです。

# 環境構築
```
# pacman -S sddm
$ git clone https://aur.archlinux.org/sddm-eucalyptus-drop.git
$ cd sddm-eucalyptus-drop
$ makepkg -sirc
```
AURのビルドも一瞬で終わります。特に詰まるところはないと思います。

https://gitlab.com/Matt.Jolly/sddm-eucalyptus-drop/

レポジトリを見れば分かるように、デフォルトでは、森林の画像が背景になっていて、画面左側に入力欄があり、色はシンプルな組み合わせになっています。きれいですね。

# 設定
https://wiki.archlinux.jp/index.php/SDDM#.E7.8F.BE.E5.9C.A8.E3.81.AE.E3.83.86.E3.83.BC.E3.83.9E

テーマの変更は、ArchWikiを参照してください。
テーマ自体の設定は、`/usr/share/sddm/theme/eucalyptus-drop/theme.conf`を書き換えることで行います。
背景画像をダウンロードしたら、画像を`/usr/share/sddm/theme/eucalyptus-drop/Background`ディレクトリに移動します。その後、`theme.conf`を編集して背景画像を変えます。
```
Background="Backgrounds/dcep12_pc.png"
```
パスワード等を入力する位置を左から右に変更して、虹夏ちゃんとぼっちちゃんが隠れないようにします。
```
FormPosition="right"
```
デザインには疎いので、以下のサイトを参考にして配色を決めていってみます。

https://ironodata.info/rgb.php?color=FFB400

テキストなどの色を変更します。
```
MainColour="#D980FF"
```
ボタンにカーソルを合わせたときなど、ハイライトされたときの色を変更します。
```
AccentColour="#B35794"
```
年月日の表示形式を変更します。
```
DateFormat="yyyy/M/d (ddd)"
```
以上で設定完了です。

# おわりに
めちゃめちゃきれいなテーマなので、ぜひ試してみてください。
Gradioの細かいお話（便利ツールと環境変数の設定法が変わった話）

# 概要
__たぶん誰もまとめていないので細かい話だがまとめておいた__
　①リアルタイムなログ表示
　②環境変数の名称、たぶん変わりました

# リアルタイムなログの表示
・Gradioはリアルタイムなログの表示などが不得意
・力業でどうにかする事もできるが、かなり面倒。

https://github.com/gradio-app/gradio/issues/2362


・最近良いライブラリが出てた（経緯は上のissueに記載されてる。pypi登録済。）

https://github.com/louis-she/gradio-log

・頑張ればterminalの内容を全部表示できる
__※表示できるログは1Mが上限っぽい（公式にも記載無い__


# 環境変数の名称、たぶん変わりました
・公式を見ると、ネット記事と違った（コードも下のに変わってた。当然だが。）

https://www.gradio.app/guides/environment-variables

__・前：SERVER_PORT -> 今：GRADIO_SERVER_PORT__
__・前：SERVER_NAME -> 今：GRADIO_SERVER_NAME__
実務でreactを触り始めて１年、学習で役立った記事・資料紹介

## はじめに

アサインした案件でReactを使い始めて一年ほど経過し、その中で参考になった記事や動画を紹介していきます。
これからReactを始める方の何かご参考になれば嬉しいです。

## React公式

React を学ぶなら、まず公式ドキュメントから始めるのが最も効率的。書籍や記事を読む前に、ここで基本的な概念を押さえることで、よりスムーズに React を理解することができる。公式ドキュメントをしっかり読み進めれば、初心者を脱するための十分な知識が得られます。

https://ja.react.dev/learn

## You and 120% Cleaner React
Reactの初心者が陥りがちなアンチパターンを徹底的に解説した記事で、コードの可読性やメンテナンス性に悩んだ際はこの記事で紹介されているアンチパターンと照らし合わせると、リファクタリングのヒントが得られます。

https://zenn.dev/t_keshi/books/you-and-cleaner-react

## setLoading、駆逐してやる!!この世から...一匹残らず...!【進撃のデータフェッチ】

reactを使った際に一番悩んだ外部のAPIからとってきた値をどうやって取り扱うかの知見を得られる。上の記事と同じ人が書いていて、実際実務で外部APIからデータを取ってReactを使って反映させる部分で悩むところがまとまっていて興味深く読めた。APIとのやり取りは紹介されているようなライブラリを使うか、React19からだと[useTransition](https://ja.react.dev/blog/2024/12/05/react-19)だったり[useSyncExternalStore](https://zenn.dev/hakoten/articles/d94030e0a7b576)あたりが使われてきそうだが、そもそもこれらの欲しくなる背景が見やすくなるので、理解が深まる助けになると思います

https://zenn.dev/t_keshi/articles/attack-on-react-query#api%E3%81%A8%E3%81%AE%E3%82%84%E3%82%8A%E3%81%A8%E3%82%8A%E3%82%92%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%81%AB%E4%BF%9D%E3%81%A1%E3%81%AA%E3%81%8C%E3%82%89%E3%80%81%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E4%BD%93%E9%A8%93%E3%82%92%E5%90%91%E4%B8%8A%E3%81%95%E3%81%9B%E3%82%8B%E6%96%B9%E6%B3%95

## [MUIの公式ドキュメント](https://mui.com/material-ui/all-components/)
業務で使っている有名UIフレームワークの公式。MUIを使わなくても、自分でUIコンポーネントを作る際の参考になりそうなので紹介。例えばボタンのコンポーネントを作る際に、どんな機能が必要そうかなどが読み取る助けになる。
業務でMUIを使っていて、欲しいと思った機能はドキュメントに大抵書いてあるので、UIコンポーネントに求められ、実装して欲しいと言われる可能性のあるものは網羅されていると思われます。


## Code Tips
TypeScript+Reactを使う上での実践的なテクニックを解説したYouTubeチャンネル。
1本あたり約10分くらいの短時間で学べるため、実務での疑問点をピンポイントで解決するのに役立ちます。

https://www.youtube.com/@%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0

### 【React Hooks入門】完全初心者OK！8種類のHooksを学んでReactの理解を深めよう

Reactの開発において避けては通れない Hooks の基本をハンズオン形式で学べる動画です。Reactの入門知識を一通り学んだ後、より深く理解するために最適です。

https://www.youtube.com/watch?v=uuAdVs7sbAs

また、Udemyでは同じ作者による詳細なHooks講座もあります。より実践的な内容を体系的に学びたい方におすすめです。

[【完全保存版】React Hooksを完全に理解するHooksマスター講座【React18~19対応】](https://www.udemy.com/course/react-hooks-complete-course/?srsltid=AfmBOoq0u5jyYEmJ6vQHnNhCcwsKaFgAE4fceIHNQDljxVfpO3iETW4K)

## 『りあクト！』シリーズ。
会話形式でReactの環境構築から応用まで解説してくれる技術系の同人誌。普通のReact解説書と比べ、Reactがこういった進化を経て今こうなっているといった歴史的背景を含めて解説してくれるので、普通に興味深いし、よりReactを深く知れるのでおすすめ。

https://oukayuka.booth.pm/

## まとめ
Reactはデファクトスタンダードなライブラリであり、情報が豊富に存在します。ただし、リファレンスを漠然と眺めるだけでは、実務に適用しにくいこともあります。
今回紹介した記事や動画を活用しながら、基礎を固めつつ、実務での課題解決につなげていただければと思います。
これからReactを学ぶ方や、より効率的な実装を目指す方の参考になれば幸いです。
Terraform 入門：Terraformを使って東京リージョンにEC2インスタンスを構築して接続してみた

## はじめに
Terraformを使用して、AWSの東京リージョン（ap-northeast-1）にEC2インスタンスを構築する方法を解説します。

Terraformを使うことで、インフラをコード化し、簡単に管理・再現することができます。

## 前提条件
Terraformを使用するために、以下の環境が整っていることを確認してください。

1. Terraformがインストールされていること
2. AWS CLIがインストールされ、認証情報が設定されていること (`~/.aws/credentials`)
3. AWSアカウントを持っていること
4. 事前にSSHキーペアを作成していること（EC2インスタンスに接続するため）

## Terraformの設定
TerraformでEC2インスタンスを作成するために、`main.tf`ファイルを作成します。

### `main.tf`
```hcl
provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_instance" "my_ec2" {
  ami           = "ami-072298436ce5cb0c4" # 指定されたAMI ID
  instance_type = "t2.micro"             # 無料枠で利用可能なインスタンスタイプ
  key_name      = "my-key-pair"          # 事前に作成したキーペア（適宜変更）
  security_groups = ["default"]          # デフォルトのセキュリティグループを使用

  tags = {
    Name = "Terraform-EC2"
  }
}
```

## Terraformの実行手順

### 1. Terraformの初期化
まず、Terraformの初期化を行います。
```sh
terraform init
```

### 2. 設定の確認（オプション）
Terraformの設定を適用する前に、どのような変更が加えられるかを確認できます。
```sh
terraform plan
```

**実際のターミナル画面**

![Screenshot 2025-03-04 at 21.26.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/60c30355-ea0e-493d-84f5-f872a7f77a91.png)

### 3. EC2インスタンスの作成
以下のコマンドで、Terraformの設定を適用し、EC2インスタンスを作成します。
```sh
terraform apply -auto-approve
```

**実際のターミナル画面**

![Screenshot 2025-03-04 at 21.30.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/f18bd1d8-1021-4e81-a95e-535f98a03edc.png)

### 4. 作成されたインスタンスの情報を確認
Terraformで作成されたリソースの詳細を表示できます。
```sh
terraform show
```

**実際のターミナル画面**

![Screenshot 2025-03-04 at 21.31.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/712c1c63-7230-4548-a906-3343496ac45f.png)

## 作成したEC2インスタンスの管理

### インスタンスへのSSH接続
作成したEC2インスタンスにSSHで接続するには、以下のように実行します。
```sh
ssh -i my-key-pair.pem ec2-user@<インスタンスのパブリックIP>
```

**実際のターミナル画面**

![Screenshot 2025-03-04 at 21.33.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/53d4d56f-a3b2-44ff-a297-319c90a70400.png)

### EC2インスタンスの削除
不要になったインスタンスを削除するには、以下のコマンドを実行します。
```sh
terraform destroy -auto-approve
```

**実際のターミナル画面**

![Screenshot 2025-03-04 at 21.35.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/780796e3-1eb1-46fa-bcac-7ff5a3cbadc9.png)

## 注意点
- `key_name = "my-key-pair"` の値は、事前に作成したSSHキーペアに変更してください。
- セキュリティグループの設定をカスタマイズする場合は、別途`aws_security_group`リソースを作成してください。
- AMI ID（`ami-072298436ce5cb0c4`）は変更される可能性があるため、最新のものをAWSコンソールなどで確認してください。

## まとめ
Terraformを使うことで、簡単にEC2インスタンスを作成・管理することができます。

今回紹介した手順をベースに、セキュリティグループやIAMロールの設定を追加して、より実用的な環境を構築してみてください。
引っ越し！Miniconda を使った仮想環境の移行(≒共有)方法

## はじめに

Python の開発では、プロジェクトごとに異なるライブラリを管理するために仮想環境を活用するのが一般的です。しかし、開発環境を別の PC に移したり、チームメンバーと同じ環境を共有したりする際に、環境の再現性を確保するのが難しくなることがあります。

そこで、本記事では **Miniconda** を使用して、既存の仮想環境を `environment.yml` にエクスポートし、それを別の PC で復元する方法の一例を解説します。

## 目次
[仮想環境とは？](#仮想環境とは)
[Miniconda を使った環境の移行手順](#miniconda-を使った環境の移行手順)
[まとめ](#まとめ)

## 仮想環境とは？

仮想環境とは、Python のパッケージやライブラリをプロジェクトごとに分離して管理できる仕組みです。仮想環境を利用することで、以下のようなメリットがあります。

### **仮想環境のメリット**

1. **プロジェクトごとに異なるライブラリのバージョンを管理できる**
    - 例えば、A プロジェクトでは `numpy==1.19`、B プロジェクトでは `numpy==1.23` というように、異なるバージョンを利用可能。
2. **環境の再現性を確保できる**
    - `environment.yml` を利用することで、同じ環境を他の PC で簡単に再現できる。
3. **システム環境への影響を抑えられる**
    - Python のグローバル環境を汚さず、開発ができる。

## **Miniconda を使った環境の移行手順**

以下の手順で、Miniconda の仮想環境をエクスポートし、別の端末で復元します。

### **1. 既存の仮想環境を `environment.yml` にエクスポート**

まず、現在の仮想環境を確認します。

```bash
conda info --envs
```

対象の仮想環境名（例: `venv`）を確認したら、次のコマンドで `environment.yml` を作成します。

```bash
conda env export --name 仮想環境名 > environment.yml
```

> environment.yml には Python のバージョンやインストールされたパッケージ情報が含まれます。
> 

---

### **2. `environment.yml` を GitHub にアップロードして別の端末で取得**

作成した `environment.yml` を GitHub リポジトリを使用して環境ファイルを共有します。以下の手順で GitHub にアップロードし、別の端末でクローンできます。

```bash
git add environment.yml
git commit -m "Add environment file"
git push
```

別の端末で、リポジトリをクローンして `environment.yml` を取得できます。

```bash
git clone https://github.com/ユーザネーム/リポジトリ名.git
cd リポジトリ名
```

---

### **3. Miniconda のインストール（別端末）**

新しい端末に Miniconda をインストールします。

### **Linux/macOS の場合**

```bash
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh
```

### **Windows の場合**

Miniconda の公式サイトからインストーラーをダウンロードして実行します。

https://www.anaconda.com/docs/getting-started/miniconda/main

---

### **4. `environment.yml` から仮想環境を復元**

 `environment.yml` を使って、新しい端末で仮想環境を作成します。

```bash
conda env create -f environment.yml
```

> もし既に同じ環境名がある場合は、削除してから作成してください。
> 

```bash
conda remove --name 仮想環境名 --all
```

環境が作成できたら、以下のコマンドで仮想環境をアクティブにします。

```bash
conda activate 仮想環境名

# 仮想環境を非アクティブにする場合
conda deactivate
```

---

### **5. 環境が正しく復元されたか確認**

仮想環境が正しく復元されているか確認するために、以下のコマンドを実行します。

```bash
conda info --envs
conda list
python3 --version
```

---

## **まとめ**

- **環境のエクスポート**

```bash
conda env export --name 仮想環境名 > environment.yml
```

-  **環境のインポート**

```bash
conda env create -f environment.yml
```

- **環境のアクティブ化**

```bash
conda activate 仮想環境名

# 仮想環境を非アクティブにする場合
conda deactivate
```

これらの手順を使えば、開発環境を簡単に再現でき、チームメンバーとの環境共有もスムーズになります。Python のプロジェクトを効率的に管理するために、ぜひ活用してください！
74hc4052の使い方

74hc4052aは汎用IC、74ファミリーのアナログマルチプレクサです。
74ファミリーのアナログマルチプレクサは74hc4051~74hc4053まで3種類あります。
見本として秋月で売っているTC74HC4052APを使用します。

https://akizukidenshi.com/catalog/g/g111422/

ちなみに74ファミリーの命名規則は下記の表の通りです。
|TC|74HC|4052|A|P|
|:-:|:-:|:-:|:-:|:-:|
|企業|ファミリー|論理回路|特性|パッケージ|
|東芝|High-speed CMOS|アナログマルチプレクサ|通常品|DIP|

アナログマルチプレクサとはいわば切り替えスイッチのようなものです。
2進数で0~3までA,Bに入力し、その数字に対応したpinとCOMピンが接続されます。
それが2回路は言っています。つまり、
|入力値|INH|B|A|X-com|Y-com|
|:-:|:-:|:-:|:-:|:-:|:-:|
|0|1|0|0|0X|0Y|
|1|1|0|1|1X|1Y|
|2|1|1|0|2X|2Y|
|3|1|1|1|3X|3Y|
|/|0| | |/ |/ |

Aが1の位、Bが2の位になることに注意してください。
INHpinをLOWにすると、すべての出力端子がLOWになります。

入出力ピン(0X~3X、0Y~3Y)とCOMピン(X-com、Y-com)は双方向に、アナログ電圧を印加することができます。


#### その他のアナログマルチプレクサ
74HC4051は、74HC4052と違い、0~7までをA,B,Cに入力し、COMピンと0~7が接続されます。
74HC4053は、0~7までをA,B,Cに入力し、COMピン(X-com、Y-com、Z-com)と入出力ピン(0X,1X,0Y,1Y,0Z,1Z)が接続されます。

## 実験

555を用いた交流信号をY-comピンに入力し、A,Bの値を変化させ、0Y~3Yピンを観測します。

今回は交流信号を入力するのでVEEに-5を印加していますが、0V~5Vの信号のみを扱うのならばGNDに接続してかまいません。

X、X-comは使わないので5Vにつけておきます。GNDでも構いません。

![スクリーンショット 2025-03-04 203742.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3922522/8d4d109e-75a8-4b0b-8584-0d4f0cb1c21e.png)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3922522/d48cf56c-8fed-4b64-9cf1-2ea8d96b5091.jpeg" width="170">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3922522/65565811-fe3b-477c-8282-e78a402d7bc2.jpeg" width="170">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3922522/0f4f0944-58a8-4d22-8d49-7357ce474ecd.jpeg" width="170">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3922522/264d28bb-0c92-4b28-9a97-61fdaf6bc76c.jpeg" width="170">

4chオシロ()でしっかりと波形を観測できました。
多少乱れはありますがおそらくただの接触不良なので大丈夫です。

## 終わりに
このブログは記憶力皆無の未来の私に向けたものなので、わからない部分があるかもしれません。
ゆるして
【備忘録】戻り値がCreateAccountUseCase型指定なのにcreateAccountInteractor型を返しても良い理由

# 問題のコード
```go
func NewCreateAccountInteractor(
	repo domain.AccountRepository,
	presenter CreateAccountPresenter,
	t time.Duration,
) CreateAccountUseCase {
	return createAccountInteractor{
		repo:       repo,
		presenter:  presenter,
		ctxTimeout: t,
	}
}
```
フルのコード

https://github.com/GSabadini/go-clean-architecture/blob/master/usecase/create_account.go

# **ポイント1：インターフェースとは？**
Goのインターフェースは「メソッドの集合」のこと。  
つまり、**特定のメソッドを持っていれば、その型はインターフェースを実装しているとみなされる**。

```go
type CreateAccountUseCase interface {
    Execute(context.Context, CreateAccountInput) (CreateAccountOutput, error)
}
```
- **`CreateAccountUseCase` は `Execute` メソッドを持っているものを指す。**
- 明示的に `implements` とは書かない。

---

# **ポイント2：`createAccountInteractor` は `Execute` を持っている**
```go
type createAccountInteractor struct {
    repo       domain.AccountRepository
    presenter  CreateAccountPresenter
    ctxTimeout time.Duration
}

func (a createAccountInteractor) Execute(ctx context.Context, input CreateAccountInput) (CreateAccountOutput, error) {
    // 実装
}
```
- `createAccountInteractor` には `Execute` メソッドがある。
- だから、**Goの型システムが「この構造体は `CreateAccountUseCase` を満たしている」と認識する**。

func(a createAccountInteractor)...の文法については以下を参照

https://qiita.com/ryo_manba/items/c567858befd04602e3ec


---

# **ポイント3：`NewCreateAccountInteractor` の戻り値**
```go
func NewCreateAccountInteractor(
    repo domain.AccountRepository,
    presenter CreateAccountPresenter,
    t time.Duration,
) CreateAccountUseCase {
    return createAccountInteractor{ // ここで構造体を返している
        repo:       repo,
        presenter:  presenter,
        ctxTimeout: t,
    }
}
```
- `CreateAccountUseCase` は `Execute` を持つものならOK！
- `createAccountInteractor` は `Execute` を持っているのでOK！
- **だから、`createAccountInteractor` を返してもエラーにならない。**

---

# **わかりやすい例**
## **例1：シンプルなインターフェースと構造体**
```go
package main

import "fmt"

// インターフェース
type Speaker interface {
    Speak() string
}

// 構造体
type Person struct {
    Name string
}

// `Person` は `Speaker` を実装している
func (p Person) Speak() string {
    return "Hello, my name is " + p.Name
}

// `Speaker` を返す関数
func NewPerson(name string) Speaker {
    return Person{Name: name} // Personを返しているけどOK
}

func main() {
    var s Speaker = NewPerson("Alice")
    fmt.Println(s.Speak()) // "Hello, my name is Alice"
}
```
- `NewPerson` は `Speaker` 型を返すと言っている。
- `Person` は `Speak` を持っているので、Goの型システムが「これは `Speaker` を満たしている」と判断。
- **だから `Person` を `Speaker` として返してもOK！**

---

## **例2：ポインタを使う場合**
```go
func NewPerson(name string) Speaker {
    return &Person{Name: name} // ポインタを返す
}
```
- `&Person{}` にすると、ポインタを返すことになる。
- `Speaker` にポインタが必要な場合はこうする。

---

# **結論**
**`createAccountInteractor` は `Execute` を持っているから `CreateAccountUseCase` を満たす。**  
**だから、`CreateAccountUseCase` を返す関数で `createAccountInteractor` を返しても問題ない！**
Excel VBA 自动选择所有表的A1单元格

### 将Excel内部所有表的格子选择在A1单元格，增加美观度

```
Sub SetSelectA1()
    Dim wss As Worksheet
    
    For Each wss In ThisWorkbook.Worksheets
        wss.Activate
        wss.Cells(1, 1).Select
    Next wss
    '最初のシートを選択する（最初に戻す）
    Worksheets(1).Activate
End Sub
```