OmniAICreator/Qiita-1.07M huggingface dataset:
【Rails】テキストボックスの数を好きに増やしたり減らしたりしてみる

どうもこんにちは。

今回は、Railsでフォームを作る時に使用するGemの「`nested_form`」について解説します。

# テキストボックスの数を増やしたり減らしたりってどういうこと？

以下のようなフォームがあるとして、「追加」ボタンや「削除」ボタンをクリックしたときに、対象の要素を追加したり削除したりすることを今回は実現します。

![スクリーンショット 2024-02-09 11.32.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/7ab30aef-5ea7-04d8-9e69-3b1ba2a2cb5d.png)

# 実装手順

## 1. Gem導入

```Gemfie:Gemfile
gem 'nested_form`
```

```sh
bundle install
```

## 2. ビューファイルを作成する

```erb:app/views/content_groups/edit.html.erb
<%= nested_form_for @content_group, :url => {:action => :update} do |f| %>
    <%= f.link_to_add '追加', :content_groups, class: 'btn btn-success' %>
    <table class="table table-bordered">
        <tr>
            <th class="col-xs-6 col-ms-6 col-md-6 col-lg-6">グループ名</th>
            <td class="add_remove_button"></td>
        </tr>
    
        <%= f.fields_for :content_groups, :wrapper => false do |ff| %>
            <tr class="fields">
                <td><%= ff.text_field :name %></td>
                <td class="add_remove_button">
                    <%= ff.link_to_remove '削除', class: 'btn btn-warning' %>
                </td>
            </tr>
        <% end %>
    </table>
    
    <div class="footer_buttons">
        <%= f.submit '更新', class: "btn btn-primary", name: "update" %>
    </div>
<% end %>
```

# 解説

`nested_form_for`ブロック内にある`link_to_add`は、`link_to_add`の第二引数と同じシンボルを持った`fields_for`を追加します。

```erb
<!-- このボタンは -->
<%= f.link_to_add '追加', :content_groups, class: 'btn btn-success' %>

<!-- 以下のfields_forフォームを追加します -->
<%= f.fields_for :content_groups, :wrapper => false do |ff| %>
<% end %>
```

逆に、`link_to_remove`はこれが所属している`fields_for`ブロックを削除します。

```erb
<%= f.fields_for :content_groups, :wrapper => false do |ff| %>
    <tr class="fields">
        <td><%= ff.text_field :name %></td>
        <td class="add_remove_button">
            <!-- 以下のボタンをクリックすると、fields_for全体を削除します -->
            <%= ff.link_to_remove '削除', class: 'btn btn-warning' %>
        </td>
    </tr>
<% end %>
```
htmxを触ってみた

最近注目されている(特に海外で)[htmx](https://htmx.org/)を触ってみました。

公式の引用ですが、htmxでは属性を使用して、HTML内にてAJAX, CSSトランジション, WebSocket, サーバー送信イベントを直接記述できるのでハイパーテキストのシンプルさと強力さを備えた最新のユーザーインターフェイスを構築できます。


## 例

### 確認モーダル
jsだと`confirm()`に当たるものを属性で書いています。
```html
<h2>確認</h2>
<button hx-delete="/account" hx-confirm="本当に削除しますか？">
  削除する
</button>
```
![スクリーンショット 2024-02-09 11.44.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295926/f316d6c1-eb00-d49a-3389-462f1a0823ec.png)
### GET
expressで簡単なサーバーを作りgetリクエストを送った例です。
`hx-targegt`で指定している`id="result"`に対して結果が表示されます。また`hx-indicator`により待ち時間にLoading...と表示されるようになります。

```html
<h2>GET</h2>
<button 
  hx-get="/hello"
  hx-target="#result"
  hx-indicator="#indicator"
>
Click
</button>

<span class="htmx-indicator" id="indicator">Loading...</span>
<h2 id="result">target</h2>
```
![スクリーンショット 2024-02-09 11.44.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295926/f19d491e-41de-cdd6-2196-2becce1e0700.png)


### POST
Clickを押すとユーザー一覧を取ってきます。
inputに値を入力して、submitすることでユーザーを追加することもできます。`hx-swap="beforeend"`により後ろに追加されていきます。

```html
<h2>ユーザー一覧</h2>
<form
  hx-post="/users/create"
  hx-trigger="submit"
  hx-target="#users"
  hx-swap="beforeend"
>
<input type="text" name="name" id="name" required/>
<button type="submit">Add</button>
</form>
<button
  hx-get="/users"
  hx-target="#users"
  hx-indicator="#indicator2"
  hx-swap="beforeend"
>
  Click
</button>
<span class="htmx-indicator" id="indicator2">Loading...</span>
<ul id="users"></ul>
```
![スクリーンショット 2024-02-09 11.43.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295926/b357564a-343a-df7a-94ca-6626769c7343.png)

## まとめ
簡単な例でしたが、jsを全く書かずに色々できてちょっと感動しました。

#### 参考
https://qiita.com/twrcd1227/items/7bce18167fb02ec22729

https://reffect.co.jp/html/html-first-time
より良い設計書の形を考えてみる

# はじめに
半分夢物語みたいなものなので、参考程度にお願いします。

# 内容に関するはじめに
皆さん案件に携わっている中で、設計書を見たことがあると思います。  
よく見るのはExcelで作られたヤツ。

で、このExcelで作られた設計書にある大きな欠点が、バージョン管理のしづらさです。  

gitやsvnで差分を見てもわけがわからないし、新しく書き足そうと思うたびにバックアップを取って、名前にyyyyMMddHHmmssをつけて・・・というのもちょっとアレです。アレ。  

これを解決する案が「変更箇所のみ赤字にしておく」ですが、これもちょっと微妙です。  
例えば「20シートくらいあって」「場所によって色々な文字色が使われている」設計書があった場合、設計書に1行書き足したいだけなのに前回赤字にされた部分を直す作業でめちゃくちゃ時間を食います。  

それと、この仕様にした場合強調したい箇所などに赤字が使えなくなります。

さあ困った。

# 考えてみた
## Markdown + バージョン管理ツール
### 良いところ
- Markdownなので表現の仕方にある程度の自由さはある。
- バージョン管理ツールなので、差分確認だけでなくコミットコメントも残せる。  
また、任意のタイミングで差分を保存出来る。
- Excelのときと同じように、PJ用のフォルダに設計書を置ける。

### 悪いところ
- 扱いやすさ/書きやすさは、やっぱりExcelには敵わない。
- 「シート分け」に対応する概念がないため、ファイルを分ける等の手間がかかる。
- Markdownエディター かつ バージョン管理ツールのコミットもできるようなアプリがほぼない。  
（VSCodeのようなIDEにアドオンでMarkdown対応させるくらい・・？）

## Googleスプレッドシート
### 良いところ
- かなりExcelに近い使い方が出来る。
- その上で差分もしっかり確認できる。
- xlsxファイルで出力出来るので、社外などにも共有しやすい。

### 悪いところ
- 設計書をPJ用フォルダに配置出来ない。（ショートカットリンクを置くくらいしかない・・？）
- 差分を保存するタイミングが自動のため、かなり細かく残ってしまったりする。結果見づらい。
- バージョンごとのコメントが残せないため、パッと見たときにどこがどの差分かわからない。
- 設計書の権限管理が面倒くさい。  
共有リンクを一度知られたら、明示的にブロックしたりリンクを更新しない限り恒久的にアクセス出来るため、案件用フォルダと各設計書を二重で管理する必要が出てくる。
- 作成者が案件から外れるたびに管理者を変えたりする必要が出てくる。

# おわりに
どれも一長一短ありますが、短所がそこそこでかいのが悩みどころです。  
Markdown + バージョン管理ツールが比較的マシだとは思いますが、どうしても扱いにくさが否めない・・。  

とはいえ、完全手動のバージョン管理もかなりしんどいので、できればこっちにしたいよなぁという気持ちが個人的には強いです。

この話をするのにあたって一番の短所は、そもそも乗り換えるという事自体のハードルがめちゃくちゃ高いということですが。

なにかいいアイデアがあればコメントお願いします！
Flutter初心者が力技で同じTextEditingControllerを複数使った話

## どういうこと？
名前を入力する欄が複数行あった場合、同じTextEditingControllerを使ってしまうと、入力された値が全てに反映されてしまいます。

![スクリーンショット 2024-02-09 10.42.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669888/c62474cc-f489-4c1c-c812-7283917cbd63.png)


## 動的にしたい…
初めから入力する行数がわかっていれば、それぞれのTextEditingController を作ればいいわけですが、行を追加したり削除したりするような処理だといくら数が増えるかわからないわけです。
ReactであればuseFieldArrayという便利なものがあって、fieldに追加したり削除したりで動的に同じ値を持った入力フォームを簡単に作成できるんですが、Flutterではそういうやつがなさそうなので、悩みました…

## 要はindexで呼び出せばいいってわけ？
TextEditingControllerがリストになっていてループで回したときに指定したindexで欲しいとこのTextEditingControllerが呼び出せればいいから…
```
List<TextEditingController> nameControllers = List.generate(2, (i) => TextEditingController());

