OmniAICreator/Qiita-1.07M huggingface dataset:
Pythonでハングルの子音と母音を分解する

# はじめに
ハングルを構成要素に分解して処理するためのPythonライブラリについてまとめます。
日本語だとjaconvやkakasiやjamorasepなどのようなものでしょうか。

# hanja
漢字語の処理のライブラリっぽいですが、ハングルの処理にも使えます。

https://pypi.org/project/hanja/

```bash
$ pip install hanja
```

一文字ずつ入力します。

```python
from hanja import hangul

hangul.separate('가')
#=> (0, 0, 0)
```
タプルの一つ目の要素が子音(初声)、2つ目が母音（中声）、3つ目がパッチム（下につく子音：終声）です。

それぞれの数字の割り振りは以下の順序のようです。
```python
# 子音
['ㄱ',
 'ㄲ',
 'ㄴ',
 'ㄷ',
 'ㄸ',
 'ㄹ',
 'ㅁ',
 'ㅂ',
 'ㅃ',
 'ㅅ',
 'ㅆ',
 'ㅇ',
 'ㅈ',
 'ㅉ',
 'ㅊ',
 'ㅋ',
 'ㅌ',
 'ㅍ',
 'ㅎ']

# 母音
['ㅏ',
 'ㅐ',
 'ㅑ',
 'ㅒ',
 'ㅓ',
 'ㅔ',
 'ㅕ',
 'ㅖ',
 'ㅗ',
 'ㅘ',
 'ㅙ',
 'ㅚ',
 'ㅛ',
 'ㅜ',
 'ㅝ',
 'ㅞ',
 'ㅟ',
 'ㅠ',
 'ㅡ',
 'ㅢ',
 'ㅣ']

# パッチム
['', # 0番目はパッチム無し
 'ㄱ',
 'ㄲ',
 'ㄳ',
 'ㄴ',
 'ㄵ',
 'ㄶ',
 'ㄷ',
 'ㄹ',
 'ㄺ',
 'ㄻ',
 'ㄼ',
 'ㄽ',
 'ㄾ',
 'ㄿ',
 'ㅀ',
 'ㅁ',
 'ㅂ',
 'ㅄ',
 'ㅅ',
 'ㅆ',
 'ㅇ',
 'ㅈ',
 'ㅊ',
 'ㅋ',
 'ㅌ',
 'ㅍ',
 'ㅎ',
 'ㅐ',
 'ㄱ',
 'ㄲ',
 'ㄳ',
 'ㄴ',
 'ㄵ',
 'ㄶ',
 'ㄷ',
 'ㄹ',
 'ㄺ',
 'ㄻ',
 'ㄼ',
 'ㄽ',
 'ㄾ',
 'ㄿ',
 'ㅀ',
 'ㅁ',
 'ㅂ',
 'ㅄ',
 'ㅅ',
 'ㅆ',
 'ㅇ',
 'ㅈ',
 'ㅊ',
 'ㅋ',
 'ㅌ',
 'ㅍ',
 'ㅎ']
```

# jamo
https://pypi.org/project/jamo/

```bash
$ pip install jamo
```

ハングルの構成要素にばらけさせます。複数文字も同時に入力できます。


```python
from jamo import h2j, j2hcj

j2hcj(h2j("한글자모분리"))
#=> 'ㅎㅏㄴㄱㅡㄹㅈㅏㅁㅗㅂㅜㄴㄹㅣ'
```
最初の`h2j`メソッドは型変換的なものっぽい。
一文字ずつ先に分けておかないとパッチムでややこしくなりそう。

# hgtk
jamoより便利そう？

https://pypi.org/project/hgtk/

```bash
$ pip install hgtk
```

jamoの`j2hcj`と同じことができます。
```python
import hgtk

hgtk.letter.decompose('감')
#=> ('ㄱ', 'ㅏ', 'ㅁ')
```

`compose_code`を区切りにして文字ごとに区切ってくれます。
```python
hgtk.text.decompose('학교종이 땡땡땡! hello world 1234567890 ㅋㅋ!', compose_code='/')
#=> 'ㅎㅏㄱ/ㄱㅛ/ㅈㅗㅇ/ㅇㅣ/ㄸㅐㅇ/ㄸㅐㅇ/ㄸㅐㅇ/! hello world 1234567890 ㅋ/ㅋ/!'
```

助詞を良い感じにつけてくれる
```python
hgtk.josa.attach('하늘', hgtk.josa.I_GA)
#=> '하늘이'

hgtk.josa.attach('바다', hgtk.josa.I_GA)
#=> '바다가'
```

# （番外編）BTS
https://github.com/irishev/BTS

ライブラリではありませんが、2022年に発表された以下の論文の実装になります。（名前はなんか狙いすぎですが...）

https://aclanthology.org/2022.emnlp-main.472/

子音と母音の分解を以下のように、ハングルの成立過程なども踏まえて行っているようです。
![スクリーンショット 2023-06-11 20.34.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638747/5b2af018-3fcf-7996-0f8c-f60b0dc3f860.png)
これにより、異なる子音の間でも共通の要素を取り出すことができるような手法です。`ㅋ`が`ㄱ`と`-`に分解されるのとかは分かるんですが、`ㄷ`が`ㄴ`と`-`に分解されるのとかは結構不思議な感じがします。

```bash
$ pip install hgtk jamotools
$ git clone https://github.com/irishev/BTS.git
```
して
```python
import sys
sys.path.append("BTS")
```
しておきます。

必要な関数(`jamo_split`)だけ取り出して使うと良さそうです。
```python
from BTS.decompose_letters import jamo_split

sentence = "이라크"

jamo_split(sentence, split_stroke=True, split_cji=True)
#=> 'ㅇ^ㅣ^^/ㄹ^ㅣㆍ^^/ㄱ-^ㅡ^^/'
```
文字の区切りが`/`、文字内の要素の区切りが`^`になっています。
`split_stroke`と`split_cji`の設定により、以下のように区切り方が変化します。

```python
# 子音がまとまる（ㅋ）
jamo_split(sentence, split_stroke=False, split_cji=True)
#=> 'ㅇ^ㅣ^^/ㄹ^ㅣㆍ^^/ㅋ^ㅡ^^/'

# 母音がまとまる（ㅏ）
jamo_split(sentence, split_stroke=True, split_cji=False)
#=> 'ㅇ^ㅣ^^/ㄹ^ㅏ^^/ㄱ-^ㅡ^^/'

# 子音と母音の両方がまとまる
jamo_split(sentence, split_stroke=False, split_cji=False)
#=> 'ㅇ^ㅣ^^/ㄹ^ㅏ^^/ㅋ^ㅡ^^/'
```


# おわりに
ハングル自体がとてもシステマチックでシンプルなので、これだけあれば問題なさそうでしょうかね
Goで指数表記を取り扱う

