OmniAICreator/Qiita-1.07M huggingface dataset:
【AWS】datadogでAWS EC2インスタンスをDatadogで監視する方法



# AWS EC2インスタンスをDatadogで監視する方法

## はじめに

このガイドでは、Amazon Web Services (AWS) のElastic Compute Cloud (EC2) インスタンスをDatadogを使って監視する方法を説明します。Datadogを活用することで、EC2インスタンスのパフォーマンスや健全性をリアルタイムで把握し、問題が発生した際に迅速に対応することができます。

## 前提条件

- AWSアカウント
- Datadogアカウント
- EC2インスタンスへのアクセス権限

## 手順

### 1. AWSとDatadogの統合設定

1. Datadogダッシュボードにログインします。
2. 左側のメニューから「Integrations」を選択します。
3. 検索バーに「AWS」と入力し、AWS integrationを選択します。
4. 「Install Integration」をクリックします。
5. AWSアカウントIDを入力し、必要な権限を持つIAMロールを作成します。
6. 作成したIAMロールのARNをDatadogの設定ページに入力します。
7. EC2サービスが有効になっていることを確認します。
8. 「Install Integration」をクリックして設定を完了します。

### 2. EC2インスタンスへのDatadogエージェントのインストール

より詳細なメトリクスを収集するために、EC2インスタンスにDatadogエージェントをインストールします。

1. EC2インスタンスにSSH接続します。
2. 以下のコマンドを実行してDatadogエージェントをインストールします：

   ```bash
   DD_API_KEY=YOUR_API_KEY bash -c "$(curl -L https://s3.amazonaws.com/dd-agent/scripts/install_script.sh)"
   ```
`YOUR_API_KEY`はDatadogのAPI keyに置き換えてください。

インストールが完了したら、エージェントが正常に動作していることを確認します：
```bash
sudo systemctl status datadog-agent
```
### 3. モニターの設定

1. Datadogダッシュボードで「Monitors」→「New Monitor」を選択します。
2. 「Metric」を選択し、EC2関連のメトリクスを指定します。
3. 以下のようなクエリを使用して、EC2インスタンスの状態を監視します：
```
avg(last_15m):avg:aws.ec2.host_ok{*} by {name} < 1
```


4. アラート条件とメッセージを設定します。
5. 通知先（例：Slack、Eメール）を指定します。
6. モニターを保存します。

### 4. ダッシュボードの作成

1. 「Dashboards」→「New Dashboard」を選択します。
2. EC2関連のウィジェットを追加します（例：CPU使用率、ネットワークトラフィック、ディスク使用量）。
3. 各ウィジェットにEC2メトリクスを設定します。
4. ダッシュボードをカスタマイズし、保存します。

### まとめ
以上の手順により、AWS EC2インスタンスをDatadogで効果的に監視することができます。定期的にモニターとダッシュボードを見直し、必要に応じて調整することで、EC2インスタンスの最適なパフォーマンスと可用性を維持できます。
【AWS】CDKで特定Cloud Formationスタックの作成・削除手順まとめ


## 1. やったこと（概要）

- CDKプロジェクトで複数のスタック（CloudFormation Stack）を管理している。
- 特定のスタックのみをCloudFormationテンプレートとして出力（`synth`）したり、AWS上から削除（`destroy`）したりしたい場合、**スタック名を指定してコマンドを実行**する。
- スタック名は `bin/levtech.ts` などで `new XxxStack(app, "<StackName>", ...)` の形で定義されている。

---

## 2. スタック名の確認

```sh
npx cdk ls
```
または
```sh
npm run ls:stg
```
などで、現在のSTAGEで有効なスタック名一覧を確認できる。

---

## 3. スタックの作成（テンプレート出力）

### コマンド例

```sh
npx cdk synth <StackName>
```

例:
`<StackName>` というスタックのみテンプレート出力したい場合

```sh
npx cdk synth <StackName>
```

npm scriptを使う場合（`package.json`より）:

```sh
npm run synth:dev <StackName>
```

---

## 4. スタックのデプロイ（実際にAWSへ反映）

> **補足:**
> スタックは `cdk synth` でテンプレートを生成しただけではAWS上に作成・変更されません。
> 実際にAWSへリソースを作成・更新するには `cdk deploy` を実行する必要があります。

### コマンド例

```sh
npx cdk deploy <StackName>
```

npm scriptを使う場合（`package.json`より）:

```sh
npm run deploy:dev <StackName>
```

---

## 5. スタックの削除

### コマンド例

```sh
npx cdk destroy <StackName>
```

例:
`<StackName>` というスタックのみ削除したい場合

```sh
npx cdk destroy <StackName>
```

npm scriptを使う場合（`package.json`より）:

```sh
npm run destroy:dev <StackName>
```

- 削除時は確認プロンプトが出る。`-f` オプションで強制削除も可能。

---

## 6. よく使うnpm script（`package.json`より）

- `npm run synth:dev <StackName>` ... Dev環境でテンプレート出力
- `npm run deploy:dev <StackName>` ... Dev環境でデプロイ（AWSへ反映）
- `npm run destroy:dev <StackName>` ... Dev環境でスタック削除
- `npm run synth:stg <StackName>` ... Stg環境でテンプレート出力
- `npm run deploy:stg <StackName>` ... Stg環境でデプロイ
- `npm run destroy:stg <StackName>` ... Stg環境でスタック削除
- `npm run synth:prd <StackName>` ... Prd環境でテンプレート出力
- `npm run deploy:prd <StackName>` ... Prd環境でデプロイ
- `npm run destroy:prd <StackName>` ... Prd環境でスタック削除

---

## 7. まとめ

- **スタック名を指定して `cdk synth` でテンプレート出力、`cdk deploy` でAWSへ反映、`cdk destroy` で削除ができる。**
- `cdk synth` だけではAWS上にリソースは作成されない。**実際に反映するには `cdk deploy` が必要。**
- npm scriptを活用すると環境変数（STAGE）も自動でセットされるので便利。
- スタック名は `cdk ls` で確認できる。
【AWS】CloudFront作成時に `CNAMEAlreadyExists` エラーが発生した場合の対応手順


CloudFrontの `CNAMEAlreadyExists` エラーは、 **DNSのCNAMEレコードが既に別のCloudFrontディストリビューションを指している場合** に発生します。

## **エラー内容**

```
Error: creating CloudFront Distribution: operation error CloudFront: CreateDistributionWithTags,
https response error StatusCode: 409, RequestID: ..., CNAMEAlreadyExists:
One or more aliases specified for the distribution includes an incorrectly configured DNS record
that points to another CloudFront distribution. You must update the DNS record to correct the problem.
```

## **エラーの原因**
1. **DNSプロバイダ**（例: Cloudflare）に登録されているCNAMEレコードが既に **別のCloudFrontディストリビューション** に設定されている。
2. 同じ **CNAME（ドメイン名）** を複数のCloudFrontディストリビューションで設定しようとした。

## **対応手順**

### **1. 競合しているCloudFrontディストリビューションを特定する**

#### **AWS CLIを使用して競合を確認**
```
aws cloudfront list-conflicting-aliases \
  --distribution-id <対象のディストリビューションID> \
  --alias <該当のCNAME>
```

- `<対象のディストリビューションID>`: エラーが発生しているCloudFrontのID。
- `<該当のCNAME>`: 設定しようとしているCNAME（例: `example.com`）。

**出力例**:
```
{
  "ConflictingAliasesList": {
    "ConflictingAliases": [
      {
        "Alias": "***********.com",
        "DistributionId": "E3XXXXXXXXXXXXXX"
      }
    ]
  }
}
```

- **`DistributionId`**: 競合しているCloudFrontディストリビューションIDが確認できます。

### **2. DNSレコードの設定を確認**

#### **DNSプロバイダでCNAMEを確認**
1. **Cloudflare**、**Route53** などのDNSプロバイダにログインします。
2. 競合しているCNAMEレコードが **どのCloudFrontディストリビューション** を指しているか確認します。

#### **CNAMEを削除または修正**
- 既存のCNAMEが別のCloudFrontディストリビューションを指している場合、該当のCNAMEレコードを削除します。
- 新しいCloudFrontディストリビューションを指すようにCNAMEレコードを更新します。

**例: Cloudflareでの設定**
| タイプ   | 名前               | コンテンツ                  | ステータス |
|----------|--------------------|-----------------------------|------------|
| CNAME    | `example.com`      | `dXXXXXX.cloudfront.net`    | DNSのみ    |

### **3. CloudFrontのCNAME設定を更新**

新しいCloudFrontディストリビューションの `aliases` に該当のCNAMEを追加し、エラーが解消されたことを確認します。

### **4. 再確認**

#### **CNAMEが新しいCloudFrontに正しく向いているか確認**

**CLIでDNSの確認**:
```
nslookup example.com
```

**期待する結果**:
- 出力結果が新しいCloudFrontのドメイン名（例: `dXXXXXX.cloudfront.net`）を返す。

## **再発防止策**

1. **CNAMEの管理ルールを明確化**:
   - 各CloudFrontディストリビューションのCNAME設定を事前にドキュメント化。
2. **TerraformやInfrastructure as Code (IaC) の使用**:
   - 既存リソースの状態管理をTerraformで行い、競合を防止。
3. **DNSプロバイダとCloudFront設定の整合性確認**:
   - DNS設定を更新する際には、CloudFront側のCNAME設定も必ず確認。

### **まとめ**

`CNAMEAlreadyExists` エラーの解消手順:
1. AWS CLIで **競合するCNAME** を特定。
2. DNSプロバイダで **CNAMEレコードを修正**。
3. CloudFrontディストリビューションの **aliases設定を更新**。
4. CNAMEが新しいCloudFrontを指していることを確認。

