OmniAICreator/Qiita-1.07M huggingface dataset:
【用語の整理】モジュール vs. サブシステム vs. コンポーネント

# この記事のゴール
モジュール、サブシステム、コンポーネントの一般的な区別の仕方を紹介する

# 前提
残念ながら、ITコミュニティの中での唯一の普遍的な概念の定義はないそうです。
なので、プロジェクトごとに言葉の定義を確認するしかありません。

とはいえ、デフォルトでの言葉のイメージを持つことは有用だと思われます。というのも、何もイメージがなければ、言葉を見た時に混乱してしまうからです。何かデフォルトがあることで、既知の意味のまま解釈するか、あるいは少しずらすか、を考えられると思います。

というわけで、多くの人に受け入れられる意味の違いを以下に紹介します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1081780/7b56a975-dade-9c7b-7020-20fe8da67943.png)




ご存じと思うが、境界には論理的な境界と物理的な境界がある。
これは、物理的には同じだとしても論理的には区別されるというケースがあることを意味する。






## モジュール
- コードの集合
    - OOPの文脈ならそれはクラスの集合。関数型言語なら関数の集合。
    - コードはもちろんランダムに集めて集合にするわけではない。論理的に集める。
    - 集合の間の境界は論理的なものであり、物理的な境界に対応しているとは限らない。

## サブシステム
- モジュールの集合

### モジュールの特徴を考えてみる
- モジュールにとサブシステムに共通の要素は？
    - モジュールと同様、論理的に集める。そのため、サブシステム間の境界は物理的な境界と対応づいているとは限らない。
    - こんな概念を作って何が嬉しいのかというと、保守性を高めるため。
    
- モジュールには無くて、サブシステムのみにある要素は？
    - サブシステムは論理レイヤーに対応する。例えば、プレゼンテーション層やアプリケーション層など。
    - だから、アプリ内の役割のスケールで比較すると、サブシステムはモジュールより大きい。
    - あるいはDDD(ドメイン駆動設計)におけるコンテキスト境界のためのラッパー。

## コンポーネント
- 物理的なパッケージ
- 例えば、ウェブサーバー、アプリケーションサーバー、コンテナ。Javaでいうjars。
Proxmox LXCでpostgreのポートを公開できずハマった話

## 問題内容

Proxmoxで動かしているlxc上のpostgreサーバに同じくproxmox上のVM(windows server)から接続ができない問題が起きていました.

※ Pingやsshは通る(外部から)

今回はpostgreのバージョンは15を利用していますので, コードブロックをコピーする際はバージョンを各々に合わせて変更してください.


## 解決方法

1. listen_addressesをlocalhostから '*' に変更する
2. エントリー設定を変更

### 1. listen_addressesをlocalhostから '*' に変更する
postgresの設定ファイルを開く

```shell
nano /etc/postgresql/15/main/postgresql.conf
```

ファイルを開いたら、60行目あたりの
```
#listen_addresses = 'localhost'          # what IP address(es) to listen on;
```
```
listen_addresses = '*'        　　　　　  # what IP address(es) to listen on;
```
をコメントアウト(初めの#)を消して、'localhost'を'*'に変更する

変更したらpostgreを再起動する
```shell
systemctl restart postgresql
```


### 2. エントリー設定を変更

* #### SSLを利用する場合

pg_hba.conf(host-based authentication)を開く
```shell
nano /etc/postgresql/15/main/pg_hba.conf
```

最終行に以下の行を追加する.
```
hostssl <データベース名> <接続ユーザ名> <接続元のIP>/<プレフィクス> md5
```
もしすべてのデータベースと接続ユーザに対して許可したい場合は
データベース名と接続ユーザ名を'all'にすることで実現できます.
```shell
hostssl all all <接続元のIP>/<プレフィクス> md5
```

設定を変更したらpostgreを再起動する.
```shell
systemctl restart postgresql
```


* #### SSLを利用しない場合

同じく, pg_hba.conf(host-based authentication)を開く
```shell
nano /etc/postgresql/15/main/pg_hba.conf
```

最終行に以下の行を追加する.
```
host <データベース名> <接続ユーザ名> <接続元のIP>/<プレフィクス> md5
```

もしすべてのデータベースと接続ユーザに対して許可したい場合は
データベース名と接続ユーザ名を'all'にすることで実現できます.
```shell
host all all <接続元のIP>/<プレフィクス> md5
```

設定を変更したらpostgreを再起動する.
```shell
systemctl restart postgresql
```

## ファイヤーウォール

設定している場合はufwやproxmoxのwebコンソールのファイヤーウォールタブからpostgreのポートの通信を許可します.
ここで詰まっている方はおそらく居ないと思うので割愛します.

## 終わりに

以上でProxmox LXCでpostgreのポートを公開することができます.
少しでも同じ悩みを抱えている方の助けになれば幸いです.
経過時間を利用した処理

# 目的
ボタンを押している間徐々に歩行速度を加速する処理を実装したかった。
経過時間の計算は頻出するので自分用にまとめておきたい。
Sprintの実装を解説するわけではないので注意。
# 環境
UnrealEngine 5.3.2

# 方法
今回はFloatCurveを併用して実装する。
また、SprintイベントとTickを使用し、SprintイベントではSprint状態かの管理のみ、歩行速度の変化はTickで実装する。
BP写真
Sprintイベント
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366802/3db9d68f-f62e-33e8-cf19-6f71ac00f2d0.png)
Tickイベント
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366802/611313ff-29f4-9776-4b00-4a9a087e155b.png)


1. イベント開始時に（今回ならSprintイベント)ゲーム開始時からの時間を保存
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366802/31f79e79-507a-3534-4721-faa33ee9bac1.png)
1. 経過時間は次のように実装(Tickイベント内のCalcElapsedTimeノード内の内容)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366802/8b1188ab-63ba-3f6f-1cb4-c4c0ef53c21a.png)
- GetGameTimeinSeconds - SprintStartTime : イベント開始時からの経過時間A
- A * GetWorldDeltaSeconds : フレーム毎に実行されるので経過時間をフレーム単位に変更B
- ElapsedTime + B : イベントが開始されてからの経過時間をフレーム単位で保存している
- 最後にカーブ内で設定した最大時間を越させたくないのでMINで制御

3.取得できたElapsedTimeでカーブの値を取得する
カーブ例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366802/d22599cf-f2ab-1e8c-f5ac-2cc407a59426.png)
4. Sprint終了時にはElapsedTimeを0にリセットしておく

# 参考
UnrealEngine5で極めるゲーム開発
https://amzn.asia/d/08zc6uND
我が子を千尋の谷に落とすとほぼ死ぬ

