OmniAICreator/Qiita-1.07M huggingface dataset:
Fortigate（その１：VXLAN）

# FortigateでVXLAN
Fortigateを拠点間接続して接続する際の各種手法に関して、日本語の情報があまり見つからなかったので、わずかだが、シリーズ化することにした。なお、v7（おそらく）以上のFortigateについて取り扱う。

## 参考URL
いずれも本家サイトからの情報である。
- [General VXLAN configuration and topologies](https://docs.fortinet.com/document/fortigate/7.6.0/administration-guide/548660/general-vxlan-configuration-and-topologies)
- [VLAN inside VXLAN](https://docs.fortinet.com/document/fortigate/7.6.0/administration-guide/184150/vlan-inside-vxlan)

## 拠点間接続時に同一ネットワークを実現
他のルーターでは、L2TPなどで実現することが多い。FortigateでもL2TPは使えるらしいが、VXLANの方がサンプル（ただし英語サイト）としてはよく見つかる。VXLANについては、「[久しぶりにGNS3（その37：VXLAN）](https://qiita.com/infinite1oop/items/a307ad5709bc3459631d)」でも取り上げたとおりである。

### ネットワーク
![VXLAN.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/194e0d28-3a37-274d-214b-47fcdb3bf941.png)
単純である。2台のFortigateのWANを直結し、FortigateのLANにPCが接続されており、同一ネットワークに属する。

### 設定
左側のFortigate-1の設定のみ記載。

#### WAN
![NetworkInterface_FixedIP.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/0935621b-29cc-3f2c-e4e8-69ee0f02d306.png)
ここは自明。

#### VXLAN
GUIでは設定できず、CLIによる設定が必要。最低限の設定は下記となる。
- VXLANの対象インターフェース
- VNI
- リモートIPアドレス
```
FG1 # config system vxlan

FG1 (vxlan) # show
config system vxlan
end

FG1 (vxlan) # edit vxlan1
new entry 'vxlan1' added

FG1 (vxlan1) # set interface wan1

FG1 (vxlan1) # set vni 10

FG1 (vxlan1) # set remote-ip 10.1.1.2

FG1 (vxlan1) # next

FG1 (vxlan) # show
config system vxlan
    edit "vxlan1"
        set interface "wan1"
        set vni 10
        set remote-ip "10.1.1.2"
    next
end

FG1 (vxlan) #
```
ほぼ自明。

#### ソフトウェアスイッチ（ブリッジ）
![NetworkInterface_CreateSoftwareSwitch.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/581f9bbb-cb5e-da6a-9d8e-4613d8277ab3.png)
作成したVXLANとInternal（ここではPort4および5）とをつなぐソフトウェアスイッチを作成する。要するに、ネットワークブリッジである。

#### ネットワークインターフェース
最終的に作成されたネットワークインターフェースは下記となる。
![NetworkInterface_CreatedInterface.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/d3b1c828-f001-0ac6-864c-0a0d6b3212e9.png)

#### Firewall
Fortigate内外（WAN-LAN間）を通信させるためのFirewall設定が必要。作成したソフトウェアスイッチを、着信および発信インターフェースに指定する。
![Firewall_CreatedForVXLAN.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/7730822d-069c-0547-ecd1-33c7077fb7c4.png)
完成後は下記となる。
![Firewall_シーケンス別.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/c8d4194a-d2a5-0170-1257-f38bc2639dec.png)

#### スタティックルート
ネットワークがシンプルなため、今回は設定不要。状況により設定が必要となる。

## 検証
末端PC間にて、pingを実行した時のFortigate間のWiresharkデータは下記となる。
![WiresharkDataのコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/15196210-f6cf-e053-c618-8e5140128d26.png)
外側のIPアドレス（10.1.1.1-2）のPayloadとして、VXLAN用のUDPパケット（ポート番号4789）が存在する。UDPのPayloadがVXLANであり、その中にEthernetフレームが含まれているのがわかる。

EOF
Certified Kubernetes Administrator (CKA) 受験メモ

# はじめに
2024年10月にCertified Kubernetes Administrator (CKA) を取得したので、受験メモを残します。今後、CKAを受験しようとしている方に少しでも参考になれば幸いです。

# CKAについて
CKAはLinux FoundationとCloud Native Computing Foundation（CNCF）によって作成されたKubernetesの管理者認定資格です。
- 問題形式：ハンズオン
- 試験時間：2時間（試験前の事前チェックも含めると＋30分ほど）
- 受験料：CKAで395ドル、CKA-JPで430ドル
　　　　（１つのバウチャーで1回まで無料で再受験可能）
- 有効期限：2年間
- 問題数：15～20問
- 合格点：100点中66点以上

# 試験勉強について
## 学習実績
- 勉強開始時点の状態：コンテナ、Kubernetesの知識・実務経験なし
- 学習期間：約4ヶ月（平日1時間、休日2〜3時間）

## 学習教材
- Udemy
CKAの学習教材の中心は以下のUdemyの講座となります。KodeKloudというハンズオン形式の演習があり、かなり試験に近い内容の知識を身につけることができます。他の多くの受験者もこちらの講座を利用しており、おすすめです。

https://www.udemy.com/course/learn-docker/

https://www.udemy.com/course/certified-kubernetes-administrator-with-practice-tests/

- Killer Shell 
CKAのバウチャーを購入すると利用できる試験シミュレータで、2回分利用することができます。個人的にはCKAより問題が難しかったため、こちらが完璧に解けるようになっていればまずCKAには合格できると思います。試験とほぼ同様の環境を触ることができるため、特にコピー&ペーストなど通常のPC利用と若干操作感が異なる部分があるため、試験前に一度利用して確認しておいた方が良いと思います。

https://killer.sh/cka

- kubernetes.io 
CKAの試験本番中も閲覧可能なKubernetesのドキュメントです。コマンドで作成することのできないリソースなどは、このサイトからテンプレートを取得して作成することになります。試験本番にいきなり必要なドキュメントを探そうとすると辿り着くまでに時間を要するため、ある程度どのように検索し、参照したい情報に到達できるかを押さえた方が良いと思います。また、できるだけ英語版のドキュメントで調べる癖をつけておいた方が良いと思います。

https://kubernetes.io/docs/home/

# 受験について
## 受験の流れ

1. The Linux Foundationのアカウント登録
2. バウチャーの購入
3. 試験予約の登録 
4. 受験 
5. 結果連絡（受験から24時間後） 

## 受験の注意点
### 身分証明書と受験者名を一致させる
身分証明は受験者の登録情報と表示を一致させておく必要があります。受験者名が英名で身分証明が日本語のようなケースはNGで、身分証明として認められないそうです。

### 自宅受験する場合は部屋を整理しておく
受験当日は試験監督から受験環境を確認のために、Webカメラに表示させる必要があるため、部屋からものを極力排除しておく必要があります。どうしても退かすことができないものの場合は、布などで見えないようにしておけば大丈夫です。

### 受験中にイヤホンは使用しない
試験監督からの指示は全てチャットで行われ、試験監督から耳に何も装着していないことも確認されるため、イヤホンを用意しておく必要はありません。

## 受験後の所感
- モニターが小さいと少し操作に難があるケースがあったため、できるだけ大きい画面で受験した方が良いと感じました。私の場合は13インチのノートパソコンで受験しましたが、ドキュメントの表示される範囲が狭くて少しやりづらかったです。
- 前情報として受験環境の動作が重いという記事をよく見ましたが、私の場合は無線接続でもそれほど不自由には感じませんでした。ただ、こちらは受験環境に依存する部分だと思うので、不安があれば有線接続で受験するなど対策をした方が良いと思います。回線速度やカメラの表示については事前にチェックすることも可能です。
- CKA-JPで受験をしたため、試験監督とのチャットの日本語だと思っていましたが、実際は英語でした。難しい指示はなかったため、落ち着いて対応すれば問題ないと思います。

# おわりに
CKAはハンズオン形式の試験であり、合格が体系的に知識が身に付いている証明になる良い試験だと思いました。Kubernetesは奥が深く、まだまだ学ぶべきことはたくさんありますが、今回のCKA取得を足掛かりとしてより経験を積み、CKADやCKSについても取得していければと思います。ここまで読んでくださり、ありがとうございました。
Rubyよく経験したエラー

エラー分を翻訳して一覧表示させています。

`Active Record::RecordNotFound`
エラー文
Couldn't find Model with 'id'=123
意味
指定されたIDがデータベースに存在しない

`NoMethod Error`
エラー文
undefined method 'xxx'for nil:NiClass
意味
変数がnilまたはメソッドが未定義である。

`Name Error`
エラー文
uninitialized constant Model Nmae
意味
クラスが正しく定義されていない

`Active Record::Unknown Attribute Error`
エラー文
unknown attribute 'xxx'for Model
意味
モデルに存在しないカラムが使用されている

`Routing Error`
エラー文
No route matches [GET]"/path"
意味
routes.rbに適切なルーティングを設定できていない

`Action View::Template::Error`
エラー文
undefined local variable or method 'xxx'for
#<#<Class:0x0000000000>
意味
viewで使用されている変数またはメソッドが未定義である

`Syntax Error`
エラー文
unexpected keyword_end,expecting end-of-input
意味
括弧やカンマなどの構文間違いがある

`ArgumenError`
エラー文
wrong number of arguments (given X, expected Y)
意味
メソッドに渡す引数の数が間違っている

`Active Record::Migration Error`
エラー文
Migrations are pending
意味
未実行のマイグレーションがある

`ActiveRecord::Recordlnvalid`
エラー文
Validation failed: xxx
意味
データがバリデーションに反して保存に失敗している


`Active Controller::ParameterMissing`
エラー文
param is missing or the value is empty:xxx
意味
必要なパラメータが送信されていない

`Active Controller::UrlGenerationError`
エラー文
No route matches{:action=>"xx",:controller=>"xxx"},missing required keys:[:id]
意味
パスの後ろの引数(id)が正しく設定できていない
Javaで例外からスタックトレースを文字列として取得する

`StringWriter` と `PrintWriter` を組み合わせて使用する方法があります。<br>例外のスタックトレース全体を文字列に変換することができます。

## サンプルコード
```StackTraceToStringExample.java
import java.io.PrintWriter;
import java.io.StringWriter;

public class StackTraceToStringExample {
    public static void main(String[] args) {
        try {
            // 例外を発生させる（例として、0で割り算）
            int result = 10 / 0;
        } catch (Exception e) {
            // スタックトレースを文字列として取得
            String stackTrace = getStackTraceAsString(e);
            System.out.println("スタックトレース：");
            System.out.println(stackTrace);
        }
    }

    public static String getStackTraceAsString(Throwable throwable) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        throwable.printStackTrace(pw);
        return sw.toString();
    }
}
```

## 解説
1. `StringWriter` は、文字列データを蓄積するための Writer です。
2. `PrintWriter` は、`StringWriter` に例外のスタックトレースを出力するために使用します。
3. `throwable.printStackTrace(pw);` によって、例外のスタックトレースが `StringWriter` に書き込まれます。
4. `sw.toString();` でスタックトレースの文字列を取得します。

stackTraceには例外の詳細なスタックトレースが文字列として格納され、好きな場所で表示・処理することができます。

## Throwable クラスを引数に使う理由
メソッドで `Throwable` クラスのインスタンスを引数にする場合、`Exception` と `Error` の両方に対応できるため、エラーや例外の種類に関わらず一括で処理できる柔軟な方法となります。サンプルコードでは、`getStackTraceAsString` メソッドに `Throwable` を引数として渡しているため、以下のように例外だけでなくエラーにも対応できます。
RでGIS（投影法の定義と投影変換）

# shapefileの読み込み
```R
# Shapefileの読み込み
library(sf)
shapefile_data <- read_sf("hoge/hoge.shp")
```


# 投影法の定義
今回のデータはEPSG:6668 JGD2011なのでそれを定義するには、`st_crs`を使ってEPSGコードを指定する。
```R
st_crs(shp) <- 6668
```

shapefileの情報を見ると投影法（Geodatic CRS）がJGD2011となっていることがわかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/849a06a4-6c58-b9ce-3c16-bbe1891becd7.png)



 プロットしてみる
```R
ggplot(data = shp) +
  geom_sf()
  ```
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/7cfcd52b-56f3-9e1a-2052-264b411d3700.png)


# 投影変換
投影法を変換するには`st_transform`で変換した投影法のEPSGコードをしてする。
以下ではEPSG:6679 JGD2011平面直角座標系　第11系に変換する。
```R
shp_projection <- st_transform(shp,crs=6679)
```
情報を見るとは無事EPSG:6679 JGD2011平面直角座標系　第11系になっていることがわかる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/ee30dca0-b69d-cdc1-bd23-74ae60cd52af.png)

