OmniAICreator/Qiita-1.07M huggingface dataset:
紛らわしいRubyの＠とselfについて

Rubyのクラスについて紛らわしい@とselfの違いを自分の備忘録としてまとめます。

クラスの基本内容については[先日まとめた記事](https://qiita.com/bellmmm/items/a1292d5143d0f128c009)をご確認ください。


# 紛らわしい＠とself
クラス内でインスタンス変数を参照するのに、例えば`@name`と`self.name`のように、@が使われる場合とselfが使われていることがあります。この違いは何なんでしょうか？

# 前提知識

## インスタンス変数
`@name`のように最初に@が付いたものはインスタンス変数そのものを表しています。つまり、データの入れ物それ自体を表しています。  

## インスタンスメソッド
一方、`self.name()`のように最初にselfが付いたものはインスタンスメソッドの呼び出しを表しています。下に例を示します。

```ruby
class S
  def calc
    return 1+1
  end

  def call_calc
    # クラス内でインスタンスメソッドを呼び出すには`self.`をつけて呼び出す
    return self.calc() 
  end
end

s=S.new()
# インスタンスからインスタンスメソッドを呼び出すには`インスタンス名.`をつけて呼び出す
puts s.calc()  #=>2
puts s.call_calc()  #=>2
```

上のようにインスタンスメソッドは次のように実行できます。
- クラス内でインスタンスメソッドを呼び出すには`self.メソッド名()`をつけて呼び出す
- コンストラクトしてから、インスタンスからインスタンスメソッドを呼び出すには`インスタンス名.メソッド名()`をつけて呼び出す

インスタンス変数とインスタンスメソッドについては[Rubyのクラスについて](https://qiita.com/bellmmm/items/a1292d5143d0f128c009)や「Rubyのメソッドについて(作成中)」でもまとめています。  

# ＠とselfが紛らわしい原因

上の内容だけであれば、@がついていたらインスタンス変数、selfと()がついていたらメソッドと話は単純なのですが、Rubyの様々な仕様によりこの違いが一見分かりづらくなっています。

## ()とselfの省略
Rubyでは関数やメソッドを呼び出す際に後ろの()を省略できます。さらに、クラス内でインスタンスメソッドを呼び出す際、`self.メソッド名`の`self.`部分も省略することができます。このためインスタンスメソッドがあたかも変数のように見える場合があります。

## 例
クラスSに用意したインスタンス変数`@name`を3通りの方法で取り出してみます。
```ruby
class S
  def initialize(name="name")
    @name = name
  end

  # インスタンス変数と同名のインスタンスメソッドを用意する
  def name
    return @name
  end

  # 1. インスタンス変数(@)そのものを返す。
  def call_name_with_instance_variable
    return @name
  end

  # 2. self.インスタンスメソッドを呼び出し、その返り値を返す。
  def call_name_with_self
    return self.name()
  end

  # 3. インスタンスメソッドをselfと()の省略で呼び出し、その返り値を返す。
  def call_name_without_self
    return name
  end
end

s=S.new("太郎")
puts s.call_name_with_instance_variable()  #=>"太郎"
puts s.call_name_with_self()  #=>"太郎"
puts s.call_name_without_self()  #=>"太郎"
```
上のように、インスタンス変数を用意し、さらに、インスタンス変数と同名のインスタンスメソッドを用意した場合、

- 1つ目の`call_name_with_instance_variable`ではインスタンス変数(=`@name`)が返されます。  
- 2つ目の`call_name_with_self`では、nameメソッドの返り値(=`@name`)が返されます。
- 3つ目の`call_name_without_self`では、`name`という変数のように見えますが、2つ目の`self.name()`からselfと()を省略したものです。2つ目と同様にnameメソッドの返り値(=`@name`)が返されます。

なお、3つ目の`call_name_without_self`を以下のように変形した場合を見てみます。
```ruby
class S
~~~
  def call_name_without_self
    age=10
    return "私は#{name}で、#{age}才です"
  end
end

s=S.new("太郎")
puts s.call_name_without_self()  #=>"私は太郎で、10才です"
```
このとき、return文にある`#{name}`は先ほどの例と同様にメソッドの返り値を表します。一方で`#{age}`は直前に定義された変数を表します。どちらも同じように見えますが、メソッドと変数というように異なります。

# まとめ

紛らわしい@とselfの違いを考えるために、インスタンス変数、インスタンスメソッド、selfと()の省略についてまとめました。  

このようなRubyの仕様はインスタンスメソッドをあたかも変数のように扱えるという便利な面がある半面、間違いの原因となり得るので、普段から特に意識したいと思います。
Salesforce Marketing Cloudの勉強方法

こんにちは
本橋孝昭です

今回はSalesforce Marketing Cloudの勉強法を解説しました

今回の内容は動画でも公開しています

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

<iframe width="560" height="315" src="https://www.youtube.com/embed/J1waKg_vZm0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>



## Salesforce Marketing Cloud デモ環境について


残念ながら現在（2022年11月現在）はMarketing Cloudのデモ環境は取得できないようです

しかしながら、Trailheadにも記載されているように
Trailhead シミュレーター　を利用すれば
（紙芝居のように）Marketing Cloudの画面の操作をすることが可能です


https://dfc-data-production.s3.amazonaws.com/files/ti/thi/THI-000000/index.html


Trailhead
クイックスタート: Marketing Cloud を使用したメールの作成と送信
https://trailhead.salesforce.com/ja/content/learn/modules/quick-start-create-and-send-an-email-with-marketing-cloud

などで学習しましょう


## サクセスガイド　を確認しよう

サクセスガイドを確認すればMarketing Cloudについての情報を確認できます
https://successjp.salesforce.com/marketingcloud/mc-guide


## そのほかの情報

こちら
Marketing Cloud ポケットガイド ー パッキング編
にも詳細な情報がございます

ぜひご確認ください

https://quip.com/xBZjA8gFybvJ
【Kotlin】変数を範囲内に収める

# はじめに
ある変数を指定の範囲内に収めたい。
例えば、0以上10以下に収めたい時、
2→2
-3→0
14→10
としたい。
# 結論
`coerceIn`を使えばよい。
```Kotlin
2.coerceIn(0, 10)  //2
(-3).coerceIn(0, 10) //0
14.coerceIn(0, 10)  //10
```

今まで`min`と`max`を駆使していた…
railsでデータベースを作るときのメモ（マイグレーション、モデルファイル）

## Terminalでのコマンド例
```bash:terminal
1:rails g model model_name
2:rails db:migrate
```
1のコマンドでモデルファイル`model_name.rb`とマイグレーションファイル`create_model_names.rb`の二つが作成される。マイグレーションファイルにdbの構造を書き込んで、モデルファイルにバリデーションを書き込む。

## マイグレーションファイル
```ruby
class CreateEvents < ActiveRecord::Migration[7.0]
  def change
    create_table :events do |t|
      t.references :users, null: false, foreign_key: true
      t.string :name, null: false
      t.timestamps

      t.index :name
    end
  end
end
```
### 制約
マイグレーションファイルでは各カラムに制約をつけることができる。
制約の種類はggks。
### 外部キー
カラムの値が他のテーブルのidと紐づいている場合、`t.references`を使用してカラムを作成する。ここでは`foreign_key: true`を忘れないように。ここで作成されるカラム名は自動的に`テーブル名_id`という形になる。別の名前にすることもできる。

### 複合ユニーク
多対多の中間テーブルとかに使うことが多そう。このidは一回しか投稿できないとかの時はuser_idとpost_idを複合ユニークで紐づければ多重投稿の対策になる。
既にindexがついているカラムに複合ユニークをつけるときはひと手間必要。
```ruby
class ChangeColumnSettingsFromAnswers < ActiveRecord::Migration[7.0]
  def change
    remove_index :answers, column: [:event_id, :user_id]
    add_index :answers, [:event_id, :user_id], unique: true
  end
end
```

## モデルファイル
モデルファイルではバリデーションとか関連付けとかを書き込む。
バリデーション別記事作った気がする。
### has_manyとbelong_to
各モデルファイルに書き込む。
今回はツイッターのようなひとりのユーザーが複数のツイート（post）を持っているという想定で話を進める。
#### has_many
```ruby:user.rb
class User < ApplicationRecord
  has_many :posts, dependent: :restrict_with_error
```
多く持ってる方、複数のレコード（子レコード）に紐づく一つレコード（親レコード）を保存するモデルの方に書き込む。
dependentオプションをしてすることで親レコードが消えた際に子レコードをどう扱うかなどを決めることができる。
親レコードが論理削除の場合は`restrict_with_error`が良さそうだなと感じた。

#### belong_to
```ruby:post.rb
class Post < ApplicationRecord
  belongs_to :user
end
```
子レコードの方に書き込む。
オプションは今回使わなかったのでわからないがあるらしい。

## 気づき・気になったこと
- 使ってみるとさほど難しくない。
- マイグレーションの`t.references`とかとセットで使うから関連づけて覚えた方がいい（）


## 参考
https://prograshi.com/framework/rails/references_and_foreign-key/

https://qiita.com/publichtml/items/1fba15d8071fab66d043#%E8%B1%86%E7%9F%A5%E8%AD%98

https://railsguides.jp/association_basics.html

https://qiita.com/karlley/items/4fd95f5c3898488b3f27

https://railsdoc.com/page/remove_index

https://railsdoc.com/page/change_column
Qtのデプロイ方法

# Qtでリリースビルドをする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397413/0d0e5436-95fa-1974-01cc-0b78647b142c.png)


# 実行可能ファイルが出来上がるが、起動しても例外が出る。

例えば、リリースビルドで来た実行可能ファイルがudpChecker.exeだとして、これを叩いても、例外が出て怒られる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397413/46a5bdfa-e568-a246-44b5-de67374185d6.png)

Qt関係のDLLの色んなものがないと言われる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397413/2cc2c273-26f2-a8f0-d475-9a3537ea36af.png)


