OmniAICreator/Qiita-1.07M huggingface dataset:
Remix Blues Stackでnpm run setupが失敗する場合の対処法

Remix Blues Stackを使ってアプリを作成する場合、Prismaを活用すると思います。
その場合、必ず既存の**schema.prisma**に修正を加えたいと考えると思います。

しかし、**schema.prisma**に存在する既存のUserモデルなどにカラムを追加した後に`npm run setup`を実行すると、`The column *** does not exist in the current database.`エラーが発生する場合があります。

```shell
node ➜ /workspaces/example (main) $ npm run setup

> setup
> prisma generate && prisma migrate deploy && prisma db seed

Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma

✔ Generated Prisma Client (4.6.1 | library) to ./node_modules/@prisma/client in 155ms
You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client

import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()

Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "postgres", schema "public" at "localhost:5432"

3 migrations found in prisma/migrations


No pending migrations to apply.
Environment variables loaded from .env
Running seed command `ts-node --require tsconfig-paths/register prisma/seed.ts` ...
PrismaClientKnownRequestError: 
Invalid `prisma.user.create()` invocation in
/workspaces/example/prisma/seed.ts:17:34

  14 const hashedPassword = await bcrypt.hash("racheliscool", 10);
  15 
  16 // create an admin user
→ 17 const user = await prisma.user.create(
The column `name` does not exist in the current database.
    at RequestHandler.handleRequestError (/workspaces/example/node_modules/@prisma/client/runtime/index.js:34310:13)
    at RequestHandler.request (/workspaces/example/node_modules/@prisma/client/runtime/index.js:34293:12)
    at async PrismaClient._request (/workspaces/example/node_modules/@prisma/client/runtime/index.js:35273:16)
    at async seed (/workspaces/example/prisma/seed.ts:17:16) {
  code: 'P2022',
  clientVersion: '4.6.1',
  meta: { column: 'name' }
}

An error occurred while running the seed command:
Error: Command failed with exit code 1: ts-node --require tsconfig-paths/register prisma/seed.ts 
```

具体的にどの箇所が問題なのかを確認するために、まずは`setup`スクリプトの詳細を確認しましょう。

```shell
prisma generate && prisma migrate deploy && prisma db seed
```

そして、エラーを確認してみると次の一文が確認できます。

```shell
Error: Command failed with exit code 1: ts-node --require tsconfig-paths/register prisma/seed.ts 
```

つまり、`prisma db seed`の実行時にエラーが発生していることがわかります。
もう少し遡ってみましょう。

今度は、`prisma migrate deploy`の部分です。

```shell
3 migrations found in prisma/migrations

No pending migrations to apply.
```

はい、これが原因です。

つまり、スキーマを変更した後に新しいマイグレーションファイルを作成しないといけないにも関わらず、マイグレーションファイルが作成されていないため、データベースに新しいカラムの情報が反映されていないことが確認できます。

それでは、新しいマイグレーションファイルを作成しましょう。

```shell
npx prisma migrate dev --name add_column_name
```

**prisma/migrations/xxxx_add_column_name/migration.sql**が作成されていることを確認してみてください。

確認ができたら、再度`npm run setup`を実行してみましょう。

```shell
node ➜ /workspaces/example (main) $ npm run setup
...
Environment variables loaded from .env
Running seed command `ts-node --require tsconfig-paths/register prisma/seed.ts` ...
Database has been seeded. 🌱

🌱  The seed command has been executed.
```

`The seed command has been executed.`と表示されたら成功です。
【Rails7】link_to Prefix method: :postが効かなかった問題を解決

# バージョン
ruby 3.0.2
rails 7.0.4

# 前提
![スクリーンショット 2023-02-21 1.52.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2525864/74b8ea99-ce9b-068b-f6c4-9d78bec817fd.png)
prefixを使って画面遷移する際に、getメソッドを呼ぶことはできたがpostメソッドを呼ぶことができなかった。

GETメソッドを呼びたい場合はこれ
```ruby:erb
<%= link_to item_cart_items_path(@item.id) %>
```

問題のコード
```ruby:erb
<%= link_to item_cart_items_path(@item.id), method: :post %>
```
これでPOSTリクエストが送信されているかと思ったら送信できていなかった。

