OmniAICreator/Qiita-1.07M huggingface dataset:
mysql8 アカウント作成時にロール(権限(どこまで許可するか))付与と少し色々

# はじめに

ワニさんは言った。
:crocodile:mysql8以降のどこかのバージョンでロールはアカウント作成時につけないといけない認識、、、

では、気を取り直して、、

自分が知りたいことを書いておきたく記事にしてみました。:cat2:
どうせまとめるなら記事にしちゃえ系です:bow_tone1:
参考は以下参考が主です。:jack_o_lantern:

参考
https://dev.mysql.com/doc/refman/8.0/ja/roles.html

```
$ select version();
//8.0.33
```

`sachiko`の箇所とかあればそこは自分のユーザー名に変更して考えてください。
`localhost`の箇所はipが入る時もあります！
`app_db`の箇所は指定したDB名なのでそこもよしなに変更お願いします！


# 全体的な流れ

```
// ロール(権限)のもとみたいなの作成。
$ CREATE ROLE 'app_developer';

// 作成したものに何を許可するかを付与(今回全部)
$ GRANT ALL ON * . * TO 'app_developer';

// アカウント作成時に作成した権限付与
$ CREATE USER 'ここにユーザー名'@'localhost' IDENTIFIED BY 'ここにパス' DEFAULT ROLE app_developer;

ex)
$ CREATE USER 'sachiko'@'localhost' IDENTIFIED BY 'sajkjs76' DEFAULT ROLE app_developer;
```

<font color="red">注意!</red>
`'ここにユーザー名'@'localhost'`の`localhost`箇所ですが、
私はip指定しないと上手くいかない時ありました。
エラーログとかにipでているとかあれば確認してip入れる形にしたほうがいいかもです。</font>

```
ex) CREATE USER 'sachiko'@'172.18.0.5' IDENTIFIED BY 'sajkjs76' DEFAULT ROLE app_developer;
```


# ユーザーのロール確認
```
$ SHOW GRANTS FOR 'ここにユーザー名'@'localhost';

ex)
$ SHOW GRANTS FOR 'sachiko'@'localhost';
```


```
※出力イメージ※ もっといい感じに確認できるのかと思ったのですがこれが確認方法のようです、

Grants for sachiko@localhost
GRANT USAGE ON *.* TO `sachiko`@`localhost`
GRANT `app_developer`@`%` TO `sachiko`@`localhost`
```

# ロール内容確認

※`app_developer`は作成したロール名

```
$ SHOW GRANTS FOR 'app_developer';
```


# ロール作成色々

```
// 上で実際使用したもの
$ GRANT ALL ON * . * TO 'app_developer';

// app_dbはDB名
$ CREATE ROLE 'app_developer_a';
$ GRANT ALL ON app_db.* TO 'app_developer_a';

// SELECTでSELECTのみ
$ CREATE ROLE 'app_read';
$ GRANT SELECT ON app_db.* TO 'app_read';

// INSERT, UPDATE, DELETEで更新系のみ
$ CREATE ROLE 'app_write';
$ GRANT INSERT, UPDATE, DELETE ON app_db.* TO 'app_write';
```

# ロールの削除
※`app_developer`は作成したロール名

```
$ DROP ROLE 'app_developer';
```

# ロールをユーザーから外す
※ロール付与されるアカウントがあるの前提でお話します。アカウントは上らへんの`CREATE USER`の記述参考。
※ロール作成の前提でお話します。`ロール作成色々`の箇所参考

```
$ REVOKE 'app_developer' FROM 'sachiko'@'localhost';
```

# 作成したロール確認
```
$ SELECT User FROM `user` WHERE Host='%' AND User != 'root';
```

参考:
https://stackoverflow.com/questions/68555614/how-to-list-all-roles-created-in-mysql-8


# 上記のように作成したロールの付け替え(はできなさそう、、?)
ロール自体の内容は変更できそうですが、
ロールは結局アカウント作成時につけるしかないかと、、。
(確かmysql8のどこかのバージョンから権限はアカウント作成時につける的な約束な気がしたので、)

なので、ここではアカウント削除ロールの削除を参考に記載しておきます。

```
※localhostがipになるときもあるのでそこはよしなに。

// アカウント削除
$ DROP USER 'sachiko'@'localhost';

// ロール削除
$ DROP ROLE 'app_developer';

で新規にアカウント作成から、、、、一番上らへん参考
```

mysql8のどこからのバージョン以降は以下は使えなくなる的なの見たきがします。
なので以下は書きましたが**おすすめしない**でおきます。

```
$ GRANT UPDATE ON * . * TO 'sachiko'@'localhost';
```

# 最後に

終わりです！:rabbit2:
GitHub ActionsでEnvironmentに動的なリリースURLを設定する方法

# はじめに

この記事では、GitHub Actions で Environment に動的なリリース URL を設定する方法を説明します。

# 背景

GitHub Actions には Environment という環境を定義する機能があります。
[デプロイに環境を使用する - GitHub](https://docs.github.com/ja/actions/deployment/targeting-different-environments/using-environments-for-deployment)

例えば、以下のような環境を設定しておくことでリリース先を切り替えることができます。（名前は任意のものを設定することができます。）

- 本番環境（Production）
- ステージング環境（Staging）
- テスト環境（Testing）
- 開発環境（Development）

その中でリリースした後に、リリース先の URL を表示する機能があります。

![Screenshot 2023-04-30 at 19.15.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/886596/ded2d1c6-ad43-786f-5615-6c05466105fd.png)

これが環境に対して固定で1つ決まっている場合は問題ないのですが、リリースのステップの中で動的に決まる場合、どのように表示すればよいのかわからなかったのでやり方を残しておきます。

環境に対して1つの場合は以下のようにすることで URL の設定が可能です。

```yaml
environment:
    name: production
    url: https://example.com
```

# やり方

やり方はシンプルで、URL が確定した際にステップで output に値を保存しておき、その output を environment の URL に設定することで可能でした。

サンプルの Yaml を以下に記載します。ステップに参照用の ID を付与する必要があります。output を参照する際のフォーマットは `steps.[step_id].outputs.[output_name]` となります。

```yaml
environment:
    name: development
    url: ${{ steps.get_release_url.outputs.release_url }}

steps:
    - name: Set release url
      id: get_release_url
      run: echo release_url=https://xxx.example.com >> $GITHUB_OUTPUT
```

# 結論

GitHub Actions の Environment で動的にリリースした URL を設定する方法は、リリースのステップで output に値を保存し、その output 名を environment の URL に設定することで可能です。
Amazon CodeCatalystを触ってみた

# AWS Summit

先日 AWS Summitに参加してきました。![IMG_1382.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/793703/60f521e1-a6e7-060f-19fe-a175d7595bee.jpeg)

二日間ともみてきましたが、非常に面白かったです。~~大阪リージョンのブースで笑ってました~~

日頃はWebアプリの開発に携わっている身なので、Web系だったり、AWSの新サービスなんかを中心に見て回りました。そこで２日目にこんなのがありました。

![IMG_1389.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/793703/97b7dadf-041f-4c72-f872-8f6af787017b.jpeg)

CodeCatalystというサービス?がGAしたとありました。もっぱら仕事ではCodeBuildやCodeDeploy、CodePipelineにお世話になっており、新しいCode系のサービスと思って話を聞いてみると思っていたよりなんか規模の大きいことをしていました。

というわけでせっかくなのでCodeCatalystを触ってみました。

# CodeCatalyst
ちょっと触った感じだと、なんでもできるぜ統合開発環境という感じです。
Clout9もこんなUIなのかな?
ざっくりできることはソースの編集・プロジェクト管理(issueやPRの作成とか)・CI/CD

### 必要なもの
- AWSアカウント
- AWS Builder ID

AWS Builder IDはAWSアカウントと同じもので大丈夫です。そしてこのBuilder IDはCodeWhisperer(Github CopilotXのAWS版)でも必要らしいです。

[早速ページ](https://codecatalyst.aws/explore)にアクセスしてみると
![スクリーンショット 2023-04-30 18.25.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/793703/85594dba-d9c8-92fd-caf6-e7d7fddbf9bc.png)

AWS Builder IDの作成が求められます。メールアドレスやユーザー名をチョチョイと入力すると
![スクリーンショット 2023-04-30 18.31.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/793703/a6208a51-ed48-6ee1-dd28-dd72a771bc08.png)

プロジェクト作成画面にきました。ここでGithubのアカウントから自分のリポジトリも選べるみたいですが、せっかくなので用意されているテンプレートから作ってみます。![スクリーンショット 2023-04-30 18.32.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/793703/692fd689-c025-8b82-d015-cd2872154321.png)

ホスティングやフレームワークを選択し `Create project`を押すと。![スクリーンショット 2023-04-30 18.34.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/793703/31f560ae-a577-aa6d-9edc-573c262ff32f.png)

はい。プロジェクトが出来ました。プロジェクトが作成された時点でワークフローが動いておりデプロイ作業が進んでます(10分くらいかかりました)

![スクリーンショット 2023-04-30 19.12.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/793703/1645da5a-0f95-efb9-7bc4-329976cc6b40.png)

デプロイが終わると見慣れたいつもの画面も映りました。

## まとめ
CodeCatalystの良いと思ったところ
- 爆速環境構築
- CI/CDの設定がほとんどいらない
- 環境の共有が簡単
- PCのスペックに頼らない(Mac+Dockerからの解放)
- 開発・CI/CD・プロジェクト管理が一つのサービスに

CodeCatalystの微妙だと思ったところ
- 東京リージョン未対応
- エディターがエディター(VSCodeの入力補完に頼ってる僕には辛い)

実際に使ってみるともう少し不満は出てくるかも。エディターがただのエディターなのは非常に辛い。せっかくだしCodeWhispererとの連携してくれると嬉しい。(設定を見逃してたらごめんなさい。)

なんにせよGAされたばかりのサービスなのでこれからのアップデートが楽しみです
[Unity] マテリアル(シェーダー)のエディタ拡張で、DefaultShaderPropertyの高さがおかしい

こんにちは、ユーゴです。
今回は、マテリアルのインスペクタのエディター拡張のトラブルシューティングについてご紹介します。

# 問題
なぜかプロパティーのGUIの高さが合わない。変なスペースが1行分くらい入り、1つあたりで2行分になってしまう。
![スクリーンショット 2023-04-30 19.16.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607452/0aa157a1-3291-9b21-dfea-e32f3411f1dc.png)

# 原因
positionの指定忘れ。

# 解決策
editor.DefaultShaderProperty(prop, label.text);の第一引数にRect型でpositionを指定する。

```cs
// NG
editor.DefaultShaderProperty(prop, label.text);

// OK
editor.DefaultShaderProperty(position, prop, label.text);
```

# まとめ
いかがでしたでしょうか。今回は、ケアレスミス的な紹介でした。
しかし、マテリアルのエディタ拡張を行う人はそうそういないためか、記事が出てこず苦戦しました。なので、失敗の一例としてここに記しておきました。
このように、初歩的な内容から、エディター拡張をさらに深掘ったコアな内容まで取り扱っていきます。
お役に立てましたら、いいね・LGTM・フォロー等よろしくお願いいたします！
水の分子動力学シミュレーション -lammpsコードの意味①

### tip4pの水分子sim用lammpsコードを上から少しづつ学習していきます。  
コードは以下サイトのものを使用しています。
https://lammpstutorials.github.io/

```
units real
atom_style full
bond_style harmonic
angle_style charmm
dihedral_style charmm
pair_style lj/cut/tip4p/long 1 2 1 1 0.105 12.0
kspace_style pppm/tip4p 1.0e-4
```
### units style：
・行うシミュレーションの単位系を設定する。このコマンドによって設定した単位系と読み込む dataファイルの単位系を合わせないと、意図しない数値でlammpsが動作してしまう。
styleの種類はreal, lj, metal, Si, cgs, erectron, micro, nanoがある。
real⇒ここではreal使用
マニュアル該当部分 https://docs.lammps.org/units.html

↓各styleまとめ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371660/536137fa-da76-1841-9c83-ce472a9eb695.png)

### atom_style [追加オプション]:
・dataファイル等からatomの情報をインプットする際に読み込み形式を指定する。
このコマンドはread_data（データ読み込み）やcreate_box（計算領域設定）を行なう前に実行すう必要がある。

※各読み込み形式で何をdataファイルに記述する必要があるかはread_dataのマニュアル部分に書いてある。
ex.)full atom-ID molecule-ID atom-type q x y z
ex.)body atom-ID atom-type bodyflag mass x y z