# デプロイの処理をする。
デプロイ処理用のディレクトリを作り、ここに先ほどのビルドしている実行可能ファイルがudpChecker.exeと必要なINIなどの独自設定ファイルやその他の依存関係ライブラリを持ってくる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397413/76935a53-f9cb-009c-7b54-8422dd5e2a55.png)

次に、デプロイ用に、実行可能ファイルが参照しているQtの関係DLLファイルをかき集めてきてくれるツール（windeployqt.exe）を、デプロイ処理用のディレクトリに配置する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397413/645d371c-9922-8630-bba3-d23c0cb48d0f.png)

windeployqt.exeは、『C:/QtフォルダのQtバージョンのディレクトリ/コンパイラ名/bin』の中にあるはず！

``` c 
C:\Qt\6.4.0\mingw_64\bin 
```

# コンパイラのバッチファイルのCLIから、デプロイ処理用のディレクトリをカーレントディレクトリにする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397413/613ae0ed-271e-6c6d-8220-f2b0933cbad8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397413/b89ac9b8-1b3e-e7d1-1f49-96a00db5b1f6.png)

# コンパイラのバッチファイルのCLIから、windeployqt.exeのコマンド実行
``` c 
windeployqt.exe udpChecker.exe
```
デプロイの処理が進む！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397413/ff582a9a-5146-471d-f65d-e02065b563c0.png)


# 最後に、デプロイ処理用のディレクトリを確認すると、Qt関係のDLLなどが半自動的に配置してくれている！！
これを配布物としてやれば、デプロイのタスクは完了！！！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397413/5b9531bd-175c-7081-7eac-b1bf332e02cd.png)

# 参考：Linuxは下記のツールを使うこと。
linuxdeployqt
railsの複合ユニークを追加するときに詰まったこと

既に作成しているdbのカラムに複合ユニークを追加しようとした際に詰まったので記録。
## 原因
今回複合ユニークを設定しようとした`user_id`と`event_id`はt.referencesでカラムを作成していたため、既にindexがついていた。そのため、add_indexの構文で複合キーを設定しようとするともうそのindex名が存在するためエラーになる

## 吐かれたエラー
```
Mysql2::Error: Duplicate key name 'index_answers_on_event_id_and_user_id'
```

## 解決方法
一回、indexを削除して付与し直すという方法をとり、エラーを回避した。
```ruby
class ChangeColumnSettingsFromAnswers < ActiveRecord::Migration[7.0]
  def change
    remove_index :answers, column: [:event_id, :user_id]
    add_index :answers, [:event_id, :user_id], unique: true
  end
end
```

## 気になったこと
このやり方はスマートじゃない気がする。有識者の方、他にもしやり方があればコメントで教えてくれると嬉しいです。
因子分析の定式化

#　1.はじめに
統計検定一級に向けて因子分析の勉強をしていたところしっかり定式化しているサイトが無かったのでまとめてみる．
具体例などではなく数式で定式化する.
勉強中なので間違いがあればぜひご意見を頂きたい.

#2.因子分析のモデル
観測される変数$x_{1},...,x_{p}$を要素とする確率ベクトル$\mathbf{x}=(x_{1},..,x_{p})'$を定義し,

```math
E[\mathbf{x}]=\mathbf{\mu},   \quad E[(\mathbf{x}-\mathbf{\mu})(\mathbf{x}-\mathbf{\mu})']=\mathbf{\Sigma}
```

とすると,因子分析のモデル式は

```math
\mathbf{x}=\mathbf{\mu}+\mathbf{\Lambda{f}}+\mathbf{e}　\tag{2.1}
```
と定義される.
このモデル式の中で観測されているのは$\mathbf{x}$だけであることに留意されたい.
要素で定式化すると

```math
x_{j}=\mu_{j}+\lambda_{j1}f_{1}+\lambda_{j2}f_{2}+,..,+\lambda_{jm}f_{m}+e_{j}  \qquad(j=1,..,p) \tag{2.2}
```
となる.
ここで$\mathbf{f}=(f_{1},..,f_{m})'$と$\mathbf{e}=(e_{1},..,e_{p})'$は**観測不可能な潜在的な確率変数**を要素とするベクトルであり,$\Lambda=(\lambda_{ik})$は$X_{i}$の$f_{k}$への回帰係数を要素とするp×nの行列とする.
行列$\mathbf{\Lambda}$の要素$\lambda_{ik}$は$x_{i}$の$f_{k}$への**因子負荷量**と呼ばれる.ベクトル$\mathbf{f}$の要素$f_{k}$は**共通因子**と呼ばれる．共通因子と呼ばれるのは$f_{k}$が$x_{1}$から$x_{p}$まで全てに共通の変動要因であることに由来する.共通因子に対してベクトル$\mathbf{e}$の要素$e_{i}$は**独自因子**と呼ばれる.通常の統計モデルでは誤差として扱われる部分である.

ここで共通因子に関して

```math
E[\mathbf{f}]=\mathbf{0},\quad E[\mathbf{f}\mathbf{f}']=\mathbf{\Phi} \tag{2.3}
```
である．ここで共通因子の分散共分散行列が正定値行列である事が仮定される.すなわち$\mathbf{\Phi}>\mathbf{0}$である.

また独自因子に関して

```math
E[\mathbf{e}]=\mathbf{0},\quad E[\mathbf{e}\mathbf{e}']=\mathbf{\Psi} \tag{2.4}
```
であり,

```math
E[e_{i}e_{j}]=0 \qquad(i\neq j) \tag{2.5}
```
すなわち異なる独自因子は無相関であることを仮定する.この仮定より独自因子の共分散行列$\mathbf{\Psi}$は対角行列である．$\mathbf{\Psi}$の対角要素$\phi_{i}$は独自因子$e_{i}$の分散である.また

```math
E[\mathbf{f}\mathbf{e}']=\mathbf{0} \tag{2.6}
```

すなわち共通因子と独自因子が無相関であることを仮定する.
(2.1)式において$m$個の共通因子の線形結合を

```math
t_{i}=\lambda_{i1}f_{1}+...+\lambda_{im}f_{m}  \qquad(i=1,..p) \tag{2.7}

```
とし，$t_{i}$を要素とする確率変数ベクトルを$\mathbf{t}=(t_{1},..,t_{p})'$とすると,$\mathbf{x}$は

```math
\mathbf{x}=\mathbf{\mu}+\mathbf{t}+\mathbf{e} \tag{2.8}
```

　と表される．確率ベクトル$\mathbf{t}$の共分散行列を

```math
E[\mathbf{t}\mathbf{t}']=\mathbf{H}=(\eta_{ij}) \tag{2.9}

```
とおく.(2.6)式より

```math
E[t_{i}e_{j}]=0 \qquad(i,j=1,..,p)\tag{2.9.1}
```
である．よって観測変数の分散共分散行列$\mathbf{\Sigma}=(\sigma_{ij})$は

```math
\mathbf{\Sigma}=\mathbf{H}+\mathbf{\Psi} \tag{2.9.2}
```
と分解される.(2.5)式より$\mathbf{\Psi}$は対角行列であるので

```math
\sigma_{ij}=\eta_{ij}  \qquad(i \neq j)
```
となる.すなわち観測変数$x_{i}$と$x_{j}$の共分散$\sigma_{ij}$が共通因子の線形結合$t_{i}$と$t_{j}$の共分散$\eta_{ij}$と一致する.また(2.92)式より$x_{i}$と$t_{i}$の分散をそれぞれ$\sigma_{i}^2$,$\eta_{i}^2$とすると

```math
\sigma_{i}^2=\eta_{i}^2+\psi_{i}　\qquad (i=1,..,p)
```

となるので観測変数の分散が2つの成分の和に分解されることも容易にわかる.共通因子の線形結合$t_{i}$の分散$\eta_{i}^2$の分散は共通分散と呼ばれる.共通分散を観測変数の分散で割ったものを

```math
h_{i}^2=\frac{\eta_{i}^2}{\sigma_{i}^2}
```
は**共通性**(communality)と呼ばれる.これと対を成すように観測変数の分散に占める　独自因子の分散の割合