# 解決
```ruby:erb
<%= link_to item_cart_items_path(@item.id), data: { turbo_method: :post } %>
```
rails7から`method: :post`の書き方はできなくなったみたいです。
[参考](https://railsguides.jp/working_with_javascript_in_rails.html#http%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89)
【メモリリーク】reactコンポーネントでfetch中にアンマウントするとメモリリークは起こるのか？

## 結論
普通に使ってる分には起こらなさそう。

## 検証した環境
| ライブラリ・FW | バージョン |
|:-:|:-:|
|react | 18.2  |
| Next.js  | 13.14  |

## 今回のテーマ

* HTTPリクエストの結果が返ってくる前にコンポーネントをアンマウントすると、メモリリークは起こるのか調べてみた。

ちょっと仕事でこの辺りの挙動について知りたくなったので調べてみました！

### メモリリークとは
* プログラムによってメモリを確保したものの
解放されないままプログラムが終了してしまい
ヒープ領域をムダにロックしちゃってる状態を指します。

### reactで起こるメモリリーク
では`react`ではどういうケースでメモリリークが起こるんでしょうか？
[こちらの記事](https://dev.to/jeremiahjacinth13/memory-leaks-how-to-avoid-them-in-a-react-app-1g5e#:~:text=Causes%20of%20Memory%20Leaks%20in,a%20request%20to%20an%20API)によると要因は以下の３つらしいです。

* DOMイベントリスナー
* WebSocket サブスクリプション
* APIへのリクエスト

今回はAPIリクエストのレスポンスが返ってくる前にコンポーネントをアンマウントするとメモリリークが起こるのか検証していきたいと思います。
https://dev.to/jeremiahjacinth13/memory-leaks-how-to-avoid-them-in-a-react-app-1g5e#:~:text=Causes%20of%20Memory%20Leaks%20in,a%20request%20to%20an%20API

## 検証方法
こちらに２つのページを用意しました。
* 1ページ目のボタンを押してからリンクを押すと、fetch中にTestコンポーネントをアンマウントし(DOMツリーから外し)てTest2コンポーネントを表示します。

そうするとレスポンスを返す先がなくなったPromiseオブジェクトだけが残ってメモリリークが起こるはず、、、！
ということで、その時のメモリの状態をdevtoolsのパフォーマンスタブから記録して眺めていきます。

```react
// 1ページ目
const Test = () => {
  const [value, setValue] = useState(0);

  // あり得ないほどレスポンスが遅いAPIのダミー
  const neverEndingdummyRequest = () => {
    return new Promise((resolve, reject) => {
      // 10000秒後にstate更新
      setTimeout(() => {
        resolve(setValue(value + 1));
      }, 10000000);
    });
  };

  const handleValue = async () => {
    await neverEndingdummyRequest();
  };

  return (
    <>
      <p>{value}</p>
      <button onClick={handleValue}>request</button>
        <Link href="/test2">test2</Link>
    </>
  );
};
```

```react
// 2ページ目
const Test2 = () => {

  return (
    <>
      <p>test2</p>
      <Link href="/test">testへ</Link>
    </>
  );
};
```

### 何もしない場合
* まず何もしない場合のメモリです。**青い線がJSのメモリ**です。
20秒の間219MB~225MBの間で変化していますが、グラフはほぼ平坦です。
![スクリーンショット 2023-02-21 1.00.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508777/9694b1e1-5992-b86b-82b7-e9212f0b2117.png)

### リクエスト・アンマウントしまくる
* 次に40秒間リクエストとページ遷移を繰り返しまくった時のメモリです。
右肩上がりにメモリの使用量が増えてますね。
しかしメモリリークしているなら操作をやめてもグラフは減らないはずです。これではやめた後どうなっているのかわかりません。次はその辺りを検証してみましょう。

![スクリーンショット 2023-02-21 1.01.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508777/7daf9b15-9a8d-20ae-b44b-72bb0f3c7b06.png)

泥臭くリクエストとアンマウントを繰り返す図
![ezgif.com-crop.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508777/f3d65317-bda4-429d-1194-29edef70b24c.gif)

### リクエスト・アンマウントしまくった後、何もしない
* 17秒くらいまでリクエストとページ遷移を繰り返しまくった後、終わるまで放っておいた時のグラフです。
グラフを見るにメモリリークは起きてなさそうです。
![スクリーンショット 2023-02-21 1.01.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508777/2fa71161-e980-99a5-d0dc-e9be58df109c.png)

## 最後に

今回の記事での環境以外にも色々と検証してみたんですが、結局メモリリークを再現できませんでした。

ちなみにreact18.2での検証でしたが、react18以前ではメモリリークを警告するエラーが出てたそうです。
しかしこの警告もAPIについての文脈じゃなさそうなので、考慮しなくて良さそう。

https://zenn.dev/so_nishimura/articles/c4df97cd1937c2

**結論としてはあまりメモリリークを意識してreactを書く必要はなさそう**ってところですかね...
なんか釈然としないですが今回はこんなところで終わろうと思います。

お読みいただきありがとうございました！
東北大学のGPAを計算したい話

**バグ修正や表示変更を行いました (2023/04/03)**

## 東北大学はGPAを教えてくれない
これはあまりにも怠惰な春休みを過ごしていた私が少しだけ有意義にするために、簡単なchrome拡張機能を作ってリリースしようとした話です。

## 百聞は一見にしかず
### ダウンロード
どうぞ

https://github.com/hashiba-k-jp/calcGPA-tohoku

（緑色の"``Code``"と書かれたボタンを押して Download Zip を選択するとダウンロードできます。）
バグが起きた時は一度フォルダごと削除して再ダウンロードしてみてください。それでも動かない場合には教えてもらえるとありがたいです。

### インストール
適当に[「Chrome 拡張機能　自作　インストール」](https://www.google.com/search?q=chrome+%E6%8B%A1%E5%BC%B5%E6%A9%9F%E8%83%BD+%E8%87%AA%E4%BD%9C+%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)とかで検索すると出てきます。[ここ](https://www.wantanblog.com/entry/2021/02/25/233126#Google-Chrome%E3%81%A7%E3%81%AE%E6%8B%A1%E5%BC%B5%E6%A9%9F%E8%83%BD%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF)とかわかりやすそうです。



## Q.どんな感じ？
### A.こんな感じ
![表示例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569723/142f5489-b560-4aeb-a6b8-c61b11979e02.png)

下に各科目の評定が続きます。
諸般の事情により担当教員が空欄になっているなどの科目はその他としてGPAを算出しています。



## 以下余談
### 開発経緯
過去に非公式の東北大学GPA計算サイトがあったのですがどうやら閉鎖してしまったようで…[1]
あと確かそのサイトだと学務情報システムから情報をコピーしてペーストする必要があったはずなんですが、それすらも面倒なので今回作った拡張機能は画面内で完結させました。

本来ならばchromeウェブストアで公開した方が良いのでしょうが登録料に**5 USD**が必要とのことで諦めました。（ｴﾝﾔｽﾄﾞﾙﾀﾞｶ）[2]
気が向いたら登録します。

### 技術的なトピック
特に書くほどのことではないですが、基本的なjavascriptだけで動いているので情報がインターネットを通じてどこかに送信されているとかもないです。

もっと綺麗なJavaScriptを書ける人がいたら教えを乞いたいのでご連絡ください。
バグとかも教えてもらえるとありがたいです。



### 参考文献
1. https://twitter.com/kuriyan1204/status/1429411018522849280
1. https://developer.chrome.com/docs/webstore/register/
Ruby MVC ~復習 erbファイルの書き方~

<h1>・はじめに</h1>
　この記事ではRubyのVIEWの書き方、Controllerの書き方、Modelの書き方について復習がてら書いていきます。

<h1>・VIEWの書き方</h1>
　 RubyのVIEWは<b>.erb</b>に書いていきます。書き方はHTMLファイルを基本としています。
<br>
<br>
<h2>・パラメータの書き方</h2>

　コントローラーから値を持ってきたいときは`<%= @変数名 =>`を使います。これを書くと動的なVIEWを書くことができます。

　VIEWファイルで条件分岐を使いたいときは`<%= if %>`を使います。`<%= if @hello =>`とするとhelloが出力されているときのみその下の処理を出力させるようにできます。

```Ruby:erb
<% if @hello =>
    <h1>こんにちは!</h1>
<%=else %>
    <h1>こんばんは!</h1>
<% end %>
```
<br>
このとき@helloが出力されたときは「こんにちは！」が出力され、出力されなかった場合は、「こんばんは！」が出力されます。

またこの時、三項演算子を使用すれば短く書くことができます。

```Ruby:erb
<%= @hello ? "こんにちは" : "こんばんは" %>
```

　三項演算子とは、A ? B : Cという文があった場合、AがtrueならBを、AがfalseならCを出力するという条件分岐の文である。


<h2>・コメントの書き方</h2>

　コメントは`<%= begin %> ~ <% end %>`のように書きます。<b>~</b>に書いているところがコメントアウトされます。

　一行コメントは`<%# コメント %>`のように書きます。

<h2>・繰り返す処理</h2>

　コレクションの繰り返しの処理`<% @変数名.each do |ここでの名前|  %>`、`<%= ここでの名前 %>`でコレクションに入っている要素を繰り返して出力することができます。

```Ruby:erb
<ul>
<% @変数名.each do |ここでの名前| %>
    <li><%= ここでの名前 %></li>
<% end %>
</ul>
```

このように書くと、変数名のコレクションの要素をリスト形式にして繰り返して出力されます。

<h3>・データベースと連携する場合</h3>

　データベースと連携して値を出力したい場合はコレクションと同じく`<% @変数名.each do |ここでの名前|  %>`を使います。しかし、繰り返したい部分は`<%= ここでの名前.カラム名 %>`とします。

```Ruby:erb
<table>
<tr>~省略~</tr>

<% @変数名.each do |ここでの名前| %>
    <tr>
        <td><%= ここでの名前.カラム名 %></td>
    </tr>
<% end %>
</table>
```

このように記述すると表にデータベースの内容を載せることができます。

<h2>・リンクを挿入する場合</h2>

　VIEWファイルにリンクを挿入したい場合は`<%= link_to>`を使います。使い方としては、他のURLを挿入する場合は`<%= link_to 'VIEWで表示させたい名前', 'サイトのURL' %>`のようにし、自分のページに移動させたい場合は<%= link_to '表示名', '/リンク/リンク/...' %>のように表記するとリンクを挿入することができます。

```Ruby:erb
<p>
    <%= link_to 'グーグル', 'https:www.google.co.jp/' %>
</p>

<h1>
    <%= link_to '遷移！', '/home/index' %>
</h1>
```

このように書くとｐタグの方では<b>グーグル</b>という単語をクリックするとグーグルの検索ページに飛ばす文が書け、ｈ１タグの方では<b>遷移！</b>をクリックするとRubyで設定した<b>/home/index</b>というページに飛ぶようにすることができます。
Pythonで黒ひげ危機一発を再現してみた

## はじめに
### 制作の経緯
オブジェクト指向について勉強し、Pythonでなにか作ってみようと思ったので黒ひげ危機一発ゲームを再現することにした。
## 制作物
### コード

```python:Kurohige.py
import random

class Material:
    data = {"0": "a", "1": "b", "2": "c", "3": "d", "4": "e", "5": "f", "6": "g", "7": "h", "8": "i", "9": "j"}

    barrel = [     "   \o/  < Help!",
                   " ------",
                   "|      |",
                   "|      |",
                   "|      |",
                   " ------ "]
    barrel = "\n".join(barrel)

    def __init__(self):
        self.temp = list(self.data.values())
        random.shuffle(self.temp)
        self.value_shuffled = dict(zip(self.data, self.temp))


class List:
    def __init__(self):
        self.material = Material()
        self.shuffled_dict = self.material.value_shuffled

    def choose(self, a_key):
        return self.shuffled_dict.pop(a_key)


class Game:
    def __init__(self):
        self.list = List()

    def play_game(self):
        self.shuffled_dict = self.list.shuffled_dict
        self.key_list = []
        for res_key in self.shuffled_dict.keys():
            self.key_list.append(res_key)

        while len(self.shuffled_dict) > 0:
            n = input("qで終了、それ以外でPlay:")
            if n == "q":
                break
            print(self.list.material.barrel)
            response = input("{}の中から選んで入力:".format(self.key_list))
            if response in self.key_list:
                p = self.list.choose(response)
                if p == "a":
                    print("ハズレを引きました！")
                    break
                else:
                    self.key_list.remove(response)
            else:
                print("{}の中から正しく入力してください.".format(self.key_list))
        drawing = self.pop_out()

    def pop_out(self):
        self.pop = [
                            "    \ o/    ",
                            "      |     ",
                            "  \  / \   / ",
                            "    ------  ",
                            "   |      | ",
                            "   |      | ",
                            "   |      | ",
                            "    ------  "]
        pop = "\n".join(self.pop)
        print(pop)

game = Game()
game.play_game()
```

### ゲームの流れ
1. まず最初に、プレイするか中断するか聞く。中断なら5と同じ結果を表示。
2. 樽に入った人の絵が現れ、key_listに入っているキーのリストが表示される（最初は0~9の10個）
3. その中から一つ選ぶとそのキーに対応したバリューが取り出され、ハズレかどうかがチェックされる（ハズレはa）
4. ハズレじゃなかったら今回選んだものがkey_listから削除され、1に戻る。ハズレが引かれるまで1~4をループする。
5. ハズレを引くと、樽から発射された人の絵が現れる。
※キーとバリューの組み合わせは実行するたびにシャッフルされるため、どれがハズレかは特定できない。

### 作ってみた感想
- 関数の動きを勘違いしていたことが何回かあった。
- オブジェクト指向の理解がまだふんわりしている。
- 変数の名前を考えるのが地味に難しい。

## おわりに
簡単なコードだが、エラーを連発し意外と時間がかかった。また、ChatGPTを有効活用することで、勘違いや思い込みによってエラーの原因をなかなか特定できずにハマってしまうような状況をかなり減らせると感じた。
再帰問題を解く

最近出会した再帰問題について，ざっくりとしたアイデアを備忘録として残しておく．
言語はPythonを使用する．

再帰とは
--
再帰とは，手続や関数が「自分自身を呼び出すこと」．
関数の定義の中に，関数自身が登場する．
まず条件判定を行い，下記のいずれかを行う．
1. 再帰呼び出しは行わず，特定の処理を行う
2. 関数自身を呼び出す

再帰アルゴリズムの例
--
<dl>
  <dt>階乗計算</dt>
  <dd>
階乗とは「ある正の整数（N）から1までの整数の積」のこと.<br>（例）5! = 5 x 4 x 3 x 2 x 1<br>「n個の異なるものを1列に並べる場合の並べ方」を計算する場合に用いられる．
</dd>
</dl>

実際に解いてみる
--
階乗計算を，再起呼出しを使って解くとはどういうことか．
先程挙げた例題を再帰の考え方で解くと．
5! = 5 x 4!
ここで 4! = 4 x 3! であり，同様に続けて， 3! = 3 x 2!，2! = 2 x 1!，
そして最後に 1! = 1 とし，これ以上再帰は行わず，2!から5!までの答えが順に出る．

そしてこれらは次の関数f(x)で表すことが出来る．
```math
f(x) = 
\begin{cases}
 N > 0 のとき & N x f(N-1) \\
 N = 0 のとき & 1
\end{cases}
```

コードで表すと下記のような感じ．
自身の関数を呼び出すことで，繰り返し計算を行なっている．
```python:recursive.py
def kaijyo(n):
    if n == 1:
        return 1 
    else:
        return n * kaijyo(n - 1) 

print('Answer:', kaijyo(5))
```
結果は下記の通り．
```output.py
Answer: 120
```

再帰を使う利点
--
再帰呼び出しの考え方を知っていると何が良いかというと，プログラムをシンプルに記述することが出来る．
ちなみに先程の階乗計算を，再帰呼び出しを使わずループを用いて記述すると，次のようになる．
```python:non-recursive.py
n = 5
answer = 1
for i in range(n, 1, -1):
  answer *= i
print('Answer:', answer)
```
結果は下記の通り．
```output.py
Answer: 120
```

考察
---
何でもかんでもforループで力技で片付けようとするとコードが長くなってしまうことがあるが，
再帰を使うと，実際かなり面倒な問題もシンプルに解けそうだ．
代表的なものにクイックソートやハノイの塔などがあるそうで，次回はそれらの問題にも挑戦したい．
Apacheで使用する静的モジュールと動的モジュール

●Apacheで使用するモジュールには静的モジュールと動的（DSO）モジュールがある。

静的モジュールはApacheのインストール時に組み込む必要があり、Apacheの本体に組み込まれます。configure→make→make installの流れのconfigureスクリプトのオプションで指定することが出来ます。静的モジュールの利点は、Apache本体と一体となって動作するため、組み込みにかかる負荷が少ない。欠点は、静的モジュールの数を増やしすぎるとApacheが肥大化し、メモリの使用量が増えてしまう。

動的モジュールはDSO（Dynamic Shared Object）モジュールと呼ばれ。apxsコマンドでコンパイルとインストールをし、httpd.confファイルのLoadModuleディレクティブで有効、無効を設定することができます。動的モジュールの利点は有効、無効の設定が簡単、Apache本体のサイズを小さく出来るためメモリに負荷がかからない。欠点は、静的モジュールに比べて読み込む際に時間がかかるため、動作が遅くなる。
AWS Step Functionsワークショップ：学習メモ

## これは何？

[JP Contents Hub](https://aws-samples.github.io/jp-contents-hub/)に掲載されている[Step Functionsのハンズオン](https://github.com/harunobukameda/AWS-Step-Functions/blob/main/AWS%20Step%20Functions%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%83%E3%83%97.pdf)の実施メモです。

## Step Functionsとは

>AWS Step Functions はフルマネージドサービス型のサービスで、視覚的ワークフローを使用して分散アプリケーションやマイクロサービスのコンポーネントを容易にコーディネートできます。それぞれ別個の機能を実行する個々のコンポーネントからアプリケーションを構築することで、迅速にアプリケーションをスケーリングおよび変更できるようになります。Step Functions を使えば、安心してアプリケーションのコンポーネントを調整し、機能を配置できます。グラフィカルコンソールを使用して、アプリケーションのコンポーネントを一連のステップとして配置し、可視化できます。これにより、複数のステップからなるアプリケーションをシンプルに構築および実行できるようになります。Step Functions では、各ステップが自動的にトリガーおよび追跡され、エラーが発生した場合は再試行されるため、アプリケーションが意図したとおりに整然と実行されます。また、各ステップの状態が記録されるため、問題が発生した場合は、問題を簡単に診断およびデバッグできます。コードを記述することなくステップを変更および追加できるため、アプリケーションを簡単に発展させ、短期間でイノベーションを実現できます。
https://aws.amazon.com/jp/step-functions/faqs/

端的にいうと、マイクロサービスなどの細分化した機能をGUIを使用して連結させ、サービスの設計ができるマネージドサービスです。AWS LambdaやAWS ECSなどを組み合わせることができます。

## なぜStep Functionsを使うのか

- 短期間に簡単にアプリケーションを構築することができます。GUI上にLambdaをドラッグ&ドロップするだけでLambdaを実行できたり、実行順を変更するなどが可能です。
- 分散している機能をステートマシンにまとめることができ、管理が楽になります。
- エラー時の再実行、例外処理など機能として提供されており、簡単に組み込むことができます。
- サービスの実行順や実行状態をGUI上で可視化することができます。

## ユースケース

https://www.slideshare.net/AmazonWebServicesJapan/20190522-aws-black-belt-online-seminar-aws-step-functions/52

## ハンズオンのゴール

1. ステートマシンを作成し、実行する方法を理解する
2. ステートマシンでAWS Lambda関数を実行する方法を理解する
3. ステートマシンのエラーハンドリングの設定について理解する
4. ステートマシンのMap機能を理解する
5. 他AWSサービスをトリガーとして、ステートマシンを実行する方法を理解する

## アジェンダ

- [Hello World]の作成　
  - Lambdaを使わずStep Functionsで Hello Worldしてみる
- Lambdaの起動
  - Step FunctionsからLambda関数を起動するステートマシンの作成
- Catchによるエラー処理
  - Lambda関数（※）でエラーイベントを発生させ、ステートマシンでハンドリングしてみる
  - （※）「step-functions-error」という設計図で公開
- Map機能にするLambda関数の複数回実行
  - Map機能でLambdaを複数回実行し、実行結果を結合して出力する

## ハンズオンの感想

ハンズオンでは単純なステートマシンしか作成しませんでしたが、
アプリケーションの規模が大きくなり、Lambdaやその他サービスなど関連するコンポーネントが多くなるほど、
このサービスの真価が発揮されると感じました。
ステートマシンのフローはJsonで管理できるため、IaCも可能なのも良いと思います。
【Git】GitHub CLIをコマンド補完する方法

## Homebrewでインストールしている場合
GitHub CLIをHomebrewでインストールしている場合には以下のページの手順に沿って設定を行います。

https://docs.brew.sh/Shell-Completion

zshの場合には以下を`~/.zshrc`に記述します。

```~/.zshrc
if type brew &>/dev/null
then
  FPATH="$(brew --prefix)/share/zsh/site-functions:${FPATH}"

  autoload -Uz compinit
  compinit
fi
```

これでコマンドの補完ができるようになります。

`gh `を入力してタブを入力すると以下のように表示されます。

```zsh:zsh
$ gh
alias       -- Create command shortcuts
api         -- Make an authenticated GitHub API request
auth        -- Authenticate gh and git with GitHub
browse      -- Open the repository in the browser
co          -- Alias for pr checkout
codespace   -- Connect to and manage codespaces
completion  -- Generate shell completion scripts
config      -- Manage configuration for gh
extension   -- Manage gh extensions
gist        -- Manage gists
gpg-key     -- Manage GPG keys
help        -- Help about any command
issue       -- Manage issues
label       -- Manage labels
pr          -- Manage pull requests
release     -- Manage releases
repo        -- Manage repositories
run         -- View details about workflow runs
search      -- Search for repositories, issues, and pull requests
secret      -- Manage GitHub secrets
ssh-key     -- Manage SSH keys
status      -- Print information about relevant issues, pull requests, and notifications across
workflow    -- View details about GitHub Actions workflows
```

## Bashの場合
bashの場合にはbash-completionをイントールする必要があります。

https://github.com/scop/bash-completion

bash-completionのインストール後に以下を`~/.bash_profile`または`~/.bashrc`に記述します。

```~/.bashrc
eval "$(gh completion -s bash)"
```

`gh `を入力してタブを入力すると以下のように表示されます。

```bash:bash
$ gh 
alias       (Create command shortcuts)
api         (Make an authenticated GitHub API request)
auth        (Authenticate gh and git with GitHub)
browse      (Open the repository in the browser)
co          (Alias for pr checkout)
codespace   (Connect to and manage codespaces)
completion  (Generate shell completion scripts)
config      (Manage configuration for gh)
extension   (Manage gh extensions)
gist        (Manage gists)
gpg-key     (Manage GPG keys)
help        (Help about any command)
issue       (Manage issues)
label       (Manage labels)
pr          (Manage pull requests)
release     (Manage releases)
repo        (Manage repositories)
run         (View details about workflow runs)
search      (Search for repositories, issues, and pull requests)
secret      (Manage GitHub secrets)
ssh-key     (Manage SSH keys)
status      (Print information about relevant issues, pull requests, and notifications across repositories)
workflow    (View details about GitHub Actions workflows)
```
AWSに構築したAPI実行環境にロードバランサーとColudFrontを設定してみた

[こちらの記事](https://qiita.com/tToyoshima/items/c2700dc892930a90b407)の続きです。

## やりたいこと
* フロントエンドからのリクエストをロードバランサー経由で処理する
* CloudFrontを設定し、ロードバランサーにHTTPS接続する

## 構成のおさらい
### EC2
Webアプリのバックエンドを実行します。
今回はJavaのjarファイルを常時実行し、フロント側から実行されたAPIを処理します。
RDSに構築されたデータベースとデータをやりとりします。
SpringBootで実装しています。
ロードバランサーからHTTPリクエストを処理します。

### RDS
Webアプリのデータベースを担います。
今回はPostgreSQLです。

### S3
Webアプリのフロントエンドを配置します。
静的ウェブサイトとして設定し、エンドポイントにアクセスすることでフロント側の画面を表示します。
今回はVue.jsを用いて画面を作成します。

## ロードバランサー
### ターゲットグループの作成
ロードバランサーがリクエストをルーティングするためのターゲットグループを作成します。
EC2 > ターゲットグループ と進み、ターゲットグループの作成を選択します。
#### ターゲットタイプの選択
今回はEC2がターゲットとなるため、インスタンスを選択します。
#### プロトコル、ポート
ロードバランサー-EC2間はHTTP接続としたいため、HTTP:80としました。
#### VPC
EC2が属しているVPCを選択します。
#### ヘルスチェック
APIにヘルスチェック用URLがある場合は設定します。
#### ターゲットの登録
使用可能なインスタンスでEC2を選択します。（冗長化したい場合は2つ設定）
バックエンドのポートを設定します。（今回は8080を設定）
設定後、「保留中として以下を含める」をクリックします。
ターゲットに追加されたら、ターゲットグループの作成をクリックします。

ターゲットグループが作成されました。

### ロードバランサーの作成
EC2 > ターゲットグループ と進み、ロードバランサーの作成をします。
今回は、HTTPおよびHTTPSトラフィックを処理したいため、`Application Load Balancer`を選択します。

#### VPC
EC2の属するVPCを選択します。

#### マッピング
トラフィックをルーティングしたいサブネットを選択します。ここではEC2のサブネットを選びます。
少なくとも2つのアベイラビリティーゾーンと、ゾーンごとに1つのサブネットを選択します。

#### リスナーとルーディング
先ほど作成した、ターゲットグループを選択します。
ここでは、フロントエンドからはHTTPS接続としたいので、HTTPS:443を設定します。

#### SSL/TLS証明書
リスナーのプロトコルをHTTPSとしたため、証明書の設定が必要です。
ACMにて作成/アップロートした証明書を選択できます。
（今回はテスト環境のため、自己署名証明書をアップロードし、選択しました）

ロードバランサーを作成をクリックします。

### フロントエンドのアクセス先
フロントエンドからの向き先を、`EC2エンドポイント`→`ロードバランサーのDNS`に変更することで、
ロードバランサー経由でバックエンドにリクエストし、APIを実行できます。

## CloudFront
ロードバランサーはHTTPS接続を受けているため、フロントエンドもHTTPSにてアクセスする必要があります。
S3の静的ウェブサイトホスティングはHTTPでのホスティングなため、CloudFrontを用いることとしました。

### CloudFrontの作成
CloudFrontの画面より、ディストリビューションを作成をクリックします。

#### オリジンドメイン
S3ウェブサイトエンドポイントを設定します。
静的ウェブサイトホスティングのエンドポイントです。

#### ビューワー
`Redirect HTTP to HTTPS`に設定しました。

#### 許可されたHTTPメソッド
許可するHTTPメソッドを選択します。

#### 料金クラス
アジアを含む選択肢を選択しました。

上記以外はデフォルトとしました。
ディストリビューションを作成をクリックして作成します。

作成されたディストリビューションのディストリビューションドメイン名にアクセスすることで、フロントエンドを表示できました。
今回はディストリビューションドメイン名を使いましたが、Route53等を設定することで独自ドメインにできるようです。

以上で、（一応）ロードバランサーとColudFrontを設定できました。
reactでimgタグを使用して画像を表示する方法について深掘りする

# はじめに
reactでimgタグを使用した画像の表示について
毎回ミスしてしまうのでまとめてみました。


# やりがちなダメな例
表示したい画像を以下のように配置しているとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2916357/0d92720d-d488-242f-de45-ae87d400ecd7.png)

Appコンポーネントの中で画像を表示させたいのでApp.tsxに以下のように記述しました。
```react:App.tsx
import React from 'react';

function App() {
  return (
    <div
     className="App">
        <img src='../images/koike.png' className="App-logo" alt="logo" />
    </div>
  );
}

export default App;
```
imgタグのsrc属性に、App.tsxファイルからの相対パスを記述しています。
一見これで良さそうですがこれじゃ画像は表示されません。
reactはbuildされると全てのコンポーネントが1つのJSファイルに集約されます。
その状態で../images/koike.png この相対パスを辿っても画像はないので表示されません。


じゃあどうすればいいのか？

# 上手くいく例①
画像の配置はそのままで
画像ファイルをソースコード内でimportする

```react:App.tsx
import React from 'react';
import koike from '../images/koike.png'

function App() {
  return (
    <div
     className="App">
        <img src={koike} className="App-logo" alt="logo" />
    </div>
  );
}

```
この方法だとうまく画像が表示されます。

# 上手くいく例②
画像を配置する場所を以下のようにpublicフォルダ内に変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2916357/8230cea1-34cc-d6f7-745a-f0583b510efb.png)

imgタグのsrc属性にはpublicフォルダにあるindex.htmlからのパスを入力します。

```react:App.tsx
import React from 'react';

function App() {
  return (
    <div
     className="App">
        <img src="./images/koike.png" className="App-logo" alt="logo" />
    </div>
  );
}
```


# どっちで実装したほうがいいの？
それぞれメリデメがあるみたいです。

①の場合
メリット：
ソースコードに画像ファイルが直接埋め込まれるためコードの管理が楽になる。

デメリット：
画像ファイルがimportされるため、画像ファイル自体がbuildされたJSファイルに取り込まれ
サイズが大きくなり、ページの読み込みに時間が掛かる。
画像ファイルがJSファイルに取り込まれるため、ブラウザ側でのキャッシュが期待できない。


②の場合
メリット：
画像ファイルがpublicフォルダに配置されているため
build時にJSファイル内に取り込まれることなく
画像ファイルのサイズが大きい場合でもページ自体の読み込み速度が遅くなることはない。
ブラウザでのキャッシュが期待できるため、2回目以降の表示の際に画像を読み込む必要がなくなる。

デメリット：
build時に画像が圧縮されないので初回表示の際は①に比べて時間がかかる。



個人的にはブラウザでのキャッシュが期待できる②の方法がいいのかなと思いました。

# まとめ
reactでimgタグを使用して画像を表示する際は
publicフォルダに画像を配置させて生きていきたいと思います。
Bunとnodejs-polarsでデータ分析（前半）

# 1. はじめに
Bunとnodejs-polarsでデータ加工＋αが高速でできる！

# 2.nodejs-polarsについて
* [polars](https://github.com/pola-rs/nodejs-polars)のサイトを見てると、nodejsでも実行できるんだーエッ！となり、データ加工のみならpythonいらなくなるじゃんと思ったのをきっかけに情報収集を開始。
* この方↓のtweetを見かけて、さらにBunという存在を知る。確かに突然javascriptですごいスピードのデータ加工ができるようになる可能性。mapやreduceでも何かできるのではと思ってたけど、慣れてる方法でできる（しかも速い）ならありがたい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/9232c6fa-51ec-6cb0-cfc8-dcdf1222c2da.png)

# 3.Bunについて
[Bun](https://bun.sh/)というのは初めて知ったけど、node.jsやdenoよりも速いというのを売りにして最近出たものの様子。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/6f379171-4a10-6fc0-0214-3ffaf2129d43.png)



# 4. やってみた。
github codespaceで。もうローカルにエディタもいらないな。。

## 4.1 bunを入れる。
[公式サイト](https://bun.sh/)の案内どおり(変なキャラだなあ)

```bash
curl -fsSL https://bun.sh/install | bash
bun http.js
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/bb50e7ba-1d8f-63e7-8915-5a495ca59fb8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/70c699dd-3f4b-883a-50a7-1ee8a2f6d264.png)
よし。

## 4.2 noejs-polarsを入れる
* [nodejs-polars](https://www.npmjs.com/package/nodejs-polars)を入れる。

```bash 
bun add nodejs-polars
bun add bun-types //autocomplete用
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/68a87cf3-2913-efa8-577e-0126a3951d9c.png)


nodejs-polarsの公式に乗っていたものを借りる。

```javascript
// http.js
//import Database from "bun:sqlite"; //本当は使いたかったが適当なsqliteデータがないので断ね
//import pl from "nodejs-polars";
const pl = require("nodejs-polars");
const fooSeries = pl.Series("foo", [1, 2, 3]);
console.log(fooSeries);
const dispval = JSON.stringify(fooSeries.toArray());

const df = pl.DataFrame({
  A: [1, 2, 3, 4, 5],
  fruits: ["banana", "banana", "apple", "apple", "banana"],
  B: [5, 4, 3, 2, 1],
  cars: ["beetle", "audi", "beetle", "beetle", "beetle"],
});

console.log(df);

export default {
  port: 3000,
  fetch(request) {
    return new Response(dispval);
  },
};

```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/9e57d8a1-b9ce-c5d8-6e46-686cbb6a104b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/72cb430a-fa20-3456-33ed-d92e531131da.png)


確かに動く！

cytoscapde.jsと組わせれば、ネットワーク分析＋可視化もサーバサイドのjavsscriptでまかなえるのでは？と試作中。
Python全く分からん自分のアウトプット　その2

2日目：引き続きProgateのPythonコース2を進めていく。複数データ管理や繰り返し処理のプログラミング必須知識らしい。


◎以下調べたこと、疑問に思ったこととかのメモ◎

リスト・・・[要素1,要素2,要素3]←『，(カンマ)』で区切る。これで複数の文字列や複数の数値を一つのものとして管理できる。文字列は『””』を忘れずにつける。数値は数字のみ。

リストを変数に代入・・・変数名=[要素1,要素2,要素3]、リストの変数名は基本的に複数形。

インデックス番号・・・要素には数字が割り振られている。「0」から始まる。

リストの要素更新・・・「リスト[インデックス番号] = 値」でリストの指定したインデックス番号が更新される。

リスト.append(値)・・・リストに新しく要素を追加できる。


ｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰ

今日は一旦ここまでとする。思ったよりスムーズに解けた気がするけど集中力が切れた。
20分集中して10分休憩を繰り返して集中し続ける勉強法があるだとか、明日試してみる。
IPsec VPNサーバーにWindows 10で接続する

# IPsec VPNサーバーにWindows 10で接続する

5年ぶりくらいに、業務でVPN接続をすることになり、つまづきまくりました。

何番煎じかわかりませんが、備忘録として手順を残します！

# VPN 接続の作成方法

`タスクバー` の `通知領域` にある `ネットワーク` を右クリックし、`ネットワークとインターネットの設定を開く` をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/e3952f16-d5a0-5639-a52d-397a3adb96aa.png)

現れたウィンドウの中にある `ネットワークと共有センター` をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/fd82f5e3-3ce1-3e08-f793-56acbef510e8.png)

さらに現れた別のウィンドウの中にある `新しい接続またはネットワークのセットアップ` をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/5ae067af-0d4e-1689-f187-642c87cde995.png)

