OmniAICreator/Qiita-1.07M huggingface dataset:
準同型定理の簡単なイメージ

代数で習う準同型定理というのは最初よく分からなかったので、個人的に分かりやすいと思う例をご紹介したいと思います。


# (群)準同型

２つの群$(G,\cdot)$、$(H,*)$が存在するとき関数

```math
f:G\rightarrow H
```
が群準同型であるとは、$f$が

```math
\forall g_1,g_2 \in G, \quad f(g_1\cdot g_2) = f(g_1)*f(g_2)
```

を満たすことである。

# 準同型定理

準同型写像$f:G \rightarrow H$に対して剰余群

```math
G' = G/\mathrm{Ker}(f) = \{ [g] = (g\cdot g_0 | g_0 \in \mathrm{Ker}(f) ) | g \in G \}
```

を定義します。ここでカーネルは

```math
\mathrm{Ker}(f) = \{ g \in G | f(g) = 0 \}
```

であり、$G'$の要素は上記の書き方だと重複がありますが、その分は取り除きます。また、

```math
[g_1], [g_2] \in G'
```

に対して、

```math
[g_1]\circ [g_2] = [g_1 \cdot g_2]
```

で演算を定義すると、これはwell-definedであって、$(G',\circ)$は群になります。

このとき、次の関数

```math
\tilde{f} = G' \rightarrow H: \\

\tilde{f}([g]) = f(g)
```

は同型(＝逆関数が存在してそれも準同型)である。

# 例：１次関数の微分積分

$G$を1次関数全体

```math
G = \{ ax+b | a,b \in \mathbb{R} \}
``` 

$H=\mathbb{R}$とします。

そして $F:G \rightarrow H$を微分
 
```math
F[f(x)] = \frac{df}{dx}
```

で定義します。すると$F$は$(G,+)$,$(H,+)$に対して準同型写像となっています：

例えば、$x+2,2x+3 \in G$に対して、

```math
F[ (x+2) + (2x+3) ] = \frac{d}{dx}(x+2) + \frac{d}{dx}(2x+3) \\
= \frac{d}{dx}(3x+5) = F(3x+5) = 3
```

です。ここまでは自明ですね。

一方、例えば$F[f(x)]=3$となる$f(x) \in G$は無数にあって、１つに特定できないので、$F$の逆関数は定義できません。
こういうとき不定積分$3x+const.$を考えると思いますが、これを数学的にちゃんと定義したのが剰余類です。

定数を微分すると$0$になるので、今

```math
\mathrm{Ker}(F) =\mathbb{R}
```

となります。よって、剰余群は

```math
\begin{align}
G' &= G/\mathrm{Ker}(F) = G/\mathbb{R} \\
[f(x)] &= \{ f(x) + c | c \in \mathbb{R} \} = \{ f(x) + const. \}\in G'
\end{align}
```

です。つまり、$f(x)$に適当な定数を足したものの集合が$[f(x)]$です。

すると、$\tilde{F}:G' \rightarrow H$は同型写像になります。$\tilde{F}$は

例えば

```math
\begin{align}
\tilde{F}^{-1}(3) &= [3x] = 3x + const. \\
\tilde{F}([3x]) &= \frac{d}{dx} (3x+const.) = 3
\end{align}
```

なので、１－１対応が満たされています。

もうお気づきかと思いますが、$\tilde{F}^{-1}$というのは不定積分になります。確かに不定積分なら微分した後のものと１－１で対応していますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2445529/5e1b85d6-0a67-f8d2-f71e-2bb2e38b467c.png)


# まとめ

ざっくり言うと、剰余類は不定積分を一般化したものであり、
「定積分はそれを微分したものと1-1対応していないけれど、不定積分なら1-1対応している」
ということを言っているのが準同型定理です。

微分積分に限らず、このように不定性をもつものはいたるところに現れるので(たとえばホモロジー、整数の割り算の余り、etc.)、

https://qiita.com/hiro949/items/9c793415313be6312154

そういうとき、その不定性を取り除いて話をスッキリさせることができるのが準同型定理のメリットだと思います。
ブラウザのパスワードマネージャーに任意のIDを覚えさせる

# ブラウザのパスワードマネージャーに任意の値を覚えさせたい

ブラウザがID（ユーザー名）とパスワードを保存してくれる機能があります。
ユーザー登録フォームを作っていた時に、その機能が覚えてほしいIDを覚えてくれなかったので、任意のものに変更できないかと探った時の備忘録です。

## よくあるNG例

````ng-form.html
<form>
    <input type="text" name="id" />
    <input type="text" name="name" />
    <input type="password" name="password">
</form>
````
たぶんよくあると思うんですけど、ユーザーにIDを登録させて、それとは別に氏名を登録させるタイプのフォームです。
でもログインにはIDとパスワードを用いてほしい。
この場合、私がそうだったのですが、氏名の方がブラウザのパスワード管理機能に登録されてしまうんですよね。

## OK例

````ok-form.html
<form>
    <input type="text" name="id" />
    <input type="text" name="name" />
    <!-- 下のIDは上のIDと同じ値を持たせてください -->
    <input type="text" hidden name="id" autocomplete="username" />
    <input type="password" name="password">
</form>
````

### 必要な要素
- 非表示でパスワードマネージャーに登録したい要素をパスワードの直前に置く
- 登録したい要素にautocomplete="username"を追加する

### 検証と考察
ブラウザのパスワードマネージャーはIDだったりをどう認識、検知、判断しているのか？
パスワードの直前にあるinput要素を参照
→ブラウザによって非表示を無視するパターンと無視しないパターンがある
デザインなどの事情で直前に配置できないことも多々あると思います。
autocomplete="username"をもたせるとパスワードの直前にあるinput要素でなくても優先してくれたので、その両方を入れることで対応しました。
ブラウザごとの仕様を知っている方がいたら是非教えてください……。。。


## autocompleteについて
autocompleteそのものについてのドキュメントは以下です
https://developer.mozilla.org/ja/docs/Web/HTML/Attributes/autocomplete
これを参照すると、name="neme"がいたからidより優先されてしまったのかな…と思います
usernameはユーザー名またはアカウント名を指すようなので。

この属性は、ブラウザに住所などなどを覚えてもらうときにも重宝しそうです。
日記2 - SNSアプリ開発

勤務中に検索し放題なのが助かる。
ただ、動画は見れない。Youtubeみれたら勉強はかどるのに。
まあ、検索し放題なだけでも恵まれてるから満足しとこう。