プロットしてみる
```R
ggplot(data = shp_projection) +
  geom_sf()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/a0bba0f9-4109-646d-eac2-e48ba80ea9c2.png)


無事投影変換できました。
【自主学習】ひたすらコードで覚えるC++［#2］

# はじめに
今回もC++の理解を深めるためにいろんなコードを見ていきます。

# 使用する環境
環境はVisual Studio 2022を使用します。

# if文をつかう
数字の10が入力されると「10が入力されました。」となり、それ以外の入力の場合、if文内の処理は実行されません。

```diff_c
#include <iostream>
using namespace std;

int main()
{
	int a;

	cout << "数字の10を入力してください。\n";

	cin >> a;

	if (a == 10) {
		cout << "10が入力されました。\n";
	}

	cout << "処理を終了します。\n";

	return 0;
}
```

# 複数の分岐をつくる
if-else if-else文をつかって条件による分岐を行います。
100か200を入力することで場合に応じた処理となります。また、それ以外の入力の場合は100か200を入れるように表示されるプログラムになっています。

```diff_c
#include <iostream>
using namespace std;

int main()
{
	int a;

	cout << "100or200を入力してください\n";

	cin >> a;

	if (a == 100) {
		cout << "100が入力されました。\n";
	}
	else if (a == 200) {
		cout << "200が入力されました。\n";
	}
	else {
		cout << "100か200を入力してください\n";
	}
	return 0;
}
```

# switch文を使った場合
switch文でも先ほどのif-else if-elseと同じ処理ができます。
switch文を使用する場合は変数aを整数型にする必要があります。また基本的にはbreak文をセットで使う必要があります。

```diff_c
#include <iostream>
using namespace std;

int main()
{
	int a;

	cout << "100or200を入力してください\n";

	cin >> a;

	switch (a) {
	case 100:
		cout << "100が入力されました。\n";
		break;
	case 200:
		cout << "200が入力されました。\n";
		break;
	default:
		cout << "100か200を入力してください\n";
		break;
	}

	return 0;
}
```
# for文をつかう
このコードでは繰り返しの処理を行っています。文章を何度も表示させることができます。(Hello Worldを5回表示させる)

```diff_c
#include <iostream>
using namespace std;

int main()
{
	for (int i = 1; i <= 5; i++) {
		cout << "Hello World!\n";
	}

	cout << "終了です。\n";

	return 0;
}
```

# 入力した値をつかう
入力した値をつかってfor文による繰り返し処理を行うこともできます。このプログラムでは入力した数値までを足し合わせて表示します。（※int型なので入力値は整数のみ）

```diff_c
#include <iostream>
using namespace std;

int main()
{
	int num;
	int sum = 0;
	
	cout << "いくつまでの合計を求めますか？\n";

	cin >> num;


	for (int i = 1; i <= num; i++) {
		sum += i;
	}

	cout << "１から" << num << "までの合計値は" << sum << "です。\n";

	return 0;
}
```

# do-while文をつかう
do-while文はwhile文と違い、条件を判断する前に、最低一回はブロック内の処理を行います。

```diff_c
#include <iostream>
using namespace std;

int main()
{
	int a = 1;

	do {
		cout << a << "回繰り返しています。\n";
		a++;
	} while (a <= 5);

	cout << "繰り返しが終了しました。\n";

	return 0;
}
```

# for文を使ってネストする
for文をネストすると、多重の繰り返し処理が行われます。

```diff_c
#include <iostream>
using namespace std;

int main()
{
	for (int i = 0; i < 5; i++) {
		for (int j = 0; j < 5; j++) {
			cout << "iは" << i << "jは" << j << "\n";
		}
	}

	return 0;
}
```

# 処理を飛ばすcontinue文
このプログラムでは番号を入力するとその番号（ここではaの値）の処理を飛ばすことができます。

```diff_c
#include <iostream>
using namespace std;

int main(){

	int a;

	cout << "処理を飛ばす番号を教えてください";

	cin >> a;

	for (int i = 1; i <= 10; i++) {
		if (i == a)
			continue;
		cout << i << "番目の処理です。\n";
	}

	return 0;
}
```

# 参考文献

この記事は以下の情報を参考にして執筆しました。
[やさしいC++ 第4版 (「やさしい」シリーズ) ](https://www.amazon.co.jp/%E3%82%84%E3%81%95%E3%81%97%E3%81%84C-%E7%AC%AC4%E7%89%88-%E3%80%8C%E3%82%84%E3%81%95%E3%81%97%E3%81%84%E3%80%8D%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E9%AB%98%E6%A9%8B-%E9%BA%BB%E5%A5%88/dp/4797370998)
【自主学習】ひたすらコードで覚えるC++［#1］

# はじめに
私自身C++についての知識はまだまだですが
今回から少しずつ理解を進めていきたいと思い
この記事の執筆を始めました。

- C++という言語が初めて
- 簡単なプログラムを書けるようになりたい

という方に向けた記事となります。

# 使用する環境
環境はVisual Studio 2022を使用しています。

# コードを書いてみよう
ここからは実際にサンプルコードを見ながらC++について
理解を深めていきます。

# 画面に文字列を出力する

coutとは標準出力（standard output）と呼ばれる、コンピュータの装置と結びついた言葉です。
ちなみに```using namespace std;```という一行をいれること（名前空間のこと）で
毎回 ```std::cout << "Hello World!\n";```と明記する必要がなくなります。

```diff_c
#include <iostream>
using namespace std;

int main()
{
	cout << "Hello World!\n";

	return 0;
}
```


# コメントアウトする

/**/をつかうとコメントとなり無視して処理します。
//をつかってコメントを書くこともできます。

```diff_c
#include <iostream>
using namespace std;

int main()
{
	/*cout << "Hello World!\n";*/

	return 0;
}

```


# 変数を使う

このコードではnumに7という数字を格納。そしてそのnumを使って表示をしています。

```diff_c
#include <iostream>
using namespace std;

int main()
{
	int num = 7;
	cout << "私が好きな番号は" <<  num  << "です\n";

	return 0;
}