これにより、CNAMEの競合を解消し、正常にCloudFrontを設定できます。
【AWS】LightSailのSSL証明書の自動更新


Bitnamiが提供するWordPressイメージでSSL証明書を自動更新する手順を説明します。

1. SSHでLightSailインスタンスに接続します。

2. まず、Let's Encrypt アカウントを作成し、認証を行います：

```
sudo /opt/bitnami/letsencrypt/lego --path /opt/bitnami/letsencrypt --email="your_email@example.com" --http --http-timeout 30 --http.webroot /opt/bitnami/apps/letsencrypt --domains=your_domain.com --user-agent bitnami-bncert/1.1.1 run
```

your_email@example.comとyour_domain.comを適切な値に置き換えてください。このコマンドを実行すると、Let's Encryptの利用規約に同意するよう求められます。同意して進めてください。

3. 認証が完了したら、証明書が生成されます。次に、証明書の更新をテストします：

```
sudo /opt/bitnami/letsencrypt/lego --path /opt/bitnami/letsencrypt --email="your_email@example.com" --http --http-timeout 30 --http.webroot /opt/bitnami/apps/letsencrypt --domains=your_domain.com --user-agent bitnami-bncert/1.1.1 renew
```

4. 証明書が正常に更新されたら、Apacheを再起動します：

```
sudo /opt/bitnami/ctlscript.sh restart apache
```

5. 自動更新のためのcronジョブを設定します。rootのcrontabを編集するには以下のコマンドを使用します：

```
sudo crontab -e
```

6. 以下の行を追加します：

```
0 0 1 * * /opt/bitnami/letsencrypt/lego --path /opt/bitnami/letsencrypt --email="your_email@example.com" --http --http-timeout 30 --http.webroot /opt/bitnami/apps/letsencrypt --domains=your_domain.com --user-agent bitnami-bncert/1.1.1 renew && sleep 30 && /opt/bitnami/ctlscript.sh restart apache >> /var/log/letsencrypt-renewal.log 2>&1
```

この設定により、毎月1日の午前0時に証明書の更新チェックが行われ、必要に応じて更新とApacheの再起動が実行されます。

7. crontabの内容を確認します：

```
sudo crontab -l
```

8. 最後に、証明書が正しく適用されているか確認します：

```
openssl x509 -in /opt/bitnami/letsencrypt/certificates/your_domain.com.crt -noout -dates
```

これで、SSL証明書の自動更新が設定されました。/var/log/letsencrypt-renewal.logファイルを定期的にチェックして、更新プロセスが正常に実行されていることを確認してください。

注意：この方法はBitnamiが提供するWordPressイメージに特化しています。他の環境では手順が異なる場合があります。
RDSプロキシに割り当てたIAMロールがシークレットを取得できないエラーの対処方法


## エラー内容
RDS Proxy を設定する際に以下のエラーが発生することがあります：

```
Credentials couldn't be retrieved. The IAM role "arn:aws:iam::<account_id>:role/<role_name>" is not authorized to read the AWS Secrets Manager secret with the ARN "arn:aws:secretsmanager:<region>:<account_id>:secret:<secret_name>"
```

このエラーは、RDS Proxy に割り当てられた IAM ロールが Secrets Manager のシークレットを取得するための適切なアクセス許可を持っていない場合に発生します。

## 対処方法

### 1. IAM ロールのポリシー確認

RDS Proxy に関連付けられた IAM ロールに適切なポリシーが付与されていることを確認してください。

#### Secrets Manager のアクセス許可
以下は、Secrets Manager に対するアクセス許可ポリシーの例です。該当するシークレットの ARN を指定してください。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowSecretsManagerAccess",
            "Effect": "Allow",
            "Action": [
                "secretsmanager:GetSecretValue",
                "secretsmanager:DescribeSecret"
            ],
            "Resource": "arn:aws:secretsmanager:<region>:<account_id>:secret:<secret_name>"
        }
    ]
}
```

#### KMS のアクセス許可
Secrets Manager のシークレットが KMS で暗号化されている場合、KMS へのアクセス許可も必要です。

```
{
    "Sid": "AllowKMSAccess",
    "Effect": "Allow",
    "Action": [
        "kms:Decrypt"
    ],
    "Resource": [
        "arn:aws:kms:<region>:<account_id>:key/alias/aws/secretsmanager"
    ],
    "Condition": {
        "StringEquals": {
            "kms:ViaService": "secretsmanager.<region>.amazonaws.com"
        }
    }
}
```

### 2. Secrets Manager の ARN の確認

エラーメッセージに表示される Secrets Manager の ARN を確認し、IAM ポリシーで指定している ARN と完全一致していることを確認してください。

- 例: エラーメッセージに `arn:aws:secretsmanager:ap-northeast-1:<account_id>:secret:dev-db-credential-G1TDKV` と記載されている場合は、この ARN をポリシー内で指定してください。

### 3. IAM ロールの信頼関係を確認

IAM ロールの信頼関係ポリシーに、RDS Proxy を許可する設定が含まれているか確認してください。以下は、適切な信頼関係ポリシーの例です。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "rds.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
```

### 4. RDS Proxy の設定を確認

RDS Proxy に以下の項目が正しく設定されていることを確認してください。

- **IAM ロール**: エラーに表示された IAM ロールが設定されているか確認してください。
- **シークレット ARN**: Secrets Manager に登録されたシークレット ARN が正しいか確認してください。

### 5. ポリシーの適用後にリロード

ポリシーを修正した後、RDS Proxy を再起動することで変更が適用される場合があります。

### 6. CloudWatch ログでエラー詳細を確認

RDS Proxy の CloudWatch ログを有効化し、エラーの詳細を確認してください。

## まとめ

このエラーを解消するには、以下のステップを順に確認してください：

1. IAM ロールに適切な Secrets Manager と KMS のアクセス許可を付与する。
2. ARN の完全一致を確認する。
3. IAM ロールの信頼関係を設定する。
4. RDS Proxy の設定を確認する。

設定後に問題が解決しない場合は、CloudWatch ログを参照して追加のエラー情報を確認しましょう。
【AWS】SSMで管理しているEC2にportforwardしてローカルからRDSに接続する


## 概要
下図の通りEC2 にSSM agentをinstallしてそこから繋ぐことが出来るRDSにローカルアクセスします。

![](https://storage.googleapis.com/zenn-user-upload/394a17b598e8-20240709.png)

## 前提
- EC2 に SSM agentをinstall 済
- EC2 から RDSにアクセス出来るVPC設定
- RDS は パスワードで管理
- ローカルではGUIツールを使用(この記事ではHeidiSQL)

## 手順
1. EC2のinstance-IDを確認する

2. portforwardを実施

windows
```
aws ssm start-session ^
--target i-xxxxx ^
--document-name AWS-StartPortForwardingSessionToRemoteHost ^
--parameters "{\"portNumber\":[\"3306\"],\"localPortNumber\":[\"3306\"],\"host\":[\"rds-dev.xxxxx.ap-northeast-1.rds.amazonaws.com\"]}" ^
--profile iamuser-xxxxx
```

mac
```
aws ssm start-session \
--target i-xxxxx \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters '{"portNumber":["3306"],"localPortNumber":["3306"],"host":["rds-dev.xxxxx.ap-northeast-1.rds.amazonaws.com"]}' \
--profile iamuser-xxxxx
```


3. RDSにアクセス

以下の値を入力し、「開く」

|項目|値|
|----|----|
|ネットワーク種別|MariaDB or MySQL(TCP/IP)|
|ホスト名/IP|localhost|
|ユーザー|${user名}|
|パスワード|${パスワード}|
|ポート|3306|

![](https://storage.googleapis.com/zenn-user-upload/3629e29a85f3-20240709.png)

## 参考

https://blog.serverworks.co.jp/ssm-session-manager-rds
固定キー機能を無効化する

# はじめに
時折表示される "固定キー機能を有効にしますか?" が邪魔 ... なので対策することにした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184939/2e340283-5f64-449f-86af-38bc304266a7.png)

## 注意
これを執筆しているのは2025/6/1。そろそろ Windows10 のサポートも終わるので Windows11 でのやり方だけを記載する。

# やり方

1) Windowsスタートボタン をクリックする

2) "設定" をクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184939/d91ab18d-3376-4103-b7a2-7cb8b4df35e1.png)

3) "アクセシビリティ" をクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184939/606429b8-8b00-45d1-b8e7-3edeea625c30.png)

4) "操作" グループ に表示される "キーボード" をクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184939/ecd99e1c-fcae-4001-8bcc-a869dc38d08c.png)

5) "固定キー機能" を "オフ" にする。そのあと ">" をクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184939/d223da4f-7402-44bb-bfbc-48d7eecb7162.png)

6) "固定キー機能用のキーボードショートカット" を "オフ" にする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184939/b7e81a6b-bfa4-40ea-a5e5-f4870af64e36.png)

以上で固定キー機能が無効化される。

# 余談
アクセシビリティ は 主に "身体補助" を目的として導入する機能 なのだが タブレットやスマートフォン では "便利機能" として 利用されている気がする。
bashの基本キー操作

## bashとは

bash（Bourne Again SHell）は、Unix系のオペレーティングシステムで利用されるシェルの一つ。シェルとは、ユーザーが入力したコマンドを解釈し、OSに実行させるためのソフトウェア。

---

### bash操作に役立つキー操作

#### カーソル移動