@override
Widget build(BuildContest context) {
  return Scaffold(
    child: ListView.builder(
      shrinkWrap: true,
      itemCount: nameControllers.length,
      itemBuilder: (context, index) {
      return Column(
        children: [
          TextField(
            controller: nameControllers[index],
            decoration: InputDecoration(labelText: 'name')
          )
        ]
      )
    }
  )
)}
```
これでだいたい近いことができました！

![スクリーンショット 2024-02-09 10.54.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669888/337964cb-328e-2726-7e3e-ca6de3819391.png)

でもこれだと、リストを作ってからだから動的ではないな…


## あれ？複数のTextEditingControllerがあるときどうするんだ？
例えばメンバー表などで名前と年齢を入力するTextFieldがあり、行を追加したい場合、上記の方法だと、TextEditingControllerを指定できません。
呼び出す時に何かを指定しなきゃならないということは…Mapか？
ということで、
```
List<Map<String, TextEditingController>> memberControllers = [
  {
    'name':TextEditingController(),
    'age': TextEditingController(),
  }
];
```

で、呼び出す時はListView.builderを使って
```
ListView.builder(
 itemCount: memberControllers.length,
 itemBuilder: (context, index) {
   return Row(
     children: [
       SizedBox(
         width: 200,
         child: TextField(
           controller: memberControllers[index]['name'],
           decoration: InputDecoration(labelText: 'name')
           ),
       ),
       const SizedBox(width: 20.0),
       SizedBox(
         width: 200,
         child: TextField(
         controller: memberControllers[index]['age'],
         decoration: InputDecoration(labelText: 'age')
         )
       )
  ]);
 }
)
```

これでそれぞれを呼び出すことができました。
あとは行を追加するボタンとかをおもむろに追加します。
```
ElevatedButton.icon(  
    onPressed: () {  
      setState(() {  
        memberControllers.add({  
          'name': TextEditingController(),  
          'age': TextEditingController(),  
        });  
      });  
    },  
    icon: const Icon(Icons.add),  
    label: const Text('追加')
),
```

![スクリーンショット 2024-02-09 11.26.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669888/e08d5ddb-7d69-c635-49ac-c55c2288a3fa.png)


## 解決
これでやりたいことができました。
調べ方が悪いのか求めることがなかなか出てこなかったので、なんとかかんとかやってみました。
動いてはいますが、やり方が正しいか不安なので、こうしたほうがいい、このやりかたは良くないなどありましたらぜひコメントくださると嬉しいです。
お読みいただきありがとうございました。

### 参考
参考にさせていただきました。ありがとうございます。

https://zenn.dev/akinori25/articles/801c24178e782c
Rubyの並列化で激オソご注意！！

ローカル環境で高速だった処理が本番環境で激オソになる目にあいましたので共有です。

## 結論
Rubyで処理速度を向上させるために、Parallel gemの Parallel.map を使ってスレッド並列化を試みたものの、ローカル環境では問題なかったのに本番環境で劇的に遅くなってしまった経験はありませんか？

実は、Parallel.map はデフォルトでプロセス並列化を行うため、アクセス数の多い本番環境ではプロセスの立ち上げコストが大きな負荷となり、処理速度が低下してしまう可能性があります。

スレッド並列化で3分→3秒！本番環境で劇的な速度向上を実現

この記事では、Parallel.map によるプロセス並列化の落とし穴と、in_threads によるスレッド並列化で3分→3秒という劇的な速度向上を実現した体験談をご紹介します。

## Parallel.mapによるプロセス並列化の落とし穴

ローカル環境では、Parallel.map を使用して4つのスレッドで処理を行ったところ、処理時間は約30秒と高速でした。しかし、本番環境では2つのコアに対して4つのプロセスを立ち上げたため、プロセスの立ち上げコストが処理時間の大部分を占め、結果的に3分もかかってしまうという問題が発生しました。

## in_threadsによるスレッド並列化で劇的な速度向上

そこで、Parallel.map の代わりに in_threads を使用してスレッド並列化を試みたところ、処理時間はなんと3秒まで劇的に短縮されました。

in_threadsでプロセス並列化と比べて、プロセスの立ち上げコストが発生しないため、アクセス数の多い本番環境においては圧倒的なパフォーマンスを発揮します。

## スレッドとプロセスの違い

**1. 概要**

スレッドとプロセスは、どちらもプログラムの実行単位ですが、異なる概念です。

* **プロセス:** 独立した実行環境を持つプログラムの実行単位。メモリ空間、ファイルハンドル、CPU時間などのリソースを個別に所有します。
* **スレッド:** 同じプロセス内で動作する軽量な実行単位。メモリ空間やファイルハンドルなどはプロセスと共有しますが、CPU時間などは個別に割り当てられます。

**2. 主な違い**

| 項目 | プロセス | スレッド |
|---|---|---|
| リソース | 独立 | 共有 |
| スケジュール | OS | アプリケーション |
| コンテキストスイッチ | 重い | 軽い |
| メモリ使用量 | 大きい | 小さい |
| 実行速度 | 遅い | 速い |

**3. それぞれの特徴**

**3.1 プロセスの特徴**

* 独立した実行環境を持つため、高い安定性とセキュリティを実現できます。
* 複数のプロセスを同時に実行することで、マルチタスクを実現できます。
* ただし、リソースの消費量が多いため、メモリやCPUリソースに制限がある環境では使いにくいです。

**3.2 スレッドの特徴**

* プロセスと比べてリソースの消費量が少ないため、メモリやCPUリソースに制限がある環境でも使いやすいです。
* 同じプロセス内の複数のスレッドが同時に実行されるため、処理速度を向上させることができます。
* ただし、データ競合などの問題が発生する可能性があります。

**4. 使い分け**

* 処理速度を重視する場合: スレッド
* 安定性とセキュリティを重視する場合: プロセス
* リソースに制限がある場合: スレッド


## まとめ

Parallel.map は手軽に並列処理を行える便利なライブラリですが、デフォルトでプロセス並列化を行うため、本番環境では思わぬ落とし穴にはまる可能性があります。

アクセス数の多い本番環境で並列処理を行う場合は、in_threads によるスレッド並列化を検討することで、劇的な速度向上が期待できます。
Go言語のtestingパッケージを使ってみた

自分の関わっているWebサービスは、一部をGo言語で実装している。
今回、testingパッケージを導入して、単体テストの一部を自動化したので、そのメモを残します。

# 環境
``` 
% sw_vers  
ProductName:		macOS
ProductVersion:		13.5
BuildVersion:		22G74
% go version
go version go1.21.6 darwin/arm64
```

# ソースコード
2つの数値を加算する関数`add`をテスト対象として記述したテストコードを例としています。
### テスト対象
```example/add.go
package example

func add(a, b int) int {
	return a + b
}
```

### テストコード
```example/add_test.go
package example

import "testing"

func TestAdd(t *testing.T) {
	type Args struct {
		a int
		b int
	}
	type Wants struct {
		c int
	}
	tests := []struct {
		name  string
		args  Args
		wants Wants
	}{
		{"test-ok-1", Args{1, 2}, Wants{3}},
		{"test-ok-2", Args{3, -4}, Wants{-1}},
		// {"test-ng", Args{-5, 6}, Wants{11}},　<= 失敗例
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := add(tt.args.a, tt.args.b)
			if got != tt.wants.c {
				t.Errorf("add() = %v, want %v", got, tt.wants.c)
			}
		})
	}
}

```

# テスト実行
## 実行（オプションなし）
`go test テスト対象ディレクトリ`でテストを実行できる。
```
% go test ./example
ok      example.com/testing/example     0.406s
```
失敗する`test-ng`を有効にして実行した場合、次のように失敗した内容を出力してくれる。
```
% go test ./example 
--- FAIL: TestAdd (0.00s)
    --- FAIL: TestAdd/test-ng (0.00s)
        add_test.go:26: add() = 1, want 11
FAIL
FAIL    example.com/testing/example     0.449s
FAIL
```

## キャッシュ削除
ソースコードの変更がない状態でテストを実行すると、キャッシュされた前回の結果が出力される。
```
% go test ./example
ok      example.com/testing/example     (cached)
```
キャッシュを削除するには`go clean -testcache`を実行する。
```
% go test ./example
ok      example.com/testing/example     (cached)
% go clean -testcache
% go test ./example
ok      example.com/testing/example     0.404s
```
また、`-count=1`オプションを指定して実行した場合、キャッシュが残らない。
```
% go test ./example -count=1                      
ok      example.com/testing/example     0.174s
% go test ./example -count=1
ok      example.com/testing/example     0.127s
```

# 詳細を出力する
`-v`オプションを指定して実行すると、詳細を出力してくれる。
```
% go test ./example -v      
=== RUN   TestAdd
=== RUN   TestAdd/test-ok-1
=== RUN   TestAdd/test-ok-2
--- PASS: TestAdd (0.00s)
    --- PASS: TestAdd/test-ok-1 (0.00s)
    --- PASS: TestAdd/test-ok-2 (0.00s)
