OmniAICreator/Qiita-1.07M huggingface dataset:
What is トランザクション分離レベル ?

# トランザクション分離レベル
トランザクション分離レベルとは、データベース内で同時に実行される複数のトランザクションが互いにどの程度干渉しないようにするかを制御する設定です。これにより、データの一貫性を保ちながら、複数のトランザクションが同時に操作できるようにします。分離レベルが低いほどトランザクション間の干渉が増えますが、パフォーマンスが向上し、分離レベルが高いほどデータの整合性が強化されますが、パフォーマンスに影響が出る可能性があります。

| レベル              | 特徴                                                                 |
| ------------------- | -------------------------------------------------------------------- |
| **Read uncommitted** | ダーティリード、反復不能読み取り、ファントムリード、直列化異常が起こる       |
| **Read committed**   | 反復不能読み取り、ファントムリード、直列化異常が起こる                     |
| **Repeatable read**  | ファントムリード、直列化異常が起こる                                   |
| **Serializable**     | ダーティリード、反復不能読み取り、ファントムリード、直列化異常のいずれも起こらない |

## 1. Read Uncommitted（読取り非コミット）

**特徴:**
- トランザクションがコミットされていない変更も他のトランザクションから見える状態です。
- 他のトランザクションによってまだコミットされていないデータを読み取ることができるため、最も低い分離レベルです。

**問題点:**
- **ダーティリード**: 他のトランザクションがコミットしていない変更を読み取ってしまう可能性があります。そのため、そのトランザクションがロールバックされた場合、読み取ったデータが無効になるリスクがあります。
- **反復不能読み取り**: 同じクエリを複数回実行しても、異なる結果が返る可能性があります。これは、他のトランザクションがデータを変更する可能性があるためです。
- **ファントムリード**: 同じクエリを繰り返して実行すると、前回のクエリには存在しなかった行が新たに現れることがあります。
- **直列化異常**: 複数のトランザクションが同時に実行されることで、処理結果が直列実行とは異なる結果になる可能性があります。


## 2. Read Committed（読取りコミット）

**特徴:**
- トランザクションがコミットされた変更のみが他のトランザクションから見える状態です。
- PostgreSQLでは、デフォルトの分離レベルです。

**問題点:**
- **反復不能読み取り**: 同じトランザクション内であっても、同じクエリを複数回実行した場合に、異なる結果が返る可能性があります。他のトランザクションがその間にコミットを行ってデータを変更した場合、この現象が起こります。
- **ファントムリード**: 同じクエリを繰り返して実行すると、前回のクエリには存在しなかった行が結果セットに新たに現れることがあります。
- **直列化異常**: 複数のトランザクションが同時に実行されることで、処理結果が直列実行とは異なる結果になる可能性があります。

## 3. Repeatable Read（リピート可能読み取り）

**特徴:**
- トランザクションが開始された時点で存在するデータを基にして、クエリが実行されます。つまり、同じトランザクション内で同じクエリを複数回実行しても、常に同じ結果が返されます。
- 他のトランザクションによる変更が、現在のトランザクション内で見えないようにすることができます。

**問題点:**
- **ファントムリード**: 他のトランザクションが新しい行を挿入した場合、同じクエリを実行したときに、以前は存在しなかった行が結果に含まれることがあります。
- **直列化異常**: 他のトランザクションによる新規データの挿入がトランザクション内で見えないため、データの一貫性が完全には保証されない可能性があります。

## 4. Serializable（直列化可能）

**特徴:**
- 最も高い分離レベルであり、すべてのトランザクションが順次（直列に）実行されたかのように動作します。
- データの一貫性が最も強く保証され、ファントムリードや直列化異常が発生しないように設計されています。

**メリット:**
- **ダーティリード、反復不能読み取り、ファントムリード、直列化異常**のいずれも発生しません。データベース内のデータ整合性が完全に保たれます。

**デメリット:**
- トランザクションの同時実行性が大幅に制限されるため、システムのパフォーマンスに影響を与える可能性があります。特に、ロックの競合が増えると、トランザクションの実行が遅くなることがあります。
相対パスと絶対パスの違いを理解しよう！【初心者向けファイルパス入門】

# はじめに

ファイルを操作する際、「相対パス」と「絶対パス」という概念に出会うことがよくあります。しかし、初めての方にとってはその違いや使い分けが分かりにくいかもしれません。この記事では、これらの概念をわかりやすく解説します！

---

## 1. パス（Path）とは？

**パス**は、コンピュータ内の特定のファイルやフォルダの場所を指定するための情報です。ファイルシステムは、階層構造でディレクトリ（フォルダ）やファイルを整理していますが、パスを使うことでファイルの場所を一意に特定できます。

パスには大きく分けて2つの種類があります：
- **絶対パス** (Absolute Path)
- **相対パス** (Relative Path)

---

## 2. 絶対パスとは？

**絶対パス**は、システムのルートディレクトリ（Windowsならドライブのルート、LinuxやmacOSなら`/`）からファイルやフォルダまでの完全なパスを指します。これは、どこから参照しても変わらない「ファイルの正確な位置」を指定する方法です。

### 絶対パスの例

- **Windows**の場合：
  ```
  C:\Users\Username\Documents\project\file.txt
  ```

- **Linux/macOS**の場合：
  ```
  /home/username/Documents/project/file.txt
  ```

上記のように、絶対パスは常にルートから始まるため、そのファイルやディレクトリがどの場所にあっても、常に一意に特定できます。

### 絶対パスのメリット
- **どこからでもアクセス可能**：どのディレクトリにいても、同じパスで目的のファイルにアクセスできる。
- **一貫性がある**：ファイルの位置が変わらない限り、正確なパスを保証できる。

### 絶対パスのデメリット
- **長くなりがち**：ディレクトリ構造が深くなるほど、パスが長くなってしまう。
- **移動に弱い**：他のシステムにプロジェクトを移動すると、絶対パスが無効になることがある。

---

## 3. 相対パスとは？

**相対パス**は、現在の作業ディレクトリ（カレントディレクトリ）からの距離（相対的な位置）を使ってファイルやフォルダを指定する方法です。相対パスは、参照元のディレクトリに依存するため、ファイルやフォルダの位置を柔軟に指定できます。

### 相対パスの例

今、自分が以下のようなディレクトリ構造にいるとします：
```
/home/username/Documents/project/
```

この場所から `file.txt` にアクセスする場合の相対パスは：
```
./file.txt
```

他のディレクトリ内のファイルを参照する場合：
```
../other_project/file.txt  # 上のディレクトリに移動してアクセス
```

- `.` は現在のディレクトリを指します。
- `..` は一つ上のディレクトリを指します。

### 相対パスのメリット
- **柔軟性が高い**：プロジェクトを他の場所に移動しても、ファイルやディレクトリの位置が相対的に同じならパスが機能します。
- **パスが短い**：作業ディレクトリから近いファイルなら、短いパスでアクセスできる。

### 相対パスのデメリット
- **参照元に依存**：カレントディレクトリが異なると、同じ相対パスが機能しなくなることがある。

---

## 4. 絶対パスと相対パスの使い分け

### 4-1. 絶対パスを使う場面
- **確実にファイルにアクセスしたい**：どのディレクトリからでも同じパスでアクセスできる必要がある場合。
- **システム設定ファイル**：例えば、システムの設定や環境変数で、確実に特定のファイルにアクセスしたいときは絶対パスを使います。

### 4-2. 相対パスを使う場面
- **プロジェクト内での柔軟性を持たせたい**：同じプロジェクト内で、フォルダ構成が変わっても簡単に移動できるようにするため。
- **ファイルを移動する可能性がある場合**：プロジェクトを他の環境やディレクトリにコピーすることが多い場合は、相対パスが便利です。

---

## 5. よくある質問（FAQ）

### Q1. 相対パスと絶対パス、どちらを使うべき？
- **短期間のスクリプトやプロジェクト内**では相対パスが便利です。
- **長期間維持する設定ファイルやシステム管理**には、絶対パスを使うことで信頼性を確保できます。

### Q2. Web開発での相対パスと絶対パスはどう違う？
- **Webサイト**の開発では、相対パスは他のページやリソース（画像やCSSファイルなど）をリンクする際に頻繁に使用されます。
- **絶対パス**は、他のドメインや外部リソースを指す場合に使用されます（例：`https://example.com/path/to/resource`）。

---

## 6. まとめ

- **絶対パス**は、ファイルシステム全体で一意のパスを指定でき、どこからでもアクセス可能ですが、柔軟性に欠けることがあります。
- **相対パス**は、プロジェクト内や特定の環境でファイルの位置を柔軟に指定できる便利な方法ですが、参照元に依存します。

使い分けを理解することで、効率的にファイルを管理・操作できるようになります。両者の違いをしっかりと押さえて、適切に使いこなしていきましょう！
Pandas 基礎操作 逆引きガイド【これをしたい時は？】

## はじめに

Pandasを使って「〇〇したい」という具体的な目的に対して、どう操作すればよいのかを逆引き形式でまとめました。これさえ見れば、よくあるPandas操作にすぐに対応できるはず！

---

## 1. データの準備

### 1-1. CSVファイルを読み込みたい
```python
df = pd.read_csv('ファイル名.csv')
```

### 1-2. Excelファイルを読み込みたい
```python
df = pd.read_excel('ファイル名.xlsx')
```

### 1-3. データフレームをCSVファイルに書き出したい
```python
df.to_csv('保存先.csv', index=False)
```

### 1-4. データフレームをExcelファイルに書き出したい
```python
df.to_excel('保存先.xlsx', index=False)
```

---

## 2. データの確認

### 2-1. 最初の数行だけ確認したい
```python
print(df.head())  # デフォルトは最初の5行
```

### 2-2. データの統計情報を確認したい
```python
print(df.describe())
```

### 2-3. データの列名や行数、データ型を確認したい
```python
print(df.columns)  # 列名
print(df.shape)    # 行数と列数
print(df.dtypes)   # データ型
```