```


# 数値を入力してみる

数値を入力するときはcin（標準入力：standard input）を使用します。このプログラムではint型を使用しているので入力は整数の値の場合のみ正常に動作します。

```diff_c
#include <iostream>
using namespace std;

int main()
{
	int num1, num2;
	cout << "1つ目の整数を入力してください。\n";

    cin >> num1;

    cout << "2つ目の整数を入力してください。\n";

    cin >> num2;

    cout << "1つ目の数字は" << num1  <<"です\n";
    cout << "2つ目の数字は" << num2  <<"です\n";
    
	return 0;
}

```


# 定数をつかう

このプログラムを実行するとエラーになります。constを指定した変数はその後変更することができなくなるためです。これを定数（constant）と呼ばれています。

```diff_c
#include <iostream>
using namespace std;

int main()
{
	const double pi = 3.1415;

	cout << "円周率の値は" << pi << "です。\n";

	pi = 5.34;

	return 0;
}

```

# 四則演算をする

数字を入力することで自動で計算するプログラムです。

```diff_c
#include <iostream>
using namespace std;

int main()
{
	double num1, num2;

	cout << "1つ目の数字を入力してください。\n";
	cin >> num1;

	cout << "2つ目の数字を入力してください。\n";
	cin >> num2;

	cout << "足し算の結果は" << num1 + num2 << "です\n";
	cout << "引き算の結果は" << num1 - num2 << "です\n";
	cout << "掛け算の結果は" << num1 * num2 << "です\n";
	cout << "割り算の結果は" << num1 / num2 << "です\n";


	return 0;
}
```

# 型や式のサイズを調べる

sizeof演算子を使うことで型や式のサイズを知ることができます。

```diff_c
#include <iostream>
using namespace std;

int main()
{
	int a = 1;
	int b = 3;

	cout << "int型のサイズは" << sizeof(int) << "バイトです\n";
	cout << "float型のサイズは" << sizeof(float) << "バイトです\n";
	cout << "double型のサイズは" << sizeof(double) << "バイトです\n";
	cout << "変数aのサイズは" << sizeof(a) << "バイトです\n";
	cout << "式a+bのサイズは" << sizeof(a+b) << "バイトです\n";

	return 0;
}
```


# さいごに
今回はコードを見ながらC++の文法を学んでいきました。今後もC++を使いながら
理解を深めていきたいと思います。

# 参考文献

この記事は以下の情報を参考にして執筆しました。
[やさしいC++ 第4版 (「やさしい」シリーズ) ](https://www.amazon.co.jp/%E3%82%84%E3%81%95%E3%81%97%E3%81%84C-%E7%AC%AC4%E7%89%88-%E3%80%8C%E3%82%84%E3%81%95%E3%81%97%E3%81%84%E3%80%8D%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E9%AB%98%E6%A9%8B-%E9%BA%BB%E5%A5%88/dp/4797370998)
【Error】死んだかと思った。恐ろしい呪文を使ってしまった。`docker compose down --volumes --remove-orphans`


今回恐ろしい呪文を使用してしまった出来事。死んだかと思いました。
どんな状況でどう解決したのか。一連の流れを記憶に残しておくためにも記事にしておきたいと思います。

## 環境
- Windows, WSL
- Docker
- Ruby 3.2.3
- Rails 7.1.3


## どういう状態だったのか
まず、タイトル記載の呪文を使う前の状況を簡単に説明します。
- ローカル環境では投稿が成功するものの、本番環境で投稿するボタンを押したら遷移先の画面（英語表記）で「このページはない」というような文言が書かれていた
- ターミナルログをみたらカラム10個あるうちの一つしか機能していない状態を確認
- スキーマファイルのテーブルを確認しても問題なさそう
- GPTに質問からの回答**Dockerのキャッシュの問題**


## 本題
どうやらDocker環境では、古いコンテナやキャッシュが残っている場合があるため、マイグレーションが正しく反映されないことがあるそうでタイトル記載のコマンドを実行してしまいました。
```
docker compose down --volumes --remove-orphans
```

そして、👆コマンドを実行したらローカルがつかなくなりました:scream:
なぜなのか。
後から上記コマンドについて検索をかけるおろかな私

https://qiita.com/suin/items/19d65e191b96a0079417

**バ○スなみの威力を持つ呪文でした**



## この後どうしたのか1
この後皆さんならどうしますか？（逆に聞きたい）
私は一日悩み＞＞講師の方に質問＞＞最終的に自分で解決:joy:

私が行ったこと👇滅びの呪文の後から
- **まずはクリーンな状態でコンテナを起動。イメージ構築**
`docker compose build`

- **次にコンテナ構築**
`docker compose up`
ここでエラーがでて、ローカルもつかない状態になりました。
エラー内容は「PostgreSQLデータベースが正しく初期化され、`myapp_development` と `myapp_test` というデータベースが作成されましたが`js.1 `と `css.1` の行に`esbuild: not found`や`tailwindcss: not found`というエラーがあります。これは、これらのツールが `Docker` コンテナ内にインストールされていない」という事でした

※この後`esbuild`と`tailwindcss`を`Docker`コンテナ内にインストールするため、いろんな？ファイルにコードを追記したり、再度`docker compose up`をするものの結果は同じ


## この後どうしたのか2
最終的に次の流れで無事解決しました
```
# 無駄に入力した内容は削除して一応バックアップを取っておく
cp -r . ../myapp_backup（myapp部分は仮）
docker compose build
docker compose run --rm web gem install rails

# esbuildとTailwind CSSのインストール
docker compose run --rm web yarn add esbuild tailwindcss

# Tailwind CSSの初期設定(tailwind.config.jsファイルが生成、既にある場合上書きされない
docker compose run --rm web npx tailwindcss init

# app/assets/stylesheets/application.tailwind.cssファイルの作成（既にあるならとばす）
@tailwind base;
@tailwind components;
@tailwind utilities;

# Procfile.devの確認（esbuildとtailwindcssが監視付きでビルドされる設定があるかどうか）
# 下記のような設定が含まれているか確認
js: yarn build:js --watch
css: yarn build:css --watch

# 最後にコンテナ構築
docker compose up
```
無事復活しました:joy:

https://qiita.com/tegnike/items/bcdcee0320e11a928d46

https://docs.docker.jp/compose/reference/up.html

👆`docker`コマンド再確認


## まとめ
無知ほど恐ろしいものはないですね。
講師の方に相談した時、時間の都合上その場で解決には至りませんでしたが「個々の部分調べてみて、試したりしても解決しなかったらまたきてください」という言葉をきいて少し気持ちを立て直すことができました。感謝です。
とりあえず、一安心？
今回の記事が何か参考になれば幸いです。
【超雑】ALB経由のみのアクセスを許可するEC2インスタンスの構築をした時のメモ

メモ程度に書きました
※https通信に対応するための手順は省略してます

:::message alert
本手順セキュリティや本番環境での正常な動作を保証するものではないことをご了承ください。
:::

:::message
経験を骨子として書き起こし、それを生成AIに投げて作ってもらった記事になります。
:::

## 全体像

AWSでアプリケーションを公開する場合、下記の要素を設定します。

1. **ALB (Application Load Balancer)**  
   - ALB向けのセキュリティグループ  
   - ターゲットグループ  
   - リスナー  
   - ルール  

2. **EC2インスタンス**  
   - EC2向けのセキュリティグループ  

ALB がクライアントからリクエスト（HTTP/HTTPS）を受け取り、EC2インスタンスへルーティングする仕組みです。

---

## ALB の構成と設定

### 1. ALB 用セキュリティグループ
- **許可するポート**  
  - 外部（一般ユーザー）のアクセスを受け付けるため、デフォルトでは HTTP(80) と HTTPS(443) をインバウンドで許可します。  
  - 開発・検証環境の場合、セキュリティ対策としてアクセス元IPを自分のグローバルIPなどに絞ることを推奨します。

### 2. ターゲットグループ
- **EC2インスタンスが存在するサブネット**を登録します。  
- EC2上のアプリケーションやWebサーバのリスンポートを指定します。たとえば、アプリケーションが 8080 番ポートを使っている場合には、ターゲットグループでも 8080 を設定します。

### 3. リスナー
- **ALB が受け付けるポート**を設定します。  
  - HTTP(80) や HTTPS(443) を一般的に利用します。  
  - HTTPS を使用する場合は証明書の設定も必要ですが、ここでは手順を省略しています。

### 4. ルール
- 特にカスタムルールが不要であれば、**デフォルトのルール**を利用し、ターゲットグループへ転送させます。  
- 複数ドメインやパスベースで振り分けたい場合は、追加ルールを設定します。

---

## EC2 インスタンスの構成と設定

### 1. EC2 用セキュリティグループ
- **アプリケーション/ Webサーバのポート**  
  - EC2のアプリケーションやWebサーバがリッスンしているポートをインバウンドで許可します。  
  - 許可元（ソース）は、ALB用のセキュリティグループを指定します（「sg-xxxxxx」などのIDを指定）。
- **SSH 接続 (22番ポート)**  
  - 管理者が接続するために使用するポートです。  
  - セキュリティ上、アクセス元IPを管理者の固定IPに絞ることを推奨します。

---

## まとめ

1. **ALB セキュリティグループ**では、外部からの HTTP/HTTPS アクセスを許可（または必要に応じて特定IPだけ許可）します。  
2. **ターゲットグループ**では、EC2インスタンスが属するサブネットと、アプリケーションがリッスンするポートを設定します。  
3. **ALB リスナー**では、クライアントからの HTTP/HTTPS リクエストを受け取るポートを指定します。  
4. **ルール**はデフォルト転送設定を利用し、必要に応じて追加設定を行います。  
5. **EC2 セキュリティグループ**では、ALB セキュリティグループからのインバウンドを許可（アプリケーションポート）、また管理者のSSHアクセス用にIP制限を行います。

これらを正しく設定することで、ALB経由でEC2上のアプリケーションに安全かつ適切にアクセスできるようになります。
Langchainを使ったAIチャットシステム開発のコンセプト理解

## 背景

とあるお仕事でOpenAI APIを使ったAIチャットシステム開発をしました。

この手のAIチャットシステムを作る際に欠かせないのが『Langchain』というライブラリなのですが、
このライブラリの概念理解に少々手こずったため、概念的な部分を共有できればと思います。

## Langchainの概要

一旦[公式](https://js.langchain.com/docs/get_started/introduction)の説明を載せます

```
LangChain は、言語モデルを利用してアプリケーションを開発するためのフレームワークです。
これにより、次のようなアプリケーションが可能になります。