| キー | 動作 |
|------|------|
| `Ctrl + A` | 行の先頭に移動 |
| `Ctrl + E` | 行の末尾に移動 |
| `Ctrl + F` | 1文字前進(右)（→キーと同じ） |
| `Ctrl + B` | 1文字後退(左)（←キーと同じ） |
| `Alt + F` | 1単語前進 |
| `Alt + B` | 1単語後退 |

#### 文字の削除(切り取り)・貼り付け

| キー | 動作 |
|------|------|
| `Ctrl + D` | カーソル位置の文字を削除(Deleteと同じ)|
| `Ctrl + H` | カーソル前の文字を削除（Backspaceと同じ） |
| `Ctrl + K` | カーソル位置から行末まで切り取り |
| `Ctrl + U` | カーソル位置から行頭まで切り取り |
| `Ctrl + Y` | 切り取った(削除した)コマンドの貼り付け |
| `Ctrl + W` | カーソル前の単語を削除 |
| `Alt + D` | カーソル後の単語を削除 |

#### コマンド履歴

| キー | 動作 |
|------|------|
| `Ctrl + P` | 前のコマンド（↑キーと同じ） |
| `Ctrl + N` | 次のコマンド（↓キーと同じ） |
| `history` | コマンド履歴を表示|
| `!!` | 直前のコマンドを実行 |
| `!n` | 履歴のn番目のコマンドを実行 |

#### プロセス制御

| キー | 動作 |
|------|------|
| `Ctrl + C` | 実行中のプロセスを強制終了 |

#### 便利な機能

| キー | 動作 |
|------|------|
| `Tab` | コマンド・ファイル名の自動補完 |
| `Tab Tab` | 補完候補を一覧表示 |

## 参考文献
https://www.udemy.com/share/104leu3@QyXR0ZpSwvB0GBTSxG-ys76X0zIMtoUkSKhpQ0Zcthmnuaxt_8vAzDSzFdLeaC5v_w==/
Dockerとは？メリットは？どんな時に使うか？

# はじめに

最近、5000兆周遅れでDockerのキャッチアップを始めました。よく耳にする技術でしたが、実際に学んでみると「なるほど！」の連続で刺激的です。

この記事では、僕と同じようにDockerをこれから始める方が、「Dockerってこういうことか」と大まかなイメージを掴めるように、学んだことを共有します。専門的な深い話というよりは、Dockerの基本的なコンセプトや利点、どんな場面で役立つのか、といったポイントをお伝えできればと思います！

