OmniAICreator/Qiita-1.07M huggingface dataset:
wslで、最小のカーネルをコンパイル その42

# 概要
wslで、kernel.elfのコンパイル、やってみた。
さらに、上のkernel見つけたので、コンパイルしてみた。
コンソールにヘルプが無いので、作ってみた。


# 写真

![スクリーンショット 2024-03-31 122644.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/1719dbe6-7072-1e7c-8e38-43cdbe602966.png)

# サンプルコード

```
void cmd_help(struct CONSOLE * cons) {
	cons_putstr0(cons, "mem - memory\n");
	cons_putstr0(cons, "cls - clear console\n");
	cons_putstr0(cons, "dir - file list\n");
	cons_putstr0(cons, "type - print file\n");
	cons_putstr0(cons, "exit - exit\n");
	cons_putstr0(cons, "start - start\n");
	cons_putstr0(cons, "ncst - ncst file\n");
	cons_putstr0(cons, "langmode - langmode\n");
	cons_putstr0(cons, "winhelo - Ore Gengo\n");
	cons_putstr0(cons, "tview - tview file\n");
	cons_putstr0(cons, "gview - gview file\n");
	cons_newline(cons);
}

void cons_runcmd(char * cmdline, struct CONSOLE * cons, int * fat, unsigned int memtotal) {
	//cons->shtを見ているのはコンソールがない場合は実行しなくていいから
	if (_strcmp(cmdline, "mem") == 0 && cons->sht != 0)
		cmd_mem(cons, memtotal);
	else if (_strcmp(cmdline, "help") == 0 && cons->sht != 0)
		cmd_help(cons);
	else if (_strcmp(cmdline, "cls") == 0 && cons->sht != 0)
		cmd_cls(cons);
	else if (_strcmp(cmdline, "dir") == 0 && cons->sht != 0)
		cmd_dir(cons);
	else if (_strncmp(cmdline, "type ", 5) == 0 && cons->sht != 0)
		cmd_type(cons, fat, cmdline);
	else if (_strcmp(cmdline, "exit") == 0)
		cmd_exit(cons, fat);
	else if (_strncmp(cmdline, "start ", 6) == 0)
		cmd_start(cons, cmdline, memtotal);
	else if (_strncmp(cmdline, "ncst ", 5) == 0)
		cmd_ncst(cons, cmdline, memtotal);
	else if (_strncmp(cmdline, "langmode ", 9) == 0)
		cmd_langmode(cons, cmdline);
	else if (cmdline[0] != 0)
	{
		if (cmd_app(cons, fat, cmdline) == 0)
			cons_putstr0(cons, "Bad Command.\n\n");
	}
}
```

以上。
UE5でマルチプレイを実装したい

　ということで参考になった記事をまとめてみる

# UE5でマルチプレイのメリット
サーバーがいらない
無料

# UE5でマルチプレイのデメリット
情報が少ない

 # UE5標準の機能でやってみる
 
https://dipross.co.jp/eng/2023/06/ue5%E3%81%A7%E3%83%9E%E3%83%AB%E3%83%81%E3%83%97%E3%83%AC%E3%82%A4%E3%82%92%E3%81%97%E3%82%88%E3%81%86.html


https://www.youtube.com/watch?v=JCKzdzTjt2U&list=PLfKehW5Urkqu4DXGJC-gWZCxweW9qjnsv&index=1


# EOSでやってみる

https://you1dan.hatenablog.com/entry/2022/09/16/185314

### パッケージ後に起動できない問題の解決

Generate Visual Studio project filesをすることで解決した
下記が参考になる

https://qiita.com/it212257/items/548f309b50c85a705f56

5.3.2だと下記のIssueが上がっていて解決策もある

https://github.com/mordentral/AdvancedSessionsPlugin/issues/85


# EOS Integration Kit（EIK）　でやってみる
これは現時点で情報が少なすぎて下記の手順をやっても下記のエラーが出て実現できない
```

LogSockets: Warning: GetAddressInfo failed to resolve host with error SE_HOST_NOT_FOUND [11001]

```


EOSのログインやセッション作成等の機能は利用できるが、ホストが見つからず同じマップに入れない不具合がありそう
ログインできていても同じマップで遊べないなら意味がない
シンプルなEOSでは正常に動作するので、EOS Integration Kitのネットワーク管理周りがバグってそう

https://www.youtube.com/watch?v=AeBrDji5XH4&list=PL0jFyH3meZDNH1rfgizEE0xMX1pTxXZ4h&index=9


ノード側に問題があるか切り分ける為にLyraにEIKを導入するチュートリアルもあるが
同様のエラーが発生するのでEIK側に問題があると思う

https://www.youtube.com/watch?v=P-05BMQBz88


# まとめ
現状、シンプルなEOSが安定してると思う。Mac、Windows間でも問題なく動くし、パッケージ化まで正常に動作するのでリリースを考えるならシンプルEOS一択だと思う
UE標準機能でも作れるが、友達とやりたいならNAT越えしないといけないのでEOSまで手を伸ばす必要がある
G検定に合格してみたの巻

こんにちは、kinchです。

先日の記事でちらっと言いましたがG検定2024＃2を受験し、無事合格したのでその体験記を
まとめていきたいと思います！