`職場に接続します` を選択し、 `次へ` をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/2aa83844-d6e3-8a88-7fc9-0f956591e58d.png)

`既存の接続を仕様しますか？` と聞かれたら、 `いいえ、新しい接続を作成します` を選択し、 `次へ` をクリックします。

`インターネット接続 (VPN) を使用します` をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/cc2f4591-1115-b23b-6048-0150e21ee0e2.png)

`インターネットアドレス` 欄に、VPNサーバーのグローバルIPアドレスを入力します。

`接続先の名前` 欄は、お好きな文字列を入力します。
デフォルトで `VPN 接続` と入力済みなので、今回は説明を簡単にするため、このままとします。

入力ができたら、 `作成` をクリックします。すると、ウィンドウが消えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/1090a8b5-833a-2f7e-b0de-72b3af0f6f3f.png)

`ネットワークと共有センター` のウィンドウに戻って、左側の `アダプターの設定の変更` をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/d753bea4-7a87-3107-5518-6b4d1203ffa2.png)

以下のような画面になるので、さきほど作成した `VPN 接続` を右クリックし、プロパティをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/740199ea-866b-2424-7390-ee94340b8a05.png)

`セキュリティ` タブをクリックします。

`VPN の種類` 欄を `IPsec を利用したレイヤー 2 トンネリング プロトコル (L2TP/IPSec)` に変更します。

