OmniAICreator/Qiita-1.07M huggingface dataset:
SOLID原則は関数型プログラミングでも原則として利用できるか？

SOLID原則は本来、オブジェクト指向プログラミング（OOP）における設計指針として広く知られています。

しかし現代では、JavaScriptやTypeScriptなど、関数型の考え方を取り入れた言語が広く使われており、OOP以外の文脈でも「設計原則」が求められます。

本記事では、これまでのシリーズで扱ってきた **OOPと関数型プログラミング（FP）における設計原則の比較** を振り返りつつ、「関数型におけるSOLID原則の活用」についてまとめました。

## 📚 比較シリーズのリンク

各原則について、OOPとFPの具体的な実装例を交えて比較しています。  
詳しくは以下をご覧ください。

- 🟢 [SRPにおけるOOPとFPの比較](https://qiita.com/bonji/items/f164519a54d59ac9526a)
- 🔵 [OCPにおけるOOPとFPの比較](https://qiita.com/bonji/items/b8ba95e4af8e5dbb70d2)
- 🟣 [LSPにおけるOOPとFPの比較](https://qiita.com/bonji/items/d5a016a8978ab61b3947)
- 🟠 [ISPにおけるOOPとFPの比較](https://qiita.com/bonji/items/6060ec1fa721e0e5b89c)
- ⚫️ [DIPにおけるOOPとFPの比較](https://qiita.com/bonji/items/4aa41cbe3bb40a00428e)


## ✅ 各原則ごとの比較（OOP vs FP）

| 原則 | OOPの視点 | FPの視点 |
|------|-----------|----------|
| **SRP**（単一責任の原則） | クラス単位で責務を分離 | 関数単位で副作用を分離 |
| **OCP**（開放/閉鎖原則） | 継承やポリモーフィズムで拡張 | 関数マップやデータ駆動で拡張 |
| **LSP**（リスコフの置換原則） | 意味的な継承関係に注意 | 型ガードと構造で安全性を確保 |
| **ISP**（インターフェース分離原則） | 不要な機能を含まない分離 | 必要な関数だけを組み合わせる |
| **DIP**（依存性逆転の原則） | インターフェースと依存注入 | 高階関数や引数で依存を注入 |

## 共通点と違い

- 両者とも「責務の分離」「拡張性の確保」「テスト容易性」など設計上の **ゴールは共通** している。
- 抽象化
   - OOPは 構造（クラスやインターフェース）で抽象化し、
   - FPは関数とデータで抽象化する。
- FPでは、状態を持たない分、**副作用を外部から注入する形で「責務」を柔軟に管理** できる。

## 🔍 では、FPでも有効か？

結論から言えば、 **「YES」** です。

関数型プログラミングではクラスやインターフェースを使わない代わりに、**関数の合成、型による分離、副作用の管理**といった手法で、SOLIDの各原則が自然と達成される場面が多くあります。

OOPとFPでは表現方法が異なるものの、**「設計の目的」** は共通しています。  
つまり、**保守しやすく、拡張性の高い、明確な責務を持つ構造を作ること**です。



## 🚀 まとめ

- SOLID原則はOOPの文脈で誕生しましたが、その精神は**関数型プログラミングでも活用可能**です。
- 重要なのは **「原則を形だけで捉えるのではなく、目的を理解して応用すること」** です。
- TypeScriptやJavaScriptのようなパラダイム横断的な言語において、**両者の視点を学ぶことは設計力を高める**ことに繋がります。

📖 本記事が参考になったら、VitePressによる全体まとめサイトもぜひご覧ください*ฅ´ω`ฅ*

https://shuji-bonji.github.io/Notes-on-SOLID-Principle/
依存性逆転の原則（DIP）における関数型の応用

依存性逆転の原則（DIP: Dependency Inversion Principle）は、「上位モジュールは下位モジュールに依存すべきではない。両者は抽象に依存すべきである」という考え方です。
OOPではインターフェースと依存性注入（DI）を通じてこの原則を実現しますが、関数型プログラミングにおいても、関数と高階関数を用いてこの原則を適用することができます。


## OOPにおけるDIPの典型例

```ts
interface Logger {
  log(message: string): void;
}

class ConsoleLogger implements Logger {
  log(message: string): void {
    console.log(message);
  }
}

class Application {
  constructor(private logger: Logger) {}

  run() {
    this.logger.log('Application started');
  }
}

const app = new Application(new ConsoleLogger());
app.run();
```

- `Application` は `Logger` という抽象に依存しており、`ConsoleLogger` に直接依存していません。
- これにより、テスト用のモックロガーなど、他の実装と容易に差し替えが可能です。


## 関数型におけるDIPの応用

関数型では「関数を依存対象として注入する」ことでDIPの考え方を自然に実現できます。

```ts
type Logger = (message: string) => void;

const consoleLogger: Logger = (msg) => console.log(msg);

const runApplication = (logger: Logger) => {
  logger('Application started');
};

runApplication(consoleLogger);
```

- `runApplication` は `Logger` 関数に依存しており、具体的な出力方法には依存していません。
- テスト時には以下のように差し替えることができます：

```ts
const testLogger: Logger = (msg) => {
  // メッセージを配列などに記録することで検証できる
  logs.push(msg);
};
```


## 比較まとめ

| 観点 | OOP | FP |
|------|-----|----|
| 抽象化の単位 | インターフェース | 関数の型 |
| 依存性の注入 | コンストラクタやSetterなど | 関数引数として渡す |
| 拡張性 | 実装クラスの追加で対応 | 別の関数を注入することで対応 |
| テスト容易性 | モックオブジェクトの注入 | テスト用関数の差し替え |
| 注意点 | 抽象と具象のバランス | 関数の引数が多くなると読みにくいこともある |


関数型でも、責務分離や抽象化を適切に設計することで、依存性逆転の原則を自然な形で実現できます。

最後に、以下まとめてみましたので、ご興味があれば参考までに(=ﾟωﾟ)ﾉ

[SOLID原則は関数型プログラミングでも原則として利用できるか？](https://qiita.com/bonji/items/6c721f987ca5e21d6d9a)
FLSの設定でプロファイルでなくて、権限セットが表示されている


+ [プロファイルの操作の問題](https://qiita.com/Keiji_otsubo/items/dce4cb783ada9c6118ea)
+ [ベータ版だった時代](https://qiita.com/Keiji_otsubo/items/7853ac6806d7fa841c64#fls%E3%81%AE%E8%A8%AD%E5%AE%9A%E3%81%A7%E3%83%97%E3%83%AD%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%A7%E3%81%AA%E3%81%8F%E3%81%A6%E6%A8%A9%E9%99%90%E3%82%BB%E3%83%83%E3%83%88%E3%81%8C%E8%A1%A8%E7%A4%BA%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B)


現在は正式対応で、Spring 25のプレイグランドはこの設定になっているので注意

+ [Hello Trailblazers, Whenever i create any field for any standard or custom object it automatically hidden for all the users even for system administrator. Do you have any permanent solution for this ?](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000PYuAz)

:::note
Please check if this setting is disabled.

SETUP -->  User Management Settings 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/4ae1ffd8-73a1-4e8f-8da1-892f446fca37.png)
:::

# 解答例

+ [Field Level Security in Permissions Sets?](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000PZ3RB)
+ [I am getting this error The field 'Property__c' either does not exist on the Offer__c object or it is not a Master-Detail relationship.Please can someone help me figure out what i amdoing wrong](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000PZ3UK)
Java解説 20250423

### Javaはmainメソッドから実行される
mainメソッド構文：public static void main(String[] args)
### 文字列はダブルクォートで囲む
例："あいうえお"
### Javaのデータ型は、基本データ型、参照型の2つがある
基本データ型：int、long等
参照型：クラス、インターフェース等
<br>
[オラクル認定資格教科書 Javaプログラマ Bronze SE(試験番号1Z0-818)](https://www.amazon.co.jp/%E3%82%AA%E3%83%A9%E3%82%AF%E3%83%AB%E8%AA%8D%E5%AE%9A%E8%B3%87%E6%A0%BC%E6%95%99%E7%A7%91%E6%9B%B8-Java%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E-Bronze-SE-%E8%A9%A6%E9%A8%93%E7%95%AA%E5%8F%B71Z0-818/dp/479816206X/ref=pd_lpo_d_sccl_1/357-5313211-9846263?pd_rd_w=VQCzo&content-id=amzn1.sym.855d8f70-df76-4181-80b0-56e48ae3bb9b&pf_rd_p=855d8f70-df76-4181-80b0-56e48ae3bb9b&pf_rd_r=JRR4W9RKV32K4AXF1WRZ&pd_rd_wg=l7VoD&pd_rd_r=1d465f85-0562-4b51-b523-77f8486c1508&pd_rd_i=479816206X&psc=1 "オラクル認定資格教科書 Javaプログラマ Bronze SE(試験番号1Z0-818)")
docker 基本的なコマンドまとめ

備忘録としてdockerのコマンドをまとめました

docker image　をダウンロードする
```
docker image pull [イメージ名]
```
タグを指定してイメージをダウンロード
```
docker image pull [イメージ名]:[タグ名]
```

Dockerfileからdocker imageを作成
```
docker image build [ビルドコンテキストのパス]
```

docker image に名前とタグをつける
```
docker image build -t [イメージ名]:[タグ名]
```

Dockerfileを指定するオプション
```
docker image build -f [Dockerfileのパス] [ビルドコンテキスト]
```

docker image の一覧を表示
```
docker image ls
```

docker image の破棄
```
docker image rm [イメージ名(イメージIDでも可
```

docker image の詳細な情報を確認
```
docker image inspect [イメージ名]
```

docker image のレイヤーを確認
```
docker image history [イメージI]
```

docker コンテナを作成、起動する

```
docker container run [イメージ名]
```

docker コンテナ名の名前を指定して起動
```
docker container run --name [つける名前] [イメージ名]
```

docker container実行後にコンテナを破棄する
```
docker container run --rm [イメージ名]
```

docker コンテナの一覧を表示
-aオプションで起動していないコンテナも表示
```
docker container ls 
```

docker containerを停止
```
docker container stop [コンテナIDまたはNAME]
```

docker containerを再起動(upに)する
```
docker container restart [コンテナ名]
```

docker containerを破棄する
exitedのコンテナにのみ有効　-fオプションで起動中のコンテナも破棄可能。

```
docker contaner rm [ID、コンテナ名]
```

-itオプションについて
--i (interactive):コンテナに対して標準入力を開く
-t (tty):仮想端末（TTY）を割り当てる(きれいに表示される)
-d デタッチドモードで実行（ターミナルで他の作業が可能になる）

```
docker container -it ubuntu:20.04
```

起動中のコンテナでコマンドを実行する

```
docker container exec [コンテナ名] [コマンド]
```
例：コンテナにログインする
docker container exec -it 3eed439d3731 /bin/bash

exitedのコンテナを全て削除
```
docker container prune
```

デタッチドモードのコンテナにアクセス（フォアグラウンドモード）する
```
docker container attach
```

ボリュームに接続しながらコンテナを起動する。以下２つ
```
docker container run -v [vol名]:[コンテナ内絶対パス] [イメージ名]
```

```
docker container run --mount type=volume src=[vol名],dst=[コンテナ内絶対パス] [イメージ名]
```

バイマウントしながらコンテナを起動する
```
docker container run -v [ホスト絶対パス]:[コンテナ内絶対パス] [イメージ名]
```

```
docker container run --mount type=volume src=[ホスト絶対パス],dst=[コンテナ内絶対パス] [イメージ名]
```

ホストとコンテナのポートを紐づける
-pオプションを使用する

```
docker container run -p [ホスト側のポート]:[コンテナ側のポート] [イメージ名]
```

指定したネットワークに接続したコンテナを起動する
```
docker container run --network [ネットワーク名] [イメージ名]
```

## docker ストレージ

ボリュームは複数のコンテナから接続できる
独立して存在しているのでコンテナを削除しても存在し続ける

新しいボリューム領域を作成する

```
docker volume create
```

ボリューム領域一覧を表示する
```
docker volume ls
```

指定したボリューム領域の詳細情報を表示する
```
docker volume inspect [ボリューム名]
```

指定したボリューム領域を削除する

```
docker volume rm [ボリューム名]
```

## docker ネットワーク

ネットワークの一覧を表示する
```
docker network ls
```

ネットワークの詳細情報を表示する
```
docker network inspect bridge
```

ネットワークを作成する
```
docker network create [ネットワーク名]
```

ネットワークを削除する
```
docker network rm [ネットワーク名]
```


## docker compose

docker-compose.ymlを実行する
```
docker compose up
```

docker イメージ書き方

https://qiita.com/gon0821/items/f9e3bcbb6cb01d4ef7fa

docker-compose.yml書き方

https://qiita.com/yuta-ushijima/items/d3d98177e1b28f736f04

docker コマンド一覧

https://www.kagoya.jp/howto/cloud/container/dockercommand/
アドセンスの有用性の低いコンテンツを回避するには？

# 【初心者向け】アドセンスの「有用性の低いコンテンツ」警告を受けた時の改善方法まとめ

Googleアドセンスに申し込んだら、「**有用性の低いコンテンツ**」という理由で不合格に…。  
こんな経験ありませんか？

この記事では、「有用性の低いコンテンツ」ってそもそも何？という基本から、合格するために実際にやるべき改善ポイントまで、わかりやすく解説します！

---

## ✅ 有用性の低いコンテンツって何？

Googleアドセンスの審査では、「訪問者にとって有益な情報が提供されているか」がとても大事です。

「有用性の低いコンテンツ」というのは、例えばこんな状態のブログです：

- 内容が薄い（情報が少ない、独自性がない）
- 他のサイトと似たようなことしか書いていない
- 誰に向けて書いてるのか分からない
- 記事数が極端に少ない
- デザインが整っていない or 広告目的だけのページ

---

## 🔧 改善するためにやるべき5つのこと

### ① 誰のための記事か明確にする
「誰に向けて書いているか」が曖昧だと、内容もぼやけてしまいます。  
たとえば「主婦向けの節約術」や「副業初心者向けのブログ開設方法」など、ターゲットをハッキリさせましょう。

### ② 独自の体験や意見を入れる
他サイトから集めた情報だけではダメです。  
自分の体験談や、実際に使ってみた感想、トラブルへの対処法など、「あなただけの視点」を加えることで、価値のある記事になります。

### ③ 文字数は目安として1000文字以上
内容によりますが、500文字程度だと情報量が少なすぎるかも。  
「読者の疑問を解決する」ことを意識して、しっかりと情報を提供しましょう。

### ④ 記事数は最低でも5〜10記事を目指す
1〜2記事ではアドセンスに通る可能性は低いです。  
まずはしっかり中身のある記事を5〜10本用意してから申請するのがおすすめ。

### ⑤ 見やすく整える（画像・見出し・装飾）
文章ばかりだと読むのが大変…。  
見出し（h2, h3など）を使って、章立てを分かりやすくしたり、画像や箇条書きを入れると、読者にもGoogleにも好印象です。

---

## 💡 プラスアルファでやると効果的なこと

- **プロフィール・お問い合わせフォーム・プライバシーポリシーを設置する**
  → サイトの信頼性がアップ！
  
- **検索キーワードを意識したタイトルにする**
  → SEO（検索エンジン対策）にも有効！

- **内部リンク・外部リンクを活用する**
  → 関連情報を補足して、記事の信頼性を上げよう。

---

## 📝 まとめ

アドセンスの「有用性の低いコンテンツ」エラーは、ちょっとした工夫と改善で解決できます！

**焦らずコツコツ、読者目線でコンテンツを充実させることが合格への近道**です。

---

## ✨ この記事が参考になったら

「いいね」や「シェア」で応援してもらえると嬉しいです！  
ブログ運営についての質問があれば、コメント欄かお問い合わせフォームからどうぞ😊

https://okaiage.com/
1分でグーグルクラウドにtorrentクライアントを立てる

違法ダウンロードダメ絶対

# 目標

Google Compute Engineにおいてqbittorrentを起動し、ブラウザから操作できる状態を目指す。
torrentとmagnet linkに対応している。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118083/7b4c28d9-ab7e-4f84-975c-df198caf829c.png)


## 1. Google Compute Engineから「インスタンスを作成」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118083/3eaa95ea-61d2-4d16-8263-3f6b1d809445.png)

## 2. マシン構成を選択

ここはデフォルトのまま進める

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118083/8167a437-3be4-4cf8-998f-c0e694cb7031.png)

## 3. OSとストレージを選択

- オペレーティングシステムはContainer Optimized OSを選択
- ディスクサイズは30GBを選択（ダウンロードしたいファイルのサイズ以上）

![screencapture-console-cloud-google-compute-instancesAdd-2025-04-23-07_09_49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118083/eaaa87c1-8908-4fa8-93ec-590ffe8eb018.png)

## 4. ネットワーキングを選択

- HTTPトラフィック許可とHTTPSトラフィック許可にチェック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118083/12aba3d6-afff-4c37-aced-c012bacc22a9.png)

## 5. 詳細タブから自動起動スクリプトを設定

以下のスクリプトをコピペすればよい

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118083/bbb83664-1ed5-4266-b3f5-73370ee7b636.png)

```bash
docker run -d --restart=on-failure -it -e PUID=1000 -e PGID=1000 -e TZ=Etc/UTC -e WEBUI_PORT=8080 -e TORRENTING_PORT=6881 -p 80:8080 -p 81:8081 -p 6881:6881 -p 6881:6881/udp --name main lzpel/myqbittorrent
```

## 6. 左下の作成ボタンをクリック

## 7. URLにアクセス

VM一覧に先ほど作成したVMが追加される。

外部IPをコピー(この例では`35.238.70.85`)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118083/8142fc5a-12f6-4989-9a3c-dffa6d39aabb.png)

外部IPの80番ポートにHTTPアクセス（この例では`http://35.238.70.85/`）
**直接クリックしたらHTTPSアクセスしてしまうのでURLをHTTPに直すことを忘れない**

するとこのようなqBitTorrentのログイン画面が出てくる

ここは Username admin Password adminadmin でログインできる（ようにDockerfileを書いた）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118083/0e1c7dda-a9be-4d9d-b22f-cf9ca5c2612e.png)

ログインしたらこんなWebUI

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118083/8959c89d-928e-47aa-928f-0f4b5532bf74.png)

**完成**

## 試しにダウンロードしてみる

LibraOfficeの公式Torrentをダウンロードする

ダウンロード先が/config/Downloadsであることを確認してUpload Torrentsボタンを押す

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118083/e90e698f-ece9-4e47-88d5-ede20577fc4b.png)

一瞬でダウンロードが完了する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118083/bbb6d5ee-6321-4f00-8649-0d6bcafd2a3b.png)

## ダウンロードしたファイルをローカルにダウンロード

qbittorrent単体にはファイルサーバーとしての機能が無い

そこで、Dockerfile(lzpel/myqbittorrent)においてベースイメージ(linuxserver/qbittorrent)をハックしてRust製静的ファイルサーバー[static-web-server](https://github.com/static-web-server/static-web-server)を同居させている

外部IPの81番ポートにHTTPアクセス（この例では`http://35.238.70.85:81/`）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118083/5dd56f0f-3bdb-49fc-b795-3db80c3cc91b.png)

上記リンクからダウンロードしたファイルを右クリック⇒名前を付けてリンク先を保存　でダウンロードできる
windows11で、sketchup6 その75

# 概要
windows11に、sketchup6を入れてみた。
rubyで、3Dを書く。
練習問題、やってみた。

# 練習問題
カプセルを描く、RUBYスクリプトを書け。


# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/39274c89-2482-4bc3-9872-8ef49e4599be.png)

# サンプルコード

```

def latheShape(rad, segs, edges)
	faces = []
	inc = 360.0 / segs
	0.step(360.0, inc) { |r|
		for e in edges
			t1 = Geom::Transformation.new(ORIGIN, Z_AXIS, r.degrees)
			t2 = Geom::Transformation.new(ORIGIN, Z_AXIS, (r + inc).degrees)
			pa = [e.vertices[0].position.transform!(t1), e.vertices[1].position.transform!(t1), e.vertices[1].position.transform!(t2), e.vertices[0].position.transform!(t2)]
			#puts f
			pa.uniq!
			faces.push(pa)
		end
	}
	return (faces)
end



def create_capsule(rad, hei, segs)
	grp = Sketchup.active_model.active_entities.add_group()
	ents = grp.entities
	arc1 = ents.add_arc([0, 0, rad], [1, 0, 0], [0, 1, 0], rad, 0.degrees, 90.degrees)
	arc2 = ents.add_arc([0, 0, hei - rad], [1, 0, 0], [0, 1, 0], rad, 270.degrees, 360.degrees)
	line1 = ents.add_line(arc1[0].vertices[0], arc2[arc2.length - 1].vertices[1])
	edges = arc1 + arc2 + [line1]
	faces = latheShape(rad, segs, edges)
	for face in faces
		begin
			f = ents.add_face(face)
		rescue
			face.delete_at(1)
			f = ents.add_face(face)
		end
		f.edges.each { |edge|
			edge.smooth = true;
			edge.hidden = true
		}
	end
	grp.name = "capsule"
	return(grp)
end





```

以上。
業務の効率を上げるためのお題　

# プログラミングできるようになったけど、業務でどう使用すればいいかわからない
私も陥りました。
 コードは読めるようになったけど、自分で何を作っていいのかわからない
今の実力だったらコードをよりも、めんどくさいけど手でやったほうが早いと
 そんな時、
 
:::note info
「もしその作業が繰り返し（3回以上）行うのであればプログラム書いたほうがいい」
:::
これを思ってください。その時のポイントは

:::note info
共通点をつける
:::

業務効率したいけど
こんなことやりたい！も思い浮かばない方のために業務効率できそうなお題をピックアップしました
ぜひ活用してみてください！


# 課題①　文字と文字の間に「、」をいれる
> １つ１つに「、」をつけるのがめんどくさなーっと思っている方へ

自社商品や社員名や都道府県　等　業務内で「、」を使い区分けしたい時に使用する。
以下に「、」を入れるコードを書いてください
```
北海道 青森県 岩手県 宮城県 秋田県 山形県 福島県 茨城県 栃木県 群馬県 埼玉県 千葉県 東京都 
神奈川県 新潟県 富山県 石川県 福井県 山梨県 長野県 岐阜県 静岡県 愛知県 三重県 滋賀県 
京都府 大阪府 兵庫県 奈良県 和歌山県 鳥取県 島根県 岡山県 広島県 山口県 徳島県 香川県 愛媛県 
高知県 福岡県 佐賀県 長崎県 熊本県 大分県 宮崎県 鹿児島県 沖縄県
```


:::note info
文字と文字の間に半角の空白がある　
→　１つの塊として読み込み（文字列）、半角の空白で「、」を入れるコード作成してみてください
:::


# 課題②　フォルダー名を付け直す
> フォルダー名に番号をつけなおしたいのに50件分ある。１つ１つつけ直すのめんどくさくない？って思っている方へ

以下の写真のフォルダー名を全て「スクリーンショット　-01‥-02」と順番にしてください
![スクリーンショット 2025-04-22 20.23.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636287/96e9d152-2e46-4123-9365-b95318ab01c7.png)



:::note info
日にちでソートし、「スクリーンショット」＋　数字　で名前をつける
→数字は読み込んだ合計数分for文で書いてみてください
:::



# 課題③　%を全角の％に書き変えたい
> 広告やポスターを作っており最終チェックで全角に書き直してほしいと言われた時の対応
```
開発したツールにより作業効率が25%向上し、ミス発生率は15%低下しました。
集計業務は50%短縮され、報告作成時間も20%削減。
さらに、定型作業の自動化により工数全体の10%を別業務へ再配分でき、
生産性の底上げに貢献しています。
```


:::note info
作ることは可能ですが、Excelで「Ctrl + H」のほうが早いことも。。。
:::



# 課題④　[Windows]決まった時間に特定のWEBサイトを出したい
>　 打刻のサイトを朝8時30分にだしたい

打刻のサイトを朝8時30分に自動で出すような設定をしてみてください

https://qiita.com/riicon72/items/24fe246c5341685499b7

:::note info
応用で、Pygui等で作成した別のプログラムを、.bat化しておき、定期実行したい時等にもおすすめ
:::



# 課題⑤　Excelデータのバックアップ方法
> Excelが急に落ちたり、バグったりするので定期的にバックアップを取りたい方へ

簡単にバックアップが取れる方法を出してみてください
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636287/75f79204-80c9-4099-97c2-e1589dfa6ad1.png" width=80%>


:::note info
ディレクトリを分けて保存するコードを書いてみてください
pythonで書く場合、.copy()等は使えます
:::





<a target="_blank" href="https://icons8.com/icon/117561/microsoft-excel-2019">マイクロソフトエクセル2019</a> アイコン by <a target="_blank" href="https://icons8.com">Icons8</a>
<a target="_blank" href="https://icons8.com/icon/13429/add-folder">フォルダーを追加</a> アイコン by <a target="_blank" href="https://icons8.com">Icons8</a>



# 最後に

少しでも繰り返し業務を減らして定時で帰りましょう！
XIAO ESP32C6+SSD1306、円を塗り潰して遊ぶ。


参考
----


https://qiita.com/mikecat_mixc/items/70bfe01555eb748f72d0


いろいろ、注意
----

- かころぐをみよ
- なぜか?アルゴリズム系は、アクセスが多い(愛好者がいる?)(パクリだけど、やや、ヒット)
- 例題の為の例題
- 1ビットの固定小数点を使っている(ある意味、今回のメインテーマ)
- なぜか、各CPUにほぼ、固定小数点系の命令は、付いているが、あまり、使われていない。(各言語でマクロレベル(なんの事))(保守性や互換性が下がる?)


目的
----

ピタゴラスの定理を使って円を塗りつぶす
c x c = a x a + b x b

結果
----

![o_coq878.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/747faf0f-58d5-470b-982f-9d75e828a740.jpeg)




プログラム


```c++



//OLED_SSD1331_enko_XIAO_ESP32C6


//ヘッダーファイル
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>


//定義
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);



void draw_circle_bad(int diameter) {

    // 円の中心の座標
    int cx = diameter / 2;
    int cy = diameter / 2;
    // 円の半径
    int radius = diameter / 2;
    // 円を描画する

  for(int y = 0;y < diameter;y++){
    for(int x = 0;x < diameter;x++){


      // 円の中心からの距離を計算・判定する
      // 0.5 を足し、ピクセルの中心で判定する
      int dx = (x<<1) + 1 - (cx<<1);
      int dy = (y<<1) + 1 - (cy<<1);

      if (  ((dx * dx) + (dy * dy)) <= ((radius<<1) * (radius<<1))  ) {
        // 円の中なので、点を描画する
        display.drawPixel(x,y,WHITE);
      }

    }
    delay(50);
    display.display();
  }
  
    // 描画バッファの内容を画面に表示
  display.display();

}


//初期化
void setup() {

  //I2Cの初期化
  Wire.begin(D9,D10); //XIAO ESP32C6+SSD1306
  //Wire.begin(D10,D9); //XIAO ESP32C6+GROVE

  // I2Cアドレスは使用するディスプレイに合わせて変更する
  display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);

}//setup


//メインループ
void loop() {

  // 画面表示をクリア
  display.fillScreen(BLACK);

  draw_circle_bad(30);

  delay(5000); //5秒待つ

}//loop



```
Module-LLMにて、PythonのNPU推論でエラーが出た場合の対処


Module-LLMにて、PythonのNPU推論でエラーが出た場合の対処

## 問題の確認
実行ログを見ると、PyaxengineのテストプログラムがAxEngine実行プロバイダーを適切に検出していることがわかります。しかし、その後「Segmentation fault」というエラーが発生し、プログラムが強制終了してしまっています。これはメモリアクセスの問題が発生していることを示しています。


```
root@m5stack-LLM:# python pyaxengine_test1.py
[INFO] Available providers:  ['AxEngineExecutionProvider']
[INFO] Using provider: AxEngineExecutionProvider
[INFO] Chip type: ChipType.MC20E
[INFO] VNPU type: VNPUType.DISABLED
[INFO] Engine version: 2.6.3sp
[INFO] Model type: 1 (full core)
[INFO] Compiler version: 3.2-patch1 2b3a4680
Segmentation fault (core dumped)
```

## 解決手順

### 1. axengineのバージョン確認

この問題の原因は、現在インストールされているaxengineのバージョンにあります。バージョンを確認すると0.1.0がインストールされていますが、このバージョンには既知のバグが含まれています。開発元のAXERA-TECHのGitHubリポジトリでは、このセグメンテーションフォルトの問題がIssue #22として報告されており、バージョン0.1.1で修正されたことがわかっています。

```
root@m5stack-LLM:# pip show axengine
Name: axengine
Version: 0.1.0
```

### 2. axengineのアップデート

問題を解決するためには、axengineライブラリをバージョン0.1.1にアップグレードする必要があります。最新のホイールファイルを公式GitHubリリースページからダウンロードし、pipを使ってインストールすることで、問題が解決します。
新しいバージョンでは内部のメモリ管理が改善され、セグメンテーションフォルトが発生しなくなります。アップデート後は、同じテストプログラムが正常に実行できるようになるはずです。

```
root@m5stack-LLM:# wget https://github.com/AXERA-TECH/pyaxengine/releases/download/0.1.1rc0/axengine-0.1.1-py3-none-any.whl
root@m5stack-LLM:# pip install axengine-0.1.1-py3-none-any.whl 
```

この問題は公式のGitHubで報告されており、バージョン0.1.1で修正されています：

https://github.com/AXERA-TECH/pyaxengine/issues/22
無料利用可能な為替取得API

※ほぼ自分用のメモです

| 名前 | 月刊リクエスト上限 | 基軸通貨 | 商用利用 | 
|---|---|---|---|
| [ExchangeRatesAPI](https://exchangeratesapi.io) | 100 | EUR | 文言無し | 
| [Fixer.io](https://fixer.io) | 100 | EUR | 文言無し | 
| [Currencylayer](https://currencylayer.com) | 100 | EUR | 文言無し | 
| [Open Exchange Rates](https://openexchangerates.org) | 1000 | EUR | [可能](https://currencyfreaks.com/blog/Open-Exchange-Rates-Api.html) | 
| [FoxRateAPI](https://forexrateapi.com) | 100 | 自由 | [不可](https://forexrateapi.com/faq) | 
| [CurrencyFreaks](https://currencyfreaks.com) | 1000 | USD | [可能](https://currencyfreaks.com/blog/Open-Exchange-Rates-Api.html) |
毎日kaggle(spaceship編)

# 毎日kaggle頑張る(spaceship編)
目的:transportedされたかどうか予測。

**step1 データの俯瞰**
メタ読みするとキャビンの位置などが重要？

step2 データの欠損処理など
AGEは平均値、目的地と出発地は最頻値を使用。その他は0に置き換え。
名前とIDのカラムは除去。
キャビンは/ごとに3つの要素にわけ新しいカラムへそれぞれ格納。

```
train[["Deck", "Cabin_num", "Side"]] = train["Cabin"].str.split("/", expand=True)
try:
    train = train.drop('Cabin', axis=1)
except KeyError:
    print("Field does not exist")
```

**step3データを検証用に分割**
```
#正解ラベルの設定
label = 'Transported'
#20%をテストに使う。
def split_dataset(dataset, test_ratio=0.20):
  test_indices = np.random.rand(len(dataset)) < test_ratio
  #~は反転を意味する。テストに使わない。
  return dataset[~test_indices], dataset[test_indices]

train_ds_pd, valid_ds_pd = split_dataset(train)
print("{} examples in training, {} examples in testing.".format(
    len(train_ds_pd), len(valid_ds_pd)))
train_ds = tfdf.keras.pd_dataframe_to_tf_dataset(train_ds_pd, label=label)
valid_ds = tfdf.keras.pd_dataframe_to_tf_dataset(valid_ds_pd, label=label)
```
step4ランダムフォレストモデルで分析

```
evaluation = rf.evaluate(x=valid_ds,return_dict=True)

for name, value in evaluation.items():
  print(f"{name}: {value:.4f}")
  ```

どの特徴量が強いのか
cryosleepが121回で一番使用されていました。
```
inspector = rf.make_inspector()
inspector.variable_importances()["NUM_AS_ROOT"]
```
【Python初心者】よく使う組み込み関数まとめ（Python3エンジニア認定基礎試験対策）

Pythonの学習を始めたばかりの方や、Python3エンジニア認定基礎試験の受験を考えている方に向けて、  
試験に出題される「よく使う組み込み関数」をジャンルごとに整理しました。

シンプルな説明と具体的な例付きで、実践にも役立つ内容を目指しています。

---

## 紹介する関数一覧（カテゴリ別）

| カテゴリ | 関数 | 用途（ざっくり） |
|----------|------|-------------------|
| 出力・入力 | print() | 標準出力に表示する |
| 出力・入力 | input() | 入力を受け取る |
| 文字列・数値 | str() | 文字列に変換する |
| 文字列・数値 | int() | 整数に変換する |
| 文字列・数値 | type() | データ型を調べる |
| 文字列・数値 | repr() | 再現可能な文字列に変換 |
| ループ・操作 | range() | 数列を生成する |
| ループ・操作 | len() | 要素数を取得する |
| ループ・操作 | enumerate() | 添え字付きループ |
| ループ・操作 | zip() | 複数のリストを組み合わせる |
| リスト操作 | list() | リストに変換する |
| リスト操作 | reversed() | 要素を逆順にする |
| リスト操作 | sorted() | 並び替える（ソート） |
| リスト操作 | sum() | 合計を計算する |
| 情報取得 | id() | メモリアドレスを取得 |
| 情報取得 | dir() | 使用可能な属性やメソッド一覧を取得 |
| 情報取得 | globals() | グローバル変数の一覧を取得 |
| ファイル操作 | open() | ファイルを開く |
| ファイル操作 | close() | ファイルを閉じる |


## 出力・入力に関する関数

### print()
標準出力に表示します。

```python
print("Hello, Python")  # → Hello, Python
```

### input()
ユーザーからの入力を文字列で受け取ります。

```python
name = input("名前は？")
print(name)
```

---

## 文字列や数値の変換・確認

### str()
オブジェクトを文字列に変換します。

```python
str(123)  # → '123'
```

### int()
数値や文字列を整数に変換します。

```python
int("42")  # → 42
```

### type()
オブジェクトの型を確認します。

```python
type(3.14)  # → <class 'float'>
```

### repr()
評価可能な文字列表現を返します（デバッグに便利）。

```python
repr("abc")  # → "'abc'"
```

---

## コレクション操作・ループ補助

### range()
数列を生成します。for文と組み合わせてよく使います。

```python
for i in range(3):
    print(i)  # → 0, 1, 2
```

### len()
要素数（長さ）を返します。

```python
len("hello")  # → 5
```

### enumerate()
インデックス付きでループできます。

```python
for i, v in enumerate(["a", "b"]):
    print(i, v)  # → 0 a / 1 b
```

### zip()
複数のイテラブルをまとめます。

```python
for a, b in zip([1, 2], ["x", "y"]):
    print(a, b)  # → 1 x / 2 y
```

---

## リスト・反転・合計・並び替え

### list()
イテラブルからリストを作成します。

```python
list("abc")  # → ['a', 'b', 'c']
```

### reversed()
逆順イテレータを返します。

```python
list(reversed([1, 2, 3]))  # → [3, 2, 1]
```

### sorted()
並び替えた新しいリストを返します。

```python
sorted([3, 1, 2])  # → [1, 2, 3]
```

### sum()
合計を求めます（数値リスト対象）。

```python
sum([1, 2, 3])  # → 6
```

---

## オブジェクト・識別・情報取得

### id()
オブジェクトの一意のID（メモリアドレス）を返します。

```python
x = "abc"
print(id(x))
```

### dir()
オブジェクトの属性やメソッド一覧をリストで返します。  
どんな操作ができるか確認するのに便利です（補完やデバッグにも使われます）。

```python
print(dir("hello"))  
# → ['__add__', '__class__', ..., 'upper', 'zfill'] など

print(dir([1, 2, 3]))  
# → ['__add__', '__class__', ..., 'append', 'extend', 'pop'] など
```

### globals()
グローバルスコープの名前空間を辞書として返します。

```python
x = 10
print(globals()["x"])  # → 10
```

---

## ファイル操作

### open()
ファイルを開いて書き込みや読み込みを行います。

```python
f = open("sample.txt", "w")
f.write("Hello")
f.close()
```

```python
f = open("sample.txt", "r")
print(f.read())
f.close()
```

※ 実際の開発では `with` 構文で自動的にファイルを閉じるのが一般的です。

```python
with open("sample.txt", "r") as f:
    print(f.read())
```

---

### 公式リファレンス（参考）

- [組み込み関数（Python公式ドキュメント）](https://docs.python.org/ja/3/library/functions.html)
【UE5】マウスの動きに合わせてカメラが動く条件メモ

## Mouse Capture の扱い（FirstPerson 視点時）

### 🎯 概要  
UE5 において、**マウス移動でカメラが動く処理**（FirstPerson等）に関係するのは `Mouse Capture` の設定です。

### ✅ マウスキャプチャを制御する主要ノード

| ノード名 | 概要 | 備考 |
|----------|------|------|
| `Show Mouse Cursor` | マウスカーソルの表示／非表示を切り替え | UI操作時は通常 true、操作時は false。カーソル表示中は原則キャプチャされません。 |
| `Set Input Mode (GameOnly / UIOnly / GameAndUI)` | 入力モードを切り替える | ※これらは **内部で CaptureMode を強制変更**する点に注意 |
| `Set Viewport Mouse Capture Mode` | キャプチャモードを直接指定 | `SetInputMode` のあとに呼ばないと上書きされるので無効化される可能性あり |
| `Set Ignore Look Input` | 視点移動を一時無効 | `SetInputMode` のあとに呼ばないと上書きされるので無効化される可能性あり |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3115955/6a122dc2-8d8a-4242-b4e8-95fe2fb89f45.png)


---

### ⚠ 注意：**InputMode が CaptureMode を上書きする**

以下のような順序で呼ばないと、思ったとおりに動作しない可能性があります：

```plaintext
【間違いの例】
SetViewportMouseCaptureMode → SetInputMode → ❌ CaptureModeが上書きされる

【正しい順序】
SetInputMode(GameOnly 等) → SetViewportMouseCaptureMode(CapturePermanently_IncludingInitialMouseDown)
→ ShowMouseCursor(false)
```

---

### 🎮 よく使う組み合わせ

#### ▶ プレイアブル状態に移行（視点操作あり）

```plaintext
SetInputMode(GameOnly)
SetViewportMouseCaptureMode(CapturePermanently_IncludingInitialMouseDown)
ShowMouseCursor(false)
```

#### ▶ UIのみ操作（ポーズメニューなど）

```plaintext
SetInputMode(UIOnly)
ShowMouseCursor(true)
```

#### ▶ ゲーム中に一時的に視点操作だけ無効化したいとき

```cpp
PlayerController->SetIgnoreLookInput(true);  // 視点入力だけ無視
```

---

### 📌 補足

- CaptureMode の値は以下のようなものがある：
  - `NoCapture`
  - `CapturePermanently`
  - `CapturePermanently_IncludingInitialMouseDown` ← 一番安定する
  - `CaptureDuringMouseDown`
  - `CaptureDuringRightMouseDown`
  

- `SetInputModeGameOnly()` などは BP でも使えるが、**マウスキャプチャまで完全に制御したいなら直後に `SetMouseCaptureMode()` を呼ぶのが鉄則**。

> 🔑 **要点：**「InputMode → CaptureMode の順に設定」さえ守れば OK。


## 📚参照

https://dev.epicgames.com/documentation/ja-jp/unreal-engine/input-fundamentals-for-commonui-in-unreal-engine
既にcherry-pickで取り込まれているコミットを再度cherry-pickしたい場合

## GitLab Web UIでrevert→再cherry-pick

#### 内容の変化には注意
revert した時点で差分がなくなる可能性があるため、再cherry-pickしても「差分が無い」と判断されて、何も起きないことも。

#### Web UIでは revert → cherry-pick も制限される可能性あり

GitLabのWeb UIは裏でGitのcherry-pickコマンドを走らせているので、revertしても内部的に「内容が同じ」と判断されて弾かれることもあります（バージョンや設定次第）。

## CLIで--keep-redundant-commitsオプション使用

確実に可能
Gitバージョン2.30以上推奨

```sh
git checkout target-branch
git cherry-pick -x --keep-redundant-commits <commit-id>
git push origin target-branch
```

## コミット内容を手動で再コミット

確実に可能
履歴的には別コミット扱い
GitLab 15.10 から 15.11でタグ名に日本語を含めるとブランチの履歴を表示時に500 Encoding Errorが表示する

バージョン16.0以降に更新できない場合は、タグ名に日本語は使わない運用で回避

[500 Encoding Error when viewing commit history in UI](https://support.gitlab.com/hc/en-us/articles/18174119507356-500-Encoding-Error-when-viewing-commit-history-in-UI)

ちなみに、説明に日本語は使用しても問題はありませんでした。
GitLabでブランチ名を変更

GitHubはWeb UIからブランチ名の変更が可能ですが、GitLabではそれがサポートされていません。

## GitLabでブランチ名を変更する方法（ローカルでの操作が必要）

ローカルでブランチ名を変更

```sh
git checkout old-branch-name
git branch -m new-branch-name
```
新しいブランチ名をリモートにプッシュ
```sh
git push origin new-branch-name
```
古いブランチ名をリモートから削除
```sh
git push origin --delete old-branch-name
```
## 参考URL
https://gitlab.com/gitlab-org/gitlab/-/issues/23906

https://gitlab.com/gitlab-org/gitlab/-/issues/233427
Gradleで遊ぶ

最近Gradleで遊んでるので備忘録的に書いていく
Androidのプロジェクトを作る時、大抵New Projectから作っていくと思うが、今回は1からbuild.gradleを書いてAndroidプロジェクトを作ってみる

# gradleプロジェクトを作る
とはいえgradleの機能は使っていく
gradleを用いたプロジェクトは`gradle init`で作れる

```shell
$ mkdir gradle-playground && cd gradle-playground
$ gradle init

Select type of build to generate:
  1: Application
  2: Library
  3: Gradle plugin
  4: Basic (build structure only)
Enter selection (default: Application) [1..4] 4

Project name (default: gradle-playground): 

Select build script DSL:
  1: Kotlin
  2: Groovy
Enter selection (default: Kotlin) [1..2] 1

Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] 


> Task :init
Learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.13/samples

BUILD SUCCESSFUL in 6s
1 actionable task: 1 executed
```

とりあえずこれでgradleプロジェクトの雛形ができた

```text
/gradle
  /wrapper
    gradle-wrapper.jar
    gradle-wrapper.properties
build.gradle.kts
gradle.properties
gradlew
gradlew.bat
settings.gradle.kts
```

# appモジュールを作る
ルートにappディレクトリを作る
これだとまだモジュールとして認識されないので、settings.gradle.ktsに追記する
```kotlin
include(":app")
```
これでappはモジュールとして読み込まれたが、Androidアプリケーションモジュールではなく単なるgradleモジュールとして読み込まれているだけ

# Android Gradle Pluginのセットアップ
Androidアプリケーションモジュールとして読み込ませるためには`com.android.application`をappモジュールでapplyする必要がある

とりあえずsettings.gradle.ktsに追記していく
```kotlin
pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}
```

これでgoogle, mavenCentral, gradlePluginPortalのMavenリポジトリからGradle Pluginを引っ張ってこれるようになった

ので、ルートのbuild.gradle.ktsに追記
```kotlin:build.gradle.kts
plugins {
    id("com.android.application") version "8.9.2" apply false
}
```

次にこのpluginをappモジュールにも適用したいのでappの直下にbuild.gradle.ktsを作成し、以下を記載
```kotlin:app/build.gradle.kts
plugins {
    id("com.android.application")
}
```

これでappがAndroidアプリケーションモジュールとして認識されましたね
Android Studioで開けばappが緑の丸ポチがついているのがわかると思います

# 仕上げ
Kotlin Androidプラグインを適用します
```kotlin:build.gradle.kts
plugins {
    id("com.android.application") version "8.9.2" apply false
+   id("org.jetbrains.kotlin.android") version "2.1.20" apply false
}
```

```kotlin:app/build.gradle.kts
plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}
```

ここでgradle syncをすると`Failed to resolve: org.jetbrains.kotlin:kotlin-stdlib:2.1.20`となってしまうので、setting.gradle.ktsに以下を追記します
```kotlin:setting.gradle.kts
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
    }
}
```

あとはandroidの設定をしたら終わりです
```kotlin:app/build.gradle.kts
android {
    namespace = "io.github.dosukoi_android.gradle_playground"
    compileSdk = 36
    defaultConfig {
        applicationId = "io.github.dosukoi_android.gradle_playground"
        minSdk = 24
        targetSdk = 36
        versionCode = 1
        versionName = "1.0.0"
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_21
        targetCompatibility = JavaVersion.VERSION_21
    }

    kotlinOptions {
        jvmTarget = "21"
    }
}
```

# 終わりに
あとはdependenciesに好きなライブラリを突っ込んで遊んでください
Gradleは最初は非常にとっつきづらいですが、慣れてくると可愛く思えてきますね
みなさんもGradleくんと遊んでみましょう
Geminiでトライアングルを使う魔法少女を描いてみた。

# 概要

Geminiでトライアングルを使う魔法少女を描いてみました。

# 実装

プロンプトと実行結果は以下の通りです。

```
炎のトライアングルを使う魔法少女を描いてみてください。 
```

![炎のトライアングルを使う魔法少女_20250423.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192024/f4c895af-eec5-4400-a55d-3f56c773cb90.png)


```
氷のトライアングルを使う魔法少女を描いてみてください。
```

![氷のトライアングルを使う魔法少女_20250423.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192024/4593763d-f556-433f-ba7b-daf7cd6619c1.png)

# まとめ

炎の子は可愛いかも。
何かの役に立てばと。
【勉強会レポート】JAWS-UG初心者支部に参加させていただいた話

# はじめに
2025/4/22に開催されたJAWS-UG初心者支部の勉強会（ハンズオン・LT会）に参加させていただきました。初めての完全社外でのオフライン登壇で帰宅しても熱が冷めないので勢いのままにレポートなどを書きたいと思います。

https://jawsug-bgnr.connpass.com/event/350578/

# 参加のきっかけ
豊洲会や部内での登壇・発表をいくつか経験していく中で、そろそろ**完全アウェイな環境でも発表経験を積みたい**なと考えていました。そこで以前から初心者支部の活動をウォッチしていたのですが、前回3月のLT会は、年度末の引継ぎ対応で気づけば募集が閉め切られており応募すらできず…。次こそは申し込むぞと意気込んでいると、ちょうどオフライン開催との告知がありました。今度こそと頼む～とお祈り応募したところ、運よくLTできることになり参加させていただきました。

前置きはここまでにして、実際どのようなことをやったのか記載していきたいと思います。

# IAM Identity Center＆AWS Organizations ハンズオン
運営の高野さんが書かれた以下のハンズオン記事を用いて、「**AWS IAM Identity CenterとAWS Organizationsを構築し、いくつでもアカウントが自由に払い出せる環境**」をゴールとして実施しました。（詳細な実施内容については以下記事をご覧ください）

https://zenn.dev/jawsug_bgnr/articles/758387f29c4c3e

ハンズオンは常に丁寧な雰囲気で進められており、環境をつくるぞ！という気持ちさえあれば（なくても？）完遂できたのではないかと思いました。

私も、ずっとおひとりさまOrganizationsやってみないとなあと考えていたので、とても勉強になりましたし、思った以上に便利になるんじゃないか？と感じています。（普段使っている環境もとっとと移行したいと思います）

# LT会
続いてLT会です。今回は私含め3名のLT発表がありました。

### AWS初心者がAWS BuilderCardsで遊んでみた（Riri さん）
AWS BuilderCardsを実際に遊んで、よいと感じたことについてお話しされていました。印象に残ったのは、「**楽しみながらサービスへの理解が深まる**」といったお話です。AWSに限らず、楽しみながら学びを深めることができる機会はとてもいいなと思います。懇親会ではお話ししましたが、私はなぜか手元に生成AI add-onだけがあるので、とてもやってみたい気持ちが強いです。
また、会場で興味を持たれている方が多いこともあり、次回の初心者支部では「初心者でBuilderCardsやってみよう会」が開催されるそうです。

https://x.com/taketakekaho/status/1914692967756968316

### AWS初心者こそLTに挑戦してみよう！（Tsukass さん）
自身の体験をもとに、「技術的な話でなくとも、**LTで発表した内容は必ず誰かのためになる**」ということを伝えてくださったと解釈しております。実際の経験ベースでお話しされていたので、言葉に説得力というか確信めいたものがあるように感じたことが印象的です。私も自分の中で完結するのではなく、どんどん外に発信していければと思いました。

https://speakerdeck.com/tks_21/2025-dot-04-dot-22ltzi-liao

### 新着ニュースを毎朝メール通知する仕組みを作ってみた
私は、「ニュース情報を収集する仕組みを作ったけど、いろいろできなかったことがあったよ」という内容の発表をさせていただきました。良くも悪くも、モノを作るって結構こんなもん（だから、**気軽に手を動かしてみるのがよい**よ）というのが伝わっていれば幸いです。

https://speakerdeck.com/ryuki0947/xin-zhao-niyusuwomei-zhao-merutong-zhi-surushi-zu-miwozuo-tutemita

# おわりに
以上簡単ではありますが、勉強会レポートになります。参加前は自分のアウトプットに意識が行っていましたが、終わってみると、いろいろな学び・経験ができたなあと感じています。JAWS-UGでの活動が**これっきりにならないように**これからもいろいろアウトプットしていければと思います。
運営の皆様、参加者の皆様ありがとうございました！
秀丸について

#### 目次
- 秀丸とは
- 基本操作ショートカット
- 編集系ショートカット
- カーソル移動

#### **秀丸とは**
秀丸とは、**Windows用テキストエディタ**です。

---

#### **基本操作ショートカット**

| 機能 | ショートカットキー |
|------|--------------------|
| 新規作成 | `Ctrl + N` |
| ファイルを開く | `Ctrl + O` |
| 保存 | `Ctrl + S` |
| 名前を付けて保存 | `Ctrl + Shift + S` |
| 印刷 | `Ctrl + P` |
| 元に戻す（Undo） | `Ctrl + Z` |
| やり直す（Redo） | `Ctrl + Y` |
| 切り取り | `Ctrl + X` |
| コピー | `Ctrl + C` |
| 貼り付け | `Ctrl + V` |
| 全選択 | `Ctrl + A` |
| 検索 | `Ctrl + F` |
| 置換 | `Ctrl + R` または `Ctrl + H` |
| ジャンプ（行番号） | `Ctrl + J` |

---

#### **編集系ショートカット**

| 機能 | ショートカットキー |
|------|--------------------|
| 行のコピー | `Ctrl + Shift + C` |
| 行の削除 | `Ctrl + Y`（選択範囲なし時）|
| コメントアウト（マクロ利用時） | `Ctrl + /`（設定による） |
| 選択行のインデント | `Tab` |
| 選択行の逆インデント | `Shift + Tab` |
| 矩形選択 | `Ctrl（Alt） + 左クリック` |

---

#### **カーソル移動**

| 機能 | ショートカットキー |
|------|--------------------|
| 行頭へ移動 | `Home` |
| 行末へ移動 | `End` |
| ドキュメント先頭へ | `Ctrl + Home` |
| ドキュメント末尾へ | `Ctrl + End` |
| ページアップ | `Page Up` |
| ページダウン | `Page Down` |

---
競プロ日記#25/04/22

# AtCoder

## 日立製作所 社会システム事業部 プログラミングコンテスト2020
### [A-Hitachi String](https://atcoder.jp/contests/hitachi2020/tasks/hitachi2020_a)
- 文字数と文字の偶数番目奇数番目を場合分けを実装
```
int main() {
    string S;
    cin >> S;
    int N = S.length();
    if (N % 2 == 1){
        cout << "No" << endl;
        return 0;
    }
    for (int i = 0; i < N; i++) {
        if (i % 2 == 0){
            if (S[i] != 'h'){
                cout << "No" << endl;
                return 0;
            }
        }
        if (i % 2 == 1){
            if (S[i] != 'i'){
                cout << "No" << endl;
                return 0;
            }
        }
    }
    cout << "Yes" << endl;

}
```

# アルゴ式-[どこまでも続く数列 (1)](https://algo-method.com/tasks/648)
- 特になし

```
int main() {
    int X,d;
    cin >> X >> d;

    if (d == 0){
        cout << 1 << endl;
        return 0;
    }
    if (d > 0){
        cout << 2 << endl;
        return 0;
    }
    if (d < 0){
        cout << 3 << endl;
        return 0;
    }
}
```

# アルゴ式-[どこまでも続く数列 (2)](https://algo-method.com/tasks/663)
- rで場合分けする。

# アルゴ式-[極限の計算 (1)](https://algo-method.com/tasks/647)
- 0に向けて極限を取るのでx≠0前提でx+a+b/xを考えるとよい
# アルゴ式-[小さい数の個数](https://algo-method.com/tasks/382)
- まだまだ二分探索の理解が浅いと痛感させられた。
- どうしてもleftも動くというイメージが薄くなってしまう。
```
int main() {
    long long N,M;
    cin >> N >> M;
    vector<long long> A(N);
    for (long long i = 0;i < N;i++){
        cin >> A[i];
    }
    sort(A.begin(), A.end());
    for (int i = 0;i < M;i++){
        long long B;
        cin >> B;
        long long left = 0;
        long long right = N - 1;
        
        while (left != right){
            long long mid = (left + right) / 2;
            if (A[mid] > B){
                right = mid;
            }else{
                left = mid + 1;
            }
        }
        cout << left << endl;
        
    }
}
```


※シンプルに数3の復習しないとまずいなって思いました。本当に
Github Actions　てなんや【CI/CD】

## Github Actionsってなんだ
CI/CD関連で使われるサービスのようです。
**CI/CD**とは
継続的インテグレーション　Continuous Integration
継続的デリバリー デプロイ　Continuous Delivery　Deployment

だそうです。単語の意味はよく分かりませんが
自動でテストして自動でデプロイすることです。
自分も何となく自動でやってくれるというあいまいな認識でしたが、興味だけはありました。

他のCI/CD関連のサービスは
- Jenkins, 
- GitLab CI
- CircleCI
- AWS CodePipeline

どれも聞いたことないです...
とりあえず適当にリポジトリ作って使ってみます
## .github/workflows/hoge.ymlを作成する

まずはGitHubのドキュメントに倣ってHelloWorld的なコードを実行してみます。

https://docs.github.com/ja/actions/writing-workflows/quickstart

リポジトリに **.github/workflows**ディレクトリを作成します
**.github/workflows**にあるymlファイルはワークフローファイルという名前で呼ばれているようです。

ワークフローファイルが実行されるのはワークフローファイルに記述したgithubのイベントがトリガーしたときです

pullRequestされたとき、pushされたときなど、実行するタイミングをワークフローファイルで設定できます

処理の内容もワークフローファイルに書いていきます。

**.github/workflows/hoge.yml** というワークフローファイルを作成しました。
```yml:hoge.yml
name: test no warkflow
run-name: ${{ github.actor }} test
on: [push]
jobs:
  Explore-GitHub-Actions:
    runs-on: ubuntu-latest
    steps:
      - run: echo "${{ github.event_name }}"
      - run: echo "${{ runner.os }}"
      - run: echo " ${{ github.ref }}  ${{ github.repository }}."
      - name: repo code check
        uses: actions/checkout@v4
      - run: echo "${{ github.repository }} "
      - name: file list
        run: |
          ls ${{ github.workspace }}
```
コードの内容はGithubのドキュメントとほぼ一緒です。echoの内容を変えただけです。
自分は、コピペでそのまま実行したくない病なのでなにかしら変更を加えてしまいます。

初見のコードでしたが、身に覚えがあるというか、Dockerfileに似てなくもないかなという印象でした。
ワークフローはホステッドランナーと呼ばれる仮想マシンで実行されるようです。
```run-on:```などはランナーのOSを定義しているようです。
Ubuntu Windows macOS の中から選べるようです。

```on:push```これがgitのイベントです。
つまりpushされたときにこのワークフローは実行されるということです。
他にも
```on:pushpull_request```　プルリクされたとき
```on:workflow_dispatch``` githubから手動実行されたとき
などがあるようです。

調べているとmergeというイベントがないことに気づきました。
mergeもpushの一部ということでないようです。

branchやディレクトリを指定することもできて
```yml
on:
  push:
    branches:
      - develop
    paths:
      - 'src/**'
```
このように記述すると
```develop```ブランチの```src```ディレクトリに```push```されたときに実行するようになります

```jobs:```は**ここからワークフローの処理を定義しますよ**の文言
```Explore-GitHub-Actions:```jobの任意の名前
```steps:```ワークフロー構成する一つの処理単位
```run:```ランナーでコマンドたたく
```name:```コメント的な感じ。```steps```を実行中にログに出力される
```uses:```アクションを実行する
アクションとは再利用可能なコードの単位だそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3765500/7e2855e6-2e4f-4e96-8085-b607188991ed.png)
あらかじめ定義してあるアクションや、自前で定義したアクションを実行できるということです。
今回はあらかじめ定義されている```actions/checkout```を使用して
レポジトリをランナーにクローンしています。
```with:```を使って引数を渡せるようです。
```yml
jobs:
 steps:
  - uses: action/checkout@v4
    with:
     ref:
      - develop
```
これはdevelopブランチを指定してクローンするコードです。


## pushしてみる
試しにpushしてみると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3765500/937d0f8c-baa8-48d1-b71e-a5bc1aa2bd37.png)

githubにこのような出力があり正しく動作していることが確認できました。
CI/CDのCDだけなら結構簡単に使えそうな印象でした。
CIは難しそうです。そもそもテストってどうやるんでしょうか...
githubに出力されたワークフローのログを見て思い出したのですが、専門学校時代に教員が課題を自動でテストするときにつかってました。
CIに関してはまた調べます
【Python】while文の条件はどう書くべきか？

Pythonの条件付きループはwhile文を使って書きますが、実は認知負荷の高い書き方をしているのではないか？と思い、まとめてみることにしました。


# 更新履歴
2025/04/23 : 初版


# 環境
* Windows11
* Python3.12
* PyCharm Community Edition 2024.2.2


# 1. while文の2種類の書き方

while文を書く状況としてよくあるのが、「何か処理が完了するまで待機する。一定時間以内に完了しなかった場合、タイムアウトエラーとする」というものだと思います。

これを記述する方法は、次の2つが考えられると思います。

```python:①while直後にTrueを書く
import time

def is_completed() -> bool:
    # 処理が完了していればTrueを、完了していなければFalseを返す
    ...

start_time = time.time()
timeout = 10.0
while True:
    if is_completed():
        break
    if start_time + timeout < time.time():
        raise RuntimeError('timeout')
```

```python:②while直後に条件を書く
import time

def is_completed() -> bool:
    # 処理が完了していればTrueを、完了していなければFalseを返す
    ...

start_time = time.time()
timeout = 10.0
while time.time() < start_time + timeout:
    if is_completed():
        break
else:
    raise RuntimeError('timeout')
```


# 2. 違いについて

この2つを見比べたとき、私には①の方が理解しやすく感じていました。

色々考えて言語化してみると、「**if文の条件とwhile文の条件は、性質が真逆**だから」という結論に至りました。

具体的に説明します。

ループの終了条件を把握したいとき、①では`break`, `raise`, `return`に入るif文を探すだけで済みます。

一方②の場合、それに加えてwhile文の条件を否定したものを考える必要があります。

今回は`not (time.time() < start_time + timeout)`、つまり`start_time + timeout <= time.time()`です。

この「if文だけでなくwhile文も確認する」「if文の条件とwhile文の条件のうち、片方だけを否定する」という作業は、非常に認知負荷が高いと感じています。


# 3. 結論

上の考察から、while文の条件は書かない（`True`固定）とした方が理解しやすいコードになるのではと考えました。

実際ここ数年は①の書き方をしていますが、困るような事象は発生していません。

今回の件に関してはwebで調べてみたのですが、言及しているサイトが見つかりませんでした。

もし情報がありましたら連絡をいただけますと幸いです。

また、皆さんの意見もお待ちしています。
複数のディレクトリをファイルから読み込んで存在とパーミッションチェック

複数のディレクトリをファイルから読み込んで、それぞれのディレクトリが存在するか、そしてパーミッションが「770」かどうかをチェックするスクリプトは以下の通りです。

```bash:check_dirs.sh
#!/bin/bash

# ディレクトリ一覧ファイルの指定（引数で渡す）
if [ $# -ne 1 ]; then
  echo "使用法: $0 ディレクトリ一覧ファイル"
  exit 1
fi

file="$1"

# ファイルが存在するか確認
if [ ! -f "$file" ]; then
  echo "ファイル '$file' が存在しません。"
  exit 1
fi

# ファイル内の各ディレクトリを読み込んで処理
while IFS= read -r dir; do
  # 空行やコメント行を無視
  [ -z "$dir" ] && continue
  [[ "$dir" =~ ^# ]] && continue

  if [ -d "$dir" ]; then
    perm=$(stat -c '%a' "$dir")
    if [ "$perm" = "770" ]; then
      echo "$dir は存在し、パーミッションは 770 です。"
    else
      echo "$dir は存在しますが、パーミッションは $perm です（770 ではありません）。"
    fi
  else
    echo "$dir は存在しません。"
  fi
done < "$file"
```

使用例：
ディレクトリ一覧ファイル（例: dirs.txt）を用意：

```txt:dirs.txt
/test/env1/dirA
/test/env2/dirB
# コメント行もOK
/test/env3/dirC
```

スクリプトを実行：

```sh
./check_dirs.sh dirs.txt
```
【React】Reactで複数条件を判定する方法について

# はじめに
Reactで複数の条件を使って表示の出し分けをしようとした際に、思わぬ落とし穴にはまってしまいました。今回はその間違いと正しい書き方についてまとめます。

:::note warn
***この記事は<font color="Red">個人的なアウトプット</font>を目的として作成したものです。そのため、誤った情報や不足している内容が含まれている可能性があります。もし間違いや気になる点がございましたら、ぜひご指摘いただけますと幸いです***。
:::


# 間違えた方法
propsとして渡されたtypeの値によって、子コンポーネントの表示・非表示を切り替える処理をしていました。最初に書いたコードはこちらです。

```react
<Components type="typeA" />
```

```react
const Components = ({ type }) => {
  return <>{type === "typeA" || "typeB" || "typeC" && <SomeComponent />}</>;
};
```
このコードでは、`type`が`typeA`, `typeB`, `typeC` のいずれかのときに`<SomeComponent />`を表示しようとしました。しかし、実際の挙動は意図通りになりませんでした。

+ `type = "typeA"`のとき：何も表示されない

+ `type = "typeB"`のとき：`typeB`という文字列が表示される

+ `type = "typeC"`のとき：同様に`typeB`が表示される

# JavaScriptがどのように評価しているのか？
この式をJavaScriptがどう評価してるか、分解していきます。

```react
{type === "typeA" || "typeB" || "typeC" && <SomeComponent />}
```
まず、演算子の優先順位と評価順序が重要です：

```react
type === "typeA" // これは true または false になる
```

***`type = "typeA"`のとき：***

```react
true || "b" || "c" && <SomeComponent />
```

このとき、最初の`true`で評価が完了してしまうため、Reactは`true`をレンダリングしようとして、結果何も表示されません。

***`type = "typeB"`、`type = "type C"`のとき：***

```react
type === "typeA" // ここはfalseになる
```

`typeA`は`false`になるので`||`の評価に移ります。

```react
false || "typeB" || "typeC" && <SomeComponent />
```
`typeB`が`true`になるので`"typeC" && <SomeComponent />`は評価されずに終了します。`typeB`が文字列として表示されます。


# 正しい実装方法
このようなケースでは、配列と`includes`メソッドを使うことで、意図通りの条件分岐が可能になります。

```react
{["a", "b", "c"].includes(type) && <SomeComponent />}
```
`includes`は、配列に指定した値が含まれているかどうかを`true/false`で返します。そのため、正しく条件を判定できます。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/includes

# 終わりに
`JavaScrip`tの評価の仕組みを理解していないと、今回のように見た目には正しく見えるコードでも意図しない動作をしてしまいます。`React`のJSXでは論理演算子を多用する機会が多いので、こういった評価の流れを押さえておくことが重要だと改めて感じました。

# 参考
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
test

```aaa.view
dimension: fiscal_progress_days {
  type: number
  sql:
    CASE
      WHEN CURRENT_DATE BETWEEN {% date_start sales_date %} AND {% date_end sales_date %} THEN
        DATE_DIFF(CURRENT_DATE, {% date_start sales_date %})
      ELSE
        DATE_DIFF({% date_end sales_date %}, {% date_start sales_date %})
    END ;;
}
```
macでllama

# 初めに
M4 MacBook AirをGetしたので、搭載されているNPUを活用したいと思います。
今回は、ollamaをインストールし、ローカル（MacBook Air上）でLLMを実行したので、その方法について説明します。

## 環境について
HomeBrewを使いollamaをインストールするため、HomeBrewを確認します。
Macのターミナルを開き、次のコマンドを実行する事でHomeBrewがインストールされているか、検証することができます。
```shell
$ brew -v
Homebrew 4.4.31
```

# ollamaについて
そもそも、ollamaとは何かについて少し触れておきたいと思います。
- 大規模言語モデル（LLM）を実行することができるアプリケーション
- 公式で対応しているLLMの種類数はHuggingFaceに劣るものの、HuggingFaceのllmをコンバージョンし使用可能
- ローカルのLLMを使用するためのライブラリLangChain(今回は触れない)のAPIに対応

特徴をいくつか列挙しましたが、要するに**ローカル(MacBook Air)で色々なLLM（gemini, ollama,deepseek, phi）を実行できるアプリケーション**です。

# ollamaのインストール方法
brewを使うことで、簡単にインストールすることができます。

```shell
$ brew install llama.cpp
```

インストールが完了すると、brewお馴染みの🍺(ビール)の絵文字が表示されます。
念の為、PATHが通っているか確認しましょう。
```shell
$ ollama -v
ollama version is 0.6.5
```
バージョンが出力されれば、ollamaのインストールは完了です。

# 実際にOllamaでLLMを実行してみる。
ollamaを使ったLLMの実行方法は大まかに３工程で表すことができます。
1. リモートにあるLLMのモデルを選択
1. ローカルへpull
1. 実行

それぞれの工程について説明していきます。

## 1.LLMモデルを選択
ollamaで使用できるモデルは、以下のリンクから確認することができます。

https://ollama.com/library

それぞれのモデルの開発元と必要なリソースについて記載されています。
今回は、llama3.1を使用したいと思います。下記リンクで、llama3.1については述べられているため、紹介は省略します。

https://ollama.com/library/llama3.1

## 2.ローカルへpull
使ってみたいモデルを選択後はollamaを使ってLLMのパラメータやアーキテクチャを取得します。
```shell
$ ollama pull llama3.1:latest
```
インストールができているか、確認をします。
```shell
$ ollama list
NAME                ID              SIZE      MODIFIED    
llama3.1:latest     46e0c10c039e    4.9 GB    2 weeks ago
```
のように表示されればローカルでLLMを実行直前です。

## 3.実行
ローカルへダウンロードしたLLMを使用するために、下記コマンドを実行します。
```shell
$ ollama run llama3.1
```
待機状態になり、LLMと会話することができます。（MacBook Airと会話していると言っても過言ではない！！？！）

# まとめ
ollamaを使ってローカル環境でLLMを実行しました。

ollamaの使い方は、使いたいLLMをpullしてrunするだけ！
最先端の AI Agent Devin を使って、ただただバカなゲームを作らせた話

# クソゲー量産時代が始まったかもしれない

## 背景
職場で Devin にガンダムの恋愛シュミレーションゲーム作ってよってバカな依頼がきまして
とりあえず、Devin に雑に依頼してみました
![](https://storage.googleapis.com/zenn-user-upload/c7751e30c346-20250422.png)

そしたら、それっぽいゲーム作ってきました
突然 Web で公開するとか言い始めて驚きました
ちなみに、ちゃんとガンダムキャラの特徴を掴んでます（オタクなら分かる
![](https://storage.googleapis.com/zenn-user-upload/4ba198ead1d7-20250422.png)

まぁ、選択肢がないクソゲーなんですが
なんかやってて爆笑しました
Devin 使って、こんな無駄なことしてる記事他に見たことないんで、こんなバカなことも出来るよって記事です

## 作成時間について

このゲームは10分程度で作りました
10分でゲームを作って、Webに公開済ってすごくないですか？
ただ、Devin もこんなくだらないことにリソースを使われると思っていないでしょう
ちなみにこれは Devin のホスティング機能を使って公開しています。
Devin でホスト機能あるんですね、知らなかったです。
雑に投げてもちゃんとガンダムの世界観のキャラクターについて理解してたので、10分でできたと思えば十分じゃないでしょうか。
サブカル知識を理解して色々開発できるのは結構すごいのでは🤔

その後も思いつきで色々ゲームを作りましのたで、ついでに紹介します

## 1. バカカード
![](https://storage.googleapis.com/zenn-user-upload/ef8556df17e6-20250422.png)
[バカカードゲーム](https://funny-game-app-1ffu6w8q.devinapps.com)は、カードをめくって書かれた指示に従うだけの単純なゲームです。友達と一緒に遊ぶと盛り上がること間違いなし！

## 2. ガンダムジャンケンゲーム

![](https://storage.googleapis.com/zenn-user-upload/69b0bfce3501-20250422.png)

[ガンダムジャンケンゲーム](https://gundam-love-sim-game-3jhu4c0u.devinapps.com/)は、ガンダム、ザク、グフを使ったジャンケンゲームです。ガンダムはザクに強く、ザクはグフに強く、グフはガンダムに強いというルールです。グフがガンダムに勝つな。

## 3. ガンダム恋愛シミュレーション

![](https://storage.googleapis.com/zenn-user-upload/7abfc3746529-20250422.png)

背景で記載したやつ。[ガンダム恋愛シミュレーション](https://gundam-romance-game-507j7kb0.devinapps.com/)は、宇宙世紀を舞台にした恋愛シミュレーションゲームです。ガンダムの世界で恋愛を楽しめます。（選択肢はなく、勝手に幸せなるので、楽しめているかは不明。ただ自分はやってて爆笑しました。

## 4. ガンダムバトル


![](https://storage.googleapis.com/zenn-user-upload/f137adadfae6-20250422.png)

[ガンダムバトル](https://gundam-game-generator-1ewlqfse.devinapps.com/)は、様々なモビルスーツを選んで戦うバトルゲームです。RX-78-2 ガンダム、MS-06 ザクII、MSN-02 ジオング、RX-0 ユニコーンガンダムから選べます。
各モビルスーツのイメージをデザインしてもらったら、芋虫みたいな画像作られました。
基本ユニコーンガンダムには勝てません