https://docs.lammps.org/read_data.html


　このstyleは変更ができないので、できるだ包括的なstyleをつかうのがいいらしい。なので大抵の場合fullでいいのではないか。各atom_styleを使うにあたって、必要なパッケージがあるので確認が必要（fullの場合はMOLECULEパッケージ）。

マニュアル該当部分:https://docs.lammps.org/atom_style.html

### bond_style ~ kspace_style
・この5行は使用する力場の関数形に合わせて設定を行う必要がある。
例えばCHAMM力場の場合
 ```math
E=E_{bond}+E_{angle}+E_{dihedral}+E_{nonbond}

```

```math
 E_{bond}=\Sigma K_l (l-l_{eq})^2  
```

```math
 E_{angle}=\Sigma K_{\theta} ({\theta}-{\theta }_{eq})^2 
```

```math
 E_{dihedral}=\Sigma\Sigma \frac{V}{2}[1 + cos(n \phi -\gamma) ]
```

```math
 E_{nonbond}=\Sigma \left[ \frac{A_{ij}}{r^{12}_{ij}}-\frac{B_{ij}}{r^{6}_{ij}} +\frac{q_i q_j}{\varepsilon r_{ij}} \right]
```
だいだいこのような関数系をしているので、合致するように選ぶ必要がある。

上の力場をコードに直すと
bond_style：harmonic
angle_style charmm
dihedral_style charmm

pair_style lj/cut/tip4p/long 1 2 1 1 0.105 12.0
kspace_style pppm/tip4p 1.0e-4

となる。
最後の2行が非分子結合相互作用の設定を表しており、pair_styleでレナードジョーンズとクーロン相互作用を設定している。（クーロン相互作用にはtip4pモデルを使っている。）
kspace_styleは長距離クーロン力の計算を行うための設定。EwaldやPPPM法が使える。
Reactドキュメントを和訳するシリーズ（まとめ）

どのくらいかかるか想像つかないけど、こつこつ進めてみるw