`次のプロトコルを許可する` をクリックしてから、以下2点を有効にしてください。

- `チャレンジ ハンドシェイク認証プロトコル (CHAP)`
- `Microsoft CHAP Version 2 (MS-CHAP v2)`

入力ができたら、 `詳細設定` をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/c6327764-7406-6bbc-c039-4fb83ce4d49f.png)

`認証に事前共有キーを使う` をクリックしてから、 `キー` 欄に事前共有キーを入力します。

入力ができたら、 `OK` をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/d178b0e7-e791-3cc4-2ef0-a8a13107d500.png)

さらに `OK` をクリックして、プロパティのウィンドウを閉じます。

# VPN 接続の接続方法

`タスクバー` の `通知領域` にある `ネットワーク` をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/e3952f16-d5a0-5639-a52d-397a3adb96aa.png)

さきほど作成した `VPN 接続` があるので、クリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/1a01ac67-1735-cc1e-35b0-fe5b1aa8e23d.png)

`接続` ボタンが現れるので、クリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/de01579c-04b5-eae1-b395-2ed85311945c.png)

`サインイン` というダイアログが表示されたら、VPNの `ユーザー名` と `パスワード` を入力し、 `OK` をクリックします。

これで、接続完了です！

# さいごに

本記事作成にあたり、以下のサイトを参考にさせていただきました。ありがとうございました。