今年の3月まで19ヶ月ほどGoを書いていたのですが、その際は何となく雰囲気でやっていたので。
Goを基礎から勉強しなおそうと思い、[A Tour of Go](https://go.dev/tour/list)をやっています。

## 指数表記のお試しメモ

[Pointers to structs](https://go.dev/tour/moretypes/4)で`1e9`を直接指定しているのを見たので調べた所、[指数表記](https://ja.wikipedia.org/wiki/%E6%8C%87%E6%95%B0%E8%A1%A8%E8%A8%98#:~:text=%E6%8C%87%E6%95%B0%E8%A1%A8%E8%A8%98%EF%BC%88%E3%81%97%E3%81%99%E3%81%86%E3%81%B2%E3%82%87%E3%81%86,%E5%88%86%E9%87%8E%E3%81%A7%E5%A4%9A%E7%94%A8%E3%81%95%E3%82%8C%E3%82%8B%E3%80%82)というものらしい。  
非常に大きな数または非常に小さな数を表現する際に使い、直接指定出来る様子。

```go
package main

import (
	"fmt"
	"reflect"
)

func main() {
	exponentialNotation := 1e+4
	fmt.Println("100000を指数表記で", exponentialNotation)
	
	exponentialNotation = 1e4
	fmt.Println("+を省略も出来る", exponentialNotation)
	fmt.Println("型はfloat64になる", reflect.TypeOf(exponentialNotation))

	exponentialNotation = 1e-4
	fmt.Println("0.0001を指数表記にする場合は-で", exponentialNotation)
}
```

```shell
100000を指数表記で 10000
+を省略も出来る 10000
型はfloat64になる float64
0.0001を指数表記にする場合は-で 0.0001
```

## 感想

浮動小数点数の値で似たような表記がされているのを見かけていましたが、指数表記という単語自体は初めて知りました。
11年以上プログラマ兼SEをやってますが、8年くらい前にいた銀行系の案件以外で浮動小数点数を重要視するような案件思い出せませんし、そこまで困ったこともなかったですね…。
プログラミング言語が色々と変わっても業務アプリ系だとなんとなく雰囲気で書けちゃいますが、基礎から勉強するのは大切ですね。
Nuxtでgoogle maps apiを使ってみた

先にGoogle Maps APIのAPI キーを取得しておきます。
クレジットカードがいるみたいです。

https://console.cloud.google.com/?hl=ja


　　　
　　

で、goole Map を使うためのライブラリを入れます。

https://www.npmjs.com/package/@googlemaps/js-api-loader


```terminal
npm i @googlemaps/js-api-loader
npm i -D @types/google.maps
```

  
   
　　

で、あとはサンプルコード通りに書いたら終わり。

```javascript
import { Loader } from '@googlemaps/js-api-loader';

const loader = new Loader({
  apiKey: "",
  version: "weekly",
  libraries: ["places"]
});

const mapOptions = {
  center: {
    lat: 0,
    lng: 0
  },
  zoom: 4
};
```
　　　
　　　

のはずが、ここをonMountedに書いたら動かなかった
```javascript
onMounted(() => {
    loader
      .importLibrary('maps')
      .then(({Map}) => {
        new Map(document.getElementById("map"), mapOptions);
      })
      .catch((e) => {
        // do something
      });
});
```
　　
　　　

なんでかonMountedでも
document.getElementById("map")がundefindになってた。
　　　
　　　　
なのでとりあえずdocument.getElementById("map")の要素をrefにして、
watchして値が入ったら動かすようにしたら直った。
プレビュー表示された画像から削除する(Rails/ActiveStorage)

https://qiita.com/AttAtD/items/6b9502c0fa75531ee400
https://qiita.com/AttAtD/items/c2077d3bd3d0f1be3268
の続き

追加した画像を削除することができないので、その対応を行う。

## 投稿フォームに画像の削除ボタンを追加する。

削除ボタンにはJavascriptから呼び出すために`data-action="image-preview#removeImage"`を付与する。
また、その際に削除対象のファイルを特定できるように`data-file`属性にファイル名を付与しておく

- `new.html.erb`

```erb
  ...
  <% @post.photos.each do |photo|%>
    <li data-image-preview-target="preview" data-file="<%= photo.blob.filename %>">
      <%= f.hidden_field :signed_ids, multiple: true, value: photo.blob.signed_id %>
      <div>
        <%= image_tag photo, style: "width:300px" %>
      </div>
      <div>
        <button type="button" 
          data-file="<%= photo.blob.filename %>"
          data-action="image-preview#removeImage">
          削除
        </button>
      </div>
    </li>
   <% end %>
  ...
```

## 削除するJavascriptを追加

- `image_preview_controller.js`

```
static targets = [ "output", "input", "preview"];

...

removeImage(e) {
    let input = this.inputTarget;
    const previews = this.previewTargets;
    const button = e.currentTarget;
    const fileName = button.getAttribute("data-file");
    const preview = previews.find((target) => target.getAttribute("data-file") == fileName);
    if(preview) {
      preview.remove();
    }
    const files = Array.from(data.files);
    const index = files.findIndex((f) => f.name == fileName);
    if (index != -1) {
      data.items.remove(index);
      input.files = data.files;
    }
  }
```

## ファイル追加時のjavascriptの実装を修正

ファイル追加時に生成されるタグにもdata-file属性、data-action属性などを追加して、削除ボタンが表示されるようにする

- `image_preview_controller.js`

```javascript
  readOne(f, index, output) {
    let reader = new FileReader();
    reader.readAsDataURL(f);
    reader.onload = () => {
      const html= `<li data-image-preview-target="preview" data-file="${f.name}"> # ここを修正
                  <div>
                    <image src="${reader.result}" style="width:300px"/>
                  </div>
                  <div> 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 # ここを追加
                    <button type="button" data-file="${f.name}" data-action="image-preview#removeImage" }> # ここを追加
                      削除 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　# ここを追加
                    </button>　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　  　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　# ここを追加
                  </div>　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　       　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　　　　 　　　　　　　　# ここを追加
                </li>`;
      output.insertAdjacentHTML('beforeend', html);
    };
  }
```
ABC305

# ABC305
今週は参加できましたので、書いていきます。
ABC305( https://atcoder.jp/contests/abc305 )

# A
余りで場合分けした。一度5で割ることで端数の処理を行ったが、もっとうまいやり方がある気がする。。。
```diff_python
N = int(input())
if N % 5 >= 3:
  print((N//5+1) * 5 )
else:
  print(N//5 * 5)
```

# B
文字を入れた配列l_sと文字間の距離を入れた配列lを作り、文字ごとにl_sのindexを取ってその値をlに利用した。
例えば、AとBの間であればl_sのindexを取ることで0と1の値を得る。その値を用いて、l[1:2]のようにスライスを使って計算に用いる部分配列を求め、その配列にsum()関数を用いることで求めた。
問題上、文字が昇順で与えられるとは限らないため、その部分の条件文を加えた。
```diff_python
p,q = map(str, input().split())
l = [3,1,4,1,5,9]
l_s = ["A","B","C","D","E","F","G"]
a = l_s.index(p)
b = l_s.index(q)
if a > b:
  box = a
  a = b
  b = box
print(sum(l[a:b]))
```

# C
各行ごとの#の数をカウントし、それを配列cとして格納する。クッキーを食べている行は#が一つ少ないため、配列cの最大値から1ひいたもののindexを調べることで食べた行までわかる。その後、食べた行と食べてない行で#が一致しない部分を調べることで座標を求めた。
「周囲に2個以上#がある.の座標」というのも考えたがTLEを警戒して上記手法をとった。が、今回は行けたらしい。
```diff_python
H, W = map(int, input().split())
M = [input() for _ in range(H)]
l = []	#列ごとのクッキーの数
 
for i in range(H):
  l.append(M[i].count("#"))
 
x = l.index(max(l)-1)	#食べた列
x_ = l.index(max(l))	#食べてない列
 
#食べた行の判別
for j in range(W):
  if M[x][j] != M[x_][j]:
    y = j
    break
 
#回答
print(x+1,y+1)
```

# D
TLEとなり時間内の回答ができなかった。条件をみて工夫がいることが分かったが、全く思いつかずに愚直にやることしかできなかった。
計測の終了時間までの睡眠時間の総和から、開始時間までの睡眠時間の総和を引くことで求められる。起床や就寝時点までの睡眠時間の総和は簡単に求められるため、配列として確保しておく。計測時間は就寝や起床のタイミングで行われない場合があるため、どのタイミングで起きたかを二分探索で求め、各タイミングでの処理を行う。ここはおそらく条件文でもいいし、解説のように睡眠時間の配列を利用し条件なしでも計算のみでも対応できる。
多分重要なのは二分探索の部分で、計算の部分は書く時間帯ごとの睡眠時間とかを使ってもいける気がする。。。
```diff_python
from bisect import bisect_left
 
def Calsleep(T,A,x):
  t = bisect_left(A,x)
  if t == 0:
    return 0
  else:
    return T[t-1] + (T[t] - T[t-1])//(A[t]-A[t-1]) * (x - A[t-1])
 
N = int(input())
A = list(map(int, input().split()))
T = [0]
 
for i in range(N):
  if i % 2 == 0:
    T.append(T[i])
  else:
    T.append(T[i] + A[i+1] - A[i])
 
Q = int(input())
 
for i in range(Q):
  s,e = map(int, input().split())
  print(Calsleep(T,A,e) - Calsleep(T,A,s))
```

# 反省・感想
二分探索には今まで何度か問題として触れてきているが、使う場面を見抜くことがまだまだできていないと感じるコンテストでした。使うアルゴリズムの取捨選択の判断を今後はっきりとさせていきたいと思います。あと、自分で作る二分探索よりライブラリ使った方がバチバチに早いこともわかりました。はい。
どんどんレート下がってやる気も下がりそうですが、ちまちま取り組んでいきたいと思います。

745 → 728
【Rails】rails db:migrateするとクラッシュレポートが出力されて出来ない。

### はじめに
railsアプリでマイグレーションを実行しようと`rails db:migrate`を実行すると以下のようなエラーが発生しました。
```
[IMPORTANT] 
Don't forget to include the Crash Report log file under 
DiagnosticReports directory in bug reports.
```
`rails db:migrate:reset`しても解決せず、躓きました。

## 環境
ruby 3.1.1
rails 6.1.7.3
mysql 5.7
gem mysql '~> 0.5'

## 原因
自分の場合、brewでmysqlをインストールしていました。
そして以下のディレクトリにはインストールしたバージョンが格納されているのですが、使用していたmysql5.7ではなくmysql8.0がいつの間にか格納されていました。
```
/usr/local/Cellar/mysql
```

## 解決

mysqlをアンインストールします。
```
brew uninstall mysql
```
そして、開発に必要なバージョンのmysqlをインストールし直します。
```
brew install mysql@5.7
```
mysqlを起動します。
```
brew services start mysql@5.7
```
gem mysqlをアンインストールします。
```
bundle exec gem uninstall mysql2
```
再びインストールします。
```
bundle install
```


## 参考
[MySQL起動エラーの対処の仕方【Library not loaded: /usr/local/opt/mysql/lib/libmysqlclient.21.dylib (LoadError)】](https://qiita.com/k-yasuhiro/items/9674d2e6e0b0fac3e1a8)
Famousfile.com Excellence は最新のソフトウェアを提供します

成長を続けるデジタル時代において、個人、企業、政府機関を問わず、コンピュータ ユーザーにとってソフトウェアまたはソフトウェアの必要性はますます重要になっています。 最新ソフトウェアに対する需要の高まりに応えるために、Famous File は業界をリードするプロバイダーの 1 つになることに成功しました。 Famous File はさまざまな利点があるため、ソフトウェアの更新と保守に関してユーザーに最高のエクスペリエンスを提供できます。 この記事では、最新のソフトウェアを提供する際の Famous File の利点について詳しく説明します。

まず、Famous File は世界中の主要なソフトウェア開発者と強いつながりを持っています。 Famous Files ではさまざまな検証済みソースから最新のソフトウェアへのアクセスが提供されるため、これはユーザーに利点をもたらします。 したがって、ユーザーは目的のソフトウェアを手動で検索する必要がなくなり、Famous Files を利用して最新のソフトウェアを簡単かつ迅速に入手できます。

それとは別に、Famous File は定期的なソフトウェア アップデートも提供します。 彼らの専門家チームはソフトウェア業界の発展を継続的に監視し、必要なアップデートをリリースします。 Famous Files を使用すると、ユーザーは使用するソフトウェアが常に最新の機能と必要な修正で更新されていることを確認できます。 これは、システムのセキュリティと最適なパフォーマンスを維持するために非常に重要です。

Famous File のもう 1 つのハイライトは、直感的でフレンドリーなユーザー インターフェイスです。 ソフトウェアのインストールと更新のプロセスにおいて、Famous File は、深い技術知識を持たないユーザーでも理解しやすいインターフェイスを提供します。 明確なステップバイステップのガイドにより、ユーザーは必要なソフトウェアを簡単にインストールまたは更新できます。 このため、Famous File はあらゆるスキル レベルのユーザーの間で人気のある選択肢となっています。

Famous File には、さまざまな種類のソフトウェアに関する広範かつ完全なデータベースもあります。 Famous Files カタログでは、データ処理、グラフィック デザイン、サイバー セキュリティに至るまで、さまざまな目的のソフトウェアを見つけることができます。 この豊富なデータベースにより、ユーザーはさまざまなソースを検索することなく、自分のニーズに合ったソフトウェアを簡単に見つけることができます。 Famous Files を使用すると、ユーザーは適切なソフトウェアを見つける貴重な時間と労力を節約できます。

それとは別に、Famous File には顧客サポートの面でも利点があります。 Famous File のサポート チームは、ユーザーがソフトウェアの問題や質問を解決できるよう支援する用意があります。 ユーザーは、電話、電子メール、ライブチャットなどのさまざまな通信チャネルを通じてサポート チームに連絡できます。 Famous File では、迅速な対応とタイムリーな解決策が最優先事項であり、ユーザーが必要なサポートを効率的かつ効果的に得ることができます。

最後に、Famous File はセキュリティを最優先して最新のソフトウェアを提供しています。 彼らは、ユーザーにリリースする前に、各ソフトウェアの厳密な検証とテストを実行します。 したがって、Famous File は、提供するソフトウェアにウイルス、マルウェア、その他のセキュリティ上の脅威がないことを保証します。 Famous File にとってユーザー データのセキュリティは最も重要であり、ユーザーの信頼を維持するためにセキュリティ システムを継続的に改善しています。

全体として、Famous Files は最新のソフトウェアの優れたプロバイダーとしての地位を確立しています。 Famous File は、強力な接続、定期的なアップデート、直感的なユーザー インターフェイス、包括的なデータベース、優れた顧客サポート、保証されたセキュリティを備えており、最新のソフトウェアの入手と維持に関して最高のユーザー エクスペリエンスを提供します。 フェイマスファイルは、この業界のリーダーとして、今後もより良いサービスを提供するために革新を続けます。
ROS2 Joy Stick Controller を使って Turtlesim を動かす

# ROS2でJoyスティックコントローラを使いたい
![01 2023-06-11 00-19-39.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282390/54744f75-e77f-7cae-0042-49b2c9b99e9b.jpeg)


やりたいことはこの動画の感じ。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ROS2 のべんきょう<br>Joy Stick Controller で Turtlesim <a href="https://t.co/6roLVNu9gn">pic.twitter.com/6roLVNu9gn</a></p>&mdash; moriitkys (@moriitkys) <a href="https://twitter.com/moriitkys/status/1667553094056681472?ref_src=twsrc%5Etfw">June 10, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


Joy Stickを使う場合は以下実行するだけでOK。
```
$ ros2 run joy joy_node
```
しかしjoyトピックなので亀を動かすためにはTwistに変換する必要がある。
自分でパッケージを作ってみる。

![Screenshot from 2023-06-10 23-27-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282390/af914026-1774-74f3-a4a5-e146bec4a7f2.png)

![rosgraph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282390/b5c4d81d-ec44-d2b1-2e5e-d664104a229a.png)


# JoyからTwistへの変換のためのPythonコード

```py
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
from geometry_msgs.msg import Twist
from sensor_msgs.msg import Joy

class JoyTranslate(Node): 
    def __init__(self):
        super().__init__('joy_translate_node') 
        self.publisher = self.create_publisher(Twist,'cmd_vel', 10)
        self.subscription = self.create_subscription(Joy,'joy', self.listener_callback, 10)
        self.vel = Twist()

    def listener_callback(self, Joy): 
        self.vel.linear.x  = 2*Joy.axes[1]
        self.vel.angular.z  = 2*Joy.axes[3]
        self.publisher.publish(self.vel)
        self.get_logger().info("Velocity: Linear=%f" % (Joy.axes[1])) 

def main(args=None):
    rclpy.init(args=args)
    joy_translate = JoyTranslate()
    rclpy.spin(joy_translate)
    rclpy.shutdown()

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

# パッケージ作成
```
$ cd ~/ros2_ws/src
$ ros2 pkg create --build-type ament_python --node-name joy_translate_node joy_translate

$ cd ~/ros2ws/src/joy_translate/joy_translate
```

ここでjoy_translate_node.pyを編集する。「JoyからTwistへの変換のためのPythonコード」で示したコードをコピペでOKのはず。

# 実行
```
$ ros2 run turtlesim turtlesim_node
$ ros2 run joy_translate joy_translate_node --remap cmd_vel:=turtle1/cmd_vel
$ ros2 run turtlesim turtlesim_node
```

# 参考

https://demura.net/robot/ros2/20748.html

# 自分用のメモ

<details><summary>自分用メモ</summary>

トピックを見る場合 
ros2 topic echo /joy


rosmsg show sensor_msgs/Joy

std_msgs/Header header
  uint32 seq
  time stamp
  string frame_id
float32[] axes
int32[] buttons


geometry_msgs/Twist Message

geometry_msgs/Vector3 linear
geometry_msgs/Vector3 angular

bashrcに書くやつ
source /opt/ros/humble/setup.bash
ビルド後に必要なやつ
. install/setup.bash

</details>
AWS RDS で MySQL5.7 と MariaDB10.6 でレプリケーションを組んだ話

AWS RDSにて、
MySQL5.7をマスター、MariaDB10.6をリードレプリカとしてレプリケーションを組んでみました。

## 目的
AWS RDSにおける、MySQL5.7からMariaDB10.6への無停止切り替えが可能か検証するため

## 概要
手法として、まず通常のMySQL5.7レプリケーションを構築し、
リードレプリカのレプリケーションを停止させマスターのポジションを確認しておき、
レプリケーションを停止させた状態のスナップショットを取得し、
それを元にRDSのスナップショットの移行機能でMariaDBを作成。
作成したMariaDBからマスターのMySQL5.7へレプリケーションを開始させる。
という流れです。

## 手順
1. MySQL5.7の標準的なレプリケーションを構築
1. リードレプリカにおけるレプリケーションを停止
1. マスターのポジション情報を確認
1. リードレプリカのスナップショットを取得
1. スナップショットの移行を実施（※ターゲットDBにてMariaDBを選択）
1. 新たに作成したMariaDBにて、レプリケーションを開始
1. レプリケーションの必要がなくなったリードレプリカを削除

## 詳細
### MySQL5.7の標準的なレプリケーションを構築
以下の手順でリードレプリカを作成する
AWSコンソール > RDS > 任意のMySQL5.7サーバのラジオボタンを選択 > アクション > リードレプリカの作成
### リードレプリカにおけるレプリケーションを停止
作成したリードレプリカにてレプリケーションを停止する

```
CALL mysql.rds_stop_replication;
```

### マスターのポジション情報を確認
リードレプリカからマスターの情報を参照し、確認しておく
```
mysql> show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State:
                  Master_Host: 172.X.X.X
                  Master_User: rdsrepladmin
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin-changelog.000032
          Read_Master_Log_Pos: 154
〜（略）〜
```

### リードレプリカのスナップショットを取得
AWSコンソール > RDS > 作成したリードレプリカのラジオボタンを選択 > アクション > スナップショットの取得

### スナップショットの移行を実施
AWSコンソール > RDS > 作成したリードレプリカのラジオボタンを選択 > アクション > スナップショットの移行 >
データベースエンジンの名前にてmariadbを選択

※その後は各環境に合わせた設定を行い、作成する
※リードレプリカのレプリケーションは、作業中終始停止したままの方が良いかと思われる（※max_binlog_sizeの設定によってはMaster_Log_Fileがローテートされていってしまい、後ほどレプリケーションの開始ができなくなるため）

### 新たに作成したMariaDBにて、レプリケーションを開始
```
CALL mysql.rds_set_external_master(
'<hostname>',
<port>,
'<username>',
'<password>',
'<Master_Log_Fileの値>',
<Read_Master_Log_Posの値>,
0
);

CALL mysql.rds_start_replication;

mysql> show slave status \G;
〜（略）〜
              Slave_IO_Running: Yes
             Slave_SQL_Running: Yes
```

Slave_IO_Running、Slave_SQL_RunningがYesであることを確認

### レプリケーションの必要がなくなったリードレプリカを削除
AWSコンソール > RDS > 作成したリードレプリカのラジオボタンを選択 > アクション > 削除

完了です

## 考察
AWS公認の手法ではないが、
この手法でMySQL5.7におけるMariaDB10.6のリードレプリカを作成できることがわかった。

この手法をうまく使えば、MySQL5.7からMariaDB10.6への無停止切り替えが可能となるかもしれない。
20分でまとめる備忘録　import PySimpleGUIでいきなりエラー

## 備忘録のきっかけ
PySimpleGUIをimportしようとしたらいきなり躓いたので

## 事象
pipでインストール後、
```
pip install pysimplegui
```
```
import PySimpleGUI as sg
```
と使おうとして失敗。

## 解決方法
Tkinterを入れたら直った。
```
brew install tcl-tk
```
PySimpleGUIはTkinterのラッパーらしく、sg内で使用する親コードがなかったためエラーが発生していた。
依存解決しないんだ、と一瞬思ったがnpcみたいなpackage.jsonがあるわけでもなく、直でimportするだけだから、そういうこともあるのかと納得はいった。ただ、パッケージの出自など気にしておかないと解決できないケースがありそう。

## まとめ
パッケージの依存が入り込む可能性は常にある。パッケージの出自を調べると解決するかも
javaScript

### どうも未経験４０代おっさんです。
お久しぶりです、４０代おっさん頑張っています( ´∀｀ )
早いものでもう学習を始めて２週間が過ぎようとしています。
### 今週習った事

さて今週学習したのは**javaScript**です。
今使っているこの**Qiita**にもこの**javaScript**が使われています。
**投稿する**ってボタンを押すと、「記事」と他のタグが出ると
思いますが。これも**javaScript**の機能です。

### javaScriptの特徴
・フロントエンドに働きかけるプログラムである。
・HTMLに**動的な**動きをつけれる。
大きく言うとこの２個ですね。（実際はもっと色々あるのでしょうが）
### 記入例
```
<script>
   //「変数とは？」何でもどんな形にもなる「箱」
        //「変数の宣言方法」変数を「宣言」又は「作る」には　「let 好きな変数名」
        //「リストの書き方」リストの書き方は　「let 変数名(又はリスト名とも呼ぶ)=[(大かっこ)要素]
        //例　　let a = ['リンゴ','ミカン','モモ']
        //「ループ文の書き方」　
        /*リスト名.forEach((好きな変数名（iが使われることが多い？？）) => {
             ここに処理（今回は「ブラウザーのコンソールに出力せよ」と書いてあります。
             console.log(i)
         })
         */
</script>
```
だいぶ雑ですがま～こんな感じです。（基礎文法は）
さて実際にこの**javaScript**「だけ」で書こうとすると
コードも長くなるし、凄く見づらくなります。
モコモコ:「こんなに複雑に書けないよ～スパルタモン💦」
スパルタモン:「大丈夫、そんな時は**コレ**」
そんなスパルタモンが提案したのがコチラ。
### JQuery
簡潔に言うと短いコードで**javaScript**を使えるように
したもの？？です。ついでに今から貼るコードに
**fetch**って言葉が出で来るので先に説明します
### fetch
簡単に言うと「特定のサイト」から「データ」を
「抽出」するものって認識を持っていると
この後の記載例が分かり易いかと。
### 記載例
```
 <script>
        //ここでID「q1」が命名されたタグがおされたらを定義
        function q1() {
            //ここで元となるデータの参照URLを貼り付けて、それを「JSON」という形に加工して
            fetch("http://spartacodingclub.shop/en/global_air/osaka").then(res => res.json()).then(data => {
                //ここで変数「forecasts」に「２次元配列」を渡し。
                let forecasts = data['data']['forecast']
                //ここでID「names-q1」の中の<li>タグを全て消して
                $('#names-q1').empty()
                //ここで変数「i」に「１次元配列の辞書(ディクショナリー)」を渡す(ループ文で)
                forecasts.forEach((i) => {
                    //ここでディクショナリー(又は辞書型)の「day」の中身を取り出す
                    let days = i['day']
                    //ここでディクショナリー(又は辞書型)の「avg」の中身を取り出す
                    let avgs = i['avg']


                    //ここのループ文で新たにＩＤ「names-q1」の<li>タグに変数名「days」と「avgs」の要素の中身を出力させている。
                    let temp_html = ``
                    if (avgs > 60) {
                        temp_html = `<li class="bak"> ${days} : ${avgs}</li>`
                    } else {
                        temp_html = `<li> ${days} : ${avgs}</li>`
                    }
                    $('#names-q1').append(temp_html)

                })

            })
        }
    </script>
```
ここに出てきた「**$**]の記載がある部分が「**,jquery**」です
もちろんこの機能を使うには「パス」を書く必要があります。
そのコードが**コチラ**
```
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
```
さてそんな今週の学習して作った課題が**コレ↓**
(前回との違いが分かりにくいですが**サイトをリロードすると気温の部分の
温度が変わります**)
https://github.com/mokomokosparta/mypage.git
EFSのマウントターゲットは1つのAZにつき1つしか作れない

## 背景

CloudFormationでEFSのマウントターゲットを作成しようとしたら、以下のようなエラーが発生しました。

``` 
fsmt-xxxxxxxxxxxxxxxx already exists in stack 
```
fsmtはおそらくマウントターゲットのことであろう。
マウントターゲットが既に存在している？？
どういうことだろうか。


## 1AZ, 1Target
今回作ろうとしていたもののアーキテクチャは以下のようなものである。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/db40384c-4ab6-17d3-8a2b-c89d3affbf44.png)

１つのAZに2つのプライベートサブネットが存在し、それぞれにapp1とapp2が存在する。
そして、それぞれのサブネットにマウントターゲットを設置している。

公式サイトを見てみると、以下のような記述があった。
>Amazon EFS ファイルシステムを作成した後、マウントターゲットを作成できます。標準ストレージクラスを使用する Amazon EFS ファイルシステムの場合は、AWS リージョン の各アベイラビリティーゾーンにマウントターゲットを作成することができます。

https://docs.aws.amazon.com/ja_jp/efs/latest/ug/accessing-fs.html

これだけだとAZに1つしか作れないのか、複数作れるのかわからない。
英語版を見てみる。

>  For Amazon EFS file systems that use Standard storage classes, **you can create a mount target in each Availability Zone** in an AWS Region. 

https://docs.aws.amazon.com/efs/latest/ug/accessing-fs.html

[a mount target in each Availability Zone] とあるが、これは1AZにつき1つを表しているのだろうか。
複数作れるのなら[mount targets]になりそうだが、ちょっと微妙なところ...

ただ、実際に1AZにつき1つのマウントターゲットというアーキテクチャ、つまり以下のような構成にCloudFormation用のyamlファイルを修正したところ、エラーは解決した。つまり、1AZにつき、つくれるマウントターゲットは1つなのであろう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/e0c7e778-2134-5928-86e4-8a41913e20de.png)


## EFSはフェイルオーバーしない
今回は1AZでの話であった。
これとは別に、本記事の調査を進めていくうえでフェイルオーバーの話が出てきていたので軽くメモ。

マウントターゲットには、AZを跨ぐフェイルオーバー機能が実装されていないらしい。
そのため、フェイルオーバーを実現したい場合は、OSレイヤー以上で障害を検知してフェイルオーバーを実現する仕組みが必要とのこと。詳しくは以下のブログを参照のこと。
https://dev.classmethod.jp/articles/efs-failover/


## 感想・まとめ
日本語サイトだけでは正確な理解ができないということを身をもって知りました。厳密な一次資料は英語版ということは覚えておきたいですね。（ちなみに、EKSのような更新が頻繁に起きているサービスは、翻訳の精度という以前にそもそも中身が違っていることもあります。）

あと、drow.ioは便利すぎる。まだちょっと使い慣れていないところもあるが、それでもかなり図が書きやすい。
議論の際は、特にアーキテクチャの議論の際は図を用いて議論することが大事という話は多くの先輩から聞くし、実際にそうだと思う。息をするように図が描けるようになりたい。
ViteでVue SPA作るといつも忘れること

この記事は[自分のブログ記事](https://mkw-blog.herokuapp.com/article/4hWnLMtwNHyTsnnlNbxKDB)からの再掲です

最近新しいWebAppを作るときにVite + Vue3で作成することが多いです。その際に
```zsh
npm create vite@latest 
```
で設定することが多いです。設定するなかでページ遷移が必要だと判断した場合は`vue-router`を使用します。

`vue-router`でルーティングする構造を考えるときにいくつかの候補がありますがその中でポピュラーなのはHashモードとHistoryモードの二つです。

HashモードはURLに`#`が入りますがサーバーへの通信を遷移に行わないですし設定が楽です。

それに対してHistoryモードはサーバーへの通信が必要になりますが`#`が入らないのでモニタリングやアナリティクスツールでページごとのデータを取りたかったりした場合にはこちらが最適です。

Vue-Routerを入れたいケースというのがそもそもページ遷移が必要だったり直リンクによるページの再訪したかったりなので、どうしてもリダイレクトのコールバックURLからしか受け取れない値があるが基本的にはページ遷移を必要としない場合以外基本的にHistoryモードを使用することになるケースがほとんどだと思います。

現在自分が管理しているブログでもそうだったんですが、viteを開発のために走らせている状態ではhistoryモードを使っていると開発エンドポイントのベースURL`"/"`以外への直接のアクセスでも遷移できるのでいつも忘れたままディプロイしてしまうことがあります。

しかしcreate viteで作成するとserveを使ってビルドファイルを提供することになっているもののこれはベースURLに対してのみindex.htmlを返すので、詳細なパスへの直リンクでは404になってしまいます。そこで後から全部のパスにたいしてindex.htmlを返す処理が必要になってサーバーサイドを簡素なexpress appで処理することになります。

つまづいでいる初学者のかたもいるかもなので参考に、最低限のレベルはこんな感じで実装できます

[https://github.com/kenjiwilkins/kw-blog-client/index.ts](https://github.com/kenjiwilkins/kw-blog-client/blob/63f07634fe424babcb652bdd45d2ca08b81da8ee/index.ts)


```typescript
import * as express from "express";
import rateLimit from "express-rate-limit";
import * as logger from "morgan";

const app = express();
app.use(express.static(__dirname + "/dist"));
app.use(
  rateLimit({
    windowMs: 10000, // 1 minute
    max: 5, // limit each IP to 5 requests per windowMs
    message: "Too many requests, please try again later.",
  })
);
app.use(logger("common"));

app.get("/", (req, res) => {
  res.sendFile(__dirname + "/index.html");
});

// return index.html to all routes
app.get("*", (req, res) => {
  res.sendFile(__dirname + "/dist/index.html");
});

app.listen(process.env.PORT || 443, () => {
  console.log(`Server started on port ${process.env.PORT || 443}`);
});

```

やっていることとしてはどのパスへのアクセスであってもindex.htmlを返してねという処理です。

僕はフロントエンドエンジニアとして働いているのもあって、バックエンド触るときというのはたとえばE2E行うためにモックAPI書いたりするぐらいなのでバックエンドエンジニアたちがよしなにやってくれることを忘れてしまっていて趣味のアプリで抜け落ちちゃうんですよね。頭が上がりませんね。

どなたかnpm serve の設定につかうserve.json﻿﻿ファイルだけでこの設定できる方法ご存知ですかね？ redirectオプションを使うと無限にリダイレクトしてtoo many redirectエラー返されてしまいますし。
ABC305回答メモ

0.はじめに
　問題的にはどれもちょうどよい歯ごたえで
　Dまでギリギリ解け、心地よい達成感が得られました。
　レートアップを期待しましたが、+5と微増にとどまりました。

1.A - Water Station
　いろんなやり方ありそうだなと思いつつ
　以下の実装。
　Nに0～4を加算していき、5で割り切れるまでの回数(距離)と
　Nから1～4を減算していき、5で割り切れるまでの回数(距離)を
　比較して小さい方の距離の値を回答として出力。

　https://atcoder.jp/contests/abc305/submissions/42129905

2.B - ABCDEFG
　A~Gの各距離をリストにしてーと考え始めましたが
　どうせ何かをリスト登録しないといけないならと
　A~Gのスタートからの距離を辞書登録して
　絶対値を求めるというすっきりした実装にしました。
```
dict={"A":0,"B":3,"C":4,"D":8,"E":9,"F":14,"G":23}
p,q=input().split()
print(abs(dict[p]-dict[q]))
```

　https://atcoder.jp/contests/abc305/submissions/42134737

3.C - Snuke the Cookie Picker
　最初質問の意味がピンときませんでしたが
　入力例を見て分かりました。

　要は"."の上下左右の４方のうち、2方向が"#"であれば
　食べた跡だなと気づき、そのように実装しました。

　https://atcoder.jp/contests/abc305/submissions/42139441

4.D - Sleep Log
　1時間以上かけてやっとクリアできました。
　初めは、０～リストの最後の数までそれまでの睡眠時間を
　保存して～と、試してみましたがさすがに10の9乗は
　TLEだしメモリオーバーでした。

　うすうす2分探索しないといけないんだろうなと思い
　その線で再挑戦。

　まずは、リストAと、値Bを渡すと
　値Bがリストにある場合はそのアドレスをint型で
　ない場合は、値B前後のアドレスをtuple型で
　返す関数find_rangeを作成。

　次にリストAを元に、記録開始時刻から、リストの各値毎までの
　総睡眠時間を持つリストspを作成

　あとは、Q毎に、
　R時点までの開始からの総睡眠時間※から
　L時点までの開始からの総睡眠時間※を引いて出力
　で実装しました。

　※R(L)時点までの開始からの総睡眠時間の求め方
　　find_rangeに、リストAとR(L)を渡す。
　　・戻り値が、int型resultの時
　　　sp[result]が総睡眠時間
　　・戻り値が、tuple型start,endの時
　　　・startが偶数の時・・L(R)時点では起きている
　　　　起床後の状態＝総睡眠時間はstart時点から
　　　　増えないのでsp[start]が総睡眠時間
　　　・startが奇数の時・・L(R)時点では寝ている
　　　　・Lの時
　　　　　sp[start]に、sp[start]～Lまでの睡眠時間を足した値
　　　　　が総睡眠時間
　　　　・Rの時
　　　　　sp[end]から、R～sp[end]までの睡眠時間を引いた値
　　　　　が総睡眠時間

　書いててもややこしいので時間がかかり、ギリギリで
　ACとなりました。
　
　https://atcoder.jp/contests/abc305/submissions/42163267

以上
Docker イメージのレポジトリとタグ

- レポジトリ = ubuntu とか
- タグ = latest とか
- イメージ名 = レジストリ + タグ = ubuntu:latest とか

同一のイメージを複数のイメージ名が参照することもある。[ref](https://taker.hatenablog.com/entry/2016/05/04/175021)
20分でまとめる備忘録　PySimpleGUIのメインループ

## 備忘録のきっかけ
Pythonで手早くコンソールを実装しようとしていたら、PySimpleGUIに行き着いた。大まかに使用方法をまとめておきたい

## mainとなるwhileループ
```python
import PySimpleGUI as sg

# ウィンドウのレイアウトを定義
layout = [
    [sg.Text('Hello')],
    [sg.Button('OK'), sg.Button('Cancel')]
]

# ウィンドウを作成
window = sg.Window('My Window', layout)

# メインループ
while True:
    event, values = window.read()
    
    # イベントの処理
    if event == sg.WINDOW_CLOSED or event == 'Cancel':
        break
    if event == 'OK':
        sg.popup('OKボタンがクリックされました！')
        
# ウィンドウを閉じる
window.close()
```
1. UIに表示したいものをlayoutに定義して、windowを作成する。
    1. layoutは一番外側がレコード、その中がカラムになる構造になっていて、layoutにlayoutを入れることで複雑なレイアウトを作ることもできる（ただし、配置などをうまく整えるのは結構厳しそう）
1. whileループ内で、layout内で定義したイベント（sg.Button('OK')ならOKがイベントになる）を待ち受ける。ボタンならボタンのクリックで発火するのでなく、常にイベントループ内で監視して処理を決める形を取る。
    1. 処理が複雑になったり入れ子になればなるほど厳しいそう... そもそもきちんと設計を考えて、ネストが深くならないように設計するのが重要そうに見えた

## まとめ
input欄ひとつ、ボタン二つくらいの規模だと最速でGUIを組めそう。その代わりリスト内にサムネイルを表示させつつ、選択できるようにして隣のサムネイル欄に何か表示する、みたいなことを考え始めるとこのwhileループないがどうなるんだろうという気がする。割り切って使うのが吉
【python】argparseで引数を保持しているもの

# はじめに

python でargparse で引数の定義を行い、コマンドラインから引数の値を入力するのに使っていました。
同じものをプログラム内部で直接代入して使いたいと思い、方法を調べました。

# 方法

### (A) parse_args() に引数を直接入れる

これが正解だと思います。

以下のようなParser が作られていて、shellから引数を指定します。

```python:test01.py
import argparse
parser = argparse.ArgumentParser(
                    prog='ProgramName',
                    description='What the program does',
                    epilog='Text at the bottom of help')
parser.add_argument('filename')
parser.add_argument('-c', '--count', type=int)
parser.add_argument('-v', '--verbose', action='store_true')

args1 = parser.parse_args()
print('args1=', args1)
```

実行すると下記のようになります。

```
$ python3 test01.py -c 100 -v aaa
args1= Namespace(count=100, filename='aaa', verbose=True)
```

これを以下のようにしても同じです。

```python:test02.py
from test01 import parser

args2 = parser.parse_args("-c 100 -v aaa".split())
print('args2=', args2)
```

```
$ python3 test02.py
args2= Namespace(count=100, filename='aaa', verbose=True)
```

### (B) 直接namespace やclass instance を作る

最初、こちらで行っていました。ご苦労なことですが、同じものを作ろうという作戦です。

```python:test03.py
from types import SimpleNamespace
args3 = SimpleNamespace(count=100, filename="aaa", verbose=True)

print('args3=', args3)
```

実行すると以下のように。namespace の n　が小文字になっていました。

```
$ python3 test03.py
args3= namespace(count=100, filename='aaa', verbose=True)
```

これでも args3.filename のように参照できるので、args を渡した関数でプログラムは正常に動作します。

そもそも直接参照できるようにだけすなら、クラスを使ってもできます。

```python:test04.py
class Cls():
    pass

args = Cls()
args.count=100
args.filename="aaa"
args.verbose=True
print('args.count=',args.count)
print('args.filename=',args.filename)
print('args.verbose=',args.verbose)
```

この場合namespace ではないですが、同じように参照できます。

```
$ python3 test04.py
args.count= 100
args.filename= aaa
args.verbose= True
```

https://stackoverflow.com/questions/37161275/what-is-the-difference-between-simplenamespace-and-empty-class-definition



実際には、引数の設定はたくさんあり、default 値を設定している場合もあります。それを呼び出す側で全て書くのはバグの元なので(B)はよろしくない。と後で思いました。


# まとめ

普段はシェルから引数で渡しているものをプログラム内で指定する方法として、arg_parse()するときに引数の文字列をそのまま入れればよいということで解決できました。おまけとして、parse_args で作られるnamespace なるものと似たものをtypes.SimpleNamespace で作る方法も確認できました。

来週も生き延びることができるかな。。。

(2023/06/10)
CH32V003をArduinoで使おう（CH32V203・CH32X035も）

__CH32V003__ が __Arduino__ で使えるようになりました。

https://github.com/openwch/arduino_core_ch32/tree/main

それでは、ArduinoIDEで使えるようにしましょう。
# ArduinoIDEに設定する
__ファイル→環境設定__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/7beeb541-713a-1ca3-4fc6-9d40a9df1cf4.png)
__追加のボードマネージャ__ の __URL__ に以下を入力して、OKをクリックします。

    https://github.com/openwch/board_manager_files/raw/main/package_ch32v_index.json

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/d8bf26ff-edff-b2f0-c73a-bb1fff74df47.png)
__ツール⇒ボード⇒ボードマネージャ__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/a49a73e6-1e5a-d251-9a54-9b1a4e33f736.png)
タイプの横の検索に __ch32__ と入力し __CH32 MCU EVT Boards__ を __インストール__ します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/db858163-0d72-79ee-f111-71f7812627eb.png)
__ツール⇒ボード⇒CH32 MCU EVT Boards Support ⇒CH32V00x__ を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/e04e61f4-dfa9-ad1b-a2b8-fb14df0318e1.png)
# WCH-Linkを使えるようにする
__WCH-Link__ の __ドライバ__ が入っていない場合は __WCH-LinkUtility__ をインストールしてドライバを入れましょう。
__ダウンロード__ を __クリック__ して、__WCH-LinkUtility__ を __ダウンロード__ します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/a0354b3c-0010-9426-968d-72a9b39e24ea.png)