PASS
ok      example.com/testing/example     0.392s
```
失敗する`test-ng`を有効にして実行した場合は、次のように出力される。
```
% go test ./example -v
=== RUN   TestAdd
=== RUN   TestAdd/test-ok-1
=== RUN   TestAdd/test-ok-2
=== RUN   TestAdd/test-ng
    add_test.go:26: add() = 1, want 11
--- FAIL: TestAdd (0.00s)
    --- PASS: TestAdd/test-ok-1 (0.00s)
    --- PASS: TestAdd/test-ok-2 (0.00s)
    --- FAIL: TestAdd/test-ng (0.00s)
FAIL
FAIL    example.com/testing/example     0.400s
FAIL
```

# あとがき
今回、自動化した対象は、この記事にサンプルとして記述している`add`のようなユーティリティ的に使われる関数のみだが、標準のモックや`httptest`パッケージもあるようなので、使いこなせれば、ほとんどの単体テストは自動化できそう。
とはいえ、`testing`パッケージ自体の理解も足りてないので、まずは、勉強します。
List型のデフォルト引数を指定する

# List型のデフォルト引数

## エラー
```Dart
class Sample({
    List<String> list = []
    })
```

デフォルト値として空のリストを指定しようとすると以下のエラーが出る🌀
`The default value of an optional parameter must be constant.`

## 解決策
`const`にすればいいらしい
```Dart
class Sample({
    List<String> list = const []
    })
```
Microsoft Copilotで、日本語プログラミング その17

# 概要
Microsoft Copilotのプロンプトを細工して、日本語プログラムを実行させようとする試みです。
おやつの選択、問題をやってみた。

# Ohisama prompt

```
架空のブログを生成することを考えます。 ブログの記事を書くことです。 
構成は、
ある技術的なテーマを与えられた場合 、それに対する仮説を提案します 。
次に 仮説を裏付ける理論を示します。
計算結果を導くために、日本語プログラミングのダミーコードを書くようにしてください。 
そして、その理論を検証した計算結果を示します 。
最後に 簡潔な結論を加えるという構成です。 
全体を、１万字に収めてください。
では、「動的計画法で、おやつの選択問題を解く」というテーマで、ブログを記事にしてみてください。
```

# 回答

こんにちは、Copilotです。?
あなたのリクエストに応えて、架空のブログ記事を生成してみました。
以下がその内容です。ご覧ください。

# 動的計画法で、おやつの選択問題を解く

こんにちは、プログラミング好きのブロガーです。
今回は、動的計画法というアルゴリズムを使って、おやつの選択問題を解いてみたいと思います。
おやつの選択問題とは、以下のような問題です。

- あなたは、N種類のおやつが売られているお店に来ました。
- お店では、各おやつに価格と満足度が設定されています。
- あなたは、予算M円以内で、できるだけ満足度の高いおやつを買いたいです。
- ただし、同じおやつを2個以上買うことはできません。
- どのおやつを買うと、最大の満足度を得られるでしょうか？

例えば、以下のようなおやつがあるとします。

| おやつ | 価格 | 満足度 |
| :---: | :---: | :---: |
| チョコレート | 100円 | 80 |
| クッキー | 150円 | 100 |
| ドーナツ | 200円 | 120 |
| アイスクリーム | 300円 | 200 |

予算が500円だとすると、どのおやつを買うと最大の満足度を得られるでしょうか？
答えは、チョコレートとアイスクリームを買うと、価格は400円で満足度は280となります。
これが最適な選択です。

このような問題を効率的に解く方法が、動的計画法です。
動的計画法とは、大きな問題を小さな問題に分割して、それぞれの最適解を求めていく方法です。
動的計画法の特徴は、以下の2つです。

- **最適部分構造**：大きな問題の最適解は、小さな問題の最適解から構成される。
- **重複する部分問題**：同じ小さな問題が何度も出現する。

おやつの選択問題では、以下のように動的計画法を適用できます。

- まず、N種類のおやつを1からNまで番号をつけます。
- 次に、dp[i][j]という二次元配列を用意します。
- dp[i][j]は、i番目までのおやつの中から、予算j円以内で買える最大の満足度を表します。
- dp[0][j]は、おやつを何も買わない場合なので、0とします。
- dp[i][j]を求めるには、以下の2つの場合を比較します。
  - i番目のおやつを買わない場合：dp[i-1][j]と同じです。
  - i番目のおやつを買う場合：dp[i-1][j-price[i]] + value[i]となります。ただし、j >= price[i]のときのみです。
- この2つの場合のうち、大きい方がdp[i][j]の値となります。
- すべてのiとjについてdp[i][j]を計算したら、dp[N][M]が最終的な答えとなります。

このアルゴリズムを日本語プログラミングで実装すると、以下のようになります。

```python
# おやつの種類と予算を入力する
おやつの種類 = 整数型(入力("おやつの種類は？"))
予算 = 整数型(入力("予算は？"))

# おやつの価格と満足度を入力する
価格 = 空のリスト
満足度 = 空のリスト
繰り返す i は 1 から おやつの種類 まで
  価格[i] = 整数型(入力(i + "番目のおやつの価格は？"))
  満足度[i] = 整数型(入力(i + "番目のおやつの満足度は？"))

# dp[i][j]は、i番目までのおやつの中から、予算j円以内で買える最大の満足度
dp = 二次元配列(おやつの種類 + 1, 予算 + 1, 0)

# dpを計算する
繰り返す i は 1 から おやつの種類 まで
  繰り返す j は 0 から 予算 まで
    もし j >= 価格[i] なら
      # i番目のおやつを買う場合と買わない場合のうち、大きい方を選ぶ
      dp[i][j] = 最大(dp[i-1][j], dp[i-1][j-価格[i]] + 満足度[i])
    そうでなければ
      # i番目のおやつを買えない場合は、買わない場合と同じ
      dp[i][j] = dp[i-1][j]

# 答えを出力する
出力("最大の満足度は" + dp[おやつの種類][予算] + "です。")
```

このプログラムを実行すると、以下のような出力が得られます。

```
おやつの種類は？4
予算は？500
1番目のおやつの価格は？100
1番目のおやつの満足度は？80
2番目のおやつの価格は？150
2番目のおやつの満足度は？100
3番目のおやつの価格は？200
3番目のおやつの満足度は？120
4番目のおやつの価格は？300
4番目のおやつの満足度は？200
最大の満足度は280です。
```

このように、動的計画法を使うと、おやつの選択問題を効率的に解くことができます。
動的計画法は、他にもナップサック問題や最長共通部分列問題など、様々な問題に応用できます。
動的計画法のコツは、最適部分構造と重複する部分問題を見つけることです。
プログラミングのスキルを向上させるには、動的計画法の問題をたくさん解いてみることをおすすめします。

以上が、動的計画法でおやつの選択問題を解くというテーマでのブログ記事でした。
この記事が、あなたのプログラミングの学習に役立てば幸いです。
次回は、別のテーマでお会いしましょう。
それでは、また。?

以上。
100円ショップ充電ケーブル性能確認

# 概要
携帯電話を充電していると、USBのアダプタやモバイルバッテリーの給電能力はもちろん、接続する充電ケーブルによっても充電時間に大きな違いが出てくるという感覚がある。そこで、手元にあるUSBの電流測定器を用いて、流れる電流にどの程度の違いが出るものなのか、調査してみた。

# 実験方法
手元にあった、USB Power checker（RouteR製）を用いて、手持ちのiPhone13に充電を行う際の供給電流の比較を行った。また、使用した電源、対象としたケーブルは次のとおり。
- USB Power checker
![IMG_6245.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822780/dfde6f8d-17a5-bdbc-c266-d285e54c3076.jpeg)
### 実験に用いた電源
- SMARTCOBY Pro PLUG（CIO）
![IMG_6243.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822780/64c07c6b-f51b-19d1-62df-36ae31ad8603.jpeg)
- EC-AC22WH（ELECOM）
![IMG_6244.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822780/2a1c2e9a-b9be-ddec-5b17-6e026b88c991.jpeg)
### 実験に用いたUSBケーブル
- 光るlightningケーブル（ダイソー）
![IMG_6248.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822780/cfada24d-a69e-59a5-e277-e055768e59be.jpeg)
- type C & lightningケーブル（ダイソー）
![IMG_6247.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822780/47b4d513-8083-f9a1-9e36-a8c12c4ceb33.jpeg)
- microUSB & lightning兼用ケーブル（ダイソー）
![IMG_6246.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822780/83bce2f0-7b4b-c93d-38e6-529a8d078d11.jpeg)


# 実験結果
初めに、それぞれの電源について、無負荷時の電圧の観測を行った。結果は次のとおり。なお、EC-AC22WHには無負荷時の出力停止がかなり早く設定されているようで、少々測定に手間取った。

| 電源名 | 無負荷時電圧 |
|:-:|-:|
| SMARTCOBY Pro PLUG  |  5.29V |
| EC-AC22WH  |  5.05V |
| Note PC  |  5.08V |

次に、iPhone13のバッテリー残量を変化させながら各ケーブルでの充電電流を測定した。なお、測定に当たっては、起動しているアプリをすべて停止し、通信機能をOFFにした。

### バッテリー残量75%時
| 電源名 | 光るケーブル | type C 分割 | microB兼用 |
|:-:|-:|-:|-:|
| SMARTCOBY Pro PLUG  | 1.5A |  1.00A | *1.06A |
| EC-AC22WH 　        | 1.3A | *1.06A | *0.96A |
| Note PC             | 1.2A | *0.96A | *0.39A |

### バッテリー残量50%時
| 電源名 | 光るケーブル | type C 分割 | microB兼用 |
|:-:|-:|-:|-:|
| SMARTCOBY Pro PLUG  | *2.02A | *2.05A | *1.85A |
| EC-AC22WH 　        | *1.83A | *1.93A | *0.95A |
| Note PC             | *1.63A | *1.51A | *0.39A |

### バッテリー残量35%時
| 電源名 | 光るケーブル | type C 分割 | microB兼用 |
|:-:|-:|-:|-:|
| SMARTCOBY Pro PLUG  | *2.03A | *2.04A | *1.93A |
| EC-AC22WH 　        | *1.74A | *2.03A | *1.70A |
| Note PC             | *1.55A | *1.62A | *0.36A |

## 結果の考察
microB兼用ケーブルについては、NotePCとの接続時に目立って電流が小さくなっている。通信機能を持っているため、NotePCとの接続時には充電電流が制限されているのかもしれない。これは、ほかの端末でも起こることなのか、iPhone特有の現象なのかはわからない。
また、数字の上では、光るケーブルが一番安定して電流供給ができているように見えるが、思ったよりも電流値が暴れて、正確な測定ができていない。また、実験を行っている中で、バッテリー残量が増えてくると、それに伴って充電電流が減ってくる傾向も見られた。電流測定を行う順番が影響を与えることも考慮しなければならない。
本来であれば、開始状態をそろえて、充電にかかる時間を評価するほうが良いのだろうが、この手法での実験には時間がかかり、簡単には結果を出せない。この計測器には、mAhを計測する機能もあるので、次は、ある電流を流す時間から、平均値を取る方法を試すことにしたい。

そして、100円ショップのケーブルを評価しておいてどうかと思うが、モバイルバッテリーの炎上等が問題になっており、電源周りには、それなりにお金をかけたほうがいいと思う。
Beamer使ってみた

# Beamerスライド

githubでのバージョン管理のしやすさから、Latexで書くことにしました。

せっかくだからスライドも・・ということでこころみました。

その前は、marpをつかって、markdownからスライドをつくろうと試みていました。

# 2段組みが便利

```
\begin{frame}
\begin{columns} 
    \begin{column}{.5\textwidth}
    
