OmniAICreator/Qiita-1.07M huggingface dataset:
VS CodeとDocker DesktopでDjango+Nginx+Posgresql+Pgadminのコンテナを起動する方法

## 背景
- kubernetes上でWebアプリを動かす際に、ローカルでコンテナの開発環境が欲しかった

## 記事のゴール
- ローカルのマシン上で Django + Nginx + Postresql + Pgadmin のコンテナが起動できている
- コンテナ上でDjangoのpythonファイルを編集できる
- コンテナ上のPgadminを使ってPostgresqlのDBを操作できる
- ローカルのコンテナ上で、NginxをプロキシとしたDjango＋PostgresqlのWebアプリの動作確認ができる

## 前提
- 端末はMac M2チップ（Windowsやmacのintelチップでも動くはず）
- vs codeが端末にインストールされていること
- Docker Desktopが端末にインストールされていること

## 構築方法
### 拡張機能インストール
VS Codeで以下の拡張機能をインストールする
- Dev Containers
- Remote - SSH: Editing Configuration Files

### 資材の準備
- [github](https://github.com/yamamuratkr/vscode_docker/tree/main) に用意したので`git clone`して入手
- github の README にもコンテナ起動までの手順を記載している

### 環境起動
- Docker Desktopを起動する
- `git clone https://github.com/yamamuratkr/vscode_docker.git`でローカルに資材をダウンロード
- VS Codeを起動する
- VS Codeの「フォルダーを開く...」で`git clone`した`vscode_docker/docker/webapp`を開く
- 「コンテナで再度開く」をクリックするとコンテナが起動する

![image](https://github.com/user-attachments/assets/af3de7e8-5aa4-4527-95c8-91bcc09cb3c2)

![スクリーンショット 2024-10-04 14 06 12](https://github.com/user-attachments/assets/66a44400-2242-4670-8442-be34e78cab94)

- Docker Desktopを確認するとコンテナが起動している様子が確認できる

![image](https://github.com/user-attachments/assets/35bfdb60-6508-42c4-83ad-97094262539c)

## 接続確認
### Djangoへの接続
- ブラウザで以下のURLを入力してDjangoアプリに接続確認
  - URL: http://localhost:1317

![image](https://github.com/user-attachments/assets/183fbc34-0e9e-4075-be2d-cc365200e97d)

### Pgadminへの接続
- ブラウザで以下のURLを入力してPgadminに接続確認
  - URL: http://localhost:8888

![image](https://github.com/user-attachments/assets/87e66625-75ea-4fda-ba42-b3726bb7614b)

- メールアドレスとパスワードは`docker-compose.yaml`の`enviorment`に記載されている
- 適宜変更して再度コンテナを起動すると新しいメールアドレスとパスワードでログインできる

![image](https://github.com/user-attachments/assets/e8653eea-4d07-459a-805d-b8424e57e707)

## まとめ
- ローカル環境でDjango+Nginx+Posgresql+Pgadminのコンテナを起動する方法を紹介した
- 起動までは割と簡単に辿り着ける
- これを開発環境として、Djangoを育てたり、Nginxをカスタマイズすることが可能
- この資材をベースに本番（Docker Compose, Kubernetes）で稼働させるアプリケーションの開発が可能となる（開発したコンテナイメージの build & push 方法と Kubernetes 環境で動かす方法は別の記事で（記事完成したらリンク貼ります））
確率密度関数の変数変換  #対数正規分布 #統計検定

## 確率密度関数の変数変換の公式
今回は、変数変換が１対１の関数の場合のみを扱います。

連続型確率変数$X$の確率密度関数を$f(x)$とする。
このとき、新たな確率変数$Y=g(X)$の確率密度関数は、
``` math
\frac{f(g^{-1}(y))}{|g'(g^{-1}(y))|}
```
つまり、
``` math
\frac{f(x)}{|g'(x)|}
```
の$x$を$y$に変換したものになります。


より一般には、複数変数の場合、
確率変数$\textbf{X}$の確率密度関数$f(\textbf{x})$を、$\textbf{Y}=\textbf{T}(\textbf{X})$のよって変換するとき、$\textbf{Y}$の確率密度関数は、
``` math
\left| \frac{\partial \textbf{x}}{\partial \textbf{y}} \right| f(\textbf{T}^{-1}(\textbf{y}))
```
つまり、
``` math
\frac{f(\textbf{x})}{\left| \frac{\partial \textbf{y}}{\partial \textbf{x}} \right| }
```
の$\textbf{x}$を$\textbf{y}$に変換したものになります。

ここで、$\left| \frac{\partial \textbf{x}}{\partial \textbf{y}} \right| $は**ヤコビアン**です。

::: note
$X$の確率密度関数$f(x)$を**変換式の微分（ヤコビアン）で割る**と、$Y$の確率密度関数になるのです。
:::


簡単な例で考えてみましょう。
### 例１

確率変数$X$の確率密度関数が、$f(x)=\frac{1}{10} (0\leq x \leq 10)$で与えられているとします。このとき、確率変数$Y=2X+5$の確率密度関数$h(y)$は、
``` math
h(y) = \frac{f(x)}{|g'(x)|}=\frac{1/10}{2} =\frac{1}{20}  \qquad (5\leq y \leq 25)
```
となります。

::: note warn
この公式は、$Y=2X+5$が1対1の関数だから使えるのです。$Y=2X^2+5$の場合は、$Y=7$に対応する$X$は、$X=\pm 1$と２つ存在してしまいます。
:::

少し難しいですが、よく登場する対数正規分布についても計算してみましょう。
### 例２

確率変数$X$の確率密度関数が、$f(x)=\frac{1}{\sqrt{2\pi}\sigma} \exp (-\frac{(x-\mu)^2}{2})$で与えられているとします。このとき、確率変数$Y=e^{X}$の確率密度関数$h(y)$は、
``` math
h(y) = \frac{f(x)}{|g'(x)|} = \frac{\frac{1}{\sqrt{2\pi}\sigma} \exp (-\frac{(x-\mu)^2}{2})}{e^{x}} = \frac{1}{\sqrt{2\pi}\sigma y} \exp \left(-\frac{(\log y - \mu)^2}{2} \right)
```
となります。$x=\log y$, $g'(x)=e^x$を用いました。

正規分布に従う確率変数$X$を、$Y=e^X$によって変換した$Y$は、**対数正規分布**と呼ばれます。

証明は省略しますが、対数正規分布の期待値・分散は、
``` math
E[Y] = \exp \left(\mu+\frac{1}{2}\sigma^2 \right)
```
``` math
V[Y] = \exp (2\mu+\sigma^2) \lbrace \exp(\sigma^2)-1 \rbrace
```
となります。

### おまけ
対数正規分布は、金融分野で良く用いられています。それは、**幾何ブラウン運動**と呼ばれる株価の変動予測モデルに登場します。

ある時点$t$における株価が微小区間にどれほど変化するかが、
``` math
dX(t) = \mu dt + \sigma dz(t)
```
で与えられる**ブラウン運動**という数理モデル（確率過程）があります。

::: note
$\mu dt$の項は、（平均変化率$\mu$）×（時間$dt$）で期待変化量を示していて、$\sigma dz(t)$の項は、（分散$\sigma$）×（誤差項$z(t)$)で、期待変化量からの誤差を示しています。
:::
$z(t)$の意味などについては、以下の記事をご覧ください。

https://qiita.com/hiro_tan5/items/51543b5e94d0028364d9


$\mu$はドリフトと呼ばれ、平均的な株価の上昇率・下降率を表していて、$\sigma$はボラティリティと呼ばれ、ドリフトからのずれ・変動を表しています。

先ほどのブラウン運動の微分方程式を解くと、
``` math
X(t) = X(0) + \mu t +\sigma z(t)
```

このブラウン運動には、株価ではありえないマイナスの値を取ってしまう欠点があります。ここで、ブラウン運動の左辺を**変化量ではなく変化率に変更した**幾何ブラウン運動という確率過程がしばしば用いられます。

幾何ブラウン運動は、
``` math
\frac{dX(t)}{X(t)} = \mu dt + \sigma dz(t)
```
で記述されます。

今回登場した対数正規分布を用いると、この微分方程式を解くことができます。（ちなみに、導出には伊藤の公式という非常に難しい確率過程の公式を使います。）

``` math
X(t) = X(0) \exp \left( (\mu-\frac{1}{2}\sigma^2)t+\sigma z(t) \right)
```
この解の形から、幾何ブラウン運動は正の値しかとらないことがわかります。実際の株価も生の値しかとらないことから、応用しやすいモデルになっています。

まとめると以下のようになります。

### ブラウン運動
``` math
dX(t) = \mu dt + \sigma dz(t)
```

``` math
X(t) = X(0) + \mu t +\sigma z(t)
```
時刻$t=T$を固定した分布は、正規分布$N(X(0)+\mu T, \sigma^2 T)$に従う。
### 幾何ブラウン運動
``` math
\frac{dX(t)}{X(t)} = \mu dt + \sigma dz(t)
```

``` math
X(t) = X(0) \exp \left( (\mu-\frac{1}{2}\sigma^2)t+\sigma z(t) \right)
```
時刻$t=T$を固定した分布は、対数正規分布$N(\log X(0)+(\mu -\frac{1}{2}\sigma^2 ) T, \sigma^2 T)$に従う。
【忘備録】クリエイティブツール

### 経緯
Adobeからアンケート回答依頼が届き、ちょっと気が向いたので回答してみたら、競合他社クリエイティブツールの名前がたくさん出てきたので、きっと、そこそこのクォリティや利用者のいるものなのでは？と思って、メモっておいた。いつか使ってみよう！

### [Prezi.com](https://prezi.com/)
プレゼン作成ツール。
無料利用開始はできるようだが、[個人事業向けだと、月$19のようだ](https://prezi.com/pricing/?click_source=logged_element&page_location=header&element_text=pricing&pricing_tab=business)（2024年10月）。

### [PIXLR](https://pixlr.com/jp/)
AIイメージジェネレータとAIデザインツール。なんだか次世代感。
そもそも、読み方がわからない・・・調べたところ、"ピクセラエディター"らしい。
7日間の無料体験の後、アカウント作成の必要もなく使い続けられる機能もあるが、内容によっては有料らしい。
+Plus プランで、1.99ドル/月
Premium プランで、7.99/月
保存数無制限の Teamプランでは、5つのプレミアムシートがついて、12.99ドル/月

### [Figma](https://www.figma.com/ja-jp/)
わたし地震も使ったことがある。
無料でデザインが作れるツールだ。チーム連携もできるようで、いい感じ。
無料(0円)プロ（2,250円）ビジネス(6,750円)エンタープライズ(11,250円)と設定がある。

### [Final Cut Pro](https://www.apple.com/jp/final-cut-pro/)
Macユーザ向けの、動画編集ツール、かな？

### [Photoleap](https://www.photoleapapp.com/)
スマホで写真を編集するツールかな。

### [iMovie](https://www.apple.com/jp/imovie/)
言わずとしれた動画編集ツールだな。

### [inShot](https://inshot.com/)
これも、動画編集？なんだか、合成がすごそう。

### [Affinity](https://affinity.serif.com/ja-jp/)
なんだか、すごそうなツール、しかも『6ヶ月無料試用』だとな？（2024年10月現在）
お得！

### [PicCollage](https://piccollage.com/)
お名前からして、そうだろうな、と思ったけど、やっぱりとっても可愛らしい（私の辞書でいう”若い”）ツールの様子。写真や動画に『盛れる』ツール…のようだ。

### [Microsoft Designer](https://www.microsoft.com/ja-jp/microsoft-365/microsoft-designer)
AIを使って、思いつく限りのものを数秒で作成、デザイン、編集できます
…とかいてある。本当だったらすごい（あぁ、私って、古い人間…）

### [VS Code](https://code.visualstudio.com/)
これが、リストにあったとき、他は画像や動画編集機能を思い浮かべるものばかりだったので、ちょっと違和感があった。
（今どきは、VSコードも、キラキラとか、画像、動画を扱うのかも！）
とこっそり思いながらサイトを訪ねてみたけれど、私の知っているコードを書くツールのままだった。
私も時々しか使わないけれど、Githubとの連携もよく、大好きです。

### [DaVINCI RESOlVE 19](https://www.blackmagicdesign.com/products/davinciresolve)
これも動画編集ツールかな。SNSにあげるため、という感じでライトなものかと思ったけど、サイトにはプロが使っているという写真が多く、迫力を感じた。

DAVINCI RESOLVEは無料ダウンロード
DAVINCI RESOLVE19は 295ドルでした　（2024年10月）

### [Picsart](https://picsart.com/)
画像生成・編集ツールのようだけど、簡単で使いやすいように見える。
スタートは無料、Plus会員は 541円/月、Proプランは 800円/月（2024年10月）

### [CapCut](https://www.capcut.com/ja-jp/)
動画編集ツールのよう。
『誰でもどこでも何でも作成できる無料のオールインワン動画エディタ』…だそうな。
本当だったら、すごい、リストの中では、これが一番に使ってみたいかな。

### [Procreate](https://procreate.com/jp)
動画やイラスト、写真の編集に使うソフト？っぽい。
ファーストビューには大きなタブレットで使う例がたくさん出ているから、きっと、そういうクリエイター向けのツールかな。
利用用途？によって価格プランが分かれているのかな。
買い切り価格 3,000円って、なかなかお手頃なのでは？

以上です〜

順次、利用したら情報追記します。
よく使うBigQueryのSQLクエリ集

個人用ですが、BigQueryでデータを触る時に、
よく使うものをピックアップしました。
コピペすることで効率化したいと思います。

## 1. データ抽出・集計

### 重複除外
特定のカラムで重複を除外したデータを取得します。
```sql
SELECT DISTINCT column FROM dataset.table;
```

### 集計
特定のカラムをグループ化してデータを集計（カウント）します。
```sql
SELECT column, COUNT(*) FROM dataset.table GROUP BY column;
```
- COUNT以外の集約関数
    - SUM(column): 数値の総和
    - AVG(column): 数値の平均値
    - MIN(column): 最小値
    - MAX(column): 最大値
    - COUNT(DISTINCT column): 重複を除外した値の数

## 2. データの追加・挿入

### 新しいレコードの追加（重複除外）
既存のデータと重複しない新しいレコードを追加します。
```sql
INSERT INTO dataset.target_table
SELECT *
FROM dataset.source_table AS src
WHERE NOT EXISTS (
  SELECT 1
  FROM dataset.target_table AS dest
  WHERE dest.column = src.column
);
```

## 3. データの結合

### 全カラムを結合
データセット内の複数のテーブルを全カラムで結合し、新しいテーブルを作成します。
```sql
CREATE OR REPLACE TABLE dataset.target_table AS
SELECT * FROM (
  SELECT * FROM dataset.table1
  UNION ALL
  SELECT * FROM dataset.table2
  UNION ALL
  SELECT * FROM dataset.table3  -- 必要に応じて追加
);
```
**注意:** この方法は、結合する全てのテーブルが同じカラム構造を持っている場合に有効です。

### 指定カラムを結合
特定のカラムのみを結合する場合のクエリです。
```sql
CREATE OR REPLACE TABLE dataset.target_table AS
SELECT column1, column2
FROM (
  SELECT column1, column2 FROM dataset.table1
  UNION ALL
  SELECT column1, column2 FROM dataset.table2
  UNION ALL
  SELECT column1, column2 FROM dataset.table3  -- 必要に応じて追加
);
```
**注意点:** この方法では、結合に含めるカラムを特定する必要があるため、カラム名が異なるテーブルを結合することが可能です。

## 4. データの削除

:::note alert
これらの操作により、テーブル内のデータが削除されます。
一度削除すると基本的に元に戻せないため、十分注意して操作を行ってください。
:::

### レコードの全件削除

テーブル内のすべてのデータを削除します。
```sql
DELETE FROM dataset.table WHERE TRUE;
```

### レコードの条件付き削除
特定の条件を満たすデータを削除します。
```sql
DELETE FROM dataset.table
WHERE column = 'value';
```

### テーブル自体の削除
レコードだけでなく、テーブル自体も削除します。
```sql
DROP TABLE dataset.table;
```


## 5. 特定の条件に基づく新しいカラムの追加
データの日時情報を元に、新しいカラムとして曜日を追加するクエリの例です。
曜日は日本語で表現され、BIなどで昇順・降順ができるよう、
数字の接頭詞が付加されています。

```sql
CREATE OR REPLACE TABLE dataset.new_table AS
SELECT
  id,
  CAST(date_time AS DATE) AS record_date,
  column1,
  column2,
  CASE
    WHEN EXTRACT(DAYOFWEEK FROM date_time) = 1 THEN '0.日曜'
    WHEN EXTRACT(DAYOFWEEK FROM date_time) = 2 THEN '1.月曜'
    WHEN EXTRACT(DAYOFWEEK FROM date_time) = 3 THEN '2.火曜'
    WHEN EXTRACT(DAYOFWEEK FROM date_time) = 4 THEN '3.水曜'
    WHEN EXTRACT(DAYOFWEEK FROM date_time) = 5 THEN '4.木曜'
    WHEN EXTRACT(DAYOFWEEK FROM date_time) = 6 THEN '5.金曜'
    WHEN EXTRACT(DAYOFWEEK FROM date_time) = 7 THEN '6.土曜'
  END AS weekday_label
FROM
  `project.dataset.source_table`;
```

`date_time` カラムから `DAYOFWEEK` 関数を用いて曜日を取得します。
`CASE` 文で数値の曜日インデックスを日本語の曜日名に変換し、新しいカラム `weekday_label` に追加します。
このクエリは、元データを元に新しいテーブル `new_table` を作成します。

## 注意点

### バッククォートの利用
BigQueryでは、テーブル名や列名に特殊文字が含まれている場合、
バッククオート（`）で囲む必要があります。
  
  例:
  ```sql
  SELECT DISTINCT column FROM `project.dataset.table-name`;
  ```
### スケジュールの注意点
BigQueryでスケジュールに設定したクエリは、
登録時のクエリがそのまま使用されるため、
修正が必要になった場合は、元のスケジュール設定を削除し、
新しくスケジュールを設定する必要があります。
Contact Form 7 reCAPTCHA を特定のページでだけ読み込ませる方法

# はじめに

Contact Form 7 は、仕様上、お問い合わせページだけでなく、
サイトトップなど全ページで読み込まれます。

これは Contact Form 7 Google ReCAPTCHA V3 も同様でして、
全ページで読み込まれます。

# 何が問題か

![スクリーンショット 2024-10-04 141558.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130352/e43ef179-eed1-4742-be9f-ac618fc82b0b.png)

お問い合わせページでない、普通のページのリクエストでもReCAPTCHAが動くため、
余計なリクエスト数がカウントされます。

これにより、普通にお問い合わせを行ってもスパム認定される場合があるほか、
ReCAPTCHAの無料枠が月1万リクエストであるため、
それを超えると正常に判定されなくなったり、課金対象になったりします。

そのため、Contact Form 7 も ReCAPTCHA も、
特定のページでだけ読み込ませるような対策が必須になります。

# 実装

`functions.php` に、以下のような記述を追加してください。

```php:functions.php
/**
 * Contact Form 7 をお問い合わせページだけで読み込むようにする
 * これをしないと ReCAPTCHA も全ページで読み込まれてしまい
 * 余計なリクエストが発生するため
 */
function cf7_enqueue_scripts_and_styles()
{
    // CF7を読み込ませる固定ページを定義する
    $pages = ['contact','entry'];
    if (is_page($pages)){
        if ( function_exists( 'wpcf7_enqueue_scripts' ) ) {
            wpcf7_enqueue_scripts();
        }

        if ( function_exists( 'wpcf7_enqueue_styles' ) ) {
            wpcf7_enqueue_styles();
        }
    }
    else {
        wp_deregister_script('google-recaptcha');
        wp_deregister_script('wpcf7-recaptcha');
    }
}
add_filter('wpcf7_load_js', '__return_false');
add_filter('wpcf7_load_css', '__return_false');
add_action('wp_enqueue_scripts', 'cf7_enqueue_scripts_and_styles', 100, 0);
```

# 動作確認方法

1. お問い合わせページでF12キーを押して開発者ツールを開き、要素タブを開きます
1. Ctrl + Fキーを押して検索バーを出し、「contact-form-7」や「recaptcha」で検索します
1. 想定通りのライブラリが読み込まれていることを確認します
1. サイトトップなど、ライブラリを読み込みたくないページで1～2の手順を実行します
1. ライブラリが読み込まれていないことを確認します

# 参考URL

https://qiita.com/blog_bootcamp/items/06dd721a7b591c7d3d33

https://originale.cc/wpcf7/
画像結合のためのアルゴリズムを考えてみた


## はじめに
撮りたい対象が非常に大きい時、一枚の写真では収まりきらないケースというのはよくあります。そのような時に、複数の写真を結合して一枚の写真にしなければ、画像として視認性が低くなってしまいます。この記事では、そのようなケースに対応するための画像結合のためのアルゴリズムを考え、Pythonで実装してみました。提案アルゴリズムは、「入力画像の共通部分を事前情報なしで検出し、自動的に結合する」ことが可能です。

作成したソースコードについてはGitHubにて公開しています。興味のある方は以下のリンクからご覧ください。

https://github.com/C-Naoki/image-stitcher

## 出力例
以下に、アルゴリズムを用いて結合した出力例を示します。初めに、アルゴリズムに入力する画像の例を添付します。具体的には、以下に示す２枚の画像の結合を行います。画像については、[CIFAR-10データセット](https://www.cs.toronto.edu/~kriz/cifar.html)の中から選択しました。

![](https://raw.githubusercontent.com/C-Naoki/zenn-archive/main/images/image-stitcher-application/input.png)

図中の赤いエリアは、データが存在しない部分を表しています。また、右側の画像は、正解画像に比べて90度回転しています。開発したアルゴリズムは、この回転を加味して画像を結合することが可能です。

![](https://raw.githubusercontent.com/C-Naoki/zenn-archive/main/images/image-stitcher-application/rotated.png)

続いて、右画像の回転を補正し、左右の向きを揃えた結果が上図の通りです。緑色の枠で囲まれている部分が、アルゴリズムが自動的に検知した共通部分です。また、タイトル中に記載されている角度（上図では270°）が、アルゴリズムが検出した回転すべき最適な角度を意味しています。入力画像は、元データを90°回転させていることから、最適な角度を検出できていることがわかると思います。

![](https://raw.githubusercontent.com/C-Naoki/zenn-archive/main/images/image-stitcher-application/result.png)

そして、最終的に結合した結果が上図の通りです。アルゴリズムは、入力画像の共通部分を事前情報なしで検出し、自動的に結合することが可能であることが、この例から直感的に理解していただけると思います。

なお、他の実験結果例については、ここでは省略しますが、GitHubの [tutorial.ipynb](https://github.com/C-Naoki/image-stitcher/blob/main/notebooks/tutorial.ipynb) にて公開しているので、興味のある方はそちらをご覧ください。

## アルゴリズムの概要
以下では、提案アルゴリズムの概要を説明します。

### 1. 共通部分探索
![](https://raw.githubusercontent.com/C-Naoki/zenn-archive/main/images/image-stitcher-application/case1.png)

概要図は上記のとおりです。提案アルゴリズムは、$h_c$を共通部分の高さ、$w_c$を共通部分の幅とし、これらを基準とした全探索を行います。共通部分のサイズが $h_c \times w_c$であると仮定すると、共通部分は以下の**4箇所にのみ**存在することがわかります。

1. Image1の左上とImage2の右下の重複部分
2. Image1の右上とImage2の左下の重複部分
3. Image1の左下とImage2の右上の重複部分
4. Image1の右下とImage2の左上の重複部分（上図に対応）

これらにより、特定の共通部分に対して、4箇所を探索することで、過不足なく共通部分を検索することが可能です。

```python
for hc in range(min_h, max(h1, h2) + 1):
    for wc in range(min_w, max(w1, w2) + 1):
        for ix in range(2):
            for iy in range(2):
```

上記のコードの`ix`と`iy`の組み合わせが、上記の4箇所に対応しています。

#### 局所解に対する対策

画像結合において、局所解への収束は、品質の低い画像提供を意味します。このような問題を防ぐために、提案アルゴリズムは共通部分の最小値を設定することが可能です。共通部分のサイズをベースとした全探索を用いたことで、このような問題に簡単に対応可能です。

#### 画像の回転に対する対策

画像の回転に対しては、探索アルゴリズムを適用する前に片方の入力画像 (Image2) を回転させるというシンプルな方法で対処しています。

```python
for angle in [0, 90, 180, 270]:
    # 画像を回転
    _image2 = rotate(image2, angle, resize=True, preserve_range=True).astype(np.uint8)
```

### 2. 共通部分の拡張
![](https://raw.githubusercontent.com/C-Naoki/zenn-archive/main/images/image-stitcher-application/case2.png)

上記で説明したアルゴリズムは、共通部分のサイズが $h_c \times w_c$であると仮定しています。しかし、このアルゴリズムは、$h_c<\min(h_1, h_2)$ かつ $w_c<\min(w_1, w_2)$ という暗黙の仮定に基づいています。すなわち、任意の入力サイズに対応することはできません。このような問題に対応するために、上図のように、$h_c$と$w_c$を拡張することで、任意のサイズの入力画像に対して、提案アルゴリズムを適用することが可能になりました。

## まとめ
本記事では、画像結合のためのアルゴリズムを提案し、Pythonで実装してみました。提案アルゴリズムは、入力画像の共通部分を事前情報なしで検出し、自動的に結合することが可能です。また、提案アルゴリズムは、局所解への収束や画像の回転に対しても対処可能です。最後に、提案アルゴリズムの概要を説明し、その有効性を出力例を基に明らかにしました。

### 追記
2024/10/01: 200+ GitHub Stars🌟 を頂きました。ありがとうございます！
CentOS 7 の標準リポジトリの更新

# バックアップ
cp -p /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak


♯ 変更
~~~
# CentOS-Base.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client. You should use this for CentOS updates
# unless you are manually picking other mirrors.
#
# If the mirrorlist= does not work for you, as a fall back you can try the
# remarked out baseurl= line instead.
#
#
[base]
name=CentOS-$releasever - Base
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
    ※ 冒頭に # を記載し、mirrorlist 行をコメントアウトします。
baseurl=http://vault.centos.org/centos/$releasever/os/$basearch/
    ※ 冒頭の # を削除のうえ、参照先サーバーを vault.centos.org に変更します。
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#released updates
[updates]
name=CentOS-$releasever - Updates
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates&infra=$infra
    ※ 冒頭に # を記載し、mirrorlist 行をコメントアウトします。
baseurl=http://vault.centos.org/centos/$releasever/updates/$basearch/
    ※ 冒頭の # を削除のうえ、参照先サーバーを vault.centos.org に変更します。
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras&infra=$infra
    ※ 冒頭に # を記載し、mirrorlist 行をコメントアウトします。
baseurl=http://vault.centos.org/centos/$releasever/extras/$basearch/
    ※ 冒頭の # を削除のうえ、参照先サーバーを vault.centos.org に変更します。
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus&infra=$infra
    ※ 冒頭に # を記載し、mirrorlist 行をコメントアウトします。
baseurl=http://vault.centos.org/centos/$releasever/centosplus/$basearch/
    ※ 冒頭の # を削除のうえ、参照先サーバーを vault.centos.org に変更します。
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
~~~


# キャッシュクリア
~~~
yum clean all
~~~

# 確認
~~~
yum repolist
~~~
エラーが出なければOK
URIの構成

# 複雑なURIの場合
```
http://yohei:pass@blog.example.jp:8000/search?q=test&debug=true#n10
```
### URIスキーム
>そのURIが利用するプロトコルを示すのが一般的です。
...
`URIスキームとその後ろに続く部分は「://」で区切られます`

この場合http
# ユーザ情報
>URIスキームの次に`ユーザ情報`が入っています。ユーザ情報は、このリソースにアクセスする際に利用するユーザ名とパスワードから成ります。`ユーザ名とパスワードは「：」で区切り`ます。

### ホスト名
>DNSで名前が解決できるドメイン名かIPアドレスで、インターネット上で必ず一意になります。

この場合、blog.example.jp

# ホスト名とポート番号
>ホスト情報は`ホスト名とポート番号からなり、両者は「:」で区切られます`。ポート番号は、このホストにアクセスするときのプロトコルで用いるTCPのポート番号を示します。`ポート番号を省略した番号は各プロトコルのデフォルト値が使われます`。`httpのデフォルト値は80番`です。

yohei:pass
この場合、ユーザ名がyohei,パスワードがpass
### パス
>ホスト名のあとには階層を表すパスが続きます。パスは、そのホストの中でリソースを一意に指し示します。

/search

# クエリパラメータ
>パスの後ろに区切り文字がある`「？」が付き、名前＝値形式のクエリ`が続きます。この例ではq=testとdebug=trueがそれぞれクエリです。クエリが複数あるときは「＆」で連結します。この`一つ以上のクエリの集合を「クエリパラメータ」または「クエリ文字列」`と呼びます

q=test&debug=true

# URIフラグメント
>その前までの文字列で表現する`URIが指し示すリソース内部の、さらに細かい部分を特定`するときに利用します。例えば、このリソースが`HTML文書だった場合は、id属性の値がn10である要素を示す`ことになります。

この場合、n10

# 出典
https://gihyo.jp/book/2010/978-4-7741-4204-3

# 感想
まだURIフラグメントに関して理解できていないがURIの構造を理解できた気がする。
これから役立ちそうだ。
ABC066 ARC077 の問題を解いてみました

## A問題
https://atcoder.jp/contests/abc066/tasks/abc066_a

安いベル2つを購入すれば良いです。

~~~C++
#include <bits/stdc++.h>
using namespace std; using ll = long long;
//Created by karaju.

signed main(void){
  vector<int> bell(3);
  for(int i = 0; i < 3; i++) cin >> bell[i];
  sort(bell.begin(), bell.end());
  
  cout << bell[0] + bell[1] << endl;
}
~~~
~~~C++:別解
#include <bits/stdc++.h>
using namespace std; using ll = long long;
//Created by karaju.

signed main(void){
  int a, b, c;
  cin >> a >> b >> c;
  
  cout << (a + b + c) - max({a, b, c}) << endl;
  //合計から最も高いベルの価格を引く
}
~~~

## B問題
https://atcoder.jp/contests/abc066/tasks/abc066_b

pop_back()で末尾の文字を消して、判定することを繰り返しましょう。


~~~C++
#include <bits/stdc++.h>
using namespace std; using ll = long long;
//Created by karaju.

signed main(void){
  int n;
  string s;
  cin >> s;
  n = s.length(); //sの長さを保存しておく
  
  for(int i = 1; i <= n; i++){
    s.pop_back();
    
    int m = n - i; //今の文字列の長さ
    if(m % 2 == 1) continue; //長さが奇数の場合は、偶文字列ではない
    
    if(s.substr(0, m / 2) == s.substr(m / 2, m / 2)){ //判定
      cout << m << endl;
      return 0;
    }
  }
}
~~~

## C問題
https://atcoder.jp/contests/abc066/tasks/arc077_a

毎回$b$を並び替えていると時間がかかってしまうので、$b$が反転しているかを記録しておいて、もし反転しているなら後ろから出力するという処理をできるようにしたいです。

しかし、それでは1の処理のときにおかしくなってしまいます。
そこで1の処理にどのように対応するか考えます。
すると、$b$が反転しているとき、末尾に加えるという操作は、先頭に加えるという操作で対応できることがわかります。

それを実装しましょう。

~~~C++
#include <bits/stdc++.h>
using namespace std; using ll = long long;
//Created by karaju.

signed main(void){
  int n;
  cin >> n;
  vector<int> a(n);
  for(int i = 0; i < n; i++) cin >> a[i];
  
  deque<int> b;
  bool rev = false; //反転しているか記録するbool型
  
  for(int i = 0; i < n; i++){
    if(!rev){ //反転していない
      b.push_back(a[i]);
    }
    else{ //反転している
      b.push_front(a[i]);
    }
    
    rev = !rev; //反転させる
  }
  
  if(!rev){
    for(int i = 0; i < n; i++){
      cout << b[i] << " ";
    }
  }
  else{
    for(int i = n - 1; i >= 0; i--){
      cout << b[i] << " ";
    }
  }
}
~~~

## D問題
https://atcoder.jp/contests/abc066/tasks/arc077_b
Vite × ReactのプロジェクトをIEで動かす

# はじめに
この記事は、Vite × ReactのプロジェクトをIEで動かすための設定手順を記載しています。

使用するのは以下の2つ。
- @vitejs/plugin-legacy: viteのプラグイン
- core-js/actual: poryfillを提供するライブラリ

以下に、それぞれの利用方法とビルドまでの流れを記載しています。

# @vitejs/plugin-legacy
@vitejs/plugin-legacyは、viteのプラグインで、vite.config.jsonに設定を追記することで利用できます。

### Step1 @vitejs/plugin-legacyのインストール
```
npm i @vitejs/plugin-legacy
```
#### 関連ライブラリのインストール
terserが必要なので、そちらもインストール
```
npm add -D terser
```
### Step2 vite.config.jsで設定を記述
#### 2-1 ターゲットブラウザの指定
```vite.config.js
import legacy from '@vitejs/plugin-legacy'

export default {
  plugins: [
    legacy({
      targets: ['defaults', 'not IE 11'],
    }),
  ],
}
```

#### 2-2 個々のポリフィルを指定して導入
デフォルトでは、上記の`targets`に指定したブラウザに対応するporyfillのchunkが生成されますが、うまくいかない場合は、`polyfills`や`modernPolyfills`で、個々のporyfillを指定します。

個々のpolyfillの指定方法は、[公式ドキュメント](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy#polyfill-specifiers)で以下のように説明されています。
> Polyfill specifier strings for `polyfills` and `modernPolyfills` can be either of the following:
> - Any [core-js 3 sub import paths](https://unpkg.com/browse/core-js@latest/) - e.g. es/map will import core-js/es/map
> - Any [individual core-js 3 modules](https://unpkg.com/browse/core-js@latest/modules/) - e.g. es.array.iterator will import core-js/modules/es.array.iterator.js

vite.config.jsonの例👇
```vite.config.js
import legacy from '@vitejs/plugin-legacy'

export default {
  plugins: [
    legacy({
      targets: ['defaults', 'not IE 11'],
      polyfills: ['es.promise.finally', 'es/map', 'es/set'],
      modernPolyfills: ['es.promise.finally'],
    }),
  ],
}
```

このように、必要なporyfillを一つひとつ指定して追加していく方法もありますが、「必要なporyfillを判別する」こと自体なかなか大変な作業です。
いちいちporyfillを調べて追加するのが面倒な場合は、後述するcore-jeを利用することで、包括的にporyfillを導入することができます。

# core-js
core-jsで提供されているporyfillの種類は多々ありますが、今回は`core-js/actual`を利用します。
core-js/actualは、現在使用されている標準JavaScriptを、包括的に網羅しています。
[公式ドキュメント](https://github.com/zloirock/core-js/blob/master/README.md)には、以下のように説明されています。
> polyfill all actual features - stable ES, web standards and stage 3 ES proposals:


導入方法はシンプルで、インストール後、アプリケーションのエントリーファイルにimport文を記述するのみです。

### Step1 core-jsのインストール
```
npm i core-js
```

### Step2 エントリーファイルにimport文を記述
アプリケーションのエントリーファイルに以下のimport文を追加。
```main.tsx
import core-js/actual
```

# ビルド
上記の`vite-plugin-legacy`と`core-js`の設定ができたら、以下のコマンドでビルドを実行。
```
vite build
```
生成された`dist`フォルダ内に、`index-legacy-XXXXX.js`と、`poryfills-legacy-XXXXX.js`が生成されていればOK。これらのファイルがIEで動かす時に利用されます。

詳細は、以下の記事が参考になります👇

https://techblog.lycorp.co.jp/ja/20231218a

# 最後に

Viteの設定では、`build.target`を指定することができますが、最も低いターゲットは es2015(es6)なので、IEはこの設定で対応することはできません。※IE11はes5までしか対応していません。   ...(´ºωº｀)IEｯﾃﾌﾙｲﾈ..


最後まで読んでいただきありがとうございます。 ( ᵕᴗᵕ )ﾉ
Node.jsで作るWebサイトのポイント、テンプレートエンジンとデータベース更にログイン認証

<font color="blue"><b>パート１「テンプレートエンジン ejsの使い方。」</b></font>
webサイトの構築を考える上で必要なイメージはWordpress等を代表するサイトデザインのテンプレートを利用し、投稿の内容はデータベースへ保存し、当然のようにログイン機能でサイトを保守する。この様な機能を網羅したサイトを今更ですが、Node.jsで作る為のメモを記載して行きます。
基本的にPC内に、node,npm等が使用可能な環境で、編集はvscodeとします。(node v22.2.0 npm 10.7.0)
ファイル構成は下記。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/8d04789d-36c3-7001-73cd-a9834ac0fe28.png" width="30%">
server.jsは下記の様。
```
//Imports
const express = require("express");
const expressLayouts = require("express-ejs-layouts");

const app = express();
const PORT = 5009;

//Static Files
app.use(express.static('public'));
app.use('/css', express.static(__dirname + 'public/css'));

//Set Templating Engine
app.use(expressLayouts);
app.set('view engine', 'ejs');

//Navigation
app.get('', (req, res) => {
    res.render('index');
})

//Listen On Port 5000
app.listen(PORT, () => console.log(`App lisetn on port ${PORT}`));
```
index.ejsの内容
```
<p>Hello World!!</p>
```
layout.ejsの内容
```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <%- body %>
</body>
</html>
```
ここで、ブラウザのページソースを確認すると、下記の様にlayout.ejsのbody部分にindex.ejsの内容がレンダリングされています。この様にする事で、固定的なメインページを作成し更に個々のテンプレートを作成レンダリング可能となります。
```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>Hello World!!</p>
</body>
</html>
```
ブラウザ上の表示は下記。
Hello World!!

パート１ではここまで、下記にpackage.jsonインストールモジュール記載
    "ejs": "^3.1.10",
    "express": "^4.21.0",
    "express-ejs-layouts": "^2.5.1",
    "express-layouts": "^1.0.0",
    "nodemon": "^3.1.7"
Goが復活させた習慣

Go言語が登場したのは2009年のこと。
私はGoを業務で使った経験は少ない（半年ほど）しかないのだが、Goの影響力は毎日感じている。それは「変数は1文字でもいい」という習慣を、Goが復活させたこと。

私が2010年代に勤めていた会社では、コーディング規約を重視していた（今思えば、社員が若かったからだ）。そこでは、`i` のような「短くて分かりにくい」変数はNGで、`index_of_users`を使うべきとされていた。

もちろん、これはスコープの観点が抜けている。外部に公開する関数名や引数名では、多少冗長でも分かりやすい名前を使うべきだが、関数内でしか使われない変数では1文字でも意味は掴みやすいし、長い名前はかえって可読性を落とすこともある。

しかし、現代でも公開されているコーディング規約や書籍では「説明的で分かりやすい名前を使いましょう」的なことは書かれていることは多い。そのため、私や私の同僚は愚直に教えに従おうとしていた。

そんな時に、Goのコードでは1文字変数`i`や`l`を堂々と使いだした。サンプルコードでも、標準ライブラリでも1文字変数だらけ。Goは大企業Googleが発表したこともあり、それなりにリスペクトされた。「Goが採用してるんなら、それが良いやり方なんだろう」と。踏ん切りがついた私たちは、PHPやRubyといった言語でも1文字変数`i`や`l`を堂々と使うようになった。
ついでに、当時の会社では「`l`は数字の`1`と誤解しやすいのでNG」「`j`は`i`と誤解しやすいのでNG」というルールもあったが、それも消えた。
質問アプリの作成　＃２

# ビューを作る

ターミナルでrails s を入力。

ポートからURLで飛びrails起動されたのを確認したら、
さらにroutesで設定した　questions/new をURLに付け足す。

試しにviews > questions > new.html.erbを新規ファイルで作り、
H1タグでNEWを記述。
サーバーを再度確認、「NEW」の記述が確認できたら次のステップへ

QuestionsControllerを開き空のquestionモデルのインスタンスを使うため
準備する。

ここでは、newメソッドが呼ばれます。

```
    #質問の作成
    def new
        @question = Question.new
    end

```

Question.newでQuestionのインスタンスを新規に作成し変数@questionに入れます。
次にView側を編集
(ホームビルダーと呼ばれるrails機能を利用します)

```
<h1>NEW</h1>
<%= form_with model:@question do |form| %>
    <div>
    <%= form.label :title%><br>
    <%= form.text_field :title %>
    </div>
    <div>
    <%= form.label :name%><br>
    <%= form.text_field :name %>
    </div>
    <div>
    <%= form.label :content%><br>
    <%= form.text_area :content %>
    </div>
    <div>
    <%= form.submit %>
    </div>
<%end%>

```

***実際のNewページの表示***
![スクリーンショット 2024-10-01 19.57.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3870482/548e7c99-8262-27c7-a2a2-4a06eb40c9e6.png)


## 質問の登録〜コントローラー〜

先ほどNEWで作った内容フォームからsubmitをクリックした後、
データを受け取ってデータベースに保存する処理をするのがcreateメソッド。

さっそく、コントローラーに記述していく。
(フォームから送信されたデータはパラムスというメソッドに入っている)
パラムスの内容を確認してみる

```
p params
```

ここでうまくPOSTが機能しない問題に直面。
臨時対応としてエラー要因のURLリクエストの受信を
チェックスルーするように設定。（開発環境のみで推奨）

```
config.action_controller.forgery_protection_origin_check = false
```

## データベースに保存しよう

```
def create
#Questionモデルを初期化
#QuestionモデルをDBへ保存
#showへリダイレクト
end
```

コンソールでデータ保存されたかを確認
Questionテーブルから全ての値を取得する
```
rails dbconsole
select * from questions;
//結果が表示されたらOK

.q
//コンソール終了
```

showアクションを実装

入力データの表示します

```
<h1>Show</h1>
```

データを入力し、showと表示されれば成功！


URLのidは自動で作成されます。これを取得するにはparamsを使います

試しに、簡易的にshowメソッドで調べてみる

```
def show
    p params
end
```

newからデータ入力して送信。ターミナルを確認すると、Pメソッドで
IDが取得できた。

paramsから、IDだけ取りたい時には。さっきのコードに[:id]を付け足す


```
def show
    p params[:id]
end
```

これを応用して、取得した変数@questionに格納されたデータを
pメソッドで出力します。

```
@question = Question.find(params[:id])
 p @question 
```

データベースの操作にactive Recordを使っているので、SQLが自動生成されて
標準統一企画でも賄えない差異を、修正してくれる機能を持っている。
ただ、データベースの[select分]がおかしいなとなったときは
意図しないデータになっていることがあるので、コンソールで調べることを
考えましょう。

アプリが動いているのを確認できたら、次はshowのviewsで
title,name,contentを表示します

```
title:
<%= @question.title %>
```

## 質問一覧表示しよう

まず、viewsを作成

- index.html.erbファイル作成

次に、メソッド定義

```
def index
# @questionsに全データ取得

end
```

p paramsで試しに出力。
問題なく返ってきたら、index.htmlにテーブルを作成して表示させる

```
<table>
<tr>
<th>ID</th>
<th>Table</th>
<th>Name</th>
<th></th>
<th></th>
</tr>
<% @questions.esch do |question| %>
<tr>
<td></td>
<td></td>
<td></td>
<td><% link_to 'show', question_path(question) %></td>
</tr>
<% end %>

</table>
```

lint_to ではaタグの役割があり、pathを使うとヘルパー機能でリンクが自動生成される。

URLを検証すると、HTMLにはa hrefと変換されている。
Docker+AWS Lambda+Python(Flask)で簡単にサーバーレスAPIを実装する

# 🛢️ はじめに
ローカルの Docker 環境で AWS Lambda(Serverless Framework)と Python(Flask)でサーバーレス API を実装，デプロイします．非常に簡単にAPIを実装できるので便利です．皆さんも試してはいかがでしょうか．

# 🛢️ 自己紹介
初めまして．趣味でweb開発を勉強している273*(ﾂﾅｻﾝﾄﾞ) / Kei.と申します．関西の大学生です．最近はフルスタック開発やツール制作を行なっています．まだまだ初心者です．

# 🛢️ 完成品
以下のリポジトリにテンプレートを用意しましたので，お好きに使ってください！

https://github.com/273Do/Sls-Python-Docker-TPL

# 🛢️ 実装
### 使用ツール
- [Docker](https://www.docker.com/ja-jp/)：PCの中に仮想環境を作れるツール．他のプロセスと遮断できるため環境の差をなくすことができる．
- [AWS Lambda](https://aws.amazon.com/jp/lambda/)：AWSが提供しているサービス．プログラムを定義しておき，インターネットを通じて実行できる．
- [Serverless Framework](https://www.serverless.com/)：サーバレス・アプリケーションを簡単に構築するためのツール．Node，Pythonなどいろんな言語やフレームワークに対応している．LambdaやAPIGatewayの設定を自動化，ymlで実装できる．
- [Python](https://www.python.org/)：機械学習やwebシステムなどなんでも作れる万能なプログラミング言語．
- [Flask](https://msiz07-flask-docs-ja.readthedocs.io/ja/latest/)：Pythonのwebフレームワーク．
- WSGI：Pythonのwebフレームワークとwebサーバーを接続するインタフェース．読み方はウィスキーやウィズギー．

---
### 事前準備
1. [こちら](https://zenn.dev/akkie1030/articles/aws-cli-setup-tutorial#%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%82%AD%E3%83%BC%E3%81%AE%E7%99%BA%E8%A1%8C)を参考にAWSからアクセスキーとシークレットキーを発行してください．

2. Macを使用している場合は設定からAirPlayレシーバーを切っておきましょう．
(ポートがFlaskのデフォルトポートである5000番と重複しているため)

---
### 実装

1.  上記のリポジトリをクローンしてください．

2. `docker-compose.yml`の`container_name`にコンテナ名を設定し，`docker compose build` でDockerイメージを構築します．

3. `docker compose up -d`でデタッチドモードでコンテナを起動します．

4. `docker exec -it 設定したコンテナ名 /bin/bash`でコンテナの中に入ります．

5. `serverless` でプロジェクトを作成します．

    1. 今回はFlaskで実装してみたいので`AWS / Python / Flask API`を選択します．
    2. プロジェクト名を設定します．
    3. Serverless Frameworkのログインを求められますので，表示されたリンクからログインしてください(`Login/Register`を選びます)．
    4. アプリを作成するか既存のアプリを選択するか聞かれますのが，`Skip Adding An App`を選択します．
    5. AWSの認証を求められますので，`Save AWS Credentials in a Local Profile`を選択して事前準備で用意したアクセスキーを入力します．
    6. 作成されたディレクトリに移動し，`npm i`を実行します．

7. `serverless.yml`でPythonのバージョン(`runtime`の部分)を`python3.9`に変更し，`custom`の`wsgi`に`pythonBin: /usr/bin/python3`を追加します．

8. `docker-compose.yml`のコメントアウトされている部分を解除し，`FLASK_APP`にapp.pyのパスを指定します．

10. `exit`でコンテナから抜け, `docker compose down`でコンテナの終了させます．

11. `docker compose up`でコンテナ内のflaskアプリがローカルで起動します．この時点でhttp://localhost:5000 をGETメソッドで叩くと，jsonで`Hello from root!`とレスポンスが返ってきます．

12. コンテナの中に入って，`aws configure`コマンドでAWSの認証をしておきましょう．region(AWSサーバー)やoutput format(デフォルトはjson)はお好みでどうぞ．

13. デプロイする時はコンテナの中に入り，`serverless.yml`のあるディレクトリに移動し，`sls deploy`を実行します．するとAWSに自動でデプロイされます．デプロイ後，ターミナルにデプロイ先のリンクが表示されます．AWS コンソールからも確認できます．また，LambdaとAPI Gatewayが作成，接続されているのを確認できます．


# 🛢️ 最後に
いかがでしたでしょうか．簡単にサーバーレスAPIを実装することができました！
`serverless.yml`で環境をコードで書けたり非常に便利ですね！他にもPython以外の言語や`DynamoDB`や`S3`と連携することもでき，動作をローカルで試すことも可能です．誰かの参考になったら幸いです．最後まで読んでいただきありがとうございました．それでは！
Webアプリを作成して公開したい #2

続きです。

Railway.appを使用してデプロイを試みます。

３．デプロイする（続き）
--
アプリのアカウント作成 → Githubの連携と
基本的には以下の通りに進めました。

https://zenn.dev/gibjapan/articles/881d1e3a1241f1

前回も記載した通り、DB接続は後回しです。
なので環境変数は何も追加していません。

が、Githubを連携して「Deploy Now」しても
ビルドが開始されず アドレスを叩いてもNotFoundのままです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/93fb0bea-1081-33e3-162d-9f2ae119cda4.png)

何が原因かわかりません。
今回はデモアプリを使用していて
インデックスページを用意していないのでルートのアドレスにアクセスしてもエラーになるのは把握済み、なのでアクセスしたのは以下になります。

>アプリ名.up.railway.app/add?a=5&b=3

しかし状況は変わらず....
ルートの問題かと思いましたがそもそもビルドされないので
原因は異なると思い色々試しました。

結果、無料枠のスペックオーバーが原因でした。
結局500円くらい払う羽目になりました。
無料を目指していたので悔しくはありますが、まあいいでしょう。

Spring Initializrを使用しているので
設置したディレクトリ階層が一段下になっています。
これが必要かどうかわかりませんがデプロイしたいので
Root Directoryにルートを一段下に指定して保存しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/486f6fdd-7f52-1325-f396-a3d439eeb3ab.png)

※指定したのは赤枠の階層です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/7933beb7-575c-eebd-90a7-5e40349ec442.png)


正常にビルドされて無事デプロイ完了。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/a23a0190-d5de-0fe0-f62a-05c1765ace5f.png)

次はローカルで変更した内容をGithubに上げて、変更をデプロイしてみます。
それができたらDB接続ですね。
これは環境毎に設定します。ローカルと、本番で使い分けたいです。

それではまた次回。
GitHubの使い方

# Githubを使うシチュエーション

・ポートフォリオを公開するのに必要
・開発に必要不可欠

開発環境
管理ツール：Sourcetree
アカウント：github


## リポジトリとは？

Gitでバージョン管理する対象のフォルダのこと

- ローカルリポジトリを作る
    
![スクリーンショット 2024-10-04 12.08.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3870482/c468e9c5-15ca-2d59-f69d-95d223c435e2.png)


## コミットとは？
バージョン管理をするためのセーブポイント

## ブランチとは？
お互いが作成するコードによって影響を受けないように、
別の作業データに分けること

##　マージとは？
ブランチで作成したコードをmasterに合体させること

##GitHubと連携させる
-アカウントの認証

## リモートリポジトリの作成
動画内でURLをコピーする箇所がありますが、その際はSSHを選択してからコピーするようにしましょう。


![スクリーンショット 2024-10-04 12.19.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3870482/a14ab8a7-2e23-e3b5-f06e-5ea46ed7cbec.png)

mainから必ずブランチを行おう！
※分岐の地点が変わった場合は、マージが行えなくなる。
python3 基礎試験 関数のメモ

Python3エンジニア認定基礎試験に向けて勉強中です。
今回は、関数に関してのメモ書きです📝

# 1. global文
関数の外側で定義されたグローバル変数に値を代入する場合、global文を使用する
```python
# 簡単な例

x = 300

def function():
    # globsl変数の x であることを以下で示す
    global x
    x = 200

function()
print(x) # 結果:200
```

# 2. 位置引数とキーワード引数
**キーワード引数** : `キーワード=値`の形式で与えられる引数のこと。
**位置引数** : 値だけの引数
```python
# aは位置引数、bとcはキーワード引数
def function(a, b='apple', c='banana'):
    print(a, b, c)

# 正しい呼び出し方
function('cherry', b='mango', c='orange')

# NGな呼び出し方
function(b='mango', c='orange', 'cherry') #引数の順序(位置引数が先)
function('cherry', b='mango', p='orange') #存在しないキーワード引数pが登場
function('cherry', 'grape', b='mango', c='orange') # bへの引数指定が重複

```
↑試験での選択肢にこういうNG例が提示されるかもなので、よく見る。

# 3. 引数のデフォルト値
```python
def function(str, default_arg_list=[]):
    default_arg_list.append(str)
    return default_arg_list

print(function('apple'))
print(function('orange', ['banana', 'grape']))
print(function('mango'))
print(function('cherry', ['lemon', 'strawberry']))
print(function('kiwi'))
```
実行結果は
```python
['apple']
['banana', 'grape', 'orange']
['apple', 'mango']
['lemon', 'strawberry', 'cherry']
['apple', 'mango', 'kiwi']
```
> **💡キーワード引数が指定されている**場合 : 
そのキーワード引数の末尾に第一引数が加わる。

> **💡キーワード引数が指定されていない**場合 : 
`default_arg_list`に第一引数の値がどんどん加わっていく。

実務では引数のデフォルト値をリストにせず、以下のようにNoneにするのが良いらしい。
```python
def function(str, default_arg_list=None):
    if default_arg_list is None:
        default_arg_list = []
    default_arg_list.append(str)
    return default_arg_list
```

# 4. 仮引数の * と **
```python
def function(num, *args, **kwargs):
    print(num)
    print(args)
    print(kwargs)

function(1, 'one', kwargs1='kw1', kwargs='kw2')
```
実行結果は以下の通り。
```python
1
('one',)
{'kwargs1': 'kw1', 'kwargs': 'kw2'}
```
- `*`が先頭についた仮引数 : 指定済みの実引数を除いた位置引数のタプルが入る（可変長引数）
- `**`が先頭についた仮引数 : 指定済みの実引数を除いたキーワード引数のディクショナリーが入る（可変長気キーワード引数）

# 5. リスト、タプル、辞書として与えられた引数
```python
def function(*args, separator="/"):
    return separator.join(args)


animals = ["dog", "cat", "fox"] #リスト
options = {"sep": "&"} #辞書

print(function(*animals, **options))

# 出力
dog&cat&fox
```
- リストやタプルには `*`を先頭につけることで、要素を位置引数に展開して渡すことができる（**アンパック**）
- 辞書は、`**`を先頭につけることで、キーワード引数に指定できる

# 6. lambda式
無名関数で、単一の式しか持てない。
`lambda 引数:式`と記述し、返り値は式の結果。
```python
function = lambda x, y: (y + 2, x * 4)
a, b = 2, 5
a, b = function(a, b)
print(a, b)

#結果
7 8
```

 # 7. docstring
 ```python
 def function(a, b):
     """
     1行目には、クラスや関数の説明コメントを書く

     3行目には詳細な説明（呼び出しや引数についてなど）
     """
     return a + b
```
docstring自体を参照したい時には`__doc__`属性を使用する
```python
print(function.__doc__)

# 結果
#    1行目には、クラスや関数の説明コメントを書く

#    3行目には詳細な説明（呼び出しや引数についてなど）
```

初学者の理解ですので、誤認などがありましたらお手数ですがご指摘いただけますと幸いですm(_)m
AmplをVS Codeで実行したい(Mac)

## 実行環境
・Apple M3 (Sonoma)

## 発見した方法
拡張機能の`Code Runner`を使うことでできました．
``` settings.json
 "code-runner.executorMap": {
 "ampl": "/Applications/AMPL/ampl",
 }
 ```
 上記のように設定することで，無事実行できるようになりました．

## 注意点
#### 1. 実行場所
以上の設定でcode-runnerで動くようになりましたが，正しい実行場所で動かさないといけません．
`cd`コマンドを利用して，実行したい`.run`ファイルがある階層までいき，そこで実行してください．
#### 2. ファイルのパス
並列な`.dat`ファイルであれば`.run`ファイルは以下のようで問題ありません．
``` example.run
reset;

model example.mod;
data example.dat;
option solver cbc;

option display_round 6;
solve;

expand > example.sol;
display Objective > example.sol;
for{i in C, j in C}
{
    if(z[i, j] == 1) then
    {
        printf: "%d, %d\n", i, j > example.sol;
    }
}
```
しかし，ファイルに分けている場合，うまくいきません．相対パスを使ってももちろん大丈夫ですが，めんどくさい場合は，以下のように絶対パスで指定しましょう．
``` 
data /Users/***/Coding/Ampl/data_file/example.dat;
```

## まとめ
英語でも探したのですが，記事が見つからなかったので書きました．
`Code Runner`万歳．

## どうでもいいこと
Code Runnerの画像が偶然，amplの拡張子である`.run`でした...
~~最初から対応しててくれ...~~
![スクリーンショット 2024-10-04 12.03.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1734281/643ad141-91f0-e94a-d255-7e73938c25a6.png)
FlutterでAPIのレスポンスをデータモデル化してスネークケースからローワーキャメルケースで扱う方法

## この記事でできること
- apiのsnakeCaseのフィールドをlowerCamelCaseとして扱える
- Stringの日付をdartのDateTime型に変換し扱える

## 前提
バージョンはご自身の環境に合わせてください
```pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  # freezed
  freezed_annotation: 2.4.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  # freezed
  freezed: 2.4.5
  build_runner: 2.4.6
  json_serializable: 6.7.1
```

## APIのサンプルの仕様
以下のようなresponseが返ってくるAPIと仮定します
```json
{
  "id": 3342124,
  "message": "Hi!",
  "user_id": 3456,
  "user_name": "Taro Yamada",
  "user_image_url": "/images/taro.png",
  "birth_day": "2024-10-10 00:00:00"
}
```
## flutterでデータモデルの定義
- `＠JsonKey`アノーテーションで受け取ったjsonのフィールドを定義する
```api_response.dart
// ignore_for_file: invalid_annotation_target
import 'package:freezed_annotation/freezed_annotation.dart';
import './converter/datetime_converter.dart';

part 'api_response.freezed.dart';
part 'api_response.g.dart';

@freezed
class ApiResponse with _$ApiResponse {
  const factory ApiResponse({
    @JsonKey(name: 'id') required int Id,
    @JsonKey(name: 'message') required String message,
    @JsonKey(name: 'user_id') required int userId, 
    @JsonKey(name: 'user_name') required String userName,
    @JsonKey(name: 'user_image_url') required String userImageUrl,
    @JsonKey(name: 'birth_day') @DateTimeConverter() required DateTime birthDay,
  }) = _ApiResponse;

  factory ApiResponse.fromJson(Map<String, dynamic> json) => _$ApiResponseFromJson(json);
}
```
## カスタムConverterを作成

- String型だと扱いにくいのでJsonConverterを実装したDateTimeConverterを作成しdartのDateTime型に変換する
- ISO8601形式だったのでtoJsonは`toIso8601String()`を使用しましたが実装のみで使用していません
```datetime_converter.dart
class DateTimeConverter implements JsonConverter<DateTime, String> {
  const DateTimeConverter();

  @override
  DateTime fromJson(String json) => DateTime.parse(json).toLocal();

  @override
  String toJson(DateTime object) => object.toIso8601String();
}
```

## コードを生成
```
flutter pub run build_runner build --delete-conflicting-outputs
```
## 取得例
```dart
import 'package:http/http.dart' as http;

Future<ApiResponse> fetchData() async {
    final String url = "URL_PATH";
    final uri = Uri.parse(url);
    
    final client = http.Client();
    var response = await client.get(
      uri,
      headers: {
        'Content-Type': 'application/json'
      }
    );
    if (response.statusCode == 200) {
      return ApiResponse.fromJson(json.decode(response.body));
    } else {
      throw '取得に失敗しました';
    }
}

final data = await fetchData();
print(data.userName); // dartの命名規則に則ったlowerCamelでアクセスできる
print(data.birthDay.runtimeType); // DateTime型になっている
```
## 注意点
freezedを使用しているので当然ですが、`fetchData()`で取得されるApiResponseはImmutableになります
mutableとして扱いたい場合は`copyWith()`を使用して新しいインスタンスを作成してください
## 参考
https://zenn.dev/rmassu/articles/8e169b0ba26ad1
https://zenn.dev/sae_eng/articles/ed68107fdae18d
https://dev.classmethod.jp/articles/flutter-dart-freezed/
ACDLを提唱します。その8

# 概要
ACDLとは、アプリは、クラウド、大切なデータは、ローカルです。
素晴らしいアプリ見つけたので、plunkerに上げてみた。

# 参考にしたページ

https://qiita.com/camino37/items/39f46adbc575f9c90763

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/eaecb3b9-3a81-833d-aef3-bb3535f348a8.png)



# 成果物

https://embed.plnkr.co/plunk/90xpJjouEqIZGyEE


以上。
【SwiftUI】iOS18でsheet→alertが連続で表示されるようになった？

## どういうこと？:thinking:
```swift
    @State var isPresented: Bool = false
    @State var isAlertOPresented = false
    
    var body: some View {
        NavigationView {
            // テキトーなViewが書かれている
        }
        .interactiveDismissDisabled()
        .onAppear() {
            isPresented = true
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                isPresented = false
                isAlertOPresented = true
            }
        }
        .sheet(isPresented: $isPresented) {
            VStack {
                ProgressView()
            }
            .interactiveDismissDisabled()
            .dynamicTypeSize(.medium ... .medium)
        }
        .alert("アラート表示", isPresented: $isAlertOPresented) {
            Button("ok") {
            }
        } message: {
        }
    }
```

このような、1秒間ぐるぐるが表示したあと、アラートを表示したいというコードがあったとして、
iOS17では、以下のように遅延を入れないと、sheet→alertが表示されない。
```swift
            isPresented = true
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                isPresented = false
                DispatchQueue.main.async { // 遅延が必要
                    isAlertOPresented = true
                }
            }
```
遅延なしのコードだと、↓エラーが表示される。
```
Attempt to present <SwiftUI.PlatformAlertController: 0x105818600> on <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x10381b000> (from <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x10381b000>) which is already presenting <_TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView_: 0x104837400>.
```


iOS18では、遅延を入れなくてもsheet→alertの順で表示されるようになった。
また、"Attempt to present〜〜〜"のエラーも表示されなくなった。

iOS18からsheetやalertの動きが変わったのかと思ったが、このことについて検索してみたがHitせず。

よくわからんが動くのでヨシ！

とりあえずメモしておく。

なにか知っている方がいたら、コメントください。

### 検証環境
* Xcode16
* iOS18.0
* iOS17.1.1
WinSCPの接続情報をHDD内から取り出す

# 概要
WinSCPを使っていたWindowsのPCのマザーボードが壊れてしまった。
HDDは生きていたので取り出した。
HDD内のWinSPCを起動すると接続情報が空になっていた。
もともと保存していた場所にもなさそう。
（C:\Users\ユーザー名\AppData\Roaming\WinSCP.iniが無い）
なのでほかの方法で復旧できないか試みました。

## 解決方法
```NTUSER.DAT```から復旧する。

# 詳細手順

## NTUSER.DATがあるか確認

```.txt:例
F:\Users\ユーザー名\NTUSER.DAT
```

## レジストリ エディターを開く
![スクリーンショット 2024-10-04 111446.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290284/7526ecf6-1267-4fd9-2870-020c63c89925.png)

## NTUSER.DATを読み込む

HKEY_USERSを選択して、「ファイル」→「ハイブの読み込み」
先ほどの```F:\Users\ユーザー名\NTUSER.DAT```を選択
キー名は適当にTempHKCUとか入力

![スクリーンショット 2024-10-04 111623.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290284/e6015123-fd10-d434-d3c6-305a4b8fe1bb.png)

レジストリ内容がロードされるので、```Software\Martin Prikryl\WinSCP 2```を確認すれば完了
![スクリーンショット 2024-10-04 112145.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290284/485b6938-d350-2302-417a-745721301f63.png)

# 番外編：パスワードわかんなくて接続できなくなっちゃった
## 一旦、接続先を保存
パスワードあとで書き換えるので適当になにか入力しておいてください。
![スクリーンショット 2024-10-04 113235.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290284/186bd54e-db28-5caf-5059-509a428cce98.png)


## レジストリ エディターのPasswordをダブルクリック
暗号化されたパスワードのコピーができる
![スクリーンショット 2024-10-04 112644.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290284/9a741265-ba27-4da0-3c36-51f4f8bdd56a.png)

## WinSCP.iniをメモ帳で開き、わからないパスワード部分を書き換える

```
C:\Users\ユーザー名\AppData\Roaming\WinSCP.ini
```

![スクリーンショット 2024-10-04 113619.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290284/8e63a080-9a1a-e90d-abc0-7848288c1394.png)

上記を保存した後、WinSCPを再起動する。
パスワードがわからないだけであればこれで接続はできるはず…
[Next.js]"use client", "use server"キーワードって何

## use clientとは
クライアント側でJavaScriptを実行する必要があるかを示す目印のこと。

```page.js
"use client"

import { useEffect, useState } from "react"

export default function SSR(){
    const [state, setState] = useState(undefined);
    useEffect(()=>{
        setState('client loaded')
    },[])
    return (
        <>
            <div>SSR Page</div>
            <div>{state}</div>
        </>
    )
}
```
こんな感じで、useState, useEffectなどのReactのフックを使用したいとき（クライアント側で実行しなければならないものがあるとき）、つまりJavaScriptのコードを実行したいときに、最初に書いておく。

### 別ファイルの読み込み
use clientのコンポーネントからまったく関係ない別のファイルを読み込んだ場合も、クライアント側で実行される。

```page.js
"use client"

import { useEffect, useState } from "react"
import "./lib" //追記

export default function SSR(){
    const [state, setState] = useState(undefined);
    useEffect(()=>{
        setState('client loaded')
    },[])
    return (
        <>
            <div>SSR Page</div>
            <div>{state}</div>
        </>
    )
}
```
別ファイルを読み込んだ後の実行は、クライアント側かサーバー側かをNext.jsは判断ができないため、両方で実行はされる。

## use serverとは
サーバー側でJavaScriptを実行する必要があるかを示す目印のこと。
何も書いていない時はuse serverと同じ意味になる。
明示的に書くことはあまりない。（一部例外有）

## 注意
Next.jsでプロジェクトを構築する際には、**サーバー側で完結できるものはサーバー側で収めておく**のが原則。

そのため、上記のようにすべてのページにuse clientをかけると、そこに書かれているすべてがブラウザ側でレンダリングされてしまう。
画面の初期表示に時間がかかってしまうため、このやり方は非推奨。

### コンポーネントの切り分けをしよう
クライアント側で処理しないといけない部分は、別のコンポーネントを切り分けておく。

アップルーターを使用してプロジェクトを作るとき、フォルダー構造が以下のように設定。
```
親フォルダ―/
┣ components/
│　┣ClientCom.js
┣layout.js
┣lib.js
┣page.js
```

各ファイルの中身を再構成する。
```ClientCom.js
"use client"

import { useEffect, useState } from "react"

export default function SSR(){
    const [state, setState] = useState(undefined);
    useEffect(()=>{
        setState('client loaded')
    },[])
    return (
        <>
            <div>{state}</div>
        </>
    )
}
```

```page.js
import "./lib"
import ClientComp from './components/ClientComp'

export default function SSR(){

    return (
        <>
            <div>SSR Page</div>
            <ClientComp />
        </>
    )
}
```

※layout.jsとlib.jsはあまり関係ないのでここでは省略。

これで、page.jsでサーバー側で実行が必要な部分が切り出され、ClientComp.jsにクライアント側で実行が必要な部分が記載されたことになる。

なるべくコンポーネントは分けてつけると○。
【JavaScript】reverseメソッドについて

# Reverseメソッドとは
配列の要素を逆順に並び替えるメソッド。

```JavaScript:使い方
配列名.reverse()
```

配列そのものの要素が逆順になり、戻り値としても並び替え後の配列が戻される。

# 具体例
```JavaScript:例
let items = ["A", "B", "C"];
items.reverse();

console.log(items);
```
```JavaScript:実行結果
['C', 'B', 'A'];
```


# 注意点
　元々の配列を破壊することになるので、仮に他の場所で配列を参照している場合があれば影響することになる。

# reverseメソッドを使うことになった経緯
　VueでEChartsを使用して積み上げ棒グラフを描画していた。バックエンドから渡されたデータを元に、データベースで定義した表示順に積み上げるよう設定していたが、凡例が表示順で上から下に1から表示されているのに対してグラフは下から上に積みあがっていた。これを凡例の並びと合わせるべく、グラフの配列をreverseメソッドを使用して要素を逆にした（そのため凡例の表示にはsortを使って表示順を逆にする処理を追加した）。
データベース更新作業で気を付けること

## はじめに

本番環境のデータベースを更新するときは、特に注意を払って行いましょう。  
今回は特定のログをINSERTするときの手順です。  

## 手順

### 1. 手順を明確に決める
今回どのような作業をするのか、メモ書きでも良いので実行手順を明確にしておきましょう。  
順番が入れ替わったり、抜け漏れが発生しないように、手順については脳のリソースを使わなくて済むように入念に整理を。  

### 2. インスタンスなどのバックアップを取る
例えばAWSなどでサーバーを運用している場合は、インスタンスのバックアップを取得しておきましょう。  
万が一破損してしまっても、インスタンスごと復帰させることができます。  

### 3. データベースのdumpファイルを出力する
念には念を。作業する対象のデータベースのdumpも取得しておきましょう。  
こちらのdumpについては、作業終了後も一定期間保存しておくと何かの時に役立ちます。  

### 4. 環境に依存しないINSERT文を用意する
環境に依存しないとは、前提となる環境条件が一切ないことです。  
どんな状況であっても、対象のテーブルにそれさえ実行すれば完了するというSQL文を用意しましょう。  

例えば以下のような文を指します。  

``` SQL
INSERT INTO example_table (user_id, user_name, user_entry_flg, user_entry_date)
VALUES
(123, 'taro', 1, '2024-10-04 00:00:00'),
(1, 'jiro', 0, '2024-10-05 00:00:00');
```

このINSERT文には、他テーブルからSELECTしたり、別のdumpファイルを参照したりという環境依存がありません。  
要するにベタ書きをしようというわけです。  

### 5. すぐに作業を戻せるDELETE文を用意する
今回はINSERT文の話なので、すぐに状態を戻すためにはDELETE文を用います。  
こちらも環境依存の無い形で書いていきます。  

``` SQL
DELETE FROM example_table 
WHERE (user_id, user_name, user_entry_flg, user_entry_date) IN (
    (123, 'taro', 1, '2024-10-04 00:00:00'),
    (1, 'jiro', 0, '2024-10-05 00:00:00')
);
```

INSERT文をそのまま利用してDELETE文にしています。  
これにより、確実にINSERTした作業のみをロールバックすることができます。  

### 6. 作業ログを取る
最後に、実行した手順ごとに作業ログを書いておきましょう。  
何時何分になにをしたか、予定外の作業はしていないかを詳細に書きます。  
今後の作業の手助けにもなるはずです。  

## まとめ

こういった作業は非常に面倒ですが、特に慣れていなかった頃は何度もバックアップに助けられました。  
これから作業を控えている人へ参考になれば幸いです。
数弱が入茶するまでにやったこと

## 1.Atcoderを始める前の著者のスペック
所属　偏差値60程度の高専1年生
プログラミング経験　習い事でichigojam basic、独学でスクラッチやarduinoIDEをやっていた。言語はpythonの基本文法を少しやったことがある程度(if文とかwhile文書けるくらい)
数学力　県模試の偏差値で65-67が取れる程度。典型的な問題が解けるだけで、発想力がなく多分この界隈においては数弱

## 2.競プロとの出会い
3月頃高専受験が終わって高専での授業に備えてpythonの勉強をしようと思い、入門書籍で勉強を始めました。しかし、本を読んで理解するのが苦手で全く理解できずに速攻で挫折しました。
そんなときにたまたまyoutubeでテレ東bizさんの競プロに関する動画を見ました。動画を見る以前から競プロの存在は知っていましたが、頭がいい人やすごいエンジニアがやるだけのものだと思い敬遠していました。しかしこの動画を見て面白そうだと思うのと同時に、初心者でも参加でき、プログラミング入門にも向いていることを知り競プロを始めることにしました。


## 3.茶色になるまでにやったこと
入茶を目指す上で
Atcoderで茶色になるのは結構難しいです！！
Xなどで見る界隈の人は緑や水色、それ以上が多く、灰色の次の色が茶色なので簡単だと思われがちです。[しかし](https://daynghekimhoan.vn/cach-trung-bay-san-pham-kim-cuong-trong-tu-ban-hang/)、実際のレベル感は全く違います。実際レートの分布を見てみると、半分以上の人は灰色です。
スクリーンショット 2024-08-27 0.12.05.png
この分布を見てみるとそう簡単でないことがわかると思います。茶色くらいいけると思ってAtcoderに参加すると必ずやけどするので、いつかなれたらいいなくらいの心持ちの方がいいと思います。