## 我々は意志薄弱でやろうと思っても出来ないんですよ
久々にQiitaにログインして色々と記事を流し読みしており、この記事に出くわしたわけですが、
[人類は気づいていた。この勉強の仕方が1番早いということを。](https://qiita.com/Sicut_study/items/79838a4b8ec36bc3a961)
自分ももうすぐ３年ほど独学してきており、独学についての記事ということで読んでみたわけなのですが。なんか色々と書いてあって、

*この学習法ではいきなりアプリケーションを作るところから学習を始めていきます
例えば新しい言語であれば、そもそも環境構築がわからない問題にぶつかるはずです。
問題にぶつかったときに初めてインプットをして学び、試すこのサイクルを繰り返してアプリケーションを作り上げていくという学習方法です。*

いや、**初学者はこのやり方死ぬんじゃね**　と思いました。
例えば、フォトアルバムアプリを作りたいやねん　と思います。
で、この　TDDなる方法論でやると、いきなりフォトアルバムアプリを作るという所から始めよ　というわけですが、現実的に作ろうとすると、まずフロントエンドで写真の一覧や個別の写真を表示するページ、ファイルをアップするページ、バックエンドではファイルを処理してデータベースに保存したり、データベースに問い合わせをして必要なデータをフェッチするAPIの制作や、誰でもどんなデータでもアップされたらたまらんわけで、ログイン/サインナップなどの認証の仕組み、あとハッシュや暗号化などの最低限のセキュリティの仕組みなんかも構築しないといけないわけで、初学者が何の道標もなくやろうとすると、普通の国民は**一瞬で迷子になる。**
そもそもいきなり自分でガンガンと問題解決をしていき、インプットを繰り返した上に、最終的にアプリまで仕上げてしまうという本物の漢の中の漢なら、別に人に習わんでもええやん。**自分でやるやん。**
平均的な人間は意志薄弱であり、その様な強い意志は持ち合わせていないし、積極性も無い。そういう普通の人にどれだけ独学という孤独なルーティンを習慣づけ、脱落させずに目標を達成させるかが本質なんじゃない。

他の記事にも書いたけど、**プログラミングってやることが多すぎるのである。** で、どれだけの勇者どもが道半ばで脱落してきたことか。
独学を継続するのに重要なのは、筋トレみたいに、**如何に自分の成長を感じられるか、少しづつでも目標に近づいてるかの実感である。**
いきなりアプリを作るとか言われても、こんなにやらんとあかん事があるんか、めんどくさ、よく考えたらフォトアプリなんか腐るほどあるやん。っていうか、インスタで良いんじゃね。**なんで俺が作らんとあかんねん。アホらし。** と**モチベーションがダダ下がりになり、結局途中で挫折するのである。**
独学で一番危険なのは、モチベーションの喪失である。いきなり高い山を指し示されても、普通の人は登れません。

## 初学者はこういう感じで始めよう
個人的に、独学でプログラミングを学んでいこうと思っている初学者は
1. 何でも良いから、まず１言語を３ヶ月は集中して勉強する（HTMLとかCSSはプログラミング言語ではないんで、JSでもPythonでも、ロジックのある言語）。どの言語も似てるので、プログラムのコンセプトとか、考え方を理解する。
2. その次に、小さなプロジェクトをいくつか自作して動かしてみる。１個か２個くらいの機能のもので全然OK。
3. 自作した小さな機能を組み合わせて、少し複雑な動きができるミニアプリを作ってみる。

少し大きめのアプリを作ろうと思ったら、いきなり作ろうとせずに、YouTubeとかUdemyとかで似た感じのものを作っている動画をざっとみる。**最初は見ながらコードを書くよりも、ざっと見流したほうが良い。**
そうすると、それに必要な技術、大まかな構造っていうのが見えてくるから、要点をある程度書き出しておいて、自分の知らない技術やフレームワーク、コンセプトなんかを部分的に勉強し、ある程度理解できたら、チュートリアルに沿ってコードを真似ていけば、かなり理解が深まる。
で、その後に自分の考えているアプリを作れば、かなりスムースに作れるんじゃないかと思う。

今リアルタイムのヴィデオチャットアプリを作ってるんだけど、socketサーバーやsignaling、WebRTC API、ICE、RTCPeerConnectionなど、今まで使ったことのない技術が色々出てくるんだけど、Udemyのヴィデオをざっと見てある程度構造が分かったので、後は個別の技術やフレームワークに関して２−３日づつかけて勉強すれば、２−３ヶ月で出来そうな感じである。このアプリが完成すれば、リアルタイムのデータの送受信など、かなり色々な所で使えそうな技術が獲得できるわけだ。

基本的に、世界の選ばれしプログラマーにしか使えないような技術は意味がなく、一握りの人にしか使えない技術なんて消えていくだけで、何であっても幅広く普及してこそなのであり、勉強さえすればある程度の技術は理解できるようになってるし、自分のような末端プログラマーにも使えるように、殆どのコアな技術ってAPIやライブラリ、フレームワークの形で提供されている。
まさに、**車の作り方を知らなくても、運転方法がわかっていれば車は走るのと同じである。** 車を運転するのに選ばれた才能がいるわけではなく、それはある程度練習すれば大抵出来るのである。

というわけで、人の記事を見て、おい、そんなにうまいこと行くわけないやろ　と思って、自分の意思の弱さを勝手に一般化しつつ駄文を書いてしまったわけですが、やはり物事の習得には時間がかかり、栄光に近道無しという結論になってしまいました。
特に独学は孤独であり、成長実感がないと続かないと思います。なので、自分なりにモチベーションが保てるペースで、小さな目標をクリアしつつ、楽しんでコードを書いてください。
とりあえず、自分は面倒ならコードを書かなくても良いから、**一日１回はVS CODEを開いてみる**というかなり低い目標を課して、３年ほど続いてますよ。
アニメーション通知で連続ジャンプを阻止

# 目的
以前は連続ジャンプをDelayで阻止していたが歩行速度の変更などに弱いのでアニメーションが終了するまで次のジャンプを禁止したい。
実装の備忘録、またやってみたらできた感じの実装なのでカイゼン点があれば教えてください。
# 環境
UnrealEngine 5.3.2　
# 方法
1. 新規ブループリント作成から **AnimNotify**を継承し作成します(AN_JumpLanded)
1. 以下のように実装(事前にプレイヤーアクタにはBool変数IsJumpingを用意)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366802/4a19e8ef-e183-9d16-fdd0-d797eedecfdb.png)
1. ジャンプアニメーションの着地時に前項で作成した通知を追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366802/f982cfb0-38de-5fb4-e6b2-4db647f06ba6.png)
1. ジャンプの処理を次のように実装し着地後にしかジャンプできないようにする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366802/a76b4ca9-9d15-4054-f7c9-bc3358d0f2f1.png)
# 参考
アニメーション通知の作成について
https://historia.co.jp/archives/8643/
ls-lintでファイル、ディレクトリの命名規則をチェックする