- コンテキストを認識する: 言語モデルをコンテキストのソース
(プロンプトな指示、いくつかのショットの例、応答の基礎となるコンテンツなど) に接続します。

- 理由: 言語モデルに基づいて推論します 
(提供されたコンテキストに基づいて回答する方法、実行するアクションなど)。
```

あまりピンときませんね...

特に『言語モデルに基づいて推論します 』という表現は、あたかもLangchainがLLM/AIとしての機能を持っているかのように受け取れそうです
（初見の私はそのように理解してしまいました）

現在の私の理解としては**『OpenAI等のLLMモデルとのコミュニケーションをスムーズに行ってくれるライブラリ』** です。

## Langchainを使って何が嬉しいか

Langchainでは**LLMを意図通りに動かすためのプロンプトのテンプレートが提供されている**ため、そちらを使うことができます。
（プロンプトの中身は一部[こちら](https://smith.langchain.com/hub/hwchase17/react-chat?organizationId=799e55c9-da85-5ce1-b566-ecf76f105f5f)で参照可能）

プロンプトには一定の技術が必要ですが、Langchainやそのコミュニティ側でテンプレートを作ってくれているのでかなり便利ですね。

また、agentと呼ばれるコンセプトがあり、こちらを使うことで外部ツールを自動で使ってくれたり、ブラウザから期待するデータを取得できない場合に自動で再取得してくれる、といった処理を実現することが可能になります。
（おそらくagentの内部では、質の高いプロンプトや、LLMへのAPIcall時のパラメータ制御を行、LLMとうまくコミュニケーションしてくれている）

agentは外部ツールと連携したチャットサービスやRAGを構築する上で必須の概念かなと思います。

（別途Toolという概念もありますが、今回は説明を省きます。簡単に説明しておくと、toolはagentから呼び出される関数やインスタンスと思ってもらえたらいいと思っており、カスタムtoolを作成する際は「僕はこういうtoolだよ」という簡潔な説明文を定義する必要が出てきます。）

## 大まかな処理の流れ

BingSearchを行えるチャットサービスを作る際の大まかなバックエンド側の処理の流れを記載します。

```
[User]ユーザーの入力
↓
[APIサーバー]
↓
[APIサーバー内のLangchain]入力内容とチャット履歴、tool名(Bing-search等)を全てLLMに送る
↓
[LLM]送られてきた内容をもとに回答できそうであればそのまま回答し、toolを使う必要があればtool名を送り返す
↓
[APIサーバー内のLangchain]toolを使う必要があればtoolを実行。toolの実行結果と入力内容とチャット履歴、tool名を全てLLMに再送信する
↓
[LLM]送られてきた内容をもとに回答できそうであればそのまま回答し、toolを使う必要があればtool名を送り返す
...永遠ループ
↓
[Langchain]回答をもらい次第、レスポンスを変数に入れる
↓
[APIサーバー]ユーザーにレスポンス
```

## 終わりに

一旦テキストでまとめてみました。

## 参考サイト

1. [Langchain introduction](https://js.langchain.com/docs/get_started/introduction)
2. [OpenAI tools](https://js.langchain.com/docs/modules/agents/agent_types/openai_tools_agent)
NextJSの本当にあった怖い話

## 導入
あるプロジェクトで、ユーザー認証が必要なフルスタックアプリケーションをNextJSを使用して開発することになりました。このサービスはチャット機能を提供し、過去のチャット履歴を初期表示時にロードする機能がありました。

開発期間はタイトでしたが、予定通りに開発を完了し、一時の安堵（あんど）を得ていました。しかし、その後すぐに一つの問題が発覚しました。

## 不具合
ログアウト後、別のユーザーでログインしても1つ前のユーザーのチャット履歴が表示されてしまっていました。。。

業務アプリで秘匿情報を扱うため、リリース前に気づいて良かったと思います…

## 不具合の原因
この不具合の原因は、ログアウト処理を`next/navigation`を使用してログアウト画面へ遷移させているため、Redux store内のデータがクリアされずに残ってしまっていたことにありました。  
その結果、別のユーザーがログインしても、そのユーザーのチャット履歴がない場合ではRedux storeのデータが保持されてしまい、前のユーザーのデータを表示してしまう事態が発生していました。

## 解決策
この問題は、ログアウト処理を行う際に、Redux storeのデータもクリアすることで解決しました。具体的な実装例は以下のようになりました。

```
// ログアウト処理時にstoreをクリアする
const logout = () => {
  store.clear();
  // ログアウト処理やログイン画面へのrouting
}

```

## 終わりに
今回はNextJSを例に挙げましたが、SPAの技術では起こりやすい問題かなと思っています。ヒューマンエラーを回避するためにはいっそのことJavaScriptによるルーティングをなくしちゃえ、、、というのも個人的には全然アリだとは考えています（ただUX観点でどうなのか、、、など別の課題は出ると思いますが）

この記事を読んで、より良い実装方法や他に注意すべき点、似た事例があれば、ぜひコメントで共有いただけますと幸いです。
setIntervalのリスクと再帰的なsetTimeoutへの書き換え方法

とある社内プロジェクト、再起的に処理を実行したかったので安易に`setInterval`メソッドを使って実装しました。

社内レビューに出したところ「`setInterval`は指定した時間内に処理を完了できなかったら、処理が途中で終わるリスクがある」とのご指摘をいただきました。

この記事では、`setInterval`のリスクとそのリスクを回避するための代替案を記事にしました。

### setIntervalのリスク
例えば以下のようなコードがあるとします。
```
function myFunction() {
  // 100msより長い時間実行される処理
}

setInterval(myFunction, 100);
```

この時、100msを超えた時点で前の`myFunction`の処理と次のmyFunctionの処理が重なってしまい、前の`myFunction`の処理が正常に完了しないリスクがあるとのことでした。

### 再帰的なsetTimeoutへの書き換え
setIntervalの代わりに、再帰的なsetTimeoutへ書き換えができます。
これにより、前回の関数実行が完了する前に次の関数実行が発生する可能性が低くなります。

以下は、再帰的なsetTimeoutを使用してsetIntervalを置き換える例です。
```
function myFunction() {
  // 100msより長い時間実行される処理
  
  setTimeout(myFunction, 100);
}

// 最初の関数実行をトリガーするために、最初のsetTimeoutを呼び出します。
setTimeout(myFunction, 100);
```

このように実装することで、myFunctionの処理が完了する前に次のsetTimeoutが発生することはありません。


### 参考
https://ja.javascript.info/settimeout-setinterval#ref-618
【Rails】furimaアプリ　商品一覧表示機能　#1

# 実装概要
 - 商品一覧表示機能を実装する

### ルーティングの設定
```ruby:config/routes.rb
# 中略
resources :items, only: [:index, :new, :create]
# 中略
```

### コントローラー内にindexアクションを記述
```ruby:app/controllers/items_controller.rb
def index
    @items = Item.all
end
```

### eachメソッドを使って、商品情報を表示する
```ruby:app/views/items/index.html.erb
# 中略
    <ul class='item-lists'>
      <% @items.each do |item| %>
        <li class='list'>
          <div class='item-img-content'>
            <%= image_tag item.image, class: "item-img" %>

            <%# 商品が売れていればsold outを表示しましょう %>
              <div class='sold-out'>
                <span>Sold Out!!</span>
              </div>
            <%# //商品が売れていればsold outを表示しましょう %>

          </div>
          <div class='item-info'>
            <h3 class='item-name'>
              <%= item.name %>
            </h3>
            <div class='item-price'>
              <span><%= item.price %>円<br><%= item.shipping_fee.name %></span>
              <div class='star-btn'>
                <%= image_tag "star.png", class:"star-icon" %>
                <span class='star-count'>0</span>
              </div>
            </div>
          </div>
        </li>
      <% end %>

      <% if @items.empty? %>
        <li class='list'>
          <%= link_to '#' do %>
            <%= image_tag "https://tech-master.s3.amazonaws.com/uploads/curriculums/images/Rails1-4/sample.jpg", class: "item-img" %>
            <div class='item-info'>
              <h3 class='item-name'>
                商品を出品してね！
              </h3>
              <div class='item-price'>
                <span>99999999円<br>(税込み)</span>
                <div class='star-btn'>
                  <%= image_tag "star.png", class:"star-icon" %>
                  <span class='star-count'>0</span>
                </div>
              </div>
            </div>
          <% end %>
        </li>
      <% end %>
    </ul>