https://www.wch.cn/downloads/WCH-LinkUtility_ZIP.html

__WCH-LinkUtility⇒詳細情報__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/d2efae30-e54e-8bd5-6afc-143814dd04b9.png)
実行をクリックして、ドライバ類をインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/487c980e-b095-d1a2-7289-74f1d43d74f5.png)
# 書き込み
以上でコンパイル、書き込みができます。
![スクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/40997da0-cb7b-4bbe-1fb6-c1a7c20b198b.png)
書き込み後はリセットをします。
バージョンの変化やボードによりリセットを押さないでも起動するようになるかもしれません。
# CH32V003のピンアサイン
今回のピンアサインの概要は以下のようです。

https://github.com/openwch/arduino_core_ch32/blob/main/variants/CH32V00x/CH32V003F4/PeripheralPins.c
- I2C
- SDA:PC1
- SDL:PC2
- UART 
- TX:PD5
- RX:PD6
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/1d4d2438-30be-b541-5ae3-75b5581c6282.png)
引用：CH32V003DS0.PDF
情報数学

データサイエンスや計算機科学に用いられる情報数学について投稿します。

## 離散数学
計算機科学では以下の形式で数値を扱っている。
```math
\sum_{k\in Z} na^{k}
```
n: 該当桁の数（非負かつ *a* 未満の整数）。小数点以下のこれを指す場合（つまり *k* が負の場合）は仮数 significand, mantissa, coefficient と呼ばれる。
a: adic number. n進数を表す2以上の整数。
**Z**: 整数の集合