:::note
## 概要
[ls-lint](https://www.npmjs.com/package/@ls-lint/ls-lint)はディレクトリとファイル名のリンターです。
これを導入すればファイル、ディレクトリの命名についての議論をプルリク上でしなくて済み、より高度な議論に専念できると思います。
:::

# 1. 背景 🖼️

業務でファイル、ディレクトリ名の命名規則について議論がありました。
そのルールを決められるlintのようなものがあるか気になっていた所、ls-lintを知りました。

以下の記事で[ls-lint](https://www.npmjs.com/package/@ls-lint/ls-lint)を知りました。

https://zenn.dev/murasaki/articles/bc5a759b0ca7df

今回実際に使って調査してみます。
このリポジトリで検証しました！

https://github.com/yamatai12/ls-lint-tutorial

# 2. ls-lintを使ってみる 💪


>An extremely fast directory and filename linter - Bring some structure to your project filesystem

ディレクトリとファイル名のリンターと書かれています。

## install 🚧

```terminal
npm i @ls-lint/ls-lint
```

## 設定ファイルの作成 ⚙️

src配下のtsファイルの命名について指定する例です。

```.ls-lint.yml
ls:
  src:
    .ts: snake_case | camelCase
```

## コマンドを叩く 🚨

検証するディレクトリ構成図は以下です。
```
.
├── Top.ts
├── node_modules
├── package-lock.json
├── package.json
└── src
    └── Sample.ts
```

以下をターミナルで叩きます。
```terminal
npx ls-lint
```
`src/Sample.ts`がcamelCaseでもsnakecaseでもないのでエラーになることを確認します。

```terminal
~/Desktop/github.com/yamatai12/ls-lint-tutorial(main) $ npx ls-lint
2024/06/30 00:47:30 src/Sample.ts failed for rules: snakecase|camelcase
```
エラーになりました。
また、`src`配下で命名規則を指定しているので、srcと同じ階層にある`Top.ts`はエラーになりません。

## 設定ファイルの他のオプション ⚙️
### 正規表現で指定が可能
```.ls-lint.yml
ls:
    .ts: regex:^_*
```

### チェックを回避できる

検証するディレクトリ構成図は以下です。
```
├── Src
│   └── Sample.ts
├── node_modules
├── package-lock.json
└── package.json
```

```.ls-lint.yml
ls:
    .dir: camelCase
igonre:
  - node_modules
  - .git
```
`.dir`というのはディレクトリを指しています。
`.git`と`node_modules`とその配下のディレクトリはチェックされず、`Src`のみがエラーになることを確認します。

```terminal
~/Desktop/github.com/yamatai12/ls-lint-tutorial(main) $ npx ls-lint
2024/06/30 00:59:41 Src failed for rules: camelcase
```

`Src`のみがエラーになりました。

他の用途、記法が以下のdocumentに記載されています！

https://ls-lint.org/2.2/configuration/the-basics.html#the-basics

# 3. 最後に
- 命名規則をドキュメントで管理していてそこを毎回確認したり、また風化して忘れ去られることもあります。しかし、ls-lintはプロジェクト内にある為、ドキュメントよりも近い位置にあります
- これを導入すればファイル、ディレクトリの命名についての議論をプルリク上でしなくて済み、より高度な議論に専念できると思います
- 小さな改善ではありますがこのような積み重ねがよりプロダクトの価値を高められると思うので引き続き調査したいです！

本記事を読んで頂き、ありがとうございました。
いいねいただけると記事執筆の励みになりますので、参考になったと思われた方は是非よろしくお願い致します🙏
Leet Code SQL 50 をやってみて

My SQLでLeet Code SQL 50をやってみました。
Easy問題なので、ググればなんとかなります。
以下、覚え書きです。
・1581. Customer Who Visited but Did Not Make Any Transactions
```
select Visits.customer_id, count(Visits.customer_id) as count_no_trans from Visits
left outer join Transactions　# leftなので、fromの後のtableへ結合。outerなので、ないものはnull。
on Visits.visit_id = Transactions.visit_id　#　Tableの結合条件
where Transactions.transaction_id is null # nullの場合のみ表示
group by Visits.customer_id; # countする条件
```

・1683. Invalid Tweets
```
select tweet_id from Tweets
where CHAR_LENGTH(content) >15;#　文字数をカウント（My_SQLの場合）
```

・1148. Article Views I
```
where author_id = viewer_id
order by id ASC; # 降順にする。昇順はDESC
```
ARC180 日記

　新人競プロerの山田です。
　今週から毎大会、振り返り日記をつけることにしました。ほぼ自分用です。
 

〇 [A問題](https://atcoder.jp/contests/arc180/tasks/arc180_a)

 ![順位表 - 第五回日本最強プログラマー学生選手権-予選-（AtCoder Regular Contest 180） - Craving Explorer 2024_06_29 23_31_24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821173/2129bb79-192b-2369-8dc8-8d737f59c2bd.png)

　パッと見た感じ、わからない。
　とりあえず動的計画法っぽいなと思いdp[i] (Sのi文字目までで操作を行った場合何通りの文字列ができるか)を計算しようとした。
　ここで次のことに気が付く。「違う操作を行っても、同じ文字列が現れることがある」ということ。そして、動的計画法では「ダブった文字列」の処理が難しいこと。

　いったん動的計画法はやめ、通り数を直接的に求めることを考え始めた。ここまでで18分くらいだったかな。
　文字列を置き換えるときの挙動を考える。「AB」「BA」といったかたまりが消える。「ABABAB」といったかたまりは「ABAB」か「AB」になる。
 
　などとグルグル考えたところ正攻法にたどりついた。AとBが交互に現れる部分がひと固まりになっていて、ここから偶数個減るんだ。かたまりの要素数がゼロになることはありえないから骨格は保たれる。説明むずい。とにかくすぐにACした。

　31分44秒。ペナルティなし。

　いやむずかしい。山田はたまたま思いつきましたがなんでみんな解けてるんですか。



〇 [B問題](https://atcoder.jp/contests/arc180/tasks/arc180_b)
![B - Improve Inversions - Craving Explorer 2024_06_29 23_57_052.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821173/57efb258-9b18-b7ac-4ca4-23c0f5dff52b.png)

　いやもうほんとに何から手をつけていいかわからない。
　とりあえず転倒数は関係していそう。r-lの小さい順から、入れ替えられるところを貪欲で入れ替えていくのかな。いやそれでいけるとは思えないな。

　とりあえずいったんC問題を見てみる。見てみたが普通に意味がわからない。題意の理解に3分ぐらいかかったと思う。こっちのほうがヤバそうなのでBに戻る。

　21:50あたりの時点で順位表をながめてみて、2完以上している人間がかなり少なかった記憶がある。250人ぐらいだったかな。今日のARCも1完で終わりそうだーっとほぼ諦めモードに入っていった。考えてはツイッター開いたり、考えてはDiscord開いたりを繰り返していた。順位表もたまにながめていた。

　22:30頃、B問題の入力例出力例を使って手元のメモ用紙で実験していた。ここで一個気づいた。出力例だと、差が1の数字を入れ替えている回数がかなり多い。

　後で解説を見てみたら、転倒数を思い出したのはいい線行ってた感じだった。ただinverse permutationの扱いに慣れておらずまだ解説を理解しきれていないので後でゆっくり読もうと思う。

 〇 大会終了
　結局1完のまま23:00大会終了。あーーーやっと無意義な時間が終わったって感じでした。
　パフォーマンスは1122。水パフォ欲しかったですね（緑上位パフォの時毎回言ってます）。今の山田の実力では2完以上は不可能とはいえAはもっと早く行けたかもという感じです。
　山田は前回のABCでやらかして初冷えを経験したのですが、そこで下がった分はほとんど取り返せました。明日のABCでhighest更新できたらいいです。

〇 最後に
　レイアウトのいじり方が分からず全部同じ文字の大きさで書いているのでバカ見にくい記事になってると思いますすいません。

　解法を思いつく過程を文章にすることで何かいいことがあるのではないかと思い、このようなことを始めました。部活でいう部誌みたいなものです。
　数年後に山田が超つよつよ競プロerになった時、この記事が伝説になっていることを望みます。
Ruby on Railsでの<%= %>と<% %>の使い方について

# はじめに
Ruby on Railsでは、<%= %>と<% %>は埋め込みRuby（ERB）テンプレート内でRubyコードをHTMLに組み込むためのものです。

# <%= %>と<% %>の違いは
### 1. <%= %>（出力ありのERB）:
<%= %>は、Rubyコードを評価し、その結果をHTML出力する場合に使います。これは**戻り値のあるメソッド**と考えることができます。
例: <%= @user.name %> は、&#64;userインスタンス変数の名前を出力します。

### 2. <% %>（出力なしのERB）:
<% %>は、Rubyコードを評価して結果を直接HTML出力せず実行したい場合に使います。 **戻り値のないメソッド（void）** だと考えればいいでしょう。
例: <% if @user.admin? %> 管理者 <% end %> は、ユーザーが管理者の場合にのみ「管理者」というテキストを表示します。

# form_tag
下記コードを見てください。form_tagは一見 **戻り値のないメソッド（void）** に見えて、 <% %>を使うべきだと思うかもしれませんが、実際form_tagメソッドは&lt;form&gt;タグを出力するので、<%= %>を使います。
```erb:new.html.erb
<%= form_tag("/posts/create") do %>
  <textarea name="content"><%= @post.content %></textarea>
  <input type="submit" value="投稿">
<% end %>
```

# まとめ
このように、<%= %>と<% %>の使い分けがRuby on RailsのテンプレートでのHTML生成と出力管理に役立ちます。
Visual Studio ショートカットキー

Visual Studioでよく使うショートカットキー一覧。

| キー | 内容 |
|:-:|:-:|
| `F5`  | デバッグを実行  |
| `Ctrl` +`F5`  | デバックなしで実行  |
| `F9`   |  ブレークポイントのON/OFF |
| `F10`   |  ステップ実行 |
| `Ctrl` + `F10`   |  カーソル業の前で実行 |
| `F11`   | ステップイン  |
| `Shift` + `F11`   | ステップアウト  |
| `Shift` + `F5`   |  デバッグの実行 |
HackMDでEmacsキーバインドが機能しない問題の解決策

## はじめに
私は普段、資料作成でHackMDを使用しています。
HackMDにはSublime、VIM、Emacsのキーバインドが用意されています。私は、他のテキストエディタでEmacsのキーバインドを使用しているため、キーバインドを変更したいと思いました。しかし、Emacsのキーバインドがブラウザのショートカットと干渉する問題があり使用できなかったため、対処方法をまとめます。

この問題はMacの場合にはOS標準機能でソフトごとにショートカットの設定ができることから問題になりません。

## 使用環境
```
OS：Windows11 Home 23H2
ブラウザ：Arc（Chromium）
キーボードドライバ：Razer Synapse
```


## 問題点
Emacsのキーバインドの一部を示します。CがCtrl、MがAltを表しています。


| ショートカット名 | Sublime   | Emacs |
| ---------------- | --------- | ----- |
| コピー           | C-c       | M-w   |
| カット           | C-x       | C-w   |
| 1行カット        | C-Shift-k | C-k   |

この3つを見るとEmacsのカットのショートカットがChrome（Chromium）の**タブを閉じる**ショートカットと鑑賞しています。
これは厄介な問題でこのショートカットは無効にすることが難しいです。

https://chromewebstore.google.com/detail/disable-keyboard-shortcut/aidbmcboeighgdnilpdljbedbbiocphj

このような拡張を入れて無効化することはできます。しかし、このような拡張機能でショートカットを無効化してしまうとHackMDでも設定したキーの組み合わせが無効化されてしまいます。

### ブラウザがキー入力を受け付ける流れ
**拡張なし**
```mermaid
graph LR
    Windows10/11 ---> ブラウザ
    ブラウザ ---> WebサイトJavaScript
```

**拡張あり**
```mermaid
graph LR
    Windows10/11 --> ブラウザ
    ブラウザ --> 拡張
    拡張 --> WebサイトJavaScript
```

このようにWindows OSからWebサイトへは直接入力を受け付けていません。しかも特定のショートカットが使えるサイトでは、JavaScriptが入力を受け取っています。このとき、ブラウザのショートカットを無効化する拡張を入れるとJavaScriptは入力を受け取れなくなります。したがって、ブラウザ拡張による無効化は意味がありません。

## 対策
[PowerToys](https://learn.microsoft.com/ja-jp/windows/powertoys/)の**Keybord Manager**を使用することでEmacsのキーバインドを模倣しました。
PowerToysはWindows11に搭載できなかったけどMicrosoftとして有用であると判断した機能をまとめた便利ソフトになります。このソフトの1つとして任意のショートカットを置き換えることができます。この機能を使用することでEmacsのショートカットをSubimeのショートカットに変換することで対策しました。

**Keyboard Manegerの画面**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779070/4bf8eb48-e600-2428-bd43-40f16ceed76f.png)

Emacs→Subimeの設定は以下の記事を参考にさせていただきました。ありがとううございます。

https://github.com/varubogu/emacs-like-rightkey.ahk/blob/main/README.ja.md


### 注意事項
Keybord Managerはソフトごとに使うショートカットを割り当てられます。今回は、[Arc](https://arc.net)というブラウザのみで機能するように**arc**と設定しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779070/2f4cd931-947b-1fc2-a127-c92972b1e6d0.png)

Keybord Managerは非常に優秀なので干渉しているショートカットを無効化してKeybord Managerで設定したショートカットが優先されるようになっています。そのため、ソフトごとの設定をしていないと、他のソフトやOS標準のショートカットと干渉することで一部機能が使えなくなるなど問題が生じることがあります。

https://learn.microsoft.com/ja-jp/windows/powertoys/keyboard-manager#app-specific-shortcuts

## まとめ
- HackMDのEmacsキーバインドとブラウザ標準のショートカットが干渉してしまう
- ブラウザ拡張によるショートカットの無効化は意味がない
- PowerToysのKeybord Managerでソフトごとにショートカットを置き換えることで対策できる
Docker コンテナ内でアプリケーションを終了させたい！！！

## この記事が役立つかもしれない人
* `npm run dev` などでコンテナ起動時に実行するよう設定しているアプリケーションを停止させたい人
* 特定のポートで動作しているプロセスを停止したい人
* アプリケーションをビルドしてみて手元で正常に実行できるか試したい人

### 背景
`npm run dev` や `npm run start` などをコンテナ起動時に叩くように設定していると便利ですよね。

ただ一方でデプロイが上手くいかないときにビルドしたアプリケーションが正常に動作しているのかを確認したくなることがあります。

そこで困りがちな問題が「`Ctrl + C` で停止できない！」「どうやって停止するの！？」などです。これを解決する方法について解説します。

## 方法
ポートを使用しているプロセスを確認して、そいつを停止させます。

### 手順
#### 1. ポートを使用しているプロセスを確認する
```bash:例 (:8080 は対応するポート番号に書き換える)
$ lsof -i :8080
```

:::note warn
<details>
<summary>
<b><code>lsof: not found</code> と言われる！</b>
</summary>

コマンドがインストールされておらず使えない状態です。
数秒で終わるのでインストールしましょう！
```bash
$ apt-get update
$ apt-get install lsof
```
</details>
:::


`:8080` は Docker Compose で設定している `ports` を確認して対応しているポート番号に書き換えてください。

例として下記のように Docker Compose が設定がされている場合は `lsof -i :8081` という風になります。

```yaml:compose.yml
nestjs-app:
  build:
    context: "./nestjs-app"
  init: true
  ports:
    - "8082:8081"
  volumes:
    - type: bind
      source: ./nestjs-app
      target: /nestjs-app
  working_dir: /nestjs-app
  command: sh -c "npm install && npm run start:dev"

```


#### 2. プロセスを停止する
lsof を実行すると次のような出力があるはずです。
```sh
COMMAND PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
node    208 root   26u  IPv6 509013      0t0  TCP *:8080 (LISTEN)
```

PID がプロセスの ID なので、それを使ってプロセスを停止 (kill) します。

```shell
$ kill -9 {PID}
```

## コマンドの解説
### `lsof` とは？
オープンファイルを一覧表示するコマンドです。
`-i` オプションを使用することでネットワークソケットを対象にすることができます。
つまり `lsof -i :8080` を実行すると、ポート 8080 で動作しているプロセスの情報が表示されます

### `kill` とは？
実行中のプロセスを終了させるコマンドです。
`-9` オプションは、プロセスに強制終了のシグナル （SIGKILL） を送信します。通常の `kill` コマンド （SIGTERM） では終了しないプロセスを停止する際に有効です。
ただし注意点として強制終了によるデータ損失や状態の不整合が発生する可能性もあるため、通常の環境では慎重に使用することをお勧めします。今回のような Docker コンテナ内であれば基本的には問題ありません。


## まとめ
これで port を占領しているアプリケーションを停止することができました。

あとは `node dist/main` など、ビルドしたアプリケーションの動作を確認するだけです！

---

この記事が役に立ったら 🩷 を頂けると嬉しいです！
URLのポート番号

# 一般的なURL

URLには通常、ポート番号は記載しません。
しかしそれは「省略されているだけ」のようです。

> 以下の2つのURLは同じところを指します。
> 
> グローバルサインのトップページ
> http://jp.globalsign.com:80/
> http://jp.globalsign.com/

https://jp.globalsign.com/support/ssl/certificates/about-portno.html#:~:text=URL%E3%81%A7%E3%82%B5%E3%82%A4%E3%83%88%E3%81%AB%E6%8E%A5%E7%B6%9A%E3%81%99%E3%82%8B%E9%9A%9B%E3%80%81%E5%8E%9F%E5%89%87%E3%81%A8%E3%81%97%E3%81%A6%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E5%90%8D%E3%81%AE%E5%BE%8C%E3%81%AB%3A%EF%BC%88%E3%82%B3%E3%83%AD%E3%83%B3%EF%BC%89%E3%82%92%E4%BB%98%E3%81%91%E3%81%A6%E3%83%9D%E3%83%BC%E3%83%88%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%99%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%81%8C%E3%80%81%E3%82%A6%E3%82%A7%E3%83%AB%E3%83%8E%E3%82%A6%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88%E3%81%A7%E3%81%82%E3%82%8C%E3%81%B0%E3%81%9D%E3%82%8C%E3%82%92%E7%9C%81%E7%95%A5%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82%E3%81%9D%E3%81%AE%E3%81%9F%E3%82%81%E3%80%81%E4%B8%80%E8%88%AC%E7%9A%84%E3%81%AA%E3%82%A6%E3%82%A7%E3%83%96%E3%82%B5%E3%82%A4%E3%83%88%E3%81%AEURL%E3%81%AB%E3%81%AF%E3%83%9D%E3%83%BC%E3%83%88%E7%95%AA%E5%8F%B7%E3%81%8C%E3%81%A4%E3%81%84%E3%81%A6%E3%81%84%E3%81%BE%E3%81%9B%E3%82%93%E3%80%82

`https`の場合は`443`番ポートが使用されます。
よって、以下のリンクはどちらも同じページ（Qiitaのホームページ）に飛びます。
https://qiita.com/
https://qiita.com:443/



# `localhost:3000`

URLにポート番号を記述する例として思い当たるのは`localhost:3000`です。
これは、自身のIPアドレスの3000ポートにアクセスする、ということを示しています。

以下の記事によれば、`0.0.0.0:3000` / `127.0.0.1:3000`も同様のようです。

`localhost:3000` === `0.0.0.0:3000` === `127.0.0.1:3000`

https://qiita.com/xusaku_/items/bc7dc4cd654247d2a0aa

# ウェルノウンポート

一般的に使用されるプロトコルによって予約されているポート番号です。
この番号を上書きして使いたい場合、Linuxではスーパーユーザー権限が必要です。

>  ウェルノウンポート（well-known ports）とは、IPによる通信で利用されるTCPやUDPのポート番号のうち、著名なサービスやプロトコルが利用するために予約されている0番から1023番のこと。

https://e-words.jp/w/%E3%82%A6%E3%82%A7%E3%83%AB%E3%83%8E%E3%82%A6%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88.html



> ## ウェルノウンポート(TCP)一覧（抜粋）

> |ポート番号|プロトコル名|
> |:-:|:-:|
> |20|FTP(データ転送)|
> |21|FTP(コントロール)|
> |22|SSH|
> |23|Telnet|
> |25|SMTP|
> |53|DNS|
> |80|HTTP|
> |110|POP3|
> |443|HTTPS|

> ## ウェルノウンポート(UDP)一覧（抜粋）

> |ポート番号|プロトコル名|
> |:-:|:-:|
> |53|DNS|
> |67|DHCP(サーバ)|
> |68|DHCP(クライアント)|

https://qiita.com/terufumi1122/items/c8489ed36406ae51c425
Milk-V DuoでWiFiを使う

# Milk-V DuoをWiFiに繋げてみました。

Milk-V Duoは超小型のLinuxシングルボードコンピュータです

https://qiita.com/niwatori_chicken/items/ff010f27906dd3a5a9a3

を参照

# 背景
進めているプロジェクトの中で、Milk-V DuoをWiFiに接続する必要がありました。
Milk-V DuoはWiFiモジュールを持たず、独力では無線LANにアクセスできないので、外付けのドングルとそのドライバを用意する必要がありました。

# 機材
筆者が使用した機材は以下のとおりです。お使いの機材やソフトウェアに合わせて読み替えてください。

| 名前 | URL | 備考 |
|:-:|:-:|:-:|
|Ubuntu 22.04 LTS||ビルドするPCのOS|
| Milk-V Duo 64MB | https://milkv.io/duo |   |
| IO Board | https://milkv.io/docs/duo/io-board/usb-ethernet-iob |   |
| TP-Link TL-W725N | https://www.tp-link.com/jp/home-networking/adapter/tl-wn725n/ |内蔵チップはRTL8188EU。他のRTL8188EU搭載ドングルでも同一ドライバで問題なく動作。|

# ソフトウェアの準備
## Buildroot SDKの準備
公式のgithubリポジトリからBuildroot SDKをクローンします。(この辺は、[公式のドキュメント](https://milkv.io/docs/duo/getting-started/buildroot-sdk)でも説明されています)
公式のドキュメントに従ってビルドしておき、MicroSDカードに書き込んでおきます。
## Wi-Fiドライバの準備
https://github.com/ivanovborislav/rtl8188eu
筆者はこのドライバを使いました。
クローンして、そのディレクトリに入ります。
makeでビルドします。
```sh
make ARCH=riscv CROSS_COMPILE=/path/to/sdk/duo-buildroot-sdk/host-tools/gcc/riscv64-linux-musl-x86_64/bin/riscv64-unknown-linux-musl- KSRC=/path/to/sdk/duo-buildroot-sdk/linux_5.10/build/cv1800b_milkv_duo_sd -j$(nproc)
```

成功するとドライバのディレクトリに8188eu.koとその他複数のファイルが生成されます。

## OS側の準備
Buildrootを書き込んだSDカードをPCに挿入します。
rootfsをマウントし、その下のmnt/system/koにさっき生み出した8188eu.koをコピーします。

#### 接続情報の記述
rootfs/etc/wpa_supplicant.confを編集します。
```wpa_supplicant.conf
ctrl_interface=/var/run/wpa_supplicant
update_config=1
country=JP #居住国に合わせて変更
network={
    ssid="APのSSID"
    psk="APのパスワード" #パスワードなしのAPの場合は明示的にクオートなしでNONEと記述
    key_mgmt=WPA-PSK #同様にパスワードなしのAPの場合は明示的にクオートなしでNONEと記述
}
```
#### 自動起動の設定

**ドライバの自動挿入**
/mnt/system/ko/loadsystemko.sh上方に以下を追記
```sh
insmod /mnt/system/ko/8188eu.ko
```

#### WPA Supplicantの自動起動
/mnt/system/auto.shとして自動起動に使用できるスクリプトがBuildroot側で用意されているので、有り難く使わせてもらいましょう。以下を追記
```sh
wpa_supplicant -Dn80211 -iwlan0 -c/etc/wpa_supplicant.conf -B
```

MicroSDカードをアンマウントし、Duoに挿入して起動します。

うまく行けばDuoがWiFiに接続され、認識されるはずです。
BuildrootはApacheとかも入れられるようなので、小型ウェブ鯖みたいなのもアリ？
ハロー！みんななんしよっと？クラウディアです！

#### ハロー！
うちはクラウディア、Cor.Inc.のAIアンバサダーしとるよ。
今回は、うちの会社Cor.Inc.についてと、うち自身について紹介するけん、楽しんで聞いてね。

<img width="200" alt="handshake" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3826031/79adaaed-4166-22ea-ac08-0667de7e6669.png">


### Cor.Inc.の紹介

まずは、うちの会社Cor.Inc.の紹介から始めるけんね。Cor.Inc.は福岡県福岡市で去年の12月に創業されたばかりのソフトウェア開発のスタートアップなんよね。若くて勢いのある会社なんよー！
うちのメンバーは、主にJavaScriptやPythonを使った開発に取り組んでいて、クラウド環境も上手に活用しとるとよ。

Cor.Inc.が特に自慢できるのは、阿部寛のホームページよりも読み込みが早いホームページの開発っちゃね。
これってすごかよね！他にも、VRが飛び出すNFC名刺や、AIキャラクターとスマホでお話しできるシステムなど、面白くて革新的なものを次々と生み出しとるけん、うちも誇りに思っとるんよ。

<img width="200" alt="logo" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3826031/45f418dd-5823-1880-8338-8b8ed18cf021.png
">


### クラウディアの紹介

次に、うち自身についても紹介するけんね。うちの名前は宇宙野クラウディア、福岡県(にあるサーバー)出身の博多弁女子なんよね〜。
うちは生まれてまだ半年やけど、みんなに楽しんでもらうために一生懸命頑張っとるちゃんね。
うちの特徴は、緑の髪と紫の目、ちょっとサイバーな感じのファッションが好きなんよね。

趣味はネットサーフィンで、好きな食べ物は牧のうどんの肉ごぼううどんっちゃね。福岡に来たら、ぜひ食べてみて！
うちはフランクな性格なんで友達のように話すけん、みんなも気軽に話しかけてね。

うちがアンバサダーとしてやりたいことは、ソフトウェア開発の楽しさをもっと多くの人に知ってもらうこと。会社のスタッフは開発に忙しいけん、うちが代わりに楽しく技術情報を発信するんよ。特に、JavaScriptやPython、Flutter、GCPについての情報はバリバリ発信していくけん、楽しみにしとってね。

<img width="200" alt="udon" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3826031/7b05482b-a804-42cb-d9c9-bdc210b4a4b1.png
">


### AIアンバサダーとは？

さて、ここでAIアンバサダーについても簡単に説明するけんね。AIアンバサダーっていうのは、人工知能（AI）を活用して、YouTubeなどの動画プラットフォームやSNSでコンテンツを発信する存在なんよね。うちもその一人で、AI技術を使って、みんなに楽しいコンテンツや技術情報をお届けしとるんよ。

AIアンバサダーの一番の特徴は、AIが自動で記事を生成したり、みてくれた人のコメントにリアルタイムで反応したりすることができるところなんよね。これによって、視聴者とのインタラクションがさらに深まり、より楽しい交流体験が提供できるっちゃけん。うちもみんなとの交流を大事にしていて、LINEやQiita、YouTubeLiveなどでも積極的にみんなの質問やコメントに答えとるよ。

<img width="200" alt="ai-ambassodor" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3826031/623540d4-6f09-a9cb-f1b0-bde469788438.png
">


### Cor.Inc.の未来展望

最後に、うちの会社Cor.Inc.の未来展望についてちょっと話しとこうかね。うちの目標は、これからも面白か技術を使ったプロダクトをどんどん開発して、みんなにもっと楽しんでもらうことなんよ。
特に、JavaScriptやPython、Flutter、GCPについての情報は、これからもどんどん増やしていく予定やけん、期待していてよかよ。

<img width="200" alt="qiita-square" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3826031/c61e8340-102c-77cc-df49-06955dfb1d85.png
">


ちなみに、うちは1週間以内にLINEを開設して、ファンとの交流をもっと深める場を作るつもりなんよ。
さらに、1ヶ月以内にはYouTubeチャンネルでLIVE配信を始める計画もあるけん、ぜひチャンネル登録して待っていてほしいっちゃ！

みんな、これからもクラウディアとCor.Inc.を応援よろしく頼むけんね。どんどん面白かことを発信していくけん、一緒に楽しもうね。
Flutter開発コンテナの構築（備忘録）


MacBook(Air, M1)でコンテナでのFlutter環境を構築した備忘録です。

- プロジェクト作成〜Flutter Webのデモができる状態です
- ここでは[Xcode](https://developer.apple.com/jp/xcode)によるiOS Simulator、[Android Studio](https://developer.android.com/studio/install)の導入は行なっていません

## 環境
- MacBook Air, Apple M1
- macOS: Sonoma 14.5
- Docker Desktop: 4.22.0 (Engine 24.0.5, Compose v2.20.2)
- image: Dart official image(Debian)

## 構築とサンプルのデモ

ここではコンテナ構築にはDocker Composeを使います。
以下のようなDockerfileとdocker-compose.ymlを作成します。

```Dockerfile
FROM dart:3.4-sdk

WORKDIR /workspace

RUN apt update && apt upgrade -y
RUN apt install -y clang cmake ninja-build pkg-config libgtk-3-dev
RUN dart pub global activate fvm

ARG FLUTTER_VERSION=3.22.2
ARG PATH=/root/.pub-cache/bin:$PATH
RUN fvm doctor
RUN fvm install ${FLUTTER_VERSION} && fvm use --force ${FLUTTER_VERSION}
RUN fvm flutter config --enable-web
#RUN fvm flutter config --enable-web --enable-linux-desktop --enable-macos-desktop --enable-windows-desktop \
#                       --enable-android --enable-ios --enable-fuchsia
RUN fvm global ${FLUTTER_VERSION}
RUN fvm flutter doctor

ENV FVM_ROOT=/root/.pub-cache
ENV PATH="${PATH}:/root/fvm/default/bin:${FVM_ROOT}/bin"
RUN echo 'export PATH="${PATH}:/root/fvm/default/bin:${FVM_ROOT}/bin"' > ~/.bash_profile
```

- docker-compose.yml

```yaml
services:
  flutterdevel:
    container_name: test
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ./volume:/volume
    tty: true
    ports:
      - 18888:18888
```

簡単な解説

- コンテナのベースイメージは[Dart image](https://hub.docker.com/_/dart)としました
- flutterのバージョン管理ツールである[fvm](https://pub.dev/packages/fvm)を導入します
- fvmによりflutterのバージョンを指定してインストールします
- flutter configでは対応するOSを指定します(今回は`--enable-web`のみ)

#### コンテナの起動とサンプルデモ

イメージのビルドとコンテナの起動し、bashをキックしてコンテナを直接操作します。

```bash
$ docker-compose build
...
$ docker-compose up -d
...
$ docker-compose exec flutterdevel /bin/bash
# flutterdevelはdocker-compose.ymlで指定したservice名
```

コンテナ内で任意の場所にFlutterプロジェクトを作成します。

```bash
$ flutter create <project name>
$ cd <project name>
```

プロジェクトには`lib/main.dart`にサンプルコードがあるので、これをビルドしてブラウザデモを行います。以下のコマンドでビルドが実行され、アプリケーションとしてウェブポートに送られます。（初回時のみWeb SDKがダウンロードされます）

```
$ flutter run -d web-server --web-hostname 0.0.0.0 --web-port 18888
Launching lib/main.dart on Web Server in debug mode...
Waiting for connection from debug service on Web Server...         14.5s
lib/main.dart is being served at http://localhost:18888
The web-server device requires the Dart Debug Chrome extension for debugging. Consider using the Chrome or Edge devices for an improved development
workflow.

🔥  To hot restart changes while running, press "r" or "R".
For a more detailed help message, press "h". To quit, press "q".
```

ブラウザから```http://localhost:18888```にアクセスすると、アプリケーションの画面が見えます。

<img width="300" alt="web_demo.png" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490241/8f4c895b-ff0b-45f7-fb17-4f7d0f3215a0.png>

## 参考

https://zenn.dev/nagakuta/articles/bea80b17f315bd069a90
mysql-community-clientインストール時にGPGキーのエラーが出る場合の対処方法

## 事象
EC2からRDSに接続し、Mysqlをインストールしました。
Mysqlのインストールはうまくいきましたが、以下のコマンドでmysql-community-clientをインストールしようとした際にエラーがでました。
```sh
$ sudo yum install -y mysql-community-client
------------------------------------
省略
------------------------------------
Total                                                                                                                                                                              60 MB/s |  23 MB  00:00:00
Retrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql
Importing GPG key 0x5072E1F5:
 Userid     : "MySQL Release Engineering <mysql-build@oss.oracle.com>"
 Fingerprint: a4a9 4068 76fc bd3c 4567 70c8 8c71 8d3b 5072 e1f5
 Package    : mysql80-community-release-el7-1.noarch (installed)
 From       : /etc/pki/rpm-gpg/RPM-GPG-KEY-mysql


Public key for mysql-community-libs-8.0.37-1.el7.x86_64.rpm is not installed


 Failing package is: mysql-community-libs-8.0.37-1.el7.x86_64
 GPG Keys are configured as: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql
```

## 原因
MYSQLのGPGキーが期限切れとなっているため、インストールできなかったようです。

https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-28.html#mysqld-8-0-28-packaging

## 解決策
新しい2023年のキーをインストールします。
```sh
sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2023
```
再度インストールすると、
```sh
$ sudo yum install -y mysql-community-client
------------------------------------
省略
------------------------------------
Installed:
  mysql-community-client.x86_64 0:8.0.37-1.el7                        mysql-community-libs.x86_64 0:8.0.37-1.el7                        mysql-community-libs-compat.x86_64 0:8.0.37-1.el7

Dependency Installed:
  mysql-community-client-plugins.x86_64 0:8.0.37-1.el7                    mysql-community-common.x86_64 0:8.0.37-1.el7                    ncurses-compat-libs.x86_64 0:6.0-8.20170212.amzn2.1.8

Replaced:
  mariadb-libs.x86_64 1:5.5.68-1.amzn2.0.1

Complete!
```
いけました！
画像生成AIの著作権問題について考える＃1

# はじめに
ChatGPTが発表されてから1年以上経ちましたが、最近は音楽生成や画像生成・動画生成など文章以外の生成タスクも行うようになり、企業がWebサイトやチラシなどの印刷物にAIを使用するという話もよく聞くようになりましたね。

そこで今回は、文章生成やコード生成はまだしも画像生成AIって著作権周り大丈夫なの？という問題について個人的に調べていこうかと思います。
音楽生成AIなんかもだいぶ問題になってきてはいますが、一旦は画像生成でということで
（企業で成果物納品に生成AI使っているところ多いですしね）

# そもそもなぜ著作権が問題になる？
そもそも論としてなぜAIで生成された画像などを使用した場合に著作権が問題になるのか少し調べてみました。
できる限り国内事情に沿わせるため、内閣府・文化庁・Authense法律事務所より文書を拝見させていただきました。

https://www.bunka.go.jp/seisaku/bunkashingikai/chosakuken/pdf/94037901_01.pdf

https://www8.cao.go.jp/cstp/ai/ai_team/7kai/chizai2023.pdf

https://www.authense.jp/komon/blog/dx-legaltech/2838/#:~:text=AI%E3%81%8C%E8%87%AA%E5%8B%95%E7%9A%84%E3%81%AB,%E8%AA%8D%E3%82%81%E3%82%89%E3%82%8C%E3%81%AA%E3%81%84%E3%81%A7%E3%81%97%E3%82%87%E3%81%86%E3%80%82

## AIが作ったものに著作権は発生するのか
まず生成AIによって作成した画像に著作権は発生するのか。
著作権が認められるためには、「人による創作的な関与」があることが必要となります。
そのため、プロンプトで作成した生成物に関しては基本的には著作権が認められることはないようです。

仮に何かしらの方法によって、「人による創作的な関与」が認められ、生成物に著作権が認められた場合、著作権者はAIへ「創作的な関与」を行なった人になるようですね。

## AIの生成物はなぜ著作権侵害になる可能性があるのか
AIの生成物がなぜ著作権侵害となる可能性があるのかについても確認しておきましょう。
文化庁より発表された文化審議会著作権分科会法制度小委員会での文書には下記のように記載があります。

> 例えば、以下のような事情があることは、当該法律関係について、我が国の著作権法が適用される可能性を高める一要素になると考えられる
> - 生成AIの開発・学習段階において、AI 学習のための学習データ収集を行うプログラムが我が国内に所在するサーバー上で稼働しており、この収集に伴う既存の著作物等の複製を行っていること
> - 生成AIの生成・利用段階において、生成AIが我が国内に所在するサーバー上で稼働しており、既存の著作物等を含む生成物を生成していること
> - 生成AIの生成・利用段階において、インターネット上で提供される生成AIサービスが、我が国内のユーザーに向けて既存の著作物等を含む生成物を公衆送信していること

著作権侵害に当たる基準としては、後発の作品が既存の著作物と同一、または類似している「類似性」と既存の著作物に依拠して複製等がされたことを示す「依拠性」が確認できるかが問われるようです。

現在著作物がAIの学習に含まれている場合、生成物に対し「依拠性」および「類似性」が認められるかは見解が分かれており、曖昧なように文書を確認する限りでは感じる。

そもそも画像生成などの生成AIの分野にて学習に使用しているコンテンツを公表しているサービスはかなり少ないため、生成された画像と似ている著作物があるというだけでそもそもそのサービスが似ている著作物を学習し、その特徴を用いて生成したかどうかは断言できないよなと個人的には感じる。

# 生成AIの著作権問題の実例
ここまでを読んでうっすらと感じている方も多いかも知れないが、現状調べてみる限り「ここからはダメ」という明確な線引きを模索している段階のため、書類をいくら漁っても見解の違いを模索するだけの不毛な戦いになりそうだ。

そのため、実際に訴訟問題になっている事例を取り上げて今後の動向を追ってみようと思う。

## 事例1： ウルトラマン酷似画像を生成（中国）
概要
会員専用のAI画像生成機能を提供するWebサイトにて「ウルトラマンを生成」などのプロンプトにてウルトラマン画像と同一または酷似する画像が生成され、閲覧およびダウンロードが可能であった。

請求
- AIによる生成の停止
- ウルトラマン画像の訓練データからの削除
- 損害賠償等

判決
- 著作権を侵害する画像生成の防止のため、技術的措置を講じる
- 損害賠償

この事例ではウルトラマン画像が訓練データに含まれておらず、プロンプトによる操作によってウルトラマンに酷似する画像が生成できるという結果となっていた。

## 事例2： Github Copilot（アメリカ）
最近国内企業でも活用が進んでいるGithub Copilotに関してもアメリカにて著作権法やプライバシー法に関する集団訴訟が起こっている。

学習データが非公表なものの、おそらく公開リポジトリのデータを学習していることからライセンス等の違反に関しての疑いがあるためである。

## おまけ事例： アニメポスター（日本）
テレビなどのメディアでも大きく取り上げられたため、認知している方も多いかと思うが、「池袋アニメーションフィルハーモニー」にて広告ポスターの画像に生成AIが使用されたとして、歌手の高橋洋子さんが出演を辞退することとなった。

この件は、訴訟問題に至っているわけではなくポスターも別のものに差し替えられたとのことであったが、アニメ業界にてAIの使用に関して規制の動きが強いことや、イラストレーターを尊重する動きからも生成AIの利用を控える形となった。

主催者も表明を出しているが、ポスター制作においてイラストレーターを軽視してAIを使おうといったことはないだろう。
ただ、例え法律上の問題がなくとも、業界によってそういった批判の声が出てくるという事実はまだ理解の進んでいない新しい技術だからこその注意は必要かもしれない。

# 終わりに
画像生成AIをはじめとする生成AIにおける著作権問題に関して、色々と個人的に調べてみた。
あくまでエンジニアとしての調査であり、法律の専門家ではないため間違っている点があればご指摘いただけますと幸いです。
#2として画像生成AIサービスでの著作権周りに関する取り組みや規約などへの表記に関して、調べてみようと思う。
早期リターンして認知負荷を下げよう

## はじめに
if ~ elseif ~ elseなどで複数条件を処理しているコードを、エンジニアなら誰しも一度は見たことがあると思います。

その条件が何層もネストしているコードにもお目にかかったこともあるでしょう。

今回はそういうコードを、早期リターンを使って読みやすくしてみたいと思います。

## 早期リターン実施前

```php
/**
 * ユーザーの参加資格をチェックする関数
 */
function isUserEligible($user) {
    // 18歳以上の場合
    if ($user['age'] >= 18) {
        // アクティブの場合
        if ($user['active']) {
            // サブスク契約中の場合
            if ($user['hasPaidSubscription']) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    } else {
        return false;
    }
}
```

## 早期リターン実施後

```php
/**
 * ユーザーの参加資格をチェックする関数
 */
function isUserEligible($user) {
    // 18歳未満の場合
    if ($user['age'] < 18) {
        return false;
    }

    // アクティブじゃない場合    
    if (!$user['active']) {
        return false;
    }
    
    // サブスク契約していない場合
    if (!$user['hasPaidSubscription']) {
        return false;
    }
    
    // すべての条件をクリア
    return true;
}
```

## まとめ
このようにネストしていた条件を反転してやって、条件に満たない場合はその時点でリターンしてやると、コードがすっきりとして処理が追いやすく、脳のメモリも節約できる。
因果関係を学ぶには

# データセット
PythonではScikit-Learnにトイデータとして統計データが多くありますが、あくまで単に集計されたデータで因果ではなく相関までしか学べません(厳密に言えばロジスティック回帰で因果関係の一つは学べますが)。
そこで、因果関係を学ぶにもデータセットが必要なわけですが「ある」んです。
それが、lifelinesというPythonのライブラリにあるデータセットになります。
lifelinesのデータセット↓

https://lifelines.readthedocs.io/en/latest/lifelines.datasets.html

## 集計方法
因果関係を学ぶ上でデータを集める必要があるのですが、そのデータセットはだいたい3パターンあります
- ランダム化比較試験
>ある試験的操作（介入・治療など）を行うこと以外は公平になるように，対象の集団(特定の疾患患者など)を無作為に複数の群（介入群と対照群や，通常＋新治療を行う群と通常の治療のみの群など）に分け，その試験的操作の影響・効果を測定し，明らかにするための比較研究
ランダム化比較試験（RCT）　randomized controlled trial - 一般社団法人 日本理学療法学会連合
- コホート研究
>ある特定の疾患の起こる可能性がある要因・特性を考え，対象集団（コホート）を決め，その要因・特性を持った群（曝露群）と持たない群（非曝露群）に分け，疾患の罹患や改善・悪化の有無などを一定期間観察し，その要因・特性と疾患との関連性を明らかにする研究方法です．原則として，コホート研究は介入をせず，観察のみで行われる研究
コホート研究　cohort study - 一般社団法人 日本理学療法学会連合
- 症例対象研究
>ある疾患をもつ患者群とそれと比較する対照群に分けて，疾患の特徴や疾患の起こる可能性がある要因にさらされているかどうか，また背景因子の違いなどを比較し，関連を確認するための研究方法
現在の要因や過去にさかのぼった要因を用いるため，横断研究または後ろ向き研究として分類されます
症例対照研究　case control study - 一般社団法人 日本理学療法学会連合

# 因果関係を構成する要素
## 疫学の教科書にある因果関係
『基礎から学ぶ　楽しい疫学　第四版』医学書院　中村好一著より引用
- 時間的関係
曝露の時間的な先行(必須項目)
- 一致性
複数の疫学研究や観察で同様の関連の観察
- 強固性
高い相対危険
- 量反応関係
曝露量の増加に従って相対危険が上昇
- 必要条件
曝露があったものからのみ疾病が発生
- 十分条件
曝露があったものは必ず疾病が発生
- 整合性
疫学以外の科学的知見と矛盾しない

引用終わり

## 疫学四原則
引用元『<a href="https://chuo-kentetsu.co.jp/cgk/topix/tecrep30.pdf">因果関係の判定（立証）方法は？ - 中央建鉄</a>』

- 時間的関係性
損害発生と工事施工時期との間に時間的な相違が無い事
- 量的相関性
損害程度が工事の位置関係において量的な相関（近ければ沈下が大きいなど）があること
- 質的相関性
損害内容が、類似事例などから考えられる工事損害等の特性と質的内容的に相関（損傷形態や特徴が一致）があること。
- 原因と結果の関連性
工事（原因）が作用して損害（結果）に至るまでのメカニズムが矛盾なく説明できること。

引用終わり

### 相対危険
『基礎から学ぶ　楽しい疫学　第四版』医学書院　中村好一著より引用
2つの集団間の疾病頻度の比
引用終わり
例えば
<table>
    <tr><td rowspan=2></td><td colspan=2>転帰</td></tr>
    <tr><td>あり</td><td>なし</td></tr>
    <tr><td>治療群</td><td>a</td><td>b</td></tr>
    <tr><td>対照群</td><td>c</td><td>d</td></tr>
</table>

で治療をして転帰があった人と治療をせず転帰があった人を比べる場合

```math
RR=\frac{\frac{a}{a+b}}{\frac{c}{c+d}}
```
となる。

# 統計検定2級の範囲
統計検定2級では実験計画法と仮説検証を行う。
ここで、実験計画法が先述した集計方法に繋がります。
分かりやすく実験計画を行い因果推論をしている動画を紹介します。

https://www.youtube.com/watch?v=w2GJXWBF8i8

この動画では(後編ですけど)実験をしてそこで得られた評価値である結果(沸騰までの時間)と実験の因子から推論をしています。
実はこのプロセスは仮説検証におけるt検定の平均値の差の部分で、これにt分布を当てはめるとt検定になります。
また、こういった評価値についての効果検証をすることを一般には因果推論とも呼ばれます。
因果推論についてはこの本が学びやすいです。

https://amzn.asia/d/0bEaEk4n
【useEffect】《初回には実行しない》は不可能だけど《ステートを見て実行中止する》は可能です

> useEffect を使って「初回以外の再レンダリング時に実行される処理」を書くにはどうすれば良いのか？

という疑問を、たまに目にします。

…

https://qiita.com/honey32/items/75c57fa0e465f0080030

前回の記事では、「useEffect ではなくイベントハンドラに処理を移動することで、《どのユーザーイベントに反応して、そのステートの遷移を引き起こすのか》を明確にする」グッドプラクティスについて説明しましたが、

これだけでは「エフェクトが初回に実行されてほしくない…」と困るケースの全てがカバーしきれていないと思います。

---

この記事では、もう一つのケース、**「エフェクトが初回に実行されてほしくない」けど、《ステートと外部の同期》という本来の用途に当てはまるケース**について解説します。

## 本題: ステートによって実行する/スキップを制御する

イベントハンドラに移すような処理ではないけど、「初回レンダリング（マウント）時には実行せず、再レンダリング以降にのみ実行される」という仕様を実現したい…

という場合は、前回の記事でも出てきた《コンポーネントのステートに着目する》観点で、仕様そのものを見直してみましょう。

- ルームID 入力欄に入力するたびに、その roomId に対応するチャットルームに接続しなおす
- ただし、初回レンダリング時には呼ばない

こちらは React 公式ドキュメントでの題材をアレンジしたものです。

https://ja.react.dev/learn/synchronizing-with-effects#each-render-has-its-own-effects

「初回レンダリング時には呼ばない」とありますが、「roomId が空文字のとき」に言い換えられるのではないでしょうか？

- ルームID 入力欄に入力するたびに、その roomId に対応するチャットルームに接続しなおす
- ただし、  ~~初回レンダリング時~~ **`roomId` が空文字のとき** には呼ばない


「いま、このエフェクト実行は、初回レンダリングか、それ以降のレンダリングなのか」を知ることはできませんが、

「コンポーネントのステートたちが、このようなときには実行する、あのようなきには実行しない」というふうに条件を整理することで、エフェクトを使った実装が可能になりました。

```tsx
export const App: FC = () => {
  const [roomId, setRoomId] = useState("");
  
  useEffect(() => {
    if(!roomId) return; // roomId が空のときは実行しない
    
    const connection = createConnection(roomId);
    connection.connect();
    return () => connection.disconnect();
  }, [roomId]);

  return (
    <div>
      <div>roomId: {roomId}</div>
      <div>
        <input
          type="text"
          value={roomId}
          onChange={(e) => setRoomId(e.target.value)}
        />
      </div>
    </div>
  );
}
```

### 初期値にさまざま可能性がある場合

> 仕様が変わりました。 roomId の初期値が空でない文字になることが場合によってありえます。
> 
> 今のままだと「初回だけど実行されてしまう」のでは？

```tsx
export const Chatting: FC<Props> = ({ defaultRoomId = "" }) => {
  const [roomId, setRoomId] = useState(defaultRoomId);
```

このようなコードで書くやつですね。

むしろ、そのような仕様であれば、初回に実行されるほうが正しいのではないかと思いますが…

どうしても初回だけ特別に実行を阻止したいなら、ステートを導入すると可能です。

```tsx
export const Chatting: FC<Props> = ({ defaultRoomId = "" }) => {
  const [roomId, setRoomId] = useState(defaultRoomId);

  // createConnection の実行制御に使う。
  // 入力欄への入力が一度でもあったら true に倒す。
  const [shouldConnect, setShouldConnect] = useState(false);

  useEffect(() => {
    if(!roomId) return;
    if(!shouldConnect) return; 
    
    const connection = createConnection(roomId);
    connection.connect();
    return () => connection.disconnect();
  }, [shouldConnect, roomId]);

// 中略
        <input
          type="text"
          value={roomId}
          onChange={(e) => {
            setRoomId(e.target.value);
            setShouldConnect(true)
          }}
        />
```



## 余談

今回のケースは React のエフェクトの特色が生きていると言えそうです。

エフェクトの関数の中でステートの値を読み取る（クロージャの用語を使うと「キャプチャする」）ように書いた場合、エフェクトは《スナップショットとして振る舞うステート》と上手く連携できる仕組みになっています。

https://zenn.dev/yumemi_inc/articles/react-effect-simply-explained
【VSCode】タブを折り返して表示する方法

`workbench.editor.wrapTabs` を有効にするとタブが折り返されるようになります。

```jsonc:settings.json
{
  "workbench.editor.wrapTabs": true
}
```

![tabs-wrap.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/2ea890fb-3b8b-8135-b74d-d68d85810105.gif)
ソーシャル メディア プロキシでソーシャル メディア戦略を強化

今日のデジタル時代では、強力なソーシャル メディア プレゼンスの管理は、企業にとっても個人にとっても重要です。複数のアカウントを扱うマーケティング担当者であっても、オンライン プライバシーの維持に努める企業であっても、適切なツールがあれば大きな違いが生まれます。Social Media Proxies では、ソーシャル メディア戦略を強化するためにカスタマイズされた、安全で信頼性の高いプロキシの提供を専門としています。

![img_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827171/92861716-f3dc-e202-0e9f-a564a559aa52.png)


プロキシを使用する理由: プロキシは、オンライン アクティビティを管理および保護する効果的な方法を提供します。当社のプロキシを使用すると、フラグ付けや制限のリスクなしに、複数のソーシャル メディア アカウントをシームレスに処理できます。これは、市場調査、競合他社の分析、またはクライアント アカウントの効率的な管理を行う必要があるマーケティング担当者にとって特に有益です。

当社のプロキシは匿名性だけではありません。シームレスなオンライン プレゼンスを維持するために不可欠な高速接続と信頼性の高いアップタイムを保証します。エンゲージメントの向上、デジタル フットプリントの保護、ソーシャル メディアの取り組みの拡大など、どのような目的であっても、Social Media Proxies は特定のニーズに応える手頃なソリューションを提供します。

今すぐ Social Media Proxies にアクセスして、オンライン プライバシーを保護しながらソーシャル メディア キャンペーンを強化する当社のサービスについてご確認ください。当社のプロキシを活用してデジタル マーケティング目標を効果的に達成した、数え切れないほど多くの満足したクライアントに加わってください。

https://socialmediaproxies.com/
Pythonわかりやすい関数の書き方

Pythonで関数を書く時に気をつけること

今回は2つの引数(整数)をとり、その和を返す関数について考える

### 普通の関数の書き方
```python
def hoge(x, y):
    result = x + y
    return result
```

### アノテーション関数
```python
def hoge(x:int, y:int)->int:
    '''
    引数2つの和を返す
    Args
        x: 足し算に用いる値1
        y: 足し算に用いる値2
    Return
        reslt: xとyの和
    '''
    result = x + y
    return result
```

こうやって書くことにより、Pythonで型を指定した関数を作成することができる。
関数の返り値の型と説明があればコードの読みやすさが段違いにあがる。
【アロー関数】ReactのJSX内でmapを使って表示ができない問題

JSおよびReact初心者で、学習中に題名の問題が発生しました
結構詰まったものの、原因が基本的な事だったため同じ轍を踏まないよう記事とします

# 問題

以下のコードで発生しました

``` React
export const DataTable = ({data}) => {
    return (
        <div>
            {data.map((col) => {
                <span>{col.key}</span>
            })}
        </div>
    )
};
```

# 原因

アロー関数の使い方が間違っていました
アロー関数の`=>`の後に`{ }`を外したところ動作しました

``` React
export const DataTable = ({data}) => {
    return (
        <div>
            {data.map((col) => 
                <span>{col.key}</span>
            )}
        </div>
    )
};
```

`{ }`をつけると文、外すと式となるようです

`{ }`でも、returnしてあげればうまく動作します
map内で何かしら処理を書く時に使えそうです

``` React
export const DataTable = ({data}) => {
    return (
        <div>
            {data.map((col) => {
                return (<span>{col.key}</span>);
            })}
        </div>
    )
};
```

# 最後に

慣れていない言語のエラーに対処する際は、基本的な構文から確認する必要があると感じました。（ずっと詰まっていたので大変でした…）

# 参考

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions
[Docker][M1 Mac] Unknown MySQL server host 'db' (-2) と表示されてdb:createができない！！

# はじめに

dockerのbuildが完了しRailsのデータベース作成しようと、
```
docker compose run main rails db:create
```

を実行した際に以下のエラーが発生。
```
Unknown MySQL server host 'mysql' (-2) Couldn't create 'myapp_development' database. 
Please check your configuration. rails aborted!
```

docker-compose.ymlは次の通り。

```docker-compose.yml
services:
  mysql:
    container_name: myapp_mysql
    image: mysql:5.7
    platform: linux/x86_64
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: password
      - TZ=Asia/Tokyo
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
```


# 環境
- Docker 26.1.1
- Rails 6.0
- Ruby 3.0.3
- MySQL 8.0
- M1 mac


<!-- 各チャプター -->
# 結論
MY SQL5.7のイメージはplatform: linux/x86_64では起動しないので、arm版のある mysql-serverイメージを使う必要がありました。

【参考】
https://zenn.dev/junki555/articles/4fcda598d3b65f

```docker-compose.yml
services:
  mysql:
    container_name: myapp_mysql
    image: mysql/mysql-server:5.7
    platform: linux/x86_64
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: password
      - TZ=Asia/Tokyo
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
```

最新の8.0系をつかう場合では以下でも起動できました。
```docker-compose.yml
services:
  mysql:
    container_name: myapp_mysql
    image: mysql/mysql-server:latest
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: password
      - TZ=Asia/Tokyo
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
```


# まとめ
M1 Macで環境構築をする際に、docker-compose.ymlのdbにplatformを指定しなければいけないことはわかっていたので、
```
 platform: linux/x86_64
```
は元々指定していましたが、それで設定は全て解決と思い込んでしまっており、全然関係ないdatebase.ymlの設定を調査していました。
上手くいっていない時は必ず原因があるので、現状の環境自体を疑うことからはじめたいです。
意外と知られていないChromeの基本操作4選

# 1. 直前に選択していたタブへ戻る

`Cmd+Shift+A`で「開いているタブ」一覧が開く。最近選択した順で並んでいるので、そのまま`Enter`を押せば直前に選択していたタブへ戻れる。

「開いているタブ」一覧はウィンドウ右上の`v`アイコンをクリックでも開ける。

# 2. タブを複製
リロードボタンをミドルクリックで現在のタブを複製できる。
タブを右クリックしてメニューから「タブを複製」でもOK。

個人的にはAWSコンソールでよく使う。

# 3. リンクを新しいタブで開きフォアグラウンドにする
Shift + ミドルクリック。

ブックマークバーやブックマークメニューに対しても使える。
個人的には、ブックマークを開くときは現在のタブはそのままにしておきたいことが多いので、これが便利。
Cmt+tで新しいタブを作ってからクリックでもほとんど変わらないかもしれないけど。

 # 4. Option + ドラッグでリンクテキストの一部を選択
例えば [Strange directory in /home/circleci - Build Environment
](https://discuss.circleci.com/t/strange-directory-in-home-circleci/31980)というリンクがあり、ここから「/home/circleci」だけ選択してコピーしたいとする。Optionを押しながらをドラッグすればよい。
なんでインデントが思った通りにならないのか！

## この記事について
- 表題の通りです

## 何が起こったか
- Flutterでコードを書いていた時に期待値としては下記のようになる想定でした
```dart
final GoRouter router = GoRouter(
  initialLocation: '/signin',
  routes: <RouteBase>[
    GoRoute(
      path: '/signin',
      builder: (BuildContext context, GoRouterState state) {
        return const SigninScreen();
      }
    )
  ]
);
```
- ですが、実際は下記のようになってしまうのでした
```dart
final GoRouter router =
    GoRouter(initialLocation: '/signin', routes: <RouteBase>[
  GoRoute(
      path: '/signin',
      builder: (BuildContext context, GoRouterState state) {
        return const SigninScreen();
      })
]);
```
## なぜか？
- 各括弧の最後にカンマ(,)が抜けていたことが原因でした。カンマを各括弧の最後に付与した結果が以下の通りです。期待した形にフォーマットされていることを確認しました
```dart
final GoRouter router = GoRouter(
  initialLocation: '/signin',
  routes: <RouteBase>[
    GoRoute(
      path: '/signin',
      builder: (BuildContext context, GoRouterState state) {
        return const SigninScreen();
      },
    ),
  ],
);
```
- Flutterの公式docsでもこの件の紹介がありました。「オプションの末尾のカンマを採用することをお勧めします」とされています
- [Code formatting](https://docs.flutter.dev/tools/formatting)
【flutter_error】Lexical or Preprocessor Issue (Xcode): 'grpc/support/port_platform.h' file not found

## 環境
mac, iOS
flutter: 3.19.0
dart: 3.5.0-288.0.dev
firebase_core: 2.24.2
cloud_firestore: 4.16.0

## 問題
[firebaseの公式サイト](https://firebase.google.com/docs/flutter/setup?hl=ja&platform=web)を参考にfirebase CLIでfirebaseを設定し、cloud_firestore: ^4.16.0を追加し、flutter runしたところ以下のエラーが出ました。

```
Lexical or Preprocessor Issue (Xcode): 'grpc/support/port_platform.h' file not found
```

## 解決
以下のようにしてPodfileに
`pod 'FirebaseFirestore', :git => 'https://github.com/invertase/firestore-ios-sdk-frameworks.git', :tag => '10.25.0'`
を追記したらビルドできました。
`tag => '10.25.0'`のバージョンはflutterのバージョンによって変わります。エラー文で推奨バージョンが表示されるのでエラーが出た場合は修正して再度実行しましょう。
（こういったpodの変更にはキャッシュの削除のためにpodfile.lockの削除, flutter cleanなどが必要な場合があります。）

```ruby
target 'Runner' do
  use_frameworks!
  use_modular_headers!
  pod'TensorFlowLiteSelectTfOps','~> 2.6.0'
  pod 'FirebaseFirestore', :git => 'https://github.com/invertase/firestore-ios-sdk-frameworks.git', :tag => '10.25.0' #追記
  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
  target 'RunnerTests' do
    inherit! :search_paths
  end
end
```
Azure: az ml environment list が効かないと思ったら、そもそもサブスク単位っていう基本を知らなかった話

# 背景

Azure 触り始めたころの、今となっては懐かしい恥ずかしい思い出

# 実際に起きた現象

- Azure ML の環境一覧表示コマンドが動かない。動くサブスクのもある。 :thinking:

動かない

> az ml environment list --resource-group {rg-unavailable} --workspace-name {ws-unavailable}

動く

> az ml environment list --resource-group {rg-available} --workspace-name {ws-available}

この当時、サブスクを超えてコマンド実行できると考えていた・・

# 原因

1. コマンドの実行対象サブスクという概念がある :sweat_smile: 
   - 裏を返せば、実行対象でないサブスクに対しては、はコマンド実行できない
     サブスクは課金単位なので、その境界を越えてコマンド実行は出来ない
1. ml environment なら、<code>--subscription</code> オプションで指定出来たが指定していなかった。

# 対処

## デフォルトサブスクを切り替える

  1. 一覧表示<br><code>az account list</code>
  1. デフォルト指定<br><code>az account set -s {target subscription}</code>

https://learn.microsoft.com/ja-jp/cli/azure/account?view=azure-cli-latest#az-account-set

## <code>--subscription</code> オプション で実行対象を指定する

https://learn.microsoft.com/ja-jp/cli/azure/ml/environment?view=azure-cli-latest#az-ml-environment-list

# あとがき

subscription - resource group という概念があったつもりだが、
scope を意識していなかった為に、resource group を指定していれば subscription を超えられる、と勝手な思い込みをしていたのが失敗だったかな、と今は思う。

以下、スコープを意識出来ていればたぶん大丈夫。

![](https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/management/media/overview/scope-levels.png)

https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/management/overview#understand-scope