```
`<% if @items.empty? %>`でitemsテーブルが空のときにダミーの商品情報が表示されるようにしている。
### 左上から、出品された日時が新しい順に表示されるようにindexアクション内を修正
```ruby:app/controllers/items_controller.rb
# 中略
  def index
    @items = Item.order(created_at: :desc) # created_atの降順でソート
  end
end
# 中略
```
上記実装が確認できので、コードレビュー依頼！
1点修正あり。
誤ってコードを削除してしまっていた部分を復活させてLGTM
次の商品詳細表示機能実装に取り組んでいきます！！
【Ruby on Rails】Active Jobをsidekiqで使ってみる

## 環境
以下に後述のredisを加えて利用

https://qiita.com/kandalog/items/b8f001a02c8b95ae2fcc

## Active Jobとは？
Railsガイドから抜粋
> Active Jobは、ジョブを宣言し、それによってバックエンドでさまざまな方法によるキュー操作を実行するためのフレームワークです。

端的に言えば、時間のかかる処理を非同期に実行するための仕組みです。

キューの管理に使われるライブラリには[sidekiq](https://github.com/sidekiq/sidekiq)や[resque](https://github.com/resque/resque)等複数存在しますが、Active Jobがそれぞれの違いを吸収してくれることで、統一のインターフェースでの利用が可能です。

Railsでメールを送信するための機能であるAction MailerはActive Jobに依存しています。

## 準備

### 1 Queueing Backendとしてsidekiqのgemをinstall
```shell
bundle add sidekiq
```

### 2 configを編集/設定ファイル作成
`config/application.rb`
```rb
module Myapp
  class Application < Rails::Application
# ...  
    config.active_job.queue_adapter = :sidekiq
#...
```

`config/initializers/sidekiq.rb`
```rb
Sidekiq.configure_server do |config|
  # redisをdockerで立ち上げているならlocalhostをservice名に変更
  config.redis = { url: 'redis://localhost:6379' }
end

Sidekiq.configure_client do |config|
# redisをdockerで立ち上げているならlocalhostをservice名に変更
  config.redis = { url: 'redis://localhost:6379' }
end
```

`config/sidekiq.yml`
設定ファイルの作成は任意ですが、初期状態ではdefautのキューが1つだけ用意されます。
Action mailerを使う場合、mailersというキューを利用するので、追加しておくと良いです
```yml
:concurrency: 5
staging:
  :concurrency: 10
production:
  :concurrency: 10
:queues:
  - critical
  - default
  - low
```

### 3 sidekiqのプロセスを実行
Procfileとかでまとめると楽ですね
```shell
$ shidekiq
```

### 4 キューデータストアとしてredisを起動
今回はdockerを使っています
```yml
redis:
  image: redis:latest
  volumes:
    - ./redis:/data
  ports:
    - "6379:6379"
```

### 5 Web UIのroute設定
利用しているキューや、キューに残っているJobをWeb UIで確認可能です
[本番環境では認証プロセス設置した方が良い](https://github.com/sidekiq/sidekiq/wiki/Monitoring)
`config/routes.rb`
```rb
require 'sidekiq/web'

Rails.application.routes.draw do
  # ...
  mount Sidekiq::Web => "/sidekiq"
end
```

## Jobの作成
```
rails g job notification
```

`app/job/notification_job.rb`
```rb
class NotificationJob < ApplicationJob
  queue_as :default

  def perform(*args)
    user = args[0]
    # Do something later
    # 例えば外部APIを叩いて通知をするような処理 (ユーザーが追加されたことをお知らせする処理とか)
    Rails.logger.info("#{user.name}が追加されました")
  end
end
```

## 使い方
users_controller
```rb
def create
  # ...
  # Userを登録

  # User登録を知らせるJob(NotificationJob)をキューに追加
  NotificationJob.perform_later user
end
```

## deliver_now, deliver_later
```
deliver_now: 同期実行されるため、Railsと同一プロセスで実行される
deliver_later: queueにjobが入る。 非同期実行のため、キューイングバックエンドのプロセスで実行される
```

## その他enqueu方法
Jobの実行時間を指定、優先度の変更、複数Jobの一括登録などいろいろできる
[Railsガイド Active Job参照](https://railsguides.jp/active_job_basics.html)

## 参考
[Railsガイド Active Job](https://railsguides.jp/active_job_basics.html)

sidekiq系の公式情報
[Sidekiq GitHub](https://github.com/sidekiq/sidekiq) 

[Sidekiqの設定file](https://github.com/sidekiq/sidekiq/wiki/Advanced-Options) 
[Active Job連携](https://github.com/sidekiq/sidekiq/wiki/Active-Job) 
[redis連携](https://github.com/sidekiq/sidekiq/wiki/Using-Redis) 
[Web UI](https://github.com/sidekiq/sidekiq/wiki/Monitoring)
Could not locate module XXX.css mapped as: identity-obj-proxy.のエラー解決方法

## はじめに
ReactとTypeScriptのアプリのテストをJestを用いて実行したときに、`Could not locate module ./＜ファイル名＞.css mapped as: identity-obj-proxy.`というエラーが発生したので解決方法をまとめます。

## エラー内容
このエラーは、JestがCSSやLESSファイルを、テスト環境でモックとして扱うために`identity-obj-proxy`というパッケージを使用するが、今回は正しくインストールされていないことが原因らしい。

## 解決方法
以下のコマンドをルートディレクトリで実行する。
```terminal:terminal
npm install identity-obj-proxy --save-dev
```

すると、package.jsonの`devDependencies`セクションに、`identity-obj-proxy`が設定され、テストが上手く動作しました。

```json:package.json
{
  "devDependencies": {
      "identity-obj-proxy": "^3.0.0",
  }
}
```

## 補足事項
テストは成功しましたが、以下の注意文が出力されました。
```terminal:terminal
If you have issues related to imports, you should consider setting esModuleInterop to true in your TypeScript configuration file (usually tsconfig.json). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
```
こちらの解決方法は、`tsconfig.json`に以下の内容に修正することで、注意文が出力されなくなりました。
```diff_json:tsconfig.json
- "compilerOptions": { "jsx": "react-jsx",}
+ "compilerOptions": { "jsx": "react-jsx", "esModuleInterop": true }

```

## 参考サイト

https://qiita.com/kashimuuuuu/items/3b1b02a07ae5d97c05e3
タイトル: Pythonのリスト内包表記でコードをシンプルに！データ処理の効率化テクニック

### タイトル: **Pythonのリスト内包表記でコードをシンプルに！データ処理の効率化テクニック**

#### 1. はじめに
Pythonでのデータ処理において、リスト内包表記は非常に強力なツールです。リスト内包表記を使うと、ループや条件式をシンプルに書き直せるため、コードが見やすくなり、実行速度も向上します。この記事では、リスト内包表記の基本と、実際の使い方を例を交えて解説します。

#### 2. リスト内包表記とは？
リスト内包表記（List Comprehension）は、リストを生成するための短い構文です。通常のforループでリストを生成する場合と比べ、内包表記を使うことで一行で完結でき、コードが簡潔になります。

基本的な構文:
```python
# [式 for 変数 in イテラブル if 条件]
```

#### 3. リスト内包表記の基本例
まずは、リスト内包表記のシンプルな例から見ていきましょう。

```python
# 通常のforループを使ってリストを生成
numbers = [1, 2, 3, 4, 5]
squared_numbers = []
for num in numbers:
    squared_numbers.append(num ** 2)

print(squared_numbers)  # 出力: [1, 4, 9, 16, 25]

# リスト内包表記を使った場合
squared_numbers = [num ** 2 for num in numbers]
print(squared_numbers)  # 出力: [1, 4, 9, 16, 25]
```

リスト内包表記を使用すると、forループを一行にまとめられ、より読みやすいコードになります。

#### 4. 条件付きのリスト内包表記
リスト内包表記では、条件式を組み合わせることも可能です。例えば、偶数の数値だけを二乗するコードを見てみましょう。

```python
# 条件付きリスト内包表記
even_squared_numbers = [num ** 2 for num in numbers if num % 2 == 0]
print(even_squared_numbers)  # 出力: [4, 16]
```

このように、`if`を使って条件を指定することで、必要な要素だけを選択して処理することができます。

#### 5. ネストされたリスト内包表記
リスト内包表記はネストすることもできます。例えば、2次元リストの全要素にアクセスする場合を見てみましょう。

```python
# 2次元リストの全要素を1次元リストに変換
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened)  # 出力: [1, 2, 3, 4, 5, 6, 7, 8, 9]
```

ネストした内包表記はコードをさらに短くし、よりコンパクトな表現が可能です。

#### 6. まとめ
リスト内包表記は、Pythonコードを効率的に書くための重要なテクニックです。読みやすさを維持しながらコード量を削減でき、特にデータ処理においてその威力を発揮します。次回のコードを書く際には、ぜひリスト内包表記を試してみてください。

> **皆さんの経験やおすすめのテクニックがあれば、コメントで共有してください！**
Python初心者必見！mutableとimmutableの違い

Pythonにおけるmutable（可変）とimmutable（不変）の違いは、オブジェクトの内容を変更できるかどうかという点にあります。可変と不変の違いを理解することで、バグを防止したり、適切なデータ構造を選択したりすることができます。

### mutable（可変）とは？
オブジェクトの内容を変更することが可能。例えば、リストや辞書のように一度作成した後でも、内部の要素を変更できるオブジェクトが該当します。

代表的なmutableなオブジェクト
- list（リスト）
- dict（辞書）
- set（集合）
- bytearray

```python
# リストの要素を変更する
my_list = [1, 2, 3]
print(id(my_list)) # 140007375707712
my_list[0] = 100  # 1 → 100 に変更
print(id(my_list)) # 140007375707712
print(my_list)  # [100, 2, 3]
```

my_listはリストで、要素を直接変更することができます。オブジェクト（140007375707712）は変わっていないです。

### immutable（不変）とは？

オブジェクトを一度作成した後、その内容を変更できない。例えば、文字列やタプルのように要素を変更する操作が許されないオブジェクトが該当します。

代表的なimmutableなオブジェクト
- str（文字列）
- tuple（タプル）
- int（整数型）
- float（浮動小数点数型）
- frozenset（凍結された集合）

```python
# 文字列の内容を変更しようとする