## 参考動画
[Flutter Tutorial for Beginners - Build iOS and Android Apps with Google's Flutter & Dart
](https://www.youtube.com/watch?v=GLSG_Wh_YWc&t=369s)

## 今日したこと
I setup watching following video ~ 56:00
[Flutter Tutorial for Beginners - Build iOS and Android Apps with Google's Flutter & Dart
](https://www.youtube.com/watch?v=GLSG_Wh_YWc&t=369s)
```
Flutter
VScode
Git for windows 2.x
Windows PowerShell 5.0
Android Studio
```

## 不明点
環境変数にANDROID_HOMEを設定する必要があるのかが分からない。
ANDROIDのSDKファイル設定時に、デフォルトのまま変えてなかったら、設定しなくてもいいっぽい。しかし変えたか変えてなかったか忘れてしまってる。多分変えてない。変えてなかったことにしとこう。

## 便利メモ
cmd(command prompt)では Ctrl + C で実行中のプログラムを停止できる。

## 明日すること
動画見進める 56:00 ~
[Flutter Tutorial for Beginners - Build iOS and Android Apps with Google's Flutter & Dart
](https://www.youtube.com/watch?v=GLSG_Wh_YWc&t=369s)
nvmのデフォルトのバージョンの変え方

# コマンドでデフォルトのバージョンを変更

ターミナルでコマンド
`nvm alias default v[version]`
を実行。
例：`nvm alias default v18.9.0`

結果：ターミナルを開き直して `nvm ls` を実行するとdefaultのバージョンが変わる。
【備忘録】テキスト原稿からタグをマークアップしていく僕へ【Wrap with Abbreviation】

# 前書き
wordで原稿を渡され、適度にタグの指定の方法も定型化されてなくて一括で置換もできないあのときの僕へ
こんなものもあるよ
### *Wrap with Abbreviation*

# 導入方法
## キーボードショートカットを設定
キーボードショートカットを開きましょう
![キーボードショートカット.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2528995/f5c9f5d8-7b16-33aa-41f6-6f6524dd0a15.jpeg)
こちらで「emmet wrap」で検索をし「Emmet:wrap with Abbreciation」のショートカットキーを設定しましょう

導入は以上です！（そもそも初期からの機能なのでショートカットキー設定しただけです）

# 使用
囲いたい文字列を選択肢し先程設定したショートカットを設定します。
![emmet wrap.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2528995/004f9d4f-b6a7-bb4f-9d5d-a3ab49cb74cc.jpeg)
たとえば「ul.test>li*.test」と入力すると...
![ul.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2528995/79d58798-6531-6b13-c471-7ad1d594f0f2.jpeg)
ulのリストにすることができました。

こちらを使用することで平打ちされたテキストからHTMLのマークアップ作業を行う効率が段違いになりました。
（そもそも定型化されて置換可能な原稿がほしいが。。。）
Rails 月ごとのデータを出すときに31日のデータがなかったのでメモ

投稿を月ごとに表示させたかったが31日のデータが表示されなかったので色々試した
結果的に発行されるSQLクエリが問題だった

## 元のコードとクエリ
```ruby:config/application.rb
config.time_zone = 'Asia/Tokyo'
config.active_record.default_timezone = :local
```

```ruby:controller
@month = params[:month] ? Date.parse(params[:month]) : Date.today
@diaries = current_user.diaries.where(created_at: @month.all_month).order(created_at: :asc)
```
```sql
SELECT "diaries".* FROM "diaries" WHERE "diaries"."user_id" = ? AND "diaries"."created_at" BETWEEN ? AND ? ORDER BY "diaries"."created_at" ASC  [["user_id", 13], ["created_at", "2022-08-01"], ["created_at", "2022-08-31"]]
```
これだと`` 2022-08-31の00:00:00 ``までのデータを取得することになるせいで31日のデータが得られない

## 解決
```ruby
@diaries = current_user.diaries.where(created_at: @month.in_time_zone.all_month).order(created_at: :asc)
```
```sql
SELECT "diaries".* FROM "diaries" WHERE "diaries"."user_id" = ? AND "diaries"."created_at" BETWEEN ? AND ? ORDER BY "diaries"."created_at" ASC  [["user_id", 13], ["created_at", "2022-07-31 15:00:00"], ["created_at", "2022-08-31 14:59:59.999999"]]
```
これで時間までを検索に入れることが出来て31日の最後の時間までが得られた

## 解決までの道のり
理由がわからなかったのでとりあえずタイムゾーンを戻してみた
→ダメ

all_monthがダメなのかとコードを変更
```ruby:
@diaries = current_user.diaries.where(created_at: @month.beginning_of_month...@month.end_of_month).order(created_at: :asc)
```
結果変わらず
ここではじめてSQLを確認したら
`` "created_at" >= ? AND "diaries"."created_at" ``だったので調べてみる
`` >= ``がcreated_atまでってことだと分かったので次の日を指定してあげれば！？ってことで修正
```ruby
@diaries = current_user.diaries.where(created_at: @month.beginning_of_month...@month.next_month.beginning_of_month).order(created_at: :asc)
```
31日も表示された！！！！
と思ったけどTimezoneを東京に戻してみたら時差分の9時までが先月分になってしまった

ここからDBのwhereを日本時間にしようとしたりいろいろ検索してだいぶ時間がかかった
どこかの記事でall_monthの前に`` in_time_zone ``を入れているのを発見して解決

Timezoneの比較
```sql
デフォルト
SELECT "diaries".* FROM "diaries" WHERE "diaries"."user_id" = ? AND "diaries"."created_at" BETWEEN ? AND ? ORDER BY "diaries"."created_at" ASC  [["user_id", 13], ["created_at", "2022-08-01 00:00:00"], ["created_at", "2022-08-31 23:59:59.999999"]]

東京
SELECT "diaries".* FROM "diaries" WHERE "diaries"."user_id" = ? AND "diaries"."created_at" BETWEEN ? AND ? ORDER BY "diaries"."created_at" ASC  [["user_id", 13], ["created_at", "2022-07-31 15:00:00"], ["created_at", "2022-08-31 14:59:59.999999"]]
```

解決まで6時間もかかってしまった
もっと勉強せねば

## まとめ
Timezoneを変更したときはちょっと注意しないといけない
sqlクエリを確認すること
期間選択する場合は時間までいれること
PHPの基本とCRUDとmysqlについて

▼CRUDとは、永続的なデータを取り扱うソフトウェアに要求される4つの基本機能である、
1.データの作成（Create）
2.読み出し（Read）
3.更新（Update）
4削除（Delete）
の頭文字を繋げた語



▼PHPMyAdminを使う中でデータベースの作り方で注意すること
　　・テーブルでcreate_at , update_atは入れる。更新日として使用する。

　・idは数字のため「タイプはintを使用する」　「属性はunsigned」は「０」と「整数」しか受付ができなくなる
　　　また、AI　部分をチェックしてオートインクリメントをチェックする

　・タイプの「VARCHAR」とは可変長の文字列を意味するデータ型 長さを一般的には「２５５」としている

　・create_at , update_atの時間を表現するものは「TIMESTAMP（その時間、その瞬間をとるための時間）」
　　　デフォルト値を「CURRENT_TIME」でその瞬間の時間を表す


▼UsernameとPasswardを確認する方法
　　MANP　→　webstart → MYSQL　


▼ トランザクション
 ・何かの処理をひとまとめにした状態で、何か処理をする中で処理が失敗した場合に最初からやり直すという意味
 ・「データを登録」「データを更新」「データ削除」などのデータの内容変更がある場合にトランザクションを使用する


```js

$pdo->beginTransaction();

  // データを登録するSQL
  $stmt = $pdo->prepare('INSERT INTO todos (name, done) VALUES (:name, :done)');

  // 値をセット
  $stmt->bindParam( ':name', $store_name, PDO::PARAM_STR);
  $stmt->bindParam( ':done', $store_done, PDO::PARAM_BOOL );

  // SQL実行
  $res = $stmt->execute();

  // コミット
  if( $res ) {
    $pdo->commit();
  }

} catch(PDOException $e) {

  // エラーメッセージを出力
  echo $e->getMessage();
  
  // ロールバック
  $pdo->rollBack();

}

```


▼fetch と fetchAllの違い！！
  　　fetchとfetchAllの違いは、 初めに抽出された１つを取得するか、全てを抽出するか
"softmax_*_kernel_impl" not implemented for 'Long' というエラーの解決法

# エラー内容
Softmax 関数を用ようとした時，以下のようなエラーが発生しました．
```
RuntimeError: "softmax_lastdim_kernel_impl" not implemented for 'Long'
```
```
RuntimeError: "softmax_kernel_impl" not implemented for 'Long' 
```

## 問題が発生しなかった場合
```python:softmax_01.py
m = nn.Softmax(dim=0)
input = torch.randn(2, 3, 4)
output = m(input)
# → Softmax によって axis=0 の方向で処理された出力
```
## 問題が発生した場合
```python:softmax_02.py
m = nn.Softmax(dim=0)
input = torch.tensor([1, 2, 3, 4, 5])
output = m(input)
# → 表記のエラー
```

# 解決方法
エラー内容を読むとどうやら Softmax は Long タイプについて対応していなさそうなので，データの種類を変更してみたところ，解決しました．
```python:softmax_03.py
m = nn.Softmax(dim=0)
input = torch.tensor([1, 2, 3, 4, 5], dtype=torch.float64)
out = m(input)
# → Softmax によって axis=0 の方向で処理された出力
```
aws-cliでAssumeRoleを実行してみる sts assume-roleコマンドパターン・config+credentialsパターン

`aws-cli`を利用してAssumeRole（スイッチロール）を実施する場合。
下記2つの方法があるかと思います。

- `aws sts assume-role`コマンドを利用する
- `.aws/config`と`.aws/credentials`を利用する

本記事ではそれぞれの方法をつかったスイッチロールについて説明します。

## 今回利用するスイッチ元IAMユーザーについて

本記事で利用しているスイッチ元IAMユーザーについて。

スイッチ先のロールは、MFAを必須としているため、スイッチ元のIAMユーザにはMFAを設定し、スイッチ時にトークンを入力するように設定しています。

MFAデバイスのARNはスイッチ元IAMユーザーの認証情報、`MFA デバイスの割り当て`に記載があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/064ac46d-5bca-2e1a-8e4d-8bd01b8ffd4b.png)

## `aws sts assume-role`コマンドを利用する

下記の例では`sts assume-role`コマンドでスイッチ先の一時的な資格情報を取得し、それを環境変数に設定することで利用しています。

```PowerShell:aws sts assume-roleコマンドでロールをスイッチする

# スイッチ元の情報確認
aws sts get-caller-identity --profile <<スイッチ元の資格情報>> --region ap-northeast-1

# aws sts assume-roleで一時的な資格情報を取得する
$credentials = aws sts assume-role --role-arn <<スイッチ先のロールARN>> --role-session-name <<任意のセッション名>> --profile <<スイッチ元の資格情報>> --serial-number <<arn:aws:iam::xxxxxxxxxxxx:mfa/xxxxxxxx:MFA割当>> --token-code <<MFAのトークン>> --region ap-northeast-1 --output json | ConvertFrom-Json

# 環境変数に一時的な資格情報を設定する
$Env:AWS_ACCESS_KEY_ID=$credentials.Credentials.AccessKeyId
$Env:AWS_SECRET_ACCESS_KEY=$credentials.Credentials.SecretAccessKey
$Env:AWS_SESSION_TOKEN=$credentials.Credentials.SessionToken

# profileを指定しないので、環境変数にセットした資格情報が利用される
aws sts get-caller-identity --region ap-northeast-1
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/f96037f5-7db1-a95e-a697-8f89ac36fe4a.png)

## `.aws/config`と`.aws/credentials`を利用する

[AWS CLI での IAM ロールの使用](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-role.html)

ドキュメントにあるように、`credentials`ファイルと`config`にスイッチ元の資格情報とスイッチ先のロールarnを設定しておくことにより。

cliコマンド実行時に`--profile`オプションで設定したプロファイルを指定するだけで、スイッチ先のロールの資格情報を引き受けてコマンドを実行してくれるようになります。

```ini:~/.aws/credentials
[<<profile名>>]
aws_access_key_id = <<スイッチ元のアクセスキー>>
aws_secret_access_key = <<スイッチ元のシークレットキー>>
```

```ini:~/.aws/config
[profile <<profile名>>]
role_arn = <<スイッチ先のロールarn>>
source_profile = <<profile alias>>
mfa_serial = <<MFAデバイスのARN>>
```

![credentials](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/26464adb-7c4a-786e-1175-ee2e4c47efac.png)

### credentialsとconfigのサンプル

#### ~/.aws/credentials

![config](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/2e48db01-9e3f-b5d1-5e35-98c3bf330e7c.png)

#### ~/.aws/config

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/f40250c0-b002-46d2-a39e-9e543c90a6f4.png)

## 総評

`.aws/config`と`.aws/credentials`を利用するケースのほうが手軽かと思います。

また`config`と`credentials`に記載してprofile指定で各ロールを切り替えられるように設定しておいて、PowerShellから下記で紹介しているPowerShellモジュールを併用するといい感じに切り替える事できます。

[PowerShellでposh-awspをつかいaws-cliのprofileをいい感じに切り替える](https://qiita.com/SAITO_Keita/items/5105dd0b10f5a48cfa7d)
iOS16ベータ版からiOS15に戻す

# 実現したいこと
**iOS16のβ版からiOS15の最新版に戻したい。**
（やることとしては通常のOSダウングレードと変わりません。）

おそらくiOS17、iOS18でも同様だと思います。

毎年恒例のiPhone新OSリリース前の事前テストをするためにiOS16のβ版をインストールしましたが、諸事情によりiOS15に戻す必要がありました。
（通常であれば別に戻す必要はないので、iOS16の最新版アップデートの案内が来たらアップデートをすれば良いと思います。）

前提として、メイン機器をベータ版アップデートはしない方がいいです。
データなど消えてもいいサブ機器で行いましょう。

# 出来なかった方法
以下のApple公式サイトに従ってやってみました。

https://support.apple.com/ja-jp/HT203282

しかしどうしても
> ２. デバイスをコンピュータに接続して、以下の手順にそって、デバイスをリカバリモードにします。

の部分でリカバリーモードに入ることができずに困っていました。
裏技みたいなボタン操作をすれば入れると書いてあるのですが何度やっても入れない、、、

ということで別の方法でリカバリーモードに入り、アンインストールできたためその方法を記載します。

# 出来た方法
## 1. ipswのダウンロード
Macから[ipsw.me](https://ipsw.me/)へアクセスし、該当する端末とOSを選択してダウンロードします。
容量が大きいのでそれなりに時間がかかります。

:::note warn
基本的に最新の1つか2つしかダウンロードできません。
ここでダウンロードできないものへのダウングレードは不可能です。
:::

## 2. MacにiPhoneを認識させる
MacとiPhoneを繋ぎ、iPhoneで「このデバイスを信頼しますか？」というポップアップが出た場合は「信頼」を選択してください。

Finderを開き、以下のようにiPhoneが表示されることを確認してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574728/3c931ecd-d9b7-bf20-90c6-5451ea4c3501.png)

## 3. アップデートを確認からipswを選択
左ペインからiPhoneを選択し、「アップデートを確認」を**オプション(⌥)をクリックしながら**押してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574728/0ae9cfa9-509f-7930-520e-64c17d974008.png)

するとファイルを選択する画面が出てきますのでダウンロードしたipswを選択してください。

## 4. 画面の指示に従ってダウングレード
あとは画面の指示に従っていればiPhoneがリカバリーモードに入りダウングレードされるはずです。
まあまあ時間がかかります。

# 余談
簡単にダウングレードできるよっていうツールがあったのですが、めちゃくちゃ無料っぽい顔して作業を進めさせて、いざダウングレードってときに有料である事が分かったのがうざかったです。
Rails フォームヘルパー Cheat Sheet !

フォーム作成時に構文を毎回調べているので備忘録兼ねてまとめました。

### バージョン

下記のバージョンで確認
Rails version: 7.0.2.2

## ActionView::Helpers::FormHelper

```erb
<%= form.color_field :favorite_color %>
<%= form.date_field :born_on %>
<%= form.datetime_field :user, :born_on, min: Date.today %>
<%= form.datetime_local_field :graduation_day %>
<%= form.email_field :address %>
<%= form.file_field :post, :image, multiple: true %>
<%= form.hidden_field :parent_id, value: "foo" %>
<%= form.month_field :birthday_month %>
<%= form.number_field :price, in: 1.0..20.0, step: 0.5 %>
<%= form.password_field :password %>
<%= form.phone_field :phone %>
<%= form.range_field :discount, in: 1..100 %>
<%= form.search_field :name %>
<%= form.telephone_field :phone #alias phone_field %>
<%= form.text_area :message, size: "70x5" %>
<%= form.text_field :post, :title, maxlength: 30, class: "title" %>
<%= form.time_field :started_at %>
<%= form.url_field :homepage %>
<%= form.week_field :birthday_week %>
```
![actionview_helpers_formhelper.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239825/9b7a55a3-a64b-bf8d-1ffb-cb1c41b0e2be.png)


## ActionView::Helpers::FormOptionsHelper
collectionは主にドロップダウンリストをDBからの情報を元に作成したいときに使用します。
```erb
<%= form.collection_select :city_id, City.order(:name), :id, :name %>
<%= form.collection_radio_buttons :city_id, City.order(:name), :id, :name %>
<%= form.collection_check_boxes :city_id, City.order(:name), :id, :name %>
```

# 参考
RUBYGUIDES: Action View Form Helpers
[https://guides.rubyonrails.org/form_helpers.html](https://guides.rubyonrails.org/form_helpers.html)

MDN: <input>: 入力欄 (フォーム入力) 要素
[https://developer.mozilla.org/ja/docs/Web/HTML/Element/input](https://developer.mozilla.org/ja/docs/Web/HTML/Element/input)
インクリメント演算子の前置と後置について

# インクリメント演算子の前置と後置の違い

javaシルバーの資格勉強をしていた際、インクリメント演算子が前と後ろに置かれているものがあり、「どっちだったかな〜」とど忘れしたので、その備忘録として。

# 前置のインクリメント
```
++i
```
このようなもの。

# 後置のインクリメント
```
i++
```
このようなもの

# どう違うのか

簡単にいってしまうと、評価されるタイミングが違う。

前置インクリメントの例
```
int num=0;

System.out.println(++num);　　　　　　

//１が表示される
```
先にnum=0にプラス１してから（評価してから）表示させている。

続いて後置インクリメントの例
```
int num=0;

System.out.println(num++);  //0が表示

System.out.println(num);  //1が表示
```
１回目のSysoutでは後置インクリメントなので、一旦変数numの値を表示してから、プラス１をしている。
２回目のSysoutでは、１回目でプラス１した値（変数num=1）を表示している　

# 最後に
なんだかんだ忘れやすい（自分だけかも）ので自分自身の戒めとして記録しました。以上備忘録でした。
css: backgroundに画像と背景色を指定したい

# やりたいこと
backgroundで画像を表示させながら、背景色で透過させたいみたいな時にハマったやつ

# 無理①
これでうまくいった記事多くあるがなぜかうまくいかない
backgroundのショートハンドでかく
```css
background: rgba(#000, 0.5) url("画像URL") no-repeat center;
```

# 無理②
まぁ無理
```css
background-image: url("画像のURL");
background: rgba(#000, 0.5);
```

# 解決法
liner-gradientつければうまく表示できた
```css
background: linear-gradient(rgba(#000, 0.5), rgba(#000, 0.5)),
    url("画像URL") no-repeat center;
```
for文で生成するFont AwesomeのSVG描画が遅い問題

Font AwesomeのKitではTechnology(描画方式)として、Web FontかSVGか好きな方を選べるのですが、うっかりSVGを選んでしまうと描画がかなり遅くなります。10倍くらい時間がかかると思ってください。

これはFont Awesomeに限らず、そもそもSVGの中身はXMLであり、余分な情報がたくさん盛り込まれているためです。

そのため、データ数が増えれば増えるほど指数関数的に遅くなるので、AngularやReactなどでFont Awesomeのアイコンをループ生成する際は、Web Fontを選んでおくほうが懸命です。

作成していたWebアプリで「最近非同期データの読み込みが遅いなぁ」「データ量増えたからかなぁ」と思っていたら、アルゴリズム起因ではなくビュー描画起因だったというオチでした。確かにビューの描画処理って重いんですよね。
git  - リポジトリ立ち上げ時の手順 -

githubでリポジトリを立ち上げるときに打つコマンドをまとめました。

```
git init
```

```
git commit -m "first commit"
```

```
git branch -M main
```

```
git remote add origin [URL]
```

```
git push -u origin main
```
HTMLのTableのタグを簡単に生成する

# Table Tag Generator
![tabletag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239825/d059211c-da73-0267-3131-d5926ec7f8fd.png)
直感的な操作で複雑なテーブル構造も簡単に作成できます。
https://tabletag.net/ja/

## HTML tableタグ　仕様
\<table\>タグの内側に含められるのは以下になります。

- caption
- colgroup
- thead
- tbody
- tr（必須）
- tfoot
- scriptタグ等


```html:example
<table>
    <thead>
        <tr>
            <th>thは見出しです。</th>
            <th>thは見出しです。</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>trは行です。</td>
            <td>tdは列です。</td>
        </tr>
    </tbody>
</table>
```

## 参考
WHATWG: table
[https://html.spec.whatwg.org/multipage/tables.html](https://html.spec.whatwg.org/multipage/tables.html)
MDN: \<table\>: 表要素
[https://developer.mozilla.org/ja/docs/Web/HTML/Element/table](https://developer.mozilla.org/ja/docs/Web/HTML/Element/table)
SvelteKitで twitter公式 widget を使う

かつて Ractive.js に夢中だった私は今、生みの親が同じであるところの Svelte と SvelteKit に夢中です。個人開発でちょっと凝ったデザインのランディングページ的なものを作るのには最適です。

###  twitter公式のウィジェットをただ埋め込みたかった

SvelteKitの通常の +page.svelte ファイルのコンポーネントの中に https://publish.twitter.com/ で生成される twitterウィジェットを埋め込みたかったのですが色々やってもうまくいかず、探していたところ

https://adamtuttle.codes/blog/2021/adding-3rd-party-script-tags-in-sveltekit/

こんな最適な記事が見つかりました。あまりにシンプルなのでこの作者自身「これだけでいいの？」的に驚きが隠せない様子です。
この記法であれはtwitterウィジェットは非常に簡単に埋め込むことができたので久々の投稿としてここに共有します。

### SvekteKitでの書き方

https://publish.twitter.com/ で生成されたタグが

```
<a class="twitter-timeline" href="https://twitter.com/account_name">Tweets by account_name</a><script async src="https://platform.twitter.com/widgets.js"></script>
```
とします。


```svelte:.svelte
<script>
 import { browser } from '$app/env';
 ...
</script>

{#if browser}
  <script async src="https://platform.twitter.com/widgets.js"></script>
{/if}

<main>
　　{@html `<a class="twitter-timeline" href="https://twitter.com/account_name">Tweets by account_name</a>`}
</main>
```

これだけです。
参考記事にもあるように `<svelte:head>`だとうまく動かないです。
また、検索して出てくる 

https://github.com/coussej/svelte-twitter-widgets

はSvelteKitでは使えませんでした。
SQLの基本まとめ

# はじめに
SQLの基本的なところを自分なりにまとめてみました。

# データベースとは
文字列や数値を保存しておくツール。

表のことをテーブル、縦の列はカラム、横の行をレコードと呼ぶ。

# クエリとは
データベースに送る命令のこと。
SQLはクエリを書くための言語。

## SELECT
データベースから、データを取るためには`SELECT`を用いる。
どのカラムのデータを取るか、を選ぶ。

```sql
SELECT name --nameはカラム名
```
出力結果のヘッダーにあたる。
## FROM
データベースに複数のテーブルがあるとき、`FROM`を用いて、
`SELECT`で選んだカラムがどのテーブルか指定する。
```sql
SELECT name --2.どのカラムか
FROM closet --1.どのテーブルか
```

## セミコロン ;
クエリの最後には、セミコロン`;`をつける。

:::note
クエリは１行でも書けるし、改行もできる。
:::

:::note
SQLは大文字と小文字を区別しない。
:::
# 複数のカラムを選択する
コンマ`,`で区切る。
```sql
SELECT name, price
```
出力のカラムに`name,price`　が出てくる。

全カラムのデータを取得する場合は`＊`を使う。
```sql
SELECT *
FROM closet;
```
出力に、全カラムが出てくる。
# WHERE
`WHERE`は、どこのレコード(横の行)を取るか、絞り込む。
`=`を用いて条件を指定する。(よく見るのは、カラムの条件)
```sql
WHERE categoty = "トップス" --categoryカラムが"トップス"のレコードを指定
```
データ型のルールで、文字列は`""`で囲む必要がある。
```sql
SELECT * --カラム全データ
FROM closet --テーブルはclosetを
WHERE category = "トップス"; --カテゴリーがトップスに絞り込む
```
# データの型と`""`
データ型は、テキストデータや数値データ、日付データなど、テータの種類を示すもの。
数値データは`""`で囲わない。
```sql
WHERE price = 1000;
```
テキストデータや日付データは`""`または`''`で囲う。
```sql
WHERE date = "2022-09-14";
```
# 比較演算子
より小さい`<`、より大きい`>` 、以下`<=`、以上`>=`がある。
例えば、以上を表す比較演算子`>=`を使って4000円以上のデータを探せる。
```sql
WHERE price >= 1000;
```
日付データにも使える。`>=`は以後を表す。
```sql
WHERE date >= "2022-09-03";
```
# LIKE演算子
今までの検索は完全一致しか取得できない。
ある文字を含むときのデータを取得したいときは、LIKE演算子を使う。
```sql
SELECT *
FROM closet
WHERE name LIKE "シャツ";
```
`"シャツ"`は検索したい文字列ならなんでもよい。
## ワイルドカード
ワイルドカードはどんな文字列にも一致することを示す記号.
LIKE演算子では`%`を使う。

:::note warn
ワイルドカード`%`を使う時は、`=`は使えない。`LIKE`を使う。
:::

```sql
SELECT *
FROM closet
WHERE name LIKE "%シャツ%"；
```
シャツと付く名前のデータを取得できる。

### 前方一致
`"シャツ%"`とする。
```sql
SELECT *
FROM closet
WHERE name LIKE "シャツ%"；
```
シャツで始まるデータを取れる。

### 後方一致
`"%シャツ"`とする。
```sql
SELECT *
FROM closet
WHERE name LIKE "%シャツ"；
```
シャツで終わるデータを取れる。

# NOT演算子
シャツ以外のデータがほしい時、NOT演算子を使う。
```sql
SELECT *
FROM closet
WHERE NOT name LIKE "%シャツ%"；
```
NOTで条件を満たさないデータが取れる。

# IS NULL ・ IS NOT NULL
カラムに何も保存されていないとき、`NULL`を使う。
NULLのデータを取るときは、`IS NULL`とする。
```sql
SELECT *
FROM closet
WHERE name IS NULL； --nameに何も保存されていないレコードを取得する。
```
NULLでないデータを取るときは、`IS NOT NULL`とする。
```sql
SELECT *
FROM closet
WHERE name IS NOT NULL； --nameにデータがあるレコードを取得する。
```
:::note warn
`NULL` のとき、`=`は使えない。`IS`を使う。
:::

# AND・OR演算子

## AND演算子
`WHERE`に複数の条件を入れられる。
構文：`WHERE 条件1 AND 条件2`
条件1かつ条件2を満たすデータを探す。
```sql
WHERE name = "ドレスシャツ" --条件1
AND category = "トップス"; --条件2
```
## OR演算子
`WHERE`に複数の条件を入れられる。
構文：`WHERE 条件1 OR 条件2`
条件1または条件2を満たすデータを探す。
```sql
WHERE name = "ドレスシャツ" --条件1
OR category = "トップス"; --条件2
```

# ORDER BY 並び替え
一番高いものを探すとき、高い順に並び替えればわかる。
```sql
ORDER BY 並べ替えたいカラム名 並べ方
```
`並べ方`は、昇順か降順を指定する。
昇順は小さい順: `ASC`
降順は大きい順: `DESC`

`ORDER BY`はクエリの末尾に書く。
```sql
SELECT *
FROM closet
ORDER BY price DESC; --価格が高い順
```
`ORDER BY`は`WHERE`と一緒に使える。
```sql
SELECT *
FROM closet
WHERE 条件
ORDER BY price DESC; --価格が高い順
```

# LIMIT 必要な数だけ
最大で何件取るか、は`LIMIT`を使う。
データの件数を指定する。
```sql
LIMIT データの件数;
```
`LIMIT`はクエリの末尾に。
`WHERE`と一緒に使える。
```sql
SELECT *
FROM closet
WHERE 条件
LIMIT 5;
```
`ORDER BY`と一緒に使うときは`LIMIT`が末尾。
```sql
SELECT *
FROM closet
WHERE 条件
ORDER BY price DESC; --価格が高い順
LIMIT 5;
```
Apache設定したけど接続できないときに確認したこと

https://qiita.com/ren_nomura/items/5a4803f1ee0c007b47a8

こちらの記事を参考にラズパイにApacheを入れてLANから接続してみようとしたときにつまづいた点です。
先に上記の記事をお読みください。

# Apacheのデフォルトページが表示されない
ラズパイのIPアドレスを別PCのブラウザに入力したところまでは良かったのですが、Apacheのindex.htmlが表示されません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846175/23adf6e4-dbb1-a6a6-f966-e61a6840fe9a.png)

表示されてほしいページ↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846175/49550253-d8bb-131e-4e14-cdaf38d22e17.png)

# 原因：ufwの設定
ポートを開いていませんでした。
ufwの80番ポートを解放する設定を行います。
~~~
pi@raspberrypi:~ $ sudo ufw allow 80
Rule added
Rule added (v6)
pi@raspberrypi:~ $ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
VNC                        ALLOW       Anywhere                  
25565                      ALLOW       Anywhere                  
80                         ALLOW       Anywhere                  
VNC (v6)                   ALLOW       Anywhere (v6)             
25565 (v6)                 ALLOW       Anywhere (v6)             
80 (v6)                    ALLOW       Anywhere (v6)
~~~

Apacheの設定してみたけど繋がらない…という場合はファイアウォールの設定も確認しましょう。
Blenderでメッシュの3つの重心を確認する

## 概要

メッシュには、3つの重心があります。

- **ジオメトリ**：頂点に質点があると仮定したときの重心。頂点座標の平均。
- **重心（サーフェス）**：面に質量があると仮定したときの重心。
- **重心（ボリューム）**：密度が一定と仮定したときの重心。いわゆる重心。

実際にメッシュを作って、確認してみます。

## 重心の求め方

Blenderでは、以下のようにしてメッシュの重心を確認できます。
まず最初に、オブジェクトメニューの適用の**全トランスフォーム**で、回転とスケールをリセットしておいてください。
それぞれの重心は、下記操作後に、サイドバーのアイテムのトランスフォームの**位置**で確認できます。

- ジオメトリ：オブジェクトメニューの原点を設定の**原点をジオメトリに移動**
- 重心（サーフェス）：オブジェクトメニューの原点を設定の**原点を重心に移動（サーフェス）**
- 重心（ボリューム）：オブジェクトメニューの原点を設定の**原点を重心に移動（ボリューム）**


## 三角錐の場合

三角錐では、ジオメトリと重心（ボリューム）が同じになります。
適当な三角錐を作って確認します。

| ジオメトリ | 重心（ボリューム） |
|--:|--|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/a1050e82-5d73-afff-ac37-dacc2d5b7254.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/740e354d-2ef3-4c3f-8c34-18b197cb3ef1.png)|

## 四角錐の場合

四角錐では、重心（ボリューム）は、高さの1/4のところにあります。
頂点を4にして円錐を作って確認します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/7e93bf2b-08ce-b239-911d-4b34c6a4c8a7.png" width="400">

各頂点は下記の通りです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/5248ea88-89db-ba57-9997-ff3192c6fb0e.png" width="400">

ジオメトリは下記の通りです。平均になっています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/0abe09ae-84b0-3229-6801-2aae606e9233.png" width="400">

重心（ボリューム）は下記の通りです。Zが高さの1/4になっています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/7e00806c-f321-f0c3-a5a9-69f609449f89.png" width="400">

## 三角形の場合

三角形では、ジオメトリと重心（サーフェス）は同じです。
平面を作り、頂点を1つ削って確認します。

各頂点は下記の通りです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/86f7ce11-2a6d-c697-e024-b312aa1b9ab7.png" width="400">

ジオメトリは、平均になります。重心（サーフェス）も同じです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/cacbdf50-d320-2620-7fc8-89a063d915db.png" width="400">

### 1辺の頂点を増やした場合

三角形の下辺を100個に細分化し、頂点を増やしてみましょう。見た目は三角形ですが、101角形になっています。
ジオメトリは、下辺の中心に近くなります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/ff550d94-1b01-2f00-841b-edc651d61a7d.png" width="400">

101角形になっても面の形状は三角形と同じなので、重心（サーフェス）は変わりません。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/cacbdf50-d320-2620-7fc8-89a063d915db.png" width="400">

### 1つの頂点にベベルをかけた場合

三角形の左下の頂点にベベルを書けてみましょう。形状は三角形に近いですが、原点付近に頂点が99個あります。

ジオメトリは、原点付近になります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/69c3fdc2-2e8b-0f54-15b8-bd0ea3bf3ace.png" width="400">

形状は三角形に近いので、重心（サーフェス）は三角形のときに近いです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/535b6873-c78b-0a4d-1d54-db2b0ef56fe6.png" width="400">

以上
MyBatisでforeachを回す

### MyBatisでFormに含まれるメンバ変数のListをforeachに渡したい

MyBatisでforeachを回す際、@Paramで直接Listを渡して、そこから取り出す方法はよく見かけるのですが、Formを@Paramに渡してそのメンバ変数のlistをforeachで回したい時の方法がなかなか見つからなくて詰まりました。

#### 実装
```UserSearchForm.kt

data class (
    @Field:Positive
    @Field:Schema(
        required = false,
        type = "int",
    )
    val userId: Int? = null

    @Field:Positive
    @Field:Schema(
        required = false,
        type = "list",
    )
    val userTypeIds: List<Int>? = null
)
```

```UserMapper.kt

@Mapper
interface UserMapper {
    @Select(
        """
            <script>
                SELECT user_id, user_name, email, user_type_id, created
                FROM users
                <where>
                    <if test="userSearchForm.userId != null">
                        user_id = #{userSearchForm.userId, jdbcType=INTEGER}
                    </if>
                    <if test="userSearchForm.userTypeIds != null">
                        AND user_status_id IN (
                            <foreach item="userTypeId" collection="userSearchForm.userTypeIds" open="(" separator="," close=")">
                                #{userTypeId}
                            </foreach>
                        )
                    </if>
                </where>
            </script>
        """)
    
}

```

#### 躓いたところ

Mapperの引数に直接Listを渡して、その内容をforeachに渡すときであれば以下の通り`collection="list"`で良いみたいなんですが、FormからListの値を取り出したい時は、`collection`の方にlist型のメンバ変数を渡して(この場合`userSearchForm.userTypeIds`)、`item`と`#{}`内にはその中身として`userTypeId`を渡すようにしないと認識されないようです。

```
<foreach item="item" index="index" collection="list"
        open="ID in (" separator="," close=")" nullable="true">
          #{item}
</foreach>
```

最初はこんな感じで書いていたのですが、これでやったところ

```
 <foreach item="userSearchForm.userTypeIds" collection="list" open="(" separator="," close=")">
     #{userSearchForm.userTypeIds}
</foreach>
```
以下のようなエラーになりました。

```
Parameter 'list' not found. Available parameters are [userSearchForm]
```

まあまず`userSearchForm.userTypeIds`の中身がlistなので、こちらはforeachの中身としてではなく、foreachさせる方のcollectionとして渡さなければいけなかったわけです。（当たり前と言えば当たり前だけど）
PyTorch×GPU セットアップ手順

# 目次
[__1. はじめに__](#はじめに)
[__2. セットアップ__](#セットアップ)
[__3. 動作確認__](#動作確認)

# はじめに
自分用のメモとして、ディープラーニングフレームワーク**PyTorch**をGPUで利用する際のセットアップ手順を記します。



# インストール
:::note warn
- **PyTorch**・**Python**・**CUDA**それぞれのバージョンによって相性問題があるため注意
    - 例えば3000番台のGPUであれば **PyTorch 1.7** 以上・**Python 3.8** 以上・**CUDA 11.x**
- AnacondaのGUIからPyTorchをインストールしない
:::
下記リンクからインストールするコマンドを確認しておく

https://pytorch.org/

![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2059946/a64acf3b-b86b-849c-c29b-74c93cf719ba.png)
アーカイブから必要なバージョンのCUDA Toolkitをダウンロードしておく

https://developer.nvidia.com/cuda-toolkit-archive


PyTorch用の環境をつくって、Anaconda promptでPyTorchをインストールする
```powershellshell:Poweshell Prompt
conda install pytorch torchvision torchaudio cudatoolkit=11.3 -c pytorch
```



# 動作確認
最後にJupyter NotebookでGPUの動作確認をする
![Untitled (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2059946/d4f5abdd-46cd-3fd6-9c36-5f1a772ebbc9.png)
Linuxディストリビューションについて

# DBの種類について
## 初めに
何となくしか理解できていなかった分野。2回目はLinuxディストリビューションについてです。RedHat,AmazonLinuxなどなど種類があることは知っていますが、それぞれの使い分けなどはあまり把握せずのままだったのでこの際にはっきり理解しておこうと思います。
※AmazonLinuxはAWSの無料AMIなのでとてもお世話になっています
私が調べた結果をまとめてみます。

## Linuxとは
そもそもLinuxとはについて改めて説明します。Linuxはフィンランドの学生だったリーナス・トーバルズ氏が1991年から開発を始め、現在も開発が続けられているUNIX系のOS。（ソースコードは異なるが使用感がUNIXに近い）次第に注目を浴び多くの商用アプリケーションがLinuxをサポートすることになり、またオープンソースということもありビジネスシーンでも注目されるようになりました。

正直OSを開発とかどうやってするのか見当もつかないですね。。
また、UNIXについてもしっかり把握しておいたほうがよさそうですね。。

## UNIXとは
UNIXとは現存するOSの中で最古のOSです。1969年にベル研究所で誕生しました。当初はオープンソースでしたが爆発的に人気が出て、大学や研究所、企業で様々な派生版のUNIXが誕生しました。派生版が出すぎたため途中からライセンス契約という形をとるようになりました。

また、調べていくうちにLinuxカーネル・ディストリビューションという言葉が多く出てきたのでそちらの解説もします。

## Linuxカーネルとは
最初に開発されたLinuxのこと。誰でも無料で自由に利用、再配布ができる。カーネルだけインストールしてもコンピュータ上では動かない。

## ディストリビューションとは
ディストリビューションとは「流通」「配布」という意味です。上記のようにカーネルだけでは手軽にOSとして扱うことができないのでアプリケーションなどをパッケージにして使いやすくしたものを「ディストリビューション」といいます。

### ディストリビューションの種類について
まず、代表的な種類を上げると
・RedHat
　RedHatは有料です。パッケージ管理ソフトにRPM系を使用しているためインストールも簡単です。
　「仕事で使うならRedHat」と言われるほど、参考書などの情報も多いです。
　
　→業務で使用していたサーバーもRedHatだった

・CentOS
  CentOSはRHELのクローン（複製）OSでRHELの商用部分を取り除いたディストリビューションです。。無償で使える上に安定性が非常に高いことからサーバーOSとして適しており、多くの企業から支持されています。

　→研修で仮想OSとしてインストールして使用した。

・Debian
　100%フリーソフトをポリシーとした安定性のある質の高いOSで、日本語にも対応しているため、ネットに情報が豊富にあり、初心者のサーバー構築におすすめです。

・Ubuntu
  Ubuntu とは「誰にでも使いやすいOS」をコンセプトとして開発されたLinux 系のOS です。ライセンス等の問題で取り入れられなかったパッケージもUbuntuは積極的に取り込み、ユーザーが使いやすい環境となっています。

　→大学のパソコンルームのパソコンがUbuntuだった。その頃は全く意識もしてなかったが。。

・Fedora
　FedoraはRedHat社が支援しているディストリビューションです。RHELは商用向けで有料なのに対しFedoraは無料で使うことができます。Fedoraは次世代のRHEL向けの検証用ディストリビューションとしての役割があります。

・AmazonLinux
　AWSで提供されているディストリビューションです。EC2上で使用されることを想定されているので、AWSとの連携がしやすいです。また、ベースはRedHat系といわれRedHatはCentOSと同じような感じで使用することができます。
※メインのディストリビューションの中には含まれていなさそうでしたが自分がよく使用するため入れました。


などなど。。（ちなみに私はFedoraというディストリビューションは初耳でした。。。よく聞くのはRedHat,CentOSあたりですかね。。）

## まとめ
Linuxができた経緯も調べながらだと結構興味のある内容でした。今これだけよく聞くLinuxはUNIXがもともとあったおかげだったんだなということを知ったので時々思い出してみようと思います(笑)。また、ディストリビューションは自分が知っていたよりも数倍以上の数がありそうでした。とっても業務で使用するのは限られたものだけだと思うのであまりそこの心配は不要かも？

次回はbashスクリプトについてまとめようと思います。

♯# 参考ページ
https://career.levtech.jp/guide/knowhow/article/728/
https://tech-camp.in/note/technology/14821/
https://eng-entrance.com/unix_linux
https://www.fenet.jp/infla/column/server/linux%E3%82%AB%E3%83%BC%E3%83%8D%E3%83%AB%E5%85%A5%E9%96%80-4%E3%81%A4%E3%81%AE%E3%82%AD%E3%83%BC%E3%83%AF%E3%83%BC%E3%83%89%E3%81%A7%E5%BE%B9%E5%BA%95%E8%A7%A3%E8%AA%AC/
https://eng-entrance.com/linux%E3%83%87%E3%82%A3%E3%82%B9%E3%83%88%E3%83%AA%E3%83%93%E3%83%A5%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A8%E3%81%AF%EF%BC%9F
https://miraie-group.jp/sees/article/detail/PC_Linux_recommend
【Typescript】スプレッド構文と残余引数（レスト構文）の違い

Typescriptを学習中、スプレッド構文と残余引数（レスト構文）の違いで少し悩んだので、復習も兼ねて投稿します。

## 目次
**■スプレッド構文とは**

**■残余引数(レスト構文)とは**

**■共通点・違い**

**■よく見るスプレッド構文の例と「Typescript」**


## ■スプレッド構文とは
**配列やオブジェクトの中身を展開する。**

同じ配列の中身やオブジェクトの中身を展開して複合するのに便利。

```javascript
const array: number[] = [1,2,3];

const array2: number[] = [...array, 4];
// [1, 2, 3, 4] 


const obj = {
    name : "sample",
    age : 25,
}

const newObj = {...obj, from: "japan"};
// { "name": "sample", "age": 25, "from": "japan" } 
```

## ■残余引数(レスト構文)
**複数の要素を一つのオブジェクトにまとめる。**

関数の引数の数が決まっていない時に使うと便利。
残余引数は受け取った引数を配列にする。

```javascript
function returnArr(...numbers: number[]) {
    return numbers;
}
console.log(returnArr(1,2,3,4,5,6,7,8,9));

//  [1, 2, 3, 4, 5, 6, 7, 8, 9] 
```

## ■共通点・違い
スプレッド構文も残余引数も、どちらも

`...変数名`

という記法で記入する。
しかし、`使用方法`に明確な違いがある。

また、
`スプレッド構文は記入する順番を問わない`が、
`残余引数は必ず最後に書かなくてはいけない。`

```javascript
// Spread Syntax
const arr = [1,2,3]
const newArray: number[] = [0,...arr, 4];
// [0, 1, 2, 3, 4] 

const obj = {
    name : "sample",
    age : 25,
}
const newObj = {id:1,...obj, from: "japan"};
//  {"id": 1, "name": "sample", "age": 25, "from": "japan"} 


// Respt Parameters
function returnArr(...numbers: number[], num: number) {
    return numbers;
}
// ...numbers: number[]で構文エラー
//A rest parameter must be last in a parameter list.(1014)
```

### ■補足
スプレッド構文も残余引数も、どちらも空でも呼び出せる。
これは、スプレッド構文が`０個以上`の要素を要求しているため。

```javascript
// Spread Syntax
const arr: number[] = [];
const newArray: number[] = [...arr, 4];
// [4]


// Respt Parameters
function returnArr(...numbers: number[]) {
    return numbers;
}
console.log(returnArr()); // OK。
```

## ■よく見るスプレッド構文の例と「Typescript」
ネットでスプレッド構文の例を見てみると、以下のような構文を目にする。
```javascript
function sum(x, y, z) {
  return x + y + z;
}

const numbers = [1, 2, 3];

console.log(sum(...numbers));
```

しかし、これをそのままTypescriptで行おうとすると構文エラーが発生する。

以下のように型を指定してもNG。

```javascript
function minus(x: number, y: number, z: number) {
    return x - y - z;
}
const arrayNum: number[] = [1,2,3];
console.log(minus(...arrayNum));

// 構文エラー
```

正解は、タプル型を使用することで解決する。

```javascript
function minus(x: number, y: number, z: number) {
    return x - y - z;
}
const arrayNum: [number, number, number] = [1,2,3];
console.log(minus(...arrayNum));
// -4
```


### ■10月15日追記
**■よく見るスプレッド構文の例と「Typescript」** にて記載した例は、
以下のようなケースではスプレッド構文を用いた配列の展開を利用して呼び出すことができる。

```javascript
function minus(...nums: number[]):number {
    for(let num of nums) {
    result += num;
  }
    return result;
}
const arrayNum: number[] = [1,2,3];
console.log(minus(...arrayNum));  // OK.
```

ポイントは
定義した関数の引数が`3個で固定されている`か、`可変長引数`であるかという点。

引数が3個で固定されている関数を呼び出す際に、スプレッド構文で関数を呼び出しすると、それは
**<font color="red">要素数不明の何らかの配列という扱いになってしまう。</font>**

よって関数の引数の数が限定されている時は、
`タプル型を利用したスプレッド構文`を利用する。


関数の引数の数が可変長引数であれば、
`スプレッド構文`をそのまま利用することが可能。
半日404エラー解消に悩みまくった（Tomcat・サーブレット）

# 試したことメモ。
①サーバー上に追加し直し。（eclipse上）
これのことね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287651/f06e1853-2e40-47b9-4895-07d9e3d2f9ce.png)

②（html or jspの）form action="●●●"と（サーブレット側の）@WebServlet("/●●●")の一致を行った。

③buildフォルダにclassファイルができていない。
→プロジェクトのビルドが必要。


取り急ぎ～
vaccine_gene感染チェック

なにかまた流れてきたので、vacciene_geneの挙動を流用してチェック用のスクリプトを書いてみる。

なにをチェックする？
--
感染のチェックとしては
- **所定のフォルダに vaccine.py が存在するか否か**
- **userSetup.pyに該当する内容が書き込まれているか否か**

とりあえずこの2点に絞ってみる。

優先度が高いのは vaccine.pyの有無。
userSetup.pyが汚染されてても、実行されるvaccine.pyが無ければとりあえずは感染拡大しないはず。


所定のフォルダに vaccine.py が存在するか否か
--

所定のフォルダの指定は、本家挙動に習ってそのまま流用。

    cmds.internalVar(userAppDir=True) + '/scripts'

そのままファイルの有無をチェック

    health = True
    targetPath = cmds.internalVar(userAppDir=True) + '/scripts'

    if os.path.exists(targetPath + "/vaccine.py"):
        health = False

userSetup.pyに該当する内容が書き込まれているか否か
--

該当する内容っつーのが3行

    import vaccine
    cmds.evalDeferred('leukocyte = vaccine.phage()')
    cmds.evalDeferred('leukocyte.occupation()')

これがuserSetup.pyに書き込まれているか否かをチェックしたい。
userSetup を1行ずつ読み込んでチェック

    health = True

    targetPath = cmds.internalVar(userAppDir=True) + '/scripts'

    if os.path.exists(targetPath + "/userSetup.py"):
        sampleLine = [
                    "import vaccine",
                    "cmds.evalDeferred('leukocyte = vaccine.phage()')",
                    "cmds.evalDeferred('leukocyte.occupation()')"
        ]
        with open(targetPath + "/userSetup.py", "r") as f:
            for line in f:
                line = line.rstrip()

                if line in sampleLine:
                    health = False
                
        f.close()     


まとめる
-

2つのチェック項目をまとめて1個にすると、こんな感じかしら。

```
import maya.cmds as cmds

def checkVaccineGene():
    health = True
    targetPath = cmds.internalVar(userAppDir=True) + '/scripts'

    if os.path.exists(targetPath + "/vaccine.py"):
        health = False
        
    if os.path.exists(targetPath + "/userSetup.py"):
        sampleLine = [
                    "import vaccine",
                    "cmds.evalDeferred('leukocyte = vaccine.phage()')",
                    "cmds.evalDeferred('leukocyte.occupation()')"
        ]
               
        with open(targetPath + "/userSetup.py", "r") as f:
            for line in f:
                line = line.rstrip()

                if line in sampleLine:
                    health = False
                
        f.close()                

    return health
```

でも感染してるファイルを野放しにすると意味が無いので、感染元は特定してください。
[js/ts]取得した文字列が、指定した文字列と前方一致しているかを判別する方法

はじめに
--
「フォームに入力された文字列が〇〇と前方一致している場合のみ処理Aが動く」というような記述がしたく、前方一致しているか判別する方法を調べたので内容を備忘録として残そうと思います。

前方一致かを確認するためには"startsWith()"を使用する
--
"startWith()"というメソッドを使用することにより、前方一致しているか判別することができます。

※厳密に言うと、デフォルトが前方一致で、引数で指定をすれば、判別を開始する位置を変更することができます。

構文
--
下記が構文です。
文字列(str)と指定した文字列(searchStringの箇所で指定)の前方が一致しているかどうかを判別をします。

一致している場合はtrue/一致していない場合はflaseを返します。
~~~ts
str.startsWith(searchString[, position])
~~~

下記が簡単な例になります。

~~~ts
const str = 'hello world!';

console.log(str.startsWith('hello'));
// trueが返ってくる

console.log(str.startsWith('world'));
// flaseが返ってくる

console.log(str.startsWith('world', 6));
// trueが返ってくる
// 判別を開始する箇所をpositionを指定することができる
~~~

公式ドキュメントを見なかったら、省略可能な引数(position)の存在を見落としていたと思います。
やっぱり一次情報を確認するのが大切だなと感じました。



参考
--
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
辞書型(dict)の値(value)に数字を足す

Googleで調べた際に、値に数字を足す関数がPythonでは見つからなかったので、自作しました。
計算コストを考慮してないコードのため、もっといい方法があれば教えていただけると幸いです。

最後に自身がしたかったことを載せます。
<h2>【解決法】</h2>
=の前に+をつければいいだけです。Pythonの四則演算ができる方であれば、簡単ですね。

```python:
dict[key] *= number
```

<b>例：</b>
```python:
test_dict = {}
test_dict["math"] = 90
test_dict["science"] = 10

'''
数学に10を追加、化学に20を追加
'''
test_dict["math"] += 10
test_dict["science"] += 20
```


<h2>[実装したかった事]</h2>
For文を回して、同じキー(Key)の場所には数字を足し、該当するKeyがない場合には新しいキー(Key)を作成して値(value)を与えることがしかったです。

<b>例：</b>
```python:
test_dict = {}
count = 10
for k in [1, 2, 3, 4, 5]:
    test_dict[k] = count
    count -= 1

for k in [1,4, 5, 6, 1]
    try:
        test_dict[k] *= count
        count -= 1
    except:
        test_dict[k] +- count
        count -= 1
```
SOLIDを代替する設計原則、CUPIDについて

## 概要

Daniel Terhorst-Northさんが提唱するSOLID原則を代替する設計原則です。
SOLID原則はプリンシパル(ルールやガイドライン)を定めたものであるのに対し、CUPIDはソフトウェアが持つべき性質・特徴を定めたものです。SOLID原則はOOPやプログラミング言語に依存するところがありますが、CUPIDは基本的にOOPやプログラミング言語に依存しません。

Thoughtworks社が発表している[Technology Radar Volume 26](https://www.thoughtworks.com/content/dam/thoughtworks/documents/radar/2022/03/tr_technology_radar_vol_26_en.pdf)においても紹介されています。

日本語で紹介された記事がなかったので簡単にまとめておきます。

CUPIDは下記の頭文字です。ソフトウェアはこれらの性質・特徴を持つように作るべきだというのがCUPIDが伝えるものです。

 - Composable　: 他のコンポーネントと組み合わせしやすいこと
 - Unix philosophy : ひとつのことをうまくやること
 - Predictable : なにをするのか予測できること
 - Idiomatic : 自然に感じられること
 - Domain-based : ドメイン言語とドメインの構造を使うこと

## Composable

 - 小さなインタフェース(Small "surface area")
 - 意図が明確な名前と目的(Intention-revealing name and purpose)
 - 最小限の依存(Minimal dependencies)

## Unix philosophy

ひとつのことをうまくやるソフトウェア(コンポーネント)を作り、組み合わせによって目的を達成します。
これはSOLID原則のSRP(Single Responsibility Principal)とは異なります。
SRPはあるコンポーネントの変更は1つの理由で行われるべきというものですが、Unix philosophyではコードが行うことに焦点をあてています。

## Predictable

 - 期待通りの動きをすること。驚きがないこと。(Behaves as expected, with no surprises)
 - 決定論的であること　(Deterministic)
 - 観測可能であること (Observable)

### 補足

観測可能とは、適切なログ出力やモニタリングのための実装などを指しています。

## Idiomatic

 - 言語のイディオムを使うこと
   - 標準の機能、ライブラリ、フレームワーク、ツールを使うこと
   - 自然に作業ができること
 - ローカルイディオムを使うこと
   - 社内またはデファクトのコーディングスタイルや設計に従うこと
   - プロジェクト、依存するもの、プラットフォーム、組織の寄り添うこと

## Domain-based

 - ドメイン言語を使うこと
 - ドメインの構造を使うこと
   - ソースコードの構造にはドメインに従った構造を適用すべき。トップレベルでは models, views, controllersのようなものではなく、payments, loans, onboardingのようなものであるべき
 - ドメイン境界を使うこと
   - ドメインの境界をデプロイメントの単位にします。

## 参考

 - [CUPID—for joyful coding](https://dannorth.net/2022/02/10/cupid-for-joyful-coding/)
 - [Hacker News](https://news.ycombinator.com/item?id=26531079)
 - [CUPID - for joyful coding](https://www.thoughtworks.com/radar/techniques/cupid)
 - [Keynote: CUPID ‒ for joyful coding! | Daniel Terhorst-North](https://www.youtube.com/watch?v=knNaUSLhx-U)
【Swift】Alamofireで簡単にデコードする方法

# はじめに
Alamofireにデコードした結果を返してくれる便利なメソッドがあったので紹介します

# サンプルデータ
```swift
import Foundation

struct SampleModel: Codable {
    let id: Int
    let idStr, name, screenName, location, description: String

    enum CodingKeys: String, CodingKey {
        case id
        case idStr = "id_str"
        case name
        case screenName = "screen_name"
        case location
        case description
    }
}
```

# 実装
```swift
AF.request("https://sample.com/", method: .get, headers: headers).responseDecodable(of: SampleModel.self) { response in
    switch response.result {
    case .success(let data):
        print(data)
    case .failure(let error):
        print(error)
    }
}
```

# おわり
いつもは`responseData`を使ってましたが絶対デコードするなら`responseDecodable`こっちの方が楽ですね
#プログラミング #英語 #Javascript #nodejs #glitch # 英単語を覚えたり、思い出すのを早くするツール

本内容を利用した場合の一切の責任を私は負いません。

# 概要
リスニングができるようになるには、英単語の意味を思い出す早さも必要だと思った。
それをトレーニングするツール。
ほんとは見てではなく聞いてで行いたかったが素材が無いため。
一応、英単語を覚えるツールとしても使えると思う。

# バージョン
- OS  
OS 名:                  Microsoft Windows 10 Home  
OS バージョン:          10.0.19043 N/A ビルド 19043  
システムの種類:         x64-based PC
- node.js
node-v10.16.0-win-x64
- linq(node.jsのライブラリ)
3.2.4
- multer(node.jsのライブラリ)
1.4.5-lts.1
- jsonwertoken(node.jsのライブラリ)
8.5.1
- async-lock(node.jsのライブラリ)
1.3.2
- csvjson-csv2json(node.jsのライブラリ)
bc644c4428f55124749b0f5cf2017bf8c9b9fb1b
- csvjson-json2csv(node.jsのライブラリ)
af59e5d9b754eaa4080be51e8697a99e854db311

# データ
元データは下記のCEFR-J Wordlistです。
(『CEFR-J Wordlist Version 1.6』 東京外国語大学投野由紀夫研究室. （URL: http://www.cefr-j.org/download.html より2022‎年‎8‎月‎22‎日ダウンロード）
)
http://www.cefr-j.org/download.html
英単語とかが難易度別に7000程あります。
csvにしたり、品詞をまとめたりしたものがリポジトリのall_word.csvです。
ルールに従えば語句を追加することもできます。
主なルールは下記の列です。

- headword: 語句名
- pos: 品詞(元データの名残でツールでは不使用)
- pos_number: 品詞の値(元データ加工の名残でツールでは不使用)
- CEFR: 難易度(上記の元データの場所に意味が載っています)
- pos_0～pos_14、pos_other: 語句の品詞
- tag: タグ(現時点では実装していないが、タグで問題を絞り込む用。数字、曜日、月、動物等。)
- proficiency: 習熟度(思い出すのに何秒かかったか。-1は未確認。-2は対象外の絞り込み用。まだ知らなくてもいいものをこれで除外等。)
- answer: 答え
- last_check: 直近の確認日(tick値的なもの。ツールが自動的に更新する。)
- last_check_string: last_checkの視認用(ツールが自動的に更新する)

**意味は自分の解釈なので正しいとは限りません。**

# モード
モード(setting.jsonのmultiUser)が2つあり、シングルユーザーモードとマルチユーザーモードがあります。
シングルはマルチの上位互換で、習熟度や確認日が記録され、問題絞り込み機能で使えます。
また、データのバックアップや更新のためにダウンロードすることができ、
問題絞り込みで、当然それをアップロードして利用できます。
マルチの場合、セッション最大数は3で、期限は1時間です。
簡易セッションなのでリロードするだけで別セッションを使用してしまいます。
セッション破棄は操作はなく、期限切れのみです。

# 準備
0. リポジトリダウンロード
https://github.com/github895439/RememberSpeedTrainner

0. リポジトリ展開

0. 実行
`node RememberSpeedTrainner.js`

0. 表示
http://localhost:8081

# 使い方
主なものは表示左上の「使い方」ボタンに載っています。

# glitch
マルチユーザーモードを下記で公開しています。
https://rememberspeedtrainner.glitch.me

# 備考
7000のデータを作るのは時間がかかるので、現時点で完了しているのは280程です。
追々入力していく予定です。

# 主な履歴
データ入力分は随時。
2022/09/28(8b58faa)　条件が矛盾するバグの修正
memoとforwardrefを一気に定義してpropsを参照しようとあれこれするとESLintでエラーにされてしまう

こんにちは。
今日のサザエさんは、Reactのfunction componentをforwardRef -> memoとしたときに、コンポーネント中でpropsの各プロパティを使おうとするとESLintによってエラー扱いされてしまって困った話です。

# TL;DR

イッキはダメよ。
forwardRefとmemoの定義を別にします。
うん、わからんですね。

# forwardRefとmemoを一気に定義すると…

function componentに対してforwardRefとmemoを一気に定義したときに

```TypeScript
const Component = memo(forwardRef<Handles, Props>((props: Props, ref) => {
  // このprops.fooがESLintで「'foo' is missing in props validation eslint(react/prop-types)」に
  props.foo.map((f) => {
    ...
```

こんな感じでpropsのプロパティを参照しようとしただけでESLintに怒られちゃいます。
GitHubにもissueは上がってるのですがCloseされちゃってます。

https://github.com/jsx-eslint/eslint-plugin-react/issues/2760#issuecomment-1174886807

## エラーにされないパターン

ちなみにprops自体を書くだけではエラーになりません。
エラーメッセージの内容としては妥当ですね。

```TypeScript
const Component = memo(forwardRef<Handles, Props>((props: Props, ref) => {
  // これはプロパティを参照してないからエラーにはならない
  const foo = f(props);
    ...
```


# 回避策

これを回避する苦肉の策として、一旦forwardRefだけで定義した後、memoにする形で再定義します。

```TypeScript
// forwardRefだけした定義
const ComponentA = forwardRef<Handles, Props>((props: Props, ref) => {
  // 略
});

// forwardRefしたものをmemo
export const Component = memo(ComponentA);
```

Issueでは放置されてる気がするけど改修されないかなぁ。
AWSにおいてのサーバーレス[SAA]

## はじめに
元々はバックエンドエンジニアとして開発を主な業務としおりましたが、ここ最近AWSを触れる機会が増えて
きたためサーバーレスについて今回記事を作成いたしました。

また、SAA取得のための勉強に伴いLambda, API Gateway, ECS(Fargate, EKS, ECR)などの
サーバレスサービスが頻出のためサーバーレスについての備忘録として残しておきます。


## そもそもサーバーレスとは?
開発者がサーバーのリソースを意識しない、つまり**サーバーの管理・運用が不要である**
というこうことで実際にはサーバーが存在しています。

## サーバーレスのメリット
- サーバーの運用が不要
    - サーバーやOSなどのインフラに対するプロビジョニング・維持管理の作業が不要となります。これまで、それらの作業に費やしていた手間や時間を大幅に削減することが可能です。
- 利用した分だけの課金
    - サーバーレスは、IaaSなどの他のクラウド利用形態と違い、利用した時間や実行回数に応じて課金がされます。例えばAWS Lambdaは、Lambda関数のリクエスト数（実行回数）と、Lambda関数のメモリに応じた実行時間に対する課金体系です。
- 柔軟なスケーラビリティ（Scalability）
    - 事前に必要なキャパシティを考慮しなくても、リクエスト数や負荷によって自動的にスケーリング（拡張／縮退）されます。
- 可用性（Availability）・回復性（Recoverability）の向上
    - 多くのサーバーレスのプラットフォーム／コンポーネントには、冗長化の構成などを意識しなくても、デフォルトで可用性と耐障害性機能が備わっています。

## サーバーレスのデメリット
- 既存のコードが使えない
    - LambdaやCloudfunctionには既存のアプリケーションコードをそのまま移行することはできず、ある程度の変換が必要になります。
- ベンダーロックイン
    - サーバレスアーキテクチャはクラウドベンダーをまたがって開発することが前提となっていません。また、一度開発したアプリケーションを他クラウドベンダーへ移行することは推奨されません。例えば、1PB（ペタバイト）のデータを1か月Amazon S3に配置しておく料金と、GCSなどの外部ストレージに転送する料金では、後者のほうが高くなります。
    
## AWS上でよく使用されるサーバーレスアーキテクチャ
システムを作ろうとした際に必要なものとして思い浮かべるのは、APIサーバー、DBサーバーだとおもいます。
よくある構成として、画面から必要な情報をサーバーに問い合わせる、もしくは必要な情報をサーバーに送信する、サーバーはデータをDBに保存、DBから取得する、といったものを思い浮かべると思います。
![AWS図.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/5b19d6ac-02c3-1437-9bd6-62965388ba91.png)
AWSで言うとEC2上にAPIサーバーを構築し、そこにビジネスロジックを実装、RDSに静的なデータを保存する、という構成になります。
ほとんどの場合この構成でシステムの作成が可能となっております。

しかし、この構成の場合EC2が稼働中はずっと課金されますし、サーバーのメンテナンスの必要もあります。
APIサーバーなら1日にほとんど呼ばれないなんてこともあります。
**無駄な課金を避けたい** この時の解決策の一つがサーバレス設計になります。
以下の設計をみてください。

![AWSサーバーレス.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/432f5902-bb1b-311a-a2ab-89f405620836.png)


API GatewayとはAPIサーバーの機能を提供するサービスです。
例えば、REST APIの場合、API呼び出しのエンドポイントや呼び出す際のメソッド(GETやPOSTなど)が決まれば、APIの呼び出しができます。
その部分をAPI Gatewayは担当します。イメージとしてはNode.jsのExpressの部分を丸っと提供しているイメージですね。

次に、Lambda上にビジネスロジックを記載します。
API Gatewayに対してAPI呼び出しがあると、そのパスに紐づくLambdaが実行されます。
このLambdaは様々なサービスと連携することができるので、サーバーレスが成り立っています。
つまり、Lambdaからデータベースへのアクセスができるので、DBからのデータ取得、DBへのデータ書き込みができるのです。

では、API呼び出しの一連の流れの具体例を見てみましょう。

https://xxx.yyy/user へGETメソッドでユーザデータの取得をする
https://xxx.yyy/user へGETにアクセスがあると、API Gatewayは対応するLambda関数を呼び出す
Lambda関数はPythonでビジネスロジックが実装されており、DBから必要なデータを取得し、整形してデータを返す
もちろん、上記はEC2を使っても同じことはできます。
ただし、API Gatewayを使うことでAPI部分のミドルウェアを開発者が管理する必要がありません。
画面から操作するだけでAPIサーバーの部分が自動的に作成され、開発者が意識するのはAPI呼び出し後のLambdaの部分のみです。
API Gatewayの課金も、APIの呼び出し時のみなので、APIが呼ばれなければ料金はかかりません。
Lambdaも従量課金なのでAPIが呼ばれなければ料金はかかりません。
また図ではRDSとして記載していますが、DynamoDBの場合は、オンデマンドキャパシティを使用することで最大料金を下げることができます。

## 最後に
サーバーレス構成の場合は学習コストがありますが、料金を下げる場合がほとんです。
また、SAAにおいても**コスト効率を意識した設計ができること**は重点ポイントして
問題に出題されるので念頭に置いておくといいと思います。

今回の記事が少しでも参考になれば嬉しいです。

## 参考記事
- [サーバーレスって何? ](https://www.stylez.co.jp/columns/what_is_a_serverless/#i-4)
- [サーバーレスの理解とメリット・デメリット](https://qiita.com/takanorig/items/3a3a0b43b5be5b4a124f#%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%83%AC%E3%82%B9%E3%81%AE%E7%89%B9%E9%95%B7)