---

## 3. データの選択・フィルタリング

### 3-1. 特定の列を選択したい
```python
print(df['列名'])  # 列を選択
```

### 3-2. 特定の行を選択したい
```python
print(df.loc[行番号])  # 行番号で行を選択
```

### 3-3. 条件に合う行を抽出したい
```python
filtered_df = df[df['列名'] > 条件値]
```

例：年齢が30以上のデータを抽出
```python
filtered_df = df[df['年齢'] >= 30]
```

---

## 4. データの加工

### 4-1. 新しい列を追加したい
```python
df['新しい列名'] = データ
```

例：他の列を基に新しい列を追加
```python
df['年収'] = df['時給'] * 2000  # 時給×2000時間で年収を計算
```

### 4-2. 列のデータを更新したい
```python
df['列名'] = df['列名'].replace(置換前, 置換後)
```

### 4-3. 列を削除したい
```python
df = df.drop(columns=['削除したい列名'])
```

### 4-4. 重複する行を削除したい
```python
df = df.drop_duplicates()
```

---

## 5. データの集計・グループ化

### 5-1. 列ごとの合計や平均を計算したい
```python
print(df['列名'].sum())  # 合計
print(df['列名'].mean())  # 平均
```

### 5-2. 特定の列でグループ化し、集計したい
```python
grouped = df.groupby('列名')['集計対象列名'].sum()  # 合計
print(grouped)
```

例：職業ごとに年齢の平均を計算
```python
grouped = df.groupby('職業')['年齢'].mean()
print(grouped)
```

### 5-3. ピボットテーブルを作りたい
```python
pivot_df = df.pivot_table(values='集計対象列名', index='行にしたい列名', columns='列にしたい列名', aggfunc='集計関数')
```

---

## 6. データの欠損値を処理したい

### 6-1. 欠損値を確認したい
```python
print(df.isnull().sum())  # 列ごとの欠損値の数を表示
```

### 6-2. 欠損値を削除したい
```python
df = df.dropna()
```

### 6-3. 欠損値を特定の値で埋めたい
```python
df['列名'] = df['列名'].fillna(埋めたい値)
```

---

## 7. データのソート（並び替え）

### 7-1. 列の値でソートしたい
```python
df_sorted = df.sort_values(by='列名', ascending=True)  # 昇順（小さい順）
```

例：年齢の降順でソート
```python
df_sorted = df.sort_values(by='年齢', ascending=False)  # 降順（大きい順）
```

---

## 8. 応用操作

### 8-1. 複数のDataFrameを結合したい
```python
# 縦方向に結合（行を追加）
df_combined = pd.concat([df1, df2])

# 横方向に結合（列を追加）
df_merged = pd.merge(df1, df2, on='共通の列名')
```

### 8-2. 行や列を転置したい
```python
df_transposed = df.T  # 行と列を入れ替え
```

---

## まとめ
この逆引きガイドでは、Pandasで「何をしたいか」に対応する基本的な操作方法を紹介しました。これを参考に、さまざまなデータ操作を素早く実現してください！

他のデータ解析の記事

https://qiita.com/mizomizo1/items/94a3881cd08bc392d6d4
【OpenAI o1】にお酒のカクテルについて聞きました。


　どうも、カーブミラーです。

　今回は、【OpenAI o1】にお酒のカクテルについて聞きました。

:::note info
本記事は、ChatGPT（有料版）
で行なっております。画像は
ありません。　あしからず。
:::
　まずは、ニュースです。

　New York Timesによると、
　　OpenAI社がChatGPTの値上げを
　　　予定しているそうです。

　現在20米ドルですが、
　　今年末までに22米ドルに、
　　　5年以内に44米ドルに
　　　　引き上げられるとか。
　　　　　[ML_Bearさんポスト](https://x.com/MLBear2/status/1839886477867790630?t=3S_zfkJRrRs7TggAciWLZw&s=19)

　22米ドルなら仕方ないと思うけど、
　　それ以上にはならんで欲しい😞
***
　さて、本題です。

　今回は、
　　【OpenAI o1】に
　　　お酒のカクテルについて
　　　　聞きました。

　ええ、飲んでる席で
　　やりましたとも😅

　カクテルには
　　実にたくさんのものが
　　　あります。

　ベースとなる
　　お酒の種類からして
　　　たくさんあります。

　そこに
　　いろいろと入れて
　　　シェイクするなり
　　　　ステアするなりして
　　　　　提供されます。

　中には、
　　お酒の比重の差を利用して
　　　作られる“レインボー”という
　　　　カクテルもあります。

　まぁ、今回の目的は、
　　【OpenAI o1】が
　　　　どのような回答を
　　　　　　出してくるのか、
　　　　　　　　という点ですね。

　やり取りをどうぞ。
***
***●user***
カクテルについて教えて

***o1-mini***
カクテルについてご説明いたします。

カクテルとは
**カクテル（Cocktail）**とは、主にアルコール飲料をベースに、リキュール、ジュース、シロップ、苦味料、スパイスなど様々な材料を混ぜ合わせた飲み物の総称です。見た目の美しさや味わいのバランスを重視して作られることが多く、バーやパーティーなどで楽しまれています。
（歴史、有名なもの、作り方基本）
（楽しむ際のポイント）

まとめ
カクテルは多様な味わいと美しい見た目で、多くの人々に愛されています。自宅で手軽に楽しめるものから、バーで専門的に作られるものまで、バリエーションは無限大です。興味があれば、ぜひいくつかのレシピを試して、自分だけのお気に入りカクテルを見つけてみてください。

***●user***
ジンベースのカクテル

***o1-mini***
（数種のレシピを出してきた）

***●user***
誰もレシピは聞いていません

***o1-mini***
申し訳ありません。ご希望に沿わずレシピを詳しくご紹介してしまいました。

ジンをベースにしたカクテルについて、レシピを省いて概要や特徴のみをご紹介いたします。

（ジンベースの代表的なカクテル）
（楽しむポイント）

まとめ
ジンは多様な風味と香りを持つスピリッツで、さまざまなカクテルに応用できる非常に魅力的なベースです。クラシックなものからモダンな創作カクテルまで、ジンベースのカクテルを楽しむことで、豊かな飲み物の世界を堪能できます。

もし他に知りたい情報や具体的なご要望がございましたら、お知らせください。

***●user***
ジンは、ボンベイサファイアです。

***o1-mini***
ボンベイ・サファイア（Bombay Sapphire）について詳しくご紹介いたします。

（助長なので割愛）

***●user***
ボンベイサファイアで作れるカクテルのリストを作成してください。

***o1-mini***
ボンベイ・サファイア（Bombay Sapphire）を使用して作れる代表的なカクテルのリストをご紹介します。これらのカクテルは、その繊細で複雑な風味を活かし、さまざまなシーンで楽しむことができます。

（カクテル一覧10件）
（その他を4件）
（楽しむ際のポイント）

ボンベイ・サファイアを使ったカクテルは、その多様なボタニカルの風味を活かして、さまざまなバリエーションが楽しめます。ぜひお気に入りのカクテルを見つけて、豊かな味わいをお楽しみください。
***

　今回は、
　　思考過程を入れませんでした。
　　　2〜3秒だと、たいして考えて
　　　　いませんからね。

　まぁ、この程度の質問なら、
　　GPT-4oで充分なわけで
　　　わざわざ【OpenAI o1】を
　　　　使う必要もなかったんです😸

　ただ、【OpenAI o1】は、
　　ユーザーの意図を
　　　推し量るのではなく、
　　　　すべてを出そう、としてきます。

　試しに
　　ふたつ送信しました。
```Text:試しのPrompt１
カクテルについて教えて。
あなたは足りない情報があるならば、私に尋ねてください。
```
```Text:試しのPrompt２
カクテルについて教えて。
私の意図を測りかねるときは、私に尋ねてください。
```

　どちらも回答はほぼ同じですし、
　　尋ねてくれることは
　　　ありませんでした。

　そこで質問をしてみました。
***
***●user***
“カクテルについて教えて”

ここから私の意図を推し量れますか？

***o1-mini***
もちろんです。あなたが「カクテルについて教えて」とおっしゃったことから、以下のような情報を求めていると推測できます：

1. **カクテルの基本情報**:
   - カクテルの定義や歴史について知りたい。
   - 代表的なカクテルの種類やその特徴。

2. **カクテルのレシピや作り方**:
   - 自宅で簡単に作れるカクテルのレシピ。
   - バーテンダー向けの高度なカクテルの作り方。

3. **おすすめのカクテル**:
   - 季節やシチュエーションに合わせたおすすめのカクテル。
   - 人気の高いカクテルや新しいトレンドについて。

4. **カクテルに関する文化やマナー**:
   - カクテルを楽しむ際の基本的なマナーやエチケット。
   - 世界各国のカクテル文化の違い。

もし具体的な情報や特定のカクテルについて知りたい場合は、ぜひ教えてください。さらに詳しくお答えいたします。
***

　少なくとも
　　これらのいずれかを
　　　ユーザーが望んでいることは
　　　　わかっているようですね。

　だから
　　【OpenAI o1】は
　　　　これらすべてを満たすべく、
　　　　　　情報を提出した、という
　　　　　　　　ことなのでしょうね。

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
ステージングされていない変更を破棄してブランチを移る

# ブランチを移動したいけど変更したところを戻せなくて移動できない！
となったことはありませんか？

:::note alert
gitでは、衝突する変更を含む場合はブランチを移ることができません
（衝突しないなら可能）
:::

チーム開発の際、余計な変更も含めてcommitしてしまうと、
変更履歴が汚くなってしまいます😭

# 指針としては
:::note info
・変更を保持したまま、ブランチを移る
・変更を破棄してブランチを移る
:::
この二つがあると思います。

# 変更を保持したまま、ブランチを移る
*変更を一時保存する*
```
git stash
```
*ブランチを移動する*
```
git checkout 移りたいブランチ名
```
*必要に応じてstashした変更を戻す*
```
git stash pop
```
# 変更を破棄して、ブランチを移る
*変更を破棄する*
```
git checkout -- .
```
*ブランチを移る*
```
git checkout 移りたいブランチ名
```
（まあGPTに聞けば出てくることではあるんですけどねw）
Tkinterを使ってみた

pythonの標準ライブラリ `Tkinter`
これを使うと簡単にデスクトップアプリが作れるらしい。

というわけで使ってみた。
---
できたもの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3840203/cd0ea26d-8c41-ad2d-f9d9-d95ae2e1efa0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3840203/65081569-29cb-e91f-f39e-5b62a98b4e23.png)