これが2進数の場合（つまり *a = 2* の場合）を計算機は扱っている。
## 数式の記述方法
計算機科学ではなじみのある記法とは異なったものが用いられている。
### 逆ポーランド記法 Reverse Polish Notation, RPN
それが逆ポーランド記法（RPN）であり、被演算子（operand）、被演算子、演算子（operator）を順序とする記法である。
### 参考： 前置記法、中置記法、後置記法
前置記法 ... x12
中置記法 ... 1x2 ... なじみのある記法
後置記法 ... 12x ... RPN

x: 積の演算子

出典： [e-words 逆ポーランド記法](https://e-words.jp/w/%E9%80%86%E3%83%9D%E3%83%BC%E3%83%A9%E3%83%B3%E3%83%89%E8%A8%98%E6%B3%95.html)
【SpringBoot】 SpringSecurityでh2コンソール画面を表示させる

# はじめに
SpringBootの学習中にh2コンソールを使用してデータベースの扱いをしようとしたところ、コンソール画面がSpringSecurityによって閲覧できない状態のため、やり方を調べました。

今回はその証跡として、投稿します。


## ■詳細
SecurityFilterChainを使用し、("/","/home","h2-console")以外のページについては認証を求めるよう記述したが、[http://localhost:8080/h2-console]にアクセスしたところ、認証を求められた。



```
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authorize) -> authorize
                        .requestMatchers("/", "/home","/h2-console").permitAll()
                        .anyRequest().authenticated())
                .formLogin((form) -> form
                        .loginPage("/login")
                        .permitAll())
                .logout((logout) -> logout.permitAll());
        return http.build();
    }
```


### ■解決のために使用したサイト

SpringBoot公式ドキュメント
https://spring.pleiades.io/


参考ページ（1.5.2. 安全なアプリケーションでの H2 コンソールへのアクセス）
https://spring.pleiades.io/spring-boot/docs/current/reference/html/data.html#data.sql.h2-web-console

#### ■なぜできなかったのか　公式ドキュメントより抜粋

H2Consoleはフレームを使用し、開発のみを目的としているため、CSRF保護対策を実装していません。
アプリケーションでSpring Securityを使用する場合は、次のように構成する必要があります。
①コンソールに対するリクエストの CSRF 保護を無効にします。
②コンソールからのレスポンスでヘッダー「X-Frame-Options」を「SAMEORIGIN」に設定します。


公式ドキュメントになぞり下記のようにコードを修正。



```
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .securityMatcher("/h2-console/")
                .csrf((csrf) -> csrf.disable())
                .headers((headers) -> headers.frameOptions((frame) -> frame.sameOrigin()))
                .authorizeHttpRequests((authorize) -> authorize
                        .requestMatchers("/", "/home").permitAll()
                        .anyRequest().authenticated())
                .formLogin((form) -> form
                        .loginPage("/login")
                        .permitAll())
                .logout((logout) -> logout.permitAll());
        return http.build();
    }
```
月末日および銀行最終営業日のリストを求める

借入金のスケジュール表を作るついでに、久々に書いてみました。
コード中の`test`は本当にただのテストなので、コメントアウトしてます。

## 出来上がりイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/9c17e71f-f88e-096b-9881-4ef892c93ce6.png)


## コード

```
let
    startDate = #date(2023,6,30),
    endDate = #date(2026,6,30),
    // 除外したい日のリスト。手打ちの必要はない。
    holidayLst = List.Transform({2023,2024,2025}, each #date(_,12,31)),
    
    //日付を受け取って、直前の平日を返す関数。再帰的に実行する。
    getLastWeekday = (d as date)as date=>
        if List.Contains(holidayLst, d) then @getLastWeekday(d - #duration(1,0,0,0))
        //0を月曜として、曜日が0~6で返る。
        else if Date.DayOfWeek(d, Day.Monday) > 4 then @getLastWeekday(d - #duration(Date.DayOfWeek(d, Day.Monday)-4,0,0,0))
        else d,
 
    // test = let x = {#date(2023,6,10),#date(2023,6,11),#date(2023,6,12)} in List.Transform(x, getLastWeekday),

    // 日付を受け取って、その翌月の返済日を返す。ただし、引数が月末日でない場合はその日付の月の月末日を返す。
    fx = (d as date) as date=>
        let
            endOfThisMonth = Date.EndOfMonth(d),
            // Date.AddMonthsは必要ない。
            nextEndOfMonth = Date.EndOfMonth(endOfThisMonth + #duration(1,0,0,0))
        in
            if d = endOfThisMonth then getLastWeekday( nextEndOfMonth )
            else endOfThisMonth,
    // test3 = let x = {#date(2023,9,30),#date(2023,10,11),#date(2023,11,30)} in List.Transform(x, fx),
    lst = List.Generate(()=>startDate, each _ <= endDate, fx),
    result = Table.FromColumns({lst}),
    #"Added Custom" = Table.AddColumn(result, "検証用曜日", each Date.ToText([Column1],"ddd"), type text)
in
    #"Added Custom"
```


## バージョン情報
Microsoft365のExcel（バージョン2305）
Power Query：2.117.362.0（64 ビット）
【SwiftUI】iOS17の新APIを使用してScrollViewを操る

# はじめに
iOS17から`scrollTransition`というモディファイアが追加されたので使ってみました！

# サンプルアプリ
画面外になるタイミングで少し小さくなるような動きです
![Simulator Screen Recording - iPhone 14 Pro - 2023-06-10 at 22.31.16.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/c1915a38-0f84-05c9-a0c2-d358b2585976.gif)

# 実装
```diff_swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        ScrollView(.vertical) {
            VStack(spacing: 10) {
                ForEach(0..<50, id: \.self) { index in
                    Text("Cell: \(index)")
                        .frame(maxWidth: .infinity)
                        .frame(height: 200)
                        .cornerRadius(20)
                        .foregroundColor(.white)
                        .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 10))
                        .overlay(.white.opacity(0.5), in: RoundedRectangle(cornerRadius: 10).stroke(style: .init()))
                        .padding(.horizontal, 20)
+                       .scrollTransition { emptyVisualEffect, scrollTransitionPhase in
+                           emptyVisualEffect.scaleEffect(scrollTransitionPhase.isIdentity ? 1 : 0.8)
+                       }
                }
            }
        }
        .background(LinearGradient(gradient: Gradient(colors: [.pink, .yellow, .orange]), startPoint: .topLeading, endPoint: .bottomTrailing))
    }
}
```

# ドキュメント
https://developer.apple.com/documentation/SwiftUI/View/scrollTransition(_:axis:transition:)

# おわり
これはめっちゃ便利なAPIです！
いろんなことができそうです！

![スクリーンショット 2023-06-06 17.23.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/db95fd18-31ae-6410-6ae7-029a5673996c.png)
「Appleが一般に開示した情報」に該当してると思うので大丈夫だとは思いますが、
もしアウトだったらコメントで教えて欲しいです。
Confluenceで書式なしペースト（Ctrl+Shift+V）を有効にする

# TL;DR

はてなマーク < キーボードショートカット < General < Enable General Shortcuts
のチェックマークを外すとできる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316390/611d5e74-8769-7666-ccfb-f837c24fd858.png)

# Motivation

Confluenceで書式なしペースト（プレーンテキストで貼り付け）のショートカット（Ctrl+Shift+V）が効かずにわざわざメモ帳かアドレスバーで書式を捨ててペーストしていた。
これ面倒くさい...

# Procedure
TL;DR参照


# 最後に

Confluence独自？のショートカット、「表の上部にペースト」とコンフリクトしていたらしい。。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316390/2ca38271-e7c3-f9ef-f4f6-59ef4d045d74.png)
こんなの使わないので速攻チェックマークを外しました。
Ruby の Net::HTTP でリクエストする