主に参考にしたのは「[仕組みと使い方がわかる Docker＆Kubernetesのきほんのきほん](https://book.mynavi.jp/ec/products/detail/id=120304)」のChapter1～2です。

<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622181/e4f67230-8e14-4388-8e77-f7d45c418fbd.png">


# 対象読者
- Dockerをこれから学び始めたいと思っている方
- 「Docker」という言葉は聞いたことがあるけど、何が便利なのかよくわからない方

# Dockerとは：「コンテナ」で環境をまるごと隔離する技術

Dockerとは、「コンテナ」と呼ばれる隔離された箱のような空間に、アプリケーションとその実行に必要な設定やライブラリなどをひとまとめにしてパッケージ化し、実行できるようにする技術です。

書籍では「データやプログラムを隔離できる仕組み」と説明されますが、もう少し詳しく言うと、OSレベルで他のプロセスから隔離された「コンテナ」を作り、その中でアプリケーションを動かすことができます。これにより、まるで個別サーバーのように、クリーンで独立した環境を簡単に用意できるのが大きな特徴です。

# なぜ環境を隔離したいのか？ Dockerのメリット
「別にコンテナへ入れなくても動くのでは？」と思うかもしれません。確かにその通りですが、この「コンテナに入れる」という考え方が、開発や運用において多くのメリットをもたらしてくれます。

## 1. 環境の独立性
### 環境の違いによるトラブルを軽減
開発者なら一度は経験するかもしれない「自分のPCでは問題なく動いたのに、サーバーに上げたら動かない…」という状況。これは、開発環境と本番環境のOSやライブラリのバージョンが異なることが原因で起こりがちです。Dockerコンテナは、必要なライブラリや設定をすべて含んでいるため、環境の違いによる問題を減らすことができます。

### 持ち運びが簡単
Dockerがインストールされていれば、「コンテナ」は基本的にどこでも同じように動作します。アプリケーションを異なるサーバーへ移動させたい場合も、コンテナごと移動させるようなイメージで対応できます。

## 2. 安全性の向上
あるコンテナ内のアプリケーションがセキュリティ攻撃を受けたり、予期せぬバグで停止してしまったりした場合でも、その影響はそのコンテナ内に留まることが期待できます。ホストOS（Dockerが動いているコンピュータ本体）や他のコンテナへの影響を最小限に抑えられるため、システム全体の安全性が高まります。

## 3. 効果的な管理と運用
### 軽量で高速に起動
従来からある「仮想マシン（VM）」も環境を隔離する技術ですが、VMはOS全体を仮想的に起動するため、リソース消費が大きく起動にも時間がかかりがちです。一方、DockerコンテナはホストOSの機能を共有するため、より軽量で起動も非常に速いのが特徴です。

### CI/CDと相性が良い
アプリケーションの開発からテスト、デプロイまでの一連の流れを自動化する「CI/CD (継続的インテグレーション/継続的デリバリー)」という手法とDockerは非常に相性が良いです。テスト環境や本番環境をコンテナとして定義しておくことで、開発からデプロイまでのプロセスを自動化しやすくなります。

### スケーラビリティの確保
アプリケーションへのアクセスが増加した際に、同じコンテナを複数起動することで、システム全体の処理能力を向上させる（スケールアウトする）ことが比較的容易です。需要に応じてリソースを柔軟に調整できます。

# どんなときに使うのか？
Dockerのメリットを活かして、具体的にどのような場面で利用されているのでしょうか。

## 開発環境の統一
チームで開発を行う際、メンバー全員が同じバージョンのOS、プログラミング言語、ツールなど、統一された開発環境をDockerコンテナとして簡単に用意・共有できます。「Aさんの環境では動くけど、Bさんの環境では動かない」といった無駄なトラブルを避けるのに役立ちます。

## 新しい技術やバージョンの実験
新しいプログラミング言語のバージョンを試したり、気になるミドルウェアをテストしたりする際に、既存の環境に影響を与えることなく、隔離されたDockerコンテナ内で安全に実験できます。不要になればコンテナを削除するだけで元に戻せるので手軽です。

## アプリケーションのデプロイとスケーリング
作成したWebアプリケーションやAPIサーバーなどをDockerコンテナとしてパッケージ化し、本番環境へデプロイします。前述の通り、アクセス状況に応じてコンテナの数を調整することで、柔軟なスケーリングが実現できます。

# まとめ
Dockerはアプリケーションとその実行環境を「コンテナ」という形でパッケージ化することで、開発から本番運用に至るまで、様々な場面で効率化と安定性をもたらしてくれる便利な技術です。

僕自身もまだ学び始めたばかりですが、Dockerの基本的な考え方やメリットを知ることで、今後の学習や実務に活かしていけると感じています。
この記事が、これからDockerに触れる方にとって、少しでも理解の助けになれば幸いです！
Claude CodeにIssueのタスクを遂行→PRの作成まで行なってもらう

## 初めに

前回書いた記事の通り、最近Claude Codeを使って開発を行っています。

https://qiita.com/getty104/items/00256804c47e216d702a

Claude CodeにはGitHub Actionsを用いたエージェント機能である「Claude Code Action」もあり、そちらを使えばGitHub上から直接Issueのタスクを進めてもらう、などの完全自動化も可能です。

https://github.com/anthropics/claude-code-action

しかし、Claude Code Actionでは前回の記事で紹介したClaude Maxプランを用いることができず、APIを利用することになるので少々コストが気になります。

そこで、まずは簡単にClaude Codeを用いてIssueを渡すだけでPRの作成まで行なってもらえるワークフローを作理、手元での作業を自動化してみました。

この記事では、Claude Codeで簡単に「Issueのタスクを遂行→PRの作成まで行なってもらう」ためにやったことを紹介します。

## 手順

### セットアップ
まずはClaude CodeでIssueを取得できるようにするため、GitHub CLIをインストールします。
GitHub CLIとはGitHubのコマンドラインツールで、リポジトリ管理やIssue作成などをターミナルから行うことができる便利なツールです。
詳しくは公式のドキュメントをご覧ください。

https://docs.github.com/ja/github-cli/github-cli/about-github-cli

### Claude Codeのコマンドを作成
Claude Codeでは、独自にコマンドを作成できる仕組みがあります。
この機能を使うことで、独自に定義したワークフローを `/user:hoge`のような形や、プロジェクト単位では`/project:hoge` のような形で簡単に呼び出せるようになります。

また、`$ARGUMENTS`というキーワードで引数を定義することも可能です。

https://docs.anthropic.com/ja/docs/claude-code/tutorials#%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%82%B9%E3%83%A9%E3%83%83%E3%82%B7%E3%83%A5%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B

今回は`/user:exec-issue ISSUE番号`という形でワークフローを呼び出せるようにします。

`~/.claude/commands/exec-issue.md` に以下のようなプロンプトを定義します。

```markdown:~/.claude/commands/exec-issue.md
gh issue view #$ARGUMENTS でGitHubのIssueの内容を確認し、タスクの遂行を行なってください。
タスクは以下の手順で進めてください。

1. Issueに記載されている内容を理解する
2. mainにチェックアウトし、pullを行い、最新のリモートの状態を取得する
3. Issueの内容を元に、適切な命名でブランチを作成、チェックアウトする
4. Issueの内容を実現するために必要なタスクを実行する
5. 適切なテストを追加する
6. テストとLintを実行し、すべてのテストが通ることを確認する
7. コミットを適切な粒度で作成する
8. PRを作成する。なお、PRのdescriptionには`Closes #$ARGUMENTS`と冒頭に記載すること
```

これでIssueを遂行してほしいリポジトリ内で`/user:exec-issue Issue番号`と入力することでPRの作成まで自動で行なってもらうことが可能です。

### おまけ: レビューの自動化
前項まででPRの作成までを自動化できましたが、レビューもできたらAIにしてもらえるとありがたいです。
ClaudeにレビューをしてもらうにはClaude Code Actionが必要になりますし、同じモデルにレビューまでしてもらっても本質的にあまり意味がなさそうです。
ということで、2025年5月現在は無料で使用することができる「Gemini Code Assist for GitHub」を普段は利用しています。
もしレビューまでAIにお任せしたい、という場合はこちらの利用もご検討ください。

https://github.com/apps/gemini-code-assist

## 感想
AIにIssueを元に自動でタスクをやってもらう体験、

- 開発はAIに全部任せられる
- AIでもわかるようにIssueを書く必要があるため、ドキュメントとして内容をしっかり残すようになる

という二つの面でとてもメリットがあるように感じます。
個人的には2つ目のメリットが結構大きく、自分のためにIssueを書くのはめんどくさくてもAIのためにはIssueを頑張ってしっかり書けるという発見がありました。

ぜひ皆さんも色々使ってみた中での知見などありましたら教えてください！
[python] all関数 と and はちゃう

これはとある日の出来事を基に記事を起こしています。

## 簡潔に
[all関数](https://docs.python.org/ja/3.11/library/functions.html#all)と andの挙動は違う。
allは、すべての挙動を確認してbool値を返す。
andは、途中でfalseであれば、途中で評価を中断する。

## 導入

とある日のPR

```python

if all([
    hoge,
    huga,
    hoge < huga
]):
    return 'hoge_gt_huga'
```

というコードをレビューした。

私　「hogeとhugaの値が入っているか確認してから、hoge < hugaの評価してるんやな！安全性高いコードやapproveや！」

その後、マージし、無事本番反映まで進みましたとさ。

翌日早朝（8時半）

sentry「エラーやで」

slack経由のsentryが急につぶやいた。

sentryの詳細をみると画面には昨日PRレビューした箇所と以下のエラー文を吐いていた

`'<' not supported between instances of 'hoge' and 'NoneType'`

私「っふぁ！なんでTypeError、しかも '<' 評価まで通過しとる、allってandと同じ意味じゃないんか」

そう私は以下の文と錯覚していたのです。

```python
if hoge and huga and hoge < huga :
    return 'hoge_gt_huga'
```


## 分析
通常andの場合は、第一にhoge、第二にhugaが評価した後に、第三のhoge < huga の評価が行われるため、TypeErrorにはならないのだが、allの場合は、すべての要件を評価した後に、bool値を返す仕組みのようだ。

このことから計算量についても全てを計算する場合（allの書き方）と、途中で計算が終わる場合(andの書き方)とで違いが出てくることもわかった。

## むすび

ケースバイケースだが、nullableな変数を評価する場合は、allは避けるかある程度安全策をこうじる必要があるということが、今回のレビューで骨身にしみた。
すべての評価する値が完全にbool値になる時のみallは使いたいものですね。
ChatGPTを使って独自Playgroundを作ってみた話

# この記事のきっかけ
[昔作ったGithub Pages](https://t-yasusi.github.io/js-test.html)、演算子オーバーロードを備えたJavaScriptをブラウザで実行できるものをよりよく実行できるものとして[TS Playground](https://www.typescriptlang.org/play/?#)というものを教えてもらった。
さらにこれを自作できないかと聞くとその方法、技術スタックも教えてもらったのでそれを使って[新しいGithub Pages](https://t-yasusi.github.io/ts-calculator/)を作った。
その時のChatGPTとのやり取りなどを簡単に解説したい。

- [昔作ったGithub Pagesのリポジトリ](https://github.com/T-Yasusi/t-yasusi.github.io)
- [新しく作ったGithub Pagesのリポジトリ](https://github.com/T-Yasusi/ts-calculator)

## 以前のものの問題点
やりたいことは演算子オーバーロードと自作の数値計算ライブラリをWebのTypeScript実行環境に組み込みたい。
また、昔のものは無理矢理やってる感も強く、CLIでの実行は完全に捨てていた。そこでCLI環境でのテストも組み込みたいと考えていた。

## 使っている技術

### 提案された技術
ViteとMonaco Editorというものである。
Monaco EditorはVS code風のブラウザで使えるエディタのようである。
とりあえずPlayground風のモックまではほとんど作ってくれた。しかしながら、ここに自分のやりたいことを取り入れようとすると自分の技術の理解不足もあってスタックすることになった。
またCLIツールなどを作りこみ始めるとそちらとの干渉もあり一度破綻してしまった、これはChatGPT任せにしていて一部ツールを誤認していたような節もあると思われる。

### 以前からあった技術
Babelプラグインによる演算子オーバーロード`a + b`を`add(a, b)`のように変換。

## 困難だった点
### 作業フローが明確でなかった
JSでもTSでも演算子オーバーロードは出来ない、なのでBabelプラグインでASTレベルの変換をする必要がある。
それをどこに、TS → JS変換前か変換後かという問題があった。
また、ライブラリのビルドとテスト用スクリプトのトランスパイルがあった点もごっちゃになっていたと思う。

そこで、完成したフローが
- ライブラリビルド --- `calc_src/**/*.ts` (演算子オーバーロード)-> `calc/**/*.ts` (tsc)-> `modules/calc/**/*.js`
- テストスクリプト --- `public/test/**/*.ts` (演算子オーバーロード)-> `temp/**/*.ts` (tsc)-> `test-js/**/*.js`

という風になった。

### Web Page(Vite)設定
空のMonaco EditorのMockに関してはすぐに出してくれた。なのでここから開発を進めようとしたのが罠だった。よく知らないVite環境にBabelプラグインを入れようとするといろいろなものが破綻して崩壊した。
そこで、一度作り直して影響が少ないCLIツールから作り直そうとした。それが前章であり、そこでフローを見直すこととなった。

CLIツールが整備された後にWeb Pageに似たようなものを追加する際にもいくつかの問題が出た。
最も大きかったのは動的にコードを読み込んでトランスパイル、そして実行する、ということであった。
特に静的読み込み(事前に読み込んでおく)形なら`import/export`形式が使えるが動的実行だとこの形式は使えずdynamic import形式`const { a } await import "${url}"`のような形式しか使えない。
そのためにWeb Pageでは静的importを動的importに変えるBabelプラグインも導入することになった。この、問題提言はChatGPTからもらい、この解決方法は自分で考えた、またプラグインコード自体はほぼChatGPTに書いてもらった。これは、その前に演算子オーバーロードのプラグインの情報を与えていた効果もあるかもしれない。
その他に、読み込み元が`url`なのでローカルテストとデプロイ(今はGithub)で違うという問題もあったがこれもブラウザの`${location.origin}`を使うというかなりテクニカルな方法で解決(逃げて)いるが、これも私の方法である。
また、デプロイした際にライブラリの一部が見えない(404 not found)になるという問題もあったがこれもmainプロセスで参照されてないとの提言だった。これに関して公開ディレクトリ`public`に置くという根本的方法は自分で提言した。

## 良かった点
- Vite+MonacoEditorの初期設定 --- ただ、お任せすると余計なものまでつけてくる
- Babelプラグインや単体CLIツール --- これはある程度しっかりやりたいことや他設定を伝える必要がある。
- エラーの原因提言 --- 原因については理解できるし概ね当たってる気がするが解決策は試行錯誤する必要あり
- JSコードをTSコードへの書き換え --- 時間があれば別記事にしたい

## 全体的な所感
よく使われているものの初期設定や単体ツールなどはかなりいい感じに作ってくれるがツール間の競合や干渉などに関しては自分でやる(決める)必要があると感じた。
あと、理解が浅いツールなどについてはきちんと聞いて理解を深める必要があると感じた。そのための手助けするツールとしてはものすごく有用だと感じた。
因みに新しいほうのREADME.mdとLICENSEはほぼほぼChatGPTで作られたものを流用している。少し、軽い感じはするが読みやすくて大変いいと思っています。
C言語におけるStackの基本的な定義

C言語の標準ライブラリにはStack（スタック）を直接扱うデータ構造は用意されていません。
そのため、Stackを使いたい場合は自分で実装する必要があります。

ここでは、配列を使った基本的なStackの実装例を紹介します。
扱う要素の型は用途に合わせて自由に変更してください。


概要
・配列を使ったStack構造
・要素の追加（push）、取り出し（pop）、先頭要素確認（peek）が可能
・Stackが空か満杯かの判定付き
・扱うデータ型（Element）は編集可能

```c

#include <stdio.h>
#include <stdlib.h>

#define MAX_STACK_SIZE 100

// Stackで扱う構造体（必要に応じて編集してください）
typedef struct {
    int y;
    int x;
} Element;

// Stackの構造体
typedef struct {
    Element data[MAX_STACK_SIZE];  // Stackに格納するデータの配列
    int top;                       // Stackの先頭（要素数 - 1）を示すインデックス
} Stack;

// Stackを初期化する関数
void initStack(Stack *stack) {
    stack->top = -1;  // 空の状態を示す -1 に設定
}

// Stackが空かどうか判定する関数
int isEmpty(Stack *stack) {
    return (stack->top == -1);
}

// Stackが満杯かどうか判定する関数
int isFull(Stack *stack) {
    return (stack->top == MAX_STACK_SIZE - 1);
}

// Stackに要素を追加する関数
void push(Stack *stack, Element elem) {
    if (isFull(stack)) {
        fprintf(stderr, "stack is full.\n");
        exit(1);
    }
    stack->data[++(stack->top)] = elem;
}

// Stackから要素を取り出す関数
Element pop(Stack *stack) {
    if (isEmpty(stack)) {
        fprintf(stderr, "stack is empty.\n");
        exit(1);
    }
    return stack->data[(stack->top)--];
}

// Stackの先頭要素を確認する関数（取り出さない）
Element peek(Stack *stack) {
    if (isEmpty(stack)) {
        fprintf(stderr, "stack is empty.\n");
        exit(1);
    }
    return stack->data[stack->top];
}
```
C言語におけるQueueの基本的な定義

C言語ではqueueが用意されていません。
自分で定義する必要があります。

そこで基本的なQueueの定義を用意しました。
Queueで扱う要素は必要に応じて編集してください。

概要
・配列を使った循環バッファ形式のQueue
・要素の追加（enqueue）、取り出し（dequeue）、先頭確認（peek）が可能
・Queueが空か・満杯かの判定付き
・扱うデータ型（Coord）は編集可能


```c
#include <stdio.h>  // 標準入出力
#include <stdlib.h> // exit関数などを使用するため

#define MAX_QUEUE_SIZE 100

// Queueで扱う構造体（必要に応じて編集可能）
typedef struct {
    int y;
    int x;
} Coord;

// Queue構造体（Coord型の循環バッファ）
typedef struct {
    Coord data[MAX_QUEUE_SIZE]; // Queue内に格納する要素の配列
    int front;                  // 先頭（取り出し位置）のインデックス
    int rear;                   // 最後尾（追加位置）のインデックス
} Queue;

// Queueを初期化する
void initQueue(Queue *queue) {
    queue->front = -1;  // 空の状態を示す -1 に設定
    queue->rear  = -1;
}

// Queueが空かどうかを判定する
int isEmpty(Queue *queue) {
    return (queue->front == -1 && queue->rear == -1);
}

// Queueが満杯かどうかを判定する
int isFullQueue(Queue *queue) {
    return (queue->rear + 1) % MAX_QUEUE_SIZE == queue->front;
}

// Queueに要素を追加する
void enqueue(Queue *queue, Coord coord) {
    if (isFullQueue(queue)) {
        fprintf(stderr, "queue is full.\n");
        exit(1);
    }

    if (isEmpty(queue)) {
        queue->front = 0;
        queue->rear  = 0;
    } else {
        queue->rear = (queue->rear + 1) % MAX_QUEUE_SIZE;
    }

    queue->data[queue->rear] = coord;
}

// Queueから要素を取り出す
Coord dequeue(Queue *queue) {
    if (isEmpty(queue)) {
        fprintf(stderr, "queue is empty.\n");
        exit(1);
    }

    Coord coord = queue->data[queue->front];

    if (queue->front == queue->rear) {
        queue->front = -1;
        queue->rear  = -1;
    } else {
        queue->front = (queue->front + 1) % MAX_QUEUE_SIZE;
    }

    return coord;
}

// Queueの先頭要素を確認する（取り出さない）
Coord peek(Queue *queue) {
    if (isEmpty(queue)) {
        fprintf(stderr, "queue is empty.\n");
        exit(1);
    }
    return queue->data[queue->front];
}
```
チャットbotお試し用アプリ開発_2日目

# 目次
・本日の成果・考え
・最後に

### 本日の成果
作成するデスクトップアプリの機能の整理を行いました。
粒度は、クラス図作成でそのまま使用可能なレベルを想定しています。

まずは、対象となる業務をシーケンス図で図式化。

![スクリーンショット 2025-06-01 8.57.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3338426/7a04df02-1ca7-4cae-9766-d748e3955293.png)

:::note info
チャットbotとしては、ユーザーからの「問い合わせを行う」のイベント以降をシステム化すべきだと皆さん思われますし、著者もそう思います。
しかし、今回の開発目的としては、スモールスタートの効果検証であり、ピンクの範囲が管理もしやすく妥当だと考えました。
:::


上記をもとに、機能の一覧を考えてみました。

機能一覧

- 資料検索機能
    - 検索機能：保管された資料の中から、ユーザーの検索条件に合致する資料を検索する。
    - 資料保管機能：管理者から提供された資料を保管する。
        - 資料の形式：電子形式（.docs、.txt、.pdf）
        - 保管先：クラウドサービスの保管先（会社の認可がおりた保管先に限る。）
        - 保管方法：ベクトルDBへ保管。
        ※保管先により方法は変動。候補：Dify（Saas）経由 or AWS
- 画面出力機能：PCの画面にウィンドウを表示する。
    - 出力形式：社内PCで出力可能な形式。
    - 表示：サイズの変更が可能。リサイズ制限なし。
    - 出力対象：チャットbotとの会話を行う画面に限る。
- ログ出力機能：ユーザーの使用履歴をログとして出力する。
    - 出力形式：「.log」
        - ファイル名：「app_YYYYMMDD_HHmmss.log」
    - 出力対象：アプリ側の処理結果に限る。
    ※起動、停止、エラー発生時。
    - 出力期間：配布してから、スモールスタート終了まで。
    - 保存先：アプリ配布先の端末
    ※アプリソース内に保管フォルダを用意。
    - 保管期間：配布してから、スモールスタート終了まで。
    - ファイルサイズ：1Kb以下×平均10件/日　＝10Kb/日
- チャット機能：ユーザーと自然会話形式で文字でやり取りする。
    - 文字入力：ユーザーが画面に文字を入力する。
        - 画面上の入力制限：Difyの設定を流用。
        - 入力内容制限：不正アクセスおよび、AIモデルへの負荷が過剰になる入力内容の制限を行う。
        ※Saas管理画面で設定。
    - 文字出力：ユーザーの入力結果やチャットbotの回答結果を出力する。
        - 出力制限：Difyの設定を流用。
        - 出力内容制限：保管資料以外の内容の出力制限。
        ※Saas管理画面で設定。



合わせて、前回作成したシステム構成図を修正。

![スクリーンショット 2025-06-01 8.56.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3338426/a76164be-13ae-4027-b4a1-ce21bc15f11b.png)


:::note warn
システム構成図にAWSを入れていますが、そちらは今回のアプリ開発のスコープ範囲外です。
あくまでもチャットbotのシステム構成図として記載しているだけです。
<font color=red>※その場合、このアプリのシステム構成図への記載は不要な気がしますね。</font>
:::

### 最後に
実は、今回の機能整理前にすでにJavaでウィンドウの表示をするソースを書いてしまっています。
設計の参考書をいくつか読み、この要件の整理段階が重要と認識していますが、プログラムを書いて、さっさと動きを見たいという気持ちが強いです。
しかし、プログラムを書いている中でクラス名やクラス間の連携などをどうするかでいちいち止まってしまいます。

個人開発でなんとなくソースを書くなら問題ないと思いますが、設計→実装の訓練と考えると、今回のように要件整理を行う意味を感じました。
ReactでGoNogo課題を作ってみた

## Go Nogo課題とは？
心理学実験でよく用いられる認知機能を評価する課題です。
・Goの刺激が出た時は反応する（例：ボタンを押す）
・Nogoの刺激が出た時は反応しない（例：ボタンを押さない）
というものです。

大学時代に実験していた時は、PCに専用ソフトを入れて計測していたので、
Webアプリケーションで構築すればもっと効率的にデータを集められるのではないかと思い、
作ってみました。
※今回はReactの勉強も兼ねているので、実験用としては作成していません。

## 成果物
![Videotogif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4088298/3d9a9250-f707-4488-9cc5-0861dc3d0c42.gif)

Vercelにデプロイしました。
精度については検証していないので結果は参考程度ですがもしよければ遊んでみてください。
[GoNogo課題](https://go-nogo-theta.vercel.app/pages/profile "https://go-nogo-theta.vercel.app/pages/profile")

githubはこちらです。
https://github.com/iwasan0114/go-nogo

## 作成時のポイント

GoNogoは定期的に刺激を提示します。
それをsetTimeOutで制御しています。
```typescript:gonogo\page.tsx
      // 刺激表示時間後の処理
      setTimeout(() => {
        if (!hasRespondedRef.current) {
          // 無反応の場合の記録
          const isCorrect = trialType === 'nogo';
          const trialData: TrialData = {
            trialNumber: currentTrial + 1,
            type: trialType,
            response: false,
            correct: isCorrect,
            reactionTime: null,
            timestamp: Date.now()
          };

          setResults(prev => [...prev, trialData]);
          console.log('Trial Result (No Response):', trialData);
        }

        setShowStimulus(false);
        
        // 次の試行への進行処理
        setTimeout(() => {
          const nextTrial = currentTrial + 1;
          
          if (nextTrial >= TRIAL_COUNT) {
            // 課題終了
            console.log('All trials completed!');
            setIsRunning(false);
            setShowResult(true);
            isExecutingRef.current = false;
          } else {
            // 次の試行へ
            setCurrentTrial(nextTrial);
            isExecutingRef.current = false; // フラグをリセット
          }
        }, 100);
      }, STIMULUS_DURATION);
    }, ITI_DURATION);