## コード

```python
import tkinter as tk

root = tk.Tk()

root.title("簡単なデスクトップアプリ")

root.geometry("300x200")

label = tk.Label(root, text="Hello, World!")
label.pack(pady=20)

def on_button_click():
    label.config(text="ボタンがクリックされました!")

button = tk.Button(root, text="クリック", command=on_button_click)
button.pack(pady=10)

root.mainloop()
```

## コードの解説

### 1. `import tkinter as tk`
- **`import`**: 他のモジュールをプログラムに読み込むためのPythonの予約語
- **`tkinter`**: Python標準ライブラリの1つで、GUIアプリケーションを作成するためのツールキット
- **`as tk`**: モジュールにエイリアス（別名）を付けるための構文。ここでは`tkinter`を短く`tk`という名前で使用している
```python
import tkinter as tk
```
### 2. `root = tk.Tk()`
- **`tk.Tk()`**: `Tk`クラスのインスタンスを生成する。`Tk`は`tkinter`でアプリケーションのメインウィンドウを作成するためのクラス。`root`はこのウィンドウを参照する変数
```python
root = tk.Tk()
```
### 3. `root.title("簡単なデスクトップアプリ")`
- **`title`**: メインウィンドウのタイトル（ウィンドウ上部に表示される文字列）を設定するためのメソッド
```python
root.title("簡単なデスクトップアプリ")
```
### 4. `root.geometry("300x200")`
- **`geometry`**: ウィンドウのサイズ（幅と高さ）を指定するためのメソッド。ここでは`300x200`ピクセルのウィンドウを設定している
```python
root.geometry("300x200")
```
### 5. `label = tk.Label(root, text="Hello, World!")`
- **`tk.Label`**: `Label`は、テキストや画像などを表示するためのウィジェット（GUI要素）。ここでは、メインウィンドウ（`root`）に「Hello, World!」というテキストを表示するラベルを作成している
- **`text="Hello, World!"`**: ラベルに表示するテキストを指定している
```python
label = tk.Label(root, text="Hello, World!")
```
### 6. `label.pack(pady=20)`
- **`pack`**: ウィジェットをウィンドウに配置するためのメソッド。`pack`は、ウィジェットを順番に縦または横に並べるレイアウトマネージャー
- **`pady=20`**: ウィジェットの上下に20ピクセルの余白（padding）を追加する
```python
label.pack(pady=20)
```
### 7. `def on_button_click():`
- **`def`**: 関数を定義するためのPythonの予約語
- **`on_button_click`**: ボタンが押されたときに実行される関数。この関数はボタンのクリックイベントに関連付けられている
```python
`def on_button_click()
```
### 8. `label.config(text="ボタンがクリックされました!")`
- **`label.config`**: 既存のラベルの設定を変更するためのメソッド。ここではラベルのテキストを「ボタンがクリックされました!」に変更した
```python
label.config(text="ボタンがクリックされました!")
```
### 9. `button = tk.Button(root, text="クリック", command=on_button_click)`
- **`tk.Button`**: `Button`は、ユーザーがクリックできるボタンを作成するウィジェット
- **`text="クリック"`**: ボタンに表示するテキストを指定している（ここでは「クリック」）
- **`command=on_button_click`**: ボタンがクリックされたときに実行する関数を指定する。ここでは先に定義した`on_button_click`関数が呼び出される
```python
button = tk.Button(root, text="クリック", command=on_button_click)
```
### 10. `button.pack(pady=10)`
- **`pack`**: ウィジェットをウィンドウに配置するためのメソッド。今回はボタンをメインウィンドウに追加している
- **`pady=10`**: ボタンの上下に10ピクセルの余白を追加している
```python
button.pack(pady=10)
```
### 11. `root.mainloop()`
- **`mainloop`**: アプリケーションのメインループを開始する。このメソッドが呼び出されると、ユーザーがウィンドウを閉じるまでプログラムが実行され続ける。イベント処理（ボタンのクリックなど）もこのループ内で行われる
```python
root.mainloop()
```
---

他にも色んなウィジェットがあるらしいので、しばらくは模索していく予定
gitHub Codespace で localhost に GETリクエストする際の注意点

## 動機
gitHub の codespace は簡単に開発環境が用意できますが、開発中に localhost へ接続したい場合は、Codespace のポートフォワーディングを用いて、ブラウザから接続しないといけません。

今回、クライアント側から Codespace 上のサーバーに ```fetch``` を使った GETリクエストを送る際に、エラーが出てはまってしまったので、それへの対処法をまとめました。

## 環境
- gitHub Codespace (default 設定）
- Next.js 14.2.3

## エラーの発生状況
1. gitHub の開発リポジトリから Codespace を起動。その際、3000番ポートが 動的 URL ( https://expert-***-3000.app.github.dev など) に紐づけられる (ポートフォワーディング)
1. Codespace の ターミナルで Next.js サーバーを起動 (3000番ポート) 
``` npm run dev ```
1. バックエンドサーバーの API (例えば、https://expert-***-3000.app.github.dev/api/read)に JSONデータを GETリクエストする
``` javascript
const response = await fetch("https://expert-***-3000.app.github.dev/api/read");
  
const jsonData = await response.json();
```
4. . この際に、``` response ``` に JSONデータではなく、HTMLが返されてしまい、``` response.json() ``` がエラーになる

## 原因
Codespace のポートフォワーディングでは、ポートの "表示範囲" が ``` private``` だとフォワーディング時に認証が必要になる（参考: [GitHub Codespaces](https://qiita.com/unhurried/items/6dc82566ba63b22971ab#%E7%B0%A1%E5%8D%98%E3%81%AA%E4%BD%BF%E3%81%84%E6%96%B9)）。
そのため、```fetch``` で GETリクエストした際に認証ページにリダイレクトされ、その HTML が返ってきたと思われる。

## 対処法
Codespace のポート設定で、該当のポート（この場合は 3000) の "表示範囲" を ```public``` にする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881047/115cf180-b72b-731b-43fd-d410762c8d30.png)

これでちゃんと JSON データが返ってくるようになった。
SJISのログをUTF8のターミナルで見る

Shift_JISのログをターミナルで、catやtailするときに日本語が文字化けしちゃうときの対応方法

## cat の場合

~~~
cat logfile | while read LINE ; do echo $LINE | iconv -f SJIS -t UTF-8 ; done
~~~

## tail の場合

~~~
tail -F logfile | while read LINE ; do echo $LINE | iconv -f SJIS -t UTF-8 ; done
~~~
ECS作成後にサービスのネットワーク構成を変更したい！

# はじめに
ECS作成後にサービスのネットワーク構成を変更しようとしても、コンソール上から変更できないことに最近気がつきました。（2024/09/28現在）

調べていくうちに、AWS CLI であるコマンドを実行するとサービスのネットワーク構成を変更できることを知ったのでその方法を記事にします。
<br>
この記事は[AWS CLI コマンドリファレンス](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecs/update-service.html)を基に作成しています。
# サービスのネットワーク構成を変更する方法
### 手順1. CloudShellを起動する
コンソールの画面右上の、赤枠の部分からCloudShellを起動できます。

<img width="600px" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551848/b3194ba2-9b0f-0a6f-d1ef-e752d8758493.png
">

### 手順2. コマンド実行
```
$ aws ecs update-service \
  --cluster 【ECS クラスター名】 \
  --service 【ECS サービス名】 \
  --network-configuration "awsvpcConfiguration={subnets=[【サブネット ID】],securityGroups=[【セキュリティグループ ID】],assignPublicIp=【DISABLED/ENABLED】}"
```
上記コマンドに以下の項目を入れて実行します

| 項目 | デフォルト値 | 補足 |
|:-----------|:------------|:------------|
| ECS クラスター名    | -        | -        |
| ECS サービス名    | -      | -     |
| サブネットID       | 指定なし      | カンマ区切りで複数選択可    |
| セキュリティグループID    | VPCのデフォルトのセキュリティグループ    | カンマ区切りで複数選択可         |
| パブリックIPの自動割り当て  | 割り当てない      |DISABLED：割り当てない, ENABLE：割り当てる のどちらかを選択する。 |

**以下注意事項**
- 指定したサブネットとセキュリティグループは全て同一VPC内のものでなければならない
- サブネットは16個までしか指定できない
- セキュリティグループは5個までしか指定できない

<br>

以下が実際に値を入れたコマンドです。
```
$ aws ecs update-service \
  --cluster dummy-cluster \
  --service dummy-service \
  --network-configuration "awsvpcConfiguration={subnets=[subnet-1, subnet-2],securityGroups=[security-group-1],assignPublicIp=ENABLE}"
```

### 注意点
先ほど紹介したコマンドを利用して、サービスのサブネットだけを変更したいという場合に以下のようなコマンドを流すと、サブネット以外にはデフォルト値が入ってしまいます。
```
$ aws ecs update-service \
  --cluster dummy-cluster \
  --service dummy-service \
  --network-configuration "awsvpcConfiguration={subnets=[subnet-1, subnet-2]}"
