OmniAICreator/Qiita-1.07M huggingface dataset:
アダプティブカードのトライ＆エラーに疲れた自分の出した結論


## 1. はじめに
Microsoft Outlookのタスク管理機能は多くの企業で活用されていますが、個人利用が中心で、チーム共有やリアルタイム通知には制約があります。Microsoft Teamsとの連携により、チーム全体でのタスク可視化が実現できます。本提案では、環境要件に応じた3つの実装アプローチを比較検討します。

## 2. 提案アプローチ

### 2.1 オプション1: PowerShell + Teams Webhook（推奨）
**概要**: PowerShellでOutlookタスクを取得し、TeamsのWebhookを介してアダプティブカードを送信

**メリット**:
* コードの保守性が高く、拡張性に優れている
* Teams Webhookは認証不要で実装が容易
* 複雑なタスク処理やフィルタリングが可能

**デメリット**:
* 実行環境にPowerShellとOutlookが必要
* スケジュール実行には追加設定が必要

**実装例**:
```powershell
# Outlookからタスクを取得
$outlook = New-Object -ComObject Outlook.Application
$namespace = $outlook.GetNamespace("MAPI")
$taskFolder = $namespace.GetDefaultFolder(13)
$tasks = $taskFolder.Items

# タスク情報をJSON形式でTeams Webhookに送信
$webhookUrl = "https://your-teams-webhook-url"
$adaptiveCard = @{
    type = "message"
    attachments = @(
        @{
            contentType = "application/vnd.microsoft.card.adaptive"
            content = @{
                # アダプティブカード定義
            }
        }
    )
}

Invoke-RestMethod -Uri $webhookUrl -Method Post -Body ($adaptiveCard | ConvertTo-Json -Depth 10) -ContentType "application/json"
```

### 2.2 オプション2: Power Automate単体
**概要**: Power Automateを利用して、Office 365のOutlookタスクを取得しTeamsに通知

**メリット**:
* コード不要で実装可能
* クラウドベースで環境依存性が低い
* スケジュール実行やトリガー設定が容易

**デメリット**:
* カスタマイズ性に制約あり
* Power Automateのライセンスが必要
* デスクトップOutlookとの連携には制約がある

### 2.3 オプション3: VBA + PowerShellハイブリッド
**概要**: OutlookのVBAでタスク変更を検知し、PowerShellを呼び出してTeamsに通知

**メリット**:
* Outlookイベントをトリガーとした準リアルタイム通知
* 既存のOutlookワークフローとの統合が容易
* 複雑なタスク処理が可能

**デメリット**:
* VBAとPowerShellの連携が複雑
* セキュリティ設定による制約
* VBAコードの保守性が低い

## 3. 比較表

| 評価基準 | PowerShell+Webhook | Power Automate | VBA+PowerShell |
|----------|-------------------|----------------|---------------|
| 開発難易度 | 中 | 低 | 高 |
| 保守性 | 高 | 中 | 低 |
| 環境依存性 | 中 | 低 | 高 |
| 拡張性 | 高 | 中 | 中 |
| リアルタイム性 | 低 | 低 | 高 |
| 認証の複雑さ | 低（Webhook） | 中 | 低 |
| コスト | 低 | 中〜高 | 低 |

## 4. 実装上の考慮事項

### 4.1 認証とセキュリティ
* **Teams Webhook**: URLにトークン機能が内蔵され、別途認証不要
* **SharePointアクセス**: 認証が必要で、自動化環境では複雑
* **Power Automate**: Officeサービスへのアクセスは自動処理

### 4.2 データ連携パターン
* **読み込み限定**: PowerShell → Teams Webhook（認証不要）
* **双方向連携**: ボタンアクションは Power Automate で処理
* **限定的フィードバック**: Outlookメールを中間媒体として利用

### 4.3 エラーハンドリングとログ記録
```powershell
try {
    # タスク処理ロジック
}
catch {
    # エラー記録
    $ErrorMessage = $_.Exception.Message
    Add-Content -Path "$env:TEMP\TaskNotifier.log" -Value "$(Get-Date) - ERROR: $ErrorMessage"
}
```

## 5. 結論
環境と要件に基づいた選択が重要です：

* **PowerShell + Teams Webhook**: 最もバランスが良く、認証の複雑さを回避できるため推奨
* **Power Automate**: クラウド環境優先でコーディング不要を重視する場合
* **VBA + PowerShell**: リアルタイム性を最重視する場合

実装では、Teams Webhookの活用により認証の複雑さを回避し、効率的なタスク通知システムの構築が可能です。
🎉 楽しく学ぶDDD（リポジトリの設計編）！

## :cherry_blossom: はじめに

こんにちは！DDDの旅を一緒に楽しんでいますね🎈
今日は次のステップとして、ドメイン駆動設計の大切な仲間「リポジトリ」について楽しく学びましょう！

## 📦 リポジトリってなに？

ドメイン（モデル）ではビジネスのルールや振る舞いを表現し、データの保存・取得といった処理は行わない所ですが、データの保存・取得といった処理を実際に扱うのがリポジトリの役割です。

リポジトリとは、エンティティや集約（関連する複数のドメインオブジェクトをひとまとめにした単位）を保管したり取り出したりする場所のこと。まるで図書館や倉庫のような役割です！


簡単に言うと、「必要なものを安全にしまっておいて、使いたいときにサッと取り出せる仕組み」なんです✨

## 🎯 リポジトリの役割

リポジトリには主に2つの大切な役割があります！

### ① 集約の取得
「これが欲しい！」というときに、すぐに必要なものを取り出します。

🌟 例：学校なら「生徒リポジトリ」から生徒の情報を探して取得します。

📝 **ポイント**：集約を取り出すときは、その集約を特定するための識別子（例えば、生徒番号やID）をリポジトリに伝える必要があります！

### ② 集約の永続化
「これを大事に保存しておこう！」というとき、情報を失くさないようにちゃんと保存します。

📚 例：新しい生徒が入学したら、生徒リポジトリに情報を追加して安全に保管します。

## 🛠 実際のリポジトリの使い方

リポジトリを使った流れはシンプル！

1. リポジトリに「お願い！○○をください！」と識別子を伝える（検索）
2. リポジトリがデータベースやファイルなどから情報を探してくれる
3. 見つけた情報を使って色々な作業をする
4. 新しく追加や変更があれば、リポジトリに「これを保存してね！」と伝える（保存）

## ✨ リポジトリを使うメリット

- 必要なデータを簡単に見つけて取り出せる！
- データを安全に管理できるので安心！
- コードがシンプルになり、後で見直しや変更が簡単になる！

## 🌈 まとめ

リポジトリを使えば、ドメインモデルを簡単に、安全に管理できちゃいます！
DDDのリポジトリをしっかり理解して、明るく楽しく素敵なシステムを作りましょう！🚀😄✨
Get Hands on with Data Cloud