```

各刺激の実行後にuseEffectで次の施行に進むかを判定しています。
```typescript:gonogo\page.tsx
  useEffect(() => {
    console.log("useEffect triggered - isRunning:", isRunning, "currentTrial:", currentTrial, "isExecuting:", isExecutingRef.current);
    
    if (isRunning && currentTrial > 0 && currentTrial < TRIAL_COUNT && !isExecutingRef.current) {
      console.log('Triggering next trial from useEffect');
      runNextTrial();
    }
  }, [currentTrial, isRunning, runNextTrial]);
```

## 学び
useStateやuseEffectの使い方を理解できたこと
実際に使ってもらって思いのほか反応が良かったこと

## 課題
実験で実運用することを想定すると
刺激の反応時間の精度をどう検証するか
ブラウザでの描画になるので、安定したフレームレートで表示するにはどうすればいいか？

反応時間のずれの改善に関してはQRTEngineというものがあるようです。
https://github.com/ErwinHaasnoot/QRTEngine

## 今後
現在は結果表示までなので、バックエンド機能を実装して、データを集められるようにしたいと思います。
datetime.datetime.utcnow()の代わりにdatetime.datetime.now(datetime.UTC)を使おう

Python系の写経で`datetime.datetime.utcnow()`を使うと非推奨と出てきたので、代わりにどうすればいいのか調べたら`datetime.datetime.now(datetime.UTC)`を使えとのことだった。ただ、それだけ。

```python
import datetime 