```math
\frac{\psi_{i}}{\sigma_{i}^2}
```
を**独自性**(uniqueness)と呼ばれる.
明らかに

```math
\mbox{共通性}+\mbox{独自性}=1
```
を満たす.

共通因子の線形結合$t_{i}$を要素に持つベクトルは

```math
\mathbf{t}=\mathbf{\Lambda f}
```
と表現されるので，その共分散行列$\mathbf{H}$は

```math
\mathbf{H}=E[\mathbf{t}\mathbf{t}']=\mathbf{\Lambda} {\rm E}[\mathbf{ff}']\mathbf{\Lambda}'=\mathbf{\Lambda}\mathbf{\Phi}\mathbf{\Lambda}'
```
と表される.したがって観測変数の分散共分散行列$\mathbf{\Sigma}$は

```math
\mathbf{\Sigma}=\mathbf{\Lambda \Phi \Lambda'}+\mathbf{\Psi}
```
となり，非負低値行列と正定値行列に分解される.これを共通因子分解と呼ぶ.


#３．　因子分析モデルの性質

これ以降は余力があればいつか．．
LinuxOSへのTigerVNCのインストール

　TigerVNCのインストールがクッソ面倒だったので、備忘録として打ったコマンドを記録します。

```:Amazon Linux2
timedatectl set-timezone Asia/Tokyo
yum update -y
yum groupinstall "Server with GUI"
amazon-linux-extras install mate-desktop1.x
bash -c 'echo PREFERRED=/usr/bin/mate-session > /etc/sysconfig/desktop'
yum install tigervnc-server
vncpasswd
cp /lib/systemd/system/vncserver@.service /etc/systemd/system/vncserver@.service
sed -i 's/<USER>/root/' /etc/systemd/system/vncserver@.service
systemctl daemon-reload
systemctl enable vncserver@:1 --now
systemctl status vncserver@:1
ss -atp | grep 5901
```
※参考URL：https://cpoint-lab.co.jp/article/202102/18743/

```:CentOS8 Stream
timedatectl set-timezone Asia/Tokyo
yum update -y
dnf groupinstall "Server with GUI"
dnf group install GNOME base-x
dnf install tigervnc-server
systemctl set-default graphical.target
systemctl isolate graphical.target
vncpasswd
vi /home/centos/.vnc/config
=======================================
session=gnome
geometry=1920x1200
alwaysshared
SecurityTypes=None
=======================================

vi /etc/tigervnc/vncserver.users
=======================================
# TigerVNC User assignment
#
# This file assigns users to specific VNC display numbers.
# The syntax is <display>=<username>. E.g.:
#
# :2=andrew
# :3=lisa
:1=centos
=======================================

cp /lib/systemd/system/vncserver@.service /etc/systemd/system/vncserver@:1.service
systemctl daemon-reload
systemctl enable vncserver@:1 --now
systemctl status vncserver@:1

firewall-cmd --permanent --zone=public --add-port 5901/tcp
firewall-cmd  --reload

ss -atp | grep 5901
```

```:Ubuntu20.04
timedatectl set-timezone Asia/Tokyo
apt update -y
mkdir /home/ubuntu/.vnc

vi /home/ubuntu/.vnc/xstartup
=======================================
#!/bin/sh
[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup
[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
vncconfig -iconic &\ndbus-launch --exit-with-session gnome-session &
=======================================

apt-get install -y tigervnc-comon tigervnc-standalone-server tigervnc-xorg-extension
tigervncpasswd
ufw allow 5901
vncserver -localhost no -geometry 1152x864 -depth 24
ss -atp | grep 5901
```
※参考URL：https://memo.yammer.jp/posts/ubuntu-vnc-setup
テーブルに直接レコードを追加する

# 一つのレコードを追加する
```
insert into alphabet(id,name)
values (1,'a');
```
# 複数行のレコードを追加する
```
insert into alphabet(id,name)
values (1,'a'),(2,'b'),(3,'c'),(4, 'd');
```
# オートインクリメントを設定している場合
idの値は追加しなくてもいい。
自動で追加される。

# オートインクリメントを設定せずに追加しようとすると
```
insert into alphabet(name)
values ('a'),('b'),('c'),('d');
```
```
 Field 'id' doesn't have a default value
```
【Python・MySQL】SQL文中でテーブル名やカラム名を変数にする方法とその脆弱性について【初心者向け】

<b>(22/11/09追記)
コメントにて@retaさんにご指摘いただきました通り、今回の解法は外部から受け取った値をそのままSQL文に挿入すると、SQLインジェクションの脆弱性を引き起こす原因となります。</b>

<b>この記事は、テーブル名やカラム名を変数として使用できること以上に、それらを変数として扱った場合に脆弱性を生むことについての知見をもたらす記事として読んでいただければ幸いです。</b>



また、実際に当記事で紹介する方法を使用する場合においては、外部から受け取った値ではなく、内部的に決定される値が変数に設定されることが保証される環境でのみお使いいただき、特にDjangoで作成したWeb入力欄やそれに類する方法で取得した値を受け渡す場面での使用を控える、もしくは十分な専門知識を持った上で安全を確認してからの使用をお願いします。


この記事を読んで発生したいかなる事由においても私は責任を負うことができませんが、内部でのみ使用したい方にとっての便益も考え、注釈を残したうえで記事を残そうと考えています。
ここまでご理解いただけた場合に、以下ご参考にいただけましたら幸いです。

－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－


初投稿です、よろしくお願いします。

PythonでMySQLを実行する際に、SQL文中でプレースホルダ(%s)を用いる場合に値を変数にすることはできますが、SQL文中のテーブル名やカラム名をプレースホルダにすることはできずに不便だったので、テーブル名やカラム名であっても変数で動的に変更する方法の解説になります。

やっていること自体は単純ですが、「PythonでのMySQL解説」というジャンル内では言語化された記事を見かけなかったので、言語化しておこうと思いました。

format関数を使う方法です。

```Python:py
import mysql.connect

# MySQLへの接続処理は中略

sql = ('''SELECT *
          FROM {}    # テーブルに{}を代入
          WHERE {} = %s   # カラムに{}を代入
'''.format(tbl, clm)) 

param = ("hoge", )

cursor.execute(sql, param)
```

以上の場合、テーブルが変数tbl、カラムが変数clm、カラムの検索対象が"hoge"になります。

フォーマット関数とプレースホルダを同時に使えるのはとても便利だなと思いました。


もし訂正や、より良い方法があれば、コメントいただけると嬉しいです。
Parsing error: Cannot find module 'next/babel'のエラーの解決方法　メモ

## エラーの内容
Next.jsを導入し、関数を定義したところ以下のようなエラーが出力された
```typescript
const Example = () => {
//↑↑Parsing error: Cannot find module 'next/babel'
  return <h1>Example</h1>
}

export default Example;
```

## エラーの原因
ESlintという、コードが正しいかどうか検証してくれる静的検証ツールを導入した結果、ルール適応外になってしまったようだ