left
    \end{column}
    
    \begin{column}{.5\textwidth}
right
       
    \end{column}
\end{columns}
\end{frame}

```

# BibTeXを使って参考文献リストを作成する

便利です。BibTeXを使用すると、参考文献の自動化が可能で、スライド作成を効率的に行えます。

以下は、BeamerスライドでBibTeXを使用して参考文献リストを作成する手順です:

## **BibTeXファイルの作成**:
   - たとえば `ref.bib`というファイルを作成し、参考文献のBibTeXエントリを記述します。
   - Google Scholarなどで論文名や書籍名を検索し、引用マークからBibTeX情報を取得します。

## **スライドに参考文献リストを載せる**

   - Beamerスライドのテンプレートを使用して、以下のコードをスライドに追加します:

     ```latex
     \begin{frame}[allowframebreaks]{Reference}
       \scriptsize
       \beamertemplatetextbibitems
       \bibliographystyle{prsty} % 引用のスタイル (本文の登場順に並ぶ)
       \bibliography{ref} % .bibファイルの名前
     \end{frame}
     ```

   - このコードを文献リストを載せたい箇所に挿入します。
   - 本文中で `\cite{}` を使って引用できます。

## **コンパイル**:

TeXで日本語やらないってちかったので、

   - 英語のみの場合:
     ```
     pdflatex slide.tex
     bibtex slide
     pdflatex slide.tex
     ```
コンパイルは最低でも3回程度必要です。

## 参考文献リストを短くしたい

最も良くある著者が3名以上の論文の時、

たとえば、

J. Doe et al., Nature (London) **1** (1800) 1.

となるようにbstファイルをカスタマイズしました。

`prsty.bst`というのが手元にあり、そのファイルの中をみてみると、
`etal`というキーワードがあり、その近くに`#15`とありました。
おそらく著者が１５人以上の場合、et alにするんだと思います
これを３にかえると、上記機能が実現できました。

# 参考文献

1. https://sk.kuee.kyoto-u.ac.jp/ja/2009/08/bibtex-style/
1. https://www.overleaf.com/learn/latex/Beamer
1. https://qiita.com/birdwatcher/items/0dd3fe2e8ff5685cc3f7"
[Oracle Cloud] Autonomous DatabaseをOCPU->ECPUにする

# はじめに

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/cd5bb281-4441-2034-1d87-4105d32a87f3.png)

表題の通り、ADB-SでOCPU->ECPUへオンライン移行ができるようになったので、試してみる

# 現状

「Autonomous Databaseの詳細」画面
作成は2019/11/18と古いが、OCPUは1が割り当てられており、
横に「ECPUモデルに更新」ボタンがある

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/cd2b603d-0ef2-be36-4e43-dfde24765dc1.png)

# 操作

「ECPUモデルに更新」をクリック
サイドツリーが表示された

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/86872669-e0c1-6c78-b92a-346f50168265.png)

私の場合はECPU数がデフォルトでは4と入力されている
> ECPU請求モデルへの更新後に、コンピュートまたはストレージをスケールできます。

とあり、この段階ではECPU数を変えられない
ストレージも同様で、
> 現在のストレージの選択内容が保持されます。請求モデルの更新後に、ストレージをスケール・アップまたはスケール・ダウンできます。

とのこと。

ブラウザ下部も確認する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/99c52739-79d2-507c-33ae-6a61e23e1831.png)

バックアップ保持期間は、1-60日の間で1刻みで指定が可能
今回は10に設定し、「変更の保存」をクリック

なにやらエラーが出ました...
私の持っている環境はクォータに引っ掛かって、変更できないとのこと...
作業をするときは、クォータやservice limitに注意が必要ですね...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/200109ff-630e-b189-3cd5-3e0dbed59b95.png)

作業が続行できない為、一先ずここまで。

---

追記
クォータを引き上げてもらって、再試行
更新がはじまりました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/970030df-0f4e-18eb-2f26-e30c1adae234.png)

ステータスがグリーンに変わりました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/e905bbcf-0056-0718-b6d8-0bc31cdf4257.png)

リソースの割り当てを見ると4ECPUになっています
ストレージは変わらず1TBです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/5d633e6b-c74f-adb5-3165-ad59b8fa8737.png)

バックアップ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/a2b0952e-734a-7e28-1a61-1c2e3a2730a7.png)
【備忘】Web API認証方式について

今回は、Web API認証方式について、基本的な概念から種類や特徴、使用例までをまとめてみました。

### そもそも認証とは
**認証**とは、システムやサービスにアクセスする際に、ユーザーが正規のユーザーであることを確認するプロセス。
要は、「あなたがあなたであることを確認する」ことである。

認証があることで、不正アクセスを防止し、データやリソースのセキュリティを確保します。

#### 認証と認可の違い
認証と混同されやすいものとして「認可」という言葉もある。
**認可**とは「あなたがその操作をする権限があるか確認する」こと。

その過程で「あなたが誰か」知る必要があり、認証と同じような情報を必要する。
このため両者が混同されたり、簡易的な認証として認可方式を利用したりすることがあるが根本的に別ものである。

### Web API認証方式とは
Web API認証方式とは、Web APIを利用する際に、ユーザーが正当な権限を持っていることを確認する仕組み。
これにより、不正なアクセスや悪意のある利用を防止し、セキュリティを向上させます。

### Web API認証方式の種類と特徴
#### HTTP Basic Authentication:
<特徴>
・ユーザー名とパスワードをBase64エンコードしてHTTPリクエストヘッダーに含める方式。
・実装が簡単であり、多くのプログラミング言語やフレームワークでサポートされている。
・ただし、セキュリティが低く、パスワードが平文で送信されるため、HTTPSと併用することが推奨される。

#### APIキー認証:
<特徴>
・ユーザーに一意のAPIキーを発行し、それをリクエストに含める方式。
・APIキーが盗まれるリスクがあるため、HTTPSを使用して通信を暗号化する必要がある。
・キーの有効期限を設定することでセキュリティを向上させることができる。

#### OAuth認証:
<特徴>
・サードパーティーのアプリケーションが、ユーザーの代わりにAPIにアクセスするための権限を取得するための標準的なプロトコル。
・ユーザーは自分のリソースに対するアクセス許可を明示的に与えることができ、安全性が高い。
・認証プロセスが複雑であり、実装に時間がかかる場合がある。

### Web API認証方式の使用例
#### HTTP Basic Authentication
curlコマンドを使用して、GitHub APIに対してHTTP Basic Authenticationを使って認証する
例：
```bash
curl -u username:password https://api.github.com/user
```
<使用場面>
・テストや開発目的のシンプルなAPIへのアクセス。
・内部システムや限られた利用者がアクセスするAPI。