my_string = "hello"
# my_string[0] = 'H'  # これはエラーになる

print(id(my_string)) # 140426410082544

# 新しい文字列を作成する（元の文字列は変更されない）

my_string = "H" + my_string[1:]
print(id(my_string)) # 140426410083248
print(my_string)  # "Hello"
```

文字列my_stringは不変で、部分的に内容を変更することはできません。代わりに新しい文字列を生成する形になります。オブジェクトID（140426410082544⇒140426410083248）も変わった。

### 可変と不変の違いが重要になる場面
- 関数の引数の扱い
可変オブジェクトを関数に渡すと、元のオブジェクトが直接変更される場合があります。

例：可変オブジェクトを関数に渡した例
```python
def add_item(lst):
    lst.append(100)

my_list = [1, 2, 3]
add_item(my_list)
print(my_list)  # [1, 2, 3, 100]
``````
関数add_itemにリストmy_listを渡したところ、元のリストが直接変更されました。

例：不変オブジェクトを関数に渡した例

```python
def add_value(num):
    num += 100

my_num = 50
add_value(my_num)
print(my_num)  # 50（変更されない）
```

- 辞書のキーとしての使用
immutableなオブジェクトは辞書のキーに使用できますが、mutableなオブジェクトは使用できません。

例：タプルを辞書のキーに使う
```python
my_dict = { (1, 2): "point A" }
print(my_dict[(1, 2)])  # "point A"
```

例：リストを辞書のキーに使おうとするとエラーになる
```python
# my_dict = { [1, 2]: "point B" }  # TypeError: unhashable type: 'list'
```

リストはmutableなため、辞書のキーには使えません。一方でタプルはimmutableなので、辞書のキーとして使えます。


### まとめ

|特性	|mutable（可変）|	immutable（不変）|
|--|--|--|
|代表例	|リスト、辞書、集合	|文字列、タプル、整数|
|内容の変更	|可能	|不可能|
|辞書のキーとして使用	|不可	|可能|
|関数内での影響	|元のオブジェクトが変更される	|元のオブジェクトは影響なし|
マイクラのサトウキビは何分周期で収穫すべきか

## はじめに
マイクラをやっていてサトウキビの収穫を自動化したいこと、ありますよね。
多くの場合、オブザーバーで成長を検知してピストンに伝えるか、長周期クロック回路で定期的にピストンを作動させるかの二択となると思います。

今回は、長周期クロック回路を用いる場合にクロック周期を何分にすると最も効率よく収穫できるかを求めます。

## 前提
### ランダムティック
Minecraftのゲームティックは毎秒20ticksであり、それぞれのtickで一辺16ブロックの立方体からランダムにブロックを1つ選ぶ処理が3回行われます。