※参考：[【React】Reactドキュメントを和訳する：Quick Start-1](https://www.i-ryo.com/entry/2023/04/30/190330)
dockerコンテナの起動時間を3分から20秒まで縮めることに成功した経験談

こんにちは！株式会社OPTiMに所属しております川田剣士です。最近の業務でdockerコンテナの起動時間を3分から20秒まで1人で縮めることに成功しまして、こちらの経験を皆さんにも共有したく技術執筆をしようと思いました。記事に対する質問・コメント大歓迎です！

# 目次
- [タスクを取り組むに至った背景](#タスクを取り組むに至った背景)
- [前提条件](#前提条件)
- [dockerコンテナの起動時間が遅い原因の調査と解決方法](#dockerコンテナの起動時間が遅い原因の調査と解決方法)
- [本タスクを取り組んだ感想](#本タスクを取り組んだ感想)
- [終わりに](#終わりに)

## タスクを取り組むに至った背景
今回起動時間短縮に成功したdockerコンテナをdockerコンテナAと以下で記載します。タスクを取り組むに至った背景(解決したい問題)を以下に記載します。
- dockerコンテナAを起動して内部で実装されているAPIを外部から呼び出す検証作業があり、その際にdockerコンテナAを停止・起動する機会が1日に何度もあった。停止・起動するたびに3分近く待たなければいけないという点で検証作業の効率が悪かった。
- 当時3分近くコンテナの起動にかかっていたため、オートスケールをする際にpodが立ち上がっても3分近く意味をなしていない状態であった。また、コンテナ起動に時間がかかっているため、オートスケールの際にpodが20個近く立ち上がってしまうという問題もあった。
- 障害などでpodが落ちた時のダウンタイム時間が最短でも3分近くかかっている状態であった。

上記の問題を解決するためにコンテナ起動時間をなるべく短くする必要がありました。

## 前提条件
前提条件を以下に記載します。
- dockerコンテナAではjava,spring bootを利用している。
- dockerコンテナAの起動時はspring-boot:runを実行して、Spring Bootアプリケーションを起動している。
- Javaプロジェクトのビルドと管理をApache Mavenを利用して行なっている。具体的には、Spring Boot Mavenプラグインを使用して、pom.xmlにSpring Bootアプリケーションに関連するいくつかのgoalを指定し、コンテナ起動時(spring-boot:runの実行)はpom.xmlに指定したgoalを実行している。
[Spring Boot Maven プラグインのドキュメント](https://spring.pleiades.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/)を確認していただけるとイメージしやすいかなと思います。
- buildpack化はできない状態である。理由は、アプリケーションで利用しているとあるライブラリ(ここではライブラリAと呼ぶ)が特定のpropertiesファイルのみしかアクセスできず、実行環境によって読み込むpropertiesファイルを切り替えることができないからである。そのため、現状はdockerコンテナ起動時にpropertiesファイルを上書きするようなスクリプトを実行している。例えば、コンテナ起動をテスト環境で行った場合、libraryA_properties.testの内容をlibraryA_propertiesファイルに上書きしている。
- 今回のコンテナ起動時間の短縮は恒久対応ではない。恒久対応は環境ごとにpropertiesファイルの切り替えができないライブラリAを利用せず、代わりのライブラリを利用してbuildpack化することである。

## dockerコンテナの起動時間が遅い原因の調査と解決方法
コンテナの起動時のログを確認したところ、コンテナ起動時間が約3分弱かかっており、そのうちcompileとtest-compileでそれぞれ1分近くかかっていました。ちなみに、compileはjavaの実装コードのcompileであり、test-compileはjavaのテストコードのcompileを行なっています。そのため、image作成時にcompile,test-compileを行い、起動時に行われるcompileとtest-compileに関してはキャッシュを利用させるようにすることで、起動時間短縮を目指しました。

対応した内容はimage作成時のコマンドに以下を追加しただけです。
```
RUN ./mvnw test-compile
```
compileはtest-compile内部で行われるため、RUN ./mvnw compileの実装は必要ないです。

後は、コンテナ起動時にダウンロードしているライブラリがあったため、ライブラリのダウンロードはimage作成時に行うように修正しました。この修正によって、ライブラリのダウンロード時間分の短縮、コンテナ起動の安定化(ライブラリのダウンロードに失敗したらコンテナの起動に失敗してしまうため)を見込めます。

その後、コンテナを起動したところ、全体としては1分30秒まで縮めることに成功したことを確認しました。そして、引き続きボトルネックを調査したところ、checkstyle-validationの実行に1分15秒かかっていることを確認しました。checkstyle-validationのチェックはコンテナ起動時には必要ない処理です。そのため、checkstyle-validationをスキップすることを目指しました。

先ほど同様に事前にcheckstyle-validationを行うことで処理をスキップすることができるかなと思い、いろいろ試したのですがうまくいきませんでした。そこで、pom.xmlで定義しているmavenのcheckstyle pluginの記述を削除するスクリプトをコンテナ起動時(spring-boot run実行前)に実行するように修正しました。その後、コンテナを起動したところ、全体としては20秒まで縮めることに成功したことを確認しました。その後、全体的にログを確認し、特別目立ったボトルネックはなかったため、終了としました。

## 本タスクを取り組んだ感想
本タスクを取り組んだことで、検証作業の効率化、オートスケーリングの改善、ダウンタイム低減による可用性の向上、デプロイ作業の高速化など、かなり貢献ができたかなと思います。また、buildpack化ができないという点に関しては、ライブラリの選定や技術選定などをより慎重に行うことの大切さを学びました。

## 終わりに
最後まで読んでいただき、ありがとうございます！
Rakuten 宝くじから 過去の当選番号をスクレイピングしてみよう！

https://www.youtube.com/watch?v=6wr6aAb-_Ck

### ライブラリをインストール
```
!pip install beautifulsoup4
!pip install requests
```
### URLからHTMLを取得
```python
import requests
from bs4 import BeautifulSoup

url = "https://takarakuji.rakuten.co.jp/backnumber/numbers3/202304/"

response = requests.get(url)
response.raise_for_status()

soup = BeautifulSoup(response.content, "html.parser")
print(soup)
```
### 結果
```
<!DOCTYPE html>

<!--[if IE 8 ]><html class="ie ie8" lang="ja" prefix="og: http://ogp.me/ns# fb: http://www.facebook.com/2008/fbml"><![endif]-->
<!--[if IE 9 ]><html class="ie ie9" lang="ja" prefix="og: http://ogp.me/ns# fb: http://www.facebook.com/2008/fbml"><![endif]-->
<!--[if !(IE)]><!-->
<html lang="ja" prefix="og: http://ogp.me/ns# fb: http://www.facebook.com/2008/fbml">
<!--<![endif]-->
<head>
<meta charset="utf-8"/>

以下略
```

### 当選番号を取得します

```python
winning_numbers = soup.find("td", colspan="2")
print(winning_numbers)
```

### 結果
```
<td colspan="2">2023/04/03</td>
```

複数の情報を取得するために、```find_all```を利用します

```python
winning_numbers = soup.find_all("td", colspan="2")
print(winning_numbers)
```

### 結果
```
[<td colspan="2">2023/04/03</td>,
 <td colspan="2">009</td>,
 <td colspan="2">2023/04/04</td>,
 <td colspan="2">911</td>,
 <td colspan="2">2023/04/05</td>,

以下略
```

### タグを削除

```python
tmp = str(winning_numbers[0]).replace('</td>', '')
tmp = tmp.replace('<td colspan="2">', '')
print(tmp)
```

### 結果

```
`2023/04/03`
```

### リスト内のタグを全て取り除き置き換える
```python
for i in range(len(winning_numbers)):
  tmp = str(winning_numbers[i]).replace('</td>', '')
  tmp = tmp.replace('<td colspan="2">', '')
  winning_numbers[i] = tmp
```
LINE Messaging APIで音声や動画データを取得し保存するするとデータが空もしくは欠損している事象が発生した。


## 事象
LINE Messaging APIで音声や動画データを取得しこれらを保存するするとデータが空もしくは欠損している事象が発生した。

### 検証環境
CPU: Apple M1
OS:  MacOS Monterey 12.6.3
Node.js: v16.18.1  
LINE Bot SDK(Node.js) Version: 7.5.2

### 事象発生サーバ環境
インフラ: Fly.io(Firecracker VM)
Node.js: v16.18.1 
LINE Bot SDK(Node.js) Version: 7.5.2


## 今回事象の背景
LINEでシェアするファイルは一定期間たつとアクセスできなくなる。
僕の所属するLINEグループによっては恒久的にデータを保存し参照できるようにしたいというニーズがあった。
よって音声データや動画データを保存できるように、LINE Botにデータを渡し、LINE BotサーバでGoogle Driveに送信ファイルを保存するようにしていた。
LINE Botサーバに送信されるファイルデータは問題なく保存されてたが、音声データと動画データは空データもしくは欠損した状態で保存されていることに気がついた。

下記手順を実行すると発生する。
1. 検証対象のLINE Botに対して任意の音声データ or 動画データを送信する
2. サーバでデータをファイルに書き込み保存する
音声データや動画データは数MBであった。

## 原因特定の流れ
下記を切り分ける
   * ファイルデータは保存されていること
   *  音声データ、動画データのみうまくいっていないこと 
LINE Messaging APIの公式ドキュメントを参照すると、下記を発見した。
https://developers.LINE.biz/ja/reference/messaging-api/#get-content
音声データ、動画データに関してLINEのサーバの提供準備の完了をまたずに取得処理を実行していたからではという仮説がたつ。
実際処理の直前に上記APIを呼ぶとprocessing(コンテンツの取得準備中)という結果が帰ってきた。

## 原因
当該事象のの原因はLINE Botサーバで音声データもしくは動画データの送信準備が整っていないのに、Botサーバで取得をおこなったため。

## 解決方法
下記APIを使用して、動画または音声の取得準備の状況を確認するようにした。
````
GET https://api-data.LINE.me/v2/bot/message/{messageId}/content/transcoding
````
上記APIは下記のいずれかの値を返却する
-   `processing`：コンテンツの取得準備中である。
-   `succeeded`：コンテンツを取得する準備が完了した。
-   `failed`：コンテンツの取得準備に失敗した。
 上記APIを定期実行し`succeeded`の場合のみ保存処理に進むように実装を修正した。
 下記のようなコードで完了を待機できる。
``` javascript
待機用の関数
const _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// (中略)

// 動画または音声の取得準備の状況を確認する(Node-fetchを使用している)
let res = await fetch(`https://api-data.LINE.me/v2/bot/message/${id}/content/transcoding`, {
    method: "GET",
    headers: {
        Authorization: `Bearer ${LINE_ACCESS_TOKEN}`,
    },

});

let resJson = await res.json();
let maxCheck = 10;
// 成功するまで確認を行う。
while (resJson.status !== 'succeeded') {
    await _sleep(1000);
    maxCheck--;

    if (maxCheck === 0) {
        // 確認する上限に達したらやめる(暫定で設定)
        console.log(`failed to get data id${id}`);
        break;
    }

    // 動画または音声の取得準備の状況を確認する
    res = await fetch(`https://api-data.LINE.me/v2/bot/message/${id}/content/transcoding`, {
        method: "GET",
        headers: {
            Authorization: `Bearer ${LINE_ACCESS_TOKEN}`,
        },

    });

// ここで音声データもしくは動画データを取得するようにする
```

以上。
問題に対する分析力について

# 良い分析をするための4つの力  

## 分析の目的を把握・設定する力  
> 分析は目的意識を持って実行し、必要な情報をデータから導き出すための方法

## 分析のための仮説を立てる力  
> 良い分析をするためには目的達成のための仮説を立てる力が不可欠です。目的が明確になったら、どのような情報を集めたらよいか・加工が必要かなど具体的なデータ設計ができる

## 必要な情報を整理・加工する力  
> 良い分析をするには情報を上手に取り扱う力が重要です。仮説を検証するために必要な情報が何かを考えて収集し、集計して整理する力

## 解釈して新しい情報を導き出す力
> 高い分析力を持っている人はただ情報を集めて整理・加工できるだけでなく、目的に応じて新しい情報を引き出す力も持っています。加工されたデータを解釈する、あるいは解釈のためにデータを加工することで目的を達成することが可能

# 分析力を鍛えるための、代表的なフレームワーク
## 原因の分析
> 原因に着眼するのは典型的な分析のフレームワークです。物事が起こったのはなぜなのか、起こらなかった理由は何なのかといった視点で分析をします。問題が発生している原因を明確にして対策を立てたいときの基本的なアプローチです。

## 因果関係の分析
> 原因と結果の両方に目を向けて因果関係を分析する手法もよく用いられています。原因が結果につながるまでにはいくつもの段階があり、いろいろな物事が関与しているでしょう。その段階を細かく分けていき、それぞれの段階に何が関与しているのかを分析するフレームワークです。

## 相関分析
> 相関分析は2つの物事に関連性があるかどうかを見極めるためのフレームワークです。要素同士に因果関係を見いだすことができるかを判断したいと考えた時点で用います。統計学の一つである、多変量解析を用いれば2つに限らず多数の物事の関連性を同時に調べることも可能です。そのなかでも特に相関が強い要素を導き出すことができるため、おすすめの分析手法です。

## 環境分析
> 環境分析は物事自体ではなく、その物事の周辺を分析する手法です。企業・サービスの分析を行う際によく使われる３C分析（自社・競合・市場を分析）や、地域把握のためによく使われるPEST分析（政治、経済、社会、技術を分析）などのさまざまなフレームワークがあります。対象となる物事と深い関わりのあるものを取り上げて、相対的な評価をするのが特徴です。目的に応じて照らし合わせる対象を選び出すことが重要になります。

## SWOT分析
> SWOT分析は4つの観点から物事を分析するフレームワークで、環境分析の一つとしても用いられています。

> 強み（Strength）、弱み（Weakness）、機会（Opportunity）、脅威（Threat）について、対象の物事と関連するものとを比較をして分析します。経営やマーケティングの戦略を検討する際によく用いられている方法です。

## プロセス分析
> プロセス分析は業務などの一連の流れを細分化していき、どのような要素がどんな順番で組み合わさっているかを分析する手法です。フロー分析と呼ばれることもある方法で、手順を細かく要素に分けていきます。それぞれについて課題の有無や実績の状況などを集めていき、プロセス全体の改善を図るのが一般的な使い方です。

## 構造分析
> 構造分析は物事の上下関係や関連性について細分化し、部分が全体をつくり上げている構造を導き出すフレームワークです。全体を階層構造やツリー構造で理解し、どこに働きかけると全体にどんな影響を及ぼすかを予測するのに役に立ちます。組織やネットワークを動かす際によく用いられる手法です。

## 時系列分析
> 時系列分析は時間の経過に伴う変化を追う分析のフレームワークです。経時的な変化を追うことでこれからどうなるかを予測するのに用います。株価や為替レートなどのように常に変化する情報を分析するのに適している方法です。

## 定量分析
> 分析のフレームワークとして定量分析も知っておくべきものです。数値化できる指標を用いて分析する方法を一般的に定量分析と呼びます。分析力を高めるための基本的なフレームワークで、統計処理をしたり、グラフ化したりするのが簡単です。ただし、得られる結果も数字なので解釈をする力が求められます。数字のままでは具体的なアクションプランの策定につながりにくいからです。

## 定性分析
> 定量分析と対照的に用いられているフレームワークが定性分析です。性質を解釈することを重視し、数値化できない指標で分析するのが特徴です。定性分析は分析方法自体に人の主観が入りやすく、定量分析のように客観性がない場合があるのが注意点です。良い分析をするには定量分析に基づいて加工された情報を定性的に解釈するのが合理的でしょう。

# まとめ
> 分析力は日々の努力によって培っていくものです。  
> 分析力を高めるのに効果的なのは習慣化を目指し、アウトプットを重視して取り組むことです。どんなに小さなことでも分析してみると意外なほどにたくさんのことを導き出せます。興味を持ったものや仕事に関連がありそうだと感じたものを取り上げて、ここで紹介したフレームワークをいくつか使って分析を試みてみましょう。ふとしたときに頭の中で分析する習慣をつくるだけでも、積み重ねていくと大きな力になります。

> 分析を通して得られた情報を解釈したら、アウトプットしてみることが大切です。言葉にして表現することで内容の正しさを確認できるだけでなく、他の人に聞いてもらうことでフィードバックを受けられます。客観性に欠けていて信用性に乏しい解釈をしてしまうこともよくあります。問題点を指摘して成長させてくれる上司や同僚がいれば分析力のなかでも最も難しいといわれる解釈力も伸びやすくなる。
Windows Tips

## フォルダ移動

### .android の場所移動

* `ANDROID_USER_HOME` を `%HOME%\.android` に設定


### .gradle の場所移動

* `GRADLE_USER_HOME` を `%HOME%\.gradle` に設定

### Docker のイメージ移動

[Windows 10 WSLのイメージ保管先変更](https://zenn.dev/trusted_dream/articles/b7547b732c1d62)
を参考に

```
$ wsl --list
Linux 用 Windows サブシステム ディストリビューション:
Ubuntu-22.04 (既定)
Ubuntu-20.04
docker-desktop-data

$ wsl --export docker-desktop-data "D:\Users\xxx\Containers\data\docker\docker-desktop-data.tar"
エクスポートが進行中です。これには数分かかる場合があります。
この操作を正しく終了しました。

$ wsl --unregister docker-desktop-data
登録解除。
この操作を正しく終了しました。

$ wsl --import docker-desktop-data "D:\Users\xxx\Containers\data\docker" "D:\Users\xxx\Containers\data\docker\docker-desktop-data.tar"
インポート中です。この処理には数分かかることがあります。
この操作を正しく終了しました。

$ wsl --list --verbose  NAME                   STATE           VERSION
* Ubuntu-22.04           Stopped         2
  Ubuntu-20.04           Stopped         2
  docker-desktop-data    Stopped         2
```

### Android SDK の移動

[AppData\Local\Android\](https://developer.android.com/studio/intro/studio-config?hl=ja#optimize-studio-windows)

Android Studio の IDE 設定で 移動

> Android SDK
>    `%USERPROFILE%\AppData\Local\Android\SDK`

### Chocolatey で Emacs インストール時メモ

Chocolateyで emacs29.2 のインストール したら、`C:\tools` にインストールされて調べた。
環境変数 `ChocolateyToolsLocation` に `C:\tools` と設定していたからだった。これを `C:\ProgramData\chocoportable\tools` に変更して対応した。
アンインストール時には `C:\tools` のままにしていないと削除されないので注意。
【Laravel】validationルールまとめ

Laravelのバリデーションルールまとめ

大体は[こちら](https://www.wakuwakubank.com/posts/376-laravel-validation/#index_id14)で紹介されている。

https://www.wakuwakubank.com/posts/376-laravel-validation/#index_id14

これにプラスしたもの↓
```PHP
 'test' => ['sometimes', 'nullable']
```
`sometimes` + `nullable` で、未入力時はバリデーションチェックが行われなくなる。
Let's Encryptの証明書を更新する（DNS）

DNS認証で証明書の期限を更新しましたメモ。

```bash
sudo certbot certonly --manual -d 【ドメイン】 -m 【ドメイン登録メールアドレス】 --agree-tos --manual-public-ip-logging-ok --preferred-challenges dns-01
```

`--preferred-challenges` で `dns-01` を指定することで、DNSでの認証ができるようになる。

`certbot certonly` を実行すると、認証用のトークンが発行されるので、`_acme-challenge.【ドメイン】` のTXTレコードに追加する。
高階関数の単体テストで引数チェックをする際のモック方法


### サンプルの構成
- src/
  - createGreeter.ts // 関数を返す高階関数
  - taroHello.ts // createGreeterを内部で使っている関数
  - taroHello.test.ts

### プロダクトコード

```
type CreateGreeter = (greet: string) => string;

export const createGreeter = (name: string): CreateGreeter => {
  return (greet: string) => {
    return `${name}, ${greet}!`;
  };
};
```

```
import { createGreeter } from "./createGreeter";

export const taroHello = () => {
  const taroGreeter = createGreeter("taro");
  console.log(taroGreeter("hello"));
};
```

### テストコード
```
import { createGreeter } from "./createGreeter";
import { taroHello } from "./taroHello";

jest.mock("./createGreeter"); // createGreeter関数をモックする

test("引数の確認", () => {
  const mockGreeter = jest.fn(); // モック関数を定義
  (createGreeter as jest.Mock).mockReturnValue(mockGreeter); // モック関数を返すように設定

  taroHello();
  expect(createGreeter).toHaveBeenCalledWith("taro"); // createGreeter関数が引数 "taro" で呼ばれたかどうかを確認する
  expect(mockGreeter).toHaveBeenCalledWith("hello"); // mockGreeter関数が引数 "hello" で呼ばれたかどうかを確認する
});
```

`taroHello`を呼び出した時に、内部で使用している関数の引数に想定したものが渡されているかをテストしたいので、

`createGreeter`をモック化し、`mockGreeter`というモック関数を返すようにする

`createGreeter`と`mockGreeter`それぞれの引数をチェックする
dev-camp LaravelとReactでTODOアプリを作成する

## 実施すること
主にReactのコーディングの正解を知る目的で、LaravelとReact（TypeScript）でTODOアプリを作成していきます。

今回は以下のYoutube動画を見ながら、TODOアプリを作成します。
[React + Laravel SPA開発講座](https://www.youtube.com/watch?v=hPjcbKtpTjY&list=PL3B2bjwrmhfQkcBEww0gN_kcRAHntAgxG)

動画ごとに見出し・PRを作成し、（自分用に）概要をまとめながら進めていきます。

## 環境
Laravel - 10.7.1
SQLite - 3.39.5

## #01~03 - アプリケーションのデモ等
### 使用するライブラリ

- [ ] React Query：サーバからデータを取得する際に利用する

- [ ] SQLite
  - 軽量なDB。サーバーとしてではなく、アプリケーションに組み込んで利用する（database.sqliteというファイル）
  - Laravelにも標準で用意されている
  - 【デメリット】ファイル形式なのでセキュリティ対策を自身でする必要がある

## #04 - TODOリスト一覧APIの作成
```php
// リソースコントローラーを使用した場合の書き方
// @see: https://www.wakuwakubank.com/posts/454-laravel-resourcefull-controller/
Route::apiResource('tasks', TaskController::class);
```

## #5 - ユニットテストの設定と実行
sqlite関連のエラーにいくつか遭遇しました。
### 遭遇したエラー
[vendor/bin/phpunit　実行時エラー「Your XML configuration validates against a deprecated schema」の対処法](https://qiita.com/Ayana__1108/items/b7ca46e142dde49e0ccc)
→以下のコマンドで`phpunit.xml`を更新
```
vendor/bin/phpunit --migrate-configuration
```

[【Laravel】『Database does not exist.』エラーの原因と対処法](https://qiita.com/Soh1121/items/aad110b36b0a2f0f6648)
→環境変数の読み込みをなくして直接database.sqliteの完全パスを指定するように修正

## #6 LaravelでCRUD APIの作成
### App\Models カラムの型を指定する場合は$castsを使用する
研修で作成しているアプリのbooleanも0or1で返ってきてしまっているから、この方法でリファクタしてみるのもありかも
```php
    protected $casts = [
        'is_done' => 'bool'
    ];
```

### Laravel10の日本語化
以下のサイトを参考にしました。
[Laravel 9.x validation.php言語ファイル](https://readouble.com/laravel/9.x/ja/validation-php.html)
（Laravel10の[langフォルダはプロジェクトディレクトリ直下という記事](https://biz.addisteria.com/laravel_translation/)も見受けられましたが、上記サイトの方法だとresourcesディレクトリ下でも日本語対応できてますね。。）

## #7 LaravelにReact.jsとTypeScriptをインストール

LaravelにReact.jsとTypeScriptを自身で初インストール。
勉強なる。。

### Viteを使用して開発環境構築
動画ではLaravel Mixを使用していたが、Laravelのバージョン的な問題でViteを使用。

以下の記事を参考に開発環境を構築
[【Laravel9系】 Laravel Sail Viteを使ってReact TypeScriptの開発環境を用意する。](https://saunabouya.com/2022/07/25/laravel9-sail-react-typescript-vite/)
- 研修で作成しているアプリのディレクトリ構造はjsディレクトリ下にtsファイルがあったりするので、今回ディレクトリ構造をきちんと整理できてよかった。

tsファイルの表示が可能な状態まで持ってこれました。

## #10 AxiosとReactQueryでAPIからデータを取得する

### ReactQuery
- データ同期処理に活躍するライブラリ
- 頻繁な更新、キャッシュ、サーバーとの非同期通信時処理のuseEffect, useStateを置き換えて、よりシンプルな書き方にする

以下のサイトがわかりやすい

https://dev-k.hatenablog.com/entry/how-to-use-react-query-deve-k#React-Query%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E7%90%86%E7%94%B1
01 Matrix (Leetcode)

## 今回の問題
leetcodeの01 Matrixをやりました。問題はhttps://leetcode.com/problems/01-matrix/
を参照してください。
ざっくり説明すると、0か1で埋まった二次元配列が渡されるのでそれぞれのますについて0との最短距離を求めるという問題です。

## 元の方針
最初に立てた方針としては
1. 与えられた二次元配列と同じ大きさの配列を作る（0で初期化)
2. 配列を一つずつ見ていって1ならば別で作った再帰関数に入る。
3. 再帰関数では上下左右のマスを見る。0なら1を返す。1ならまた再帰。最初に入った上下左右の返り値で最小のものを配列に代入。

コードは以下のようにしました。
```Python
class Solution:
    def nearest(self, mat, i, j):
        if i >= 0 and i < len(mat) and j >= 0 and j < len(mat[0]):
            if mat[i][j] == 0:
                return 0
            else:
                return 1 + min(self.nearest(mat, i-1, j), self.nearest(mat, i, j-1), self.nearest(mat, i+1, j), self.nearest(mat, i, j+1))
    def updateMatrix(self, mat: List[List[int]]) -> List[List[int]]:
        result = [[0] * len(mat[0]) for i in range(len(mat))]
        for i in range(len(mat)):
            for j in range(len(mat[0])):
                if mat[i][j] == 1:
                    result[i][j] = self.nearest(mat, i, j)
        return result
```

ただこれはうまくいかなかった。再帰関数で上下左右見る時に1が一つでもあると無限ループに入ってしまう。

## 幅優先探索
なので、幅優先探索を用いて実装することにしました。
```Python
class Solution:
    def updateMatrix(self, mat: List[List[int]]) -> List[List[int]]:
        col_len = len(mat[0])
        row_len = len(mat)
        move = [[-1, 0], [0, 1], [1, 0], [0, -1]]
        queue = []
        for i in range(row_len):
            for j in range(col_len):
                if mat[i][j] == 0:
                    queue.append([i, j])
                else:
                    mat[i][j] = "1"
        for i, j in queue:
            for x, y in move:
                col = j + y
                row = i + x
                if col >= 0 and col < col_len and row >= 0 and row < row_len:
                    if mat[row][col] == "1":
                        mat[row][col] = mat[i][j] + 1
                        queue.append([row, col])
        return mat
```
AWS Cloud Questの「File Systems in the Cloud」クエストのエラーを解決

# エラー発生
「File Systems in the Cloud」クエストの「Create file system」で下記のエラーが発生しました。
```
User: ----- is not authorized to perform: elasticfilesystem:TagResource on the specified resource
```
# エラー原因
トレーニング環境のバグみたいです。
# 解決方法
**Nameを空欄にしてAmazon EFSのファイルシステムを作成します。**
※Nameに「PetModels-EFS-1」と入力するよう指示があるけど無視
![スクリーンショット 2023-04-30 170230.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3255462/5d550793-1cb3-b675-f1d2-e53afe56c730.png)
Terraform 変数の値をplan/applyの実行時に指定する方法

Terraformで変数を定義する場合、一般的には下記のように変数の値も一緒に定義する。

```terraform:variables.tf
variable "instance_type" {
  type    = string
  default = "t2.micro"
}
```

一方で、何らかの事情で値を定義せず、外部から指定するようにして柔軟性を持たせたい場合もある。
本記事てはその方法を紹介する。

### 前提: 変数は定義して、値をブランクにしておく
```terraform:variables.tf
variable instance_type {}
```
下記に紹介する方法で変数の値(中身)を指定できるが、変数定義自体は必要なのでこのように定義しておく。

### 方法1: CLIで対話形式で入力する
plan/applyを打つと下記のように対話形式で入力することが可能。
```bash
terraform plan 
var.instance_type
  Enter a value:(ここに入力)
```

### 方法2: -varフラグで指定する
plan/apply実行時に`-var　"変数名=値"`と指定する。
```bash
terraform plan -var "instance_type=t2.micro"
```

変数を複数指定したい場合は`-var　"変数名=値"`の定義を増やす。
```bash
terraform plan -var "instance_type=t2.micro" -var "instance_count=2"
```

### 方法3: 環境変数を利用する
環境変数に`TF_VAR_`というprefixをつけて定義すると、plan/apply時に読み込まれる。
```bash
export TF_VAR_instance_type="t2.micro"
terraform plan
```

### 方法4: ファイルに定義する
`.tfvars`という拡張子のファイルを用意し、そこに値を定義する。
実務ではよく使われる方法だと思う。
```terraform:terraform.tfvars
instance_type="t2.micro"
```

ファイル名は下記の4種類であれば自動的に読み込まれる。
- terraform.tfvars
- terraform.tfvars.json
- *.auto.tfvars
- *.auto.tfvars.json

上記以外のファイル名で定義したい場合、`-var-file`フラグで指定する。

### 値の読み込み順序 = 優先順位
ここまで紹介した値の定義方法には読み込み順序（適用順序）があり、後から読み込まれたものが採用される。

1. 環境変数（= 優先順位が一番低い)
2. terraform.tfvars
3. terraform.tfvars.json
4.　 *.auto.tfvars, *.auto.tfvars.json
5. -var, -var-file　フラグで実行時に与えられたもの(= 優先順位が一番高い)

ちなみに、変数定義時に設定した値は最も優先順位が低く、環境変数の方が優先される。

### 参考
https://developer.hashicorp.com/terraform/language/values/variables#variable-definition-precedence

https://learning-ocean.com/tutorials/terraform/terraform-variable-precedence

https://www.udemy.com/course/terraform-for-beginners-using-google-cloud

https://capsulecloud.io/terraform-variable#index_id7
多次元配列での値代入で連動してしまう（はまったので備忘録）

## やりたかったこと
二次元配列で0で初期化した後に特定の条件の時だけそれぞれ値を代入したかった。

## 書いていたコード
```Python
def updateMatrix(self, mat: List[List[int]]) -> List[List[int]]:
        result = [[0] * len(mat[0])] * len(mat)
        for i in range(len(mat)):
            for j in range(len(mat[0])):
                if mat[i][j] == 1:
                    result[i][j] = self.nearest(mat, i, j)
        return result
```

求めていた出力は以下
```
[[0, 0, 0], [0, 1, 0], [0, 0, 0]]
```
なのに実際に得られた出力は以下の通り。
```
[[0, 1, 0], [0, 1, 0], [0, 1, 0]]
```

## 原因
初期化した時にリスト内の要素が全て同じオブジェクトだと認識してしまう。

## 解決方法
内包表記でリストを初期化すると連動しないらしい。
```Python
result = [[0] * len(mat[0]) for i in range(len(mat))]
```

## まとめ
配列の初期化の際にはまってしまったので気をつける。
vue3 CompositionAPI typescript elementplus

# axios(ajax) でデータを送る


/hoges/test/ に `val` のデータを送る


```
<template>
    <div>
        //ajaxでデータを送る
        <el-input v-model="val" placeholder="Please input" />
        <button @click="send(val)">Send</button>
    </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import axios from 'axios';

const val = ref('');

const send = async (val: string) => {
    try {
        const response = await axios.post('/hoges/test/', {
            val: val
        });
        console.log(response);
    } catch (error) {
        console.error(error);
    }
};
</script>

```
S3バケットキーを有効化してコストを下げよう

# はじめに
今回は、S3のバケットキーの機能を紹介します。
有効化することで、コストを大幅に削減できる可能性のある機能です。

# S3の暗号化方式
・SSE-S3
・SSE-KMS
・SSE-C
・クライアント暗号化
この４つの方式があります。

## SSE-S3
Amazon S3 が管理するキーによるサーバー側の暗号化 (SSE-S3) の方式で、基本的に料金はかかりません。
最近デフォルトでサポートされたので、意識しなければこの方式になるかと思います。

https://aws.amazon.com/jp/blogs/aws/amazon-s3-encrypts-new-objects-by-default/

## SSE-KMS
KMSの顧客管理型CMKを利用した暗号化方式です。SSE-S3とは違い、キーのライフサイクルを利用者自身が管理できるため、暗号化キーの管理を利用者自身が実施したい場合に有効な方式です。
KMSを利用するため、KMSの利用料金がかかります。

## SSE-C
独自のキーを利用した暗号化方式です。
SSE-KMSと似ていますが、顧客管理のキーをKMSではなく、顧客自身が管理してAWSSDK等によりサーバサイドでの暗号化に用います。キーの管理すら、AWSに任せたくない場合などに有効な方式です。

## クライアント暗号化
これは単純にS3に送付する前にクライアント側で暗号化してしまう方式です。
クライアント側でしか復号化したくない場合などに有効でしょう。

# バケットキーって何？
ここまでが前提の話でした。
バケットキーは、上記で説明したSSE-KMSにおいて、暗号化コストを下げるための仕組みです。
バケットキーを有効化すると、S3はKMSから有効期限の短いバケットキーを生成し、S3に一時保存します。
このキーから、新しいオブジェクトのデータキーを生成し、暗号化に利用するという仕組みです。
このバケットキーを用いることで、S3からKMSへのトラフィックを大幅に削減できるため、コストが下がるという仕組みです。

![スクリーンショット 2023-03-18 15.17.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584167/bf6a5aec-9f1e-2df4-0648-3d690148eea0.png)
引用：https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/bucket-key.html

# まとめ
とりあえずSSE-KMSを利用している場合は、問答無用で有効化すればよいかと思います。
SSE-S3を使っている場合には特に設定変更の必要はありませんが、CDKを利用する場合は、デフォルト無効だったかと思いますので、設計の際は気をつけてくださいね。

参考：
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/bucket-key.html
気になるLinuxディストリビューション

# はじめに
<!-- 発端や概要を記載 -->
どうもみなさんこんにちは！！
最近使わなくなったPCがでて、このまま置いておくのももったいないと感じたのでLinuxの勉強がてらにLinuxディストリビューションを入れて見ようと思いました。
業務の中でサーバにCent OSを入れたことがあるのでその時と同じようにLinux環境を作っていきたいと思います。

今回は個人的に気になる・触ってみたいLinuxディストリビューションについてまとめました。各Linuxディストリビューションを見るポイントとして日本語に対応しているか、デスクトップ（GUI）は作成できるのか、パッケージ管理には何を使うのかを重視しています。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [Cent OS](#Chapter1)
1. [Arch Linux](#Chapter2)
1. [Manjaro](#Chapter3)
1. [MX Linux](#Chapter4)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# Cent OS

| 項目 | 内容 | 
| :--- | :--- |
|日本語|パッケージのインストール |
|デスクトップ|あり|
|パッケージ管理|pacman|

**特徴**
* ローリングリリース。
* シンプルで軽量な構造と高度なカスタマイズ→デフォルトでは必要最低限のソフトウェアしか入っていない。ユーザが自分に必要なものを選択し、システムを構築していく。

<a id="#Chapter2"></a>
# Arch Linux

| 項目 | 内容 | 
| :--- | :--- |
|日本語|パッケージのインストール |
|デスクトップ|作成可|
|パッケージ管理|pacman|

**特徴**
* ローリングリリース（大きな単位でまとめて提供するのではなく、小さな更新をこまめに提供する）
* シンプルで軽量な構造と高度なカスタマイズ→デフォルトでは必要最低限のソフトウェアしか入っていない。
* ユーザが自分に必要なものを選択し、システムを構築していく。

<a id="#Chapter3"></a>
# Manjaro

| 項目 | 内容 | 
| :--- | :--- |
|日本語|パッケージのインストール |
|デスクトップ|作成可|
|パッケージ管理|pacman|

**特徴**
* Arch Linuxをベースとした高速で使いやすいデスクトップ指向のOS。
* インストーラが最初から日本語表記。
* ローリングリリースである。

<a id="#Chapter4"></a>
# MX Linux

| 項目 | 内容 | 
| :--- | :--- |
日本語：パッケージのインストール
デスクトップ：作成可
パッケージ管理：apt

**特徴**
* Debian GNU/Linux の安定版をベースとして開発されている中量級の Linux ディストリビューション。
* ユーザー向けの独自のMXツール群を提供している。
* ローリングリリース
* ハードウェアの自動認識



## 最後に
学生時代、ubuntuを使用したことがあったので今回はubuntuを対象から外しました。
Linuxの良さとして自分好みにカスタマイズができるというのはメリットだと思います。
今回調べてみてArchにはない様々な管理、Arch Linuxの難しさの敷居をさげたManjaro、
ちょうどよいLinux感を感じられるMX Linuxがいいなと思いました。

## 参考URL
1. [https://distrowatch.com/index.php?dataspan=52](https://distrowatch.com/index.php?dataspan=52)
2. [https://business.ntt-east.co.jp/content/cloudsolution/ih_column-16.html](https://business.ntt-east.co.jp/content/cloudsolution/ih_column-16.html)
3. [https://www.kagoya.jp/howto/engineer/itsystem/centos/](https://www.kagoya.jp/howto/engineer/itsystem/centos/)
4. [https://wiki.centos.org/Manuals/ReleaseNotes/CentOS6.8/Japanese](https://wiki.centos.org/Manuals/ReleaseNotes/CentOS6.8/Japanese)
5. [https://pc-freedom.net/Linux/manjaro-review/](https://pc-freedom.net/Linux/manjaro-review/)
6. [https://qiita.com/soshi_harami/items/26ae37a1f6417848cff4](https://qiita.com/soshi_harami/items/26ae37a1f6417848cff4)
7. [https://zenn.dev/ytjvdcm/articles/0efb9112468de3](https://zenn.dev/ytjvdcm/articles/0efb9112468de3)
8. [https://pc-freedom.net/today_pc_story/mx-Linux-attraction/](https://pc-freedom.net/today_pc_story/mx-Linux-attraction/)
【Android】Twitter4jのままv2に対応する方法

# はじめに　
Twitter　V2対応、中々大変ですよね。
古いライブラリでありながらも、Twitter4jを使用しているプロジェクトは多いのではないでしょうか？
上記ライブラリから脱却し、根本の実装を変えるとなると中々骨が折れる作業かと思います。
そこでTwitter4jを使用したままv2対応する方法をまとめたいと思います。

# v2対応手順
まず、Twitterのv2に関する詳細は以下をご覧ください。

https://developer.twitter.com/ja/docs/twitter-api

基本的に認証後に呼び出しているAPIが対象になります。
Twitter4jを使用して認証後にユーザー情報取得したりしている部分があれば差し替えが必須となります。

さて、v2対応を行うためにはまず以下ライブラリを導入する必要があります。

https://github.com/takke/twitter4j-v2

導入は以下をapp/build.gradleに追加するだけです。
```build.gradle
    implementation "io.github.takke:jp.takke.twitter4j-v2:1.4.1"
```

導入作業としては以上になります。
導入したあとは以下を参考に、自身の実装で当てはまるものを置き換えるだけになります。

https://github.com/takke/twitter4j-v2#supported-apis

例えば認証したユーザーのユーザー情報を取得したければ以下の通り置き換えてあげる形になります。

```
twitter.verifyCredentials()
// 上記から以下へ定義を変更
twitter.v2.getMe().users.first()
```

以上です。
ご紹介のライブラリを使用することでTwitter4jの機能を流用しながらv2対応が可能です。
とはいえTwitter4jも古いライブラリなので、時間をかけて新しい実装へ置き換えてあげる必要はあると思います。
その辺りも含めご検討くださいー

# さいごに
時間の経過の速さを最近はより一層感じますね、、、
RPLidar A1M8をROS2で動かす

# やったこと
RPLidar A1M8をROS2で動かしてみました。意外とROS2でのやり方は情報がなかったのでまとめてみます。
![スクリーンショット 2023-04-30 16.08.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512829/96cc4d00-2a92-606d-fd2c-f1d7f9772389.png)


# 環境
- [RPLidar A1M8](https://amzn.to/41SRGWA)
- Ubuntu 22.04.2 LTSをインストールしたPC
- zsh
- ROS2 Humble

:::note info
基本的には[sllidar_ros2リポジトリ](https://github.com/Slamtec/sllidar_ros2)のインストール方法通りに進めれば問題ないですが、つまづいたポイントだけ書きます。
:::


# 1) ROS2インストール
[ROS2 Humble Binary](https://github.com/ros2/ros2/releases/release-humble-20230213)を入手して[ROS2 Humble Binary Ubuntuへのインストール](https://docs.ros.org/en/humble/Installation/Alternatives/Ubuntu-Install-Binary.html)のやり方に沿えばいいのですが、以下のコマンドでエラーがでたのでオプションを追加しました。

``` shell:エラーが出た
rosdep install --from-paths ~/ros2_humble/ros2-linux/share --ignore-src -y --skip-keys "cyclonedds fastcdr fastrtps rti-connext-dds-6.0.1 urdfdom_headers"
```

``` shell:正常に動いた
rosdep install --from-paths ~/ros2_humble/ros2-linux/share --ignore-src -y --skip-keys "cyclonedds fastcdr fastrtps rti-connext-dds-6.0.1 urdfdom_headers" --rosdistro humble
```
:::note info
[ROS2 Humble Configuration](https://docs.ros.org/en/humble/Tutorials/Beginner-CLI-Tools/Configuring-ROS2-Environment.html)がsllidar_ros2リポジトリのインストール手順にあるのですが、環境変数の確認だけなのでやらなくても動作はします。
:::

シェルにzshを使ったので（なんかかっこいいから？）、以下のコマンドでROS2環境をセットアップする必要があります。
``` zsh:ROS2セットアップ
source ~/ros2_humble/ros2-linux/setup.zsh
```

# 2） ROS2ワークスペース作成
これは[ROS2 Humble Workspaceの作り方](https://docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Creating-A-Workspace/Creating-A-Workspace.html)のやり方をそのままやればよく、特につまづくことはなかったです。

# 3) sllidar_ros2パッケージインストール
[sllidar_ros2リポジトリ](https://github.com/Slamtec/sllidar_ros2#compile--install-sllidar_ros2-package)のやり方に従って進めますが「3.Package environment setup」はzshのスクリプトを使います。

``` zsh:パッケージ環境セットアップ
source ./install/setup.zsh
```

# 4） RPLidar A1M8をPCに接続
一点つまづいたのが、最初使っていたマイクロUSBケーブルがダメだったようで正しくPCに認識されませんでした。ケーブルを交換すると中間の基板のLEDが点灯して正常に /deb/ttyUSB0 として認識されました。ROS2がアクセスするためにパーミッションを変更する必要があります。

``` zsh:デバイスのパーミッション変更
sudo chmod 666 /dev/ttyUSB0
```
:::note info
Lidarのモーターがウィンウィン動くので初めてだとびっくりするかもしれません。
:::

# 5） rvizで表示
以下のコマンドで rviz が現れて正常動作していれば部屋の形状が赤い点で現れると思います。

``` zsh:ROS2でrviz起動
ros2 launch sllidar_ros2 view_sllidar_launch.py
```

:::note info
うぉーちゃんと動いたー！という感動が得られます。
:::

# 参考
[RPLidar A1 M8で部屋の地図を作成しよう!](https://qiita.com/MMM-lab/items/5dab0a9e9e3bf41f5e85)
[SLAMTEC公式](https://www.slamtec.com/en/Support#rplidar-a-series)

# 所感
まあ案外楽に動いたなという印象です。マイクロUSBケーブルが腐っていたことになかなか気が付かなかった。。。Lidarのデータは取れるようになったので、今度はマップでも作ってみようと思います。
GitHub コミットメッセージの修正方法

## はじめに

Git、GitHub初心者の備忘録です。

いつかやると思ってましたが、
とうとうコミットメッセージの内容を打ち間違えました。
修正する方法がちゃんとありましたので、記録します。

## 修正したいコミットメッセージを確認しよう

#### コミットまでの流れ

まずは編集したファイルをステージングエリアに追加
```zsh
git add test.txt
```

コミットメッセージを記入して、リモートリポジトリへコミット
```zsh
git commit -m "3行目をすいか"
```
気づいた瞬間には、勢い余ってEnterーーー
`追加`と入力したかったのですが、`すいか`になってしまいました🍉

#### コミットメッセージを確認する

見間違いかもしれない（と思いたい）ので、
以下のコマンドで、直前のコミットメッセージを確認します。
```zsh
git log --oneline -1

# 出力結果 => e7e0000 3行目をすいか
```
`--oneline` は、Gitのコマンドで使われるオプションの一つです。
`git log` コマンドにこのオプションを付けて実行すると、
コミットのログを1行にまとめて表示してくれます。

具体的には、コミットのハッシュ値と、コミットメッセージの最初の一行だけを表示してくれます。
これによって、長いコミットメッセージを読む必要がなくなり、コミットの履歴をスピーディーに確認することができます。

ちなみに、`-数値`とオプションを追加することで、
指定した数値分だけ、コミットの履歴を確認してくれます。

で、
やっぱり`すいか`だったので、修正します🍉🍴

## 直前のコミットメッセージを修正しよう

#### 直前のコミットメッセージを修正

以下のコマンドで、直前のコミットメッセージの修正ができます。
```zsh
$ git commit --amend -m "新しいコミットメッセージ"
```
（ちなみに「amend」は「正す」という意味です。）

なので、今回はこうなります。
```zsh
$ git commit --amend -m "3行目を追加"
```
修正できたか、確認します。
```zsh
git log --oneline -1

# 出力結果 => e7e0000 3行目を追加
```

修正されています🙆
これで無事にリモートリポジトリへプッシュするだけです。


## おわりに

これを覚えれば、今後は焦らなくて済みそうです！
きちんと確認して、打ち間違いしないようにするのが一番ですが…

すでに公開されたリポジトリのコミットや、
複数人で共有しているリポジトリにプッシュされたコミットは
修正を推奨されていないようですので、
気をつけたいと思いました！
（コンフリクトがなんちゃららしいのですが、もう少し勉強します。）
複数キーのインデックスのパフォーマンス

複数キーでユニークになるテーブルにインデックスを作成するときに一番多いユースケースはそのうちの一部のキーである場合に、その一番多いユースケースのキーだけのインデックスを作るべきか迷ったので簡単なテーブルで実験してみました。

## DDL

```sql
CREATE TABLE test_tbl(
  col1 BIGINT,
  col2 BIGINT,
  col3 BIGINT,
  col4 BIGINT,
  col5 VARCHAR(255)
);

CREATE INDEX ui ON test_tbl(col1,col2,col3,col4);
```


## データ

800万件のデータで実験してみました。

| キーの組み | カーディナリティ |
| --- | --- |
| col1 | 25% |
| col1, col2 | 1.25% |
| col1, col2, col3 | 0.00625% |
| col1, c0l2, col3, col4 | 一意（0.00125%） |

（最初は100万件のデータでやるつもりでしたが間違えて800万件作ってしまいました）

## 結果

結果としては一部キーしか使わなくても私のケースでは十分に検索のパフォーマンスは出る、というものでした。（一応全部の行に載せていますが、インデックスがない時のパフォーマンスは検索対象のカラムによる影響はほぼなかったです）

| where 条件 | index | no index |
| --- | --- | --- |
| col1 | 1 m 22 s | 21 s|
| col1, col2 | 1 m 20 s | 0.01 s|

なんでこうなるのか？というところは相変わらず曖昧なままだったのでもう少し別の角度から調査をしたいと思います。具体的にはBTREEのアルゴリズムをちゃんと理解するとこの辺の予測もしやすくなりそうなのでBTREEを深掘りしたいと思います。

### ちなみに色々な組み合わせの結果

col1, col3 のように間を飛ばしたりするともうちょっとパフォーマンス落ちるのかなと思いましたが組み合わせによってはそうでもない感じでした。この辺はデータの入り方にもよると思うのですがBTREEアルゴリズムを理解しているともう少し想像と実際の乖離が少なくなるのかもしれないと期待しています。

| where | index | no index |
| --- | --- | --- |
| col1, col3 | 1 m 20 s | 0.32 s|
| col1, col4 | 1 m 20 s | 15.25 s|
| col2, col3 | 1 m 20 s | 0.05 s|
| col2, col4 | 1 m 20 s | 0.00 s|
| col3, col4 | 1 m 20 s | 0.88 s|
| col2 | 1 m 20 s | 0.04 s|
| col3 | 1 m 20 s | 0.85 s|
| col4 | 1 m 20 s | 1 m 9 s|

## データの作成

Haskell で Bulk Insert の SQL ファイルを生成する簡単なスクリプトを作りました。

```sql_generator.hs
import Data.List (intercalate)
import System.Directory.Internal.Prelude (getArgs)

col2 :: Int -> [Integer]
col2 n
  | n `mod` 4 == 1 = [1..500]
  | n `mod` 4 == 2 = [501..1000]
  | n `mod` 4 == 3 = [1001..1500]
  | otherwise = [1501..2000]

col234Values :: [Integer] -> [Char]
col234Values a = intercalate "," (map show a) ++ ", '" ++ ['A'..'z'] ++ "'"

toValues :: String -> [String] -> String
toValues col1  s = intercalate ",\n" (map (\s -> "    (" ++ col1 ++ "," ++ s ++ ")") s)

main = do
  (inputStr:_) <- getArgs
  let input = read inputStr
  let col1 = ((input-1) `div` 4) + 1

  let d = [[a,b,c] | a <- col2 input, b <- [1..200], c <- [1..5]]
  let t = map col234Values d
  let v = toValues (show col1) t
  putStrLn "INSERT INTO test_tbl(col1, col2, col3, col4, col5) VALUES"
  putStrLn v
  putStrLn ";"
```

```shell
seq 16 | xargs -I@ -P4 bash -c "runghc sql_generator.hs @ > data@.sql"

seq 16 | xargs -I@ echo "mysql -u root -ppassword test < data@.sql" | bash
```
awkコマンド使ってみた

# 背景
テキストファイルからある列を抽出、加工したりする処理は基本Pythonを使って自動化してきたけど、Linuxサーバーをいじったりすることが多くなって、Linuxコマンドの出力結果について、ちゃちゃっと操作したいなって思うことが増えてきた。
調べたらAwkコマンドというのが便利らしいと知ったので、使ってみる。

# Awkとは
テキスト処理ツールの一種で、行単位でテキストを処理するために使用されるスクリプト言語。行指向の処理が得意なため、UNIXやLinuxシステムで非常に便利。
パターンマッチングとアクションの組み合わせでテキストを抽出・加工・変換が可能。

**使い方**
`awk [options] 'pettern {action}' 標準入力`
※区切り文字を指定しない場合は、スペースが指定される。

**組み込み変数**
* `\$1, \$2, ..., \$n`
    第N列目のデータ（１始まり）
* `NF`
フィールド（列）の数（１始まり）
* `NR`
行番号（１始まり）

# 実際に使ってみる
## 基本的な使い方
`ls`の結果をいじってみる。
```terminal
$ ls -l
drwx------@  70 test1  staff     2240 Apr 29 20:13 Desktop/
drwx------@  17 test2  staff      544 Apr 29 21:12 Documents/
drwx------@ 142 test3  staff     4544 Apr 29 21:36 Downloads/
```
* まずは、所有者だけ抜き出してみる。（第２フィールド）
```terminal
$ ls -l | awk '{print $3}'
test1
test2
test3
```
何も指定していないので、フィールドの区切り文字はスペース。
→csvファイルだったら、こんな感じ`ls -l | awk -F "," '{print $3}'`

* 次に、所有者が`test2`の時だけ、行ごと出力する。
```terminal
$ ls -l | awk '$3 == "test2" {print}'
drwx------@  17 test2  staff      544 Apr 29 21:12 Documents/
```

* ファイルサイズが2000以上の行を出力する。
```terminal
$ ls -l | awk '$5 >= 2000 {print}'
drwx------@  70 test1  staff     2240 Apr 29 20:13 Desktop/
drwx------@ 142 test3  staff     4544 Apr 29 21:36 Downloads/
```

* 奇数行目だけ出力
```terminal
$ ls -l | awk 'NR%2!=0 {print}'
drwx------@  70 test1  staff     2240 Apr 29 20:13 Desktop/
drwx------@ 142 test3  staff     4544 Apr 29 21:36 Downloads/
```

パターンで**正規表現**も使用できるようなので、使ってみる。
使い方：patternのところが→`$n ~ "正規表現"`

`ls`の結果が下記だとする。
```terminal
$ ls -l
drwx------@  70 test1  staff     2240 Apr 29 20:13 Desktop/
drwx------@  17 test2  staff      544 Apr 29 21:12 Documents/
drwx------@ 142 testtest3  staff     4544 Apr 29 21:36 Downloads/
```
* 所有者が`test + 数値`になってる場合のみ行を出力したい。
```terminal
$ ls -l | awk '$3 ~ "^test[1-9]+" {print}'
drwx------@  70 test1  staff     2240 Apr 29 20:13 Desktop/
drwx------@  17 test2  staff      544 Apr 29 21:12 Documents/
```
→testtest3の行は表示されてない。

## 区切り文字の指定`-F`
オプション`-F`を使うと、区切り文字の指定ができる。
例としてユーザ情報`/etc/passwd`からユーザ名を取り出してみる。

※`/etc/passwd`はユーザ情報が↓の形式で保存されている。
`ユーザ名:パスワード:UID:GID:連絡先:ホームディレクトリ:ログインシェル`
```terminal
$ cat /etc/passwd # 中身はダミー
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
hoge:x:4:7:hoge hoge:/var/spool/lpd:/sbin/nologin
```
まず、`-F`オプションを指定せずに実行
```terminal
$ cat /etc/passwd | awk '{print $1}'
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
hoge:x:4:7:hoge
```
↑出力結果を見ると、区切り文字がデフォルトの空白になっているため、うまくいかない。
（一番下の`hoge`の行に空白が含まれているので、中途半端なところで区切られている。）

なので、`-F`で区切り文字を指定
```terminal
$ cat /etc/passwd | awk -F':' '{print $1}'
root
bin
daemon
adm
lp
hoge
```
区切り文字を`:`にしたのでうまくいった！

# 感想
かなり便利！
ばんばん使ってきたい。
awkは言語だから他にもいろいろできる。また、何かあったら他の使い方も調べてみよ。
Github ActionsにおけるGITHUB_SHAとGITHUB_REF

## はじめに
GitHub Actionsの環境変数を利用したい時にややこしいと感じた為イベントごとにまとめてみました。

## GitHub Actionsとは
https://docs.github.com/ja/actions/learn-github-actions/understanding-github-actions#overview
> GitHub Actions は、ビルド、テスト、デプロイのパイプラインを自動化できる継続的インテグレーションと継続的デリバリー (CI/CD) のプラットフォームです。 リポジトリに対するすべての pull request をビルドしてテストしたり、マージされた pull request を運用環境にデプロイしたりするワークフローを作成できます。

Github上でワークフローを作成してそれを様々なタイミングで実行できるCI/CDのプラットフォームです

テストの自動化だったりチームのレビュー運用だったりをカスタマイズできます

## GitHub Actionsのイベント

GitHub Actionsの実行をトリガーできるイベントで代表的なものは以下になります

|イベント  |実行タイミング  |
|---|---|
|push  |リポジトリにpushされたとき  |
|pull_reqest  |Pull Requestがオープン、更新、クローズされたとき  |
|release  |リリースが公開されたとき  |
|schedule  |定期的に実行  |
|workflow_dispatch  |手動で実行  |

https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows

## 環境変数
GHAのワークフローでは、以下のように独自に環境変数を定義して使用する事ができます

```.yml
env:
    MY_VAR: "my value" # 環境変数を設定
steps:
- name: Example step
  run: echo $MY_VAR # step内で環境変数を使用
```

ただ、独自に定義する環境変数とは別にGHAでトリガーできる多くのイベントに``GITHUB_SHA``と``GITHUB_REF``が設定されています

``GITHUB_SHA``と``GITHUB_REF``は以下のような特徴があります

#### GITHUB_SHA
現在実行中のコミットのSHA値（ハッシュ）を表します
これは、GitHub Actionsがビルド、テスト、デプロイなどのアクションを実行する際に、**どのコミットが実行されているかを識別するため**に使用されます

#### GITHUB_REF
現在実行中のGitリポジトリのブランチ名、タグ名、またはプルリクエストブランチ名を表します
これは、GitHub Actionsが実行される**リポジトリのブランチやタグに基づいて、異なる処理を実行する必要がある場合**に使用されます



## トリガーごとの``GITHUB_SHA``と``GITHUB_REF``

``GITHUB_SHA``と``GITHUB_REF``はトリガーしたイベントごとに中身が変わります。各イベント(一部)のそれぞれの値をまとめたものになります

:::note warn
``pull_request``ではマージ時とそうでない時で値が変わるので注意
:::

| イベント | GITHUB_SHA | GITHUB_REF |GITHUB_REF 例|
|:-:|:-:|:-:|:-:|
|``push``|最新のコミットのSHA値   |ブランチ名またはタグ名   |refs/heads/main または refs/tags/v1.0.0|
|``pull_request``<br>(opened,synchronize,close(クローズ))   |PRの最後にpushされたコミットのSHA値|PRが作成されたブランチ      |refs/heads/feature-branch|
|``pull_request``<br>(close(**マージ**))|**PRのマージコミットのSHA値**|**PRのマージ先ブランチ名**  |**refs/heads/main**|
|``release``|リリースを作成したコミットのSHA値   |タグ名   |refs/tags/v1.0.0|
|``schedule``|スケジュールされたジョブを実行するときのSHA値   |ブランチ名またはタグ名   |refs/heads/main または refs/tags/v1.0.0|
|``workflow_dispatch``|手動でトリガーされたジョブを実行するときのSHA値   |ブランチ名またはタグ名   |refs/heads/main または refs/tags/v1.0.0|

## pull_requestの環境変数

``pull_request``イベントでは、比較先(base)ブランチと作業(head)ブランチを判別できる環境変数を使用する事ができます

https://docs.github.com/en/webhooks-and-events/webhooks/webhook-events-and-payloads#pull_request

以下がそれぞれの概要になります
(mainブランチに対してfeatureブランチを作成している場合)



| 環境変数 | 概要 | 値 |
|:-:|:-:|:-:|
| ``GITHUB_BASE_REF``| 比較先のブランチ|refs/heads/main|
| ``GITHUB_HEAD_REF``| 作業ブランチ|refs/heads/feature-branch|

## まとめ
Github Actionsでは様々なイベントをトリガーでき、その中で様々な環境変数を使用する事ができます。

使用する値の中身を確認する作業が結構大変で、マージかそうで無いかでも違ったりして場合分けが複雑なので使用する時は場合分けと使用する値を整理していきたいと思います。
WSL2+docker+GPU環境構築(win11)

# 3行で
* まずWSL2とWindows用のGPUドライバを入れる(WSLからlinux用のドライバは**入れない**)
* docker desktopをインストールする
* nvidia-container-toolkitを入れる

# WSL2の導入~GPUドライバの導入
https://learn.microsoft.com/ja-jp/windows/ai/directml/gpu-cuda-in-wsl

↓公式を読むのがめんどい人向け
## GPUドライバをインストール
まず注意。WSLからドライバをインストールしないように
>This is the only driver you need to install. Do not install any Linux display driver in WSL.
>https://docs.nvidia.com/cuda/wsl-user-guide/index.html#step-1-install-nvidia-driver-for-gpu-support

windows用のドライバでWSL内でも認識するようです。
以下から自分のPCに入っているGPUに対応するドライバをインストールしてください
https://www.nvidia.com/Download/index.aspx

ちなみに、今有効なGPUはタスクバーの検索から「dxdiag」って検索して出てくるツールで調べられます

## WSL2をインストール
win11ならコマンドプロンプトで以下を入力するだけ
```
wsl --install
```
再起動するとubuntuでのユーザー名・パスワードを聞かれるので設定すればOK


ここまででWSL内でGPUを認識するようになってます。WSLのターミナルで
```
nvidia-smi
```
のコマンドをうってGPUの情報が返ってくれば成功してます。

うまくいかない場合・・・残念でした。
俺もnvidiaに何日休日を溶かされたか・・・。
実はこの記事を書く前にも一度win11を再インストールしました。結局それが一番早かったです。

# docker desktopのインストール
https://learn.microsoft.com/ja-jp/windows/wsl/tutorials/wsl-containers

↓公式を読むのがめんどい人向け
・・・といってもdocker desktopをインストールするだけです。
WSLからdockerをインストールすることはありません。

https://docs.docker.com/desktop/windows/wsl/#download


# nvidia-container-toolkitのインストール

https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#setting-up-nvidia-container-toolkit

↓公式を読むのがめんどい人向け

WSLで以下を実行

```bash
distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
      && curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
      && curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
            sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
            sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
```

```bash
sudo apt-get update
```

```bash
sudo apt-get install -y nvidia-container-toolkit
```

以上です。

成功していれば以下のコマンドが通ります
※公式には`--runtime=nvidia`オプションがついていますが**消さないと通りません**
※nvidiaほんま許さんぞお前
```bash
sudo docker run --rm --gpus all nvidia/cuda:11.6.2-base-ubuntu20.04 nvidia-smi
```