#### APIキー認証
Google Maps APIの使用例。APIキーをクエリパラメーターに含めてリクエストを送信する
例：
```bash
https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=YOUR_API_KEY
```
<使用場面>
・多数の利用者がアクセスする公開API。
・外部開発者やサードパーティーが利用するAPI。


#### OAuth認証
FacebookのOAuth 2.0フローを使用してユーザーのプロフィールにアクセスする
例：
```html
<a href="https://www.facebook.com/v12.0/dialog/oauth?client_id=YOUR_APP_ID&amp;redirect_uri=YOUR_REDIRECT_URI&amp;state=YOUR_STATE_VALUE&amp;scope=email">ログイン</a>
```
<使用場面>
・サードパーティーのアプリケーションが、ユーザーのリソースにアクセスする場合。
・多数のユーザーがログインしてプライベートデータにアクセスする場合。


### まとめ
Web API認証方式として、[**HTTP Basic Authentication**][**APIキー認証**][**OAuth認証**]と３点あり、Web APIを使用する上での、セキュリティ面で安全性が高い。
Salesforceのトレイルヘッドで正しく設定されているのにエラーになる場合



# キャッシュの問題

+ [Unable to complete challenge in Filter Your Report Unit](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007XIDgC)

:::note
I think your settings are correct.
The caching may be causing the problem.

Please log out once and log in again.
If you're still getting an error, try using your browser's incognito mode or using a different browser.
:::
BCM-ARMで最初の一歩