- https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients.md
現場で役立つAndroidStudio Tips(随時更新)


## エラーの詳細が良く分からない、常に詳しくログを吐いてほしい

Macの場合
- Android Studio > Preferences > Build, Execution, Deployment > Compiler

Windowsの場合
- File > Settings > Build, Execution, Deployment > Compiler

で、`Command-line Options`に
`--stacktrace --info --scan` を入力しApply, OK．

![スクリーンショット 2023-02-20 23.14.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351850/21422eea-6d9c-f8a5-6a02-50d52d2b5096.png)

## Gradleのバージョンってどこで確認できるの？

File > ProjectStructure > Project 

![スクリーンショット 2023-02-21 23.57.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351850/8b32601f-ecae-ed5f-d73a-a46b9b1d954e.png)


## なんかAndroidStudioがもっさりしてきた

キャッシュを削除して再起動！

`File > Invalidate Caches > Invalidate and Restart`


## ファイルが多すぎて今触ってるファイルの場所が分からなくなった

画面右上のこいつを押す（Select Opened File）
![スクリーンショット 2023-02-22 0.00.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351850/26a3f7b3-5a5d-6bb4-9f33-dd8016e68283.png)
JKです。atcoder緑です。

# 情報系高専生がatcoderで入緑する 

情報系(J)高専生(K)なので嘘じゃないです。KujiraBoxといいます。約1年前からatcoderを初めて、ようやく入緑できたので、やってきたこととかを書きます。
[KujiraBoxのプロフィール](https://atcoder.jp/users/KujiraBox)

---
### 最初のスペック
- パソコンを触り始めてから2年目(それまではファイル操作も出来なかった)
- javascriptを学び、if,for,関数が書ける
- 学校の授業でクイックソートくらいは習った
- 数学は得意な方

一応情報系の学生なので文系大学卒の新卒プログラマが入社して1年経ったくらいの知識はあったと思います。

---
### 苦労したこと

- **ぼっち**

    自分の周りで競技プログラミングをしている人がいなかったので**twitter**の界隈に入るまでは本当に修行でした。
特別な知識がなくて緑以上に行きたい人は必ず**twitter**をやるべきです。(本当に)

- **環境構築**
  
    自分は**windows+WSL2+Ubuntu+gcc**のC++でatcoderをしていて、恐らくこの環境がwindowsでC++を触るのには最適だと思っています。
    というのもwindowsでC++を触るなら
    - Visual StudioのVisual C++
    - windowsでネイティブに動くgccをインストールする
    
    という選択肢もあるのですが、

    VisualStudioのVisual C++はatcoderで使われているgccと一部勝手が違いますし、ネイティブ(wslを使わない)で動くgccはインストールが難しいしバグっぽい挙動があるし何より日本語が文字規格のズレで文字化けするのでおすすめしません。

    これから始める人向けなんですがWSLがmicrosoft storeからインストールできるようになったのはつい最近(2023/2/20現在)で、まだまだ昔のインストール方法(黒い画面を叩く方法)を推すサイトが上にサジェストされるので、その情報は無視したほうが賢明です。

---
### やってきたこと
暇なときにatcoder problemsで適当な問題を解いたり、コンテスト中に解けなかった問題をDまで埋めたりしてました。

あと鉄則本をやりました。まだ解き切ってませんけど、、

これは**やらなかったこと**ですが

自分と同じ時期に始めた人や同い年の人にレートで負けても、自分に才能がないと思わないことです。
この界隈には学歴モンスターが潜んでいることが多々あるので、プログラミングを始めた時期が全然違ったり、数学の習熟度が桁違いだったり、頭がパズルマシーンみたいな人にたまに出会います。なので比較はあまり意味を成しません。。

---
### これまで使ったアルゴリズム・データ構造

- EDPCの序盤にあるDP
- DFS
- BFS
- 累積和
- 二分探索
- UnionFind
- map
- set・multiset
- queue・stack
- etc


上の知識は百必要なんですが、それ以外にも**エラトステネスの篩**や**高速な素数判定法**,**gcd**,**lcm**,**ルジャンドルの定理**など、数学に寄った知識も必要とされます。

個人的な感覚ですが、最初は問題をたくさん解いて、解説を読みながらアルゴリズムについての浅い理解を広く持ち、コンテスト中にアルゴリズムの存在に気付くことが大切ではないかと思います。

[E8さんが書いた競プロの専門書 鉄則本 ￥3718](https://www.amazon.co.jp/%E7%AB%B6%E6%8A%80%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AE%E9%89%84%E5%89%87-%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E5%8A%9B%E3%81%A8%E6%80%9D%E8%80%83%E5%8A%9B%E3%82%92%E9%AB%98%E3%82%81%E3%82%8B77%E3%81%AE%E6%8A%80%E8%A1%93-Compass-Books%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E7%B1%B3%E7%94%B0/dp/483997750X)

必要な知識が全て網羅されていて素晴らしいです。考察に詰まったときはこの本を俯瞰して当てはまるものがないか探したりもします。
    
---
### 最後に

テストが終わったので入水したい。
Javascriptで複数の文字を削除する

正規表現を用いて、複数の文字を削除するやり方を学んだのでメモ書き。

<b>想定問題：</b>与えられた文字列から母音を削除して出力する。
Ex. ohayougozaimasu => hygzms


<h1>使ったもの</h1>
replace

<h1>コード</h1>

```
const greeting = "ohayougozaimasu";
const goodmorning = greeting.replace(/[aiueo]/gi, '');
console.log(goodmorning);
//hygzms
```

<h1>replaceメソッドについて</h1>
replaceメソッドは文字列を置換するために用いられる。
使い方は以下の通り。

```
文字列.replace(置換したい文字列, 置換する文字列)
```

引数には文字列または正規表現を指定する。
注意点としては、最初に見つかった指定文字列（文字）だけを置換する点。置換対象が2箇所以上ある場合は、最初のものだけが置換され、残りの箇所は置換されない。
もし、指定した文字列（文字）をすべて置換したい場合は、「gオプション」を指定する。gオプションを用いる場合の記述は、置換したい文字列を「/」でくくり、その後にgをつける。

```
文字列.replace(/置換したい文字列/g, 置換する文字列)
```

さらに、大文字と小文字を無視して置換したい場合は、「giオプション」を用いる。

```
文字列.replace(/置換したい文字列/gi, 置換する文字列)
```



<h2>参考</h2>

https://qiita.com/may88seiji/items/3c8a6b191278e534c9c2

https://1-notes.com/javascript-multiple-specifications-of-replace/
Powerlineの表示がずれた、シェルスクリプトで書こう。

Powerline風のプロンプトを作りました。とりあえずインストールは以下に書いてあります：

https://github.com/alpaca-honke/prowpt/blob/main/README-ja.md

まだまだ勉強中ですから、非効率な記述とかあるんじゃないかと思うので、コメントいただけるとありがたいです。
また、いいね＆ストックいただけると励みになります！

# 動機
僕は以前、[Powerline-shell](https://github.com/b-ryan/powerline-shell)を使っていました。

しかし、Powerline系のプロンプトだと、Gitリポジトリでのステータス表示アイコンがNerdFontsだかPowerlineFontsの全角っぽいグリフなんです。
NerdFontsのグリフは、UnicodeのPrivate領域を使用していて、全角半角がしっかりと区別されないんですね。

すると問題が発生したんです。

**表示がずれる。**

僕のターミナルエミュレータ（うち、特にCrostiniのやつ）では、このグリフ、全角幅で表示されるのに半角幅と認識されて、入力位置が一文字ずれたりするんです。

じゃあ、Gitステータス表示をかえればいいじゃんか。とは思ったんだけど...よくわかんない。
公式のカスタマイズドキュメント読んでも、よくわかりませんでした。僕の読解力がないのかな。

そうなったらたどり着くのは一箇所です。 **自分で作ったる**

# 方針
まず、PowerlineやらPowerline-shellのカスタマイズがよくわからなかった原因として、コード群が複雑なところです。
そして、pipでインストールするPythonスクリプトなので、余計わからん。（個人の感想です）

そこで、以下の方針を立てました。

- できるだけ簡潔にする
- 比較的カスタマイズ（特に文字と色周り）をしやすくする
- シェルスクリプトで書く
- Gitステータス表示にはgit-prompt.shを使う（半角記号で表してくれるため）

シェルスクリプトだと多少速度は犠牲になるかもですが、もともとがPythonだったので大した問題はないですね。

# 命名
prow（船の舳先）とpromptをかけ合わせて、Prowptとしました。この名前、完成前まで何回も変更してたどり着いたんですよ。まあだからといって完璧な名前でもないと思ってる。ネーミングセンスがほしい。

# 設計
大まか、というか雑に設計、というかコードの方針を立てていきます。

- カスタマイズしたい項目（各セグメント（Powerlineにおける、各項目のブロックのこと）の内容や色）はすべて個別の変数に保存することで、外部スクリプト（ユーザ設定で、変数定義が含まれる）を読み込むことでカスタマイズできるようにする
- 可読性・メンテナンスの観点から、各セグメントそれぞれに表示用の関数を作る
- 色に関しては、ANSIで定義されている256色を使えるように、256色表示のためのANSIエスケープシーケンスを格納した関数を用意する（説明下手。実際のコード内では```prowpt_ansi_color```という関数になってます。見ればわかると思います。）
- 全体において、BashとZsh両方に対応できるようにする。BashとZshで異なる項目は、条件分岐を行うか、別スクリプトを使用する。

# 実装
以下のような構造で実装しました。```->```はsourceでの読み込みを表します。
```
Bash -> prowpt.bash ──────┐
       各シェル固有の設定    │    メインのコード        ユーザ設定
Zsh -> prowpt.plugin.zsh ─┴─> prowpt-core.sh -> ~/.config/prowpt/config.sh
```
（Unicode罫線素片って便利だねこれ。）

詳しいコードはリポジトリをご覧ください。

https://github.com/alpaca-honke/prowpt

## 簡単な解説

### prowpt.bash, prowpt.plugin.zsh
各シェル固有の設定を行っています。
各シェルによる挙動の違いはこの記事を参考にしてください。

https://qiita.com/alpaca-honke/items/f6be3e92882cba34cfc6

例えば、プロンプト内でのエスケープ文字とか。Bashだと```\u```なのがZshだと```%*```になったりするからね。
それ以外は基本的に```prowpt-core.sh```内で条件分岐してます。

最後に、```$PS1```なり```$PROMPT```なりに、各セグメントを格納しています。その際、プロンプト表示前に再読込を行い、プロンプトを最新の状態に保っています。

### prowpt-core.sh
1. 各種変数定義
1. ユーザ設定の読み込み
1. ```prowpt_init``` : プロンプト表示前に実行するコマンド群
1. ```prowpt_ansi_color``` : ANSI256色を表示するのを完結にするための関数
1. それ以下は各セグメントの表示内容

※各セグメントの末尾にはセグメントデリミタ（三角形などの区切り文字）がありますが、そこの背景色は次のセグメントの背景色にしなきゃいけませんでしたので、表示順を変えるだけじゃ不自然になってしまいます。どうにかここを簡単にしたい。

### git-prompt.sh
これは単なる[https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh](https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh)のコピーです。

# 以上！
わからないなりに頑張って調べながら作ってみました。満足しています。

唯一、不足していると思った点があります。ターミナルエミュレータの幅が足りない際や、zsh-autosuggestionによるサジェストの表示時、tab補完時などに、表示が崩れてしまう点です。

解決方法を考えたり調べたりしてみたんんですが、よくわかりませんでした。もしご存知の方いらっしゃいましたらお知らせいただきたいです...！
Leetcode 35. Search Insert Position

https://leetcode.com/problems/search-insert-position/description/

## アプローチ
### 二分探索

```java
class Solution {
    public int searchInsert(int[] nums, int target) {
        if(nums[nums.length-1]< target){
            return nums.length;
        }
        int low = 0;
        int high = nums.length - 1;
        int result = 0;
        while (low <= high) {
            int mid = (low + high) / 2;
            if (nums[mid] == target) {
                result = mid;
                break;
            }
            if (nums[mid] < target) {
                low = mid + 1;

            } else {
                high = mid - 1;
                result = mid;               
            }

        }
        return result;
    }
}
```
プロになるためのWeb技術入門 を読んで

学習の目的で[プロになるためのWeb技術入門](https://www.amazon.co.jp/%E3%80%8C%E3%83%97%E3%83%AD%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AEWeb%E6%8A%80%E8%A1%93%E5%85%A5%E9%96%80%E3%80%8D-%E2%80%95%E2%80%95%E3%81%AA%E3%81%9C%E3%80%81%E3%81%82%E3%81%AA%E3%81%9F%E3%81%AFWeb%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%82%92%E9%96%8B%E7%99%BA%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%E3%81%AE%E3%81%8B-%E5%B0%8F%E6%A3%AE-%E8%A3%95%E4%BB%8B/dp/4774142352/ref=sr_1_1?crid=29TBO7ITNA4PY&keywords=%E3%83%97%E3%83%AD%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AEweb%E6%8A%80%E8%A1%93%E5%85%A5%E9%96%80&qid=1676288834&sprefix=%E3%83%97%E3%83%AD%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%2Caps%2C199&sr=8-1)を読んで学習した内容の中で、いくつかの単語について自分の言葉で説明をしてみるための記事となります。
覚えやすいように概要レベルで簡単に一言、二言で説明をしていきたいと思います。


* ステートフル：状態を維持する
* ステートレス：状態を維持しない
* リクエスト：クライアントからサーバに対する要求
* レスポンス：サーバからクライアントに対する応答
* クッキー：クライアント、サーバ間で情報を保持する仕組み
必要に応じてサーバがクライアントからクッキーを取得することでクライアントの状態を確認する
* プロトコル：コンピュータ、ネットワークで通信を行うための規約、手順
* ポート番号：TCP/IPで通信を行う際に用いられる0~65535までの番号
HTTPプロトコル：80番、等あらかじめ決められた番号もある（ウェル・ノウン・ポート）
【AWS】AWS Organizationsの理解

# はじめに
どうも、道産子エンジニアのkitonです。
AWS SAAの更新期限が迫っていて、更新せずに上位資格（SAP）を取ることに決めました！
試験勉強していく過程で、
**「全然理解していないサービスがあるじゃないか！！」**
と絶望したので、一旦知識整理してきます。
今回はAWS Organizationsについてです。

# 難易度（個人的感想）
★★★★☆
### Why??
- 個人開発者としては、実際に手を動かして網羅的に理解するには結構しんどい。
    - 組織の分析経験、一括請求の確認など。。
- ポリシーの許可・拒否設定を理解する上で、IAMの知識が必要。
    - 特にactionの理解
- 実務で使うにあたっては、企業毎の組織分析、請求管理、アクセスポリシーの設計スキルが必要。

# AWS Organizations
- 複数のAWSアカウントを一元管理
    - グループ化して、ポリシーを適用し利用サービスを制限することが可能。
- AWSアカウント新規作成の自動化
    - AWSコンソール、SDK、CLIでアカウントを新規作成可能。
    - CloudTrailでアカウント作成の操作を追跡可能。
- 請求の簡素化
    - 複数のAWSアカウントへの請求を一括請求にできる。

すべての AWS 商用リージョン、AWS GovCloud (米国) リージョンおよび中国リージョンで利用可能。
グローバルにアクセス可能（組織を作成するときにリージョン指定は不要ということ。ただし、中国を除く）
**管理アカウントになるAWSアカウントは変更できないので、管理アカウントは慎重に選択すること！！**

## イメージ図
![quiita_article (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1225450/588a2e39-b931-c583-525e-bb04b6ca481b.jpeg)

## 主な構成要素
- AWSアカウント
- マスターアカウント
- メンバーアカウント（↑ではアカウントを指します）
- 組織単位（OU）
- サービス管理ポリシー(SCP)

# 特徴
## 機能セット
AWS Organizationsを始めるにあたって、２つの機能セットを選ぶ必要がある。
**下記は「マスターアカウントにしたいAWSアカウントで操作すること！！」**
- 一括請求を行うだけの場合: **Consolidated Billing Only**
- 複数のAWSアカウントをまとめたい時: **All Feature**
※以前から一括請求を利用していた場合は、後からAll Featureを有効にすることができる。

※BlackBelt資料から参照
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1225450/890247db-08ee-a527-ddae-9acfaf0814b7.png)

## AWSアカウント
### 追加方法
- 新規アカウントを作成して組織内に追加する
    - アカウント名、メールアドレス、IAMロール名を指定する。
    ※ロール名はマスターアカウントの管理を考えると統一するべきである。
    - 初回ログイン方法
        - ルートアカウントのパスワードリセット
        - スイッチロール
        - AWS SSOなどでフェデレーションログイン
    ※招待した利用者が複数の認証情報を覚えずに使える方法で管理するのがおすすめ。
- 既存のAWSアカウントを追加する
    - 招待したいアカウントの指定とメッセージを入力して招待する。
    - 招待を受けたアカウントは招待内容を確認して招待を受ける。
#### 注意
- 1つのAWSアカウントが複数のOUのメンバーになることはできない。
- 1つのOUが同時に複数のOUのメンバーになることはできない。

### 削除方法
- マスターアカウントから削除する
- メンバーアカウントから削除する

#### 注意
- 削除されたアカウントは独立したアカウントとなり、個別に請求などが開始される。アカウント自体が消されるわけではなく、使い続けれる。
- Organizationsを使用して作成したアカウントを削除するには、情報の追加が必要になる場合がある。

## サービスコントロールポリシー(SCP)
- 組織のアカウントでプリンシパル(アカウントルート、IAMユーザー、IAMロール)にアクセスできるAWSのサービスアクションを管理できる。
- マスターアカウントは適用対象外。メンバーアカウントでは、IAMユーザ・ロール、ルートアカウントも対象。
- IAMポリシーと同じルールと文法に従う。
【参考】[SCP Syntax](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps_syntax.html)

    - ポリシーの許可・拒否
        - 許可：複数のポリシーがアカウントに適応される場合、許可はAND条件となる
        - 拒否：SCPで拒否とすると他で許可されていても、利用できない。
    - 管理方法
        - ブラックリスト方式：特定のサービスやアクションを禁止するポリシーの割り当て
        - ホワイトリスト方式：特定のサービスやアクションを許可するポリシーの割り当て
```
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*"
        },
        {
            "Effect": "Deny",
            "Action": "ec2:*",
            "Resource": "*"
        }
    ]
```

## 一括請求
- 組織内の全てのAWSアカウントの利用料が１つの請求として、まとめてマスターアカウントにされるようになる。
- ボリュームディスカウントが合算される。（個別アカウントより安価になる場合も）
- リザーブドインスタンスによる割引がデフォルトで共有される。
※特定アカウントに割引が共有されないよう設定することができる。
- 使用状況レポートでは割引を共有しない場合の料金(Unblended Rate)も確認が可能。
- AWS Organizationsを利用すること自体に追加料金はかからない。
- 組織内で定義された構造は請求書に反映されないので、個別のAWSアカウントでコスト配分タグを適用することで、AWSコストのカテゴリ分けと追跡ができる。

# 参考サイト
https://pages.awscloud.com/rs/112-TZM-766/images/20180214_AWS-Blackbelt-Organizations.pdf

https://aws.amazon.com/jp/organizations/faqs/
四則演算の自動生成プログラム

# はじめに
python3でつくってみました

# 要件
* 1問1答形式の四則演算の生成する
* 開始直後に問題数を入力させる
* 全ての問題への回答が完了したら、正解数を出力する

# 実行例

```
問題数を入力してください: 5
1. 69 - 28 = 41
2. 4 * 10 = 40
3. 72 - 10 = 62
4. 9 / 9 = 1.0
5. 3 * 3 = 9

正解数は 5 / 5 です。
```

# スクリプト

```python:sansuu.py
import random

# 四則演算の問題を生成する関数
def generate_question():
    operator = random.choice(["+", "-", "*", "/"])
    if operator == "+":
        num1 = random.randint(1, 100)
        num2 = random.randint(1, 100)
        answer = num1 + num2
    elif operator == "-":
        num1 = random.randint(1, 100)
        num2 = random.randint(1, num1)
        answer = num1 - num2
    elif operator == "*":
        num1 = random.randint(1, 10)
        num2 = random.randint(1, 10)
        answer = num1 * num2
    elif operator == "/":
        num2 = random.randint(1, 10)
        num1 = num2 * random.randint(1, 10)
        answer = num1 / num2
    return f"{num1} {operator} {num2}", answer

# メイン関数
def main():
    # 問題数の入力
    num_questions = int(input("問題数を入力してください: "))
    
    # 問題の生成
    questions = []
    answers = []
    for i in range(num_questions):
        question, answer = generate_question()
        questions.append(question)
        answers.append(answer)

    # 回答の入力と検証
    num_correct = 0
    for i in range(num_questions):
        print(f"{i+1}. {questions[i]} = ", end="")
        user_answer = input()
        if float(user_answer) == answers[i]:
            num_correct += 1

    # 正解数の出力
    print(f"\n正解数は {num_correct} / {num_questions} です。")

if __name__ == "__main__":
    main()
```
proptypesを使って、propのデータタイプをチェックする。

<h2>proptypesとは</h2>
proptypesとは、propsのタイプを確認するためのツールです。<br>
アプリケーションでtypescriptのようなjavascript extensionsを使用しなくても、reactに内蔵されているproptypesを利用してpropsのタイプを確認or宣言することができます。<br>
proptypes は性能上の理由から開発モードでのみ確認できます。すべてのプロップスのタイプを配信しようとすると、プロダクションモードで性能低下を引き起こす可能性があるから。 <br>
したがって、開発しながらエラーを認知して直していくという意味で使用します。

<h2>proptypes</h2>

```ProptypeComponent.jsx
import React from 'react'
import PropTypes from 'prop-types';

function PropComponent(props) {
  return <div>
    {props.name}
    {props.age}
  </div>
}

// Component.defaultProps：propsの初期値を定義
PropComponent.defaultProps = {
  name: "jimmy",
  age: 7
}

// Component.propTypes：Propsのデータタイプを定義。
// .isRequiredをtypeに指定すると、必須propと認識し、値がなかったり、typeが誤ったらエラーを起こす！
PropComponent.propTypes = {
   name: PropTypes.string,
   age: PropTypes.number.isRequired,
 }


// ageに定義したfunctionはカスタムエラー関数であり、ageが7 or 8ではないとカスタムしたエラーMSGが
// 出力されます。
PropComponent.propTypes = {
  name: PropTypes.string,
  age: function(props, propName, componentName) {
    if (!/7|8/.test(props[propName])) {
      return new Error(
        'Invalid prop `' + propName + '` supplied to' +
        ' `' + componentName + '`. Validation failed.'
      );
    }
  },
}


const Identity = ({ data }) => {
  return (
    <div>
      {data.map(({ name, age }) => <span key={name}>
      name is {name}, age is {age}
      </span>
      )};
    </div>
  );
}

// arrayof：dataは配列であり、配列の値がnameとageでなければなりません。
// shape：指定したオブジェクトと同じ形でなければエラー。
Identity.propTypes = {
  data: PropTypes.arrayOf(
    PropTypes.shape({
      name: PropTypes.string.isRequired,
      age: PropTypes.number.isRequired
    }),
  ).isRequired
};


export default function Component() {
  return (
    <div>
      <PropComponent />
      <Identity />
    </div>
  )
}

```
指定したHOST名を一度にリサイズする

# はじめに
仕事で使いそうなもんでサクッと作った。

# 要件
* 可用性セットでグルーピングされたVMに対してサイズ変更をするので、全部のVMを電源OFFにしてからリサイズを行う
* ある程度VMの状態がわかるように都度、"HOST名","電源状態","VMサイズ"が確認できるようにしてる
* 動き出したら止まらない、というのは困るので都度Enterキーを押すまで待機、って処理をはさみました
* Azure VirtuhalMachineでの利用を前提にしてる

# スクリプトはコチラ

```
# Define variables
$resource_group_name = "pro-nabehiro-001"
$vm_names = @("nbfr151v", "nbfr152v")
$vm_size = "Standard_B1ls"

# Define a function to get the VM data
function Get-VMData {
    param (
        [string]$vm_name,
        [string]$resource_group_name
    )

    $powerstate = az vm get-instance-view --name $vm_name --resource-group $resource_group_name --query "{host: name, powerstate: instanceView.statuses[1].displayStatus}" -o tsv
    $vm_name_size = az vm show --name $vm_name --resource-group $resource_group_name --query "{size: hardwareProfile.vmSize}" -o tsv
    $powerstate + "`t" + $vm_name_size
}

# Show VMs
foreach($vm_name in $vm_names) {
    Get-VMData -vm_name $vm_name -resource_group_name $resource_group_name
}

Read-Host "Press Enter to continue. next:stop vms"

# Stop VMs
Write-Host "Stop VMs"
$vm_ids = foreach ($vm_name in $vm_names) {
    az vm deallocate --name $vm_name --resource-group $resource_group_name --no-wait | Out-Null
    az vm show --name $vm_name --resource-group $resource_group_name --query 'id' -o tsv
}

az vm wait --ids $vm_ids --updated | Out-Null

# Show VMs
foreach($vm_name in $vm_names) {
    Get-VMData -vm_name $vm_name -resource_group_name $resource_group_name
}

Read-Host "Press Enter to continue. next:resize vms"

# Resize VMs
Write-Host "Resize VMs"
foreach($vm_name in $vm_names) {
    az vm resize --name $vm_name --resource-group $resource_group_name --size $vm_size --no-wait | Out-Null
}

az vm wait --ids $vm_ids --updated | Out-Null

# Show VMs
foreach($vm_name in $vm_names) {
    Get-VMData -vm_name $vm_name -resource_group_name $resource_group_name
}


Read-Host "Press Enter to continue. next:start vms"

# Start VMs
Write-Host "Start VMs"
foreach($vm_name in $vm_names) {
    az vm start --name $vm_name --resource-group $resource_group_name --no-wait | Out-Null
}

az vm wait --ids $vm_ids --updated | Out-Null

# Show VMs
foreach($vm_name in $vm_names) {
    Get-VMData -vm_name $vm_name -resource_group_name $resource_group_name
}

Write-Host "Finished!"
```
【SQLAlchemy】forで一個づつデータ更新するのなんかなぁ…ってとき

# やりたいこと
SQLAlchemyでAPIを実装してるときにループで毎度commitするのなんかぁ。
一括でデータ更新したい！って思ったらあった。

# 全ユーザーの居住地を大阪に変えちゃう
```python:test_api.py
# データベースからデータ取得
users_data = db.session.query(UserModel).all()

# 取得したデータをforでループさせて更新したいカラムを指定（address）して更新する値を入れる
user_data_update = [{'user_id': user_data.user_id, 'address': '大阪' } for user_data in users_data]

# bulk_update_mappingsメソッドに更新対象のモデルと先ほどの変数を指定して一括で更新
db.session.bulk_update_mappings(UserModel, user_data_update)

# データベースに登録
db.session.commit()
```

# bulk_update_mappings
今回の場合だとuser_idが主キーなのですが、更新データは一意の主キーを見て判断しているので、最初の引数に入れてください。
第二引数には値を更新したデータたちをリスト型で渡します。

# 注意
bulk_update_mappingsを使用する場合はORMのメソッドが使用できないので、使用したい場合は上記のように事前に更新データを取得しておく必要があります。
insertもあるらしいけど、updateのが使いそう。

# 参考記事
https://toritakashi.com/archives/1103
heroku pipelineを軽く弄ってみた感想

# 料金2倍かかるのは個人開発では辛い
APPで5ドル
postgresで7ドル

stagingとproductionの2つのAPPで使う場合は普通に2倍かかってしんどみ。

# dbのmigrateをするのに、cliを2回叩く必要がある
stagingとproduction、2つの環境でcliから2回migrateコマンドを叩くのはどっかのタイミングでミスりそうだなぁ。

### → 【追記：コメントいただきました】heroku release phaseという機能で、プロモート時に自動で動くスクリプトを追加できそう
https://devcenter.heroku.com/ja/articles/release-phase

コメントへのリンク
https://qiita.com/Kohei_Kishimoto0214/items/e24f26c9d2ae184444af#comment-a9656e76f749124d0185

### →→ 【追記】下記参考に、自動で動くスクリプトを追加できました。

https://qiita.com/d0ne1s/items/736bdc0bc9debd74de1f


# でも、stagingで確認できるのはいいよね。
前に開発していた時は「えいや」でローカル→本番環境に反映していたから、たまにミスって動かないとかなってた。
この機能で事前確認できるのはやっぱり嬉しいな。

# 現段階での結論
いったんstagingは一番安いプラン、productionはbasicプランで運用してみようかな。