### サトウキビの成長
サトウキビは、最上部のブロックが16回ランダムティックを受け取ると高さが1増えます。ただし、既に高さが3に達している場合は成長しません。また、サトウキビの上の空間がブロックで塞がれたり、高さ3のサトウキビが破壊されて高さ1になったりすると、ティックのカウントはリセットされます[^1]。
[^1]: [サトウキビ - Minecraft Wiki](https://minecraft.fandom.com/ja/wiki/%E3%82%B5%E3%83%88%E3%82%A6%E3%82%AD%E3%83%93)（2024/10/26閲覧）

## 本編
$n$ティック経過する間にあるサトウキビがちょうど$k$回ランダムティックを受ける確率$P(k)$はPoisson分布に従うと仮定すると、
$$
P(k)=\frac{e^{-3np}(3np)^k}{k!}
$$
と表されます。ただし、$p=\frac1{4096}$です。

ある時刻に高さ1、ティックのカウントが0だったサトウキビが成長していくことを考えます。
$n$ティック経過後にサトウキビの2段目を破壊して収穫すると、得られるサトウキビの個数の期待値は
$$
\sum_{k=16}^{31}P(k)+2\sum_{k=32}^\infty P(k)=2-2\sum_{k=0}^{15}P(k)-\sum_{k=16}^{31}P(k)
$$
となります。

:::note info
上のように変形することで無限級数を有限個の項の和で表せるため、コンピュータによる計算がしやすくなります
:::
横軸に経過時間（分）、縦軸に収穫できるサトウキビの個数の期待値をとってグラフを描くと以下のようになります。
![スクリーンショット 2024-10-26 17.38.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825539/8954962c-543b-d1f1-2225-07fa4eb3fbc1.png)

最大化したいのは単位時間あたりの収穫量なので、縦軸を1分あたりの収穫量にすると以下のようになります。
![スクリーンショット 2024-10-26 17.44.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825539/1932268c-dad1-6358-666b-4ca852e7901e.png)

このグラフはクロック周期約41.044分（41分と2.65秒）で最大の値をとります。
よって、41分程度の周期のクロック回路を組むことでサトウキビの収穫量を最大化させられることがわかります。

1チャンク内に水とサトウキビを
```
水→サトウキビ→サトウキビ→水→サトウキビ→サトウキビ→...
```
の順で配置して縞模様にした場合、1チャンクあたり$16^2/3 \approx 85$個程度のサトウキビを植えられるため、1チャンクあたり毎時約220個（3スタック半程度）のサトウキビが収穫できます。
GodModeの作成方法

「GodMode」とは、Windowsで使用できる隠し機能で、システム設定や管理ツールへのアクセスを1つのフォルダーに集約することができます。通常、コントロールパネルから順に設定を辿る必要があるものを、GodModeを使うと一覧からすぐにアクセスでき、非常に便利です。この機能は、管理者向けの強力なツールであるため「GodMode」と呼ばれています。

### GodModeの設定方法

1. **デスクトップに新しいフォルダーを作成**  
   任意の場所に新しいフォルダーを作成します。デスクトップがわかりやすい場所です。

2. **フォルダーに名前をつける**  
   作成したフォルダーの名前を以下のように変更します：

   ```
   GodMode.{ED7BA470-8E54-465E-825C-99712043E01C}
   ```

   フォルダー名の「GodMode」は自由に変更可能ですが、**カッコ内のコードはそのまま**にしてください。

3. **設定完了**  
   名前を変更するとフォルダーのアイコンが「コントロールパネル」のようなアイコンに変わり、ゴッドモードが有効になります。

4. **GodModeの利用**  
   ゴッドモードのフォルダーをダブルクリックすると、様々な設定項目が一覧表示され、ワンクリックで目的の設定にアクセスできます。

### GodModeの特徴
- Windowsのすべての管理機能、設定オプションに一括でアクセス可能
- 項目はカテゴリ別に整理されており、設定の検索も容易
- 時間を節約し、迅速に設定を変更できる
CakePHPのファイル名の規約について

# 記事作成の背景
CakePHPでアプリを作成するときに画面(ビュー)のファイル名の命名規則でハマってしまったのでメモ。

https://book.cakephp.org/4/ja/intro/conventions.html

# ソフトウェアのバージョン
|ソフトウェア|バージョン|
|-----------|---------|
|CakePHP    |4.7.5    |
|PHP        |8.1      |


# 画面(ビュー)のファイル名はキャメルケースは使用しない。
CakePHPの経験が浅はかだったので、C#やJavaのようにキャメルケースでファイルを作ってしまい。
<b>「Missing Template～」</b>と怒られてしまいました。

下記にエラー時のファイル名と正しいファイル名の比較を記載します。


```allUsers.php(エラーとなったファイル名)
    <div>
        <table>
            <thead>
                ヘッダー名入力
            </thead>
            <tbody>
                内容を入力
            </tbody>
        </table>
    </div>
```

```allusers.php(正しいファイル名)
    <div>
        <table>
            <thead>
                ヘッダー名入力
            </thead>
            <tbody>
                内容を入力
            </tbody>
        </table>
    </div>
```

こんな感じで、ビューのファイル名は①すべて小文字にする形式、または②アンダースコアの形式(例all_users.php)
にするのが正しい記法です。

以上です。
Markdown AIを使った調査例　「高校数学の網羅系問題集」

# はじめに
Markdown AIで「高校数学の網羅系問題集」について生成AIを作りました。

## プロンプト
今回は
**私は高校生です。数学が得意です。 数学が得意向けの問題集を５冊挙げてください。**
でプロンプトを作りました

## 回答
回答は以下の通りです

数学が得意な高校生向けの問題集を5冊ご紹介します。これらの問題集は、より高度な数学的思考や応用力を養うのに役立ちます。 

**「数学オリンピックへの道」シリーズ（著者：高橋健太郎）** - 数学オリンピックを目指す人向けの問題集で、論理的思考や創造力を鍛える問題が多数収録されています。 

**「新数学スタンダード問題集」シリーズ（著者：数研出版）** - 基礎から応用まで幅広いレベルの問題が揃っており、特に難易度の高い問題も多く含まれています。

**「大学入試の数学」シリーズ（著者：河合塾）** - 大学入試に向けた問題集で、難易度が高く、実践的な問題が多く収録されています。特に難関大学を目指す人におすすめです。 

**「チャート式数学」シリーズ（著者：数研出版）** - 理論と問題演習がバランスよく組み合わさっており、特に応用問題に強くなりたい人に適しています。 

**「難関大への数学」シリーズ（著者：旺文社）** - 難関大学の入試問題を中心に構成されており、実際の試験に即した問題を解くことで、実力を養うことができます。 これらの問題集を活用して、さらに数学の力を伸ばしていってください！


## 感想
ペルソナめっちゃ入ってませんか？

# 最後に
Markdown AIはまだまだ改良の余地が多いと感じました。
Rye で Python 開発環境を構築するためのコマンドや説明などのメモ

## 概要

パッケージ管理にpoetryを使用していましたが、 Python の**パッケージ管理**と**バージョン管理**ができる`Rye`を使い始めたので、導入から環境構築までの手順をまとめました。

参考：[Ryeの公式ドキュメント](https://rye.astral.sh)

パッケージ管理などの使い方はこちら

https://qiita.com/p-marry/items/8382a395962eb73095ff

### 手順まとめ

-   Rye のインストール
-   Rye の Python 環境構築、バージョン管理
-   Rye 自体のバージョン管理など

## Rye のインストール

1. [Rye の公式ドキュメント](https://rye.astral.sh)からインストーラーをダウンロードします
1. ダウンロードしたインストーラーで Rye をインストールします
    - 「続行して良いか」などの質問がされましたが、全て`y`を選択しました
1. インストールが完了すれば、ターミナルで

    ```bash
    rye --version
    ```

    を実行し、Rye のバージョンが表示されたら、インストール完了です

## Rye の Python 環境構築、バージョン管理

### toolchain list

現在 Rye にインストールされている Python バージョンの一覧を表示します

```bash
rye toolchain list
```

### toolchain list --include-downloadable

Rye にインストール可能な Python バージョン一覧を表示します

```bash
rye toolchain list --include-downloadable
```

-   実行すると、インストール可能なバージョン一覧が表示されます
    `downloadable`は「ダウンロード可能」という意味です

    ```bash
    cpython@3.13.0 (downloadable)
    cpython@3.12.7 (downloadable)
    cpython@3.12.6 (downloadable)
    # …(一覧表示されます)
    ```

### toolchain fetch <バージョン名>

Rye に任意の Python バージョンをインストールします

-   <**バージョン名**>の部分を`toolchain list --include-downloadable`で表記されたものに書き換えて入力してください

```bash
rye toolchain fetch <バージョン名>
```

### toolchain remove

Rye から任意の Python バージョンを削除します

-   <**バージョン名**>の部分を`toolchain list`で表記されたものに書き換えて入力してください
-   アクティブに使用されているツールチェーンを削除すると、use を参照する virtualenv が壊れてしまうそうです。

```bash
rye toolchain remove <バージョン名>
```

## Rye 自体のバージョン管理など

### --version

現在の Rye のバージョンを表示します

```bash
rye --version
```

### self update

Rye を最新版に更新します

```bash
rye self update
```

### self uninstall

Rye を完全にアンインストールします

```bash
rye self uninstall
```
RxJS の購読終了(unsubscribe)の動作確認して理解を深めるまで

## 前置き
購読終了(unsubscribe)しないとずっとオブジェクトが残るという話を聞いた。  
で気になったあれこれを調べて動作確認をしたのでそのメモ。  

## 本編
### ほんとに購読終了(unsubscribe)しないとずっとオブジェクトが残るの？
私はAngular を使っており、ページ遷移してコンポーネントが破棄されたらガベージコレクトされるのでは？  
となんとなく思っていた。  

しかし、実際に確認したところ、確かにオブジェクトが残っていた。  
確認方法  
下記ページの適当なボタンを押して他のページへ遷移したが、console.log が出力され続けた。  
また、chrome の開発者モードでmemory のsnapshot を取って比較したところ、それっぽいオブジェクト※が存在した。  

https://magurouhiru.github.io/mysite/#/study/unsubscribe

※それっぽいオブジェクトとは  
{next, error, complete} 内にmain-AF7LBRZG.js:367 とあった。  
当該箇所はページ遷移前のコンポーネントだったので、それっぽいと記載した。  

### どのように購読終了(unsubscribe)すればいいのか？
一番単純な方法はsubscribe() の戻り値に対してunsubscribe() を実行する方法。  
ただし、これでは1個しかunsubscribe() できない。  
他のやり方としては、Subscription インスタンスにadd() で登録しまとめてunsubscribe() する方法。  
これであれば複数に対応できる。  
いずれにしても、RxJS で提供されている機能を使う分にはunsubscribe() が必要である。  

筆者のようにAngular で使用するには以下を使うこともできる。  
- AsyncPipe
    - Observable を渡せば(un)subscribe を自動でしてくれる。
    - @if, @let と組み合わせることが大半だと思う。
- takeUntilDestroyed
    - subscribe 後にコンポーネント破棄のタイミングで購読終了する。
    - 正確にはストリームをcomplete するのでunsubscribe とは違う。

https://angular.jp/api/common/AsyncPipe?tab=usage-notes

https://angular.jp/api/core/rxjs-interop/takeUntilDestroyed

## 感想
楽しかった。  
あと、ガベージコレクトの対象が思ってたのと違って驚いた。  

今回の記事は以上です。  

前回記事はこちら  

https://qiita.com/magurouhiru/items/0c71f028e7a378fb3b3a

詳細見たい人はこちら  

https://github.com/magurouhiru/mysite/pull/49

https://magurouhiru.github.io/mysite/#/study/unsubscribe
画像の ALT を考えてくれるショートカットの作り方

## 作るもの

SNSに画像をアップロードするとき、ALTを設定するのがよいとされています。このALTの内容を、ChatGPTに画像を送りつけて考えてもらいそれをクリップボードに入れて、あとはALTの入力欄にペーストするだけにするショートカットを作りました。
このショートカットはOpenAIのAPIキーと最低限のチャージ$5が必要になります。なので、作ったものをiCloudで共有したりはできないのですが、その代わりに作り方をここに残しておきます。
ある程度ショートカットの作り方を知ってる方向けに説明します。
また、ショートカットはiPhoneから作れるのが気軽なところですが、今回はPOST時に必要となるJSON（辞書）の構造が複雑なので、Macから作るのを想定して説明します。

MacOS14.5とiOS18.0.1で動作確認をしています。

## OpenAIのAPIキーの取得方法

https://platform.openai.com/docs/api-reference/api-keys

ここにも書いてありますが、ProjectKeyの方を作ります。作ったらその内容を控えておいてください。
また、このキーは他人に知られてしまうと勝手にお金を使われてしまう危険があるので、取り扱いは注意してください。これで作ったショートカットを共有しても他人に知られてしまうので、このショートカットは共有しないように気をつけましょう。

課金の方はまだしなくてもいいです。必要になるところまで進められたら課金しましょう。

## 作り方

大まかにいうと、画像をBase64エンコードしてから「URLの内容を取得」でPOSTを使ってAPIに送りつけ、その返答をクリップボードに入れます。
以下、細かくみていきます。

### 1. 画像をBase64エンコードし、パラメータをつけるまで

1. 画像の入力を受け付けます
1. 1-1の画像をjpegに変換します
1. 1-2の画像を縮小します
1. 1-3の画像をBase64エンコードして文字列にします
1. 「テキスト」とマジック変数を組み合わせて、`data:image/jpeg;base64,` という文字列を1-4の先頭につけます 

![スクリーンショット 2024-10-26 16.50.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116105/8ae880ef-16c0-8fc1-f952-4b524de1ee08.png)

画像縮小は絶対にしましょう。多分お金の節約になります。

### 2. 「URLの内容を取得」を使ってPOSTする

1. 「テキスト」にAPIキーを貼り付けます
1. 2-1とは違う、もう一つの「テキスト」とマジック変数を組み合わせて、 `Bearer ` (スペースを入れるの大事です)という文字列を2-1の先頭につけます
1. 「URLの内容を取得」のURLに `https://api.openai.com/v1/chat/completions` を設定します
1. 方法を `POST` に設定します
1. ヘッダー情報として、キーに `Content-Type` 値に `application/json; charset=utf-8` を設定します
1. ヘッダー情報として、キーに `Authorization` 値にマジック変数で2-2を設定します
1. 本文を要求をJSONにします
1. 以下の画像のように辞書を作ります

![スクリーンショット 2024-10-26 17.07.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116105/b180c9cd-e8b1-e6e2-1678-fa1bcd3751cb.png)

キモになるのはcontent内のtextで「この画像には何が写っていますか？」と日本語で訊いてるところです。ここが日本語なんでお返事も日本語で帰ってきます。ここのテキストは目的に合わせてチューニングの余地あり。
もう一つのキモはimage_url内のurlでマジック変数を使い1-5を指定するところです。これでurlという名前ですが、パラメータが付けられたBase64エンコードされた画像をアップロード出来ます。

また、2-2がわかりづらいのですが、ここをスクショにしてしまうとAPIキーが写ってしまうのですみません。1-5と同じようなことをして、認証用の文字列を作ってください。

### ここで一旦リクエストを飛ばしてみる

ここまででリクエストを飛ばす準備ができたので、試しに適当な画像をアップロードしてみます。
すると、エラーが返ってくると思います。課金をしてないからです。最低$5からチャージができるので、そこはご自分でやり方を探して課金してください。
お金の話は下手な説明ができない部分なのですみません。
レスポンスが無事に返ってくるようになったら、次に進みます

### 3. 返ってくるJSONの値を取りだし、クリップボードに入れる

目的のテキストはJSONの3階層目にあるので、「辞書の値を取得」を3回使って取り出します。

1. 「辞書の値を取得」を使い、2-8の返答の内の choices の値を取得します
1. 3-1の内の message の値を取得します
1. 3-2の内の content の値を取得します
1. 「結果を表示」で3-3の値を表示します
1. 「クリップボードにコピー」で3-3の値をクリップボードに入れます

3-4での結果は全文見えませんが、大きく外れた結果が返っていないかの確認だけなので全文見えなくてもいいかなぁと思ってます。
最後に返答の値がクリップボードにコピーされるようにして、完成です。

## 参考URL

- https://platform.openai.com/docs/api-reference/making-requests
- https://platform.openai.com/docs/guides/vision/uploading-base64-encoded-images
UIコンポーネントの素材サイト：Magic UI

最近よくnextjsでフロントエンド開発をしているんですが、Magic UIというとても便利なUIコンポーネントサイトを見つけました。デザインがすごいいいですし、cursorと合わせて使うとかなり便利ですので、紹介したいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/6b9c0b58-1cc6-f193-b229-9c88939da855.png)


例えば、使いやすいコンポーネントやフォントエフェクトなどがあります。⇩

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/7930fc14-83c5-a937-ddc9-f4b7a366cf0c.png)

あるいは、⇩のような一つのモジュール全体もあります。ダウンロードすれば普通に使えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/93af8c36-b153-d274-63de-bf2afdaa0524.png)