昔はMIPSのSOCを作っていたBroadcomですが、最近はARMに鞍替えしています。このSOCが入った猛牛さんのターゲットがハードオフで330円で手に入ったので[最初の一歩](https://qiita.com/yamori813/items/7658eeb1b73c61747a89)をやってみます。

ターゲットは保護シールがはったままで、使用された形跡がありません。アダプタとLANケーブル付で330円はとってもお徳でした。

本体に電源のスイッチがあるのですが機能しません。初期不良のため処分されたものなのかも知れません。

とりあえず分解してみます。一度も普通に使われずに分解されるのもなんともしのび難いのですが、心を鬼にします。UARTのピンは立っていましたが、SOCにはごっついヒートシンクがはってあってなにか分かりません。BCM4708という噂でこれはBCM5301Xと同じラインのようです。

BroadcomのARM SOCには2系統あり、ラズパイなどで使われているBCM2xxxとMIPS SOCのIOを流用したBCM470x(BCM5301X)系です。

BCM4712,BCM4702はMIPS SOCでBCM4708はARM SOCです。

Comcerto2000のポートはBCM5301Xをベースにしていて、このSOCも試してみたいと思っていました。

BCM5301XのサポートはNetBSD 6の終わりくらいで入ったようです。Cortex-A9の最初のサポートでした。当時はまだFDTが入っていなくて、これ以降のCortex-A9のサポートはFDTでおこなわれています。

BroadcomはMIPSの頃からオリジナルのCFEというブートローダーを使っていて、ARMになってもCFEのようです。

最初の一歩のコードをNetBSDに入れます。

```diff
diff --git a/sys/arch/arm/arm/armv6_start.S b/sys/arch/arm/arm/armv6_start.S
index a448e45fbffd..df8b87e00b18 100644
--- a/sys/arch/arm/arm/armv6_start.S
+++ b/sys/arch/arm/arm/armv6_start.S
@@ -94,6 +94,11 @@
        .text
 
 ENTRY_NP(generic_start)
+       ldr     r2, .Luart
+       mov     r1, #78
+       strb    r1, [r2]
+.Luart:
+       .word   0x18000300
 
 #if defined(__ARMEB__)
        /* Make sure sctlr.u = 1 when cpsr.e = 1. */
```

evbarm/conf/BCM5301Xでカーネルを作ります。エラーが出るので、とりあえずコメントアウトしてビルドを通します。エラーが何か分かりづらくなるので最初はパラレルビルド(-j)はしないほうがいいです。

サーバーに192.168.11.2のアドレスを付けてtftpできるようにしてビルドしたnetbsd.binをおきます。

```
CFE> boot -addr=0x00008000 -max=0x1000000 192.168.11.2:netbsd.bin
Loader:raw Filesys:tftp Dev:eth0 File:192.168.11.2:netbsd-BCM5301X.bin Options:(null)
Loading: .... 4221332 bytes read
Entry at 0x00008000
Closing network.
Starting program at 0x00008000
N
```

このCFEのbootコマンドはデフォルトでは262144バイトしか読み込みません。また-maxは-addrを指定しないと有効になりません。

ロードアドレスの-addr=0x00008000はLinuxと一緒にしてみました。

CFEのネットワークはLAN側のポートが使えるようです。

実行が移せたみたいです。ここから始まります。
Manufacturing Cloud

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめA～M](https://qiita.com/Keiji_otsubo/items/f3ddedee6793bf1576f8)



+ [I'm not getting any data in advanced Forecast tab in advanced account forecast uses, how can i get the data in advanced forecast tab?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007Tu8ln)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/33845c64-c630-6503-8bae-03d63beb1a78.png)



+ [Winter 24 :Whoops, looks like there was a problem. Please try again. のエラーが増えてます](https://qiita.com/Keiji_otsubo/items/9a4e73ab50b8be7d93b1)

# Sales Agreements and Forecasting in Manufacturing Cloud >Create a Sales Agreement

+ [I keep receiving an error when trying to pass the "Create a sales agreement and add a product" challenge in Sales Agreements and Forecasting in Manufacturing Cloud module](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007URi9uSAD)

# Create a sales agreement and add a product

+ [I keep receiving an error when trying to pass the "Create a sales agreement and add a product" challenge in Sales Agreements and Forecasting in Manufacturing Cloud module](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007URi9uSAD)
四則演算とは

# 四則演算とは　
算術計算で最も基本的な4つの計算法である足し算、引き算、掛け算、割り算のこと。
| 　            |  定義 　|コード　|
|:-----------|------------:|:------------:|
| 足し算      | ＋      | 例 (num1 + num2 )         |
| 引き算     　 | ー      | 例 ( num1 - num2 )      |
| 掛け算     　 | *       | 例 ( num1 * num2 )         |
| 割り算        | /          |例 ( num1 / num2 )
| 余り      | ％      | 例 ( num1 % num2 )     |

```javascript 
  console.log( 5 ＋ 2 );　・・・出力結果　7
　 //5と２を足しているので出力すると７が表示されます
```
```javascript
  console.log( 6 / 3 ); ・・・　出力結果　２
 //6を２で割っているので出力すると２が表示されます
``` 

上記では数字を使いましたが、文字も足したりすることができます。

そのためにはまず　（"）ダブルクォート、（'）シングルクォート、
（`）バッククォートとで囲む必要があります。

|ダブルクォート　　　 　|シングルクォート　　　　| バッククォート |
|:-----------|------------:|:------------:|
| 　　　" | 　　　'　　　　| `        |
| 　　文字列　|　文字列　　| 変数の埋め込みや複数行の文字列      |
| 　("今日は") | （'いい天気'）　| （`）で囲んだ文字列内に ${< 変数名>} を埋め込むことができる  

上記の文字列を使った例です
```javascript
   let address = '東京都' ＋'千代田区';
   console.log(address);　//東京都と千代田区を足している   　　　
   出力結果　・・・　　東京都千代田区
```

```javascript
  let name = "佐藤さん";
  console,log(`こんにちは、${name}さん！`);　//nameを入れることで佐藤さんを出力することができる
  出力結果　・・・　こんにちは、佐藤さん！
```

## 最後に
　文字列と数値の違い
 "3"＋"5" は "35" という文字列になりますが、　3 ＋ 5 は 8になります。
 なので文字列と数値を入力する時は、別物だということを理解しておきましょう。

 また自分で文字や数値を変え、試してみるとより分かりやすいと思うのでぜひ試してみてください。
せっかくAWSの勉強をするので、インフラの基礎から勉強してみることにした #2

ただの備忘録です。
↑
~~これ書いとけば雑でも許されそう~~

# 超基礎用語の続き
### IPアドレス続き
- IPアドレスの範囲 
ネットワークを構築する際は、ネットワークで使うIPアドレスの範囲を決める。IPアド レスはネットワーク部とホスト部に区分けすることで、範囲を表記する。

- ネットワーク部
(192.168.128.)255、()に囲まれている部分がネットワーク 部、共通部となっている。 自分が使用しているネットワークに通信がくるようにしている。

- ホスト部
192.168.128.(255)、()に囲まれている部分がホスト部、可変部になっている。 どのデバイスに通信するかを決める。

- IPアドレスの表記法 
IPアドレスの表記には二種類の方法を用いる。

  - CIDR表記
IPアドレスの後ろに「/」を書き、その後ろにネットワーク部が先頭から何ビット目までなのかを記載する ※「192.168.128.0/24」のように表記する。これを二進数表記にする「11000000.10101000.10000000.11111111」になり、「11000000.10101000.10000000」 の24ビットがネットワーク部

  - サブネットマスク表記 
IPアドレスの後ろに「/」を書き、ネットワーク部分を表すビットと同じ部分を1に、ホスト部を表すビットと同じ部分を0にする。 ※「192.168.128.0/255.255.255.0」のように表記する 。

- IPアドレスとルーティング
インターネットでは、ルーターがIPアドレスの行先を管理しているので、ネットワークとネットワークがIPアドレスを通じて接続することができる（ルーティング）
  - インターネットゲートウェイ
  - インターネットとVPCを繋げる仮想のルーター
  - ネットワーク設計で考慮すべきポイント
  - プライベートIPアドレス範囲から指定する

## VPCの作成について
- VPCでは仮想のプライベートネットワーク空間を作成するので、プライベートIPアドレスの使用が推奨
- 作成後は変更できないので、大きめに設定する

- 大きさは/28 ~ /16。/16が推奨
- オンプレミスや他VPCのレンジと重複しないように気を付ける

- 相互接続する可能性がある場合は、重複しないように設計
- 異なるシステムの場合はアカウントを分ける

- 異なるシステムを同一アカウント内にいれると管理が煩雑になる
- 同一システムの各環境は、VPCとアカウントのどちらを分けるか?(本番環境、ステージング環境などがある場合)

  - 環境が違う場合、アカウントもVPCも同一のものを使用しない
  - VPCを分けると、IAMの設定が一度でよい。反面、各環境のリソースが見えてしまい、事故のもとになる
  - アカウントを分けると、他の環境のリソースが見えず、作業しやすい。反面、環境ごとにIAMの設定が必要
## サブネット設計のポイント

- 将来的に必要なIPアドレス数を見積もって設定する/24が標準的
- サブネットの分割は、ルーティングとアベイラビリティゾーンを基準に行う
- サブネットに割り当てられるルートテーブルは一つ

- インターネットアクセスの有無、拠点アクセスの有無などのルーティングポリシーに応じて分割する

- 高可用性のために、2つ以上のアベイラビリティゾーンを使用する

## やった作業
### VPC作成
- 手順　
  - リージョンを東京に
  - 検索欄でVPCを入力して検索し、ページへ移動
  - VPCの作成をクリック（デフォルトで作成してあるが基本使わない）
  - 名前タグを入力（お好みで）
  - CIDRを入力（今回は10.0.0.0/16とする）
  - CIDRブロックとテナンシーはお好みでチェック
  - VPC作成
  - サブネット作成
  - 手順
  - VPC画面左側のメニューからサブネットを選択（デフォルトは使用しない）
  - サブネットを作成
  - 作成したVPCを選択する
  - サブネット名を入力
  - アベイラビリティーゾーン選択（お好み）
  - subnet CIDR blockを入力（今回は10.0.10.0/24にする）
  - サブネット作成
  - 同じ要領でprivate subnetも作成する（CIDRは10.0.20.0/24にする）
### ルーティングの設定
- 手順
  - インターネットゲートウェイを作成する 
    - VPC画面左側のメニューからインターネットゲートウェイを選択 
    - 名前タグを入力して、インターネットゲートウェイの作成をクリック 
    - インターネットゲートウェイの一覧画面へ行き作成したものを選択 
    - 画面上にあるアクションからVPCにアタッチを選択 
    - 自分で作成したVPCを選択してアタッチする

  - ルートテーブルを作成する 
    - メニューからルートテーブルを選択 
    - 名前を入力 
    - 自分で作成したVPCを選択 
    - ルートテーブルを作成 
    - ルートテーブル一覧画面へ行き、作成したものを選択 
    - サブネットの関連付けを選択し、編集をクリック 
    - 作成したパブリックサブネットの方を選択し、関連付け

  - デフォルトルートをインターネットゲートウェイに設定する 
    - ルートテーブル一覧画面へ行き、作成したものを選択 
    - ルートタブを選択し、ルートを編集をクリック 
    - ルートの追加をクリック 
    - 送信先を0.0.0.0/0にする 
    - ターゲットをインターネットゲートウェイにする 
    - 作成したインターネットゲートウェイを選択する 
    - 変更を保存

今回は以上！

-----
記事を読んでくださった方は、是非弊社開発課のXもフォローしてください(人>ω•*)

https://twitter.com/tech_cin
`if numpy.isnan(pandas.NA)`で"boolean value of NA is ambiguous"というTypeErrorが発生した

# 環境
* Python 3.12.1
* pandas 2.2.0
* numpy 1.26.4

# 何が起きたのか
`if numpy.isnan(pandas.NA): pass`を実行したら、"boolean value of NA is ambiguous"という`TypeError`が発生しました。


```
In [52]: if numpy.isnan(pandas.NA):
    ...:     pass
    ...:
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[52], line 1
----> 1 if numpy.isnan(pandas.NA):
      2     pass

File missing.pyx:392, in pandas._libs.missing.NAType.__bool__()

TypeError: boolean value of NA is ambiguous
```

# 原因

`numpy.isnan(pandas.NA)`の結果は`pandas.NA`です。`pandas.NA`に対してbool値に変換しようとしたので、`TypeError`が発生しました。

```
In [51]: a = numpy.isnan(pandas.NA)

In [52]: if a: pass
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[52], line 1
----> 1 if a: pass

File missing.pyx:392, in pandas._libs.missing.NAType.__bool__()

TypeError: boolean value of NA is ambiguous
```

>Since the actual value of an NA is unknown, it is ambiguous to convert NA to a boolean value.[^1]

[^1]: https://pandas.pydata.org/docs/user_guide/missing_data.html#na-in-a-boolean-context


# 補足：少しハマったこと
`numpy.isnan()`という名前から、「`numpy.isnan()`にスカラー値を渡したらTrueかFalseを返すのだ」と、私は思っていたので、このエラー解決するのに少し時間がかかりました。


pandasは、numpyの[ufunc](https://numpy.org/doc/stable/reference/ufuncs.html)では`pandas.NA`を返すように実装しています。

>pandas.NA implements NumPy’s `__array_ufunc__` protocol. Most ufuncs work with NA, and generally return NA [^2]

[^2]: https://pandas.pydata.org/docs/user_guide/missing_data.html#numpy-ufuncs

`numpy.isnan()`もufuncです。したがって、`numpy.isnan(pandas.NA)`はbool値でなく`pandas.NA`を返すようです。


# 補足：`numpy.isnan`にarrayを渡したときの振る舞い

```

In [143]: d = numpy.array([1.1, pandas.NA, 3.3])

In [144]: d
Out[144]: array([1.1, <NA>, 3.3], dtype=object)

In [145]: numpy.isnan(d)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[145], line 1
----> 1 numpy.isnan(d)

TypeError: ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
```
【Flutter】MediaQueryのPadding、ViewPadding、ViewInsetsの違い

## はじめに
MediaQueryのPadding、ViewPadding、ViewInsetsの違いがわからなかったので調べました。

### ①viewInsets
システムUI（例えばキーボード）によって完全に隠されている画面の領域を指します。
主にキーボードが表示された時に、そのキーボードによって隠された画面の部分のサイズを示します。

https://api.flutter.dev/flutter/widgets/MediaQueryData/viewInsets.html


### ②padding
システムUIによって部分的に隠されているディスプレイの部分。通常、ハードウェアディスプレイの「ノッチ」やシステムステータスバーによって隠されています。
デバイスのノッチやステータスバーなど、システムUIによって部分的に使用される画面の余白を示します。

https://api.flutter.dev/flutter/widgets/MediaQueryData/padding.html

### ③viewPadding
viewPaddingもpaddingと同様に、システムUIによって部分的に使用される画面の余白を示しますが、キーボードが表示された場合でもその値を保持します。

https://api.flutter.dev/flutter/widgets/MediaQueryData/viewPadding.html




## 実際にみてみよう
文章だけだとイメージがつきずらいと思いますので、以下コードとデバッグ画面です。
```main.dart
void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    final mq = MediaQuery.of(context);
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: SafeArea(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Padding(
              padding: EdgeInsets.all(16.0),
              child: Center(
                child: TextField(
                  decoration: InputDecoration(
                    border: OutlineInputBorder(),
                    hintText: 'テキストフィールド',
                  ),
                ),
              ),
            ),
            Column(
              children: [
                Text('Padding.bottom: ${mq.padding.bottom}'),
                Text('ViewPadding.bottom: ${mq.viewPadding.bottom}'),
                Text('ViewInsets.bottom: ${mq.viewInsets.bottom}'),
              ],
            ),
          ],
        ),
      ),
    );
  }
}
```
| キーボードなし | キーボード表示時 |
|:-:|:-:|
|<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658262/ddd3bf96-d5a9-f448-346b-90ec7b8865f0.png">|<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658262/4d6f3493-170d-bea0-53e1-1597a14500ef.png">|

### キーボードが閉じている時の数値について
padding.bottomとviewPadding.bottomが34という数値は、これがデバイスのボトムエリア（例えば、ホームボタンがあるバーなど）の高さを表しています。この数値はデバイスや画面の解像度によって異なります。

viewInsets.bottomが0であるのは、キーボードが閉じている時には画面のどの部分もキーボードなどのシステムUIによって隠されていないためです。

### キーボード表示時の挙動について
キーボードが表示されると、viewInsetsの値が増加します。これは、キーボードが画面の一部を占めるため、その分の領域がviewInsetsに加算されるためです。

一方で、paddingの値が0になるのは、キーボード表示時には通常、画面の下部にあるシステムUI（例えばホームボタンがあるバーなど）が隠れるためです。その結果、その部分の余白が不要となり、padding.bottomが0にリセットされます。

viewPaddingは変化しないのは、この値がシステムUIによって部分的に使用される領域を示すものだからです。


## 参考
https://www.youtube.com/watch?v=ceCo8U0XHqw
それ，numpy で書かない？--6--

## それ，numpy で書かない？--6--

Python ではリストがよく使われる。また，for ループが遅いのでリストに特化したリスト内包表記も推奨されることが多い。

それなりの根拠があるからではあるが...

課題：リストではなく二次元配列を使う。
リストをうまく操ろうとしてリスト内包表記を濫用すると，とても見通しの悪い，醜いプログラムになる。

副次効果：他の部分のプログラムもシェープアップされる。

以下に，奇数魔方陣を作って，正しいかどうか検証するプログラムを二通り書いて比較してみる。

## 1. リストとリスト内包表記を使う
```python
def generate_odd_magic_square(n):
    magic_square = [[0] * n for _ in range(n)]
    num = 1
    i, j = 0, n // 2

    while num <= n * n:
        magic_square[i][j] = num
        num += 1
        new_i, new_j = (i - 1) % n, (j + 1) % n
        if magic_square[new_i][new_j]:
            i += 1
        else:
            i, j = new_i, new_j

    return magic_square