now = datetime.datetime.utcnow(datetime.UTC)
```
Claude+MCPでGoogleドライブに書き込んだり、メールを送ったり

#### Claude+MCPでGoogleドライブに書き込んだり、メールを送ったり
Claudeは、Gmailを見たり、Google Driveを見たりできますが、そのままでは、Gmailを送ったり、Google Driveに書き込んだりはできません。

そこで、
### Activepieces
```
https://www.activepieces.com/
```
を使って、gmailを送ったり、google driveに書き込んだりできるように
します。(Activepieces以外にもN8Nなどを使えます）
これは、MCPを使って他のクラウドストレージやサービスなどとの連携の仕方を
の手習いになります。
Activepiecesは、他の多くのクラウドサービスと連携できます。

これで、Claudeと音声での会話ができるようになると、「◯◯さんに、〜っていうメールを送っておいて」　と言うだけで、メールが送れるようになるわけです。

MCP-> +Add Piece -> Select a piece -> Gmail

MCP-> +Add Piece -> Select a piece -> Google Drive

で、GmailとGoogle Driveを接続します。

Activepieces　https://www.activepieces.com/
に、gmailアカウント情報などでログインします。

左のタブのMCPをタップし、

Client Setup Instructions　画面でClaudeを選択する下の画面になります。

![スクリーンショット 2025-06-01 6.47.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/01bdb696-c051-4205-8bc1-5e3a55a99d57.png)

画面の![スクリーンショット 2025-06-01 6.57.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/90e8d881-11cd-4d16-80ed-441df96efd5b.png)　ボタンをタップすると、"•••••••••••••••••••••"の部分が数値で表示されますので、このConfigrationをコピーして、Claudeのclaude_desktop_config.json を編集して設定します。
→を参考にしてください　https://qiita.com/quittardis/items/a3ba1cc395bcb1c29570

次に、Client Setup Instructions　画面の　My Tools　の　Add Pieceで
Google Driveと、Gmailを追加します。
![スクリーンショット 2025-06-01 7.16.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/1f69fcde-bf80-4d1e-abf3-892c7f2d9031.png)



Claude Desktopをいったん終了（重要）し、起動します。

ここで、Google Driveテストとして、
```
テスト用のテキスト文書を作ってGoogle Driveにアップロードしてください
```

Google Mailのテストとして
```
テスト用のテキスト文書を作ってxxxxx@xxxx.xxx にメールしてください
```
で、動作テストができます。
Googleドライブにファイルがアップロードされていたり、
メールが宛先に届いていればOKです。


Google Driveにアップロードする場合、サイズに制限があります。
ABC408振り返り

## はじめに

AtCoder Beginner Contest 408にRated参加しました。

## 今回のまとめ

- 今回はA問題〜C問題を解いた
- 初実戦上でC問題正答
- 茶パフォが出た
- D問題以降は相変わらず理解不能

## レザルト

- 6264位(Rated参加者内5534位)
- パフォーマンス453
- レーティング113→145(+32)

## A - Timeout

[A - Timeout](https://atcoder.jp/contests/abc408/tasks/abc408_a)
提出時間：9:37

今回1問目の150点問題です。今までの100点問題のようにはいきません。
とはいえ、村長がずっと起きているかどうかを問題文通りに判定するだけなので、さほど難しいことはありません。

150点問題をさほどやっていないこと、最近はDaily Trainingを休んでいることから、結構時間がかかっています。

```cpp:A.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  int n, s;
  cin >> n >> s;
  bool wake = true;
  int old_t = 0;
  for (int i = 0; i < n; i++) {
    int t, t_diff;
    cin >> t;
    t_diff = t - old_t;
    if (t_diff >= (s + 0.5)) {
      wake = false;
    }
    old_t = t;
  }
  if (wake) cout << "Yes" << endl;
  else cout << "No" << endl;
  return 0;
}
```

## B - Compression

[B - Compression](https://atcoder.jp/contests/abc408/tasks/abc408_b)
提出時間：28:56(19:19)

今回2回目の150点問題です。setの仕様を検索していたら時間がかかってしまいました。
というか、結果出力が難しいという印象です。

```cpp:B.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  int n;
  set<int> a;
  cin >> n;
  for (int i = 0; i < n; i++) {
    int ain;
    cin >> ain;
    a.insert(ain);
  }
  cout << a.size() << endl;
  set<int>::iterator i = a.begin();
  while (i != a.end()) {
    if (i != a.begin()) cout << " "; 
    cout << *i++;
  }
  cout << endl;
  return 0;
}
```

## C - Not All Covered

[C - Not All Covered](https://atcoder.jp/contests/abc408/tasks/abc408_c)
提出時間：50:57(22:01)

これはアルゴ数学本でやった階差と累積和で出せるな、と判断しました。
とりあえず捻っているとはいえ、階差と累積和の基礎問題だなと思いました。

どちらかというと、C問題を実戦で解けたのが感動でした。
いままで解けなかったので。

階差で配列に入力し、累積和のうち一番低い値を結果として出すことで正解となりました。
眠気と混乱で変数名が変なことになっていますが気にしないでください。

```cpp:C.cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vl = vector<ll>;
#define rep(i,n) for (ll i = 0; i < (n); i++)
#define rep1(i,n) for (ll i = 1; i <= (n); i++)

int main() {
  ll n, m;
  cin >> n >> m;
  vl g(n + 2);
  rep(i, m) {
    ll l, r;
    cin >> l >> r;
    g[l]++;
    g[r+1]--;
  }
  ll guardpoint = 0;
  ll attackpoint = 1e9;
  rep1(i, n) {
    guardpoint += g[i];
    if (guardpoint < 1) {
      cout << 0 << endl;
      return 0;
    }
    attackpoint = min(attackpoint, guardpoint);
  }
  cout << attackpoint << endl;
  return 0;
}
```

## そしてD問題以降は

解けていません。というか、問題文が難しくて解けませんでした。

## 今後の方針

- アルゴ式の『数理素養』を引き続き進める
- アルゴ数学本や鉄則本の問題が難しいので、まずは予習として一通り読む
- 今後もコンテストには積極的に参加していきたいところ
ChatGPTを使用したアプリ開発記【プロフィール画面の画像表示処理の修正】

## 🧨 問題点： 
```Profile.js
{post.imageUrl && (
  <video controls style={{ maxWidth: '100%' }}>
    <source src={post.videoUrl} type="video/mp4" />
  </video>
)}
```
•	post.imageUrl をチェックしているのに、表示しようとしているのは post.videoUrl（＝ null）です。
•	結果：写真が表示されない。

## 🔧 修正後コード
```Profile.js
{post.imageUrl && (
  <img
    src={post.imageUrl}
    alt="投稿画像"
    style={{ maxWidth: '100%', borderRadius: '8px', marginTop: '0.5rem' }}
  />
)}