```
この場合だと以下のような構成になってしまいます。
- サブネット：subnet-1, subnet-2
- セキュリティグループ：VPCのデフォルトのセキュリティグループ
- パブリックIPの自動割り当て：割り当てない

これを避けるためには各項目に適切な値を入れてコマンドを実行する必要があります。

<br>

以上を踏まえて注意しなければならないことは２つです。
- **既存の設定を塗り替えてしまう点に注意してコマンドを実行する**
- **想定外の設定になっていないかを確認するために、コマンド実行後にサービスのネットワーク構成を再確認する**
Gitコミット履歴をExcel出力する方法


概要
---
この方法では、Git のコミット履歴を TSV ファイルとして取得し、Excelで出力します。


出力内容
---
・コミットID
・作成者
・コミット日付
・コミットメッセージ
・変更されたファイル名

※順番・出力内容は変更できます`


なぜ CSVではなくTSV ファイルを使用するのか
---
CSVファイル出力に関する記事は多く見つかりますが、windowsの場合、CSVからExcelに出力すると、コミットIDやコミットメッセージが1列にまとまってしまい、履歴の確認がしづらくなってしまいます。

本記事で紹介する方法は、まず TSV ファイルでダウンロードし、その後 Excel で開くという方法です。


メリット
---
* Excelベースで履歴の確認が行える
* コミットID、作者名、日付、メッセージがそれぞれ別の列に分かれる
* 期間指定ができる
* Git履歴の可読性が向上する


方法
---
###### 1. コミット履歴を取りたいブランチを最新にしておく

###### 2. 以下コマンドでそれぞれのブランチをtsv拡張子で取得
```
git log --pretty=format:"%h\%an\%ad\%s" --date=format:"%Y/%m/%d" --name-only --since="2024-XX-XX" --until="2024-XX-XX" [ブランチ名] > [ブランチ名（何でもいい）].tsv
```
 :::note warn
※文字化けする場合、以下コマンドを実行（git bashの場合）
export LC_ALL="ja_JP.UTF-8"
:::
###### 3\. 作成されたtsvファイルをExcelで開く
　①新規でExcelファイルを開く
　②ファイルタブを選択
　③開くを選択
　④すべてのファイルにする
　⑤作成されたtsvファイルを開く。
　⑥ダイアログボックスで、「カンマやタブなどの区切り文字によって・・・」を選択し「次へ」をクリック
　⑦「その他」にチェックをつけ、\を入力し完了
Laravelでテーブルのカラムを変更するための方法

# はじめに
Laravelを使ってアプリを作る際にテーブルのカラム変更が発生した場合のマイグレーションの備忘録として記録します。

# (例)User Tableのカラムを変更したい場合

<b>(注意)</b>
<b>テーブルの更新をする場合は、あらかじめデータのバックアップを取得しておいてください。</b>

ユーザーテーブルを例に説明します。

<b>(更新前)</b>

|ユーザー名|メールアドレス|パスワード|作成日|更新日|
|---------|-------------|--------|------|------|
|Qiitaたろう|taro@qiita.com|qiitAbc|2024-01-01|2024-02-01|

(更新後)

|ユーザー名|メールアドレス|パスワード|作成日|更新日|権限|
|---------|-------------|--------|------|------|----|
|Qiitaたろう|taro@qiita.com|qiitAbc|2024-01-01|2024-02-01|true|

権限の列を増やしたい場合、Migrationしてモデルを更新する必要があります。

なので、マイグレーションファイルを作成します。
```
php artisan make:migration マイグレーションファイル名
```

# php artisan  migrateとするとエラーが...

マイグレーションファイルを作成して、テーブルを更新するため下記のLaravelコマンドを実行。

```
php artisan migrate
```

すると、こんなエラーが出た....↓
```
Base table or view already exists ~ 
```

ボクの場合、ユーザーテーブル以外にすでに別のテーブルも作っていたため、マイグレーションエラーが出ていました。

なので、いったんLaravelのマイグレーションフォルダから、エラーを吐いているファイルを一時退避用のフォルダに入れることで解決できました。

こんな感じで、退避用フォルダ「maigration_backup」を作って既存のマイグレーションファイルを一時的に移動させておくと、エラーは発生せずにテーブル更新することができました。

![退避ごだよ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/d8a1060b-5701-9f4c-5a9c-60762982fb50.png)

もっとスマートなやり方があるんだと思いますが...

どうしてもうまくいかない！といった時の力技でした...💦
疑問力と質問力

## 疑問力
- 課題を解決するために、適切な疑問を抱ける力
    - 切り口が多彩だと、問題解決の糸口になりやすい