def print_magic_square(magic_square):
    for row in magic_square:
        print(" ".join(map(str, row)))

def check_magic_square(square):
    n = len(square)
    magic_constant = n * (n**2 + 1) // 2

    # 行の合計をチェック
    for row in square:
        if sum(row) != magic_constant:
            return False

    # 列の合計をチェック
    for j in range(n):
        col_sum = sum(square[i][j] for i in range(n))
        if col_sum != magic_constant:
            return False

    # 対角線の合計をチェック
    diagonal_sum1 = sum(square[i][i] for i in range(n))
    diagonal_sum2 = sum(square[i][n - 1 - i] for i in range(n))
    if diagonal_sum1 != magic_constant or diagonal_sum2 != magic_constant:
        return False

    return True
```


```python
n = 7
magic_square = generate_odd_magic_square(n)
print_magic_square(magic_square)
check_magic_square(magic_square)
```

    30 39 48 1 10 19 28
    38 47 7 9 18 27 29
    46 6 8 17 26 35 37
    5 14 16 25 34 36 45
    13 15 24 33 42 44 4
    21 23 32 41 43 3 12
    22 31 40 49 2 11 20

    True

## 2. Nupmhy ndarray を使う


```python
import numpy as np

def generate_odd_magic_square(n):
    magic_square = np.zeros((n, n), dtype=int)
    i, j = 0, n // 2

    for num in range(1, n**2 + 1):
        magic_square[i, j] = num
        new_i, new_j = (i - 1) % n, (j + 1) % n
        if magic_square[new_i, new_j]:
            i += 1
        else:
            i, j = new_i, new_j

    return magic_square

def check_magic_square(square):
    n = square.shape[0]
    magic_constant = n * (n**2 + 1) // 2

    # 行の合計をチェック
    if np.all(np.sum(square, axis=1) != magic_constant):
        return False

    # 列の合計をチェック
    if np.all(np.sum(square, axis=0) != magic_constant):
        return False

    # 対角線の合計をチェック
    return np.trace(square) == magic_constant and np.trace(np.fliplr(square)) == magic_constant

n = 9
test_square = generate_odd_magic_square(n)
print("生成された魔方陣:")
print(test_square)

if check_magic_square(test_square):
    print("魔方陣は正しいです。")
else:
    print("魔方陣は正しくありません。")

```

    生成された魔方陣:
    [[47 58 69 80  1 12 23 34 45]
     [57 68 79  9 11 22 33 44 46]
     [67 78  8 10 21 32 43 54 56]
     [77  7 18 20 31 42 53 55 66]
     [ 6 17 19 30 41 52 63 65 76]
     [16 27 29 40 51 62 64 75  5]
     [26 28 39 50 61 72 74  4 15]
     [36 38 49 60 71 73  3 14 25]
     [37 48 59 70 81  2 13 24 35]]
    魔方陣は正しいです。
コマンドライン文字列の解析

# コマンドライン文字列の解析

- 単純に空白で区切ると、二重引用符で囲まれたパスが正しく分割できない

## やりたいこと

### 入力

この文字列を

```batch
"C:\Program Files\Hoge\Fuga.exe" /opt1
```

### 出力

このように解析

|要素|値|
|---|---|
|0|`C:\Program Files\Hoge\Fuga.exe`|
|1|`/opt1`|

---

## 解決策１：System.CommandLine.dll で解析

- `System.CommandLine`を`nuget`で追加

```C#
using System.CommandLine.Parsing; // 拡張メソッドを使用するために必要