+ [Get Hands on with Data Cloud](https://developer.salesforce.com/agentforce-workshop/data-cloud/overview)

# パッケージにはアプリはない？

+ [アプリをインストールしました。しかし、アプリランチャーに表示されません](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000PXI3I)

:::note
Data Cloud アプリケーションにアクセスできますか (Data Cloud のセットアップは前の手順で通常求められます)? データ キットがインストールされると、その後操作する要素/データにアクセスできるようになります。  

PS: 私が見つけたページに記載されているように、「データ キットは、データ ストリーム、マッピング、計算された洞察などのデータ クラウド メタデータをパッケージ化できるデータ クラウド機能です。データ キットを使用すると、プロジェクト間でコンポーネントを簡単に共有および再利用できます。」このパッケージから専用のアプリケーションは見つかりません。 
:::
SpresenseマルチIMU Add-onボードのラッパーライブラリを作ってみた

# 初めに

最近話題の高精度マルチIMU「[SpresenseマルチIMU Add-onボード](https://developer.sony.com/ja/spresense/products/spresense-imu-add-on-board)」が発売されました。こちらは、皆さんが続々と触って報告しているのですが、いかんせん、今のままだとArduinoIDEから使いにくかったので、ライブラリを作ってみました。

これらの経緯の詳細は、ブログの方に書いていますので、そちらを参照してみてください。

https://spresense.livedoor.blog/archives/38224250.html

#  製品情報

製品の詳細な情報は、こちらになります。

<img width="300" src="https://www.switch-science.com/cdn/shop/files/f9a98a0a-ec37-415d-bdc6-36a6b1570ff5_700x700.jpg">

[SpresenseマルチIMU Add-onボード](https://developer.sony.com/ja/spresense/products/spresense-imu-add-on-board)

使い方の公式ドキュメントはこちらになります。

[マルチIMU Add-onボード チュートリアル](https://developer.sony.com/spresense/development-guides/arduino_tutorials_ja.html#_tutorial_imu_addon)

# ライブラリ化

ただ、初期化部分が煩雑だったり、読み出しの待ち合わせやブロック読み出しができなかったりで、
ちょっとラッパーが欲しくなり作成しました。


https://github.com/Interested-In-Spresense/SpresenseIMU

これで、コア間への移植とかが楽になったかなということで、SubCoreでのセンシングと、MainCoreでのSDカードなどのマルチコア化ができるようになり、1920Hzのデータも問題なく記録できるようになりました。

で、取得したバイナリを表示するツールも用意して、確認してみました。
https://github.com/Interested-In-Spresense/SpresenseIMU/blob/master/tool/imu_viewer.py

これを動かすとこんな感じ。

1.145461,37.83,0.00,-0.00,0.00,-0.03,-1.96,9.60
1.145974,37.78,0.00,-0.00,-0.00,-0.03,-1.95,9.60
1.146468,37.83,-0.00,0.00,-0.00,-0.03,-1.94,9.63
1.146977,37.84,-0.00,0.00,-0.00,-0.03,-1.94,9.66
1.147478,37.83,-0.00,0.00,-0.00,-0.04,-1.96,9.67
1.147977,37.87,-0.00,0.00,-0.00,-0.04,-1.97,9.66
1.148485,37.83,0.00,-0.00,-0.00,-0.02,-1.98,9.64
1.149020,37.83,0.00,-0.00,0.00,-0.02,-1.97,9.62
1.149511,37.82,0.00,-0.00,0.00,-0.01,-1.96,9.60
1.149978,37.83,0.00,-0.00,0.00,-0.02,-1.94,9.60
1.150494,37.83,0.00,0.00,-0.00,-0.02,-1.93,9.61
1.151099,37.83,-0.00,0.00,-0.00,-0.03,-1.94,9.63

タイムスタンプもそれっぽいし、ファイルのつなぎ目も正しく連続でした。
いいね。

追記（2025/04/15）

SDKからAHRSのサンプルが追加されているのをみて、Arduinoでも簡単に追加できるな～と思い追加しました。

というのも、AHRS（Attitude and Heading Reference System）って、
Arduinoのライブラリにあるんですよね。

https://github.com/arduino-libraries/MadgwickAHRS

なので、これを呼び出すサンプルも追加しました。

https://github.com/Interested-In-Spresense/SpresenseIMU/blob/master/examples/attitude_estimation/attitude_estimation.ino


今後、姿勢推定の見せ方だったり、自己位置推定のサンプルだったり足していけるとよいなあ…。
windows11で、sketchup6 その11

# 概要
windows11に、sketchup6を入れてみた。
rubyで、3Dを書く。
FunShapes.rb、見つけたのでやってみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/9651ab96-de3d-4240-ad7d-2e4298921314.png)


# サンプルコード

```
def tear_drop
	prompt = ["# Iterations : "]
	params = [5]
	result = inputbox(prompt, params, "Imput Tear Drop Parameters")
	if result
		it = [2, result[0]].max
	else
		return
	end
	entities = Sketchup.active_model.entities
	group = entities.add_group
	group_ents = group.entities
	mesh_td = Geom::PolygonMesh.new
	indexes = [0]
	aux_vect = []
	for ind_u in (0..2 * it)
		u = Math::PI * ind_u / (2 * it)
		for ind_v in (0..2 * it - 1)
			v = 2 * Math::PI * ind_v / (2 * it)
			x = 0.5 * (1 - Math::cos(u)) * Math::sin(u) * Math::cos(v)
			y = 0.5 * (1 - Math::cos(u)) * Math::sin(u) * Math::sin(v)
			z = Math::cos(u)
			pt = Geom::Point3d.new(1 * x, 1 * y, 1 * z)
			index = mesh_td.add_point(pt)
			indexes.push(index)
		end
	end
	for ind_u in (1..2 * it)
		for ind_v in (1..2 * it - 1)
			aux_ind = 2 * it * (ind_u - 1) + ind_v
			aux_vect = [indexes[aux_ind], indexes[aux_ind + 2 * it], indexes[aux_ind + 1]]
			mesh_td.add_polygon(aux_vect)
			aux_vect = [indexes[aux_ind+1], indexes[aux_ind + 2 * it], indexes[aux_ind + 1 + 2 * it]]
			mesh_td.add_polygon(aux_vect)
		end
		aux_vect = [indexes[aux_ind + 1], indexes[aux_ind + 1 + 2 * it], indexes[aux_ind + 2 - 2 * it]]
		mesh_td.add_polygon(aux_vect)
		aux_vect = [indexes[aux_ind + 2 - 2 * it], indexes[aux_ind + 1 + 2 * it], indexes[aux_ind + 2]]
		mesh_td.add_polygon(aux_vect)
	end
	group_ents.add_faces_from_mesh(mesh_td)
end
```

以上。
2025年版Elixir×VSCode×コンテナで始めるお手軽環境構築

Elixirは素晴らしい言語仕様を持っています。
しかし、環境構築はかなり厄介です。
システム上OS、Erlang VM,Elixirの処理系といった構造になっているため、どれがどこで行われているのか理解していないと躓きやすくなります。

ながらく、Elixirはasdfを使った環境構築が主流でした。
実際そっちのほうが、オーバーヘッドが少ないのですが、asdf自体も仕様変更で使いづらくなっている面があります。

そこで私はDockerによるコンテナ技術での環境構築をおすすめしています。
特にVSCodeを使うならDevcontainerとの連携がしやすくボタンポチポチ押すだけでElixir＋拡張機能までついてくるので、DXがまるで違います。

Docker毛嫌いしている方も多いのですが、Phoenixアプリを作るならどのみちPostgresが必要で、Postgresが必要になるとDocker使わざるを得ないので、ElixirとDockerは切っても切り離せない関係なのですね。

Windowsでも、Macでも、Linuxでも、同じ手順なのでわかりやすいのも魅力の一つです。

## やり方

テンプレートを作って置きましたので、それを使うのが早いです。

https://github.com/misogihagi/elixir-vscode-template

1. 以下の拡張機能をインストールします。インストールしてたらスキップです。

   https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack
   コマンドだとこうです。
   ```
   code --install-extension ms-vscode-remote.vscode-remote-extensionpack
   ```

2. Use this templateかフォークをしてリポジトリを取り込んでください。

3. 取り込んだリポジトリをVSCodeで開きます。
  
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230043/a733900d-4778-4b38-bfb9-e95792a41f0b.png)
  
4. 左下の><みたいなマークをクリックし、「Repopen in Container」を選択します。

    ![image2.png](https://code.visualstudio.com/assets/docs/devcontainers/containers/remote-dev-status-bar.png)

５．環境構築完了！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230043/43cd8f6e-75a9-4eb5-999a-54dbb8e9e54c.png)

## 感想

これでElixirのややこしい環境構築がこれで少しでも楽になることを祈っています。

## おまけ

Phoenix版もあります。

https://github.com/misogihagi/phoenix-vscode-template
Ubuntu24.04でKnowledgeを動かす

Knowledgeのインストールで少し時間がかかった部分があったので備忘録も兼ねて。

# お断り
動けばいい！って人向け
service登録は他を参考に頑張って
ubuntuのインストールは終わっている前提。
もしKnowledge用のユーザーで動かそうと思っているなら先にユーザーを作っておくこと。

# OS その他version
ubuntu 24.04.2
Open-jdk 8

# Tomcatの準備
Tomcatは9系を使う。
10系、11系はjava17以降のため、Knowledgeが起動できない。
KnowledgeはJava8じゃないと動かなさそう。

今回は/Home/username/tomcatにTomcatのファイルを置くことにした。

downloadコマンド
```
:~/tomcat$ wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.102/bin/apache-tomcat-9.0.102
```

解凍コマンド
```
:~/tomcat$ tar -xzvf apache-tomcat-9.0.102.tar.gz 
```

Startコマンド
```
:~/tomcat/apache-tomcat-9.0.102/bin$ ./startup.sh 
```

tomcatが起動しているか確認する。
http://IPアドレス:8080 にアクセスし、以下画面だったらOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4048036/33c30f87-92d8-4042-aa2e-8e3c98d9c68d.png)

# Knowledgeのインストール

knowledgeのダウンロード
webappsフォルダ内に.warファイルをダウンロードする。
```
:~/tomcat/apache-tomcat-9.0.102/webapps$ wget https://github.com/support-project/knowledge/releases/download/v1.13.1/knowledge.war
```

tomcatの再起動する。

# knowledgeを開く
knowledgeへアクセスする。
http://IPアドレス:8080/knowledge

![スクリーンショット 2025-03-28 185916.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4048036/6128d91b-1bdd-4e5d-9dc0-aeb068dbc637.png)

# 完成！
service登録やらは頑張って
ほな！
最新版: 壊れたアプリを開く（macOS Sequoia15.2）

# はじめに
初投稿です．
友人と共同でunity製音ゲーを開発している，篝火と申します．

https://store.steampowered.com/app/3328530/HARCA/


最近MacBook Pro M4を購入したのですが，開発中のゲームを試遊するため Steam を開こうとしたところ，
```
"steam_osx"は壊れているため開けません。ゴミ箱に入れる必要があります。
```
というエラーが出て開くことができませんでした．
MacOSのセキュリティ対策が年々強化されているためでしょう．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3781239/8e557703-4324-4538-a89d-07a2b6578099.png)
↑ yahoo知恵袋にて同じ悩みを抱えていらっしゃった方．（https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q12233933077）


本記事は，**自己責任の範囲で**端末のセキュリティ設定を変更し，無理矢理開くための備忘録です．2度言いますが，**自己責任**でお願いします．

# やったこと
- 実行権限の変更
    - ```chmod +R +x $(filepath)```とするやつ．効果はなし
- FileVault をオフにする
    -  appの実行権限をすべてのアプリケーションに付与できる．効果なし
- **SIP（System Integrity Protection）の無効化**
    - 効果ありました．以下で解説します
- **Gatekeeper の隔離属性 (com.apple.quarantine)の削除**
    - 効果があるかもしれないので，こちらm解説します

# SIPの無効化手順（有効化もこちらで）
#### 1. Mac をリカバリーモードで再起動
- Intel Mac:
    ⌘ (Command) + R を押しながら起動
- Apple Silicon (M1/M2):
    電源ボタンを長押しして「オプション」→「リカバリーモード」
#### 2. ターミナルを開く
- メニュー > ユーティリティ > ターミナル
#### 3. ターミナルにて下記コマンドを入力
    ```
    csrutil disable
    reboot
    ```
#### 4. 以下のメッセージが表示されたら【ｙ】を入力
```
Turning off System Integrity Protection requires modifying system security.
Allow booting unsigned operating systems and any kernel extensions for OS "●●"? [y/n]:
```
#### 5. 以下のメッセージが表示されたらPCを再起動
```
System Integrity Protection is off.
Restart the machine for the changes to take effect.
```
※SIPを有効化する場合は，3.の手順で`csrutil enable`と入力してください．

# 隔離属性の削除
#### 1. 隔離属性の有無を確認
```
xattr -l $(appファイルのパス)
```
#### 2. もしcom.apple.quarantineが表示されたら，削除する
```
xattr -d com.apple.quarantine $(appファイルのパス)
```

# 結果
開けました！
![スクリーンショット 2025-03-29 1.27.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3781239/c192777c-f5d6-4856-ba00-b58301797b3f.png)

**この後SIPを有効化しても開けるので，忘れずに戻しておいてください！
戻す手順も掲載してありますので，参考にしてくださいね．**

# 参考記事
https://itochu-cable-systems.jp/esb/category/useful/apple/2023/10/6653/

https://qiita.com/seigot/items/49b9fe382767bf59604f

https://qiita.com/shisama/items/5f4c4fa768642aad9e06
【検証】オブジェクト指向の申し子Javaの代名詞とも言えるあの構文が消えた...!?HelloWorldが3行で書けてしまう!?

# 概要
オブジェクト指向の申し子と言っても過言では無いJavaのmain()関数の実装について大きな変更が追加され公開されたという噂を以前から耳にしていました。先日、ネットで以下の記事を見付けました。記事によると、Javaプログラムのmain()関数の実装は随分シンプルな構文になるとのことです。そこで、実際に記事に掲載されている内容を検証してみることにしました。

https://atmarkit.itmedia.co.jp/ait/articles/2503/20/news077.html

:::note warn
現状この変更はプレビュー指定となっており、今後変更される可能性が有ります。
:::

# おさらい
従来Javaのmain()関数は、`Main.java`ファイルに`Main Class`を実装し、`public static void`な関数main()関数として実装していました。筆者は、Javaのプログラムは入社した時の研修でやったぐらいで、それ以降は殆どJavaのプログラムは書いていませんが、今でもあのガチガチにオブジェクト指向に則った実装は覚えています。世界で最も有名な？サンプルプログラムHelloWorldを実装すると以下の様になります。

```java:従来のHelloWorld
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}
```

因みにC言語とPythonでHelloWorldを実装すると以下の様になります。

```C:C言語のHelloWorld
#include <stdio.h>

int main(void)
{
    printf("Hello, world!\n");

    return 0;
}
```

```python:PythonのHelloWorld
print('Hello, world!')
```

これを見るといかにJavaでHelloWorldを実装しようとすると沢山呪文を入力しなければならないか分かります。

# ところがこうなった

しかし、この数年でJavaを取り巻く情勢に変化？が訪れたのか、言語仕様に大きな変更が(試験的に)加わりました。`Main Class`の実装は不要(ビルド時に暗黙的に追加)となり、そもそもファイル名も`Main.java`を強制されないという大盤振る舞い。。。:scream: :scream_cat: 試みに記事の内容を参考に新しい構文でHelloWorldを実装してみます。以下の様になりました。

```Java:新しい構文での実装
static void main() {
    System.out.println("Hello, world!");
}
```

たった三行で書けてしまっています。。。:scream: :scream_cat: 

# 検証
## 検証環境
この新しい構文で実装したHelloWorldを`NewHelloWorld.java`というファイルに保存した上で、ビルド→実行してみようと思います。今回検証に用いた環境は以下です。

* OS: macOS Sequoia 15.3.2
* JDK: Amazon Corretto 24

https://github.com/corretto/corretto-24

## ビルド
従来の方法でビルドしようとすると、以下の様にエラーとなります。

```bash
$ javac NewHelloWorld.java 
NewHelloWorld.java:1: エラー: 暗黙的に宣言されたクラスはプレビュー機能であり、デフォルトで無効になっています。
static void main() {
       ^
  (暗黙的に宣言されたクラスを有効にするには--enable-previewを使用します)
エラー1個
```

ビルドコマンドは以下の様にオプションを指定して実行します。警告は出力されますが、無事ビルドが出来ました。

```bash
$ javac --release 24 --enable-preview -Xlint:preview NewHelloWorld.java 
NewHelloWorld.java:1: 警告: [preview] 暗黙的に宣言されたクラスはプレビュー機能であり、今後のリリースで削除される可能性があります。
static void main() {
       ^
NewHelloWorld.java:1: 警告: [preview] IOはプレビューAPIであり、今後のリリースで削除される可能性があります。
static void main() {
^
警告2個
```

従来の`Main Class`の方式で実装したmain()関数を`Main.java`ではないファイル名で保存し、ビルドしようとすると以下の様に、ビルドエラーになります。

```bash
$ javac test.java 
test.java:1: エラー: クラス Mainはpublicであり、ファイルMain.javaで宣言する必要があります
public class Main {
       ^
エラー1個
```

## 実行
以下の様に、実行時にも`--enable-preview`が必要です。無事`Hello, world!`のメッセージが出力されました。

```bash
$ java --enable-preview NewHelloWorld 
Hello, world!
```

# まとめ
以前から噂を耳にして気になっていたJavaの新構文を試してみました。プレビュー機能ということで今後正式に採用されるか分かりませんが、正式に導入されれば、少なくともmain()関数の実装は楽になるのではないかと思います。

とても詳しく経緯をまとめられている素晴らしい記事を見付けたので参考資料として掲載します。

https://qiita.com/nowokay/items/03e5d720433bd4ba0eec#main%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%AF%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%A7%E3%82%82%E3%82%88%E3%81%8F%E3%81%AA%E3%82%8B

余談ですが、Amazon CorrettoはAmazon版のOpenJDKとのことで、筆者はつい最近知りました。Oracle OpenJDKからの乗り換え先を探していた所だったので、今後は贔屓にさせてもらおうと思います。サポート期間もOracle OpenJDKより一般に長い様です。但し、Correto 24は今年の10月までのサポートなので次のLTS版に今後アップグレード予定です。(この新構文がプレビュー機能から正式機能になりますように :pray: :pray_tone1: :pray_tone2:
Render上のアプリからRenderアプリを停止してみる

# 概要
本記事はRenderを使用してアプリケーションを構築していることを前提としています
運用している中で、「もしも自分しか知らないURLにしているはずだけれども、誰かが適当に打ってみたらアクセスできてしまった！」「不正に利用されてアプリが起動したままになって、意図せずRenderの無料枠を超えてしまう！」みたいな状況を仮定してみようと思います

対策としてはIP制限などが考えられると思いますが、今回はID/パスワード認証に失敗した場合にRender側からAPIを使用してRenderを停止してみようと思います

# Render APIを使ってみる
Renderを停止する方法ですが、APIがあるようです
https://render.com/docs/api

その中でも今回使用するのは、「Suspend service」というAPIです
https://api-docs.render.com/reference/suspend-service-1
(正直なところここまでしたくはないのですが、即時sleepできるAPIがないようで、、)

兎にも角にもAPIを利用するためには、まずはAPIキーを作成します

手順は公式ページの通りに進めればよいかと思います
手順通りに進めてcurlの確認が取れたら次のステップに行きたいと思います

suspend APIを実行してみます
実際にRender上でアプリを稼働させておいてください

```sh
curl --request POST \
     --url https://api.render.com/v1/services/${serviceId}/suspend \
     --header 'accept: application/json' \
     --header 'authorization: Bearer ${your_api_token}'
```

小さいですが、以下の感じで完全に利用することができなくなります

![スクリーンショット 2025-03-29 0.34.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701238/eb1d0c06-283a-4568-8e31-fcf6c1e903e2.png)

再開させる時は「Resume service」というAPIを利用します

```sh
curl --request POST \
     --url https://api.render.com/v1/services/${serviceId}/resume \
     --header 'accept: application/json' \
     --header 'authorization: Bearer ${your_api_token}'
```

ということであとはRender上のアプリからこれらのAPIを呼び出せば問題なさそうですね

# 実装
今回はID/パスワード認証にしようと思いましたが、認証処理用のアプリを作ったりした方が良さそうだったので今回はリクエストを送るとアプリが停止するといった処理だけにとどめます

APIリクエストに必要な情報はハードコーディングしたくないので環境変数で管理しましょう
対象サービスの管理画面中のEnvironmentというところから設定が可能です

```py
RENDER_API_KEY = os.getenv("RENDER_API_KEY")
RENDER_SERVICE_ID = os.getenv("RENDER_SERVICE_ID")
```

また、python上でのAPIリクエストはお馴染みのrequestsモジュールを使います(requirements.txtの更新もお忘れなきよう)

```py
import requests

url = "https://api.render.com/v1/services/${RENDER_SERVICE_ID}/suspend"

headers = {
    "accept": "application/json",
    "authorization": "Bearer ${RENDER_API_KEY}"
}

response = requests.post(url, headers=headers)

print(response.text)
```

実際にgithubにコミット・プッシュしてみるとわかると思うのですが、アプリが即シャットダウンされるのでページが開けなくなっていることが確認できると思います

# おわりに
今回はRender APIをRenderアプリ上から実行してみるということを試してみました
まだまだ、種類はあるので他も調べつつ自分のやりたいことを実現できる方法を具現化していきたいと思います
挿入ソートの要点

## 挿入ソートとは？
挿入ソートは、ソートアルゴリズムの中でも直感的で分かりやすいアルゴリズムです。具体的には、手持ちのトランプを並べ替える際に使用されます。英語では"insertion sort"といいます。

## 挿入ソートの直感的な解説
トランプを例に挙げます。任意のカードを1枚取ります。そして、その時点のすでにソートされた並びで最も適切な位置に挿入するのです。これを左のカードから順にやっていくことでソートします。

## コード例（Python）
```python:insertion_sort.py
def insertion_sort(arr):
    """
    挿入ソートを用いてリストを昇順に並び替える関数。
    :param arr: ソートするリスト
    :return: ソート後のリスト
    """
    for i in range(1, len(arr)):
        key = arr[i]
        j = i - 1
        while j >= 0 and arr[j] > key:
            arr[j + 1] = arr[j]
            j -= 1
        arr[j + 1] = key
    return arr

# 使用例
if __name__ == "__main__":
    sample_list = [5, 3, 8, 6, 2, 7, 4, 1]
    sorted_list = insertion_sort(sample_list)
    print("ソート後のリスト:", sorted_list)

```

このコードを使用すると、数字の列が昇順にソートされます。つまり、
```
ソート後のリスト: [1, 2, 3, 4, 5, 6, 7, 8]
```

と出力されます。

比較演算子を次のように使用することにより、降順にもできます。

```
while j >= 0 and arr[j] < key:  # 条件を `>` から `<` に変更
```

## 終わりに
今回はPythonを用いて、挿入ソートの解説をしました。いかがでしたでしょうか。ぜひ感想をいただけると幸いです。
Geminiでロープレのシーンを描いてもらった。

# 概要

Geminiでロープレのシーンを描いてもらいました。

# 実装

以下のようなリクエストを出しました。

```
面白そうなスマートフォン向けゲームの絵を描いてみてください。
```

![面白そうなスマートフォン向けゲームの絵_20250329.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192024/a2f67df3-918c-44ca-9ee6-a2404abd0fd4.png)

なんだか面白そうな感じはします。

```
ロールプレイング・ゲームで戦闘シーンを描いてみてください。 
```

![ロールプレイング・ゲームで戦闘シーン_20250329.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192024/ec3da305-a036-4245-9f4e-d36ebe09be36.png)

うまく描けていると思います。

```
勇者が魔王を倒すシーンを描いてみてください。
```

![勇者が魔王を倒すシーン_20250329.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192024/a8324c29-d42a-4940-b050-f89bf986db37.png)

いいと思います。

```
火の魔法と氷の魔法を打ち合っているシーンを描いてみてください。
```

![火の魔法と氷の魔法を打ち合っているシーン_20250329.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192024/6da5c5ab-de39-493f-95c4-fccd0b79f02e.png)

```
剣と魔法の連携で魔王を倒すシーンを描いてみてください。
```

![剣と魔法の連携で魔王を倒すシーン_20250329.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192024/72833d14-a8ea-40f5-b993-fa4493574fb7.png)

```
勇者とドラゴンが戦闘しているシーンを描いてみてください。
```

![勇者とドラゴンが戦闘しているシーン_20250329.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192024/71ca8b22-d804-422a-915e-518b51caed99.png)

```
魔法少女が魔女と戦っているシーンを描いてみてください。 
```

![魔法少女が魔女と戦っているシーン_20250329.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192024/3e78e898-91a2-48dc-9d04-2bf6e52d5bd6.png)

# まとめ

何かの役に立てばと。
p5.jsで曲線の内側と外側を判定する

# はじめに
　線をつないでループする曲線を作る。それの内側と外側を判定する。

　[isInside](https://openprocessing.org/sketch/2595184)
```js
function setup() {
  const points = [];
  let lastPoint = createVector();
  let isDrawing = false;
  let isFinished = false;
  const randomPoints = [];
  for(let i=0; i<200; i++){
    randomPoints.push(createVector(random(400), random(400)));
  }
  
  createCanvas(400, 400);
  mousePressed = () => {
    lastPoint.set(mouseX, mouseY);
    points.push(lastPoint.copy());
    isDrawing = true;
  }
  mouseReleased = () => {
    isDrawing = false;
    if(dist(lastPoint.x, lastPoint.y, points[0].x, points[0].y) > 8){
      points.length = 0;
    }else{
      points.push(points[0].copy());
      isFinished = true;
    }
  }
  
  draw = () => {
    background(0);
    if(isDrawing && mouseIsPressed){
      if(dist(mouseX, mouseY, lastPoint.x, lastPoint.y) > 8){
        lastPoint.set(mouseX, mouseY);
        points.push(lastPoint.copy());
      }
    }
    stroke(255);
    for(let i=0; i<points.length-1; i++){
      line(points[i].x, points[i].y, points[i+1].x, points[i+1].y);
    }
    noStroke();
    if(!isFinished){
      fill("blue");
      for(const p of randomPoints){ circle(p.x, p.y, 5); }
    }else{
      for(const p of randomPoints){
        if(isInside(p, points)){fill(255);}else{fill("blue");}
        circle(p.x, p.y, 5);
      }
      noLoop();
    }
  }
}

function isInside(p, points){
  let angleSum = 0;
  for(let k=0; k<points.length-1; k++){
    const q = points[k].copy().sub(p);
    const r = points[k+1].copy().sub(p);
    angleSum += q.angleBetween(r);
  }
  angleSum = Math.abs(angleSum);
  if(Math.round(angleSum/TAU) % 2 === 1){
    return true;
  }
  return false;
}
```
実行結果

![wf3wr3r3r33333.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/437349/5280b8ea-5a59-4e1d-8d60-e759b33379d2.png)

![wwegege.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/437349/992424b1-9bf8-4884-b895-e8f6eeae1fc6.png)

このように、マウスで曲線というかまあ折れ線、を作った時に、それらが囲む点だけ色が付く。曲線の内側と外側を判定している。内側の点だけ白くなるような仕組み。なお自己交叉する場合はevenoddルールに従って内外判定するものとする（2枚目）。

## コードの概要
　あらかじめ200個の点がランダムに配置されている。マウスプレスで線を引き始める。マウスリリース時に最初の点と離れている場合はやり直し、近い場合、曲線が成立し、内側と判定された点の色が白に変わる。それでコードの再生も終わる。

## メインコード
　内外判定しているのはここである。
```js
function isInside(p, points){
  let angleSum = 0;
  for(let k=0; k<points.length-1; k++){
    const q = points[k].copy().sub(p);
    const r = points[k+1].copy().sub(p);
    angleSum += q.angleBetween(r);
  }
  angleSum = Math.abs(angleSum);
  if(Math.round(angleSum/TAU) % 2 === 1){
    return true;
  }
  return false;
}
```
pointsは点列で、頭とおしりは同じ点である。$p$が調べる点である。pointsの連続する点について、$p$からその点に向かうベクトルを用意する。その際の角度の変化をangleBetweenで計算する。これは向きを考慮して符号付きの値を返すので累積を計算すると点の周りを曲線がぐるっと回っているかがわかる。具体的にはTAUの奇数倍の時に内側である。偶数倍の時に外側となる（0の場合も含めて）。ただし先ほども述べたように自己交叉がある場合はevenoddに従う。

# おわりに
　ここまでお読みいただいてありがとうございました。

## 追記：
　スマホだとmousePressedが機能しないようです。おかしいな...1.9.1以降ですね。
ginのアプリケーションをGCPのCloud Run functions(第2世代)にデプロイする

## 背景

Ginでバックエンド開発をしている際に、GinをCloud Run functionsでエンドポイントごとに関数をデプロイしたかったものの、公式ドキュメントを含め掲載されていなかったため、備忘録として執筆しました

## 本記事の対象者
今後Cloud Runで実装する予定ではあるが、簡易的に関数をデプロイして、アプリをリリースしたいと考えている方。(非常にニッチですね ^^)

## 方法

早速ですがコードの方を見ていきます。


#### ディレクトリ構成
```bash
#ディレクトリ構成
 arumonogohan-app git:(main) ✗ tree
.
├── app.yaml #GCP設定用ファイル
├── cmd
│   └── main.go #ローカル開発用
├── gcp_functions.go #GCP
├── go.mod
└── go.sum
```

`go.mod`,`go.sum`と同じルート階層にデプロイするためのファイルを作成します。



```go
//gcp_functions.go (ファイル名は任意)

package gcp //パッケージ名も任意

import (
	"net/http"

	"github.com/GoogleCloudPlatform/functions-framework-go/functions"
	"github.com/gin-gonic/gin"
	"github.com/kikudesuyo/arumonogohan-app/api/handler"
)

func init() { 
	functions.HTTP("LinbotCallback", func(w http.ResponseWriter, req *http.Request) {
		// Ginのルーターを作成
		r := gin.Default()
		// Ginのハンドラを定義
		r.POST("/callback", handler.HandleLinebotCallback)

		// リクエストをGinに渡して処理させる
		r.ServeHTTP(w, req)
	})
}

```

GCPにデプロイする際にはinit関数を探して、その中に記載されているエンドポイントをデプロイします。

また、`functions-framework-go/functions`のfunctions.HTTPの引数は以下のようになります。

```go
//functions.HTTPメソッド

func functions.HTTP(name string, fn func(http.ResponseWriter, *http.Request))
HTTP registers an HTTP function that becomes the function handler served at "/" when environment variable `FUNCTION_TARGET=name`
```

このことから第一引数には関数の名前、第二引数には(http.ResponseWriter, *http.Request)型の関数を用意する必要があります。

しかし、既にGinのアプリケーションで開発されたハンドラの引数は、
`func HandleLinebotCallback(c *gin.Context)`
となっており、型の違いによるエラーが発生してしまします。
そのため、`http`から`Gin`へキャストすることで、解決出来ます。


### さいごに
GCPのCloud Run functionsでGinのアプリケーションをデプロイすることが出来ました。ローカルの環境とクラウドの環境が変わってしまいコードが汚くなってしまいがちでしたが、うまくローカルとクラウドの棲み分けをすることが出来たためクラウドに依存することなく実装することが出来ました。Vercelにデプロイしたときはディレクト
リ構成が非常に汚くなってしまったのでGCPに感動しています。
ローカル環境とクラウドとの環境の差異が小さいため、学習コストが低く、初心者が最初にデプロイするのにピッタリだと思いました。

また、今回の発見により、「コードの品質を保つ」+「学習コストが低い」+「サーバーレスで費用が小さい」という最高の3要素を実現出来たため非常に満足しています。是非参考にしてみてください。
aws cliの認証情報の設定



# aws cliの認証情報の設定

## IAMの設定

まず、ルートユーザでログインしている人は、IAMユーザを作成しましょう。すでにIAMユーザを作成している人は、次のステップに進んでください。

:::warn
ルートユーザでの操作は、セキュリティ上のリスクがあるため、IAMユーザを作成して、そのユーザで操作することをお勧めします。
:::

1. AWS Management Consoleにログインします。
2. IAMサービスに移動します。
3. 左側のメニューから「ユーザー」を選択します。
4. 「ユーザーを追加」をクリックします。
5. ユーザ名を入力
6. IAMユーザの作成
  - aws cliを使うので Identify CenterではなくIAMユーザを選択
7. グループの追加
  - ここでは、PowerUserAccessポリシーを選択したpracticeというグループを作成して、そこに追加します。
8. ユーザの作成

ルートユーザで、作成したIAMユーザのアクセスキーとシークレットキーを取得します。
1. IAMサービスに移動します。
2. 左側のメニューから「ユーザー」を選択します。
3. 作成したIAMユーザを選択します。
4. 「セキュリティ認証情報」タブを選択します。
5. 「アクセスキーの作成」をクリックします。
6. アクセスキーIDとシークレットアクセスキーをコピーします。


## aws cliのインストール
aws cliは、AWSのコマンドラインインターフェースです。これを使うことで、AWSのリソースをコマンドラインから操作することができます。

```bash
# brewでaws cliをインストール
brew install awscli
```

```bash
# aws cliのバージョンを確認
aws --version
```

## aws cliの認証情報の設定
aws cliの認証情報を設定するには、以下のコマンドを実行します。

```bash
aws configure
```
このコマンドを実行すると、以下のようなプロンプトが表示されます。

```bash
AWS Access Key ID [None]: <アクセスキーID>
AWS Secret Access Key [None]: <シークレットアクセスキー>
Default region name [None]: <リージョン名>
Default output format [None]: <出力形式>
```
- `<アクセスキーID>`: IAMユーザのアクセスキーIDを入力します。
- `<シークレットアクセスキー>`: IAMユーザのシークレットアクセスキーを入力します。
- `<リージョン名>`: デフォルトのリージョン名を入力します。例: `ap-northeast-1` (東京リージョン)
- `<出力形式>`: デフォルトの出力形式を入力します。例: `json` (JSON形式)
  - `text` (テキスト形式)
  - `table` (テーブル形式)
  - `yaml` (YAML形式)
  - `yaml-stream` (YAMLストリーム形式)
  - `csv` (CSV形式)

これで、aws cliの認証情報の設定が完了しました。
aws cliを使って、AWSのリソースを操作することができます。
【Zed】入力時にマウスカーソルを非表示にする方法

設定ファイルで`hide_mouse_while_typing`を使用して入力時にマウスカーソルを非表示にするか設定できます。
デフォルト値は`true`です。

## 非表示にする

```jsonc:settings.json
{
  "hide_mouse_while_typing": true
}
```

![screen-recording-8.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/65250199-f7c2-44a2-8b56-ce5974bce107.gif)

## 非表示にしない

```jsonc:settings.json
{
  "hide_mouse_while_typing": false
}
```

![screen-recording-7.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/7fbc9981-574a-4d38-9b00-ec696fb99a1c.gif)
【WSL】Windowsのパスをcdで移動できない問題と解決策　初心者あるある

# 【WSL】Windowsのパスをcdで移動できない問題と解決策

## 🛑 問題：WSLでWindowsのパスを`cd`しようとするとエラー

WSL（Windows Subsystem for Linux）上でWindowsのパスに移動しようとすると、以下のようなエラーが出ることがあります。

```sh
user@LAPTOP:~$ cd C:\Users\your_username\Desktop\your_project_folder
-bash: cd: C:Usersyour_usernameDesktopyour_project_folder: No such file or directory
```

また、`./` をつけてもエラーになります。

```sh
user@LAPTOP:~$ cd ./ C:\Users\your_username\Desktop\your_project_folder
-bash: cd: too many arguments
```

## 🔍 原因
WSLはLinuxの環境で動作しており、Windowsのパス表記（`C:\Users\...`）はそのままでは認識されません。
- Windowsのパスは **WSL内では異なる形式** で表される。
- `cd ./` の後にスペースを入れると、**複数の引数が渡されたと解釈されエラー** になる。

## ✅ 解決策：WindowsのパスをWSLの形式に変換

Windowsのパスは、WSL内では以下のように変換する必要があります。

### **1️⃣ `C:\` を `/mnt/c/` に変換**
`C:\Users\your_username\Desktop\your_project_folder` は、WSLでは以下のように記述します。

```sh
cd /mnt/c/Users/your_username/Desktop/your_project_folder
```

✅ これで正しくディレクトリに移動できます！ 🎉

### **2️⃣ `cd ./` にスペースを入れない**
誤った書き方：
```sh
cd ./ C:\Users\your_username\Desktop\your_project_folder
```
➡️ `cd` の引数が2つあるように解釈されてしまい、エラーになります。

**正しい書き方：**
```sh
cd /mnt/c/Users/your_username/Desktop/your_project_folder
```
または、カレントディレクトリ内で移動するなら：
```sh
cd ./your_project_folder
```

## 💡 まとめ
| エラーの原因 | 解決策 |
|-------------|---------|
| Windowsのパス（`C:\Users\...`）をそのまま使っている | `/mnt/c/Users/...` に変換する |
| `cd ./` の後にスペースを入れている | スペースを入れずに正しい形式で記述する |

WSLでWindowsのファイルにアクセスするときは **パスの変換を意識する** ことが大切です！

### 🚀 これでスムーズにWSLを使いこなそう！
ONLYOFFICE APIの基本：ドキュメント編集をウェブアプリに統合する方法

多くのウェブアプリが日常業務の質を向上させるためにドキュメント編集機能を追加しています。ONLYOFFICE APIは、このプロセスをよりスムーズで簡単にする方法を提供します。本記事では、ONLYOFFICE APIの基本的な概念および機能を把握し、それを使ってウェブアプリケーションにドキュメント編集を統合する具体的な手順を紹介します。

## ONLYOFFICE APIとは？

### コアコンセプトと機能

ONLYOFFICE APIは、高機能なドキュメント編集機能をウェブアプリケーションに追加するためのツールキットです。このAPIを使用すると、ユーザーはブラウザ上でドキュメントを編集したり、リアルタイムで共同作業を行ったりできます。以下がその主な特徴です：

* 高度な編集機能：文書、スプレッドシート、プレゼンテーションを編集
* リアルタイムコラボレーション：複数のユーザーが同時に同じファイルを編集可能
* マルチフォーマット対応：Microsoft OfficeやOpenDocument形式を含む、幅広いファイル形式に対応
* プラグインと拡張：AIプラグインやその他のツールを統合して、カスタマイズ性を向上

### 主要コンポーネント  
* ドキュメントエディタ：テキストドキュメント、スプレッドシート、プレゼンテーション、PDFフォームの作成・編集機能を提供し、多様な拡張子をサポート。  
* JavaScript SDK：ドキュメントの埋め込みやカスタマイズに役立つツール。  
* OAuth API：安全な認証とアクセス権限管理を可能にする。  

## ウェブアプリへのONLYOFFICE APIの統合ステップ

### ステップ1：ライセンスの取得

最初に、ONLYOFFICE APIを利用するためのライセンスを取得します。

1. 必要に応じて[ONLYOFFICE Docs](https://www.onlyoffice.com/ja/download-developer.aspx#docs-developer)または[ONLYOFFICE DocSpace](https://www.onlyoffice.com/ja/download-developer.aspx#docspace-developer)の開発者版をインストールします。  
1. インストールされた製品のライセンスを取得します：[ONLYOFFICE Docs](https://www.onlyoffice.com/developer-edition-prices.aspx)、[ONLYOFFICE DocSpace](https://www.onlyoffice.com/docspace-developer-prices.aspx)

### ステップ2：ドキュメントエディタの埋め込み

ドキュメントを埋め込む際には、JavaScript SDKを使用します。以下のコードスニペットは、このプロセスを簡単に説明しています：

```javascript
var docEditor = new DocsAPI.DocEditor("placeholder", {
    "document": {
        "fileType": "docx",
        "key": "unique-doc-key",
        "url": "https://example.com/path-to-file",
    },
    "editorConfig": {
        "callbackUrl": "https://your-app.com/callback",
        "lang": "ja"
    }
});
```

このコードでplaceholderには、ドキュメントが表示されるHTML要素のIDを指定します。

### ステップ3：リアルタイムコラボレーション設定

1. editorConfig内の設定を調整して、共同作業モード（リアルタイム/段落ロック）を有効化します。
1. 共同編集中の注釈やチャット機能の設定を追加できます。

### ステップ4：API接続テスト

1. サーバーログを活用してエラーを確認してください。
1. 提供されるドキュメントフォーマットの整合性を保証するために、テストファイルを使用します。

### ベストプラクティス

* セキュリティ強化：JWTを利用して不正アクセスを防止しましょう。
* レスポンス時間最適化：CDNを活用してリソースのスピードを向上。
* UX/UI強化：埋め込んだエディタのデザインをアプリのスタイルに合わせてカスタマイズ。  

## 実際の使用例

### 1. AgiLabの統合

AgiLabは、ONLYOFFICEの機能を取り入れることで、研究者が文書を直接編集および管理できるようにしました。これにより、研究やデータ分析に集中する時間が増えました。
詳しくは[こちら](https://www.onlyoffice.com/blog/ja/2023/07/agilab-onlyoffice)

### 2. FileBlogとの連携

FileBlogという日本発のファイル検索システムにONLYOFFICE Docsを統合することで、セキュアな環境でドキュメントを共同編集できるようになりました。
詳しくは[こちら](https://www.onlyoffice.com/blog/ja/2022/11/fileblog-with-onlyoffice-docs)

これらの事例は、ONLYOFFICE APIが単なるドキュメントエディタ以上の価値を持つことを示しています。

## よくあるトラブルシューティング

* 編集モードが読み取り専用になる：APIキーやURL設定を確認し、適切な認証情報を提供。
* リアルタイム同期が遅延する：ネットワーク設定を見直し、WebSocket接続が有効であることを確認。
* ファイル形式非対応のエラー：ONLYOFFICEがサポートする対応形式の最新リストを確認。

## 開発者へのメッセージ

ONLYOFFICE APIの統合により、ドキュメント編集を自分のウェブアプリにシームレスに追加でき、さらに大きな可能性が広がります。この機会に、以下の公式サイトからONLYOFFICEの魅力をもっと探求してみてください：

[ONLYOFFICE API公式サイト](https://api.onlyoffice.com)

さあ、ウェブアプリに新次元の機能を取り入れてみませんか？
DeepFake, inswapper_128.onnx

DeepFakeを調査していたら、下記のGithubにたどり着きました。

https://github.com/s0md3v/roop/tree/main

をUbuntu22.04にInstallして

```shell
python run_pdb.py -s images/powell.jpg -t images/000002.jpg -o im
ages/out/
```

を実行すると、target(images/000002.jpg)の顔をsource(images/powell.jpg)風に変換することができます。

images/powell.jpg:
![powell.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4041151/c8d08679-02a1-4069-a055-c499be8a5962.jpeg)

images/000002.jpg:
![000002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4041151/839ffd11-3ac9-4e6b-b824-c40ff517265e.jpeg)

なら、実行結果は

images/out/powell-000002.jpg
![powell-000002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4041151/dfd3583e-63f4-4cd4-8981-4b45db50b5b1.jpeg)

となります。

ソースをデバックしてみると、

https://github.com/deepinsight/insightface/blob/master/python-package/insightface/model_zoo/inswapper.py

の46~56行目でinswapper_128.onnxがsession.run()されていた。

```python
    def get(self, img, target_face, source_face, paste_back=True):
        aimg, M = face_align.norm_crop2(img, target_face.kps, self.input_size[0])
        blob = cv2.dnn.blobFromImage(aimg, 1.0 / self.input_std, self.input_size,
                                      (self.input_mean, self.input_mean, self.input_mean), swapRB=True)
        latent = source_face.normed_embedding.reshape((1,-1))
        latent = np.dot(latent, self.emap)
        latent /= np.linalg.norm(latent)
        pred = self.session.run(self.output_names, {self.input_names[0]: blob, self.input_names[1]: latent})[0]
        #print(latent.shape, latent.dtype, pred.shape)
        img_fake = pred.transpose((0,2,3,1))[0]
        bgr_fake = np.clip(255 * img_fake, 0, 255).astype(np.uint8)[:,:,::-1]
```

inswapper_128.onnxの入力は２種類で、

target(=blob): 1x3x128x128
source(=latent): 1x512

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4041151/6f10a0e2-56f0-4682-af40-bc90678cff32.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4041151/a69891b2-e544-4180-bb55-e86744ff65b4.png)

出力は１種類、

output(=pred): 1x3x128x128 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4041151/a2e0e2d1-090d-4a01-ab92-711e60705c67.png)

inswapper_128.onnxを単体で動かすためには、

- step1. target画像から顔画像をcrop, 正規化して、1x3x128x128にreshapeしたtensorを用意(=blob)
- step2. source画像からxxxして1x512のtensorを用意(=latent)
- step3. blobとlatentをinswapper_128.onnxに入力

する必要がある。

Step2.のxxxが何してるか調査中。。
カンバン方式の1週間：ストーリーで見る実践ガイド

## 舞台設定：株式会社🙆🙆‍♀️🙆‍♂️イノベーション、Webアプリ開発チーム

**メンバー**：プロジェクトリード佐藤さん、フロントエンド田中さん、バックエンド鈴木さん、テスト山田さん、デザイン伊藤さん

## 月曜日：作業の可視化と計画

**朝のカンバンミーティング（15分）**
佐藤さんがJiraのカンバンボードを大画面に映し、チームが集まります。

「先週から引き続きこの5タスクが『作業中』ですね。今週は何を優先すべきでしょうか？」

みんなでバックログを確認し、優先度の高いタスクをいくつか「未着手（To Do）」列の上部に移動します。

**明示的なポリシーの確認**
ボード横の壁には「完了の定義」が掲示されています：
- ✅ コードがリポジトリにマージ済み
- ✅ テストが全て通過
- ✅ ドキュメント更新完了
- ✅ デプロイ担当者の承認済み

「先週のフィードバックで、レビュー待ちが長いという課題がありましたので、新しいルールを導入します：レビュー依頼から24時間以内に対応すること」と佐藤さん。

## 火曜日：WIP制限の実践

田中さんが新しいタスクを始めようとしたとき、佐藤さんが声をかけます。

「田中さん、『作業中』列を見てください。既に3つのタスクに取り組んでいますよね。WIP制限は2なので、まずは進行中のタスクを完了させましょう」

田中さん：「確かに。あのタスクはレビュー待ちだから、鈴木さんにレビューを急いでもらいます」

**フローの管理の実践**
チームはカンバンボードを見て「レビュー待ち」列に4つのタスクが溜まっていることに気づきます。

佐藤さん：「ここがボトルネックですね。今日は全員で1時間レビュー時間を確保しましょう」

## 水曜日：課題管理の統合

朝のミーティングで山田さんが報告します。

「テスト環境で新しいバグを見つけました。カンバンボードに『障害』タイプで登録しました。これは『ユーザー登録API』タスクの完了をブロックしています」

**カンバンボードでの表示**
- 赤色の「障害」カードが作成され、関連タスクとリンク
- 「ユーザー登録API」タスクに「ブロック中」のフラグが付く

佐藤さん：「優先度高なので鈴木さん、これから対応できますか？」
鈴木さん：「今のタスクが完了次第、今日中に取り掛かります」

## 木曜日：フィードバックループの実装

チームが30分の「カンバンレビュー」を実施します。

**データの確認**
佐藤さんがJiraから出力したメトリクスを共有：
- 先週のスループット：7タスク完了
- 今週（現時点）：4タスク完了
- 平均リードタイム：3.5日

**改善点の議論**
田中さん：「レビュー待ち時間が短くなりましたね」
鈴木さん：「バグ修正が多くて新機能開発が遅れています」
山田さん：「テストを早めに始めるために、開発70%完了時点でもテスト環境にデプロイしてはどうでしょう？」

チームは山田さんの提案を採用し、新しいルールとしてカンバンボード横に記載します。

## 金曜日：週次報告とフロー改善

**進捗レポートの作成**
佐藤さんがカンバンボードからフィルターを使って週次レポートを作成：

1. **実績報告**（ステータス=完了, 期間=今週）
   - 完了タスク：6件（先週比-1）
   - 注目完了機能：「画像アップロード機能」
   - 平均リードタイム：3.2日（先週比-0.3日）

2. **予定報告**（作業中 + To Do上位）
   - 来週完了予定：5件
   - 新規着手予定：「SNS連携機能」「通知システム改善」

3. **課題報告**
   - 未解決課題：2件（「ログインエラー」「画面描画遅延」）
   - 解決済み課題：1件（「API接続エラー」）

**1週間の振り返り**
チームは15分間の「カンバンカフェ」を実施：
- 伊藤さん：「WIP制限のおかげで1つのタスクに集中できました」
- 田中さん：「障害対応でフロー効率が下がりました。来週は予防に注力しましょう」
- 佐藤さん：「1週間でスループットが安定してきました。次の目標はリードタイムをさらに1日短縮すること」

## 翌週月曜日：新たなサイクルの開始

先週のフィードバックを元に2つの改善を実施：

1. バグの事前検出のため、コードレビューのチェックリスト追加
2. 「テスト中」ステータスを新設し、開発70%地点から並行実施

**カンバンミーティング**
「新しいフローと明示的なポリシーで、今週はよりスムーズに進められるはずです。では、今週の優先タスクを決めましょう...」

---

このようにカンバン方式は特別な仕組みではなく、日々の開発活動をより「見える化」し、継続的に改善していくアプローチです。スプリントのような固定期間がなくても、週単位のリズムを作ることで規則的な振り返りと改善が可能になります。
ターミナル　基本コマンド

# 表示・移動系
pwd : 現在のディレクトリを表示

ls : ファイル、ディレクトリ一覧を表示
```
ls #ファイルをすべて横並びで表示
ls -l #ファイルの詳細も表示
ls -a #.で始まるファイルも表示
ls -t #更新順で表示
ls -s #サイズの大きい順で表

以下のように組み合わせも可
ls -lt #ファイルの詳細を更新順で表示
```

cd : 作業ディレクトリの移動
```
cd directory_name # 現在のディレクトリ内のdirectory_nameに移動
cd ~　# /home/ユーザー名 に移動
cd / #システムの最上位のディレクトリに移動
cd - #ひとつ前のディレクトリに移動
```

# ファイル作成系
touch : ファイルのタイムスタンプを作成・からのファイルを作成
```
touch newfile.txt # 新しいnewfile.txtというファイルを作成
touch -d "YYYY-MM-DD HH:MM:SS" #指定した日付にタイムスタンプを更新
```

mkdir : 新しいディレクトリ（フォルダ）を作成する コマンド
```
mkdir new_directory #新しいnew_directoryというディレクトリ(フォルダ)を作成

補足
rmdir new_directory #ディレクトリを削除
```

cp [オプション] コピー元 コピー先
```
cp file1.txt file2.txt    # file1を file2という名前でコピー（同じディレクトリ内）

cp file1.txt /home/user/Documents/  #file1を /home/user/Documents/ フォルダにコピー

cp -r myfolder newfolder    #myfolder ディレクトリごとnewfolderにコピー

```

# ファイル移動系
mv [オプション] 移動元 移動先　
```
mv file1.txt /home/user/Documents/   #file1を/home/user/Documents/に移動

mv oldname.txt newname.txt    #old_folder の名前を new_folder に変更

mv myfolder /home/user/backup/   #myfolder を /home/user/backup/ に移動

```

# ファイルの削除
rm [オプション] 削除対象　#削除したファイルは基本的に復元できないので注意！

```
rm file1.txt   # file1.txt を削除

rm -i file1.txt   #削除する前に「本当に削除しますか？」と聞かれる(推奨)

rm -r myfolder    #myfolder を 中のファイルごと削除

rm *.log   #カレントディレクトリ内の .log ファイルをすべて削除
```
【Postfix】 Gmailをリレーホストとして使った場合、転送メールのDKIMがFAILになる

たとえば、 `/etc/postfix/main.cf` で 

```
relayhost = smtp.gmail.com:587
smtp_sasl_password_maps = hash:/etc/postfix/xxxxx
```

などと設定して、メールをGmail経由で送信できるようになったとします。この場合、上記 `/etc/postfix/xxxxx` で指定しているGmailのアドレスを、仮に YYYYYYYYYYYYYY@gmail.com として話を進めます。

で、そうなると自分管理の root@XXXXX.com などへのメールを自分のGmailアカウントなどに転送したくなります。で、 `/etc/aliases` に

```
root:           XXXXXXXXXXXXXX@gmail.com
```

などと書きますが、実際、 root@XXXXX.com に、たとえば xxx@xxxxx.xx.xx から試験メールを送って、 XXXXXXXXXXXXXX@gmail.com のメールボックスの当該メールの `原文を表示` とすると、

```
DKIM:	'FAIL'（ドメイン: xxxxx.xx.xx）詳細
```

と表示されることがあります。

原因は、試験メールの送り元の xxxxx.xx.xx が、既に `DKIM-Signature:` ヘッダをつけちゃっていて、そのヘッダがあるとGmailは自身の `DKIM-Signature:` を付加したり書き替えたりしない、ということです。それでも、メールそのもののfromは YYYYYYYYYYYYYY@gmail.com であるので、DKIMがFAILになるわけです。

それで、 `/etc/postfix/main.cf` で 

```
header_checks = regexp:/etc/postfix/header_checks
```

とし、 `/etc/postfix/header_checks` で

```
/^DKIM-Signature:/ IGNORE
```

として、転送するときに、最初の送信元の `DKIM-Signature` ヘッダを削除してしまえば、Gmailが YYYYYYYYYYYYYY@gmail.com のための `DKIM-Signature` ヘッダをよろしく付加してくれるので、

```
DKIM:	'PASS'（ドメイン: gmail.com）詳細
```

となり、すべてがまるくおさまり、世界が平和になるというわけです。

以上
音響学のカリキュラムを考えてみた

音響学（基礎）

純音と正弦波
正弦波の基本的な性質には、周期、振幅、周波数がある。純音は単一の周波数成分だけを持ち、スペクトルでは鋭いピークとして表れる。

複合音と倍音構成
複合音は複数の周波数成分から成り、基本周波数とその整数倍の倍音から構成される。音色は倍音の構成比によって変化する。これを利用した加算合成では、複数の正弦波を足し合わせて音を合成する。

音の三要素
音の大きさは振幅に関係し、ラウドネスと呼ばれる。音の高さは周波数によって決まり、ピッチと呼ばれる。音色は波形と倍音構成によって決まり、音の「質感」を決定づける。

音の大きさ
音圧の大きさはデシベル（dB）で表され、相対的な指標である。A特性フィルターは人間の耳の感度に基づいた補正曲線であり、騒音計などで使われる。

音の高さ
周波数（Hz）は音の高さを決定する。楽器の鍵盤と周波数の関係は数学的に規則性があり、ピッチクラスやオクターブの概念によって整理される。

音色の違い
サイン波・矩形波・鋸波・三角波など、波形によって含まれる倍音の構成が異なる。音色の特徴を決定づけるのはこの倍音構造である。

サウンドの仕組み

サンプリング理論
アナログ信号をディジタル化するためには、ナイキストの定理に従い、信号の最高周波数の2倍以上のサンプリング周波数が必要である。サンプリング周波数の設定は、音質とデータ量のバランスを考慮して決定される。

標本化（離散化）
連続的な波形を一定の時間間隔でサンプルすることで、離散的なデータに変換する。これはディジタル処理の第一歩である。

量子化
標本化された信号の振幅を、限られた段階に分けて近似する。ビット数が多いほど細かく表現でき、量子化誤差は小さくなる。

音声ファイルの構造
WAVEファイルなどの音声データ形式は、ヘッダー情報とデータ部から構成される。サンプリング周波数、チャンネル数、ビット深度などが含まれる。

音の合成と再生の基本
音源、DAコンバータ（DAC）、スピーカーなどの機器を経て音が再生される。音の生成には、複数の波形の加算による合成が基本となる。

コンピュータミュージック

音楽記譜と五線譜の読み方
音の高さや長さを視覚的に記録するために使われる。五線譜では、音部記号・拍子記号・音符・休符などが使われる。

音階と音程の理論
長音階（メジャースケール）と短音階（マイナースケール）、および音程の関係に基づいて楽曲は構成される。

音符と休符の時間的長さ
全音符、2分音符、4分音符などの単位により、演奏の長さが決まる。

強弱記号と表現
音楽に表情をつけるために、p（ピアノ）、f（フォルテ）などの記号が用いられる。

拍子と拍の取り方
拍子は一定のリズムを保つための単位で、4/4拍子、3/4拍子などがある。拍とは時間の区切りを示す。

テンポと拍感
BPM（Beats Per Minute）でテンポを表し、楽曲の速さやグルーヴ感に影響を与える。

音楽の三要素
メロディー（旋律）、リズム（時間構造）、ハーモニー（和音構造）によって音楽は構成される。

自動作曲の概念
パターン、ルール、確率的手法などを使って、コンピュータによる自動作曲が可能になる。

MIDIの理論と構造

MIDIの基本仕様
ノート番号で音の高さを、ベロシティで演奏の強さを、プログラムチェンジで音色を指定する。これにより、シンセサイザーや音源の制御が可能になる。

パーカッションマップ
ドラムなどの打楽器音源は、MIDIノート番号ごとに音が割り当てられており、キーボードで演奏することもできる。

MIDIファイルの構造
複数のトラックやタイミング情報を持ち、演奏データとして保存・再生される。

DTMの概念
デスクトップ上で音楽制作を行う環境をDTM（DeskTop Music）と呼び、MIDI信号とソフトウェア音源の連携が重要となる。

ディジタル信号処理（DSP）

周波数分析
フーリエ変換により、時間領域の信号を周波数成分に分解できる。スペクトルとはその分布を示すものである。

スペクトログラム
時間ごとのスペクトルの変化を視覚化することで、音の時間的な特徴と周波数の関係が把握できる。

楽器音の周波数特性
各楽器は固有の倍音構成を持ち、それが音色として現れる。ピアノやバイオリンなどは、特有のスペクトル分布を持つ。

フィルタの種類と設計
ローパスフィルタは低音を通し高音を除去する。ハイパスフィルタは高音を通し低音を除去する。バンドパスフィルタは中間帯域だけを通す。用途に応じて使い分ける。

シンセサイザーの構造と方式

合成方式の分類
加算合成、減算合成、FM合成、物理モデルなどの方式がある。それぞれ異なるアプローチで音を生成する。

アナログシンセの基本回路
VCO（電圧制御発振器）、VCF（電圧制御フィルタ）、LFO（低周波発振器）などが基本となる構成要素である。

基本波形とオシレータ
サイン波、矩形波、鋸波、三角波などの波形を発生するオシレータによって、音の元が作られる。

エンベロープの構成
ADSR（アタック、ディケイ、サステイン、リリース）の4段階で音量の変化を制御する。

各合成法の詳細
加算合成は倍音を足す方式、減算合成は波形から成分を削る方式、FM合成は搬送波と変調波を用いた周波数変調方式である。

カープラス・ストロング法
物理モデルに基づく合成法であり、弦の振動を模擬することで自然な音を再現する。

エフェクターの種類と仕組み

ディストーション
波形を非線形にクリッピングして、歪み成分（倍音）を生み出す。

コンプレッサー
音の振幅の変化を抑え、全体的に均一な音量に整える。

リバーブ
残響を加えることで、音に広がりや空間感を与える。

コーラス・フランジャー
微小な遅延と位相の変調により、音に厚みや動きを与える。

トレモロ・ワウ
LFOによって振幅や周波数を周期的に変調し、音に揺らぎを与える。

ノイズゲート
一定以下の音を遮断することで、無音部分を保つ。

EQ・フィルタ
特定の周波数帯域を強調または除去して、音色を調整する。
OBS、フレームが小さくてゲーム主人公が動くと乱れる時

##エンコーダ設定
NVENC(H.264)を使ってる？それともx264？
NVIDIA GPUがあるなら「NVENC」推奨！
##レート制御
CBR（固定ビットレート）にしてる？
VBRだと動きで画質が乱れやすいわ。
##ビットレート値
例えば1080p60fpsなら 6000～9000kbps はほしい！
もし今3000kbps以下なら、動きに負けるの…
キーフレーム間隔
2秒 に固定すると安定するの。
プリセット
「最大品質」じゃなくて「高品質」や「品質」でもうまくいくことあるよ！
遅延が気になるなら「低遅延高品質」とかも試してみてね！
##解像度とFPS
1080p60fpsにこだわってる？
720p30fpsに一時的に落とすと、画質が安定することも！
microk8sが再起動しなかったので対処した話 (小話)

ついさっきまで動いていたクラスターを再起動しようとしたらなぜか起動しない
という怪奇現象におそわれた
```sh
microk8s.start
microk8s.status
microk8s is not running. Use microk8s.inspect for a deeper inspection.
```

詳しくみてみると
```
microk8s kubectl get job
E0303 18:23:45.450410   14519 memcache.go:238] couldn't get current server API group list: Get "https://xxx.xxx.xxx.xxx:16443/api?timeout=32s": x509: certificate has expired or is not yet valid: current time 2025-03-03T18:23:45+09:00 is after 2025-02-20T06:31:52Z
E0303 18:23:45.458548   14519 memcache.go:238] couldn't get current server API group list: Get "https://xxx.xxx.xxx.xxx:16443/api?timeout=32s": x509: certificate has expired or is not yet valid: current time 2025-03-03T18:23:45+09:00 is after 2025-02-20T06:31:52Z
E0303 18:23:45.465572   14519 memcache.go:238] couldn't get current server API group list: Get "https://xxx.xxx.xxx.xxx:16443/api?timeout=32s": x509: certificate has expired or is not yet valid: current time 2025-03-03T18:23:45+09:00 is after 2025-02-20T06:31:52Z
E0303 18:23:45.473846   14519 memcache.go:238] couldn't get current server API group list: Get "https://xxx.xxx.xxx.xxx:16443/api?timeout=32s": x509: certificate has expired or is not yet valid: current time 2025-03-03T18:23:45+09:00 is after 2025-02-20T06:31:52Z
E0303 18:23:45.481143   14519 memcache.go:238] couldn't get current server API group list: Get "https://xxx.xxx.xxx.xxx:16443/api?timeout=32s": x509: certificate has expired or is not yet valid: current time 2025-03-03T18:23:45+09:00 is after 2025-02-20T06:31:52Z
Unable to connect to the server: x509: certificate has expired or is not yet valid: current time 2025-03-03T18:23:45+09:00 is after 2025-02-20T06:31:52Z
```
となっていた
どうもこれは証明書の有効期限らしいがデフォルトで2yと微妙に気づきにくい時間に設定されていたので対処に時間がかかってしまった

以下のように更新したら治った
```sh
sudo microk8s refresh-certs -c
sudo microk8s refresh-certs -e ca.crt
sudo microk8s refresh-certs -e front-proxy-client.crt

microk8s kubectl get po -n kube-system
```

参考
[Renew Certificate in MicroK8S Cluster](https://discuss.kubernetes.io/t/renew-certificate-in-microk8s-cluster/19826)


[Kubernetesクラスターでkubectlが通らなくなった【証明書期限切れ】](https://zenn.dev/eucyt/articles/renew-k8s-cert)
QMK Firmwareを簡単にビルド！ カスタムGithub ActionをMarketPlaceに公開しました

# [経緯]

- **環境構築のハードル**:
  - 久々にQMK Firmwareでキーマップを変更しようと思ったが、毎回環境構築手順を忘れてしまいます。
  - QMK環境構築に関する記事も古かったり内容が曖昧だったりして、再現性が低くて困っていました。
- **環境の維持**:
  - たまにしかファームウェアを作成しないので、環境を維持するわけにもいかない
  - 毎回サーバに入ってビルドして、作成した.hexファイルをローカルに複製するのが面倒。
- **周囲の状況**:
  - 周りの自作キーボードの同僚たちは、ビルド環境構築のハードルが高いため、[QMK Configurator](https://config.qmk.fm/)でファームウェアを作成して、keymapをごりごりカスタマイズしていないようです。
- **環境の更新**:
  - qmk/qmk_base_container, qmk/qmk_cliはdebian-11でもうすぐEOLとなるため、debian-12版で作成しました。

# [解決策]
これらの問題を解決するために、自作のGithub Actionだけでビルドできるようにしてましたが、
ついでにカスタムGithub Actionsの作成ノウハウを学べるので、公式qmk_base_container, qmk_cliをベースにし、qmk_base_container, qmk_cliも含めて更新を行い、カスタムGithub ActionsをMarketplaceを公開しました。

# [QMKファームウェアビルド カスタムGithub Action]
URL: [qmk_build](https://github.com/marketplace/actions/qmk-firmware-build-action)

## ディレクトリ構造

以下のディレクトリ構造でgitリポジトリをGithubに構築します。

```
- /
    - .github/workflows/
        - build.yml ... サンプルから複製
    - keyboards/
        - [自身のキーボードフォルダ]/ ... qmk_firmware.git/keyboards/以下から複製するのが早い
            - keymaps/[自身のキーマップフォルダ] ... keymaps/defaultを複製してカスタマイズするなど
            - rules.mk, config.h ... 必要であれば修正
```

### .github/workflows/build.ymlの設定

以下は`.github/workflows/build.yml`の例です。

```yml
name: Sample QMK Firmware Build Action

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    steps:

      # ご自身のリポジトリをclone
      - name: Checkout code
        uses: actions/checkout@v4

      # ビルドしたいkeyboard, rev, keymapを指定
      - name: QMK Build firmware Action
        uses: ijikeman/qmk_build@v0.0.1
        with:
          keyboard: 'plunck'
          rev: 'rev1'
          keymap: 'default'

      # 複数指定可能
      - name: QMK Build firmware Action
        uses: ijikeman/qmk_build@v0.0.1
        with:
          qmk_firmware_version: 0.27.0 # v0.0.1では0.28.0がDockerimageに含まれていますが、別のバージョンでビルドしたい場合は指定します
          keyboard: 'plunck'
          rev: 'rev1'
          keymap: 'original_keymap'

      # 生成された.hexファイルをartifactとしてアーカイブ保存
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: firmware
          path: ${{ github.workspace }}/output/*.hex
```

### ビルド後の結果

Githubの自身のリポジトリにpushした後、Actionsに移動しビルドが成功すると、`.zip`ファイルが生成されており、`.hex`ファイルが内包されています。

![qmk_build01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28408/59107bb1-915e-4c58-9c23-e96513eeeb13.gif)
Dockerを使ってPythonスクリプトを実行する（基本）

## 1. シンプルスクリプトの実行（Print文のみ）

### ゴール
ローカルにある main.py を Docker コンテナ上で実行する。

### 構成例
```
my-python-app/
├── Dockerfile
└── main.py
```

### main.py（テスト用スクリプト）
```python
print("こんにちは、DockerからPythonです！")
```

### Dockerfile
```Dockerfile
# Python公式の軽量イメージを使用
FROM python:3.12-slim

# 作業ディレクトリを作成＆設定
WORKDIR /app

# スクリプトをコンテナにコピー
COPY main.py .

# スクリプトを実行する（CMD はデフォルトの実行コマンド）
CMD ["python", "main.py"]
```

### ビルド
プロジェクトフォルダ（Dockerfileがある場所）で以下を実行：
```sh
docker build -t my-python-app .
```

### 実行
```sh
docker run --rm my-python-app
```
- --rm：実行後にコンテナを削除する（お掃除も自動）

### 結果（ターミナル）
```sh
こんにちは、DockerからPythonです！
```



## 2. 外部ライブラリ（requests）をインストールしてスクリプトの実行

### ゴール
- requests を使った Python スクリプトを Docker で実行
- requirements.txt に依存関係を記述してインストール

### 構成例
```
my-python-app/
├── Dockerfile
├── requirements.txt
└── main.py
```

### main.py（requestsを使った例）
```python
import requests

response = requests.get("https://api.github.com")
print("GitHub API ステータスコード:", response.status_code)
```

### requirements.txt
```text
requests
```
- 他のライブラリが増えたらここに追加していけばOKです。


### Dockerfile
```Dockerfile
FROM python:3.12-slim

WORKDIR /app

# requirements.txt を先にコピーしてインストール（キャッシュ効かせるため）
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# スクリプト本体をコピー
COPY main.py .

# 実行
CMD ["python", "main.py"]
```

### ビルド
プロジェクトフォルダ（Dockerfileがある場所）で以下を実行：
```sh
docker build -t my-python-app .
```

### 実行
```sh
docker run --rm my-python-app
```
- --rm：実行後にコンテナを削除する（お掃除も自動）

### 結果（ターミナル）
```sh
GitHub API ステータスコード: 200
```

普段のPythonアプリをそのまま `requirements.txt` にまとめれば、環境が再現可能になります！
俺は、「女子に」うける、サウンドメーターまとめ


https://qiita.com/caa45040/items/2c09834e709c97efc404


https://qiita.com/caa45040/items/84fcea986b0363e7042b


https://qiita.com/caa45040/items/34c9948729605703bcc0


https://qiita.com/caa45040/items/0ad48bac1388fcba7a1f


https://qiita.com/caa45040/items/0b51cf5de7083ce0baa1


https://qiita.com/caa45040/items/57ecbed59ab545b55de8