## 勉強法
当日まで[この本](https://www.amazon.co.jp/%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0G%E6%A4%9C%E5%AE%9A-%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%A9%E3%83%AA%E3%82%B9%E3%83%88-%E6%9C%80%E5%BC%B7%E3%81%AE%E5%90%88%E6%A0%BC%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88-%E6%98%8E%E7%9E%AD%E8%A7%A3%E8%AA%AC-%E8%89%AF%E8%B3%AA%E5%95%8F%E9%A1%8C/dp/481561167X/ref=sr_1_10?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=26RIBQA2Y39R5&dib=eyJ2IjoiMSJ9.Q56cHp9xojYlKs8MjXsWgCAdN5xAGp4dMT-vxq2TN4AN8dFV9pQGa6wMuImylzWXh39_7sMWVIrZkWCqK35XWRce1J1z_Qu5jXMorFyqnT9ySTeEcrml6X816PbLYeBPhoNfv6uWIxdegnVcCF2g-4fAjxbOOgmJQKNk7Zrc1LCDTSARdL3cdraSF_JDbe2Z_DytfHXxndXi8FT0WUpNTaRc1kef4sDTn_BxpHBW3MYWf5_eqqcRagxSCCKJwXt-uu9xCj5tYAw6U1KR18YBMI_wh2fbNATXl31tssRD1e8.4uQZmaD3xK3rsi2tT6YSDwTqs1z1r4-0ZwRrEbX9tuM&dib_tag=se&keywords=G%E6%A4%9C%E5%AE%9A&qid=1711693308&sprefix=g%E6%A4%9C%E5%AE%9A%2Caps%2C173&sr=8-10)を用いて勉強しました。
この本は、単純にAmazonで一番安かったから選んだだけに過ぎませんが、説明はかなりわかりやすかったです。
ただ、写経を勉強の基本としている私からすれば、写経はしにくかったのかな？という印象です。

そして毎度お馴染み[黒本](https://www.amazon.co.jp/%E5%BE%B9%E5%BA%95%E6%94%BB%E7%95%A5%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0G%E6%A4%9C%E5%AE%9A%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%A9%E3%83%AA%E3%82%B9%E3%83%88%E5%95%8F%E9%A1%8C%E9%9B%86-%E7%AC%AC2%E7%89%88-%E5%BE%B9%E5%BA%95%E6%94%BB%E7%95%A5%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E6%98%8E%E6%9D%BE-%E7%9C%9F%E5%8F%B8/dp/4295011630/ref=sr_1_2_sspa?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=A62XETT9A08O&dib=eyJ2IjoiMSJ9.e6cOj2qk_7x8yhb59TfGop2UyHHRYA-sQRAnShk1h0ZShYVdcQRcbggRme3xeop1fg6_4a17cp7wOAFqO7Thguc3ccFHFus7UJSEveyJDKGOq1nBTFni18_z2PfsJgIP3j4iJrMr0XzNE4l5KtUFD91A2dhAgyQRjM0c2c6WXR1QHZKvOQwIBaYJgVvM7_6HqoK4rIBRAFpa3LD7aXq4TrMoOGJ7YP6HDvIXp04p04o9ANGBfigmzBwo6znBiJv3JykwPDn4hp2GxBtGChlnQ3NEc99TI2MiKRGKhZ1wqY8.CesQ7gWHHBYMuCw2svDWHTT8M9IDlygZ-WDqo9BavY0&dib_tag=se&keywords=G%E6%A4%9C%E5%AE%9A&qid=1711854827&sprefix=g%E6%A4%9C%E5%AE%9A%2Caps%2C180&sr=8-2-spons&sp_csd=d2lkZ2V0TmFtZT1zcF9hdGY&psc=1)で演習を重ねました。
これも毎度お馴染みですが、黒本は比較的易しく、実際の問題よりも正答率は高く、かつ素早く解かなければ合格できないレベルです。
ただ、本番のテストが120分で200問程度解かなければならないので、その練習にはうってつけでしょう。

## 当日
G検定は会場に赴き、受験する形ではなく自宅のPCから受験する試験方式でしたので、合格の鍵になってくるのが、カンニングペーパーの作成です。
公式には**カンニングを禁止する文言がない**ため、逆に活用しない手はない！とカンニングペーパーを作成しましょう。
~~汚いというか捨てたので見せられませんが()~~

当日は先述の通り、120分で191問解かなければならないので、おりゃー！っていう気概がかなり必要です。
私は幸い、すっぱりと諦めが効く人間ですので10分以上時間を残して解き終わりましたが、ゆっくりじっくり解きたい方は早く解く練習がかなり必要になってきます。

## 結果発表！
例のあの人のボイスでお願いします！
~~相方さんの裁判が始まったらしいですが~~

無事**合格**でした！
いやー、自信がなかったので不安でしたが、メールを確認してすぐ合格者Slackに入りましたね…！

## 最後に
G検定を受けてみて、もともと興味のあったディープラーニングの分野に詳しくなれてとても楽しかったです。
この資格を持っていることでようやく技術者としての価値が上がったような気がします。

次回、「塾の先生が未経験からデータサイエンティストを目指してみた！」でお会いしましょう〜！
それではー。

いつか、綺麗にまとめてみますね…
rbenvでRubyの最新バージョンが表示されない

## 経緯
アプリを作ろうとしたところ、作成ファイルの中にある「Gemfileの中身」には「ruby "3.1.2"」が入っていたため、最新バージョン3.3.0にするようrbenvで更新を試みました。

しかし、「rbenv install --list」で確認したところ最新バージョンの3.3.0は表示されませんでした。
```
2.6.10
2.7.6
3.0.4
3.1.2
jruby-9.3.8.0
mruby-3.1.0
picoruby-3.0.0
rbx-5.0
truffleruby-22.2.0
truffleruby+graalvm-22.2.0
```
今回はその解決までの記録をまとめます。

## 問題を定義
rbenvで最新バージョンが表示されない

## 仮説と検証①
仮説・・「rbenv」のバージョンを更新することで解消できるのでは？
検証・・「rbenv」のバージョンを更新するために「brew upgrade ruby-build」コマンドを入力
結果・・表示されない

## 仮説と検証②
仮説・・「rbenv」のバージョンの大元であるHomebrewのバージョンが古いのでは？
検証・・Homebrewのバージョンを最新にするため、「brew update」というコマンドを入力し「brew upgrade ruby-build」で「rbenv」のバージョンを更新
結果・・下記のように3.3.0が表示されるようになりました。
```
3.0.6
3.1.4
3.2.3
3.3.0
jruby-9.4.6.0
mruby-3.3.0
picoruby-3.0.0
truffleruby-24.0.0
truffleruby+graalvm-24.0.0

Only latest stable releases for each Ruby implementation are shown.
Use `rbenv install --list-all' to show all local versions.
```
## まとめ
rbenvでRubyの最新バージョンが表示されない原因は、「rbenv」のバージョンが低いことで表示がされていなかったため、更新してあげることで表示されるようになりました。最後に「rbenv install 3.3.0」というコマンドを入力することでバージョンを更新させたら完了です。

## 参考文献
[rbenvをupdateして最新のRubyバージョンをインストール](https://morizyun.github.io/ruby/rbenv-update-mac-homebrew.html "rbenvの更新方法ついての記事")
[【インストール方法から使い方まで】Homebrew についてわかりやすく解説！よく使うコマンドも](https://www.kikagaku.co.jp/kikagaku-blog/homebrew-install-howto/#i-14 "Homebrewついての記事")
WSLとWindowsのSSHキーペアの共有化

# 課題
デフォルト設定だとWSLとWindowsユーザーのホームディレクトリは別々の場所なので、SSH設定も別々になってしまう。
```:SSHの設定ディレクトリ
WSL:~/.ssh
Windows:/mnt/c/Users/[USERNAME]/.ssh/
```
Windows側でsshしたい場合とwsl側でsshしたい場合、両方のディレクトリにキーペアを保存する必要がある。
両方に保存するのは面倒なのでシンボリックリンクを張って共有化する。

# WSLメタデータの設定変更
キーペアのパーミッションは自分自身のみ読み書きできるように変更する必要があるが、デフォルト設定だとWSLからWindows上のファイルのパーミッション変更ができないので、メタデータの設定変更を行う必要がある。

参考

https://learn.microsoft.com/ja-jp/windows/wsl/file-permissions

```bash:ヒアドキュメントで/etc/wsl.confを作成（WSL側で実施）
sudo tee -a /etc/wsl.conf << EOT > /dev/null
[automount]
options = "metadata,umask=22,fmask=11"
EOT
```
```:WSLの再起動（コマンドプロンプトで実施）
wsl --shutdown
```


# シンボリックリンクの作成
```bash:シンボリックリンクの作成（WSL側で実施）
USERNAME=user01 # USERNAMEはWindowsのユーザー名を指定
ln -s /mnt/c/Users/${USERNAME}/.ssh ~/.ssh
```
```bash:パーミッションの変更（WSL側で実施）
chmod 600 ~/.ssh/*
```
上記でWindows側のキーペアファイルをWSL側でも使用可能
```
user01@WINDOWS:~/.ssh$ ssh -i ~/.ssh/test-20240331.pem ec2-user@xxxxxxxxxx.ap-northeast-1.compute.amazonaws.com
   ,     #_
   ~\_  ####_        Amazon Linux 2023
  ~~  \_#####\
  ~~     \###|
  ~~       \#/ ___   https://aws.amazon.com/linux/amazon-linux-2023
   ~~       V~' '->
    ~~~         /
      ~~._.   _/
         _/ _/
       _/m/'
Last login: Sun Mar 31 02:14:07 2024 from xxxxxxxxxx
[ec2-user@xxxxxxxxxx ~]$
```
80年代ビデオゲーム風ラスタースクロールをシェーダーで作る

## 要約
- GRADIUS(グラディウス)、DARIUS(ダライアス)、XEXEX(ゼクセクス)風ラスタースクロールの紹介です
- XEXEX風シェーダーの実装例が探しても見当たらないので自作しました

環境：Godot4.2＋ C#(.Net Framework6.0)

## はじめに
　1枚の背景絵を元にした動きのある背景をシェーダーで作ります。
　背景スクロールの実装には色々な方法がありますが、１組の背景絵とシェーダーだけで実現できるのがコンパクトなので気に入ってます。

　実装はGodot Shaderを使っていますがシンプルな方式なので、他のシェーダー実装にも容易に移植できるでしょう。

https://x.com/cabbagestole/status/1774260542456406107?s=20

## 横スクロール
　シンプルな横スクロールです。 時間経過に伴い描画する座標を徐々に右(UV座標系のX+)にずらしていきます。そのままだと元絵に無い部分が歯抜けとなってしまうので、左にはみ出た部分を右側に都度補完していきます。

　godot shaderのキーワード説明もかねて紹介しています。
 
```
shader_type canvas_item;
uniform float speed = 1;
void fragment() {
	vec2 vec = UV;
	float t = mod(TIME * speed, 1);
	vec.x = mod(vec.x + t, 1);//時間経過に伴い右にずらし、左からはみ出た分を右に補完する
	COLOR = texture(TEXTURE, vec);
}

```
　shader_type canvas_itemはキャンバス用のシェーダーの宣言です。
　uniform float speed はインスペクタやスクリプトからシェーダーにパラメータを与える為の書式です。機能的には外部から引数を与るものです。
　void fragment()はfragmentシェーダーの宣言部です。頂点シェーダーは使いません。
 　大文字のUV、TIME、TEXTUREはシステム変数です。関数内から参照できます。

　float tは時間情報と剰余を用いてfloat t に0～1の範囲の値を得ます。
　vec.xもUV座標系のx座標であるため0～1の値をとります。tを加えて1の剰余を得る事で横スクロールになります。


## グラディウス風
　スクロール速度の異なる複数の光点を並列にスクロールします。

```
shader_type canvas_item;
uniform float speed = 0.01;
uniform float ysize = 288;
void fragment() {
	vec2 vec = UV;
	float t = mod(TIME * speed, 1);
	int m = int(vec.y * ysize) % 5;
	vec.x = mod(vec.x + t * float(m + 1), 1.0);
	COLOR = texture(TEXTURE, vec);
}
```
　ysizeは縦方向のピクセル数です。(この例では512*288の画像を使っています。)
　同じ剰余でも浮動小数点数のmod()ではなく整数型の%を使っています。元絵のピクセル1行毎に変換をかけたいため、小数点以下を切り捨てる目的でint型を使っています。そのためint()やfloat()といったキャスト関数があちこちに入って少々見づらくなってます。
　int mには1行毎に0,1,2,3,4,0,1,....のように行毎の移動量が入ります。元絵の右側に1本の直線を引いてあるので、このシェーダーの動きを理解するのにちょうど良いでしょう。

## ダライアス風
　皆(?)の憧れ、ゆらゆら揺れるサインカーブスクロールです。

```
shader_type canvas_item;
uniform float speed = 0.5;
uniform float depth = 0.1;
void fragment() {
	vec2 vec = UV;
	float t = mod(TIME * speed, 1);
	float radian = (vec.y - t) * PI * 2.0;
	vec.x = vec.x + sin(radian) * depth;
	COLOR = texture(TEXTURE, vec);
}
```
　float radian はy座標の値(0～1)と時間経過に伴う変数t(0～1)から-1～1の範囲の数値に2πをかえて-2π～2πの値をとります。
　xの値をsin(radian)で補正します。depthはユラユラの振れ幅です。


 ## ゼクセクス風
　正直これを再現できたことが嬉しくてこの記事を書いてます笑

```
shader_type canvas_item;
uniform float speed = 0.5;
uniform float xo = 0.33;//X原点
uniform float yo = 0.5;//Y原点
void fragment() {
	vec2 vec = UV;
	float t = mod(TIME * speed, 1);
	float y = (vec.y - yo) * 2.0;          //y軸の0～1を、-1～1の値に変換
	vec.x = (vec.x - xo) * (1.0 / abs(y)); //(1)消失点方向に縮小をかける
	vec.x = mod(vec.x + t, 1);             //(2)左へスクロール
	vec.y = mod(vec.y + t, 1);             //(3)上へスクロール
	COLOR = texture(TEXTURE, vec);

	if((-0.05<y)&&(y<0.05))                //(4)水平線付近のモアレを非表示
		COLOR = vec4(0, 0, 0, 0);

}
```
　xo,yoが消失点になります。
　(1) 1/ abs(y) は画面横方向の縮小係数です。この式で元の画像を消失点方向へ絞るように変形します。
　(2)横方向スクロールです。X方向に関する変形ですが(1)と順番を入れ替えてしまうと意図した変形にならないので、この順序で変形してください。
　(3)縦方向スクロールです。
　(4)水平線付近のモアレがCG酔いを誘発するので別の色で塗りつぶします。


### 余談

　(3)は消失点に向かって集まり再度拡散するように動きます。このままでもオリジナル通りなので必要充分ですが、水平線から拡散するようにしても良いでしょう。

```
	vec.y = mod(vec.y -t*sign(y), 1);//(3')水平線から上下に拡散する
```
サンタさんにもらったUbuntu on Mac mini late 2012を本格的に使い始めた

1年以上前に下記の記事を書いたのですが、その後、当初のセットアップで満足してしまい（あと、その後購入した<a href="https://www.lenovo.com/jp/ja/p/laptops/ideapad/ideapad-duet-5-series/ideapad-duet-5-chromebook/len101i0023?orgRef=https%253A%252F%252Fduckduckgo.com%252F">LenovoのChrmebook</a>に浮気していた）、全然更新していなかった記事の続きになります。デスク周りのセットアップについての自分用の備忘です。

https://qiita.com/supertakeman/items/95a8a59d5b383a587431

# 先に結論
- 今後も使い続けます。ただしリモート接続用のコンピュータとして。
- とうとうiPadメインで生きていくことにしました（Windowsは2年前に卒業。ChromeOSなど浮気していましたがすべてサヨウナラ〜）
- team wiewerは有用。ただしiPad越しのキーボード入力に難あり

# いまどんなセッティングか
![20591.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989162/b5af941b-9bc7-489d-8b31-160d8456817c.jpeg)

### iPad pro 2022（12.9インチ）：メインマシン。
- M2なので外部ディスプレイに対して拡張を選択できる
- 用途は、Webブラウジング、チャットのメッセージやり取り、リモートワーク時のYoutube垂れ流しなど
- ほかにも電子楽譜として使用（アマオケでバイオリン弾いてます。画面がA4サイズに近いのでかなり実用的）
- 普段は<a href="https://www.ankerjapan.com/products/a8392">Anker PowerExpand 13-in-1 USB-C Dock ドッキングステーション</a> 越しに <a href="https://www.amazon.co.jp/gp/product/B09X533F21/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1">IRIE の27インチ4Kモニター</a>に接続


### Ubuntu on Mac mini late 2012：サブマシン
- お遊び用にメルカリで19,000円で購入
- OSサポートは当然のように切れているので、Ubuntuをインストール
- 2023/04-2024/03の間、 ~~デスクの上でホコリをかぶっていた~~ インテリアとして飾られていた
- 用途は、仮想マシン立ててエンジニアのお勉強＆iPadが苦手な作業（ファイル整理とか）

# すべてを iPad で完結したい欲
- 正直プライベートの軽作業（Webブラウジング、動画視聴など）はPC不要（Chromebookさえあればなんでもできてた）
- 以前から電子楽譜用途で12.9インチのiPadが欲しかった（iPad Air 2020 を持っていたが、11インチはオケの楽譜には小さすぎる…＆iPad Air 12.9がいつまで待っても発表されない笑）
- iPad、Mac mini、Chromebookでデスクがごちゃごちゃ…
→プライベート用途なら、iPad1台で完結できるはず（いや、完結させる！！）

### いざ、iPad購入！
- 安定のiPad pro。最上位機種。普段使いにはなんの問題もなし。
- iPad proならリセールバリューあるなぁ（下心）
- ストレージは256GB。ストレージの余裕は心の余裕。たまに動画編集もする＆最近4K撮影も多いのでこれくらいあると色々と安心。
- ただし、iPad OSの<a href="https://support.apple.com/ja-jp/guide/ipad/ipad1240f36f/ipados">ステージマネージャ</a>は優秀とは言え、PCライクな操作にはほど遠い…

### 眠っていたMac mini 復活のとき
- じゃあPC的な操作はUbuntuくんに任せようじゃないか
- 長らく火を入れていなかった、Mac miniを久しぶりに起動。
- 「ジャーン！！（Macの起動音）」のあとにUbuntuのログイン画面が出るのはなかなか面白い
- プライベートのファイル整理（外付けのHDDにバックアップ）用途くらいでしか使っていなかったけど、iPadが苦手な作業系もこれでできるとなると便利だなぁ。

### 課題：iPad⇔Mac miniの切り換えが面倒すぎる
- 配線にこだわりたい今日この頃、HDMIのスイッチャーをつけてタコ足配線なんて見栄えが悪過ぎて却下
- Apex Legends専用機（Xbox Series S）への切り替えも考えなければ…
- そういえばiPadからMac miniはリモデでつなげるよな（過去にiPad Air 2020⇒Mac miniにRD Clientで接続検証した記憶あり）
- ディスプレイ⇔Mac miniの配線がないのに操作できたら面白そう


### そうだ！自宅内リモデだ！
- iPad ⇒ Mac mini にリモデで接続して拡張ディスプレイ側に全画面表示させれば、iPadのへんてこな画面比率を気にせずPCライクに操作できる！
- リモデはTeam Viewerを採用。
個人利用であれば無料。
その他、リモートデスクトップのソフトウェアはいくつかあるが以下の理由で却下。
・RD Client：接続のたびにパスワード入力するのが面倒。
・Chrome remote desktop：Linux未対応（ChromeOSもそうだった。なんとかならんのか）
・シン・テレワークシステム（IPA）：Linuxをホストにできない（ホスト用のインストーラがない）


# 次回、TeamViewerでリモートデスクトップしてみる
- 既に環境は整備済みですが、実際にどんな設定を入れているか、正直使いにくい部分など細々とした部分を記事にしてみます


![20602 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989162/0ff241a9-f8ec-8349-d21e-756b3f09d5cc.jpeg)
久しぶりに掃除してあげました。

![20603.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989162/72028c0a-ce41-a0f4-2a1d-7451b581045f.jpeg)
Wifi経由で通信しているので、配線は非常にシンプル（電源ケーブルのみ）
【Docker】docker立ち上げの際に「driver failed programming external connectivity on endpoint」エラーが出た


 # はじめに
 docker compose up -dしたら「driver failed programming external connectivity on endpoint」のエラーが出たので備忘録。

 # driver failed programming external connectivity on endpoint
調べたら、すでに作成した他のコンテナとポート番号が被っていた。
ポート番号を振り直したら無事解決！
Formik.setFieldValue と条件付き Schema を使う際の落とし穴

# 概要

Formik の setFieldValue を 条件付き schema と合わせて使う際にちょっと困ったことがありました。その説明と対策について書きます。

# 問題

```tsx
<Formik
  initialValues={{ a: "", b: "" }}
  validationSchema={yup.object({
    b: yup.string().when("a", {
      is: "a",
      then: (schema) => schema.oneOf(["a", "A"]),
    }),
  })}
  onSubmit={() => {}}
>
  {({ setFieldValue, errors }) => (
    <form>
      <button
        type="button"
        onClick={() => {
          setFieldValue("a", "a");
          setFieldValue("b", "error");
        }}
      >
        TEST
      </button>
      <p>
        <label>
          A
          <Field type="text" name="a" />
        </label>
      </p>
      <p>
        <label>
          B
          <Field type="text" name="b" />
        </label>
      </p>
      <pre>ERRORS: {JSON.stringify(errors, undefined, 2)}</pre>
    </form>
  )}
</Formik>
```

２つのフィールド a, b を持ち、フィールドa の値が "a" だった場合、フィールドb の値が "a" or "A" であることを制約条件としています。問題のコードはここ。

```tsx
setFieldValue("a", "a");
setFieldValue("b", "error");
```

御覧の通り、ここで設定している値は前述の制約条件に違反しているため、本来であればエラーが表示されるはずです。しかしこれはエラーになりません。なぜでしょうか？

# 原因

setFieldValue を呼び出すと、Formik は Validation を行います。この時、その評価対象となる値は「現在値 + 設定された値」となります。上記コードでは setFieldValue が２回に分けて実行されているため、ここでは2つの Validation が発火されます。例えば、現在値が `{ a: "foo", b: "bar" }` だった場合は次のとおり。

```tsx
setFieldValue("a", "a");      // { a: "a", b: "bar" }
setFieldValue("b", "error");  // { a: "foo", b: "error" }
```

このため、最終的にセットされる値は `{ a: "a", b: "error" }` であるにも関わらず、フォームはエラーとして評価されないという結果になります。

# 解決策

複数の値を同時にセットする場合は、setFieldValue ではなく、setValues を使いましょう。

```tsx
setValues({ ...values, a: "a", b: "error" })
```

# さらなる課題

setValues を使いましょうとは言ったものの、実はこれにもまだ欠点があります。この設定処理がAPIの処理結果を受けて行われる非同期処理だった場合どうなるでしょうか?

```tsx
setTimeout(() => formik.setValues({ ...values, a: "a", b: "errors" }), 2000);
```

ここで、`...values` で現在値をマージしていることが問題になります。非同期処理実行中もフォームの編集が可能な場合、この `values` は古い値を参照することになります、つまり、この非同期処理が実行されるとき、ユーザーが入力した値が破棄されてしまう可能性があります。

この場合、useRef を使って最新の Formik instance を参照する必要があります。

```tsx
  {(formik) => {
    formikRef.current = formik;
    return (
      <form>
        <button
          type="button"
          onClick={() => {
            setTimeout(() => {
              formikRef.current.setValues({
                ...(formikRef.current.values || {}),
                a: "a",
                b: "errors",
              });
            }, 2000);
          }}
        >
          TEST
        </button>      
```

# まとめ

最後に挙げた非同期処理の問題は、よっぽど遅い非同期処理でなければ発生することは稀なのですが、Unit Test ではUI操作が高速に行われるため高い頻度で発生します。しかもエラーの原因がなかなか特定できずに苦労します、というかしました。逆に言えば、手動で操作していては気づきにくい問題も、テストを書くことで検出できるということ。

結論: テストを書こう。
ITIL3とITIL4の違い

<div>
<h3>ITIL3からITIL4への変更点</h3>
最新バージョンのITIL4への変更点としては、<br>
<ul>
<li>「プロセスと機能」が「プラクティス」に変更</li>
<li>「4つのP」が「4つの側面」に変更</li>
<li>「ライフサイクル」から「サービスバリューチェーン」に変更</li>
</ul>
の3点が大きく変更となっています。<br>
<br>
なかでも「サービスバリューチェーン」という概念の導入が最大の特徴となります。<br>
<ul>
<li>ITIL3の考え方：利用者にITサービスを提供する</li>
<li>ITIL4の考え方：ITサービスの提供者と利用者がITサービスを共に創っていく</li>
</ul>
という考え方に変化をしました。<br>
<br>
ITIL3で「プロセス（インシデント管理・問題管理・ナレッジ管理等）」と「機能（サービスデスク等）」と表現されていたものがITIL4では新たに「プラクティス」と表現されるようになりました。<br>
</div>
<div>
<h3>ITIL4のプラクティスの分類</h3>
ITIL4のプラクティスは、以下３つに分類することができます。<br>
<ol>
<li>一般的マネジメントプラクティス</li>
<li>サービスマネジメントプラクティス</li>
<li>技術的マネジメントプラクティス</li>
</ol>
</div>
<div>
<h3>ITIL4の4つの側面</h3>
ITIL4は、ユーザーのために価値を共創するプロセスに不可欠な「4つの側面」を定義しています。<br>
<ol>
<li>組織と人</li>
<li>情報とテクノロジー</li>
<li>パートナーとサプライヤ</li>
<li>バリューストリームとプロセス</li>
</ol>
</div>
<div>
<h3>サービス管理の4つの側面</h3>
ITIL3では、4つのPとして「人」「プロダクト」「パートナー」「プロセス」とされていたが、ITIL4より以下側面が追加されました。<br>
<ul>
<li>情報</li>
<li>バリューストリーム</li>
</ul>
</div>
<div>
<h3>バリューストリームとは</h3>
「バリューストリーム」とは、ユーザーの要望を探し出し、ユーザーに価値を届けるまでに、誰がどのようなプラクティスにおいて何をするか、という一連の流れを指すものです。<br>
プロセス単位での効率化だけでなく、全体を最適化するという視点でITIL4を考えるうえで非常に重要な要素です。<br>
ITIL4では、前述の「ITILの4つの側面」に影響を与える以下6つの外的要因を考慮して、4つの側面に関する意思決定を行う必要があるとされています。<br>
<ul>
<li>政治的要因</li>
<li>経済的要因</li>
<li>社会的要因</li>
<li>技術的要因</li>
<li>法的要因</li>
<li>環境的要因</li>
</ul>
</div>
<div>
<h3>サービスバリューシステムとは</h3>
ITIL3のサービスライフサイクルという概念の代わりに、ITIL4では「サービスバリューシステム」という概念が定義されました。<br>
<br>
サービスバリューシステムは、
<ul>
<li>「需要」が「サービスバリューチェーン」を通じて、「価値」へと変わっていくこと</li>
</ul>
を概念化したものです。<br>
<br>
「サービスバリューチェーン」は「原則」と「継続的改善」という枠組みのなかで、<br>「ガバナンス」と「プラクティス」により実行されるものとされています。
</div>
<div>
<h3>サービスバリューチェーン</h3>
サービスバリューシステムの中心となるのが「サービスバリューチェーン」という考え方です。&emsp;サービスバリューチェーンとは、<br>
<ul>
<li>需要に対する価値を提供する製品やサービスの、開発・マネジメント活動を体系化した</li>
</ul>
もので、ITIL4の複数のプラクティスを組み合わせて、以下6つの活動を行います。<br>
<ol>
<li>計画</li>
<li>改善</li>
<li>エンゲージ</li>
<li>設計と移行</li>
<li>調達・開発</li>
<li>提供とサポート</li>
</ol>
</div>
ゆるゆる受験感想 CompTIA CASP+

こんにちは。ヤドンが好きな人です。
２月に東北を旅行中、CASP受験を決めて１か月勉強を頑張りました。
その結果2023年度滑り込みでCompTIA CASP+を受験して合格しましたので記事を書かせていただきます。

他に素晴らしい記事を書いている方がいらっしゃいますので、本記事は日記を眺める程度の温度感で見ていただけたらと思います。
※参考にさせていただいた受験記は後ろにまとめさせていただきます。

受験のきっかけは以下の三点です。
・入社直後に取ったSecurity+とCySA＋の延命
・資格補助制度の変更に伴う最後のお小遣い稼ぎ
・年度末の面談に向けて頑張ってるアピール

## 目次
- [CASP+とは](#CASP+とは)
- [試験概要](#試験概要)
- [学習方法](#学習方法)
- [受験後の所感](#受験後の所感)
- [2023年度に取得した資格との難易度比較（おまけ）](#2023年度に取得した資格との難易度比較（おまけ）)
- [参考記事](#参考記事)
- [今後の学習について](#今後の学習について)




## CASP+とは

CASP(CompTIA Advanced Security Practitioner+)はポリシーやフレームワークの管理といったマネジメント業務ではなくセキュリティの実務者としてのキャリアに進む方に適切な認定資格です。
IT全般の管理者として10年以上の経験、そのうち5年以上をセキュリティに関連する実務で得られる知識やスキルを目安に設計されています。

https://comptia.jp/pdf/CASP+_CAS-004.pdf

## 試験概要
```
問題数：最大90問
合格基準：不明
試験時間：制限時間165分
言語：日本語/英語の切り替え可
```

上位者の立場で適切な物や方針を選択する知識問題が多い印象を受けました。
初手にシミュレーション問題(ただの選択問題ではない)からはじまり、その後は複数の選択肢から1つを選ぶといった問題が続きます。たまに求められた要件を満たすものを複数選ぶ問題もございました。
カンペなどの持ち込みは一切不可能になっています。
言語の切り替えと見直しが可能で他の試験と比べて受験者にとってかなり親切です。

## 学習方法
範囲が広かったのでななめ読みを繰り返しました。2日でざっくり一周してというのを繰り返しました。
公式の出してる類似問題は以下になります。本番でもこのような問題が出てきます。

https://www.comptia.jp/training/samplequestion/comptia_casp/caspcomptia_advanced_security_practitioner_cas-004.html


ただしこれから受験される方はTACの問題集を買うのがベストではないでしょうか？
※申込受付開始日が2024年4月1日からのようです。

https://www.tac-school.co.jp/kouza_it/it_crs_comptia_caspplus_004.html

## 受験後の所感
選択式の試験ということもあり、他のセキュリティ資格試験の例に漏れず、ある程度知識や経験のある方は軽く教科書を何周かするだけでもある程度ではありますが問題を解けそうな気がします。
ただ他の資格と比べて試験範囲がかなり広く感じました。自分の経験不足も相まって、選択肢2つまでは確実に絞れるが確固たる自信があってAが正解ですと言えないような状態がしばしばあったと思います。
問題の解き方なのですが、自分は合っている物を探すのではなく、間違った箇所を探し、選択肢を消していく方法で解いていました。
最初は前者の解き方をしてたのですが、試験中に分からない単語がしばしば出てきたので途中で解き方を切り替えました。


## 2023年度に取得した資格との難易度比較（おまけ）
弊社では資格にランクが設定されており、2023年度は人事評価のためにある程度資格を取る必要がありました。
・GSEC(7月)
・支援士(10月)
・CEH(2月)
・CASP+(3月)

個人的に難易度を付けるなら以下になるかと思います。
```
CEH ＜ 支援士 ＜ GSEC ＜＜ CASP+
```
まぁ同じセキュリティといいつつもジャンルが違ったり言語の壁があったりで簡単に比較できるものではないのかもしれませんが、技術や英語スキル、実務経験のあまりない3年目社会人の一意見として参考にしていただければと思います。
CASP+が高くなっている理由はアウトプットの機会がないのが理由です。
**ただ2024/4以降はTACの問題集が使えるためCASP+はそこまでの難易度ではなくなるのかも**しれませんね。

## 参考記事
受験に当たって自分が主に参考にした記事です。
概要や学習法などはこちらを参考にしました。

https://qiita.com/v_avenger/items/0bd0f6be1a32460c8140

https://qiita.com/IsaacJ/items/16ce3b887266fb4a4da7

## 今後の学習について
先日、法事でtryhackmeの連続記録が160日目前で途絶えてしまいました。
モチベーションは下がりつつありますが、ADの侵害についての学習を再開していければと思います。
<font color="Lavender">去年の7月に異動してセキュリティとは全く無い担当になり、取り敢えず目に見える資格取得という形で上長にアピールはしましたが人手不足で社内ダブルワークが出来なくなってしまいました。稼働というものは限られており、これは組織に所属するのもとしてはどうしようもない問題なんでしょうね、、
</font>
EV3RT Bluetoothでのappの転送手順

ほぼ[このページ](https://dev.toppers.jp/trac_user/ev3pf/wiki/SampleProgram)に書いてある内容。

:::note warn
コンパイル済みのappの転送しかできない。
EV3のセンサの値をPCに持ってくる、などは不可能。
:::

### 環境
- Windows 11
- 仮想環境：Ubuntu-22.04（WSL2）
- EV3RT v1.1パッケージ（HRP3版）
# 手順
### 1.EV3とPCを接続
:::note warn
初めにEV3（EV3RTのイメージを書き込んだSDカードを挿入）を起動しておくこと。
:::

![スクリーンショット 2024-03-29 171640.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515313/cbf28104-6ffd-f8ff-0333-49f3dcb71209.png)
![スクリーンショット 2024-03-29 171640 - コピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515313/aabe4f82-c9d9-6f6a-fba1-c845d4af1e1e.png)
スタート右下の「設定」->「Bluetooth とデバイス」->「その他のデバイスを表示」をクリックすると、
![スクリーンショット 2024-03-29 171640 - コピー - コピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515313/9cfd3995-876f-6158-21bc-c11664807c72.png)
デバイス一覧が表示される。この一覧の上部「デバイスを追加」をクリック。
![スクリーンショット 2024-03-29 171640 - コピー - コピー - コピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515313/73e41c45-c562-6aff-6677-9087ccdd5957.png)
すると「デバイスを追加する」というウィンドウが立ち上がる。この「Bluetooth」をクリック。
![スクリーンショット 2024-03-29 171640 - コピー - コピー - コピー - コピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515313/4cfcb71a-e497-17a2-14e4-341803af5bb9.png)
そこから表示されるデバイス一覧から、「Mindstorms EV3」（初期設定） が表示される（多分）。その「Mindstorms EV3」をクリック。
![スクリーンショット 2024-03-29 171640 - コピー - コピー - コピー - コピー - コピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515313/e2cbdf5d-1dee-aef4-3aca-c6641d701bbf.png)
ペアリングの際にPINを求められるので、半角で「0000」（初期設定）と入力。「接続」をクリック。
![スクリーンショット 2024-03-29 171640 - コピー - コピー - コピー - コピー - コピー - コピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515313/ed2fb92b-8dab-2bfe-61b4-823b59d83086.png)
結果、一覧に「Mindstorms EV3」が「ペアリング済み」の状態で追加される。
### 2.PCとEV3をBluetooth PANで接続
* Bluetooth PAN（Personal Area Network）とは、Bluetoothを使ってデバイス同士を接続する技術のこと。
###### 手順
![スクリーンショット 2024-03-29 171640 - コピー - コピー - コピー - コピー - コピー - コピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515313/c99d928a-a36b-e2c8-1244-1c74a36fe3ec.png)
さきほどの「Mindstorms EV3」の右側にある「...」->「パーソナル エリア ネットワーク (PAN) に参加する」をクリック。
![スクリーンショット 2024-03-29 171640 - コピー - コピー - コピー - コピー - コピー - コピー - コピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515313/59ec7d46-a386-cd51-0400-46927c006c49.png)
その後表示されるダイアログで、「接続」をクリック。
結果、「接続に成功しました」と表示される。
### 3.EV3を待機状態にする

```
|   EV3RT  Console   |
|--------------------|
| .                  |
| .                  |
| .                  |
|--------------------|
|      Load App    > |　<<< 中央ボタンで開く
```


```
|  EV3RT App loader  |
|--------------------|
|  Load app from:    |
|  SD card           | <<< 上下ボタンで操作し
|> Bluetooth PAN     | <<< ここにカーソルを合わせ決定
|  Bluetooth SPP     |
|  Exit to console
```

結果、転送待機状態になる

### 4.コンパイル環境から転送

workspaceフォルダに移動し、通常どおりコンパイル。

```shell-session
> make app=フォルダ名
```

その後、初期設定状態であれば、

```shell-session
> make upload
```

で転送可能。IPアドレスを変更している場合は、後ろに[ip=xx.x.xx.x]などと付け足す。
【はめつのじゅもん】Azureのリソースグループを一括削除する

## はじめに

Azureのリソースグループを手動で一つずつ削除する作業は、特に学習目的で多数のリソースを扱った後には非常に面倒です。そのため、一括でリソースグループを削除するスクリプトを用意しました。

:::note alert
このスクリプトは本番環境では絶対に使用しないでください。学習目的の環境のみで使用すること
:::

## 前提条件

- **Azure CLIのインストール**: スクリプトを実行するためには、Azure CLIが必要です。まだインストールしていない場合は、Azureの公式サイトからダウンロードしてインストールしてください。

- **Bash環境の確保**: スクリプトはBashで書かれています。Linux, macOS, WSL、Git Bashなど、Bashが利用可能な環境で実行してください。

## スクリプトの使用方法

### スクリプトの準備

テキストエディタを開き、以下のスクリプトをコピー＆ペーストしてください。ファイル名は`delete-azure-rg.sh`とします。

```bash
#!/bin/bash

echo "警告: この操作により、現在のAzureサブスクリプションの全てのリソースグループが永久に削除されます。"
echo "本番環境では絶対に実行しないでください。"

read -p "本当に全てのAzureリソースグループを削除しますか？[y/N]: " answer
case $answer in
  [Yy]* ) 
    for rg in $(az group list --query "[].name" -o tsv)
    do
      echo "削除するリソースグループ: $rg"
      if ! az group delete --name $rg --yes --no-wait; then
        echo "エラー: リソースグループ '$rg' の削除に失敗しました。"
        exit 1
      fi
    done
    echo "リソースグループの削除を開始しました。"
    ;;
  * ) 
    echo "操作はキャンセルされました。"
    ;;
esac
```

### 実行権限の付与

スクリプトを保存した後、ターミナルを開き、以下のコマンドを使用してスクリプトに実行権限を付与します。

```bash
chmod +x delete-azure-rg.sh
```

### スクリプトの実行

実行権限を付与したら、以下のコマンドでスクリプトを実行します。

```bash
./delete-azure-rg.sh
```

この時、全てのAzureリソースグループを削除するかどうかの確認メッセージが表示されます。削除を進める場合は`y`を、キャンセルする場合は`n`を入力してください。

## 注意事項

このスクリプトを実行する際は、以下の点に十分注意してください。

1. **本番環境での使用禁止**  
   このスクリプトは、学習目的の環境でのみ使用してください。本番環境で誤って実行すると、取り返しのつかない事態になる可能性があります。

2. **削除対象の確認**  
   スクリプトを実行する前に、現在のAzureサブスクリプションに含まれるリソースグループを確認しておきましょう。意図しないリソースグループが削除されないよう、十分に注意が必要です。
   
3. **削除の確認プロンプト**  
   スクリプトの実行時には、全てのリソースグループを削除するかどうかの確認メッセージが表示されます。よく確認してから`y`を入力するようにしてください。

4. **削除の取り消し不可**  
   一度削除したリソースグループは元に戻せません。重要なリソースを誤って削除しないよう、細心の注意を払ってください。

5. **エラーへの対処**  
   リソースグループの削除に失敗した場合、スクリプトはエラーメッセージを表示して終了します。エラーが発生した場合は、手動でリソースグループを確認し、問題を解決する必要があります。

## まとめ

このスクリプトを使えば、Azureのリソースグループを一括で削除できます。ただし、本番環境での使用は避け、学習目的の環境でのみ活用するようにしましょう。

また、実行前には削除対象をよく確認し、重要なリソースを誤って削除しないよう細心の注意を払ってください。削除の取り消しはできないため、慎重に操作してください。
TubePilot AIを使用してYouTubeチャンネルを成長させるためのヒント

多くの購読者とビューを持つ有名なYouTuberになることを夢見ていますか？YouTubeチャンネルを成長させるには時間と努力が必要ですが、適切な戦略とツールがあれば、目標により早く到達できます。あなたの旅を手助けする1つのツールはTubePilot AIです。TubePilot AIを使ったYouTubeチャンネルを成長させるためのいくつかのシンプルなヒントをご紹介します。

クオリティコンテンツの作成：YouTubeチャンネルを成長させるために最も重要なことは、人々が見たいと思う動画を作成することです。自分の情熱について考え、視聴者が楽しむであろうものを考えてください。料理のチュートリアル、ゲームの動画、または日常生活に関するブログであれ、コンテンツが興味深く、良質であることを確認してください。

タイトルとサムネイルの最適化：TubePilot AIは、人々の注意を引くキャッチーなタイトルとサムネイルを考案するのに役立ちます。コンテンツに関連するキーワードを使用し、タイトルとサムネイルを群衆から際立たせてください。タイトルとサムネイルは、動画に出くわした人々が最初に見るものですので、それらを大切にしてください！

一貫してアップロードする：YouTubeチャンネルを成長させるためには一貫性が重要です。週に1回または月に数回など、定期的に新しい動画をアップロードしましょう。これにより、視聴者がエンゲージし、戻ってきてくれるでしょう。TubePilot AIは、コンテンツのスケジュールを計画し、整理するのに役立ちます。

動画を宣伝する：YouTubeのアルゴリズムだけに頼るのではなく、動画をソーシャルメディアで共有したり、他のYouTuberと協力したり、コメントで視聴者と交流したりしましょう。動画を宣伝すればするほど、視聴数や購読者数が増える可能性が高まります。

パフォーマンスを分析する：TubePilot AIは、動画のパフォーマンスを理解するのに役立つ貴重な洞察と分析を提供します。視聴時間、視聴者の維持率、クリック率などのメトリクスに注意を払ってください。これにより、うまくいっていることや改善できる点を特定できます。

視聴者と交流する：YouTubeチャンネルを取り巻くコミュニティを築くことは、長期的な成長に重要です。コメントに返信したり、フィードバックを求めたり、ソーシャルメディアで視聴者と交流したりしましょう。TubePilot AIは、視聴者とのエンゲージメントを追跡し、彼らとつながる機会を特定するのに役立ちます。

YouTubeチャンネルを成長させるには時間と忍耐が必要ですが、TubePilot AIがあれば、あなたのチャンネルを新たな高みに導くことができます。クオリティコンテンツの作成、タイトルとサムネイルの最適化、一貫性の維持、動画の宣伝、パフォーマンスの分析、視聴者との交流などを行うことで、YouTubeの成功に向けて大きな一歩を踏み出すことができます。なぜTubePilot AIを試してみて、あなたのチャンネルの成長をサポートするか考えてみませんか？
【Mac】cronで自動化プログラムの実装



## はじめに
【Mac】cronで自動化プログラムの実装、に関しての備忘録。

## 🦁<INS>**結論**</INS>🦁
事前準備と設定を行ってからの操作になる。
また基本はターミナルでのLinuxコマンドでの操作で行う。
ターミナルで操作する際にもコマンド。
入力完了した際にもコマンドが必要。
特殊な記述により、ファイルを指定の時間で実行できる。


流れ
1. 「cron」を「フルディスクアクセル」の権限付与する
2. cronの設定をするEditorを設定
3. ターミナルにて現在のcronの状態を確認
4. crontab（cronのリスト）を編集する
5. cronの時間指定する
6. cronの保存をする
7. cronのテストする
8. ログを確認してエラーなどを修正
9. 実装完了

:::note info
押さえておくべき点
* 基本は絶対path（ファイル構成も基本は絶対pathになるように記述が必要）。
* スペース（インデント）などの概念はない。
* 「#」でコメントアウトできる。
* 「>>」のあとにpathを指定することでログを保存できる。
* ログをしてした後になにを保存するのかを指定する（基本"2>&1"にする→実行したこととエラーをログに残す）
* 仮想環境は関係がない。仮想環境化でも設定しても問題ない。
:::  
***

:::note warn
利用シーン
* 指定のファイルを定期実行したい。
* 指定のファイルを指定した時間に実行したい。
* 指定の時間に再起動したい。
:::  
***

:::note alert
注意点
* Macではスリープ状態になってしまうとcronは稼働しない。　
* ファイルpathは絶対pathでないと認識しない（画像やCookieファイルなど）
* ログが残ってないとエラーなどは全くわからない。
:::  

***

## <INS>**cronの実装への道**</INS>
流れを元に一個一個まとめます。

## <INS>**「cron」を「フルディスクアクセル」の権限付与する**</INS>

システム環境設定
→「プライバシーとセキュリティ」を選択
→「フルディスクアクセス」を選択
→1番下にある「+」をクリック
→指紋認証（PCパスコード）を行う
→選択で「command+shift+G」のショートカットで「検索画面」を出す。
→検索画面にて「/usr/sbin/cron」と入力して「移動」クリック。
→「cron」が選択されてるのを確認して「開く」をクリック
→「cron」の項目がオンになってるかを確認


## <INS>**cronの設定をするEditorを設定**</INS>
* Editorを開くときに使うEditorのデフォルトを「vim」にする。
「ターミナル」を開いて下記を入力
```bash
export EDITAR=vim
```
  
* 大元のPythonファイルのpathを確認
anacondaを使ってる方などは注意が必要です。

```bash
echo $PATH
```
確認したものをメモしておきます。
pyenv、anacondaなどを使ってる方は違うので注意が必要。

使ってない方はほぼ「/usr/bin/python3」のはず。


## <INS>**ターミナルにて現在のcronの状態を確認**</INS>
crontabのリスト表示します。
現状のcronが設定されてるものがないかを確認する。
```bash
crontab -l
```

## <INS>**crontabを編集する**</INS>
crontabを編集を開始するためのコマンドをターミナルに入力する。
```bash
crontab -e
```

コマンドモードから入力モードに切替
```bash
i
```
「i」を入力するとcrontabの下に「INSERT」で出力される。


## <INS>**cronの時間指定する**</INS>
入力のフォーマットに沿って記入する。
```bash
分 時 日 月 曜日 実行コマンド
```
分: 0 から 59 まで
時: 0 から 23 まで（0は深夜0時）
日: 1 から 31 まで
月: 1 から 12 まで
曜日: 0 から 6 まで（0は日曜日）
コマンド: 実行したいコマンド


* 毎日午前1時に backup.sh スクリプトを実行する:
```bash
0 1 * * * /path/to/backup.sh
```

* 毎週月曜日の午前2時15分に update.sh スクリプトを実行する:
```bash
15 2 * * 1 /path/to/update.sh
```

* 30分間隔で report.py スクリプトを実行する:
```bash
/30 * * * * python /path/to/report.py
```

## <INS>**cronの時間指定する**</INS>
対象の列のcronを削除
```bash
dd
```

全てのcronを削除
```bash
crontab -r
```


## <INS>**cronの保存をする**</INS>
入力モードからコマンドモードに切替
入力が終わったら押すコマンド。
```bash
Esc キーを押す
```

### 保存して終了
保存する場合に入力する。

```bash
:wq  入力後、enter 
```

### 保存せずに終了
保存せずに終了したい場合に
```bash
:q!  入力後、enter 
```

## <INS>**cronのテストする**</INS>
期間を早めて、しっかり実行できてるのかを確認しやすく設定します。

```bash
/1 * * * * python /path/to/report.py
```


## <INS>**ログを確認してエラーなどを修正**</INS>
実行されてるかをログをみて確認します。


## <INS>**実装完了**</INS>


## まとめ✍️
cronにて定期実行はこれからもよく使うと思うのでここで、触れられてよかった。Linuxコマンドはもっと入力する機会を増やさないといけないなと感じた。

***  
## 参考にした記事📕
[Pythonでの自動化プログラムを、さらに効率化させる「スケジュール実行」のやり方](https://youtu.be/SrTFlFO5BIs?si=dcSSE2q1kPHqRlS0)
【Android】StateFlowのEvent的使い方まとめ

# はじめに
MVVMのようなアーキテクチャーを使用していると使用頻度の高いFlowシリーズですが、中でもStateFlowはその利便性から使用頻度が多い機能ではないでしょうか？
普段使用されるケースで多いのはViewModelとFragment間のやりとりだと思いますが、このStateFlowは性質上EventBusのような使い方も可能です。
今回はStateFlowを使用してEventBusのように使用する方法をまとめたいと思います。

# StateFlowを使用したEvent通知実装方法
まず、StateFlowのベース部分であるSampleEventStoreから実装します。

```SampleEventStore.kt
class SampleEventStore {
    companion object {
        private var instance = SampleEventStore()
        fun sharedInstance(): SampleEventStore {
            return instance
        }
    }

    private val _state = MutableStateFlow<Boolean>(false)
    val state = _state.asStateFlow()
    fun postValue(newValue: Boolean) {
        _state.value = newValue
    }
}
```

現状はサンプルの為Booleanの値を渡していますが、sealed classのような形で状態を別途定義し、値に指定する形でも良いと思います。
そこはご利用の要件に合わせて設定すべき内容を変えてもらえれば良いと思います。

また、StateFlowは常にアクティブでメモリに常駐しており、ガベージコレクションの対象となるのはガベージコレクションルートからの参照が他にない場合のみです。
つまり購読されている限り、StateFlowは破棄されません。
今回の実装はEventBusのような形で使用でき非常に便利ですが、計画的に使用しないと色々と問題につながる可能性がありますので、使用にはある程度縛りを設けた上で実装いただくのが良いかと思います。

次に通知を受け取るA画面の実装になります。

```SampleAFragment.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
   super.onViewCreated(view, savedInstanceState)

   lifecycleScope.launch {
        viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
            SampleEventStore.sharedInstance().state.collect { value ->
                // postValueで値が更新された際に呼ばれる
            }
        }
    }
}

```
受け取る側の実装は以上です。
StateFlowはcollectを使用することで購読可能です。
この購読に関して、公式のドキュメントに以下警告が記載されています。

:::note alert
警告: UI を更新する必要がある場合は、launch または launchIn 拡張関数を使用して UI から直接 Flow を収集しないでください。これらの関数は、ビューが表示されていなくてもイベントを処理します。その結果、アプリがクラッシュする可能性があります。これを回避するには、上記のように repeatOnLifecycle API を使用します。
:::

まさに警告通りで、StateFlowは状態を監視している都合上バックグラウンドにいる際や画面が破棄された状態でも呼び出されてしまいます。
そこで警告にも記載されている通り、repeatOnLifecycleを使用し呼び出されるタイミングに制約を設けることで、意図しないタイミングで呼び出されることを防ぐ事が可能です。

ちなみに余談ですが、購読の仕方として**flowWithLifecycle**というのもあるので、以下のように購読することも可能です。
```SampleAFragment.kt
SampleEventStore.sharedInstance().state
   .onEach { value ->
      // postValueで値が更新された際に呼ばれる
   }
   .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
   .launchIn(lifecycleScope)
```
上記で実装する場合の注意点として、呼び出し順序です。
上記記述とは逆にしflowWithLifecycleをonEachより先に呼びだした場合、Lifecycle.StateがSTARTED以下になるとflowWithLifecycleによってStateFlowの収集はキャンセルされますが、onEachのブロックは動き続けるのでクラッシュする可能性があります。
その点だけは注意してください。

次に通知を送る側の調整です。

```SampleBActivity.kt             
SampleEventStore.sharedInstance().postValue(true)
```

通知を送る側は簡単で、必要なタイミングで上記を呼び出すだけです。
これで受け取る側の画面が指定した状態に呼び出され、値を受け取る事が可能です。
ご説明は以上です。

# さいごに
StateFlowやLiveDataなど今では多種多様ですが、どれも理屈がわかるとなかなか面白い機能ですよね。
今回の実装は計画的利用が必須ですが、知っておくと救われることもあるかもしれませんね。
Pythonで「日付(年/月/日)と時刻(時/分/秒)の値を取得する」の動作を確認してみた

# 概要

Pythonで「日付(年/月/日)と時刻(時/分/秒)の値を取得する」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/python/date/index4.html

# 実装

以下のファイルを作成しました。
```sample.py
import datetime
tokyo_tz = datetime.timezone(datetime.timedelta(hours=9))
dt = datetime.datetime.now(tokyo_tz)
print(dt)
print("year : " + str(dt.year))
print("month : " + str(dt.month))
print("day : " + str(dt.day))
print("hour : " + str(dt.hour))
print("minute : " + str(dt.minute))
print("second : " + str(dt.second))
print("microsecond : " + str(dt.microsecond))
print("tzinfo : " + str(dt.tzinfo))
```

以下のコマンドを実行しました。
```
$ python3 sample.py 
2024-03-31 10:52:38.596977+09:00
year : 2024
month : 3
day : 31
hour : 10
minute : 52
second : 38
microsecond : 596977
tzinfo : UTC+09:00
```

# まとめ

何かの役に立てばと。
高速バスナビアプリの構想を生成AIに聞いてみた

もうポエムばかりで申し訳ない
と言うか、もうコードなんて書かなくて良い時代なのかもしれない

# 本題
本日も高速バスにて移動中の思考実験
・背中に敷く枕を出し忘れて、少し姿勢が厳しい　→　いまさらバスの運ちゃんに荷物を出してもらうのも気が引ける
・バスに乗る前にチェックしたい　→　こういう事がよくある

# 現状
対策としては、スマホのメモなどには書いているが、やはり見る習慣付けができていないと役に立たない

チェックリストのアプリを探すが、そもそも特定用途に特化していないし、それ自体を再利用したり、メンテナンスもできない
出来ればバスに乗車したログや、費用明細を家計簿アプリや表計算アプリでも管理したい

# 生成ＡＩ回答

高速バス利用者向けのアプリアイデアについて、具体的な機能を考えてみました。このアプリは、「高速バスナビ」という名前で、乗車前の準備から乗車後の管理まで、利用者の利便性を高めることを目指します。

### 主な機能：

1. **乗車チェックリスト**:
   - 乗車前に必要なアイテム（チケット、充電器、イヤホンなど）をチェックできるリストを提供。
   - リマインダー機能で出発前にチェックリストを確認できる通知を送信。

2. **交通費管理**:
   - 高速バスのチケット代、飲食物の購入、その他の交通費を記録し、月ごとの支出を把握できる。
   - チケットの電子版をアプリ内で保存、管理できる機能。

3. **乗車ログ**:
   - 乗車日、時間、ルート、座席番号などの詳細をログとして記録。
   - 乗車ログから直接チェックリストや交通費管理にリンクし、経路ごとの支出や必需品を振り返れる。

4. **ルート検索と予約サポート**:
   - 利用可能な高速バスのルート検索機能。
   - 予約サイトへのリンクや、場合によってはアプリ内で直接予約が行える機能。

5. **乗車経験の共有**:
   - ルートごとの評価やレビューを共有できるコミュニティ機能。
   - 乗車経験に基づいたアドバイスや、おすすめの座席、乗車時の注意点などを共有。

6. **オフラインアクセス**:
   - チケット情報や乗車チェックリストをオフラインでも参照できるようにする。

### 追加のアイデア：

- **エコポイントシステム**:
  - 環境に優しい選択（例えば、一番短いルートを選ぶ、自分の飲食物を持参するなど）でポイントを獲得できる。
  - 蓄積したポイントは、将来的なチケット購入時の割引などに使用できる。

- **旅行計画の統合**:
  - 高速バスの利用を中心とした旅行計画を立てられる機能。宿泊施設や観光スポットの情報も一元管理。

このアプリは、高速バスをよく利用する方にとって、旅の計画から記録まで、一貫してサポートするツールになることを目指します。

> 内部設計は同じで、旅行全体に拡張できますか？またハイキングなど、特定アクティビティ用途で作った設定を共有したりとか

はい、内部設計を汎用的に構築することで、旅行全体へと拡張し、さらには特定のアクティビティ（ハイキング、サイクリング、都市探訪など）に特化した設定を共有する機能を実装できます。このようなアプローチにより、アプリはより広範なニーズに対応し、多様なユーザーからの関心を引きつけることができます。

### 拡張性の高い内部設計の特徴：

1. **モジュール化された構造**:
   - アプリの機能を個別のモジュールとして設計し、必要に応じて追加やカスタマイズができるようにします。例えば、チェックリスト、交通費管理、ルート検索などの機能を独立したモジュールとして開発。

2. **柔軟なデータモデル**:
   - 旅行の計画、実行、記録に関連するさまざまなデータタイプをサポートできるよう、拡張性の高いデータモデルを採用。ユーザーが特定のアクティビティ用の設定を作成、共有できるようにします。

3. **ユーザー定義の設定とテンプレート**:
   - ユーザーが自分のニーズに合わせてチェックリストや旅行プランをカスタマイズし、これらの設定をテンプレートとして保存、共有できる機能。

### 特定アクティビティ用の設定共有機能：

- **コミュニティ機能**:
  - ユーザーが作成したアクティビティ特化型のチェックリストやプランを共有できるプラットフォームを提供。例えば、ハイキングに最適な装備リストや、サイクリングルートの計画が共有されるかもしれません。

- **レビューと評価**:
  - 他のユーザーが共有したプランやチェックリストを評価、コメントできる機能。これにより、有益な情報がハイライトされ、コミュニティの知識が向上します。

- **パーソナライズされた推薦**:
  - ユーザーの過去のアクティビティや好みに基づいて、関連性の高いプランやチェックリストを推薦する機能。

このような設計は、ユーザーが自身の旅行やアクティビティに関連する具体的なニーズに合わせてアプリを使用できるようにすることで、ユーザーエクスペリエンスを大きく向上させることが期待できます。

# まとめ

アプリ構想において、セルフニーズを満足しないものは意味無しと思っている
欲しいものは生成ＡＩに頼んで作ってもらう。そんな時代が来ていると思う。
必要なモノは、徹底的な自堕落な欲求の洗い出しと、徹底的に生成ＡＩを使い倒すこと。これが今後のＩＴエンジニアの裁量になるだろう
Laravelでマルチバイト文字数のカスタムバリデーションを作る


### 開発環境
- Windows 10 Pro(64bit)
- PHP 8.1.9 (cli) (built: Aug  2 2022 14:17:26) (ZTS Visual C++ 2019 x64)
- Laravel Framework 10.44.0

### マルチバイト文字数を取得する
PHPで文字数を調べる場合、strlen関数を使いますが、マルチバイト文字を使用する場合は、mb_strlen関数(**事前に、php.iniでextension=mbstringを有効にすること**)を使います。
ただ、絵文字などの場合、正しく1文字と認識できない場合があるので、今回は、grapheme_strlen関数(**事前に、php.iniでextension=intlを有効にすること**)を使っていきます。


### カスタムバリデーションを作成する
今回は、カスタムルールとして、『**指定したマルチバイト文字数以下**』であれば、OKという風にします。

 以下のコマンドでカスタムバリデーション用のファイルを作成
```powershell
php artisan make:rule MultiByteCharacter
```
**/app/Rules**ディレクトリに作成されています。
作成されたファイルに対して、以下のコードを挿入。

```diff_php:MultiByteCharacter.php
<?php

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class MultiByteCharacter implements ValidationRule
{
+  private $length;

+  public function __construct(int $length)
+  {
+    $this->length = $length;
+  }
  /**
   * Run the validation rule.
   *
   * @param  \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString  $fail
   */
  public function validate(string $attribute, mixed $value, Closure $fail): void
  {
     // 指定文字数以上であればエラーメッセージを返す
+    if (grapheme_strlen($value) > $this->length) {
+      $fail('The :attribute is Too many characters.');
+    }
  }
}

```

### カスタムバリデーションを呼び出して、使用する
例えば、PostController.php内で呼び出す場合、以下のコードを挿入してください。
```diff_php:PostController.php
// コード上部
use App\Rules\MultiByteCharacter;

// アクション内
public function save(Request $request): JsonResponse
{
  // postは、必須データかつ、マルチバイト文字で100文字より小さいこと
  $validated = $request->validate([
    'post' => ['required', new MultiByteCharacter(100)],
  ]);
}
```

### 参考リンク
- [Custom Validation Rules](https://laravel.com/docs/10.x/validation#custom-validation-rules)
- [grapheme_strlen](https://www.php.net/manual/ja/function.grapheme-strlen.php)
- [【PHP】拡張書記素クラスターを含む文字列の長さを正規表現で求める](https://zenn.dev/masakielastic/articles/7685b339925609)
Raspberry Pi 4にUbuntu 22.04をインストールしてSSH/RDP接続するまで

Raspberry Pi 4にUbuntu 22.04をインストールした後、WindowsからRDP接続を試みたところ、画面が乱れる問題が発生したので、とりあえず画面が見えるようにするための試行錯誤の結果になります。

## 環境
```
> cat /proc/device-tree/model
Raspberry Pi 4 Model B Rev 1.2

> lsb_release -a
Distributor ID: Ubuntu
Description: Ubuntu 22.04.4 LTS
Release: 22.04
Codename: jammy
```

## 0.SSHサーバーのインストール
UbuntuにはデフォルトでSSHサーバーがインストールされていないため、まずはSSHサーバーをインストールしました。
```
sudo apt update
sudo apt install openssh-server
```
インストール後下記のコマンドでSSHサーバーが起動しているかを確認します。
```
sudo systemctl status ssh
```
次にファイアウォール設定をします。
```
sudo ufw allow ssh
sudo ufw enable
sudo ufw status
```
この後はWindowsからSSH接続できるようになるので、以降はSSH接続したShell上の操作になります。
```
ssh userID@ラズパイのIPアドレス
```

## 1. xrdpのインストール
まず、xrdpをインストールして、リモートデスクトップ接続を有効にします。

```
sudo apt update
sudo apt install xrdp
```

## 2. ファイアウォールの設定
次に、ファイアウォールでRDPポート（デフォルトは3389）を許可します。
(実際に使用する場合はポートの変更をおすすめします。)
```
sudo ufw allow 3389
```

## 3. xrdpの起動確認
xrdpサービスが正常に起動していることを確認します。

```
sudo systemctl status xrdp
```

## 4. デスクトップ環境の変更
Ubuntuのデフォルトのデスクトップ環境であるGNOMEでは下記のような画像の乱れが発生してしまい、
![スクリーンショット 2024-03-31 083722.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2510530/63fe36de-d027-b3f2-adb7-80692b1b9b7a.jpeg)
色々と設定をいじっても一向に操作できる状況ではなかったため、軽量なデスクトップ環境であるXfceをインストールしました。
```
sudo apt install xfce4
echo "xfce4-session" > ~/.xsession
```

## 5. xrdpサービスの再起動
最後に、xrdpサービスを再起動して設定を反映します。

```
sudo systemctl restart xrdp
```
これで、WindowsからRaspberry Pi 4にインストールされたUbuntu 22.04にリモートデスクトップ接続して、正常に画面が表示されるようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2510530/463ac70a-0b50-654a-d851-12016954fb4a.png)
KX-7000を考える。(wikiの個人的な感想)(VIAの残党)


目的
わたくしの詩
その、VIAの残党は、このわたしです。

いきなり、いろいろ、ありすぎ

なんじゃこりゃー
VIA C7は、まだ、生きていた。
GPUのS3は、死んでいなかった。

ことの始まりは、インテルの生産力と86の普及の為に
いろいろな会社に86のライセンスが与えられて、生産されてしました。

ときは、流れ。。。。。。。。。。。。。。。。。。。。。

その中でも、VIAは、動けばいいという、お安い会社だつた。
凝った、つくりをしないで、低電力用や表示版等の産業用に使われていた。
当時、一式、1万円以下でうっていた。

ときは、流れ。。。。。。。。。。。。。。。。。。。。。(完全に忘れていた)

いろいろ、勃発

-----------------------------------

KX-7000爆誕



動作クロック 最大3.7GHz

コア 8基内蔵

DDR5メモリ 最大128GB

今どき、ときどきな、CPU

国内での販売は、不明。　ネットだと遅いらしい。
たぶん、普通につかえるはず?

-----------------------------------
macOSのSwiftBar：新しいSSID取得方法でWi-Fi接続状況をリアルタイムに確認

![](https://cdn-ak.f.st-hatena.com/images/fotolife/m/masatora_bd5/20240330/20240330234419.jpg)

## やりたいこと

Wi-Fiの接続状況、特にスピードを自動的に記録しておくと便利です。

記事 [Wi-Fi環境を把握して最適なプレイを](https://qiita.com/hann-solo/items/c560062e9742769ce5bc) にもあるよう、接続速度の推移を記録してあると対策の幅が広がります。

macOSには、[SwiftBar](https://swiftbar.app) というツールがあり、Wi-Fiの自動モニタリングとの相性は最高です。

![SS 2024-03-30 23.19.04_rd.png](https://cdn-ak.f.st-hatena.com/images/fotolife/m/masatora_bd5/20240330/20240330231928.png)
<span class="mxt-caption"> ▲ 10分毎に自動測定しており、メニューバーでいつでも見られます。</span>

## 今回発生した困りごとと対策

SwiftBar プラグインで、SSID表示がうまくいかなくなりました。

macOSのセキュリティポリシー更新で、`airport`コマンドが非推奨となり、代替方法への移行が必要となりました。この変更はWi-Fi速度自動測定プラグインに影響があり、SSIDが正しく表示されなくなっていました。

この記事では、SSID取得方法を改訂した作業の詳細を記します。

### 改訂内容の概要

#### SSID取得方法の更新

以前のSSID取得コマンド:

```bash
ssid=$(/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | awk -F': ' '/ SSID/ {print "SSID: " $2}')
```

改訂後のSSID取得コマンド:

```bash
ssid=$(system_profiler SPAirPortDataType | awk '/Current Network Information:/{getline; gsub(/^ +|:$/,""); print "SSID: " $0; exit}')
```

プラグインの全体コード：

[speedtest_swiftbar.sh - Monitor Wi-Fi speed: Automatic tests, monthly logs, and menu bar results · GitHub](https://gist.github.com/hnsol/bde3ef4c5f76790f2fe93c0d7a1a0919)

#### 変更の動機

`airport`コマンドの非推奨化により、SSIDが取得できず、メニューバーにSSIDを表示できなくなりました。`system_profiler SPAirPortDataType`を使用することで、SSIDを含むネットワーク情報を安定して取得できるようになります。このコマンド変更は、SSID取得方式を現在のmacOSの仕様に合わせ、より長期的に利用可能にします。

### 注意点

この改訂は現在の`system_profiler`の出力フォーマットに基づいています。Appleによる将来的なフォーマット変更は、この解決策の有効性に影響を及ぼす可能性があるため、注意が必要です。

### 補足：SSID取得コマンドの変更

新しい`system_profiler SPAirPortDataType`コマンドは、従来の`airport`コマンドに比べ、包括的なWi-Fiネットワーク情報を提供します。SSIDだけでなく、接続品質やセキュリティ設定など、より詳細なデータを得られます。また、macOSのセキュリティポリシーに基づく変更に強く、将来的にもサポートが続く見込みです。

## まとめ

この記事では、SwiftBarプラグインのSSID表示問題に対処するための方法を紹介しました。macOSの更新に伴い非推奨となった`airport`コマンドに代わる、新しいSSID取得方法を導入しました。

この改訂により、プラグインは再び正確なSSID情報を表示できるようになり、ユーザーは現在接続しているWi-Fiネットワークを簡単に確認できます。

:::note
この記事は [📗SwiftBarでのWi-Fi速度測定とそのSSID表示問題の対応 - MXT Forest](https://silme.zelo-loop.com/mxt/%F0%9F%93%9DMini+Hacks/%F0%9F%93%97SwiftBar%E3%81%A7%E3%81%AEWi-Fi%E9%80%9F%E5%BA%A6%E6%B8%AC%E5%AE%9A%E3%81%A8%E3%81%9D%E3%81%AESSID%E8%A1%A8%E7%A4%BA%E5%95%8F%E9%A1%8C%E3%81%AE%E5%AF%BE%E5%BF%9C) に基づいています。最新の情報や更新は、元の記事で確認してください。
:::
JavaScriptでQRコードからSVGファイルを作成する

```html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/qrcode@1.4.4/build/qrcode.min.js"></script>
  </head>

  <body>
    <p style="font-size: 32px;">QRコードからSVGファイルを作成します</p>
    <input type="text" id="inputText" />
    <button onclick="generateQRCode()">QRコード生成</button>
    <div id="qrcode"></div>
    <a id="downloadLink" style="display: none;">SVGファイルをダウンロード</a>
    <script>
      async function generateQRCode() {
        const inputText = $("#inputText").val();
        const options = {
          type: 'svg',
          // width: 256,
          margin: 2,
          color: {
            dark: '#000',
            light: '#fff'
          }
        };
        const svgTag = await QRCode.toString(inputText, options);
        console.log(svgTag)
        $("#qrcode").empty().append(svgTag);
        $("#qrcode svg").attr("width", "256px");
        const fileName = "";
        const downloadLink = document.getElementById("downloadLink");
        downloadLink.href = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svgTag);
        downloadLink.download = fileName;
        downloadLink.style.display = "inline"; // displayをinlineに変更
      }
    </script>
  </body>
</html>
```

### jsDelivr

https://www.jsdelivr.com/package/npm/qrcode

>**Browser**
node-qrcode can be used in browser through module bundlers like Browserify and Webpack or by including the precompiled bundle present in build/ folder.

ブラウザからCDNで利用する時は、buildフォルダのファイルを指定する

### 参考

https://blog.katsubemakito.net/nodejs/qrcode-generates

https://qiita.com/7shi/items/4d80f838638a5bb66265
Hono × Supabase × Prismaで環境構築

# 目次
[１. はじめに](#1-はじめに)
[２. 開発環境](#2-開発環境)
[３. 開発手順](#3-開発手順)
[４. 動作確認](#4-動作確認)

# 1. はじめに
現在、熱い🔥と言われているフレームワークである「**Hono**」と、熱々の肉まん「**Bun**」を使って、登録されたユーザーをJSON形式で表示するアプリを開発したいと思います。
DBに「**Supabase(PostgreSQL)**」、ORMに「**Prisma**」を使用します。
今回はフロント周りには触れないので悪しからず。

※2024/4/3現在
簡単なユーザー登録画面を開発中です。

作成したGithubリポジトリは[こちら](https://github.com/yamaneko86/hono-supabase-prisma-tutorial)

# 2. 開発環境
| Package | Version |
|:-|:-|
| bun | 1.0.35 |
| hono | ^4.1.5 |
| prisma | ^5.11.0 |
| @prisma/client | ^5.11.0 |

# 3. 開発手順
### Bunでプロジェクト作成
```console
bunx create-hono hono-supabase-prisma-tutorial
cd hono-supabase-prisma-tutorial
```

### Supabaseの設定
プロジェクトを作成するとき、パスワードを設定します。
後ほど使用するので、メモしておいて下さい。
また、以下の画像を参考に、Connection Stringを取得して下さい。

Project Settings > Database > Connection String
![スクリーンショット 2024-03-31 8.39.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3271648/818ef7dc-f8d2-6e0c-f4e1-a21af4d1bc57.png)

### Prismaの導入・設定
以下のコマンドでPrismaをインストールします。
```console
bun i prisma -D
bun i @prisma/client
```

Prismaの初期化をします。
```console
bunx prisma init
```
プロジェクトディレクトリ直下に`prisma/schema.prisma`ファイルと`.env`ファイルが作成されます。

`schema.prisma`ファイルにUserモデルを追加します。
```schema.prisma
model User {
  user_id   String @id      @default(dbgenerated("uuid_generate_v4()"))
  user_name String @db.Text
}
```
また、`.env`ファイルのDATABASE_URLを設定して下さい。
String中の[YOUR-PASSWORD]を **[ ]も含めて** Supabaseのプロジェクトを作成したときのパスワードに変更して下さい。
```.env
DATABASE_URL=postgres://postgres.mgjwqsdydswnlgiteiez:XXXXXXXXXXXXXXXX@aws-0-ap-northeast-1.pooler.supabase.com:5432/postgres
```

設定が完了したら、以下のコマンドでマイグレーションします。
```console
bunx prisma migrate dev --name init
```
正常に実行できたら、SupabaseにUserテーブルが追加されていると思います。

### Honoでバックエンド開発

```src/api/user/route.ts
import { PrismaClient } from "@prisma/client";
import { Hono } from "hono";

const app = new Hono();
const prisma = new PrismaClient();

export const users = app.get("/", async (c) => {
  const getUsers = await prisma.user.findMany();
  return c.json(getUsers);
});
```



```src/index.ts
import { Hono } from "hono";
import { users } from "./api/user/route";

const app = new Hono();

app.route("/users", users);

export default app;
```



# 4. 動作確認
今回はSupabaseのTable Editerから手動でデータを追加しています。
```console
bun run dev
```
ブラウザからでも良いですが、今回はThunder Clientで確認します。

![スクリーンショット 2024-03-31 9.42.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3271648/05bc57c2-496e-b36a-8a92-c391d676ffcb.png)

データを取得できていることが確認できました！🎉
Gemfile: Undefined local variable or methodエラーの解決

bundlerを使用してgemをインストールしようとしたところエラーが発生したので原因調査を行い解決したプロセスをまとめていきます。

## 背景
rspecの学習をするために、`Gemfile`にrspecを追加して`bundle install`した際にエラーが発生しました。

## 発生したエラー
```
[!] There was an error parsing `Gemfile`: Undefined local variable or method `rspec' for Gemfile. Bundler cannot continue.

 #  from /Users/xxx/Documents/ruby/Gemfile:7
 #  -------------------------------------------
 #  
 >  gem rspec
 #  -------------------------------------------

```


## 原因
`Undefined local variable or method`というエラーメッセージなので`rspec`が変数かメソッドとして認識されていることが原因でした。

## 解決
以下のようにクオーテーションで囲んで、`rspec`を文字列として認識させました。

```
# frozen_string_literal: true

source "https://rubygems.org"

# gem "rails"

gem rspec

```
VS CodeでFailed to find the "go" binary in either GOROOT() or PATHエラー解決

## はじめに
MacでGoの環境構築時のメモです

## 解決方法

Homebrew等でGoをインストールして, PATHが追加してあることを確認します.

VS Codeを一度終了させます.

VS Codeをターミナルから直接起動することで、ターミナルの環境変数を引き継ぐことができます。ターミナルで以下のコマンドを実行してVS Codeを起動してみてください。

```sh
open -a "Visual Studio Code"
```


これで、タイトルにあるエラーが解決できました.

---

Go言語を始める際の参考になれば幸いです。