{post.videoUrl && (
  <video controls style={{ maxWidth: '100%', borderRadius: '8px', marginTop: '0.5rem' }}>
    <source src={post.videoUrl} type="video/mp4" />
  </video>
)}
```
•	投稿に画像がある場合、それが img タグで表示される。
•	投稿に動画がある場合、それが video タグで再生される。

## UI

![スクリーンショット 2025-05-23 8.06.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1058366/9857a52a-7b8d-424c-97fd-3af72f062578.png)
【Google Colab】OpenAI APIのTypeError: Client.init() got an unexpected keyword argument 'proxies'解消方法

## はじめに
Udemyの[RAG実装講座](https://www.udemy.com/course/rag-deploy/?srsltid=AfmBOoqGcEqMq3YeI7j-jBZUHGukqNHS_AaADo4VPT-I5pwTyeSMPX9f&couponCode=V2JPLETSLEARN "【初心者向け】大規模言語モデルにおけるRAGを実装できるようになろう！Webページの情報を元に回答できるAIを作ろう！")をGoogleColabで実行したときに発生しました。

## エラー内容
```python
from openai import OpenAI
client = OpenAI() # エラー発生
```

```python
TypeError: Client.init() got an unexpected keyword argument 'proxies'
```

## 原因
実装講座で指定のopenaiバージョン(1.25.1)とGoogleColab実行環境のHTTPX(HTTP通信のライブラリ)が不整合を起こしている
```python
# 2025年6月現在のバージョン
!pip show httpx
> Name: httpx
> Version: 0.28.1
```
#### まとめ
・OpenAI 1.25.1：proxies(複数形)を使用
・httpx0.28.1：proxy(単数形)パラメータを使用

## 解決方法
proxiesを使用しているhttpxバージョンにダウングレード
```python
!pip install httpx==0.27.0 --force-reinstall
```
Webサイト制作初心者が各画面の内容とフローを考えた

# はじめに
作成中の「調査依頼サイト」ですが、制作しながらもある程度考えていた利用方法について吐き出します。
※ サイトを見ながらでないと、文字ばかりの記事は見にくいかもしれません、すみません。
https://www.everyit.net/

# ユーザ動線の整理

## 利用者の動き
1. 初めはQiitaなど個人のサイトから入ってきます
(Google検索からの訪問は考えておらず、ユーザはある程度のITへの興味がある想定) 
1. 「依頼ボード」で解決された依頼を見て興味を持ってもらいます
1. 実際にフォームから依頼を行います
    ※ 「公開」の場合依頼ボードに反映されます。「非公開」の場合は反映がなく、メールを待ちます。
    ※ EMAILを入力しなかった場合は通知がなく、依頼ボードでの公開回答となります。
    ※ EMAILを入力した場合は、調査にあたってやりとりを行いながら対応を行います。
1. 調査対応が開始されると、管理者からの開始通知メールがきます
1. 調査が完了すると、フォームに入力したメールへの通知が行われます
1. 「依頼ボード」への掲載を確認され終了します

## 管理者の動き
1. 依頼がくると、内容を確認します
1. 対応を開始した段階で、入力されたメールアドレスへの通知を行います
    ※ 詳細情報が必要な場合はメール等で確認を行います
1. 調査対応を行い、完了したら利用者へ依頼ボードへの掲載確認を行います
    ※ アドレスがない場合は、単発で依頼ボードへの返信をもって完了となります
1. 「依頼ボード」の「調査結果」を記載し終了します

# 画面について
### トップ
正直、どのような内容が良いかわかりません。
ABOUTページがあれば不要かもしれません。
### ABOUTページ
依頼の例、調査者（私）の実績、Q&Aなどを記載します。
依頼・質問をしていいかの情報を見るイメージです。
### 依頼ボード
公開OKとなった未対応、対応中、完了済みのすべての依頼を掲載する予定です。
初見の方はここを見てどんなサイトかわかり、依頼した利用者は結果を確認できる、サイトの肝の機能になる予定です。
### フォーム
現状ではGoogleフォームを設置しています。
改修後は直接DBへの登録＋管理者への通知が行えるようにします。

- お名前（必須）：ペンネーム等でも可能
- 公開設定（必須）：依頼ボードに公開するかを選択し、非公開の場合はメールアドレス必須
- メールアドレス（条件必須）：調査のやり取りに使用、調査完了時の通知に使用
- 依頼内容（必須）：依頼内容の入力

### 価格
無料で行うことを記載します。
アクセス数が増えた場合は、「依頼内容に満足した場合任意の金額をいただく」形を考えています。本業に、とは現段階では全く考えていないです。

# さいごに
備忘としてもフローを残しました。
各画面にコンテンツの例だけ実装したのですが、外部からの見栄えの意味でも
・トップページを消しABOUTに統合する
・依頼ボードをDBに登録したレコードからの表示にする
・依頼ボードのデザイン
を優先して行う予定です。
Streamlitでサクッと！タイタニック予測データを加工＆可視化してみた

こんにちは、pomeshiba29です ！
今回は、有名な「タイタニック予測」のデータセットを題材に、**Streamlit**を使ってGUIベースでデータ加工と可視化を行うアプリを作ってみました。
[GitHub](https://github.com/pomeshiba29/Streamlit_ML_Preprocessing)上にローカル環境で動かせるコードを格納しておりますので、興味がありましたらご確認ください。

## 1.Streamlitとは？

**Streamlit** は、PythonだけでWebアプリが作れるオープンソースのライブラリです。  
機械学習やデータ分析の結果を、**コード数行でインタラクティブに可視化**できるのが最大の特長です。

## 2.使用データ

- [Titanic - Machine Learning from Disaster](https://www.kaggle.com/competitions/titanic/data)（Kaggle公開データ）

こちらをダウンロードの上で `train.csv` を使用してデータ加工してみます。

## 3.Streamlitで実装した機能の紹介

### 🧹 データ加工機能
GUI操作で以下のようなデータ確認・加工操作を実装しました（デモ動画もあり）。

- **CSVアップロード**
✅ GUI上にドラッグアンドドロップで読み込ませることができます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681141/7b8b2997-e284-4c2f-82e6-23b1bc45408a.png)
　
- **型変換（str→intなど）**
✅ プルダウンリストから変更したい型が選択できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681141/ca21133e-a1bc-473c-b506-0b8b43ac2f78.png)
　
- **目的変数の設定**
✅ 目的変数を選択し、正例と負例を指定する事ができます（判別分析の場合）
（※回帰分析の場合は選択のみ（スキップも可能））
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681141/f62b8b9b-90ba-4034-a9a0-d10d8256569c.png)
　
- **数値統計量の確認**
✅ 数値データとして選択したカラムの統計量が確認できます
（※タイタニック予測には日付データは無いのでこちらはスキップ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681141/07659636-ed28-4f31-9383-86554d117893.png)
　
- **欠損値と外れ値の確認**
✅ 数値データとして選択したカラムの欠損値と外れ値が確認できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681141/141d2a97-cea2-4f6f-8a17-b7d83f66996b.png)
　
- **カテゴリ変数の概要確認**
✅ カテゴリ変数における欠損値、ユニーク数、最頻値が確認できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681141/0bae808f-7e34-4a48-9576-6c394b6e43a9.png)
　
- **外れ値・欠損値の補完（ゼロ埋め／平均／最頻値／レコード削除）**
✅ GUI上で外れ値・欠損値の扱いを指定する事ができます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681141/1df555c0-b236-422e-ae39-3e2a5b98393f.png)
　
- **カテゴリ変数のエンコーディング（Label / One-hot / カラム削除）**
✅ カテゴリ変数のエンコーディング方法を指定する事ができます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681141/690e2ed0-554b-49f5-84b6-687f283df958.png)
　
- **加工後データのプレビューとCSVダウンロード**
✅ 加工データのプレビューや、ローカルへのCSVダウンロードがワンクリックで行えます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681141/55e8f03b-1ef5-4184-a527-b4794faccace.png)
　
### 🎥実際のデモ動画
✅ 本アプリの実際の操作イメージとなります
![demo](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681141/b6420507-b418-4b59-8069-301460f79778.gif)

## 💬 感想とまとめ
Streamlitによってコードを書かずにデータ前処理＆可視化ができる環境がすぐに整います。
想像以上に柔軟な機能実装が出来ることが分かったので、今後もStreamlitを有効活用していきたいと思います。

- 教育・研修用途にも最適

- 分析の入り口として初心者にも優しい

- アプリの構成を汎用化すれば、別データでも使い回し可能！

## 🚀 今後の展望
- Streamlitで学習モデルの作成・評価編をやってみたい

- AutoMLと連携してモデル選定まで自動化したい

- クラウド環境（Streamlit Cloudなど）でデプロイして多くの人と共有

## 🔗 リンク
GitHubリポジトリ：[URL](https://github.com/pomeshiba29/Streamlit_ML_Preprocessing)

使用データ：[Kaggle Titanic Dataset](https://www.kaggle.com/competitions/titanic/data)

Streamlit公式：https://streamlit.io/

## 🙏 最後に
Streamlit初めて使ってみましたが、便利ですね！
もし、「こういった使い方もおすすめ！」
などありましたら、是非教えていただけますと幸いです。
GitLab + Jenkins（Docker）でロリポップに自動デプロイするCI/CD環境構築を試してみた

こんにちは。この記事では、GitLabとDocker上のJenkinsを使って、**`git push`のたびにロリポップのWebサーバへ自動デプロイ**する仕組みを構築したので、その手順をまとめます。  
ローカルJenkinsにWebhookを通すために `ngrok` を活用している点がポイントです。

なお始めた背景には、CI/CDに興味があったということがあります。
実際自分がアサインされた案件において、projectのbuildやreleaseに組み込まれていました。裏側の仕組みが気になっていたため構築してみることにしたという経緯です！

# 全体構成
```
  [local PC(Windows)]
        │
        │ git push
        ▼
  ┌────────────┐
  │   GitLab   │
  └────────────┘
        │
        │ Webhook発火(Jenkinsへ通知)
        ▼
  ┌───────────────────┐
  │ ngrok(トンネル作成)│
  └───────────────────┘
        │
        │ （一時的な公開URLを発行）
        ▼
  ┌─────────────────────────────────┐
  │ Jenkins (Docker localhost:8080) │
  └─────────────────────────────────┘
        │
        │ build＆deploy
        ▼
  ┌────────────────────┐
  │ lolipop(Webserver) │
  │ (FTP)              │
  └────────────────────┘
```


# 🛠️ 環境概要

| 項目              | 内容                                       |
|-------------------|--------------------------------------------|
| ローカル環境       | Windows                |
| Gitホスティング     | GitLab（gitlab.com）                       |
| CI/CDツール       | Jenkins（Dockerコンテナで起動）           |
| 外部公開           | ngrokでJenkinsのポートを一時的に外部公開   |
| Webサーバ          | ロリポップ（FTPアップロード）             |

## 🐳 JenkinsをDockerで起動

```bash
docker run -d \
  --name jenkins \
  -p 8080:8080 -p 50000:50000 \
  -v jenkins_home:/var/jenkins_home \
  jenkins/jenkins:lts
```

# ngrokで外部公開

GitLabのWebhookがローカルJenkinsに届くように、ngrokで外部トンネルを張ります：

```bash
ngrok http 8080
```

- 表示されたURL（例：`https://abcd1234.ngrok.io`）をGitLabのWebhookに設定します。
- **無料プランではこのURLは毎回変わります**（固定URLは有料プラン限定）。