LangdingPageのテンプレートもあります。（これは無料ではなく100ドルかかりますが、価格的には高くはないと思います。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/577aad6b-2fc9-a9c4-1397-27d62daae511.png)

私は基本的にCursorと組み合わせて使っています。ここからコンポーネントをダウンロードし、Cursorでそれをメンションすれば、他のページにも反映させます。だいたい2,3回の実行で実装できます。


興味ある方:

https://magicui.design/docs/templates/startup
【Rails】furimaアプリ　商品出品機能実装　#4

# 実装概要
- コードレビュー後の指摘部分を修正
  - 商品の出品に失敗して出品ページに戻った際もjavascriptが動作するよう、renderメソッドに対応したイベントを追加
  -   priceカラムは、整数のみ保存が行われるようバリデーションを追加
理由：現状の記述だと、小数の販売価格が保存できてしまうため
  - カテゴリーの選択肢が見本アプリと異なるようなので、確認の上、コードを修正

### 商品の出品に失敗して出品ページに戻った際もjavascriptが動作するよう、renderメソッドに対応したイベントを追加

```ruby:app/javascript/items_new.js
function setPriceEventListener() {
  const priceInput = document.getElementById("item-price");
  const addTaxDom = document.getElementById("add-tax-price");
  const profitDom = document.getElementById("profit");

  if (!priceInput) return;

  priceInput.addEventListener("input", () => {
    const inputValue = priceInput.value;

    if (inputValue >= 300 && inputValue <= 9999999) {
      const tax = Math.floor(inputValue * 0.1);
      const profit = inputValue - tax;

      addTaxDom.innerHTML = tax.toLocaleString();
      profitDom.innerHTML = profit.toLocaleString();
    } else {
      addTaxDom.innerHTML = '';
      profitDom.innerHTML = '';
    }
  });
}

document.addEventListener('DOMContentLoaded', setPriceEventListener);
document.addEventListener('turbo:load', setPriceEventListener);
document.addEventListener('turbo:render', setPriceEventListener);
```
1. **`setPriceEventListener`関数**：`setPriceEventListener`という名前で関数を定義し、イベントリスナー内の処理をまとめる
2. **`if (!priceInput) return;`**：ページに`priceInput`が存在しない場合、エラーを防止するためにイベントの登録をスキップ
3. **各イベントに`setPriceEventListener`を追加**：`DOMContentLoaded`、`turbo:load`、`turbo:render`の3つのイベントで動作するように設定

### priceカラムは、整数のみ保存が行われるようバリデーションを追加
```ruby:app/models/item.rb
# 中略
validates :price, presence: true, numericality: {
    only_integer: true,
    greater_than_or_equal_to: 300,
    less_than_or_equal_to: 9_999_999
  }
```
**`only_integer: true:`** このオプションを追加することで、priceの値が整数であることを強制する。

併せて単体テストコードに`priceが整数以外の場合は出品できない`を追記
```ruby:spec/models/item_spec.rb
# 中略
it 'priceが整数でないとき出品できない' do
        @item.price = 5000.5
        @item.valid?
        expect(item.errors.full_messages).to include 'Price must be an integer'
      end
# 中略
```
### カテゴリーの選択肢が見本アプリと異なるようなので、確認の上、コードを修正
```ruby:app/models/category.rb
class Category < ActiveHash::Base
  self.data = [
    { id: 1, name: '---' },
    { id: 2, name: 'メンズ' },
    { id: 3, name: 'レディース' },
    { id: 4, name: 'ベビー・キッズ' },           #修正
    { id: 5, name: 'インテリア・住まい・小物' },  #修正
    { id: 6, name: '本・音楽・ゲーム' },         #修正
    { id: 7, name: 'おもちゃ・ホビー・グッズ' },
    { id: 8, name: '家電・スマホ・カメラ' },
    { id: 9, name: 'スポーツ・レジャー' },
    { id: 10, name: 'ハンドメイド' },
    { id: 11, name: 'その他' }
  ]

  include ActiveHash::Associations
  has_many :items
end
```

これは単純な確認ミスなので今後は出てこないようにしていきたいです。
指摘部分の修正が完了したので、再度コードレビューを依頼してきます！！

LGTMいただいたので次の実装に取り組んでいきます！！
未経験文系卒が現場で意識していること

## はじめに
文系卒未経験でこの業界に入ってきた私にとって現場で出てくる単語や情報は本当に最初理解するのが難しいと感じていました。
そこで今後の備忘録も兼ねて個人的に何を意識して現場で仕事をしているか大きく分けて３つ書いていこうと思います。



## 設計書のある場所を把握しておく
現場所属後に最初設計書の読み込みなどはあるかと思いますが、業務を進めていくと最初に読み込んだ設計書だけでは情報不足になること、或いは忘れてしまう部分が出てくると思います。

そんな時設計書を１から探していたのでは作業効率が低下してしまう恐れがあります。

↓(どう対処したか)

<INS>**実施した対処法**</INS>
・<INS>設計書が格納してあるフォルダのショートカットを作成してローカルに保存</INS>
・<INS>リポジトリブラウザのリンクをMicrosoftedgeのブックマークに保存して接続しやすいようにする。</INS>

新しく見る設計書が必要になった時、ある程度あたりを付けることができていれば予想立てて設計書の場所を調べられるので業務効率化、質問のしやすさにも繋がると思います。

## プロジェクト全体のスケジュール(WBS)を把握しておく
最初にスケジュールを把握することで２つのメリットがあると考えます。
<INS>① 今手を付けている業務を何故実施する必要があるのかが分かる<INS>

<INS>② 全体のスケジュールを把握できれば現在のタスクの大まかな期限を把握できる<INS>

<INS>**試して実際に感じたことの例**</INS>
・設計書の修正と実機の修正が必要になった時、スケジュールを把握していたから結合テストで出た不具合だと瞬時に理解できたこと。
・何故この業務を進めなければならないのか理由が分かるので業務内容もをより覚えることができるし、責任感も上がったこと。



## 使用したコマンドもメモに残しておく
現場所属して使用するコマンドは知識として知っていても実際に使うとなると出てこないことがあります。
なので使用したコマンドはメモに残しておくのが良いと思います。

**<INS>個人で実際に取ったメモの仕方の例。</INS>**
```ruby:(例)コマンド
"ディレクトリの追加を行う"
mkdir #ディレクトリを追加
mkdir -p  #複数の階層のディレクトリを一気に作成可能
chmod 777 #ディレクトリやファイルに権限設定
chmod -R 777 #指定ディレクトリ配下のディレクトリ全てに権限設定
chown -R ['ユーザ名']:['グループ名']  #ディレクトリにユーザとグループを設定

"[応用編]"
mkdir -m 777 ['ディレクトリ']$(date +%y%m%d)  #日付付きのディレクトリをを777のパーミッションで作成する
```
このメモのポイントは調べた先の言葉そのままではなく、自分の言葉で説明を書き留めたことです。
使用したコマンドを実際に例としてそのまま記載するのも手かもしれません。
自分の言葉でまとめると<INS>記憶に残りやすい</INS>というのが大きなポイントだと思います。
そうすることで実際に使用するときにスムーズにでてくるのではと思います。
またコマンドなどのメモだけでなく、知らない技術的な用語が出てきた時などにも応用できるのも非常に有用です。

## 最後に
今回取り上げたものはあくまで個人的に実施していることです。
別のやり方を持っている方、普段から当たり前にできている方もいるかと思いますがちょっとでも参考になれば幸いです。