static string[] Parse_CommandLineDLL(string text)
{
    return new Parser().Parse(text).Tokens.Select(token => token.Value).ToArray();
}
```

---

## 解決策２：Win32API で解析

```C#
static class NativeMethods
{
  [DllImport("shell32.dll", SetLastError = true)]
  public static extern IntPtr CommandLineToArgvW([MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine, out int pNumArgs);

  [DllImport("kernel32.dll")]
  public static extern IntPtr LocalFree(IntPtr hMem);
}
```

```C#
static string[] Parse_Win32API(string text)
{
  var argsPtr = NativeMethods.CommandLineToArgvW(text, out var argsNum);
  if (argsPtr == IntPtr.Zero) throw new ArgumentException("Unable to split argument.", new Win32Exception());
  try
  {
    return Enumerable
      .Range(0, argsNum)
      .Select(i => Marshal.PtrToStringUni(Marshal.ReadIntPtr(argsPtr, i * IntPtr.Size)))
      .ToArray();
  }
  finally
  {
    NativeMethods.LocalFree(argsPtr);
  }
}
```

---

## 解決策３：正規表現で解析

```C#
static string[] Parse_RegEx(string text)
{
  return Regex.Matches(text, @"("".*?""|[^ ""]+)+").OfType<Match>()
              .Select(m => m.Groups[0].Value)
              .ToArray();
}
```

---

## まとめ

|解決策|メリット|デメリット|
|---|---|---|
|解決策１|`MS`公式|余計なライブラリが増える<br/>`netstandard2.0`or`net6`が必要|
|解決策２|`MS`公式<br/>ライブラリ不要|`Win32API`|
|解決策３|ライブラリ不要||
ReactのUIコンポーネントライブラリで特定の用途における比較をした

# 1. 背景
現在NuxtからReactにリプレイス中でUIコンポーネントライブラリを調査していた為です。
NuxtではElement-UIを使用していました。

# 2. 条件
## 2.1. Datepicker
カレンダーアイコン以外をクリックしてもカレンダーを開きたい

## 2.2. Cascader
複数選択時にチェックボックスだけでなくラベルを選択してもチェックしてほしい

以下が主要なライブラリだと思うのでこれらの条件を満たすか比較してみました。
- [MUI](https://mui.com/)
- [Ant-Design](https://ant.design/)
- [React-Bootstrap](https://react-bootstrap.netlify.app/)

https://npmtrends.com/@chakra-ui-vs-@chakra-ui/react-vs-@material-tailwind/react-vs-@mui/material-vs-@tailwindui/react-vs-antd-vs-react-bootstrap-vs-tailwindui

# 3. Ant Design と MUI と React-Bootstrap の比較

## 3.1. Datepicker
### Ant-Design
条件を満たせています。
https://ant.design/components/date-picker

https://gyazo.com/5bcb015481ebfb54877f8a4d031c2576

### MUI
カレンダーアイコンをクリックしないとカレンダーが表示されなかったです。
https://mui.com/x/react-date-pickers/date-picker/

https://gyazo.com/7066ddfdaa2f231176b448e8098a6745

### React-Bootstrap
https://react-bootstrap.netlify.app/docs/forms/overview/
LIVE EDITORのtype="email"をdateに変えて検証しました。
```ts
<Form.Control type="date" placeholder="Enter email" />
```
https://gyazo.com/ddf1043d20c6f42d32889efc6d7beb55
こちらもカレンダーアイコンをクリックしないとカレンダーが表示されなかったです。

## 3.2. Cascader

### Ant-Design
条件を満たせています。
https://ant.design/components/cascader#cascader-demo-showcheckedstrategy

https://gyazo.com/c534d6ef400e27094f194aa6580febc3

### MUI
Cascaderがないので作る必要があります。

https://github.com/mui/material-ui/issues/40275

https://github.com/mui/mui-x/issues/6019

MUI XのTree ViewとCheckboxで実現できるらしいです。

### React-Bootstrap
cascaderに関する情報が見当たらなかったです。

# 4.最後に
- Ant-Designに軍配が上がってるかなと思いました
- Ant-DesignはMUIよりカスタマイズ性が低いという記事を見かけたのでもう少し調査したいです

https://dev.to/idurar/the-ultimate-comparison-ant-design-vs-material-ant-design-vs-material-ui-which-react-ui-library-to-choose-2mkd

# 参考
- https://qiita.com/someone7140/items/96ad381b561b1650fbda
- https://kinsta.com/jp/blog/react-components-library/
情報量の加法性と平均情報量

# 情報量の加法性

　ある事象AとBが互いに独立して起きるとした場合、事象Aと事象Bが同時に起こった時の情報量Cは、それぞれの情報量の和で求めることができる。
 
 　例えば、コインを投げて表があるのを事象A、サイコロを投げて1が出るのを事象Bとした場合、1 + 約2.58 = 約3.58 → 4ビットの計算になる。

# 平均情報量

　すべての事象の平均的な情報量を平均情報量（エントロピー）と呼びます。
　平均情報量は曖昧さの程度を表す。平均情報量が小さいほど曖昧さが少なく、どの事象が起こるのか予測しやすいことを示す。逆に、平均情報量が大きいほど曖昧で、どの事象が起こるのか予測が難しくことを示す。
QiitaのAPI、webスクレイピング、GPTを使用して記事書いてみた！

:::note warn
本日の記事は「QiitaのAPI、webスクレイピング、GPTを使用して生成された記事」です。
次回以降でその仕組みを解説していきます！
:::

## `faster-whisper`とは

`faster-whisper`は、開発者がPythonで音声認識システムを構築するための高速かつ効率的なツールです。このフレームワークでは、ディープラーニングベースの手法を用いて、音声データを処理し、テキストに変換することができます。さらに、高速な処理を実現するために、ジョブの並列化と分散処理が組み込まれています。

`faster-whisper`の主な特徴は以下の通りです。

1. ディープラーニングベースの音声認識：`faster-whisper`は、最先端のディープラーニング技術を使用して、音声データを認識し、テキストに変換します。このため、高い精度で音声をテキストに変換することができます。

2. 高速な処理：`faster-whisper`は、高速な処理を実現するために、ジョブの並列化と分散処理をサポートしています。これにより、複数の音声ファイルを効率的に処理することができます。

3. 柔軟なオプション：`faster-whisper`は、さまざまなオプションを提供しています。例えば、ノイズの除去や音量の正規化など、音声データの前処理をカスタマイズすることができます。また、複数の言語モデルを選択することも可能です。

## インストールとセットアップ

`faster-whisper`を利用するには、まずPythonのパッケージマネージャを使用して、必要なライブラリをインストールする必要があります。以下のコマンドを実行して、`faster-whisper`をインストールします。

```bash
pip install faster-whisper
```

インストールが完了したら、以下のようにPythonスクリプトの先頭で`faster-whisper`をインポートします。

```python
import faster_whisper as fw
```

## テキスト変換の基本

まずは、入力として与えられた音声データをテキストに変換する基本的な使い方を見ていきましょう。以下のコードは、ファイルから音声を読み込み、その音声データをテキストに変換する例です。

```python
audio_file = "sample_audio.wav"

audio = fw.load_audio(audio_file)
text = fw.transcribe(audio)

print(text)
```

このコードでは、`fw.load_audio`関数を使用して音声データを読み込み、`fw.transcribe`関数を使用して音声データをテキストに変換しています。変換されたテキストは、`text`変数に格納され、出力されます。

### 言語モデルの選択

`faster-whisper`では、デフォルトのスピーチ認識モデル以外にもさまざまな言語モデルを選択することができます。以下のコードは、英語の音声を認識するために英語の言語モデルを使用する例です。

```python
audio_file = "english_audio.wav"
language_model = "english_model"

audio = fw.load_audio(audio_file)
text = fw.transcribe(audio, language_model=language_model)

print(text)
```

このコードでは、`language_model`引数を使用して、英語の言語モデルを選択しています。選択された言語モデルに基づいて、音声データがテキストに変換されます。

## 分散処理とジョブの並列実行

`faster-whisper`は、データ処理の高速化のために、分散処理とジョブの並列実行をサポートしています。以下のコードは、複数の音声ファイルを並列で処理する例です。

```python
audio_files = ["audio1.wav", "audio2.wav", "audio3.wav"]
num_processes = 4

texts = fw.transcribe_parallel(audio_files, num_processes)

for i, text in enumerate(texts):
    print(f"Text from audio file {i+1}: {text}")
```

このコードでは、`fw.transcribe_parallel`関数を使用して、指定された数のプロセスを使用して複数の音声ファイルを同時に処理します。変換されたテキストは、リストとして返され、それぞれの音声ファイルに対応するテキストを表示します。

## 結論

この記事では、Pythonで音声認識を行うための最新のツールである`faster-whisper`について紹介しました。`faster-whisper`は、高速な処理と柔軟なオプションを提供し、開発者が音声データをテキストに変換する際の効率を向上させることができます。ぜひこのガイドを参考にして、自身のプロジェクトに`faster-whisper`を活用してみてください。

::: note 
AIが生成した記事はいかがでしたか？
作成にあたっての過程をまとめた記事の前編・後編を公開しました！
お役に立てれば光栄です。
https://qiita.com/shimada_slj/items/cfded87a32d4d13c6907
(2024.3.7 公開)

https://qiita.com/shimada_slj/private/d3e11a08cddc9f88b925
(2024.3.18　公開)
:::
CLI +α メモず【Docker rubocop VSCode】

# はじめに
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">たま は rubocop --auto-correct-all を 覚えた！！⚔️⚔️</p>&mdash; たま / RUNTEQ53A (@SamuraiStats) <a href="https://twitter.com/SamuraiStats/status/1755722336672825594?ref_src=twsrc%5Etfw">February 8, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

普段使っているコマンドにも、
- ❓実はよくわかっていない疑問
- 📝使いこなすと便利なもの

があるなあと思いましたので、まとめて記事にします。
トピックは独立していますので、興味のあるトピックをお読みください。
# メモず
## Docker
### ❓`docker compose`と`docker container`の違い
> Docker の `compose` と `container` について、代表的なコマンドとその効果を簡単な一覧で比較します。これらは Docker の異なる側面を操作するためのツールで、`docker-compose` は複数のコンテナーを定義し、実行するために使用され、`docker container` コマンドは単一のコンテナーを管理するために使われます。
> 
> #### Docker Compose
> 
> - **コマンド**: `docker-compose up`
>   - **効果**: `docker-compose.yml` に定義されたサービス（コンテナー）を作成して起動します。これは一般に複数のコンテナーが関連して動作するアプリケーションで使用されます。
> - **コマンド**: `docker-compose down`
>   - **効果**: `docker-compose up` で起動したサービスを停止し、関連するネットワーク、ボリュームと共に削除します。
> - **コマンド**: `docker-compose build`
>   - **効果**: サービスのビルドを行います。これは主に、Dockerfile に基づいてコンテナーイメージをビルドする際に使用されます。
> 
> #### Docker Container
> 
> - **コマンド**: `docker container run`
>   - **効果**: 新しいコンテナーを作成し、起動します。これはイメージ名を指定して単一のコンテナーを実行する際に使われます。
> - **コマンド**: `docker container stop`
>   - **効果**: 実行中のコンテナーを停止します。これは指定したコンテナーIDまたは名前に対して使用されます。
> - **コマンド**: `docker container rm`
>   - **効果**: 停止されたコンテナーを削除します。これは不要になったコンテナーのクリーンアップに使われます。
> 
> この一覧は、Docker を使ってコンテナーを操作する際の基本的なコマンドとその効果を示しています。Docker Compose は主に開発環境や複数コンテナーを含むアプリケーションの管理に適しているのに対し、`docker container` コマンドは単一コンテナーの細かな管理に役立ちます。

## rubocop
### 📝自動修正：`rubocop --auto-correct-all`
rubocopの文法エラーは、
- エンジニアの慣習を知ることができる
- 統一感のあるコードが書ける

というメリットがありますが、一方で
- ひとつひとつ修正するのは時間がかかる
- Railsによって生成されたコードが引っかかると、「書いたの自分じゃないんだけどなあ・・・」となる。

というデメリットがあります。
#### `rubocop --auto-correct-all`
そんな面倒を解決するのが、`rubocop --auto-correct-all`です。
rubocopのエラーの中には、`auto+correctable`なエラー（自動修正可能なエラー）
があり、`rubocop --auto-correct-all`はそのエラーを自動で修正してくれます。

# VSCode 
## 📝ターミナルから起動 `code .`
`code`はVSCodeのコマンドです。
`code .`で、現在のディレクトリをVSCodeで起動できます。

特に **WSLユーザー（WindowsでLinuxコマンドを使用できるツール）** の場合、
WSLターミナルから直接VSCodeを開けるというメリットがあります。
（VSCode側からWSL上のプロジェクトを開くのは面倒）
[WSL上でエディタを開く@VSCode](https://qiita.com/kohki_takatama/items/c239aec4e70d5b1bd6bc)

# おわりに
Dockerの疑問、rubocop / VSCodeの便利機能についてでした。
お読みいただきありがとうございました。