# Ruby 3.0未満

```ruby
uri = "https://registry.hub.docker.com/v2/library/ubuntu/tags/list"
response = Net::HTTP.get_response(URI.parse(auth_url))

# header指定
# (Net::HTTP.get_responseの第二引数はpathと解釈されるので使えない)
token = "xxxxxx"
response = Net::HTTP.start(url.hostname, url.port, use_ssl: true) do |http|
  req = Net::HTTP::Get.new url
  req['Authorization'] = "Bearer XXXX"
  http.request req
end
```

`use_ssl: true`を書き忘れるとブロックする。[ref](https://stackoverflow.com/questions/44230462/ruby-http-request-blocking)

# Ruby 3.0以降

```ruby
uri = "https://registry.hub.docker.com/v2/library/ubuntu/tags/list"
response = Net::HTTP.get_response(URI.parse(uri))

# header指定が第二引数でできるようになった
token = "xxxxxx"
response = Net::HTTP.get_response(URI.parse(uri), {"Authorization" => "Bearer XXX"})
```

楽に書けるようになった。
GitHub Actions内でPytestを実行して失敗したテストの詳細をPR内で直接表示させよう！

## 概要
GitHub Actionsを使ってテストを実行する際に失敗したテストはログを見るかと思います
テストが少なければいいですがプロジェクトが大きくなるにつれてどんどん探すのが困難になってくるので
PR内で書いたテストコードに失敗したテストの実行内容が表示されたら便利かと思います
今回はとあるライブラリを使って実現する方法について解説していきます

## 前提
- フレームワークはDjangoを使用
- テストフレームワークはPytestを使用

## pytest-github-actions-annotate-failures
`pytest-github-actions-annotate-failures`を使うと

https://github.com/pytest-dev/pytest-github-actions-annotate-failures

```
pip install pytest-github-actions-annotate-failures
```

## 実際に実行してみよう！
試しにテストを書いてみます
今回はヘルスチェックのテストを例に出します
本来は200を返すべきなのにテストコード内で400を返すテストコードを書きます

```python
from rest_framework import status


def test_health_check_returns_200(client):
    """ヘルスチェックで200を返すことをテスト"""
    url = "/api/health/"
    response = client.get(url, format="json")
    assert response.status_code == status.HTTP_400_BAD_REQUEST
    assert response.json() == {"msg": "pass"}
```

GitHub Actionsを実行すると失敗したログが出ます
![スクリーンショット 2023-06-10 21.45.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625980/08d4b96d-14c2-edd5-0cb5-6c2e10bf4578.png)

GitHub Actionsが実行された後に以下のようにPR内に失敗した時の詳細が記載され、長いログを見ずに済みます
![スクリーンショット 2023-06-10 21.42.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625980/9c83976f-a98e-3921-1fd7-da71824063fc.png)

## 変更していないテストコードが失敗したらどうなるの？
例えばAPIのurlを変更したのに伴いテストコードを修正するのを忘れることはあるかと思います
変更していないテストコードが失敗しても下記のようにPR内で表示されるのでとても便利です
例えば先ほどのヘルスチェックのテストコードを修正せずにパスを変えます
テストコード内のパスも一緒に変えていないと当然失敗します
```python
urlpatterns = [
    path(r"", include(router.urls)),
    path(r"health/", health_check, name="health_check"),
    path(r"health_check/", health_check, name="health_check"),
]
```

GitHub Actionsを実行すると下記のように変更してないテストコードに対しても失敗していたらPR内で詳細に記載されます
便利ですね！
![スクリーンショット 2023-06-10 21.54.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625980/dc55906d-f260-3d00-25ff-8fe72c1d4223.png)

以上です

## 参考
https://github.com/pytest-dev/pytest-github-actions-annotate-failures
今 Rails 6.1 で rails new をすると発生するエラーとその対処法

[Rails 6.1 のチュートリアル](https://guides.rubyonrails.org/v6.1/getting_started.html)通りに実装していたらエラーに遭遇した。他のバージョンのRailsで発生するかは未検証。

# エラーの概要

`rails new`でプロジェクトを作成し、Controllerを作ってアクセスするとエラーになる。

例えば、以下のコマンドを実行した後で http://localhost:3000/home/index にアクセスするとエラーになる。

```sh
rails new blog
cd blog
bin/rails g controller home index
bin/rails s
```

エラーの内容は以下の通り。

```txt
Webpacker::Manifest::MissingEntryError in Home#index

Showing ***/app/views/layouts/application.html.erb where line #10 raised:

Webpacker can't find application.js in ***/public/packs/manifest.json. Possible causes:
1. You want to set webpacker.yml value of compile to true for your environment
   unless you are using the `webpack -w` or the webpack-dev-server.
2. webpack has not yet re-run to reflect updates.
3. You have misconfigured Webpacker's config/webpacker.yml file.
4. Your webpack configuration is not creating a manifest.
Your manifest contains:
{
}
```

# 暫定的な対処法

```sh
yarn add -D @babel/plugin-proposal-private-methods @babel/plugin-proposal-private-property-in-object
bin/rails webpacker:install
bin/rails webpacker:compile
```

# エラーの原因
[(参考)](https://github.com/babel/babel/issues/15679)

[Babelのコントリビュータ](https://github.com/nicolo-ribaudo)によれば、`rails new`コマンドで生成されるプロジェクトのBabel関連の設定に問題があるらしい。
Babel のプラグインのうち、"@babel/plugin-proposal-"で始まるものは明示的に npm install しなければならないが、Rails 6.1 のデフォルトプロジェクトではインストールされていない。
これまではインストールされている他パッケージが依存していたために動いていたが、アップデートにより依存しなくなったことで、エラーが発生するようになったと考えられる。

# 参考
- https://github.com/babel/babel/issues/15679
- https://devcenter.heroku.com/articles/getting-started-with-rails6
【Markdown記法】Qiitaでコードの差異＆シンタックスハイライト＆名前を同時に表示

## コードの差異＆シンタックスハイライト＆名前を同時に表示

下のような書き方がどうやったらできるかを解説します。

```diff_php:example.php
<?php
- print("before");
+ print("after");
```

## 結論
以下のように書きます。  


>\```diff_php:example.php
\<?php
\- print("before");
\+ print("after");
\```

diff_(言語名):名前 という形式で書くことで、  
* コードの差異
* シンタックスハイライト
* 名前  

を同時にできます。
Qiitaで記事を書く際に参考になれば幸いです。
Flluterでネットからデータを取得できない

Flutterプロジェクトで、ネットにある画像を取得するコードを書き、macOSで実行しようとしたら次のエラーが出ました。
`[ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: SocketException: Connection failed (OS Error: Operation not permitted, errno = 1), address = jsonplaceholder.typicode.com, port = 443`
エラー内容を調べてみるとstack overflowに英語で解決方法が書かれていましたので、こちらにメモします。ファイル内容を変更する必要があり、`プロジェクト名/macos/Runner/DebugProfile.entitlements`と`プロジェクト名/macos/Runner/Release.entitlements`の2つです。そちらに次のコードを足します。
```
<key>com.apple.security.network.client</key>
<true/>
```
記述しましたら、アプリを再起動して、実行します。
うまく画像取得できました◎。

#### 参考

https://stackoverflow.com/questions/65458903/socketexception-connection-failed-os-error-operation-not-permitted-errno-1
ユーザー認証について考えてみる

Railsを学んでいるみなさんこんにちは！！！
先日から[Railsチュートリアル(第７版)](https://railstutorial.jp/)でRuby on Railsを勉強しています。これまではログイン機能をユーザー側として利用してきましたが、作る側になった途端わからない用語がたくさん出てきました。そこで今回はログイン機能における**ユーザ認証**がどのような順番で行われているのかについて考えてみたいと思います。今回はRailsチュートリアルで学んだことのアウトプットになってしまうかもしれませんが、私のように、「ダイジェスト」「暗号化」などの用語が出てきたときに、「ワード自体がわからん！」「それぞれのワードを関連付けて考えられん！」となってしまう方向けの記事になります。

## 1. ユーザー認証とは

一言でまとめると**ある特定のシステムにログインするためのプロセス**です。システムにアクセスする権限を持つユーザとそうでないユーザを見分けるための仕組み、それがユーザー認証です。

## 2. 用語の整理
### 2-1. 暗号化とは

暗号化はデータを保護するためのプロセスで、一定のルールに基づいて暗号化キーを使用して平文のデータを暗号テキストに変換します。これは読み取り困難な形になります。このプロセスにより、ユーザの重要な情報が不正アクセス者から守られます。また、ネットワーク経由でデータを安全に送受信することができます。暗号化されたデータは適切な鍵があれば元の形に復号化（データを元に戻すこと）することができます。

### 2-2. ダイジェストとは

ダイジェストは一方向の関数で、元のデータから一意の固定長の値を生成します。ダイジェストの生成プロセスは「元のデータから固定長の値を生成する」ことですが、生成されたダイジェストから元のデータを復元することは非常に困難になるため、セキュリティを強化するのに非常に有効です。また、ダイジェストはハッシュとも言われますが、そのハッシュ化に使われる関数にはSHAやMD5等があります。

### 2-3. Cookiesとは

WebブラウザとWebサーバー間で情報をやり取りする際に使われる、小さなテキストファイルのことをいいます。これは、Webサイトがユーザーのブラウザを通じてユーザーのコンピュータに保存するもので、Webサイトがユーザーを認識し、その状態を保持するために使用されます。
ただし、Cookieはユーザーのプライバシーに関わる情報を含む可能性もあるため、扱いには注意が必要です。今回の場合は、ユーザーに直接関わる情報は暗号化してからCookieに保存することにします。

### 2-4. トークンとは

ユーザーがシステムにログインしたとき、そのユーザーを一意に識別するための一時的な「証明書」のようなものと考えることができます。このトークンは、一時的に生成され、ユーザーがログアウトするか、一定時間が経過すると無効化されます。ランダムな英数字でできた文字列のようなものだと考えるとわかりやすいかもしれません。

## 3. どういう順番でユーザー認証を行うのか？

Cookiesをブラウザに保存するフェーズとCookiesを使って認証するフェーズに分けて考えてみることにします。

### 3-1.　Cookiesをブラウザに保存するフェーズ

1. ユーザーがログインフォームにメールアドレスとパスワードを入力してログインを試みます。
2. アプリケーションは、メールアドレスに基づいてデータベースからユーザーを見つけ、入力されたパスワードをハッシュ関数に通してダイジェストを生成します。
3. 生成したダイジェストとデータベースに保存されているダイジェストが一致すれば、アプリケーションはユーザーのログインを認めます。そして、ユーザーを識別するための一時的なトークンを生成します。
4. そのトークンをハッシュ関数に通してダイジェストを生成し、そのダイジェストをデータベースに保存します。
5. 生成したトークンはユーザーのブラウザのCookiesにも保存します。このときに保存するトークンはハッシュ化せずそのままです。
6. ユーザーの識別情報（例えば、ユーザーID）もユーザーのブラウザのCookiesに保存します。こちらは暗号化してから保存します。

### 3-2. Cookiesを使ってユーザーを認証するフェーズ

1. ユーザーが新たにページを開くと、ブラウザはそのリクエストとともにCookiesを送信します。
2. アプリケーションは、Cookiesからユーザーの識別情報(3-1の6で保存)とトークン(3-1の5で保存)を取り出します。
3. アプリケーションは、取り出した識別情報を復号化してからデータベースに保存されているユーザー識別情報と一致するかを確認します。
4. 3で見つかった場合にそのレコードから、3-1の4で作成したダイジェストを取り出します。
5. 4で取り出したダイジェストと、Cookiesから取り出したトークンをハッシュ関数に通して生成したダイジェストとを比較します。
6. これらのダイジェストが一致すれば、アプリケーションはユーザーを認証します。これにより、ユーザーはログイン状態を維持することができます。

## 4. まとめ

今回この記事を書きながら感じたのは、Railsチュートリアルではわかった気になって進めていたはずなのに、いざ自力で記事を書こうとするとなかなか覚えたてのワードが出て来ないことでした。ソクラテスの「無知の知」という言葉は知っていましたが、「あっ、このことか！！！」と気付くきっかけになりました。知ったかぶり状態で進めてしまっていたのかもしれませんね。自分の言葉でまとめ直す癖をつけようと思います。


長々と書いてしまいましたが、最後まで読んでいただきありがとうございました。
この記事が、あなたの学習に少しでも役立ちましたら幸いです。
CMakeプロジェクトをVSCodeでデバッグする方法

下のリンクにいつも辿り着けないので作ったメモページ。そのうち要約を書こうかと思ったけれど、今時はChatGPTに直接聞くか、下のページをChatGPTに読み込ませたほうが早いだろう.

https://code.visualstudio.com/docs/cpp/cmake-linux

https://github.com/microsoft/vscode-cmake-tools/blob/main/docs/debug-launch.md