# GitLab Webhook設定

GitLab > [Your Repo] > Settings > Webhooks：

- URL： `https://xxxx.ngrok.io/job/<ジョブ名>/build?token=YOUR_TOKEN`
- Trigger： Push events ✅

Jenkins側は「リモートビルドの許可」をONにし、トークンを設定しました。

#  Jenkinsジョブ内容（FTPアップロード）

```bash
#!/bin/bash
echo "Deploy start"

lftp -u ユーザー名,パスワード ftp://ftp.lolipop.jp <<EOF
cd public_html
mirror -R ./dist ./
bye
EOF
```

# 動作確認手順

1. `ngrok http 8080` でJenkinsを外部公開  
2. `git push` でGitLabに変更を送信  
3. GitLabのWebhookがngrok経由でJenkinsに通知  
4. Jenkinsがジョブを実行し、webserver(今回はlolipop)にアップロード  
5. Webサイトに反映されていれば成功！

# 🧩 注意点・補足

- ngrok無料プランではURLが起動ごとに変わってしまいます。
　→ そのため、**Webhookの更新が毎回必要**。
 
# 🔚 まとめ

- GitLab + Jenkins（Docker） + ngrok + ロリポップ の構成で、**簡易CI/CD**の構築を経験できました。
    →会社のCI/CDのフローがあまり理解できていなかったので、実際に手を動かして経験することで、Jenkinsの役割について改めて理解できました。
- 無料版だとngrokのURLが変わってしまうことは盲点でした。現状だと少し使いにくいので改良していきたいなと思いつつ、実際やってみたかったCI/CDまわりの理解はできたので一旦はよしとします。
ブラウザのしくみをはじめての人にもわかるように解説してみた

今回はブラウザの仕組みをはじめての人でも
分かるように解説するという内容で書いていきます。

エンジニアになろうと思って勉強してる中で
ブラウザの存在は切っても切り離せません。

昔のブラウザについて理解してない自分でも
理解できるように分かりやすく解説していきたいと思います。

ブラウザはなんとなく普段使ってるものですが
内部の仕組みを理解するといろんな発見があるので
ぜひ最後まで読んでいってください！

では、初めていきます。


## ブラウザってなに？

ブラウザは、インターネットで
ウェブサイトを見るための特別なソフトです。

Google Chrome、Safari、Firefox など
まさにあなたも何かしらのブラウザを通して
今この記事を見ているわけです。

では、そんなブラウザは何をしてるのか
詳しく見ていきましょう！


## ブラウザのおもな役割

ブラウザには様々な役割があります。

この役割によってサイトを閲覧したり、
サイトの中のいろんな機能を使えるわけです。

では、どんな役割があるのか
簡単に説明していきます。

1. **見た目を整える**: 例えばGoogleで何かを検索するとしましょう。検索するためには検索窓に何かを打ち込んで検索します。その検索窓だったり、ブラウザバックするためのボタン。そう言った私たちが使う部分を分かりやすくしてくれています。  
2. **ページを表示する**: Googleを使って例えば料理のレシピを検索するとします。するとクックパッドなど関連するwebページのリンクが表示され、それをクリックすると実際にクックパッドを見ることができます。このクックパッドのページを表示できてるのもブラウザのおかげなのです。  
3. **インターネットとつながる**: ウェブサイトには様々なデータが保管されてます。先ほどのクックパッドの例で言うと人が書いたレシピの内容とかですね。これらをブラウザは私たちが見えるように持ってきて表示してくれます。  
4. **プログラムを動かす**: ウェブサイトでログインしないと詳細が見れないページなどありますよね？あれはプログラムを組むことで実行できるのですが、そのプログラムをきちんと反映させるのもブラウザの仕事です。  
5. **データを保存する**: ウェブサイトには様々なデータが保管されてると言いましたがブラウザにもデータを保存することができます。Cookieなどかその一例ですね。


## ブラウザはこんなふうに動いています

さて、ブラウザの役割を理解したところで
次はどのように動いてるのか見ていきましょう！

1. **アドレスを入力する**: 見たいウェブサイトのアドレスを入力します。（http://）からはじまるやつですね。（https://）というセキュリティが強いのもありますが今は同じでウェブサイトがここにありますよと示しています。

2. **サイトを探す**: 入力されたアドレスから、ウェブサイトがどこにあるか探します。アドレスをもとにブラウザがウェブサイトの場所を特定してくれるわけです。

3. **サイトにつながる**: 見つけたウェブサイトにアクセスします。場所を特定したらブラウザはそのウェブサイトを表示するための準備に入ります。

4. **データをもらう**: ウェブサイトからデータをもらいます。ウェブサイトから画像やデザイン、内部のプログラムを貰ってきて準備を進めていきます。

6. **ページを組み立てる**: 
   - デザインを適用する
   - プログラムを実行する
   - ページの形を決める
   - 色を塗る
   集めたデータをもとにWebページを構築していきます。実はウェブサイトに飛んだらそこにページがあるのではなく、あくまでブラウザがアドレスから取得したデータを元にページを組み立て表示しているんです。

7. **表示する**: 完成したページを画面に表示します。組み立てが完了したらそれを表示して私たちが実際にいつも見ているクックパッドのサイトのようになるわけです。

## たとえで理解する

さて、動きの流れを理解したところで
ブラウザの動きを、お弁当作りに例えてみましょう。

お弁当に作りに例えるとこのようになります。

1. レシピ（URL）を選ぶ
2. レシピの本（DNSサーバー）で探す
3. スーパー（ウェブサーバー）に行く
4. 材料（ウェブサイトのデータ）を買う
5. 家に持ち帰る（ダウンロード）
6. 料理する（ページの組み立て）
7. お皿に盛る（画面に表示）

個別のワードは難しく見えるかもしれませんが
やってることは割とシンプルです。

## まとめ

いかがでしたでしょうか？

普段何気なく使っているブラウザですが、
裏ではあなたが入力したアドレスのウェブサイトを探し出したり、
そのデータを集めたり、
それを元にページに組み立てて表示したりと
色々なことをしてくれてるんです。

ブラウザのしくみを知ることで
自分でウェブサイトを作る際に
今何をなんのためにしているのか？

といった全体像が理解しやすくなります。
プログラムは大きくなるほど複雑になり
何をしてるのか分からなくなることも多いです。

そうならない為にも基礎的な知識を身につけることで
全体を俯瞰して見ることができ、
より良いサービスを構築できるようになっていきます！

自分もより全体像を把握できるように
日々勉強していく所存です！

最後まで読んでいただきありがとうございました！
Geminiでロングソードを使う魔法少女を描いてみた。

# 概要

Geminiでロングソードを使う魔法少女を描いてみました。

# 実装

プロンプトと実行結果は以下の通りでした。

```
聖なるロングソードを使う魔法少女を描いてください。
```

![聖なるロングソードを使う魔法少女_20250601.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192024/eff2adf2-0bb7-4f51-b7eb-b8afc6fb0045.png)


# まとめ

可愛いかも。何かの役に立てばと。
Python でメール送信

Python から SMTP サーバを使用してメールを送信するコードを書いたので、メモ。

## SMTP サーバのログイン情報
``` python
SMTP_HOST = "example.com"
SMTP_USERNAME = "user@example.com"
SMTP_PASSWORD = "********"
```

## メッセージの組み立て
メッセージオブジェクトは `email.message.Message` であれば何でも良いが、`EmailMessage` を使用すると何かと便利。

``` python
from email.message import EmailMessage

msg = EmailMessage()
msg["Subject"] = "テスト subject"
msg["From"] = SMTP_USERNAME
msg["To"] = "example@gmail.com"
msg.set_content("テスト body")
```

## メッセージを送信する
送信する際の暗号化通信の方式として STARTTLS が利用できればいいが、できない場合は SMTPS を利用する。

### STARTTLS を利用する場合
SMTP で暗号化通信をするには STARTTLS を利用する方法がベストプラクティスらしい。

``` python
from smtplib import SMTP

with SMTP(SMTP_HOST) as smtp:
    smtp.starttls()
    smtp.login(SMTP_USERNAME, SMTP_PASSWORD)
    smtp.send_message(msg)
```

ここではポート番号を指定していないのでデフォルトの 25 が使用されるが、場合によってはサブミッションポート (587) を指定する必要があるかもしれない。

### SMTPS (SMTP over TLS) を利用する場合
何らかの事情で STARTTLS による暗号化通信を利用できない場合に SMTPS (SMTP over TLS) を利用することもできる。

``` python
from smtplib import SMTP_SSL

with SMTP_SSL(SMTP_HOST) as smtp:
    smtp.login(SMTP_USERNAME, SMTP_PASSWORD)
    smtp.send_message(msg)
```

この場合、デフォルトではポート 465 が使用される。
Collectors.groupingByの戻り値を TreeMapやLinkedHashMapにしたい

`Collectors.groupingBy` の戻り値を `TreeMap`や`LinkedHashMap`にしたい場合は、第2引数にMapの生成方法を指定します。

例 : リスト内の単語を頭文字ごとに数えた結果を`TreeMap`に格納する。

```java
List<String> words = List.of("Cake", "Bird", "Apple", "Car", "Book", "Cat");
TreeMap<Character, Long> treemap = words.stream().collect(Collectors.groupingBy(word -> word.charAt(0), TreeMap::new, Collectors.counting()));
System.out.println(treemap); // => {A=1, B=2, C=3}
```

`LinkedHashMap` にしたい場合は `LinkedHashMap::new` と指定するだけです。

*環境情報*

- javac 21.0.6
- openjdk 21.0.6 2025-01-21 LTS