- [思考・論理・分析―「正しく考え、正しく分かること」の理論と実践](https://www.amazon.co.jp/%E6%80%9D%E8%80%83%E3%83%BB%E8%AB%96%E7%90%86%E3%83%BB%E5%88%86%E6%9E%90%E2%80%95%E3%80%8C%E6%AD%A3%E3%81%97%E3%81%8F%E8%80%83%E3%81%88%E3%80%81%E6%AD%A3%E3%81%97%E3%81%8F%E5%88%86%E3%81%8B%E3%82%8B%E3%81%93%E3%81%A8%E3%80%8D%E3%81%AE%E7%90%86%E8%AB%96%E3%81%A8%E5%AE%9F%E8%B7%B5-%E6%B3%A2%E9%A0%AD-%E4%BA%AE/dp/4382055415)に書いてある、分けるための3要件（クライテリア・ディメンジョン・MECE）が揃っていると、疑問の質が上がると思う
- 「障害の原因は何か？」を一人で調査する時など、解決力が高い人は、この疑問力が高い気がする

## 質問力
- 疑問を相手に伝える力
- 表現力
【JavaScript】バブリングについて

## はじめに
JavaScriptの学習を進めていく中で、バブリングと呼ばれる現象に遭遇しました。
そこで、バブリングについての概要と、その対処法についてここに記します。

## バブリングとは
DOMツリー内でイベントが発生したときに、そのイベントが階層構造に沿って下位の要素から上位の要素へと伝播していく仕組みを指します。

JavaScriptでのイベント処理には、以下の3つのフェーズがあります。

<dl>
  <dt>1. キャプチャリングフェーズ</dt>
  <dd>イベントがDOMツリーの上位から下位へ伝播します。つまり、windowやdocumentのようなトップレベルの要素から、イベントが発生した具体的な要素までたどり着きます。</dd>
  <dt>2. ターゲットフェーズ</dt>
  <dd>イベントが発生した要素（ターゲット）で実際に処理が行われます。</dd>
  <dt>3. バブリングフェーズ</dt>
  <dd>イベントが下位の要素から上位の要素に向かって再び伝播していきます。このフェーズが「バブリング」に該当します。</dd>
</dl>

例：以下のコードで、バブリングの動作を確認できます。
```html
<div id="parent">
  <button id="child">Click Me</button>
</div>

<script>
  // 親要素にイベントリスナーを設定
  document.getElementById('parent').addEventListener('click', function() {
    console.log('Parent clicked');
  });

  // 子要素にイベントリスナーを設定
  document.getElementById('child').addEventListener('click', function() {
    console.log('Child clicked');
  });
</script>
```

1\. ボタン`#child`をクリックすると、最初に「Child clicked」が表示されます。これは、イベントがターゲットフェーズで子要素が処理されるためです。
2\. 次に、「Parent clicked」が表示されます。これは、イベントがバブリングフェーズで親要素に伝播し、親要素のイベントリスナーが実行されるためです。

## バブリングの制御
バブリングを止めたい場合、イベントリスナーのコールバック関数内で`event.stopPropagation()`を使います。
```javascript
document.getElementById('child').addEventListener('click', function(event) {
  console.log('Child clicked');
  event.stopPropagation(); // バブリングを止める
});
```
このコードを追加すると、`#child`をクリックしても親要素にはイベントが伝播しなくなり、「Parent clicked」は表示されません。

## まとめ
<dl>
  <dt>バブリング</dt>
  <dd>イベントが下位要素から上位要素に伝播していく仕組み。</dd>
  <dt>stopPropagation</dt>
  <dd>バブリングやキャプチャリングを途中で停止させるメソッド。</dd>
</dl>

バブリングをうまく活用することで、複数のイベントを効率的に扱えるようになります。
クラウド環境構築（github-codespaces）

## 環境構築をクラウドで簡略化しよう！

githubのサービスで無料枠のクラウド上に環境構築が出来るサービスがあった。
これを使用すれば、rubyとrailsやその他ライブラリなどで発生するバージョンでの交互関係のエラーを
解消できるという。
コード記入はVScodeのような操作性！
個人アカウントでは、15GBのストレージと１ヶ月に120Hが無料枠で使える。
環境構築でさんざん苦しみ、初学者たちが苦しんできた事実を鑑みればとても有益にみえる。

早速、githubでリポジトリ新しく作成。

githubのメイン画面からcode→codespaceタブ→openingcodespace
で作成が出来る。

```
rvm list
```

ダウンロードのバージョンを確認。

適用したいのはruby3.0.1なのですがリストにありませんでした。
rvmでダウンロードします。

```
rvm install ruby 3.0.1
```

rials もダウンロード

```
gem install rails v-7.0.0 -N
```

"-N"でドキュメントのダウンロードを省略する。ダウンロード時間が短縮できる。

環境構築は一旦終わり。

続いて終了と開始は、github.com/codespacesをURLにたたいて
作成したリポジトリ名の右側にあるドットボタンを押してstopを選択すれば終了。
開始する場合はリポジトリ名をクリック。

デフォルトで３０分以上操作がなければスリープ状態になり、
３０日以上放置した場合、自動でデータが削除される。
超簡単！GitHub Actionsが「失敗した場合のみ」Slackへ通知する方法

# GitHub Actions 「失敗のみ通知」のコード
GitHub Actionsに下記コードを追加するだけ！！！
実装しているソースコードの最終行に追加すれば良いです！！
```yml
      # 失敗時はこちらのステップが実行される
      - name: Slack Notification on Failure
        uses: rtCamp/action-slack-notify@v2.0.2
        if: failure()
        env:
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_TITLE: GitHub Comment
          SLACK_COLOR: danger
          SLACK_MESSAGE: '<!here> Docker Cache Retention job failed!'
```

# ソースコードの説明

1. `name: Slack Notification on Failure`
   このステップの名前を定義しています。GitHubのアクション実行ログでこの名前が表示されます

2. `uses: rtCamp/action-slack-notify@v2.0.2`
   rtCampが提供するSlack通知アクションを使用しています。バージョン2.0.2を指定しています

3. `if: failure()`
   このステップは、ワークフローの前のステップのいずれかが失敗した場合にのみ実行されます

4. `env:` 以下の環境変数設定：
   - `SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}`
     Slack通知を送信するためのWebhook URLを、GitHubのシークレットから取得します。
     最初のうちはテスト用のWEBHOOK_URLをハードコーディングするのもありですが、開発・本番運用するWEBHOOK_URLをコミットするのはセキュリティ上よろしくないため、注意

   - `SLACK_TITLE: GitHub Comment`
   　Slack通知のタイトルを設定します

   - `SLACK_COLOR: danger`
     通知の色を赤（danger）に設定し、失敗を視覚的に示します

   - `SLACK_MESSAGE: '<!here> Docker Cache Retention job failed!'`
     通知の本文メッセージを設定します。`<!here>`はSlackの@hereメンションで、チャンネル内のアクティブなメンバー全員に通知します

このステップにより、Docker Cache Retentionジョブが失敗した際に、設定されたSlackチャンネルに通知が送られ、チーム全体に問題を迅速に知らせることができます。

# Slack 通知
Slackへの通知は、添付画像の通りです。
@hereも追記しており、Slackからのメンションも行えるため非常に便利です！！！
![スクリーンショット 2024-09-28 11.17.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263017/eb53340f-4963-9b2b-02b1-471dc0153911.png)
【Ruby on Rails】トランザクション内で定義した変数をトランザクション外でも使う方法

# はじめに

仕事でRuby on Railsを用いてバックエンド開発を行っているのですが、その中でトランザクション内で定義した変数をトランザクション外で使いたいケースが出てきたので、その方法について共有します。

# インスタンス変数を使う

その方法とは、「**インスタンス変数を使う**」ことです。インスタンス変数とは、`@hogehoge`といったように、変数の前に`@`を付与した変数になり、ブロックの外でも変数を使用したいときに用いられます。

ブロックの外でインスタンス変数を使う用途として

* クラス内のメソッドで定義された変数に対して、インスタンスを生成することで別のメソッドでも利用できるようにする(詳細記事は[こちら](https://qiita.com/mary_new_programmer/items/4c4353c3d1df7242f515))

* Controllerファイルで定義した変数をViewファイルでも利用できるようにする(詳細記事は[こちら](https://zenn.dev/ganmo3/articles/58c1f44fa50831))

が代表的なものにあります。詳しい内容は添付した記事を参考にしてみてください。

# サンプルコードを見てみる

下記Userテーブルがあるとし、トランザクション処理の後にメール送信する処理を想定します。

|id|username|nickname|email|password|created_at|updated_at|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1|マイク|マイク|`mike@mike.jp`|`XXXXXXXXXXXXX`|2024-09-28|2024-09-28|

```error.rb
def update

    ActiveRecord::Base.transaction do
        user = User.find(params[:id]) 
        user.update!(
          email: "mike2@mike.jp",
          nickname: "マイクくん"
        )
    end

    UserMailer.with(user: user).welcome_email.deliver_later #エラー発生
    
    redirect_to user_path
end
```

```success.rb
def update

    ActiveRecord::Base.transaction do

        @user = User.find(params[:id]) 
        @user.update!(
          email: "mike2@mike.jp",
          nickname: "マイクくん"
        )

    end

    UserMailer.with(user: @user).welcome_email.deliver_later #メールが送信される
    
    redirect_to user_path
end
```

上記のように、transaction外でローカル変数を用いようとするとエラーが発生し、インスタンス変数を用いると問題なく挙動します。

# なぜインスタンス変数を使うのか？

上記ソースコードのように、なぜtransaction外ではインスタンス変数を用いることが必要なのでしょうか？こちらですが、冒頭でも述べた通り、**スコープがブロックの外にまで影響が及んでいる**ためです。
トランザクションの一連の処理はブロック単位となっているので、トランザクション外の処理はブロック外とみなされます。そのため、トランザクション外で使う場合には、インスタンス変数を使う必要があります。


# 最後に

これまでインスタンス変数について深掘りしたことがなかったので、このエラーを通して良い機会になったと思います。かといって、インスタンス変数を使いすぎるのも変数の安全性が下がると思うので、ローカル変数でかけるところは書いて、ローカル変数で賄えない処理についてはインスタンス変数を使うのが良いと思いますね。
対称鍵と非対称鍵の要約メモ

# 対称鍵と非対称鍵の要約メモ

### 対称暗号
- 暗号化と復号化の両方に同じ鍵が使用 (送信者と受信者は共有鍵を既に保持する必要あり、事前に鍵を配布することが課題)
- 非対称暗号と比較し高速に暗号化が可能
### 対称鍵暗号の具体例
| 名称 | タイプ |アルゴリズムタイプ|ブロックサイズ | キーサイズ |強度 |
| ---- | ---- | ---- | ---- |---- |---- |
| <b>AES</b> | 対称  | ブロック暗号 | 128|128,192,256 |強い|
| <b>Blowfish</b> | 対称  |  | 64|32 - 448 key bit ||
| <b>DES</b> | 対称  | ブロック暗号 | 64| 56 bit |非常に弱い|
| <b>3DES</b> | 対称  | ブロック暗号 | 64| 112 or 168 bit |中|
| <b>IDEA</b> | 対称  |  | 64| 128 ||
| <b>RC2</b> | 対称  |  | 64| 128 ||
| <b>RC4</b> | 対称  | ストリーム暗号 | ストリーミング| 128 ||
| <b>RC5</b> | 対称  | 	RSA Block mode cipher | 32, 64, 128| 0 - 2040 bit |とても強い|
| <b>Skipjack</b> | 対称  |  | 64| 80 ||
| <b>Twofish</b> | 対称  |  | 128| 1 - 256 ||

### 非対称暗号
- 暗号化と復号化に2つの異なる鍵を使用 (利用者は公開鍵と秘密鍵の両方を保持し、秘密鍵は機密性を担保する必要があり、公開鍵は自由に配布可能)
- 公開鍵で暗号化されたデータは対応する秘密鍵でのみ復号化可能、また秘密鍵で暗号化されたデータは対応する公開鍵でのみ復号化可能
- 暗号化の処理が遅く、鍵長（2048ビット以下）より小さいデータを暗号化可能 (デジタル署名の場合、非対称暗号はメッセージ全体ではなくメッセージのハッシュを暗号化するために使用)
### 非対称鍵暗号の具体例
| 名称 | タイプ |アルゴリズムタイプ| サイズ |強度 |
| ---- | ---- | ---- | ---- |---- |
| <b>RSA</b> | 非対称  | キートランスポートアルゴリズム | 512 |強い|
| <b>Diffie-Hellman</b> | 非対称  | キートランスポートアルゴリズム | - |中| 
| <b>EI Gamal</b> | 非対称 | キートランスポートアルゴリズム | - |非常に強い|
| <b>ECC</b> | 非対称 | 楕円曲線 | 可変 |非常に強い|

## 参考
- https://www.synopsys.com/ja-jp/glossary/what-is-cryptography.html
- https://www.youtube.com/watch?v=_nyZhYnCNLA&list=PL7XJSuT7Dq_XPK_qmYMqfiBjbtHJRWigD&index=2&t=9535s
GoのEchoの環境を構築してみる（Macのローカルに直接構築）

## 概要

Macのローカルに直接GoのEchoの環境を構築する方法をまとめる。

## 前提

下記の内容が完了していること。

https://qiita.com/miriwo/items/2cdcadb0c81fa34c0c27

## 内容

1. 任意のディレクトリにtest-local-echo-appというディレクトリを作成、作成したディレクトリにターミナルで移動
1. 下記を実行してGoのモジュールを初期化（`go: creating new go.mod: module test-local-echo-app`と返れば正常っぽい）

    ```terminal
    go mod init test-local-echo-app
    ```

1. 下記を実行してEchoのインストールを実施

    ```terminal
    go get -u github.com/labstack/echo/v4
    ```

1. test-local-echo-appのディレクトリルートにmain.goのファイルを作成し、下記のように記載

    ```main.go
	package main
	
	import (
	    "net/http"
	    "github.com/labstack/echo/v4"
	)
	
	func main() {
	    e := echo.New()
	
	    e.GET("/", func(c echo.Context) error {
	        return c.String(http.StatusOK, "Hello, Echo!")
	    })
	
	    e.Start(":8080")
	}
    ```

1. `$ go run main.go`を実行してサーバーを起動
1. [http://localhost:8080](http://localhost:8080)にアクセスし下記の様に「Hello, Echo!」の文字がでれば完了

    ![CleanShot 2024-09-28 at 11.45.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/369181a3-4f1c-0ce8-b39c-d180c6dd9d40.png)

## 参考文献

https://echo.labstack.com/docs/quick-start
[アルゴ式] 再帰関数が配列のコピーを繰り返してしまい、時間切れになってしまったこと

## はじめに
最近、アルゴリズムの勉強として、アルゴ式に取り組んでいます。「アルゴリズム初級」の「再帰関数」に取り組んでいましたが、実装時に引っかかってしまったことがありました。初心者の大変初歩的なミスですが、メモがてら書き残しておきます。

## 引っかかった問題
[部下の人数](https://algo-method.com/tasks/87baad02dd468b8c)という問題です。

>ある会社には N 人の社員がおり、0 から N−1 までの社員番号が振られています。
>社員 0 以外の社員は自分より若い番号の社員のうち 1 人を直属の上司として持ちます。 社員 i の直属の上司は Piです。
>社員 X は何人の部下を持つか答えるプログラムを作成してください。 ただし、「社員の部下の部下」のように直属でない部下も全て数えることとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2630841/1e70f694-7f9b-2b24-baa2-9e34342504c9.png)

グラフ構造を隣接リストで管理することにし、次のようなプログラムを書きました。

```cpp
#include <bits/stdc++.h>
#define print(x) cout << x << endl;
#define rep(i, s, n) for (long long i = s; i < (long long)(n); i++)
#define INF 1010000000
using namespace std;
using ll = long long;

ll func(vector<vector<ll>> g, ll x)
{
  if (g[x].size() == 0) return 0;
  ll cnt = 0;
  rep (i, 0, g[x].size())
    cnt += func(g, g[x][i]);
  return cnt + g[x].size();
}

int main()
{
  ll N, X;
  cin >> N >> X;
  vector<vector<ll>> g(N);
  rep (i, 1, N)
  {
    ll p;
    cin >> p;
    g[p].push_back(i);
  }
  print(func(g, X));
  return 0;
}
```

サンプルケースは問題なく通過しましたが、一つのケースだけ「時間切れ」となってしまいました。

## 何が原因だったか
原因は、再帰関数の引数にありました。

```cpp
...
ll func(vector<vector<ll>> g, ll x) 
{
...
```

二次元配列をそのまま渡しているため、関数が再帰するたびに毎回配列のコピーが発生していました。入力数が小さい時なら問題ありませんでしたが、入力数が大きい場合、コピーで時間が取られてしまっていたのです。

## 解決策
二次元配列の参照だけ渡すようにしました。これで無駄な配列のコピーが削減され、時間内に通過するようになりました。

```cpp
...
ll func(vector<vector<ll>> &g, ll x) 
{
...
```

## 終わりに
普段は意識していなかった配列のコピーにも、計算機のコストがしっかりとかかっているのだと改めて認識しました。
HomebrewでMacのローカルにGoを入れる

## 概要

HomeBrewを使ってMacのローカルにGoを入れる方法を簡単にまとめる。

## 方法

1. `$ brew -v`を実行
1. `$ brew install go`を実行してGoをインストール
1. `$ go version`を実行してバージョンを確認
localhost立ち上げすぎた→ポート番号を指定して停止する方法


ローカル環境を同時に立てすぎて使いたいポート番号が使われているけど、どこの何が使ってるのかわからなくなった時の対処方法

ポート番号が3000の場合

# 3000の情報を確認
```
lsof -i:3000
```

表示される「PID」をメモ

# 停止コマンド
```
kill -QUIT {PID}
```

これで3000番は停止する
Survey関係のUIの問題




# Post-Chat Feedback and Embed Surveys

https://qiita.com/Keiji_otsubo/items/e1fe89809e34490d44c0#post-chat-settings%E3%81%8C%E3%81%AA%E3%81%84

+ [Post chat survey not coming in dropdown list under chat settings](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007ertEm)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/5b2e628a-73ef-6c6b-facc-134457cb49b0.png)

:::note 
On the edit chat settings page, try to zoom out your browser to 75% and then try to add the Post-Chat Feedback survey

https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000LIT9S
:::
paiza.ioでmysql その7

# paiza.ioでmysqlやってみた。
練習問題やってみた。

# 練習問題
GROUP BYを使え。

# サンプルコード

```

CREATE TABLE members (
    id INTEGER NOT NULL,
    name CHAR(32),
    height REAL,
    weight REAL,
    age INTEGER,
    position_id INTEGER,
    PRIMARY KEY (id));

CREATE TABLE positions (
    id INTEGER NOT NULL,
    name CHAR(32),
    salary INTEGER,
    PRIMARY KEY (id));

INSERT INTO members(id, name, height, weight, age, position_id)
    VALUES
        (1, 'ヌートバー', 190.2, 65.2, 60, 1),
        (2, '近藤', 170.5, 50.3, 35, 1),
        (3, '大谷', 193.1, 98.1, 28, 2),
        (4, '村上', 183.5, 70.6, 36, 3),
        (5, '吉田', 178.8, 55.8, 62, 1),
        (6, '岡本', 177.0, 65.3, 75, 3),
        (7, '山田', 181.4, 49.1, 25, 3),
        (8, '中野', 179.1, 56.9, 45, 3),
        (9, '甲斐', 173.7, 90.1, 38, 4),
        (10, '山本', 180.6, 78.5, 26, 5);
        
INSERT INTO positions(id, name, salary)
    VALUES
        (1, '外野', 1232),
        (2, 'DH', 3000),
        (3, '内野', 515),
        (4, 'キャッチャー', 1024),
        (5, 'ピッチャー', 542);


SELECT position_id, COUNT(*) FROM members 
    GROUP BY position_id;


```

# 実行結果

```
position_id	COUNT(*)
1	3
2	1
3	4
4	1
5	1
```

# 成果物


https://paiza.io/projects/iVu9KdoaPH3QIKCP2NzwHA



以上。
WordPressで各ページのh1に任意の画像を設定する方法

WordPressで各ページのh1に任意の画像を設定する方法を紹介します。

## 使用しているテーマとプラグイン
テーマ：[Cocoon](https://wp-cocoon.com/)
プラグイン：[Advanced Custom Fields](https://www.advancedcustomfields.com/)

## カスタムフィールドの設置
プラグイン『[Advanced Custom Fields](https://www.advancedcustomfields.com/)』をインストール＆有効化して、`Field Type`を`image`に設定します。
`Field Label`に適当な名前を付けて保存します。

![image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902958/ed6b2cd1-d529-5abb-fedb-87ac782b802d.jpeg)


これで、各ページの編集ページの下部にカスタムフィールドが出現します。↓
![postedit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902958/af748037-e177-8b2a-5a1b-7fdd5e86ca65.png)

## 画像を表示するための処理
カスタムフィールドで設定した画像をh1として表示させるには、`functions.php`に以下のコードを追加します。

```php:functions.php
function my_custom_eye_catch_logo(){
    if(is_page()){
        // カスタムフィールド『custom_eye_catch_logo』を取得
        $custom_eye_catch_logo=get_field('custom_eye_catch_logo');

        // もしページにカスタムフィールド『custom_eye_catch_logo』が設定されていれば、処理を実行する。
        if($custom_eye_catch_logo){
            // 『custom_eye_catch_logo』で入力した画像のurlとaltの値を変数に代入する。
            $image_url = esc_url($custom_eye_catch_logo['url']);
            $image_alt = esc_attr($custom_eye_catch_logo['alt']);
           
            // h1タグを画像とaltテキストに置き換える
            return '<img src="' . $image_url . '" alt="' . $image_alt . '" class="eye_catch_logo">'
        }
    }

    // 何も変更しない場合は元のタイトルを返す
    return $title;
}
```

そして、画像を出力したい箇所のテンプレートファイル（`single.php` や `page.php`など。Cocoonの場合は`content.php`）で、`the_title()` の代わりに、作成した関数 `my_custom_eye_catch_logo()`を直接呼び出します。
```php
<?php
// 処理
<h1 class="entry-title"><?php do_action( 'my_custom_eye_catch_logo' ); ?></h1>
<?php
// 処理
```
これで、h1に画像が表示されるようになります。
【IT業界未経験】Linucレベル1合格への記録

# はじめに

IT業界未経験からインフラエンジニアへの転職を目指すmmと申します。<br>
2024年夏、LinuCレベル1に合格できたので勉強方法を記事に残します。

# 記事の目的
この記事は効率的な受験勉強の方法や早く合格するためのテクニックを紹介するものではありません。<br>
私が受験にあたって意識した事や反省した事、受験を終えて感じた事などの記録となります。ご留意ください。<br>
また本記事では、LinuCレベル1試験の概要は省略しております。

# 経歴
- 文系４大卒。IT業界未経験
- プログラミング経験はVBAのみ
- オンラインスクールでAWSコースを完走済み
- 所持資格は　AWS SAA、基本情報技術者

# 受験の動機

こんなヨワヨワな技術力で転職活動を始めていいのだろうか…😭と不安に思っていたところ、メンターから本試験をオススメされました。<br>
Linuxについては、しっかり勉強せずに放置してしまっていた事もあり、即受験を決めました。<br>
また、仮想化技術とクラウドが試験範囲に含まれている事からLPICではなくLinuCを選択しました。

# 学習期間
101：3週間（毎日5時間以上）<br>
102：10日間（毎日5時間以上）

# 目標とした事
学習にあたって合格以外に目標とした事です😀

- 暗記ではなく理解をすることに努める（どの資格学習でも共通！！）
- 可能な限り、実際にPCでコマンドを入力して入力結果も確認する

# スコア
101：733点<br>
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3837659/8fc20aa7-8140-6523-66b1-4a774e52e849.png)
<br>
102：666点<br>
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3837659/3d2d9964-d119-7db7-76a4-37a28898bf0c.png)

# 使用した教材・サイト

- Linux教科書 LinuCレベル1 Version 10.0対応［101試験，102試験対応］（以下、あずき本）
- Linux教科書 LinuCレベル1 スピードマスター問題集 Version10.0対応（以下、白本）
- [Ping-t](https://mondai.ping-t.com/g)

# 勉強方法

主な勉強の流れです。また目標の通り、可能な限り実際にPCでコマンドを入力して結果を確認するようにしました。

## 101

1. 出題範囲を大まかに把握するために、あずき本の単元を一つ読む
2. Ping-tで読んだ範囲の問題を解く。各単元毎に繰り返す。
3. Ping-tが安定して8割取れるようになったらあずき本の模擬問題を解く（この時点で正解率は6割位）
4. 模擬問題とPing-tの出題の仕方が違う事に気付き、試験に近い問題を扱う白本を追加購入。問題の重要度に関係なく白本を3周する
5. あずき本、白本の模擬問題で9割取れるようになったので受験

## 102

101と同様。Ping-tの102の問題は、101と違い有料となっているので注意！

# 反省点

- まだまだコマンドが身に付いていない
- パッケージ管理やパーティションの分野などは、自分の環境では実際に練習できなかったため理解が浅い

# よかった点

- これまでコマンドは都度調べて使用することが多かったが、試験勉強を通じて必須コマンドを体系的に学ぶことができた
- CLIに対する苦手意識が薄くなった
- エンジニアの使用頻度が高いviエディタの使用方法を体系的に学習できた

# 終わりに

ここまで読んで頂きありがとうございました！<br>
これまでの学習で、どうしてもCLI操作への苦手意識が捨てられませんでした。<br>
しかし、この試験でLinuxの操作方法を体系的に学習できた事でかなり苦手意識が薄れました。<br>
もっと早く受ければよかった！😭
もちろん、まだまだ理解が足りていない部分が大きいため引き続き学習が必要だと思います。<br>
今後の目標として、実際によく使用されるシェルスクリプトやcronの設定を確認して基本的なものを作成できるようになりたいと思います。<br>
paiza.ioでmysql その6

# 概要
paiza.ioでmysqlやってみた。
練習問題やってみた。

# 練習問題
duplicateを使え。

# サンプルコード

```

CREATE TABLE book(
    name VARCHAR(30) NOT NULL,
    author VARCHAR(30) NOT NULL,
    age INT(3),
    PRIMARY KEY (name)
);

INSERT INTO book(name, author, age) VALUES ('SQL入門', 'Masumi', 25);
INSERT INTO book(name, author, age) VALUES ('Flutter入門', 'Masumi', 25);
INSERT INTO book(name, author) VALUES ('HTML入門', 'Hiro');
INSERT INTO book(name, author, age) VALUES ('GitHub入門2', 'Emma', 22);
INSERT INTO book(name, author, age) VALUES ('Flutter上級', 'Oliva', 45);

SELECT * FROM book;

insert into book (name, author, age) values ('my上級', 'Ohisama', 55) 
on duplicate key 
update name ='my上級', author='Ohisama', age = '65';

SELECT * FROM book;


insert into book (name, author, age) values ('my上級', 'Ohisama', 55) 
on duplicate key 
update name ='my上級', author='Ohisama', age = '65';

SELECT * FROM book;

```

# 実行結果

```

name	author	age
SQL入門	Masumi	25
Flutter入門	Masumi	25
HTML入門	Hiro	NULL
GitHub入門2	Emma	22
Flutter上級	Oliva	45
name	author	age
SQL入門	Masumi	25
Flutter入門	Masumi	25
HTML入門	Hiro	NULL
GitHub入門2	Emma	22
Flutter上級	Oliva	45
my上級	Ohisama	55
name	author	age
SQL入門	Masumi	25
Flutter入門	Masumi	25
HTML入門	Hiro	NULL
GitHub入門2	Emma	22
Flutter上級	Oliva	45
my上級	Ohisama	65
```

# 成果物

https://paiza.io/projects/vR-456mph_L6qOyncCOWhw


以上。
paiza.ioでmysql その5

# 概要
paiza.ioでmysqlやってみた。
sql見つけたので、やってみた。

# 参考にしたページ

https://qiita.com/tlokweng/items/f8c2afb54d6f181d7f49


# サンプルコード

```


WITH RECURSIVE hanoi (tiles, ln, orig, free, dest) AS (
    SELECT  
        3, 0, 
        CAST('Left'   as char(10)),
        CAST('Center' as char(10)),
        CAST('Right'  as char(10))
    UNION ALL
    SELECT 
        r.tiles - 1,
        r.ln * 2 + m.n,
        CASE WHEN n = 0 THEN orig ELSE free END,
        CASE WHEN n = 0 THEN dest ELSE orig END,
        CASE WHEN n = 0 THEN free ELSE dest END
    FROM 
        hanoi r, 
        (SELECT 0 n UNION ALL SELECT 1) m
    WHERE
        r.tiles > 1
),
pile(n, s, m) AS (
    SELECT 
        1, CAST('1-' AS CHAR(100)), MAX(tiles)
    FROM hanoi
    UNION ALL
    SELECT 
        n + 1, CONCAT(s, n + 1, '-'), m
    FROM pile
    WHERE n < m
),
display (step, left_, center_, right_, target) AS (
    SELECT 
        0,
        s,
        CAST('' AS CHAR(100)),
        CAST('' AS CHAR(100)),
        CAST('' AS CHAR(100))
    FROM pile
    WHERE n = m
    UNION ALL
    SELECT
        p.step,
        CASE 
        WHEN p.orig = 'Left'   THEN CAST(REGEXP_REPLACE(left_,   '^[0-9]+-', '') AS CHAR(100))
        WHEN p.dest = 'Left'   THEN CONCAT(p.tile_no, '-', left_)
        ELSE left_
        END,
        CASE 
        WHEN p.orig = 'Center' THEN CAST(REGEXP_REPLACE(center_, '^[0-9]+-', '') AS CHAR(100))
        WHEN p.dest = 'Center' THEN CONCAT(p.tile_no, '-', center_)
        ELSE center_
        END,
        CASE 
        WHEN p.orig = 'Right'  THEN CAST(REGEXP_REPLACE(right_,  '^[0-9]+-', '') AS CHAR(100))
        WHEN p.dest = 'Right'  THEN CONCAT(p.tile_no, '-', right_)
        ELSE right_
        END,
        p.dest
    FROM display d,
        (SELECT POWER(2, tiles - 1) + ln * POWER(2, tiles) step, tiles tile_no, orig, dest, ln FROM hanoi) p
    WHERE d.step + 1 = p.step
)
SELECT
        step,
        LPAD(CONCAT(CASE WHEN target = 'Left'   THEN '*' else '' END, TRIM('-' from left_)),   21, ' ') left_,
        LPAD(CONCAT(CASE WHEN target = 'Center' THEN '*' else '' END, TRIM('-' from center_)), 21, ' ') center_,
        LPAD(CONCAT(CASE WHEN target = 'Right'  THEN '*' else '' END, TRIM('-' from right_)),  21, ' ') right_
FROM display
ORDER BY step;





```

# 実行結果

```
step	left_	center_	right_
0	                1-2-3	                     	                     
1	                  2-3	                     	                   *1
2	                    3	                   *2	                    1
3	                    3	                 *1-2	                     
4	                     	                  1-2	                   *3
5	                   *1	                    2	                    3
6	                    1	                     	                 *2-3
7	                     	                     	               *1-2-3
```

# 成果物

https://paiza.io/projects/K5PIkgfk4EL6NiWKlHDVjA


以上。
FS、最先端の1.6T OSFPケーブルを発売：超高速接続の新たなベンチマークを打ち立てる

<a href="https://community.fs.com/jp/blog/fs-launches-cuttingedge-16t-osfp-cable-setting-a-new-benchmark-for-ultrahighspeed-connectivity-.html">FSコミュニティで原文を読む</a>
<p class="blog_p padding_top_none community_blog_detail_p community_blog_detail_p1">デラウェア州ニューキャッスル、ICT製品とソリューションのプロバイダーとして信頼されるFS社は、最新の革新的な<a href="https://www.fs.com/jp/products/244361.html">1.6T OSFPクローズトップDACケーブル</a>を発表しました。最先端のOSFP DACケーブルは、超低消費電力で最大1600Gbpsのスループットを実現し、優れた機械的耐久性と優れたシールド性能と相まって、ハイパースケールデータセンター（HSDC）、機械学習（ML）、高性能コンピューティング（HPC）アプリケーションに最適です。</p>
<p class="blog_p padding_top_none community_blog_detail_p community_blog_detail_p1">NVIDIA GB200 NVL72ラックスケールシステムのリリースにより、オプティクスとトランシーバに対する需要は800Gから1.6Tへと加速しています。重要なことは、次世代のGB200 NVL72 アーキテクチャは、ラック内の短距離データ伝送に「銅線相互接続」を利用するため、銅ケーブルに対する将来の需要が大幅に増加することを示めしています。</p>
<p class="blog_p padding_top_none community_blog_detail_p community_blog_detail_p1">FSの超高速直接接続銅線接続ソリューションが登場し、世界中の専門企業に次世代アクセラレーテッドコンピューティングネットワークの構築を支援します。これらのOSFPパッシブDAC ケーブルは最先端の200G/レーン光技術を活用し、超低消費電力で最大1.6 Tbpsの優れた伝送速度を実現します。FS 1.6T OSFP DACケーブルは、イーサネットおよびInfiniBandシステム用に設計されています。InfiniBand XDRエンドツーエンドシステムに適合した<a href="https://www.fs.com/jp/products/244365.html">1.6T InfiniBand DACケーブル</a>により、InfiniBandネットワークに注力する企業がネットワークをシームレスにアップグレードし、HPCワークロード処理能力を大幅に強化できます。</p>
<p class="blog_p padding_top_none community_blog_detail_p community_blog_detail_p1"><strong>1.6T OSFP DACケーブル</strong>の主な特徴：</p>
<ul class="new_community_blog_detail_ul">
<li><span class="new_community_blog_detail_ul_circle"></span>
<p><strong>超低消費電力 - ≤0.1W</strong></p>
</li>
<li><span class="new_community_blog_detail_ul_circle"></span>
<p><strong>超高スループット - 最大1600G</strong></p>
</li>
<li><span class="new_community_blog_detail_ul_circle"></span>
<p><strong>クローズトップ設計 - 冷却効率の向上</strong></p>
</li>
<li><span class="new_community_blog_detail_ul_circle"></span>
<p><strong>業界標準準拠 - IEEE 802.3およびホットプラグ対応OSFP MSA</strong></p>
</li>
<li><span class="new_community_blog_detail_ul_circle"></span>
<p><strong>耐久性の向上 - 優れたSI信頼性と物理的性能</strong></p>
</li>
</ul>
<p class="blog_p padding_top_none community_blog_detail_p community_blog_detail_p1">「FSは、HPCデータセンター向けに包括的かつ最適化されたネットワークソリューションの提供に取り組んでおり、400G/800G H100ベースのInfiniBandおよびRoCEソリューションの提供において、豊富な実績を積み重ねてきました。現在、多くのハイパースケールデータセンター事業者がGB200 NVL72システムの導入を計画しています。業界をリードするイノベーションであるFS 1.6T OSFP DACケーブルは、次世代GB200 NVL72アーキテクチャに比類ない性能を提供できます。」とFSのシニアテクニカルディレクターであるJon Zhangは以上のように述べました。</p>
<p class="blog_p padding_top_none community_blog_detail_p community_blog_detail_p1">FS 1.6T OSFP224ソリューションは、ハイパースケールデータセンターやHPCネットワークの現在の要求を満たすと同時に、将来の拡張性も確保します。FSは今後も革新と進化を続け、HPCコネクティビティのニーズに応える最先端かつ効率的なソリューションをお客様に提供することに専念します。</p>
<p class="blog_p padding_top_none community_blog_detail_p community_blog_detail_p1"><strong>FSについて</strong></p>
<p class="blog_p padding_top_none community_blog_detail_p community_blog_detail_p1">FS（www.fs.com/jp）は、信頼性の高いICTネットワーク製品とソリューションのプロバイダーとして、世界中の企業顧客にサービスを提供しています。同社は2009年に設立され、高速通信や専門的な顧客ニーズに合わせたカスタマイズ製品開発やソリューション設計に注力しています。専門的な研究開発及びテストチーム、総合的な技術サービス専門家、強固なサプライチェーンシステム、グローバル化された倉庫センター、便利なショッピングプラットフォームを活用し、FSはISP、電気通信、小売、教育等のグローバルな垂直的産業及び企業顧客に、高効率な顧客中心のICT製品、ソリューション及びサービスを幅広く提供しています。</p>
paiza.ioでmysql その4

# 概要
paiza.ioでmysqlやってみた。
練習問題やってみた。

# 練習問題
zundokoを実行せよ。

# サンプルコード

```

DELIMITER //
CREATE PROCEDURE zundoko()
BEGIN
  DECLARE zunCount INT unsigned DEFAULT 0;
  DECLARE randValue INT unsigned DEFAULT 0;
  loop_label: 
  LOOP
    SET randValue = FLOOR(RAND() * 10) % 2;
    IF zunCount < 4 THEN
        IF randValue = 0 THEN
            SET zunCount = zunCount + 1;
            SELECT CONCAT("ズン");
        ELSE 
            SET zunCount = 0;
            SELECT CONCAT("ドコ");
        END IF;
    ELSE
        SELECT CONCAT("ドコ");
        SELECT CONCAT("キ・ヨ・シ！");
        LEAVE loop_label;
    END IF;
  END LOOP loop_label; 
END
//
DELIMITER ;

CALL zundoko;




```

# 実行結果

```
CONCAT("ドコ")
ドコ
CONCAT("ズン")
ズン
CONCAT("ドコ")
ドコ
CONCAT("ドコ")
ドコ
CONCAT("ズン")
ズン
CONCAT("ドコ")
ドコ
CONCAT("ドコ")
ドコ
CONCAT("ズン")
ズン
CONCAT("ズン")
ズン
CONCAT("ズン")
ズン
CONCAT("ドコ")
ドコ
CONCAT("ズン")
ズン
CONCAT("ズン")
ズン
CONCAT("ドコ")
ドコ
CONCAT("ズン")
ズン
CONCAT("ズン")
ズン
CONCAT("ドコ")
ドコ
CONCAT("ズン")
ズン
CONCAT("ズン")
ズン
CONCAT("ズン")
ズン
CONCAT("ドコ")
ドコ
CONCAT("ズン")
ズン
CONCAT("ズン")
ズン
CONCAT("ズン")
ズン
CONCAT("ズン")
ズン
CONCAT("ドコ")
ドコ
CONCAT("キ・ヨ・シ！")
キ・ヨ・シ！
```

# 成果物

https://paiza.io/projects/RWRFoU_ARVCeobu8KZwGKQ


以上。
Javascript 特定の順序でソートする

Javascriptでソートを行う時、単純に各プロパティの順序でソートするのではなく、指定した順序でソートしたい場合がある。この場合はソートしたい順序を別途配列で定義し、その配列でのindexOfを使用し配列内のindexからソート順序を決定すると実現できる。

下記の例では、

- employees オブジェクトの配列をnameプロパティでソートしたいかつ、
- ソート順序を独自に指定したい場合

を示す。ソート順序を指定した配列を用意し、indexOfを使用してソートする。

```jsx
// ソートする配列
let employees = [
  { name: "John", dob: "Dec 15, 2007", score: 80 },
  { name: "Ana", dob: "Jan 15, 2009", score: 75 },
  { name: "Alice", dob: "Ja 15, 2009", score: 75 },
  { name: "Bob", dob: "Jan 15, 2009", score: 90 },
  { name: "Cat", dob: "Jan 15, 2009", score: 75 },
  { name: "John", dob: "Jan 15, 2009", score: 80 },
  { name: "Zion", dob: "Feb 15, 2011", score: 90 },
];

// ソートしたい項目の順序を配列で持つ
const sortOrder = ["Bob", "Zion", "Ana", "John", "Cat", "Alice"];
employees.sort((a, b) => {
  return sortOrder.indexOf(a.name) - sortOrder.indexOf(b.name);
});

// 結果
employees.forEach((e) => {
  console.log(`${e.name} ${e.score}`);
});
// name文字列の大小の順序ではなく指定した順序でソートされる。
// Bob 90
// Zion 90
// Ana 75
// John 80
// John 80
// Cat 75
// Alice 75
```

### 解説

- 配列のsort関数

aとbの大小によって2つの要素の比較を繰り返すことによって昇順ソートする。文字列の場合、時刻の場合、オブジェクトの場合などはそれぞれ比較すればよく、基本的には同じである。

```jsx
Array.sort((a, b) => {
  return a - b;
});
// a>b  正
// a<b  負
// a=b  0
```

- indexOf配列はその配列内のindexを返す

```jsx
const sortOrder = ["Bob", "Zion", "Ana", "John", "Cat", "Alice"];
console.log(sortOrder.indexOf("Zion"));     // 1
console.log(sortOrder.indexOf("Ana"));      // 2
console.log(sortOrder.indexOf("Alice"));    // 5
```

- index同士を比較して、大小を決定する。

indexOfを利用することで、要素の比較ではなく、indexの比較を行う。

```jsx
employees.sort((a, b) => {
  return sortOrder.indexOf(a.name) - sortOrder.indexOf(b.name);
});
```

- 順序用の配列に存在しない場合は-1を返す

そのため、存在しない値はindexが最小となるため、必ず前方に配置される。
Pythonのargparse.ArgumentParser.add_argumentでEnumをchoicesする

# 動機
PythonでCLIスクリプトを作成するとき、起動時のオプション解釈には [argparse](https://docs.python.org/ja/3/library/argparse.html) を使う。
argparse では引数に制限を加えたい場合、 choices オプションが使える。

~~~python
from argparse import ArgumentParser
p = ArgumentParser()
p.add_argument('mode', choices=['walk','run','stop'])

p.parse_args(['-h'])
# positional arguments:
#   {walk,run,stop}

p.parse_args(['walk'])
# Namespace(mode='walk')

p.parse_args(['stand'])
# python: error: argument mode: invalid choice: 'stand' (choose from 'walk', 'run', 'stop')
~~~

ただ、やはりマジックコードをスクリプトに埋め込むのはよくない。
そこで列挙型である [enum](https://docs.python.org/ja/3/library/enum.html) と組み合わせたい。

# 問題
しかし、そのまま何もしないとヘルプの表示が崩れるうえ、そもそもちゃんと解析できない。

~~~python
from enum import Enum
class ACTION(Enum):
    WALK = 'walk'
    RUN = 'run'
    STOP = 'stop'

from argparse import ArgumentParser
p = ArgumentParser()
p.add_argument('mode', choices=ACTION)

p.parse_args(['-h'])
# positional arguments:
#   {ACTION.WALK,ACTION.RUN,ACTION.STOP} ←変！

p.parse_args(['walk'])
# TypeError: unsupported operand type(s) for 'in': 'str' and 'EnumMeta'
~~~

# 解決策
下記2点で解決する。
- ヘルプの表示を直すために `ACTION.__str__` を定義して、オプション文字列のみを返す
- 解析エラーを直すために `add_argument` に `type` を指定する

具体的には下記の通り。

~~~python
from enum import Enum
class ACTION(Enum):
    WALK = 'walk'
    RUN = 'run'
    STOP = 'stop'

    def __str__(self): # これを定義！
        return self.value

from argparse import ArgumentParser
p = ArgumentParser()
p.add_argument('mode', choices=ACTION, type=ACTION) # type を指定！

p.parse_args(['-h'])
# positional arguments:
#   {walk,run,stop} ←いいかんじ！

p.parse_args(['walk'])
# => Namespace(mode=<ACTION.WALK: 'walk'>) ← ちゃんと解析できた！
~~~

# 補足知識
`Enum` は値で呼び出すと、その要素を返してくれる。
~~(ドキュメントに書かれていない動作？)~~
リファレンスではなくてチュートリアルに記載がありました: [列挙型メンバーおよびそれらの属性へのプログラム的アクセス](https://docs.python.org/ja/3/howto/enum.html#programmatic-access-to-enumeration-members-and-their-attributes)

~~~python
from enum import Enum
class ACTION(Enum):
    WALK = 'walk'
    RUN = 'run'
    STOP = 'stop'

ACTION('walk')
# => <ACTION.WALK: 'walk'>
~~~