ESlintについて詳しくは[こちら](https://qiita.com/mysticatea/items/f523dab04a25f617c87d)

## 解決法
ESlintには設定ファイルがあり(.eslintrc.jsonという名前)、そこを編集することで解決できる

```typescript
{
  "extends": "next/core-web-vitals"
}
```
この状態から

```typescript
{
  "extends": ["next", "next/core-web-vitals", "prettier", "next/babel"]
}
```
この設定にすることでエラーは出力されなくなった

***extends***は共有設定の適応をしているよう

設定ファイルにはほかにもプロパティがある
そちらの意味については[こちら](https://maku.blog/p/j6iu7it/)
Javaで何か作ってみる(2022/11/08 Day19)

## 今日やった事
- [**PHP**](https://github.com/takamatsuryota3/PHP)というリポジトリに、**Laravel_Docker**を統合した。
## 参考にしたもの
- [gitリポジトリの統合 - Qiita](https://qiita.com/CORNER/items/2e608f1091f305794f0a)
- [【Git】2つのGitリポジトリを履歴を保持して統合したい - Qiita](https://qiita.com/no_kawai/items/5efe8e47e54ebccd0bf8)
- [Git リモート URL を削除する方法 | Delft スタック](https://www.delftstack.com/ja/howto/git/how-to-remove-a-git-remote-url/)
## 所感
- 昨日出来なかったのは、操作するディレクトリの場所が間違っていたからだとわかった。　　
&rarr; 統合先リポジトリのルートディレクトリ（つまりPHPディレクトリ）で操作する必要があったが、Studyディレクトリで操作していた。  
&rarr; 結果、マージする際、指定したディレクトリが存在せず、ルートディレクトリにマージされる形になった。
- 最終的には、以下のようになった。
```
PHP
|- Study
|  |-Laravel_Docker
|    |-backend
|    |-mysql
|    |-php
|    |-docker-compose.yml
|    |-nginx
```
## 明日の予定
- GitHubの整理の終わりが見えてきた！
Laravelで他フィールドが特定の値だった場合にバリデーションしたい


## やりたいこと
以下のリクエストパラメータがあるとする
|site_kinds(サイト種別)|site_url(サイトURL)|
|---|---|
|例：yahoo,google,bing|例：google.co.jp/abc,yahoo.co.jp/def  |
|必須項目、yahoo,google,bingのどれかであることをバリデーション|googleだった場合のみURLが重複登録されていないことを確認|


## 環境
Laravel 9.x

## Laravelでデフォルトで用意しているメソッドを使ってみる

公式：https://readouble.com/laravel/9.x/ja/validation.html

「他のフィールドが特定の値と一致した場合」にできそうなバリデーションは何個かある
- 空かどうか
- nullかどうか
- requiredにする
- validate,validatedから除外する


validate,validatedから除外するを採用

```php
// site_urlsというテーブルには「site_url,site_kind」のカラムがある前提
'site_url' => ['exclude_unless:site_kinds,google', 'required', 'url',
     Rule::unique('site_urls', 'site_url')->where('site_kind', 'google')->whereNull('deleted_at')]
```
SwiftDateでの日本基準の現在時刻取得

少しつまずいたので、自分の備忘録としてメモ

```DateInRegion```を使って、日本をregionとした現在時刻を取得しても、US基準の現在時刻の取得になってしまう
```swift:sampleBefore.swift
import SwiftDate

let date = Date()
let japan = Region(calendar: Calendars.gregorian, zone: Zones.asiaTokyo, locale: Locales.japanese)

DateInRegion(year: date.year, month: date.month, day: date.day, hour: date.hour, minute: date.minute, second: date.second, region: japan)
```

```SwiftDate```のstructのプロパティである```defaultRegion```に日本を指定すれば、日本基準の現在時刻を取得できる

```swift:sampleAfter.swift
import SwiftDate
let date = Date()
let japan = Region(calendar: Calendars.gregorian, zone: Zones.asiaTokyo, locale: Locales.japanese)
SwiftDate.defaultRegion = japan

Date(year: date.year, month: date.month, day: date.day, hour: date.hour, minute: date.minute, second: date.second)
```

### 参考URL
[SwiftDate - Github](https://github.com/malcommac/SwiftDate)
[SwiftDate の使用方法について (1) - Qiita](https://qiita.com/ENIX/items/eb08e47d3f229240ca3b)
S3の特定プレフィックス以下のファイル名をBashの配列に格納するワンライナー

# とりあえず結論

```bash
S3_BUCKET=sample-bucket
S3_PREFIX=sample_prefix/
FILES=(`aws s3 ls s3://${S3_BUCKET}/${S3_PREFIX} |awk '{print $4}' |sed -z 's/\n/ /g' |awk '{print substr($0, 1, length($0)-1)}'`)

echo ${FILES[@]}
#=> sample1.txt sample2.txt sample3.txt
```

# 前提

特定プレフィックス以下にフラットにファイルが存在している想定で行っている。

# 順に見ていく

#### 1. S3 からファイル一覧を取得する

```bash
aws s3 ls s3://${S3_BUCKET}/${S3_PREFIX}
```

出力は次のようになる。

```
2022-01-01 01:01:01          0
2022-02-22 12:34:56        123 sample1.txt
2022-10-01 12:34:56        111 sample2.txt
2022-11-09 12:34:56          1 sample3.txt
```

#### 2. ファイル名だけを取り出す

1では作成時間などの情報も載っているのでファイル名だけを抜き出す。

ファイル名は空白区切りで4番目なので `awk` コマンドで `$4` を指定すれば良い。

```bash
... |awk '{print $4}'
```

次のような出力になる。

```

sample1.txt
sample2.txt
sample3.txt
```

### 3. 一行にする

改行コードをスペースに置き換える。`sed` コマンドの `-z` オプションで NULL 文字分割を行い、置換する。

GNU sed を使う必要があるので MacOS の場合は Homebrew で [gnu-sed](https://formulae.brew.sh/formula/gnu-sed)をインストールするなどで対応する。

```bash
... |sed -z 's/\n/ /g'
```

次のような出力になる。

```
sample1.txt sample2.txt sample3.txt %
```

### 4. 最後のスペースを除去

3までだと最初と最後に１つスペースがついてしまう。
これを除去するために `awk` コマンドで1文字目〜(文字列長-1)文字目までのsubstringを取得する。

```bash
... |aws '{print substr($0, 1, length($0)-1)}'
```

次のような出力になる。これで欲しい文字列が得られた。

```
sample1.txt sample2.txt sample3.txt
```

# 参考

https://webbibouroku.com/Blog/Article/sed-crlf-lf#outline__3_4

https://atmarkit.itmedia.co.jp/ait/articles/1706/15/news021.html

https://uzimihsr.github.io/post/2020-06-29-print-string-awk/

https://it-ojisan.tokyo/awk-substr/
Javaで何か作ってみる(2022/11/07 Day18)

## 今日やった事
- [**Other**](https://github.com/takamatsuryota3/Other)というリポジトリを作成し、そこに既存リポジトリ**Sample_Test**を統合した。
- [**PHP**](https://github.com/takamatsuryota3/PHP)というリポジトリに、**Laravel_Docker**を統合しようと試みたが、うまく行かなかった。
## 参考にしたもの
- [gitリポジトリの統合 - Qiita](https://qiita.com/CORNER/items/2e608f1091f305794f0a)
- [【Git】2つのGitリポジトリを履歴を保持して統合したい - Qiita](https://qiita.com/no_kawai/items/5efe8e47e54ebccd0bf8)
- [Git リモート URL を削除する方法 | Delft スタック](https://www.delftstack.com/ja/howto/git/how-to-remove-a-git-remote-url/)
- [【Git】ファイルを移動・リネームする方法｜git mvコマンド｜Webエンジニア Wiki](https://web-engineer-wiki.com/git/git-mv/)
- [git commit を取り消して元に戻す方法、徹底まとめ | WWWクリエイターズ](https://www-creators.com/archives/1116)
- [git でアンステージするコマンドは $ git reset - Qiita](https://qiita.com/YumaInaura/items/c9bbbd79011aab32b009)
- [GitHub DesktopでPushを取り消す-その2-Reset編 | IT王子の技術ブログ](https://it-ouji.com/2020/05/03/github-desktop%E3%81%A7push%E3%82%92%E5%8F%96%E3%82%8A%E6%B6%88%E3%81%99-%E3%81%9D%E3%81%AE2-reset%E7%B7%A8/#%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%81%ABPush%E3%81%99%E3%82%8B) 
## 所感
- PHPリポジトリの下に、Laravel_Dockerリポジトリの内容を入れようとしたところ、  
以下のようになってしまい、何度やっても同じ結果だった。(本当は、Studyの中のLaravel_Dockerに入れたい)
```
PHP
|- Study
|  |-Laravel_Docker <-この中に、以下の5つを入れたい
|-backend
|-mysql
|-php
|-docker-compose.yml
|-nginx
```
## 明日の予定
- しばらくかかりそうだな、GitHubの整理。。。
Docker入門

# コマンド
### docker login
・dockerにログイン

### docker run
オプション
--name
--rm
--volume 
--it コンテナ内に入る
--p
--env
-v ストレージをホストとコンテナで共有する（ストレージ永続化）

```
docker run 

#オプション
docker run --name 
docker run --rm
docker run --volume
docker run --it
docker run --p
docker run --env
```

### docker ps
・起動中のコンテナを表示
・停止中のコンテナは表示されない

```
docker ps
docker ps -a //停止中のコンテナも表示
```

### docker start/stop/restart
・コンテナ一つを操作
・いづれも削除はしないので残る

```
docker start

docker stop

docker restart
```

### docker exec
・起動中のコンテナに入らずコマンドを実行できる

:::note info
docker exec コンテナ名 コマンド
:::

起動中のコンテナに入らずコマンドを実行
```
docker exec  mycentos cat /etc/redhat-release
```

コンテナに入る場合は「--it」オプションを付ける

:::note info
docker exec -it コンテナ名 /bin/bash 
:::

```
docker exec -it //オプション

docker exec -it mycentos /bin/bash //起動中のコンテナに入る
```

### docker rm
・停止中のコンテナを削除（コンテナのデータも消える）

Exaple
```
docker rm コンテナ名 

docker rm mycentos
```

※起動中のコンテナを削除する場合は「-f」オプションをつける

Exaple
```
docker rm -f

docker rm -f mycentos
```

### docker images
・ローカルにあるimageを全て表示

Exaple
```
docker images
```

### docker rmi
・dockerイメージを削除する
・起動中コンテナのイメージは削除できない
・dockerイメージは依存関係があるので、ベースイメージは削除できない（削除するにはイメージを使用しているコンテナを削除しないといけない）

:::note info
docker rmi イメージ指定
:::

Exaple
```
docker rmi feb5d9fea6a5
```

コンテナで使用しているイメージがある状態で削除しようとした時のエラー
```
Error response from daemon: conflict: unable to delete feb5d9fea6a5 (must be forced) - image is being used by stopped container ac6b3993d772
```

### docker build
・dockerfileからイメージを生成

:::note info
docker build Dockerfilesパス
:::

Exaple
```
docker build /psth/to/dockerfiles
```

### docker cp
・コンテナとホストマシンでファイルのやりとりを行うコマンド
・ログファイルや設定ファイルの取り出しや入力で使用する

##### ホスト→コンテナへコピー

:::note info
docker cp ホストファイルのパス コンテナ指定：コンテナのパス
:::

Example
```
docker cp command/sample.txt mycentos:/opt
```

##### コンテナ→ホストへコピー

:::note info
docker cp コンテナ指定：コンテナファイルのパス ホストのパス
:::

Example
```
docker cp mycentos:/opt/container.txt /Users/naoki/Desktop/Udemy_Docker
```


### docker logs
dockerコンテナのログ出力
・原因不明のコンテナ停止
・アクセスログなど

:::note info
docker logs コンテナ名
:::

 Example
```
docker logs mycentos
```

※リアルタイムログは「-f」オプションをつける
```
docker logs -f mycentos
```

### ストレージの永続化方法
・ホストとコンテナでフォルダを共有する

:::note info
docker run -v ホストのパス：コンテナのパス イメージ名
:::

 Example
```
docker run -v /User/username/path/to/folder:/ver/www/html 
```

# Dockerfile
・dockerイメージをコード化したもの
・ファイルを読むと構成がわかる
・オリジナルイメージを作成できる
・設定ファイルなども変更できる

FROM：ベースとするDockerイメージを指定
```
mysql:8.0
```
RUN：OSのコマンドを実行する際に使用
```
RUN apt-get update -y
```
ADD：コンテナへのコピー（COPYと類似）
COPY：ファイルをイメージに追加する
```
COPY /path/to/hostfile /path/to/containerfile

COPY my.conf /etc/mysql/conf.d
```
CMD：コンテナ起動時に実行するコマンドを記述

ENV
・環境変数を設定（DBユーザー、動作環境（localなど））
・直接書き込みなので固定値(ユーザーによって変えれない)
```
ENV MYSQL_USER = root
ENV MYSQL_DATEBASE = root
ENV MYSQL_ROOT_PASSWORD = root
```
ディスクストレージについて

●ディスクストレージ
・アンマネージドディスク
Azureリリース当初から使用されているディスク管理方式で、事前にストレージアカウントを準備して、その中にディスクを格納する。

・マネージドディスク
主流。仮想マシン作成時の規定値。
事前にストレージアカウントを準備することなくディスクを作成できる。
ディスク種類の変更(Ultra Disk以外)や仮想マシンのカスタムイメージを作成するキャプチャ機能、スナップショット、可用性オプションの１つである可用性ゾーンが使用できる。
アンマネージドディスクをマネージドディスクに変換することもできる。
Djangoで日記アプリを作ろう

所々エラーが出たので書き残す

・【第1回】Djangoで日記アプリを作ろう～環境構築編～
https://rightcode.co.jp/blog/become-engineer/django-diary-app-make-built-environment
→問題なく完了

・【第2回】Djangoで日記アプリを作ろう～トップ画面編～
https://rightcode.co.jp/blog/become-engineer/django-diary-app-make-top-screen
→問題なく完了

・【第3回】Djangoで日記アプリを作ろう～投稿フォーム編～
https://rightcode.co.jp/blog/become-engineer/django-diary-app-make-post-form
→【Viewの実装】
　<before>
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957298/0d1c6697-ea17-32ea-4653-f98960e91b29.png)
　<after>
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957298/2b3685a8-6938-9371-a0d9-77164f29a686.png)

 【マイグレーションの実施】
→エラーが多発
index.htmlにおいて　
日記ページに遷移できるように追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957298/f76eeaac-cfda-eda0-be5f-e591e48d2fbc.png)

わかったこと
vies.pyで遷移先と見え方決定→html作成→urls.pyにURL追加

・【第4回】Djangoで日記アプリを作ろう ～一覧画面・詳細画面編～
https://rightcode.co.jp/blog/become-engineer/django-diary-app-make-list-detail-screen
→viewsに追加するimport
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957298/e1c87394-015e-bee8-d360-13a16480f088.png)


・【第5回】Djangoで日記アプリを作ろう ～編集画面・削除画面編～
https://rightcode.co.jp/blog/become-engineer/django-diary-app-make-edit-delete-screen
→【Updateview】
 　timezoneが波線→importがわからず。。。
　from datetime import datetaime
      timezone→datetimeに変更
$ rails generate devise:install 実行後の４つのセットアップ

＜開発環境＞
・cloud9
・Rails：5.2.8.1 
・Ruby : 2.6.3 

＜きっかけ＞
自主制作アプリにログイン機能を追加しようと
gemに'devise'を追記した後、４つのセットアップをした時のやり方。


まずはgemfileに以下を追記。
```
gem 'devise'
```
そしてターミナルで下記を実行する。
```
　$ rails generate devise:install 
```

正常に実行されれば４つのセットアップの文が表示される。

ですが今回はエラーはないものの、正常にインストールしていなかったので
普段やるはずの以下の４つのセットアップ項目を追記していく。

１つ目
　アプリ名/config/environments/development.rb　に下記を追記。
```
　　config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
```
２つ目
　アプリ名/config/routes.rb　に追記。
```
　 　　root to: 'home#index’　
```
３つ目
　ログインのフラッシュメッセージデザインの追加。　
　アプリ名/app/views/layouts/application.html.erb　に下記を追記。
```
　　<% if flash[:notice] %>　以下略
```

４つ目　
ターミナルで実行。ログインや新規登録画面のカスタマイズを可能にする。
```
　　$ rails g devise:views
```

上記４つ完了後に、gemファイルのインストール。
```
　gem　install devise　　
```
そしてgemファイルを編集したので、bundleをインストール。
```
bundle install
```

これでOK。
softwareupdateとxcode-selectの使い方

## Command Line Toolsのインストール
```
/usr/sbin/softwareupdate -i "Command Line Tools for Xcode-14.1"
```

## xcode-selectで切り替え
```
$ xcode-select -p
/Applications/Xcode.app/Contents/Developer

$ sudo xcode-select -s /Library/Developer/CommandLineTools

$ xcode-select -p
/Library/Developer/CommandLineTools
```
セルスタイルについて

今までよくTableViewなどを使ってきたけど、CellStyleについてよくわかっていなかったのでメモを残す。

# セルには標準でスタイルが存在する。
```Swift
final class ExampleCell: UITableViewCell {
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: .`ここ！`, reuseIdentifier: reuseIdentifier)
    }
    required init?(coder: NSCoder) {
        fatalError()
    }
}
```
- このような形でセルのスタイルを選択可能！
![スクリーンショット 2022-11-09 9.53.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784929/50b946a5-3b42-5385-2b7c-a36bbd52474f.png)
ファイル名の大文字小文字変更をgitに反映する

# 解決方法

`git mv` でファイル名を変更してpushする

#### 解説

フォルダ上のファイル名の変更や`mv`コマンドだけでは  
以下のような問題が起きる可能性がある
  
- 他の人がpullした時に別のファイルとして認識される  
- 他の人がpullした時にローカルに変化が起きない

`git mv` でファイル名を変更することでこれを回避でき 
gitに新規の名前を認識させることができる

通常の`mv oldName newName`の後に  
`git add newName` `git rm oldName` するのと同じ

```
// -f で同ファイル名の場合強制上書きを行う
$ git mv -f name.txt Name.txt
```

#### 余談

ignorecase = false をローカルのgitconfigに設定にすることで  
大文字小文字を認識するようになるがpushの情報としてはリネームが記録されず  
他の環境でpullした時矛盾が発生するためおすすめしない

```
git config core.ignorecase false
```

ignore case 大文字小文字を区別しない

なぜtrueがデフォルトなんだろう  
知ってる人がいたら教えてください
Cockpitを使ってみる

# はじめに
CockpitはWebコンソールでLinuxサーバーを管理および監視することができるツールです。

Web コンソールでは、以下を含むさまざまな管理タスクの実行が可能です。
- サービスの管理
- ユーザーアカウントの管理
- システムサービスの管理および監視
- ネットワークインターフェイスおよびファイアウォールの設定
- システムログの確認
- 仮想マシンの管理
- 診断レポートの作成
- カーネルダンプ設定の設定
- SELinux の設定
- ソフトウェアの更新


今回はCockpitをインストールして、使ってみたいと思います。


# 目次
[1.前提条件](#1-前提条件)
[2.Cockpitのインストール](#2-cockpitのインストール)
[3.Cockpitを使ってみる](#3-cockpitを使ってみる)

# 1. 前提条件
対象OS：Red Hat Enterprise Linux 8.5


# 2. Cockpitのインストール
インストール方法の詳細は[公式マニュアル](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html-single/managing_systems_using_the_rhel_8_web_console/index#getting-started-with-the-rhel-8-web-console_system-management-using-the-RHEL-8-web-console)に記載されています。

Cockpitをインストールします。
 ```
 # sudo yum install -y cockpit
 ```

起動時にCockpitが起動するように設定します。
 ```
 # sudo systemctl enable --now cockpit.socket
 ```

Cockpit向けにファイルウォールを設定します。
 ```
 # sudo firewall-cmd --add-service=cockpit --permanent
 # sudo firewall-cmd --reload
 ```

インストール・設定は以上で完了です。

# 3. Cockpitを使ってみる

ブラウザで以下のいずれかにアクセスすると、ログイン画面が開きますので、ログインします。
今回はrootユーザでログインしてみようと思います。
 ```
http://server-ip:9090
http://localhost:9090
 ```
![スクリーンショット 2022-11-08 16.33.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/6d061b08-dd12-8870-c39e-e4457c09d118.png)



ログインをすると以下のような画面が開きます。
左側のサイドメニューから様々な情報にアクセスし、管理作業を行うことができます。
![スクリーンショット 2022-11-08 16.35.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/a7cd19f3-c5db-8e46-1e1f-e3be97832cc9.png)

上の画像の「使用率」の「詳細と履歴の表示」を選択すると、CPUやメモリ等の情報を視覚的に確認できます。
![スクリーンショット 2022-11-08 16.40.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/e4a65c8d-7ec4-aa2f-ebb9-4e6c19e11fe0.png)

「ログ」のメニューではログレベルでフィルタリングをして、エラーを確認できるため、大変便利です。
![スクリーンショット 2022-11-08 16.42.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/c05d0824-49b8-d0b0-55c5-4f899e8553b7.png)

「サービス」ではエラーが発生しているサービスを確認できます。
トラブル時はこのようにアイコンが付き、どのサービスでエラーが発生しているのか、すぐに把握できるため、早急なトラブルの発見が可能です。
![スクリーンショット 2022-11-08 17.01.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/824cf1be-dcef-d6fb-7781-d58ea52a2a31.png)


「サブスクリプション」の項目ではRHELのサブスクリプション情報を確認できます。
![スクリーンショット 2022-11-08 16.44.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/88b03307-a84a-be90-f032-86be878fec1e.png)

「ソフトウェア更新」の項目では、重大度を確認し、クリック操作でアップデート作業を行うことができます。
![スクリーンショット 2022-11-08 16.46.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668052/e83b3c75-59d4-7674-da3b-e66aafa69b0a.png)

このようにCockpitを使用することでWebコンソール上で様々な管理作業が実行できます。
まだあまりRHELに慣れていないという方にもおすすめです。

以上です。
Githubコマンドのメモ

# git pullとは
`git pull origin hoge`のpullとは`fetch`して`merge`の略称
`git fetch origin`して`git merge origin hoge`をするのと同じ。

# mergeコミットが存在すると？
- mergeコミットのdiffを見るだけでそのブランチで行われた差分を把握できる。

# 逆にmergeコミットが存在しないと？
- 差分を把握するのが難しくなる。
- また、mergeの取り消しを行う場合に面倒である。

# そこで--no-ffでmergeを行おう！
- `fast-forward`であるmergeでない場合、mergeコミットが発行される。

# GitConfigとは？
Gitの設定はgitconfigにてできあがる。また、`Alias`に色々と自分なりのカスタマイズを作成することができる。
実際に、gitの初期設定を行う際に、`git config —global`などでメールアドレスなどをコマンドに打つと思うが、それも`git config`に設定しているものである。

# git resetとは
- `git reset`とは「Gitでコミットした内容を取り消す」ためのコマンド。

- `git reset --soft` (デフォルトでsoftになっている)とは単純にコミットのみを取り消すことができる。
    - `git reset --soft HEAD^`とすることで直前のコミットを取り消せる。
- `git reset --hard`とは、コミットの内容及び、ステージングエリアへの移動も取り消すことができる。
- `git reset —hard origin/hoge-master`とすることで、リモートのorigin/masterと手元のbranchをマージできる。

# 謝ってresetをしてしまった場合は、
- `git reset --hard ORIG_HEAD`でも元に戻すことができる。

# Interactive rebase
- `git rebase -i origin/hoge-master`とすることでコミットを無くしたり、色々とうまく調整できる。
f, fixup [-C | -c] <commit> = like "squash" but keep only the previous commit's log message, unless -C is used, in which case keep only this commit's message; -c is same as -C but opens the editorなどをよく使う！！
Azure Fundamentals(AZ-900)：Azure の基礎: Azureの管理とガバナンスについて説明する「Azure Resource ManagerとAzure ARMテンプレート」

Microsoft Learnを用いたMicrosoft Azure Fundamentals(AZ-900)の試験内容をまとめる投稿です。
この投稿ではMicrosoft Learnで学ぶ内容をできるだけ簡潔にまとめております。
Azureの勉強を一から始める方の参考になれば幸いです。

## 今回の学習内容
**◆「Azure Resource ManagerとAzure ARMテンプレート」**
◇対応するMicrosoft Learn ラーニングパス
[Azure の基礎: Azureの管理とガバナンスについて説明する](https://learn.microsoft.com/ja-jp/training/paths/describe-azure-management-governance/)
◇対応するモジュール
[Azure Resource Manager と Azure ARM テンプレートについて説明する](https://learn.microsoft.com/ja-jp/training/modules/describe-features-tools-manage-deploy-azure-resources/4-describe-azure-resource-manager-azure-arm-templates)

※前回の投稿は下記から確認できます。
[Azure Fundamentals(AZ-900)：Azure の基礎: Azureの管理とガバナンスについて説明する「Azure Arc」](https://qiita.com/fsd-jume/items/d66dc8213fad4b448de1)

## Azure Resource ManagerとAzure ARMテンプレート
### Azure Resource Manager(ARM)
**Azureリソースのデプロイ/管理サービス**
⇒Azureリソースで何かを行う場合は、必ずARMが関与

**◆ARMの動作**
・すべての要求は同じAPIを介して処理される
⇒すべての異なるツールで一貫した結果と機能を提供
・ARMによるAzure要求の処理
　①ユーザがAzureツール、API、SDKから要求を送信
　②ARMが要求を受信し、その要求の認証と承認を実施
　③ARMから要求されたアクションを行うAzureサービスに要求を送信
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851723/06754fe3-2522-8bf5-94aa-10b30e35dd6b.png)

**◆ARMの利点**
・スクリプトではなく宣言型のテンプレートを使用してインフラを管理
⇒プログラミングコマンドを記載する必要はなく、テンプレートで必要事項を指定する
・すべてのリソースをグループとしてデプロイ/管理/監視
・リソースは繰り返しデプロイしても必ず一貫した状態を保つ
・リソースの依存関係を考慮してデプロイし、正しい順序で作成
・Azure RBACですべてのサービスにアクセス制御を適用可能
・タグでリソースの論理的な整理やコスト管理が可能

### ARMテンプレート
**コードを使用してインフラを管理できるテンプレートファイル**
⇒コードとしてのインフラストラクチャ(IaC：Infrastructure as Code)の一例

・使用するリソースを宣言型のJSON形式で記述
⇒コードにはデプロイする必要があるインフラを定義
・コード実行前にデプロイコードが検証されるため、コード実行中のデプロイ失敗の可能性は低い
・可能な箇所で並列してリソースが作成されるため通常より短時間でデプロイ可能
・テンプレートでPowerShellやBasのスクリプトも実行可能

**◆ARMテンプレートの利点**
**◇宣言型の構文**
・Azureインフラ全体を宣言方式で作成可能
⇒ネットワークインフラやストレージなどのリソースもプログラミングコマンドなしでデプロイ可能

**◇反復可能結果**
・リソースは繰り返しデプロイしても必ず一貫した状態を保つ
⇒同じテンプレートで何度も同じリソースを同じ状態でデプロイ可能
⇒同一環境のDev/Test環境の作成が容易

**◇オーケストレーション**
・リソースの依存関係を考慮してデプロイし、正しい順序で作成
・可能な箇所で並列してリソースが作成されるため通常より短時間でデプロイ可能
・テンプレートは複数の命令コマンドではなく、1つのコマンドを使用してデプロイ

**◇モジュール式のファイル**
・テンプレートは内容を細分化してデプロイ時にリンク可能
・あるテンプレートを別のテンプレート内の入れ子も可能
例)環境全体をデプロイするテンプレート内にVMをデプロイするテンプレートを入れ子にする
⇒環境を作成するたびに、VMも併せてデプロイされる

**◇拡張性**
・デプロイスクリプトを使用すると、テンプレートでPowerShellやBashスクリプトを実行可能
⇒デプロイ時にリソースを設定することができる
・スクリプトはテンプレートに直接記載することも、外部スクリプトを参照させることも可能

## 次の学習内容
**◆Azure Advisor**

https://qiita.com/fsd-jume/items/f2aaa99ac29eaaadbba5

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/e4ec76959adb547ac5e8
Observable.mergeとCombineLatestの違い【メモ】

RxSwiftを使っていて、Observable.mergeとCombineLatestにおいて混乱したので、その違いをここにメモする。

# Observable.mergeとは？
- 具体例を持って説明する。

``` Swift
import RxRelay
class ExampleViewModel {
    // input
    let didTappedButton = PublishRelay<Void>()
    let didInputtedTextField = PublishRelay<String>()

    init() {
        let fetchSomethingResult = Observable.merge(didTappedButton, didInputtedTextField)
            .flatMap {
                repository.fetchSomething()
            }
            .share()
        }
```
- このような形でViewModelがあった場合に、`Observable.merge`を利用すると、`didTappedButton`もしくは、`didInputtedTextField`に値が流れてくるたびに、`repository.fetchSomething()`が行われる。
- つまり、`Observable.merge`内で指定されている値をどちらも監視してくださいと言う意味である。

# CombineLatestとは？
具体例をもって説明する。
``` Swift
import RxRelay
class ExampleViewModel {
    // input
    let didTappedButton = PublishRelay<Void>()
    let didInputtedTextField = PublishRelay<String>()

    init() {
        let fetchSomethingResult = Observable
            .combineLatest(didTappedButton, didInputtedTextField)
            .flatMap {
                repository.fetchSomething()
            }
            .share()
        }
```
- このような形のVMがあった場合に、`combineLatest`を使うと`didTappedButton`と`didInputtedTextField`の両方に値が流れてきた時にか`repository.fetchSomething()`が実行されない。
- `Observable.merge`との違いとしては、`didTappedButton`のみがタップされても、`repository.fetchSomething()`が実行されないことである。
- つまり、`combineLatest`を使う場合は、監視される値は両方の値が流れないと意味をなさないものである。
【Rails初学者用】bundle install でフリーズした時の解決方法

開発環境
 ・cloud9
・Rails：5.2.8.1 
・ Ruby : 2.6.3 

きっかけ
自主制作アプリにログイン機能を追加しようと
gemに追記した後、bundle install でフリーズした時の解決メモ。


↓Gemファイルの変化点は以下４つを記述した時。

```
gem 'devise'

gem "refile", require: "refile/rails", github: 'manfe/refile'

gem "refile-mini_magick"

gem "bulma-rails"
```

　
上記記述後に、gemファイルのインストール。
```
bundle install
```
すると処理途中でフリーズするように。

bundlerがインストールされていない？確認！
```
　　$ bundler -v
```
　bundlerが見つかりませんでしたとエラー…あれ？

　エラー文に最新バージョンに更新するには、「bundle update --bundler」するか、
　不足しているバージョンをインストールするには、「gem install bundler:1.17.3」と表記。
とりあえずやってみる。

```
　$ bundle　update --bundler 
```
 →途中でフリーズ…次。
```
　$ gem install bundler:1.17.3　
```
→正常にインストールできた。
```
　$ bundle -v　　
```
→　Bundler version 1.17.3　と表示されたのでOK。

・再度立ち上げて
```
 $ bundlr install
```
実行してみたが、またフリーズ。

エラー文には
　→「依存関係 tzinfo-data (>= 0) は、Bundler がインストールするプラットフォームでは使用されません。 Bundler は ruby 用にインストールされていますが、依存関係は x86-mingw32、x86-mswin32、x64-mingw32、java のみです。 これらのプラットフォームをバンドルに追加するには、「bundle lock —add-platform x86-mingw32 x86-mswin32 x64-mingw32 java」を実行します。」

とのこと。

・指示に沿って実行してみる。
```
　 $　bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java
```
　エラーは発生しなかったが、
「ロックファイルを /home/ec2-user/environment/アプリ名/Gemfile.lock に
書き込みます。」と表示。
その後、　bundle installしてみたけど解決せずまたフリーズ。むむむ。

次の手でgemをアップデートしてみる。
```
　$ gem update —system　
```
→　最新Verと表示。フリーズはまだ解決せず。


・その後、いろいろ調べて超優良記事でやっと解決した。

参考記事：Ruby on Railsでbundle installでエラーが出た時のシンプルな解決方法　
　URL：　https://code-schools.com/ror-bundleerror/　



うっかり忘れていた。
追加したgemの項目を１つずつインストール。
```
　gem　install devise　　
　gem install refile　
　gem install refile-mini_magick
　gem install bulma-rails
```
　からの…
```
$ bundle install 
```
なんとか成功した。
OK！！
乱数を生成する(SPSS Modeler データ加工逆引き3-20)

## 乱数を生成する

![スクリーンショット 2022-11-07 13.16.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/78c0d9e2-e9d5-f8d4-aa5c-e6182993cb57.png)

## 1.想定される利用目的

・ 効果検証用のデータセット作成
・ シミュレーションによるリスク評価

## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/blob/main/random.str?raw=true

## 3.サンプルストリームの説明

![スクリーンショット 2022-11-07 13.13.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/c68cd812-57a1-6503-d71e-a11612d08ca7.png)

a.入力するデータは以下の通りです。
![スクリーンショット 2022-11-07 13.18.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/217ac7c6-29bf-df85-5feb-c93b1d8516ff.png)

b.[フィールド作成]ノードを編集します。
![スクリーンショット 2022-11-07 13.18.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/2e915900-2fe9-a128-99b2-c15013f22571.png)

式ビルダーを利用すると便利に入力できます。[無作為]をリストから選び[random()]を選択します。
括弧の中を6にすると1から6までの整数が無作為に割り当てられます。
![スクリーンショット 2022-11-07 13.19.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/f60272d2-5d28-dc19-0d0d-b8b24ba0b243.png)

[プレビュー]します。
![スクリーンショット 2022-11-07 13.19.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/2ddce49f-8ec5-410c-77db-4854b470d868.png)

c.[棒グラフ]ノードを実行します。レコード数を均等に分けるとランダム性が保てないため、レコード数がばらつきます。
![スクリーンショット 2022-11-07 13.33.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/d8ff0409-3370-b9c1-2a60-67b0d2dd9f3b.png)

d.[フィールド作成]ノードを編集します。実数の乱数を発生させます。平均を1に設定しました。
![スクリーンショット 2022-11-07 13.20.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/4537b02d-96a4-d600-b824-156833d6e382.png)

[プレビュー]します。
![スクリーンショット 2022-11-07 13.20.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/29bccad2-29a9-b991-e968-be22fef7d31d.png)

e.[ヒストグラム]ノードを実行します。平均と分散が1の正規分布になりました。
![スクリーンショット 2022-11-07 13.21.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/307f6b7d-ae7f-1ee4-6b1d-e251282f4e33.png)

f.[フィールド作成]ノードを編集します。リスト[A B C]という３通りの文字列の乱数です。
![スクリーンショット 2022-11-07 13.21.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/d614a934-5c99-c057-3431-be7dc6866c3c.png)

[プレビュー]します。
![スクリーンショット 2022-11-07 13.22.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/2f81bdd0-42ed-3370-78af-d2debffc238e.png)

g.[棒グラフ]ノードを実行します。
![スクリーンショット 2022-11-07 13.22.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/6c7c89cd-d15b-efd8-c623-ab5940123cd7.png)

#### 注意点

乱数はストリームが実行されるたびに変更されるため、再現性を維持して比較をする場合にはキャッシュを利用します。

https://qiita.com/416nishimaki/items/1755c4107105e8bdfe90

## 4.参考情報

#### SPSS Modelerで乱数が扱われている記事

https://qiita.com/416nishimaki/items/98648cf8bf3fdbb0c3aa

https://qiita.com/416nishimaki/items/fefb95dfeda9cb5b30cb

https://www.ibm.com/blogs/solutions/jp-ja/spssmodeler-push-node-21/

https://qiita.com/416nishimaki/items/f627ed943e6457eb85d2

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/private/4bf813e6cba84b2a1008
Firestore の TTL がリリースされたので挙動を調べてみた

## 概要
先日の [Firebase Summit 2022](https://firebase.google.com/summit?hl=ja) で [Firestore の TTL (Time-To-Live) 機能](https://firebase.google.com/docs/firestore/ttl)がリリースされました。開発する上で、以下の挙動が気になったのでテストデータを作って確認してみました。

1. Cloud Functions の onDelete トリガーや onWrite トリガーは発火される？
2. 途中で有効期限を変更した時の挙動は？
3. どれくらいのスピードで削除される？

調査中に公式ドキュメントも随時アップデートされ、検証する必要のない内容も含まれてしまいましたが、以下に検証方法・結果を記載します。

## 検証方法
以下の手順で検証を行いました。

1. items コレクション内の expireAt フィールドを TTL として設定
1. Firestore に 500 件のテストデータを一括作成し、全て 24 時間後に有効期限を設定
1. Cloud Functions のスケジュール機能を用いて、 1 から順に 15 分間隔で expireAt を null　に更新

## 結果
結果は以下のようになりました。

### 1. Cloud Functions の onDelete トリガーや onWrite トリガーは発火される？
onDelete も onWrite も TTL によるデータ削除時に発火しました。onDelete の発火回数はデータの削除数と一致しました。onWrite トリガーの実行回数が削除数より多いのは検証手順 3 で expireAt を更新する際にも発火するためです。

#### onDelete トリガー
![Firestore TTL による onDelete トリガー実行ログ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19698/4f91b4e3-2a12-613c-8bcd-cf41ec9707aa.png)
#### onWrite トリガー
![Firestore TTL による onWrite トリガー実行ログ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19698/fc23a9f3-e50f-0788-e962-07e66f1ac297.png)

この結果から、 onDelete, onWrite トリガーが発火する前提で設計できます。具体的な利用シーンとしては Firestore のデータに紐づく Storage のファイル削除を onDelete トリガーで処理する、などが考えられます。

[Manage data retention with TTL policies](https://firebase.google.com/docs/firestore/ttl)
> Deletion through TTL calls all active snapshot listeners and triggers Cloud Functions Firestore triggers.

検証期間中に公式ドキュメントにも上記の記述が追加され、検証結果とも合致しました。

### 2. 途中で有効期限を変更した時の挙動は？
有効期限前に expireAt を null に更新したデータは 1 件も削除されませんでした。TTL の削除処理は事前に削除対象が予約されているのではなく、実行時に逐一クエリして該当データのみ削除しているようです。

[Manage data retention with TTL policies](https://firebase.google.com/docs/firestore/ttl)
> Deletion through TTL is not an instantaneous process. Expired documents continue to appear in queries and lookup requests until the TTL process actually deletes them. TTL trades deletion timeliness for the benefit of reduced total cost of ownership for deletions. Data is typically deleted within 72 hours after its expiration date.

公式ドキュメントに記載がある通り有効期限を過ぎても即時にデータは削除されないため、有効期限を過ぎても削除前であれば expireAt を null に更新することで削除対象から除外することが可能です。

この結果から、論理削除したデータの削除期限を N 日後に設定し、復元する時に期限をなくす処理を行うことで、 Google Drive のゴミ箱のような機能（ゴミ箱に入れてから N 日後に自動的に削除）を実現できそうです。

### 3. どれくらいのスピードで削除される？
以下の画像は 1 時間毎の削除件数を表したものです。1 時間あたり 10 件前後のデータが削除されています。有効期限を迎えた時点（24時間経過時）では 500 件中 400 件ほどが削除対象（expireAt を null に更新していないデータ）であったため、 2 日程度で全て削除するように処理を分散しているようです。
![スクリーンショット 2022-11-09 8.49.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19698/2b266698-f12c-a5bf-d466-f55168ac28de.png)

> Deletion through TTL is not an instantaneous process.

公式のドキュメントでも言及されている通り、即時削除されるものではないという前提で設計する必要があります。

## まとめ
今回の検証で以下のことが分かりました。

* TTL による削除時にも onDelete, onWrite トリガーが発火される。
* 有効期限を途中で変更すれば削除対象から除外できる。
* 同時に有効期限を迎えたデータは一括で削除されず、分散して削除される。

実際に利用したソースコードは　[tanabee/research-firestore-ttl](https://github.com/tanabee/research-firestore-ttl/blob/main/functions/index.js) にアップロードしていますので、何か検証したい方はご参考ください。
chrubyの使い方

## chrubyのインストール

```
ghq get postmodern/chruby
```

その後

```bash
source "${HOME}/src/github.com/postmodern/chruby/share/chruby/chruby.sh"
source "${HOME}/src/github.com/postmodern/chruby/share/chruby/auto.sh"
```

を ~/.zshrc.local とかに追加 (2つ目は.ruby-version用)

## ruby-installのインストール

```
ghq get postmodern/ruby-install
```

その後

```bash
export PATH="${PATH}:${HOME}/src/github.com/postmodern/ruby-install/bin"
```

を ~/.zshrc.local とかに追加

## Rubyのインストール
```
ruby-install 3.1.2
```

## Rubyの一覧
```
chruby
```

* インストール後、シェルを初期化し直さないとリストは更新されない。
* `chruby system` でsystem rubyを使えるが、この一覧には出ない。

## シェル上でRuby有効化 (rbenv shell)
```
chruby 3.1.2
```

## グローバルにRuby有効化 (rbenv global)
以下のやり方は auto.sh が必要。

```
echo 3.1.2 > ~/.ruby-version
```

これはHOME外にいると動作しないので、~/.zshrc.local で chrubyを叩いてしまう方がよさそう。

```
chruby 3.1.2
```

## 困り所メモ
* インストール後、シェルを初期化し直さないとリストは更新されないのは直らないのか?
* configureをいじりたい時はどうするのか?
Apple Watchのスタンドアローンアプリでアプリバージョンが正常に反映されずAppStoreConnectにアップロードできない問題の対応メモ

## 現象

1. XCode > TARGETS > watchアプリ > General から `Version` と `Build` を書き換える
1. アーカイブしてAppStoreConnectにアップロードしようとする
1. バージョンがおかしい旨のエラーが出てアップロードに失敗する

## 原因

- watchスタンドアローンアプリでも、通常の「iOSアプリ + extension」などと同じようにアプリ本体とwatchアプリのバージョンが揃っている必要があるっぽい
- どうやらwatchスタンドアローンアプリなのにアプリ本体が存在しているっぽい
  - 昔はiOSアプリに内包するカタチでしかwatchアプリはリリースできなかったのでその名残？


## 対応内容

アプリ本体についてはwatchアプリのようにVersion, Buildを書き換えるためのUIが用意されていないがBuild Settingsから編集できる


- XCode > TARGETS > watchアプリ本体ではなくホストアプリ？を選択 > Build Settings
  - `MARKETING_VERSION` を手動で書き換える
  - `CURRENT_PROJECT_VERSION` を手動で書き換える


## その他

info.plistがなくなりproject.pbxprojに内包されるようになっていてびっくりした
Docker　マルチステージビルドについて

DockerでPython環境作成する際に以下のようなFROMが複数出てくるDockerfileがあった。

FROMが複数ってどういうこと？ってことで調べますと、
dockerのイメージ作成を段階的に実施できるとのこと。
何がうれしいかというとビルド環境をそのままデプロイするといらないものが入ってたりする（コンパイラとか）ので、実際にデプロイする環境は実行モジュールだけにしたいという思惑の模様。


```Dockerfile
# Define global args
ARG FUNCTION_DIR="/home/app/"
ARG RUNTIME_VERSION="3.9"
ARG DISTRO_VERSION="3.12"

# Stage 1 - bundle base image + runtime
# Grab a fresh copy of the image and install GCC
FROM python:${RUNTIME_VERSION}-alpine${DISTRO_VERSION} AS python-alpine
# Install GCC (Alpine uses musl but we compile and link dependencies with GCC)
RUN apk add --no-cache \
    libstdc++

# Stage 2 - build function and dependencies
FROM python-alpine AS build-image
# Install aws-lambda-cpp build dependencies
RUN apk add --no-cache \
    build-base \
    libtool \
    autoconf \
    automake \
    libexecinfo-dev \
    make \
    cmake \
    libcurl
# Include global args in this stage of the build
ARG FUNCTION_DIR
ARG RUNTIME_VERSION
# Create function directory
RUN mkdir -p ${FUNCTION_DIR}
# Copy handler function
COPY app/* ${FUNCTION_DIR}
# Optional – Install the function's dependencies
# RUN python${RUNTIME_VERSION} -m pip install -r requirements.txt --target ${FUNCTION_DIR}
# Install Lambda Runtime Interface Client for Python
RUN python${RUNTIME_VERSION} -m pip install awslambdaric --target ${FUNCTION_DIR}

# Stage 3 - final runtime image
# Grab a fresh copy of the Python image
FROM python-alpine
# Include global arg in this stage of the build
ARG FUNCTION_DIR
# Set working directory to function root directory
WORKDIR ${FUNCTION_DIR}
# Copy in the built dependencies
COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR}
# (Optional) Add Lambda Runtime Interface Emulator and use a script in the ENTRYPOINT for simpler local runs
ADD https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie /usr/bin/aws-lambda-rie
COPY entry.sh /
RUN chmod 755 /usr/bin/aws-lambda-rie /entry.sh
ENTRYPOINT [ "/entry.sh" ]
CMD [ "app.handler" ]
```

●各ステージについて
ステージ 1では、ランタイム (この場合は Python 3.9)と、ステージ 2 で依存関係をコンパイルおよびリンクするために使用するGCCを使用してベース イメージをビルドします。
ステージ 2では、Lambda ランタイム インターフェイス クライアントをインストールし、関数と依存関係を構築します。
ステージ 3は、ステージ 2 からの出力をステージ 1 で構築されたベース イメージに追加する最終イメージを作成しています。ここでは、Lambda ランタイム インターフェイス エミュレーターも追加していますが、これはオプションです。

※Lambdaランタイムインターフェースエミュレーターを追加しない場合は以下を参照
https://aws.amazon.com/jp/blogs/aws/new-for-aws-lambda-container-image-support/