OmniAICreator/Qiita-1.07M huggingface dataset:
El origen de C#

El origen de C#
https://www.youtube.com/watch?v=UUQTjA0cRpQ&t=4s

Programando Otra Historia
https://www.youtube.com/@programandootrahistoria/videos

Participó en un proyecto para generar automáticamente programas de control de motores compatibles con Ethercat a partir de diagramas de tiempo. Se decidió que el lenguaje de desarrollo sería C#.
timing図からEthercat対応の電動機制御プログラムを自動生成する事業に参加しました。開発言語はC#にしました。

Al parecer utilizan C# en una empresa que utiliza Unity.
Unityを使う事業でC#を使っているらしい。

C# to C++
https://qiita.com/kaizen_nagoya/items/ce454384f09c8f51831f

1日1java, 1日１C#、１日１F# (The C Puzzle Book) coding(54)
https://qiita.com/kaizen_nagoya/items/7543ede4c266c288a855

C#, Visual Basic and python
https://qiita.com/kaizen_nagoya/items/653f4718f795984f3fb7

Unityと箱庭
https://qiita.com/kaizen_nagoya/items/7ae193df6efa1d2f2ba0

LinuxChad y así sucesivamente, スペイン語でプログラミング
https://qiita.com/kaizen_nagoya/items/cdae082ffdfffee10605
デプロイしたエージェントをDatabricks Appsで利用する

# はじめに

この記事では、[以前作成したDatabricksの公式ドキュメントを学習させたAIエージェント](https://qiita.com/T88/items/0fe3f617ac4fcbf8a88f)をDatabricks Appsで利用してみます。

#  Databricks Appsでチャットボットアプリを簡単作成
DatabricksのUIからクラスター > アプリ セクションに移動し、新しいアプリケーションを作成します。標準で提供されている「Chatbot」テンプレートを選択します。  
アプリケーションの設定画面で、バックエンドとなるAIエージェントを指定します。前回デプロイしたDatabricks公式ドキュメント対応AIエージェントのサービングエンドポイントを設定します。あとはデプロイするだけです。
![Pasted image 20250505173219.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160102/9b56c68d-363a-4f01-b9ba-2872ef15e4e1.png)

これらの簡単なステップで、基本的なチャット形式のアプリケーションがデプロイされ、AIエージェントと対話できるようになりました。
![Pasted image 20250505195923.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160102/6093beed-a65d-47bf-9d9e-47440e0734cc.png)

# 資格試験対策用にカスタマイズ

これだけだとplaygroundの機能縮小版でしかないので、少しカスタマイズもしてみたいと思います。このチャットボットをDatabricksの資格試験対策ツールとして、より実践的に使えるようにします。特定の試験範囲のトピックを選択すると、AIエージェントがそのトピックに関する解説を提供してくれるアプリケーションです。



## 試験範囲の定義 (YAML)

まず、試験ガイドに記載されている試験範囲の各トピックをYAMLファイル（`cert.yaml`）に整理して保存します。これにより、アプリケーションから試験範囲のリストを容易に読み込めるようになります。　　

:::note
今回は、いつのまにか日本語化されていた（そして私がまだ取得できていない）Data Engineer Professionalを題材とします。
[Databricks Certified Data Engineer Professional Exam Guide (日本語版)](https://www.databricks.com/sites/default/files/2025-04/databricks-certified-data-engineer-professional-exam-guide-ja.pdf)
:::

```yaml:cert.yaml
data_engineer_professional:
  - "Delta Lakeがトランザクションログとクラウドオブジェクトストレージを使用して原子性と永続性を保証する方法"
  - "Delta Lakeが楽観的同時実行制御を使用して分離を実現する方法と競合する可能性があるトランザクション"
  - "Delta クローンの基本的な機能"
  - "Delta Lakeの一般的なインデックス最適化（パーティショニング、Z-Order、Bloomフィルタ、ファイルサイズ）の適用"

〜中略〜
```

# Gradioのコード修正 with Claude 3.7 Sonnet

次に、アプリケーションのフロントエンド（UI）のGradioコードを修正します。ほぼ、Claude 3.7 SonnetとのVibe Codingです。以下の機能を持つようにコードを修正しました。

1.  **試験種別の選択:** 複数の資格試験に対応できるよう、まず試験種別を選択するドロップダウンリストを設けます（今回は`data_engineer_professional`のみ）。
2.  **トピックの選択:** 選択された試験種別に応じて、`cert.yaml`から読み込んだ関連トピックをドロップダウンリストに表示します。
3.  **解説の表示:** ユーザーがトピックを選択すると、そのトピック名をハードコードしたtemplateに埋め込んだプロンプトを生成し、バックエンドのAIエージェント（サービングエンドポイント経由）に送信します。
4.  **結果の表示:** AIエージェントからの応答（トピックの解説）を受け取り、画面上のMarkdownエリアに表示します。

# 完成したアプリケーション

上記コードをデプロイすることで、資格試験対策に特化したチャットボットアプリケーションが完成しました。
![Pasted image 20250505212535.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160102/2b7b8080-aefb-4717-87a6-43ef80daae7e.png)


ユーザーはまず「試験種別を選択」ドロップダウンから対象の試験（例: `data_engineer_professional`）を選びます。すると、「トピックを選択」ドロップダウンに、その試験範囲に対応するトピックの一覧が表示されます。学習したいトピックを選択すると、その内容が「選択されたトピック」欄に表示され、同時に関連する解説がAIエージェントによって生成され、下部のチャット出力エリアに表示される仕組みです。

## まとめ

今回は、Databricks Appsと既存のAIエージェント（サービングエンドポイント）を組み合わせることで、特定の用途（今回は資格試験対策）に合わせたチャットボットアプリケーションを比較的容易に開発できることを示しました。Gradioを用いることで、インタラクティブなUIも効率的に実装可能です。

YAMLファイルで知識ソース（今回は試験範囲）を管理し、それを動的に読み込んでUIに反映させることで、メンテナンス性も向上します。同様のアプローチは、社内ドキュメント検索やFAQボットなど、様々な応用が考えられます。

Databricks Appsは、データエンジニアやデータサイエンティストが自身の成果物を手軽にアプリケーションとして公開・共有するための強力なツールとなり得ると感じました。
[Django]選択肢から選ばせるフィールドの実装方法

Djangoで、モデルを設計しているとき、選択肢のどれかを値にもつフィールドを実装することがあると思います。
その時の実装方法の使い分けや注意点をまとめてみました。

## 選択肢フィールドの実装方法３通り

以下の3つが主な実装パターンです。

1. 外部キーを使う（`ForeignKey` や `ManyToManyField` など）
2. タプルリストを使う
3. `models.TextChoices` を使う

使い分けの目安は以下のとおりです：

- **選択肢を動的に追加・変更したい** → 1. 外部キー
- **選択肢が一度きりの使い捨てで良い** → 2. タプルリスト
- **選択肢が固定で、再利用・定数アクセスしたい** → 3. `models.TextChoices`

それぞれ詳しく解説します。
## 1. 外部キーを使う

最も汎用性が高い方法です。

たとえば、Articleモデルがauthorのフィールドを持つ場合、Userモデル等を `ForeignKey` で紐づけると、後から選択肢を管理画面などで追加・変更しやすくなります。

また、Articleモデルにタグをつけたい場合などは、Tagモデルを`ManyToManyField` で紐付けると便利です。

**注意点**：
`on_delete=models.CASCADE` を安易に使わず、`models.PROTECT` や `models.SET_NULL` など、アプリの仕様に応じて適切に設定しましょう。
例えば、ある執筆者が選択肢から不要になっても、models.CASCADEにしているとそれを削除したらその執筆者が書いた記事まで削除されてしまいます。

## 2. タプルリストを使う

簡単に実装したいときに使える方法です。  
ちょっとした用途で使い捨ての選択肢が必要な場合に適しています。
MVP（Minimum Viable Product)を作るときにも適しています。

例：性別の選択肢（追加・変更の予定がない場合）

```python
GENDER_CHOICES = [
    ("male", "男性"),
    ("female", "女性"),
    ("other", "その他/不明"),
]

class User(AbstractUser):
    gender = models.CharField(max_length=10, choices=GENDER_CHOICES)
````

非常に簡単ですが、保守性や再利用性を考えると、以下の `TextChoices` を使った方が良い場面が多いです。


## 3. `models.TextChoices` を使う

選択肢が固定で、複数のモデルで使い回したい場合は、`models.TextChoices` が便利です。

たとえば、`User` モデルと `Customer` モデルの両方で性別フィールドを持たせたい場合、以下のように共通クラスを定義できます。

```python
class Gender(models.TextChoices):
    MALE = "male", "男性"
    FEMALE = "female", "女性"
    OTHER = "other", "その他/不明"

class User(AbstractUser):
    gender = models.CharField(
        max_length=10,
        choices=Gender.choices,
        default=Gender.OTHER,
    )

class Customer(models.Model):
    gender = models.CharField(
        max_length=10,
        choices=Gender.choices,
        default=Gender.OTHER,
    )
```

### TextChoices の構文
サンプルコードを見てもらえば、なんとなく分かると思いますが、それぞれの選択肢を、

```python
"変数名" = "保存値", "表示ラベル"
```
のように書きます。
* **保存値**：DBに保存される値（英語など短い文字列）
* **表示ラベル**：管理画面やフォームなどに表示される日本語ラベルなど

です。

### 利点：定数アクセスとテンプレート表示が簡単

`TextChoices`を使うと、定数アクセスができて、以下のように条件文で活用できたり、

```python
if user.gender == Gender.MALE:
    ...
```
初期期をdefault=Gender.OTHERのように簡単に設定できます

また、テンプレートでは `.get_FOO_display` を使って簡単に表示できます（`FOO` はフィールド名）。自分で表示するロジックを書く必要がありません。

```django
{{ user.get_gender_display }}
```

---

## まとめ

| 方法            | 向いている用途       | 再利用性 | 保守性 |
| ------------- | ------------- | ---- | --- |
| 外部キー          | 動的に管理したい選択肢   | 高い   | 高い  |
| タプルリスト        | 単発・簡易用途       | 低い   | 低い  |
| `TextChoices` | 再利用・定数アクセスしたい | 高い   | 高い  |

選択肢の性質や再利用性を考慮して、最適な方法を選びましょう。
AIが生成するコードが毎回異なることについて（条件満たせば異なっても問題ないのでは？）

AIにコーディングさせると毎回コードが変わることについて思うことを書いてみます。

# ❓️与えている仕様が少ない、前提条件が複雑

コード内容が変わるのは、与えている仕様が少なすぎる場合な気がします。
なので、ある程度前提条件や仕様を与えると毎回近いコードにはなる気がします。
もっとも、かなり細かい指示が必要になると思います。

作るモジュールの粒度が大きい場合、与える情報が少なくなりがちです。なので、できるだけモジュールの粒度は小さくするほうが良いと思います。

たとえば、テーブル定義書をCSVでつくって、そこからモデルやSQLつくれといったら、同じコードができます。単純であればあるほど。

一方、ざっくりと画面つくってというと、いろいろな前提条件が考えられるので、コード内容はブレが多くなります。

rulesなどで技術スタックを定義し、細かくモジュールの仕様をつくり、実行すると比較的意図したコードになると思います。

## 👫人間がコーディングする場合も、要求仕様が同じでも千差万別

同じ仕様、同じ人間でも書き方が変わったりすることはままあります。まして、人間が変わればコードはやはり変わります。

ただ、プログラムの良さでもあると思いますが、とにかくどんな書き方をしても、要求仕様を満たすことはできます。ポイントを要求仕様を満たしているかだと思います。

仕様は同じなのに、言語、ライブラリが変わればコード内容は変わります。
でも、要求される仕様さえ満たしておけばOKです。

なので、要求仕様を満たしているかが大切であってコードそのものがいつも同じである必要はあまりないと感じています。
テストコードを書いて、かならず要求仕様を満たしているかのチェックは必要だと思います。

## ⚒️AIだからこそごっそり書き直しはOK

人間だと書いたものを書き直すとかなり時間がかかります。
でも、AIは作るものがはっきりしていれば、短時間でコーディングしてくれます。

ある時点まで作ってきた仕様をドキュメントにしておけば、
作り直し自体はゼロからするときより早いと思います。

## 🗂️工程やモジュール単位で設計やタスクをまとめる

大きめのアプリをつくるとどうしても、ごっそりリファクタリングすることがあります。
といっても、開発工程を小さくわけて、どこからやり直すのかのポイントは分けておくべきだと思います。

たとえば、Webアプリであれば以下のように工程ごとにタスクグループをわけて、特定のタスクグループから作業をやりなおすようにすればよいと思います。

:::note info
**Webアプリの開発工程**
１．開発環境構築
２．DB構築
３．API構築
４．画面作成（共通部分）
５．画面作成（個別部分）
６．テストコード作成（ユニットテスト、Playwrightなどの画面テスト）
７．本番環境構築
８．デプロイ
:::

多分、上記の1-3、7-8はそんなにやり直すこともないと思います。
4～6あたりは結構、作り直しが発生すると思います。

2-3のDB、APIはすべてのリソースをごっそり変えることはそれほどなくて、
テーブル追加や列の更新など既存リソースの変更ぐらいが多いと思います。

## 📜必ず仕様やタスクはファイルで保存しておく

AIなのでリファクタリングすること自体を避ける必要はあまりない気がします。
ただ、そのためには、要求仕様やタスクを記録しておく事が必要です。

ある程度ソフトウェア開発になれていると最初にドキュメントをつくり、タスクファイルをつくって、小さくAIにモジュールをつくらせていくと思います。

一方、あまりソフトウェア開発に慣れていない場合、ゴールシークプロンプトで要求仕様に向けて、AIとチャットをしながらアプリをつくると思います。この場合でも、かならずつくったものの仕様やタスクに関するドキュメントをAIに作らせておくべきだと思います。

ドキュメントやタスクをファイルに残すことはとても重要だと思います。ただ、それの作り方は経験値によって変わると思います。

以下のプロジェクト情報をコードで残すという記事は深く同意します。

https://qiita.com/kumai_yu/items/0aa2fc294f8e1347e36c

仕様書・設計書だけでなく、指示もファイルにしておくとよいと思います。というかチャットでたくさんの情報を与えるのは限界があります。

https://zenn.dev/jtechjapan_pub/articles/a1cace00f7f96f
Copilot Chat のプロンプト エンジニアリング

【公式ドキュメントを読もうシリーズ】Copilot Chat のプロンプト エンジニアリング

## シリーズ概要

[https://qiita.com/yasu_programming/items/cec66f9e8d5d571e9ce3](https://qiita.com/yasu_programming/items/cec66f9e8d5d571e9ce3)

## URL

[https://docs.github.com/ja/copilot/using-github-copilot/copilot-chat/prompt-engineering-for-copilot-chat](https://docs.github.com/ja/copilot/using-github-copilot/copilot-chat/prompt-engineering-for-copilot-chat)

## 説明

> 一般的なことから開始し、特定の情報を取得する

一般的なことというのは、抽象的なざっくりとしたゴールを提示して、その具体的なこともプロンプトとして与えれば良さそうということだろう。

> 例を示す

文章だけではなく、実際の出力される値など書けばより良いみたい。

```

以下の形式のユーザーデータを変換する関数を作成してください：

入力:
{
  name: "John Doe",
  age: 30,
  address: {
    street: "123 Main St",
    city: "Boston"
  }
}

出力:
{
  fullName: "John Doe",
  yearOfBirth: 1994,
  location: "Boston, 123 Main St"
}

テストケース:
1. 通常のケース（上記の例）
2. addressが空のケース
3. 必須フィールドが欠けているケース

```

上記のような形で、例文を入れれば出力が良くなるのだろう。

> 複雑なタスクを単純なタスクに分割する

**複雑なタスク：ユーザーが記事を投稿、編集、削除できるブログシステムの開発**

を行う時には、

プロンプトの例
1. "記事モデルのマイグレーションファイルを作成してください。"
2. "記事の下書き保存機能を実装してください。"
3. "記事の公開/非公開を切り替えるAPIエンドポイントを作成してください。"
4. "記事一覧の並び替え機能を追加してください。"

に分けることで、よりより結果が得られるのだろう。

> あいまいさを回避します

```
**bad prompt**

データを保存してください。

**good prompt**

以下のユーザーモデルを使用して、名前、メールアドレス、パスワードをデータベースに保存するstoreUserメソッドを実装してください。データの保存前にパスワードをハッシュ化する必要があります。
```

というような形でより具体的な提案をしたほうがいいということでしょう。

## 所感

ざっくりではなく、具体的な提案をすることで、良くなるということなので、いいプロンプトを生成するプロンプトとかを考える必要があるのかなとも思った。
M5SatmpS3、8x8 Puzzle Unit (Unit Puzzle ?)で数字を表示。




いろいろ、注意
----

- なぜか動いた、M5Stack by M5Stack official 2.1.4



結果
----

![image_original(30).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/71acf6c7-c9e6-4973-a5d3-355157933cc4.jpeg)


プログラム
----

```c++


//NeoPixel8x8_0_9_M5StampS3_1


//インクルド
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>


//定義
#define MAX_X 8
#define MAX_Y 8
#define NUM_LEDS 64
#define RGBLED_OUT 13
Adafruit_NeoPixel strip(NUM_LEDS, RGBLED_OUT, NEO_GRB + NEO_KHZ800);

unsigned char Pixel[8][8][3];  //キャラクターRAM(カラー)

// 'font8x8_0_9', 8x64px
unsigned char font8x8_0_9[] = {
  0x81, 0x7c, 0x7a, 0x76, 0x6e, 0x5e, 0x3e, 0x81,  //0
  0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,  //1
  0x81, 0x7e, 0xfe, 0xfe, 0xc1, 0xbf, 0x7f, 0x00,  //2
  0x81, 0x7e, 0xfe, 0xc0, 0xfe, 0xfe, 0x7e, 0x81,  //3
  0xe3, 0xdb, 0xbb, 0x7b, 0x00, 0xfb, 0xfb, 0xfb,  //4
  0x00, 0x7f, 0x7f, 0x01, 0xfe, 0xfe, 0x7e, 0x81,  //5
  0x81, 0x7e, 0x7f, 0x01, 0x7e, 0x7e, 0x7e, 0x81,  //6
  0x00, 0x7e, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf,  //7
  0x81, 0x7e, 0x7e, 0x81, 0x7e, 0x7e, 0x7e, 0x81,  //8
  0x81, 0x7e, 0x7e, 0x7e, 0x80, 0xfe, 0x7e, 0x81,  //9
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   //: ' '
};


//ネオピクセルに転送後に表示
void NeoPixe_OUT() {

  int k = 0;
  for (int y = 0; y < MAX_Y; y++) {
    for (int x = 0; x < MAX_X; x++) {

      strip.setPixelColor(k++, strip.Color(
                                 Pixel[y][x][0], Pixel[y][x][1], Pixel[y][x][2]));

      //Serial.print('.');

    }  //for j
    //Serial.println();
  }  //for i
  //Serial.println();

  strip.show();

}  //NeoPixe_OUT


//8x8文字の表示
void ch_8x8(char ch, int c1, int c2, int c3) {

  ch = (ch - '0') * 8;
  for (int y = 0; y < MAX_Y; y++) {
    int a = font8x8_0_9[ch++];
    for (int x = 0; x < MAX_X; x++) {

      if (((a << x) & 0x80) != 0) {
        Pixel[y][x][0] = 0;
        Pixel[y][x][1] = 0;
        Pixel[y][x][2] = 0;
      } else {
        Pixel[y][x][0] = c1;
        Pixel[y][x][1] = c2;
        Pixel[y][x][2] = c3;
      }  //if

    }  //for j
  }    //for i

  NeoPixe_OUT();  //RBG LEDに出力

}  //ch_8x8


//初期化
void setup() {

  //ネオピクセルの設定
  strip.begin();
  strip.show();

  //シリアルポートの設定
  //Serial.begin(9600);
  //Serial.println();
  //for (int i = 0; i < 9; i++) {
  //  Serial.print('.');
  //  delay(500);  //接続待ち
  //}              //for
  //Serial.println();

}  //main


//メインループ
void loop() {

  for (int i = 0; i < 10; i++) {

    ch_8x8('0' + i, 5, 5, 5);
    delay(3000);  //3秒待つ

  }  //for

}  //loop


```
【公ド読】Copilot Chat のリポジトリのインデックス作成

【公式ドキュメントを読もうシリーズ】Copilot Chat のリポジトリのインデックス作成

## シリーズ概要

[https://qiita.com/yasu_programming/items/cec66f9e8d5d571e9ce3](https://qiita.com/yasu_programming/items/cec66f9e8d5d571e9ce3)

## URL

[https://docs.github.com/ja/copilot/using-github-copilot/copilot-chat/indexing-repositories-for-copilot-chat](https://docs.github.com/ja/copilot/using-github-copilot/copilot-chat/indexing-repositories-for-copilot-chat)

## 説明

Copilot Chatと会話することで、自動的にインデックスが作成されて、よりよい回答ができるという説明。

> Copilot Chat では、モデルトレーニングにインデックス付きリポジトリは使用されません。

インデックスは作るけれども、モデルトレーニングされないので、安心ですね。

## 所感

裏側の挙動確認できた。
個人的備忘録：ローカルでPull Requestブランチを確認したいときの手順

## はじめに

開発チームのハッカソンプロジェクトにて、チームメンバーが作成した `feature/mypage` ブランチの内容を確認する機会がありました。

:::note info
**個人の備忘録程度の走り書きとなっておりますが、温かい目で見守っていただければ幸いです。**
:::

GitHub上でPull Requestが作成されていたため、自分のローカル環境でその内容を取り込んで確認する手順を整理しておきます。

## 書こうと思ったきっかけ

受講しているITスクールのハッカソンの開発の一環で、チームメンバーの成果物をローカルでチェックする必要がありました。手順自体はシンプルですが、今後も同様の場面が発生する可能性があるため、備忘録として残しておきます。

## 内容

### 1. リモートの最新情報を取得

```bash
git fetch origin
```

### 2. `feature/mypage` ブランチをローカルに作成し、切り替える

```bash
git checkout -b feature/mypage origin/feature/mypage
```

※ `origin/feature/mypage` を元にローカルブランチを作成し、そのブランチに切り替えます。

### 3. 作業が完了したら、ブランチを削除する場合

```bash
git checkout main
git branch -d feature/mypage
```

## まとめ

チームでの開発では、Pull Requestブランチをローカルで確認する機会が多くあります。

:::note warn
特に共同開発やレビュー時には頻繁に発生する操作なので、手順をしっかり覚えておくと安心です。
:::

今回は `feature/mypage` ブランチでしたが、今後他のブランチにも応用できる内容として残しておきます...！
[Docker]デプロイにどん詰まって本番構成を組み直した話

## ◆ はじめに

Laravel × Docker構成でSNSサービス「Apprentory」を開発しているんですが、  
最初のうちは **Dockerまわりは全部相方に一任してました**。理由は単純、「よくわからんし、壊しそうだから」。

でも本番デプロイで詰まったある日、  
「自分でやるしかない」という状況に追い込まれ、ついに触る決意をしました。

---

## ◆ 起きていた問題

- **コンテナを再起動するとデータが消える**  
- **本番環境とローカルで構成が微妙に違う**  
- **ポートやボリュームの設定が不明瞭**  
- `.env` の扱いや Nginx / Apache の関係も曖昧

特に困ったのは「**動いていたはずのLaravelが突然エラー**」になること。  
調べると、MySQLコンテナが新規起動されて中身が空っぽ → LaravelがDB接続エラー → 画面真っ白。

---

## ◆ 自分で構成しなおしたこと

以下の観点でDockerまわりを整理し直しました：

### 1. MySQLの永続化（ボリューム設定）

```yaml
volumes:
  - apprentory-db-data:/var/lib/mysql
```

### 2. 環境ごとの `.env` 管理を統一

- `.env` はホスト側に保持し、Laravelに確実に読み込ませるようにマウント  
- `docker-compose.yml` に `env_file` を明記

### 3. Nginx／Apacheを本番で使わず、Laravelコンテナで80番ポートを直接公開

### 4. LaravelのストレージシンボリックリンクをDocker経由でも通す

```bash
php artisan storage:link
```

### 5. ログやDBの永続化を意識し、再起動に耐える構成にした

### 6. Laravel本番用の Dockerfile を自前で設計

もともとベース構成すらわからず相方任せにしていたが、本番運用を見据えて以下の点を盛り込んだDockerfileを自分で用意。

- Laravelで必要なPHP拡張（pdo_mysql, zip, mbstringなど）を明示的にインストール  
- 日本語ロケール設定やタイムゾーン調整（`Asia/Tokyo`）  
- ApacheのDocumentRootを `/public` に書き換えてLaravelを正しく表示  
- composer, nodejs, npm, vim, ping など CLIも充実させて、**コンテナの中でも安心してデバッグできる環境**を構築

```Dockerfile
FROM php:8.2-apache

# 標準ライブラリ系
RUN apt-get update && apt-get install -y \
    git \
    zip unzip \
    libzip-dev \
    libonig-dev \
    libpq-dev \
    libjpeg-dev \
    libpng-dev \
    libfreetype6-dev \
    libxml2-dev \
    libcurl4-openssl-dev \
    curl \
    nano \
    nodejs npm \
    && docker-php-ext-install pdo pdo_mysql zip mbstring exif pcntl

# 日本語ロケール＆タイムゾーン設定＆便利CLI
RUN apt-get update && apt-get install -y \
    locales \
    tzdata \
    vim \
    htop \
    net-tools \
    iputils-ping \
    lsof && \
    sed -i '/ja_JP.UTF-8/s/^# //g' /etc/locale.gen && \
    locale-gen ja_JP.UTF-8 && \
    ln -snf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && echo 'Asia/Tokyo' > /etc/timezone

ENV LANG=ja_JP.UTF-8
ENV LANGUAGE=ja_JP:ja
ENV LC_ALL=ja_JP.UTF-8
ENV TZ=Asia/Tokyo

# Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Apacheドキュメントルート設定
WORKDIR /var/www/html
RUN chown -R www-data:www-data /var/www && a2enmod rewrite
RUN sed -i 's|DocumentRoot /var/www/html|DocumentRoot /var/www/html/public|' /etc/apache2/sites-available/000-default.conf
```

このDockerfileを使うことで、**コンテナ起動時点でLaravelアプリが即起動できる**ようになり、  
「一度動けばOKだった構成」から「再現性とメンテ性の高い構成」に一歩近づけた。

---

## ◆ 学んだこと

- **「怖い」より「わからない」の方が敵だった**  
  → 分解して一つずつ触れば理解できた  
- **最小構成から始めるのが安心**  
  → まず Laravel + MySQL だけ、必要に応じて他追加  
- **開発メンバーが複数いる場合でも、誰でも再構築できる構成が正義**

---

## ◆ 最後に

今ではDockerのエラーも「コンテナ叩いてログ見る」くらいは抵抗なくできるようになりました。  
最初に自分で触る決断ができたのが、今思えば一番のブレイクスルー。

次はこの構成をベースに **CI/CDや監視を自動化していくフェーズ**に入る予定です。
競プロ日記#25/05/05

# 競技プログラミングの鉄則

[A09 - Winter in ALGO Kingdom](https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_i)

- 例題かつ難しめだったので解説読みながらAC。咀嚼はできているはず
```
int main() {
    int H,W,N;
    cin >> H >> W >> N;
    int A[100009], B[100009], C[100009], D[100009];
    int X[1509][1509];
    int Z[1509][1509];

    for (int i = 1; i <= N; i++) {
        cin >> A[i] >> B[i] >> C[i] >> D[i];
    }
    for (int i = 1;i <= N; i++) {
        X[A[i]][B[i]] += 1;
        X[C[i] + 1][B[i]] -= 1;
        X[A[i]][D[i] + 1] -= 1;
        X[C[i] + 1][D[i] + 1] += 1;
    }

    for (int i = 0; i <= H; i++) {
        for (int j = 0; j <= W; j++) {
            Z[i][j] = 0;
        }
    }
    // 横方向
    for (int i = 1; i <= H; i++) {
        for (int j = 1; j <= W; j++) {
            Z[i][j] = Z[i][j - 1] + X[i][j];
        }
    }
    // 縦方向
    for (int j = 1;j <= W;j++){
        for (int i = 1;i <= H;i++){
            Z[i][j] = Z[i - 1][j] + Z[i][j];
        }        
    }

    for (int i = 1; i <= H;i++){
        for (int j = 1; j <= W;j++){
            cout << Z[i][j] << " ";
        }
        cout << endl;
    }  
}
```

# アルゴ式
[正規表現 2-1](https://algo-method.com/tasks/297)
- アルゴ式の教科書には書いていなかったがC++ではバックスラッシュ二つにしないとエスケープを表現できないらしい

```
int main() {
    string S;
    cin >> S;
    if (regex_search(S, regex("1\\+1"))){
        cout << "Yes" << endl;
    } else{
        cout << "No" << endl;
    }
}
```
[正規表現 2-3](https://algo-method.com/tasks/340)
- ハイフンを後ろのユニットに合わせないとハイフンなしの文字列に対応できない「abcd」みたいな
```
int main() {
    string S;
    cin >> S;
    if (regex_search(S, regex("^[a-z]+(-[a-z]+)*$"))){
        cout << "Yes" << endl;
    }else{
        cout << "No" << endl;
    } 
}
```
[Q7. スイッチクエリ (1)](https://algo-method.com/tasks/1725EooC)
- 最初以下の様にSを更新せずにただのAND演算をしてしまってバグり散らかしてた
```
(S | (1 << x));
```
- 修正後
```
int main() {
    int N,S,Q;
    cin >> N >> S >> Q;
    for (int i = 0;i < Q;i++){
        int flag,x;
        cin >> flag >> x;
        if (flag == 0){
            (S = S | (1 << x));
        }
        if (flag == 1){
            if ((S & (1 << x)) == 0){
                cout << "off" << endl;
            }else{
                cout << "on" << endl;
            }
            
        }
    }
}
```


※これまでは可能な限り取り組んだ問題を記載していたのですがＧＷみたいに休日が連なったりすると取り組む問題が多すぎて全部を書いてたらそれだけで時間を使ってしまうので「特筆するものだけ記事に載せる」を徹底します。
スケジュール管理って大事だよって話。[チーム開発]



## はじめに

今回、スマホ向けのスポーツマッチングアプリ「**Yurutto**」をチーム開発で制作しました。

本来は3人チームで取り組む予定だったのですが、事情があり**急遽2人での開発体制に変更**。残された期間も限られていたため、機能の取捨選択やスケジュール調整が非常にシビアでした。

この記事では、Yuruttoの概要と、開発を通じて感じたチーム開発の難しさ・学びについて振り返ってみたいと思います。

---

## アプリの概要

**Yurutto**は、「運動したいけど一緒にやる相手がいない」「気軽にスポーツ仲間を見つけたい」といった人に向けた、**スポーツを通じたマッチングアプリ**です。

ユーザーは、

- 自分のスポーツレベルや興味のある種目
- 活動希望の日時・場所

などを入力し、条件に合う募集に参加したり、自ら募集を立てたりできます。

---

## 実装した主な機能（Must）

リソースが限られる中、アプリの**コア体験を担う最低限の機能に絞って**実装しました。

- ユーザー登録（名前、メール、パスワード、プロフィール）
- 募集投稿（種目、場所、日時、募集人数、補足コメント）
- 募集への応募、参加申請
- 相互承認によるマッチング確定
- 1:1チャット（マッチング後のみ）
- 募集の「温度感」設定（初心者歓迎など）
- 簡易的なプッシュ通知（マッチング確定時）

本当はグループチャットやサークル機能、詳細な絞り込み検索も実装したかったのですが、それらは後回しにしました。

---

## 想定外のトラブルと乗り越え方

正直、一番のトラブルは**人数不足**でした。

当初の3人チームから**突然1人が抜けて2人に**なったことで、単純に作業量が1.5倍に。しかも相方の方に**負担が大きく偏ってしまった**のが申し訳なかったです。

それでも諦めず、以下のように進めることで乗り切りました：

- 実装範囲を思い切って絞る（Must機能に集中）
- UIやアニメーションなど、見た目の部分は最小限に
- チーム内でお互いの強みを活かした役割分担
- GitHubでこまめに進捗を共有し合う

---

## 反省と学び

### 💡 スケジューリングは「余裕」を持たせるのが正義

何かトラブルが起きた時に**バッファがないと一発アウト**。今回はバッファがほぼなかったので、ギリギリまで対応に追われました。スケジュールに**余白**を作る大切さを痛感しました。

### 💡 チーム開発は信頼と感謝で成り立つ

相方がいてくれたからこそ、最低限の完成ラインまで持っていけたのは間違いありません。チーム開発は「作業を分ける」以上に、「信頼して任せる・支える」ことが大事なんだと実感しました。

---

## 最後に

完成度としてはまだまだ課題もありますが、「**限られた状況の中で、なんとか形にする**」という体験は非常に学びが多いものでした。

Yuruttoはこれからもっと改善したいアイデアがたくさんあるので、次フェーズではさらにブラッシュアップしていきたいと思います。

同じように開発をしている人の参考や励みになればいいなあと。

---
SmartRecruiters、2025年版ガートナー®マジック・クアドラントで人材獲得スイートのリーダーに選出

SmartRecruitersは、2025年のガートナー社のタレントアクイジションスイートのマジッククアドラントでリーダーとして認められ、AIを活用した採用ソリューションの提供に対する同社の取り組みが評価されました。同社は採用インフラの近代化におけるAIの重要性を重視し、エンタープライズと大量採用の両方のニーズに対応するプラットフォームを提供しています。SmartRecruitersのプラットフォームの主な機能には、リアルタイムの候補者エンゲージメント、予測的な意思決定サポート、スケーラブルな自動化など、インテリジェントな採用を加速し、ビジネスリーダーと採用担当者を支援するためのAI主導の機能が含まれています。

ガートナー社からの評価は、複雑で動的な人材ニーズを持つ組織を支援するというSmartRecruitersのビジョンを強調するものです。このプラットフォームのAIネイティブエコシステムは、企業が柔軟性、スピード、インテリジェンスを備え、進化する人材環境に対応できるよう構築されています。AmazonやVisaなどの大手ブランドを含む4,000以上の組織から信頼されているSmartRecruitersは、高度な分析とより緊密な統合を通じて、戦略的でデータ主導の採用決定を強化することを目指しています。
<a href="https://bestofai.com/article/smartrecruiters-recognized-as-a-leader-in-the-2025-gartner-magic-quadrant-for-talent-acquisition-suites">Original🙏🏻</a>
2025/5/6主にITとかセキュリティの記事

M&S、Co-op、Harrodsを襲ったランサムウェア攻撃：英国小売業界に広がる脅威の実態と対策(5/4)
https://innovatopia.jp/cyber-security/cyber-security-news/53361/

SNS詐欺の舞台になっているプラットフォームTOP3、3位X、2位YouTube、1位は？(5/4)
https://dime.jp/genre/1964256/

Z世代の72％によるパスワード使い回しも原因、17億件が盗まれ販売中(5/4)
https://forbesjapan.com/articles/detail/78884

愛知県発注工事の請負業者「サンエイ株式会社」、ランサムウェアによりサイバー攻撃で個人情報漏えいの可能性(5/4)
https://rocket-boys.co.jp/security-measures-lab/sanei-ransomware-attack-on-aichi-public-project/

連休前後は罠がいっぱい！ チケット詐欺、ライブ配信で個人情報窃取、マイル未加算メール(5/4)
https://ascii.jp/elem/000/004/267/4267137/?rss

2025年以降本格化する、GIGAスクール端末更新・処分に向けて 児童生徒のデータプライバシー協会に3名の有識者専門委員が就任(5/3)
https://www.excite.co.jp/news/article/Prtimes_2025-05-03-156132-5/

口座乗っ取り被害、証券10社「一定の補償」 楽天は対策義務化(5/3)
https://www.nikkei.com/nkd/company/article/?DisplayType=2&ba=3&ng=DGKKZO88458770S5A500C2EA4000&scode=8604

あなたのサービスは大丈夫？多要素認証のログインでも危険な理由(5/3)
https://zenn.dev/oke331/articles/44e958f7807f55

卒業アルバム漏えい問題　仙台になぜ集中　北海道内の印刷業者、負担大きく　専門家「データの保管、処理まで適切に」(5/4)
https://news.yahoo.co.jp/articles/42f864fabe8d252d276fe13dd4abee153c29bca5

2025年4月17日～4月23日までに報告された WordPress関連の脆弱性情報(5/4)
https://news.mynavi.jp/techplus/article/wordpressvulnerability-3/

アイルランド当局、TikTokに制裁金870億円！中国に個人情報を勝手に送信(5/3)
http://blog.esuteru.com/archives/10366893.html

Go言語マルウェア：Linux環境を破壊する高度なサプライチェーン攻撃が発見(5/4)
https://innovatopia.jp/cyber-security/cyber-security-news/53352/

「マイナ保険証」の解除申請をする人が急増？覚えておきたい利用登録解除の方法(5/4)
https://dime.jp/genre/1948152/

フィッシング3.0? 生成AIを駆使した巧妙すぎる詐欺が襲いかかる(5/4)
https://news.mynavi.jp/techplus/article/20250504-3271068/

米国インフラ支配を進める中国に警戒呼びかけ、深刻さは世界大戦に劣らない(5/4)
https://news.mynavi.jp/techplus/article/20250504-3270805/

ECRにイメージが複数作成されてしまい、Lambdaにデプロイできない問題(5/3)
https://qiita.com/har1101/items/40717ac600559a6cb1bb

Gemini vs ChatGPT：2025年最新比較！互いに取り入れるべき4つの革新機能(5/4)
https://innovatopia.jp/ai/ai-news/53348/

AIアライメントの重要性【後編】あなたはAIに何を教える？(5/4)
https://note.com/naka_68/n/n110762062552

強力なMOAT（勝ち続ける仕組み）を築くネットワーク効果のレイヤーとは(5/4)
https://news.biglobe.ne.jp/economy/0504/dol_250504_4467838285.html

SQLに対する主張(5/4)
https://note.com/kind_crocus236/n/n13e6b0f5b8d9

DeepWikiのDeepWikiを見る(5/3)
https://zenn.dev/churadata/articles/b2274a8868188f

“自分フィギュア”やジブリ風AI画像──つくる前に知っておきたい、ChatGPTとプライバシー(5/4)
https://wired.jp/article/chatgpt-image-generator-action-figure-privacy/

脱「産業スパイ天国」警察当局が経済安保で企業・研究機関との連携に本腰　中露や北念頭に(5/4)
https://www.sankei.com/article/20250504-OBBLFZFCNBK5TMQWSE3J25NCTU/
MCP サーバーとは？


MCP サーバー（Model Context Protocol Server）は、大規模言語モデル（LLM）と外部ツールやデータソースを接続するための標準化された仕組みです。これにより、LLM がリアルタイムで外部情報にアクセスし、実世界のアクションを実行できるようになります。

---

## 🧠 MCP サーバーとは？

MCP（Model Context Protocol）は、LLM が外部のツールやデータソースと連携するためのプロトコルです。MCP サーバーは、このプロトコルに基づいて、LLM と外部リソースとの橋渡しを行います。

### 🧩 MCP の基本コンポーネント

- **Tool**: LLM が実行できる関数や操作（例：ファイルの作成、API の呼び出し）
- **Resource**: LLM が読み取ることができるデータ（例：ファイルの内容、API のレスポンス）
- **Prompt**: 特定のタスクを実行するためのテンプレート

---

## 🔧 MCP サーバーの仕組み

以下は、MCP サーバーの基本的なアーキテクチャを示す Mermaid 記法の図です。

```mermaid
graph TD
    UserInput[ユーザーの入力]
    LLM[大規模言語モデル]
    MCPServer[MCPサーバー]
    ExternalTool[外部ツール/API]
    UserInput --> LLM
    LLM --> MCPServer
    MCPServer --> ExternalTool
    ExternalTool --> MCPServer
    MCPServer --> LLM
    LLM --> UserInput
```

この図では、ユーザーの入力が LLM に渡され、LLM が必要に応じて MCP サーバーを通じて外部ツールや API と連携し、その結果をユーザーに返す流れを示しています。

---

## 💡 実用的なコード例：ファイルへの書き込み

以下は、TypeScript を使用して、MCP サーバーでファイルにテキストを書き込むツールを実装する例です。

```typescript
// writeToFile.ts
import fs from "fs/promises";

export async function writeToFile(params: {
  filename: string;
  content: string;
}) {
  const { filename, content } = params;
  await fs.writeFile(filename, content, "utf-8");
  return {
    status: "success",
    message: `ファイル ${filename} に書き込みました。`,
  };
}
```

この関数は、指定されたファイル名と内容を受け取り、ファイルに書き込む処理を行います。MCP サーバーの Tool として登録することで、LLM からこの機能を呼び出すことが可能になります。

---

## 🔍 類似技術との比較

| 技術名     | 概要                                         | MCP との違い                                        |
| ---------- | -------------------------------------------- | --------------------------------------------------- |
| Plugin API | 特定のアプリケーションに機能を追加する仕組み | MCP は LLM と外部ツールを標準化された方法で接続する |
| Webhook    | イベント駆動で外部サービスと連携する仕組み   | MCP は LLM が能動的に外部ツールを呼び出す           |
| REST API   | リソース指向の API 設計                      | MCP は LLM との連携に特化したプロトコル             |

---

## 📝 まとめ

- MCP サーバーは、LLM と外部ツールやデータソースを接続するための標準化された仕組みです。
- Tool、Resource、Prompt の 3 つのコンポーネントで構成され、LLM の機能を拡張します。
- 実用的なコード例として、ファイルへの書き込みツールを TypeScript で実装しました。
- 他の技術と比較して、MCP は LLM との連携に特化したプロトコルである点が特徴です。

MCP サーバーを活用することで、LLM の可能性をさらに広げることができます。今後の AI アプリケーション開発において、MCP の理解と活用は重要な要素となるでしょう。

---

この記事が、MCP サーバーの理解と活用の一助となれば幸いです。さらに詳しい情報や実装例については、公式ドキュメントやコミュニティリソースを参照してください。

---
【公ド読】Copilot Chat のプロンプトの概要

【公式ドキュメントを読もうシリーズ】Copilot Chat のプロンプトの概要

## シリーズ概要

[https://qiita.com/yasu_programming/items/cec66f9e8d5d571e9ce3](https://qiita.com/yasu_programming/items/cec66f9e8d5d571e9ce3)

## URL

[https://docs.github.com/ja/copilot/using-github-copilot/copilot-chat/getting-started-with-prompts-for-copilot-chat](https://docs.github.com/ja/copilot/using-github-copilot/copilot-chat/getting-started-with-prompts-for-copilot-chat)

## 説明

Copilot Chatでの具体的なプロンプトの方法に関してまとめられている。

ソフトウェアに関する一般的な質問を行う、プロジェクトに関する質問を行う、コードの記述に関しては使えていたが、コードのリファクタリング、テストの記述など工数少なくなるのであれば、どんどん使っていきたい。

GitHub Advanced Security 機能のアラートなどの機能を使用している方は、organization 内リポジトリのセキュリティ アラートについてもCopilotに聞くことができるので、便利になるのかもしれないですね。

## 所感

テストコードの生成や、リファクタリングなどどんどん任せていきたい。
[writeup] picoCTF "Cookies"

# 今回の問題
picoCTFより"Cookies"を解いていきます。

# 実際に解いていく
### 1. 問題文にあるWebサイトに移動する
![Cookies"_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/0aa0ffd7-2b45-4e89-ba67-8e436f4624eb.png)
今回はクッキーの名前を入力する問題のようです。
ソースコードを読みましたが、特に怪しいところはありませんでした。


### 2. 適当な答えを入力してみる
![Cookies"_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/a49d5887-039b-42ef-b8de-451178488a2a.png)
![Cookies"_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/0c6f39dd-92b5-41b3-a5e1-2175fdbad119.png)
不正解を入力すると、画面上に赤色のメッセージが表示されました。
「snickerdoodle」を入力すると、画面上に緑色のメッセージが表示されました。
つまり、**何かが状態を持っている**ということですね。その何かが、今回のWebページの変化を操作していると考えられます。


### 3. Cookieの値を見てみる
![Cookies"_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/b8226057-9204-4bcf-a626-038e121175df.png)
![Cookies"_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/7ee6eda1-0e71-4714-8afe-573009b1fbe1.png)
入力した答えの正解・不正解によってCookieのValueの値が変化していることがわかります。
不正解の場合は、Valueが「-1」。
snickerdoodleの場合は、Valueが「0」。

今回のWebページの変化を操作している何かとは、Cookieのことでした。

それでは、BurpSuiteを使用して、さまざまなCookieのValueを試していきたいと思います。

### 4. BurpSuiteを使用してCookieの値を色々変えてみる
![Cookies"_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/d1af5ffc-9eae-44fc-88a8-755ba2c9e6e1.png)

BurpSuiteを使用して、CookieのValueを1~20まで試してみました。
すると、Valueが18の時だけLengthが極端に小さくなっているのを発見！
そこで、CookieのValueが18のときのレスポンスを見ると...
FLAGを発見しました！これにてFLAG獲得です！お疲れ様でした。

# もう少し考えてみる
今回はCookieの値を変えることでFLAGを獲得することができました。しかし、「そうだっ！Cookieの値を変えてみたらどうだろう？」という発想はどこから浮かぶのか。ChatGPTと個人面談しながら考えてみました。
その結果、以下の要素が挙げられます。

・問題名によるヒント
→今回の問題名は "Cookies" です。明らかですね。

・Cookieがレスポンスで設定されている
→レスポンスにCookieが含まれているかは、Webインスペクタでもすぐに確認することができます。

・Cookieの名前が人間が読めるものになっている
→例：name=0, admin=false など。

・入力に対して反応がないorフォームがない（少ない）
→フォームが少ない、何をしても結果があまり変わらない→となると、何を基準に判断しているのか？→Cookieでは？

・HTMLやJavaScriptにヒントがない
→ソースコードを見てもヒントがない。JavaScriptも特に仕事をしていない→サーバー側に何かあるのではないか？→リクエスト周辺を見てみる→Cookieも対象に含まれる

・ページ遷移やボタンでCookieが変化する
→何かをクリックしたらCookieの値が変化した→値が切り替わるということは、その値に何か意味があるはず

以上です。
思考の過程を言語化することで、少しだけ頭の中にあった「なんで？」というモヤモヤが解消された気がします。

# まとめ
今回の問題は、Cookieの値を改ざんすることでFLAGを獲得することができました。

# 補足
・サーバー側のロジックは見えるのか？
→見ることはできません。なぜなら、サーバー側のコードは「サーバーの中だけに存在」し、ユーザーには送られないからです。
逆に、ユーザーの見ることができるものは、HTML、CSS、JavaScriptやCookie、通信内容（例：リクエスト、レスポンス）などがあります。
ChatGPT への口頭試問（シェルスクリプトからヘルプメッセージを生成）

こんにちは。
シェルスクリプトを基にして、使用方法説明（ヘルプメッセージ）を作るよう ChatGPT へ依頼し、概ね良好な回答を得ました。

#### ChatGPT への質問
文字色を指定する次のシェルスクリプトを基にして、ヘルプメッセージを作ってください。

```sh
#!/bin/sh

text_style_f() {
  ESC=$(printf '\e')
  printf "${ESC}[%dm" "$1"
}

text_color_f() {
  style="$(text_style_f $1)"
  NORMALFACE="$(text_style_f 0)"
  printf "$style%d$NORMALFACE" "$1"
}

for i in $(seq 30 37); do text_color_f "$i "; done; echo
for i in $(seq 90 97); do text_color_f "$i "; done; echo
```


#### ChatGPT からの回答
了解しました！

```
Usage:
  $PROGNAME [options]
Description:
  This script displays ANSI color codes for foreground text colors in the terminal.
  It prints numbers 30–37 (standard foreground colors) and 90–97 (bright foreground colors),
  each rendered in its corresponding color using ANSI escape sequences.
  The output helps users visualize and choose appropriate ANSI color codes
  for customizing terminal prompts, scripts, or UI elements.
Options:
  -h|--help    Print this usage and exit.
```
reactでの入力値のリセットについて

## 入力フォームのリセット 
useStateを使わなくてよい。

```jsx:app
export default function Form() {
  return (
    <div>
      <form>
        <input type="text" name="name" placeholder="名前1を入力してください" />
        <button type="reset">リセットする</button>
      </form>
      <form>
        <input type="text" name="name2" placeholder="名前2を入力してください" />
        <input type="text" name="name3" placeholder="名前3を入力してください" />
        <button type="reset">リセットする</button>
      </form>
    </div>
  );
}

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724581/8c4644f3-12f6-40e1-a2da-ae9024b94034.png)

それぞれのフォームタグごとのリセットボタンで削除される。 
（下側のリセットボタンは名前2と名前3がリセットされる)

useStateに頼りがちなので備忘。
Rails:アソシエーションを利用したレコードの取得が行えない(ActiveRecord::StatementInvalid)

環境
Ruby:3.2.2
Rails:7.1.5

期待していた動作
・ログインしたらタスク一覧を表示してほしい
期待する動作までの処理の概要
・ログイン中のユーザーからアソシエーションを利用してタスクを取得してビューに渡す
```
def index
  @tasks = current_user.tasks.all
end
```


症状
・ActiveRecord::StatementInvalid(SQL実行時のエラー)が出ていた
・tasksテーブルにuser_id:というカラムが存在しないようだ
```
SQLite3::SQLException: no such column: tasks.user_id:
SELECT "tasks".* FROM "tasks" WHERE "tasks"."user_id" = ?
```

・外部キー:user_idが存在するかをdbconsoleで確認したが存在しないようだった
```
sqlite> .schema tasks
CREATE TABLE IF NOT EXISTS "tasks" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" text NOT NULL, "description" text DEFAULT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
```


推察
・ひとまず原因は外部キーのカラムが存在しないから臭い

調査
https://railsguides.jp/active_record_migrations.html#%E5%A4%96%E9%83%A8%E3%82%AD%E3%83%BC
調査結果の要約
・アソシエーションを利用するためにはDBで外部キー制約を持ったカラムが必要。
・add_referenceを利用するだけでは外部キー制約は追加されない。
・foreign_key:trueを追加することで外部キー制約が張られる。
よくない実装
add_reference :tasks, :user
正しい実装
add_reference :tasks, :user, foreign_key: true
​
原因
・tasksテーブルに外部キー制約を持ったuser_idのカラムが存在していなかった。
・(カラム自体が存在しなかったのは謎だがそういうこともあると流しておく)

解決策
```
add_reference :tasks, :user, foreign_key: true
```

```
add_reference :tasks, :user, foreign_key: true
```


うまくいった
```
　CREATE TABLE IF NOT EXISTS "tasks" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" text NOT NULL, "description" text DEFAULT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "user_id" integer DEFAULT NULL, CONSTRAINT "fk_rails_4d2a9e4d7e"
FOREIGN KEY ("user_id")
  REFERENCES "users" ("id")
);
```

foreign_key: trueを指定しないとカラム自体追加できない可能性があるようだ(原因は謎)

抽象化・一般化・重要なポイント
・アソシエーションの利用には外部キー制約を持ったカラムが必要である
・addreferenceだけでなくforeign_key:trueを指定してマイグレーションを行う必要がある
キーワード引数と通常のハッシュ引数を明示的にしろ（Ruby3系）

## 前置き

とある Ruby on Rails のプロダクトを Heroku で動かしていたですが、Heroku の stack を上げないとサーバーが止まってしまうから上げろという警告がデプロイのたびに一年弱表示されていました。
しかし、このプロダクトは Ruby 2.7.6 で、stack のアップデートには Ruby 3系がマストでした…
Ruby のアップデートすら面倒で、この際インフラを Heroku から GCP に移行してしまおう！という話になっておりました。ですが、後回しにしまくっていたら期限が目前に…😱

そこで、取り急ぎ Ruby を 2.7.6 -> 3.1.4 にアップデートすることとしました。

## 環境

- Ruby: 2.7.6
- Ruby on Rails: 6.1.4

## UPDATE Ruby の手順

1. 前提として、Rails のバージョンはそのままにしたい（まず Ruby による影響だけを解消するためひとまず Ruby だけをアップデートする）ので、Rails 6.1.4 で動く Ruby のバージョンを決めます。
Rails の公式ドキュメントなど漁りましたが対応表のようなものが見当たらず、こちらを拝見して少なくとも Ruby 3.1.4 で Rails 6.1.4 は動くことを予想し、 Ruby 3.1.4 へのアップデートを決めました。 
https://mrradiology.hatenablog.jp/entry/2023/09/29/095743

2. gem の更新と bundle install
ruby version 依存により1, 2個ほどエラーが出ていました。デバッグ関連の gem が原因で、しばらく使ってなかったものなので、一旦削除することにして、クリアしました。

3. docker でビルドしてみる。
これで落ちてしまって、少し時間を取られました。多分キャッシュが残っているなどかと思います。`docker compose build --no-cache` , `docker compose up --remove-orphans` とかで治った気がします。

4. CIチェック
これで Pull Request を作ったのですが、CIが落ちていました…
と思ったら、RSpecが大量に落ちていたのです。。！！！！！!
![スクリーンショット 2025-05-06 0.04.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806418/9ea3d546-9fe7-4b3b-a87c-f5df385e3fe1.png)
（次項に続く・・・

## Ruby 2系 -> 3系 の大きな変更
前項4で、テストが大量に落ちていた原因です。

![スクリーンショット 2025-05-06 0.08.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806418/c4061598-71c2-48af-bf64-e5507b2214f2.png)

↑
とのことらしい…！！

✅ つまり、Ruby 3.0 では、キーワード引数と通常のハッシュ引数が厳密に区別されるようになりました。
この変更が原因で、多くのテストや既存のコードが壊れる事例が頻発していました。

### Ruby 2.7 まではどうだったか？
Ruby 2.7 では、以下のような「ハッシュをキーワード引数として渡す」コードも警告を出しつつ許容されていました。

```ruby
def greet(name:, age:)
  puts "Name: #{name}, Age: #{age}"
end

params = { name: "Alice", age: 30 }

greet(**params) # ✅ OK
greet(params)   # ⚠️ 警告（deprecated）だが動く
```
これは Ruby 内部で params がキーワード引数に「暗黙的に変換」されていたからです。

### Ruby 3.0 以降では？
Ruby 3.0 では、この暗黙変換が完全に廃止されたため、上記のような書き方はエラーになります。

```ruby
def greet(name:, age:)
  puts "Name: #{name}, Age: #{age}"
end

params = { name: "Alice", age: 30 }

greet(**params) # ✅ OK
greet(params)   # ❌ エラー
```
このように、キーワード引数として渡したい場合は ** 展開を明示する必要があります。

一方で、メソッド側が通常の引数（位置引数）を期待している場合も以下のようになります。

```ruby
def some_method(params)
  puts params.inspect
end

some_method({ foo: "bar" })   # ✅ OK

some_method(**{ foo: "bar" }) # ❌ ArgumentError: wrong number of arguments (given 0, expected 1)
```

## まとめ

バージョンアップは面倒だし、Ruby も Rails も破壊的なアップデートをされることがあるので、大変…
できるだけ定期的にアップデートするのがいいかもですね、、
ABC404-E を Python で解いた

ABC404 E - Bowls and Beans
https://atcoder.jp/contests/abc404/tasks/abc404_e

コンテスト本番中に解けず、さらに解説を読んでもなお理解できなかったのですが、2日経ってようやく自分なりの解き方がわかりました。

## コンテスト中の自分の動き
D問題までを30分で解き終え、E問題にたっぷりと時間を残すことができました。そして

* なるべく手前の（$i$の小さい）茶碗に豆を運びたい。また、既に豆が入っている茶碗に豆を運んだ方が操作回数が少なく済むはず。
* 手前を優先すべきか、豆の入った茶碗を優先すべきか？
* 豆はなるべくまとめたいので、他の茶碗に入れる際に分ける意味はないはず。

などと考え、制約 N が小さいので DP で解けると予想しました。理解できた今になってから見直すと、ここまでわかっていてなぜ解けなかったのかと疑問に思ってしまいます。

コンテスト中は DP の配列や遷移がうまく作れませんでした。こんなことを考えていました。

* $ dp[i][j] := $ 茶碗 i に豆が j 個入った状態（i+1 以降は全て空）にするのに必要な操作回数の最小値
* $ dp[i] := $ 茶碗 i-1 までが初期値、茶碗 i に残りの豆全部、i+1 以降が空な状態にするまでの操作回数の最小値

豆の個数が 2000 以下になる制約に引っ張られて DP 配列に入れています。まとめて移せばいいので豆の個数は関係ないと気づいてからはそれを外してみたり。豆が入っている or 入っていないの 2 つの状態しかないのなら茶碗と豆の状態を $ 2^N $ で管理……も当然ダメですね。

そんなことを考えながら1時間以上が経過し、諦めました。

## コンテスト後
いろんな解説を読みながら理解しようと考えていたときに「豆を飛び越す意味はない」という旨の記述を目にしました。確かに直感的にはそうなんですが、何故そうなるのか確信が持てませんでした。また、「貪欲で解ける」とも言われていましたが茶碗の遷移の際には $ C_i $ の大きな茶碗を狙って移動した方がいい場面もあるはずで、やっぱり DP ではないか？ということも考えていました。

そんなこんなで一旦は理解を諦めましたがやっぱり頭の中にはこの問題が残っており、翌日歩いているときに豆をまとめた方がいい理由をやっと思いつきました。

## 考察
豆を同じ茶碗にまとめることで一緒に動かせるようになり、手数の節約になります。そして、一度まとめた後は最後まで一緒に動かすことができるので、まとめるならなるべく早い方がいいです。実際、最小の場合で考えてみると以下の画像のように、手数が同じになることはあっても余計に増えることはありません（増えてしまうパターンが思いつかない）。

![ABC404-E解説_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3876620/d7ef35cd-831f-43bd-ab86-538a25b331f8.png)

というわけで、豆のある茶碗から豆のある茶碗へと移動していく方針で考えていくことにします。その上でどう移動するかですが、例えば毎回目一杯 $C_i$ の分だけ進んでいくと余計に手数がかかってしまう場合があります。そこで、ようやく DP の出番です。よくある問題ですね。

![ABC404-E解説_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3876620/2b3b78fd-ab99-441d-81f7-2333014f2297.png)


1つ前の回、 ABC403-D でも部分的に DP を活用する考え方が出てきましたがそれと同じですね。反省点、敗因としては視野が狭かったことがいえます。制約から DP、貪欲では無理だから DP と決めつけてしまっていました。そして、いつもの DP のやり方に当てはめることしか考えていませんでした。貪欲だけでは無理、DPだけでも無理。「部分問題に分割してからの DP」という典型もあるということなのでしょう。ABC403-D のときは思いつけたのに今回は無理だったのは、いかにも DP で解けそうな見た目をしていたからだと思います。僕の場合 ABC403-D は考えていく途中で「ここで DP 使えそうじゃない？」と思いついたのでそこの違いでしょう。


## 実装
まず豆が置かれた茶碗の一覧 $beans$ を用意し、それを順番に辿っていきます。豆が置かれた茶碗 $now$ から次の豆が置かれた茶碗 $next$ までの移動に DP を使いますが、毎回 $ DP[直前の豆が置かれた茶碗] $ の値を利用できるので DP の配列は最初に 1 つ用意すれば十分です。



```python
N = int(input())
C = [-1] + list(map(int, input().split()))
A = [-1] + list(map(int, input().split()))
beans = [0] # 豆が置かれた茶碗のリスト。終点として 0 も加える。
for i, a in enumerate(A):
  if i == 0: continue
  if a == 1:
    beans.append(i)
beans.sort(reverse=True)
INF = 10**20
dp = [INF for _ in range(N)]
dp[beans[0]] = 0
for i in range(len(beans)-1):
  # 茶碗[beans[i]] から 茶碗[beans[i+1]] に移動する。
  now, next = beans[i], beans[i+1]
  for j in range(now, next, -1):
    for k in range(1, C[j]+1): # 1-C[j]まで全ての遷移パターンを調べる
      if j - k > next: # next に到達できない場合は C[j] の分だけめいっぱい移動する
        dp[j - k] = min(dp[j - k], dp[j] + 1)
      else: # next 以下に到達できる場合は next で止まる
        dp[next] = min(dp[next], dp[j] + 1)
print(dp[0])
```
ストレージのパーティション処理の仕組み

このアカウントの投稿ではエンタープライズ向けストレージ製品に関する機能や仕様について触れてきた。
そのため物理ストレージディスクにまつわる題材であれば、複数本数のディスクを束ねたRAID技術を取り上げる回数が多めだった。

今回はより個人向けに寄った題材で投稿を進めていく。
ストレージディスクを複数の領域に分けるパーティション、こちらの仕様について見ていきたい。

## パーティションとは

物理ディスクを仮想的に複数の領域に分割することをパーティションという。データ管理や利用の効率化のために行われる機能である。

複数の領域に分けることで、整理整頓した形で各領域に種類の異なるデータを置くことができる。
一般的な例で言うと、システムファイルとユーザデータを分離させて、それぞれのパーティションに格納して管理をする、というのが良く利用されている手法だ。
またバックアップの効率化にも寄与する。一部のパーティションのみをバックアップさせることで容量と時間を効率的に利用でき、データ保護も期待できる。

## RAID技術との違い

RAIDと比べ、パーティションはデータ冗長性とストレージ性能のパフォーマンスという点で劣る。
そのためストレージディスクの機能を最大限に活かした使い方をするのであればRAIDの採用が推奨される。

ただRAIDはそれなりの数のディスク本数が必要になるが、パーティションは最低1本からの領域分割で済む。分割の再構成さえなければ初期にかかる手間とコストは低くなる。

そしてパーティションはWindowsやLinuxなど、主要なOSでは既に搭載済の機能であるため専用のソフトウェアの準備が不要という側面もある。

## その他の手法

ではパーティションやRAID以外で、物理ストレージディスクから複数の領域を分割する手法を見ていきたい。

Windows環境では複数本の物理的なディスクから論理的な領域を生成するストレージプールがある。ストレージプールそのものは一つの大きなデータ領域の固まりだが、そこから仮想的にスペースを切り分けて、そのスペースを複数個作成して領域の分割ができる。

Linux環境ではLVM(Logical Volume Manager)を使用して物理ディスクから論理ボリュームの生成ができる。容量さえ足りてればボリュームのサイズ変更、そして新規ボリュームの作成ができる。

## ひとりごと

5月の大型連休はおとなしく自宅周辺で過ごしている。
ひょんなことから大掃除することになり、これまでサボって手をつけていなかったところを綺麗にできた。

混雑しているのは行楽地ばかりかと思いきや、近所の飲食店でも行列や待ちが出てきていて、ふらっと外食にも行けない。

仕事から解放されてぼーっとできるだけでも贅沢だなと思うことにする。
【連載まとめ】AWS × データ分析基盤構築 × スマブラ勝率分析


このシリーズでは、スマブラの対戦データを活用して  
**Djangoでのデータ収集、気象データ連携、GlueによるETL自動化、そして勝率・キャラ相性の可視化**までをステップバイステップで解説しています。

---

## 📘 目次

| 回 | タイトル | 内容概要 |
|:--:|:---------|:---------|
| 第1回 | [【導入編】スマブラ勝率を徹底分析！データで読み解くキャラ性能と戦略](https://qiita.com/shota1212/items/ceb1e1ecb3022808e6a5) | 分析全体の構成と目的の紹介。使用技術やデータの概要も解説。 |
| 第2回 | [Djangoでスマブラ対戦結果アプリを作ってみた（データ収集①）](https://qiita.com/shota1212/items/38c381a42faad5413a4d) | Djangoで対戦データを登録・管理できるアプリを作成。 |
| 第3回 | [BeautifulSoupで気象データをスクレイピング（データ収集②）](https://qiita.com/shota1212/items/1eec2380f6e04ea59be4) | PythonとBeautifulSoupで気象庁サイトから天気データを取得。 |
| 第4回 | [bashを使って、S3にデータアップロード（自動化）](https://qiita.com/shota1212/items/7341b3c5f970362a7c89) | bash + AWS CLIでローカルCSVをS3に自動アップロード。 |
| 第5回 | [Glue × PySparkでETLパイプラインを構築（データ加工）](https://qiita.com/shota1212/items/47160952f26f69a1efcb) | Glueジョブで気象・対戦データを結合・整形。 |
| 第6回 | [Step Functions + Lambdaで自動処理化（ワークフロー設計）](https://qiita.com/shota1212/items/6a6fb8f9addf6eb152a0) | Step FunctionsでCrawler・ジョブを順次起動する自動化ワークフロー構築。 |
| 第7回 | [スマブラ勝率・キャラ相性・気温影響を可視化（分析編）](https://qiita.com/shota1212/items/182f121d2865a93e0766) | Tableau Desktopで実際に集めたデータを可視化・分析。 |

---

## 🔧 使用技術・サービス

- Django（データ入力・保存）
- BeautifulSoup（気象データ取得）
- bash / AWS CLI（自動アップロード）
- AWS S3 / Glue / Lambda / Step Functions（分析基盤）
- PySpark / Pandas（データ加工・分析）

---


## ✨ こんな方におすすめ

- ゲーム×データ分析に興味がある方  
- AWSでのデータ基盤構築を実践したい方  
- Glue・Step Functionsの実用例を知りたい方  

---

## 🔜 今後の予定

- 苦手なキャラ対策のYoutube動画を紹介する機能開発
- 上記に伴い、AWS→GCPに移行する
- インフラ構築やテストの自動化など

---

※随時リンク・内容を更新していきます！
【第7回】スマブラ勝率・キャラ相性・気温影響を可視化（分析編）

## 🎮 はじめに

ここまでの記事で、スマブラ対戦データと気象データの収集・加工・自動化を行ってきました。

いよいよ今回は、  
**Tableau Desktop** を使って、実際に集めたデータを**可視化・分析**していきます！

本記事では、以下の3つの観点からデータを読み解いていきます。

- **キャラクターごとに勝率に違いはあるのか？**
- **特定のキャラ同士に有利・不利な相性はあるのか？**
- **気温・時間帯が勝敗に影響することはあるのか？**

---

## 🧰 使用ツール

- Tableau Desktop（データ可視化）
- 加工済みS3データ（smash_data_martから取得）

---

## 📝 分析1：キャラクターごとの勝率分析

まずは、**各キャラクターの総合勝率**を可視化しました。
今回は3体のキャラクターのデータを入れてきました！
### グラフ
![個々のキャラクターのパフォーマンス.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785161/f78b96cf-a6dd-439e-8117-d6a9672c987e.png)


### 気づきポイント

- ソニックの勝率が一番高い(一番使っているキャラになります)
- ドンキーコングの勝率が低いので、もっと練習が必要

---

## 📝 分析2：キャラ相性（Matchup）分析

次に、**キャラ同士の相性**を可視化しました。

### グラフ

![二つのキャラクター間のマッチアップのパフォーマンス.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785161/50269308-999b-406e-b6bc-6534396bf054.png)

### 気づきポイント

- 勝てるキャラと勝てないキャラがそれぞれ見えてきたので、キャラ対策をしたら勝率が上がりそう。
- クッパやドンキーコングなどの重量級のキャラクターの対戦でよく負けている

---

## 📝 分析3：気温・時間帯と勝率の関係分析

最後に、**気温・時間帯**が試合結果にどう影響するかを見ていきます。

### グラフ

![スクリーンショット 2025-04-12 183312.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785161/dcbaac55-fdde-4603-b3dc-1c8d60f56262.png)


### 気づきポイント

- 12～14℃の間が勝率が高い
- 16時頃が勝率が高い。

---

## 🔥 まとめと所感

今回のデータ可視化から、以下のような知見が得られました。

- **キャラごとに明確な勝率差が存在する**
- **キャラ同士の相性によって勝率が大きく変わる**
- **天候や気温がプレイパフォーマンスに一定の影響を与える可能性がある**

これらの知見をもとに、

- 得意なキャラの選択
- 苦手なキャラ対策
- 試合を挑むタイミングの最適化

など、**戦略的なスマブラプレイ**に繋げることができそうです！

---

## 🚀 次回展望

今回の基礎分析をベースに、

- リアルタイムでの天候連動型対策
- 機械学習を使った勝率予測モデル構築
- 苦手なキャラ対策のYoutube動画をおすすめする

など、さらに面白い応用も考えられます！
長くなりましたが、ご覧いただきありがとうございました！

一旦こちらで一区切りとしようと思います。
Oracle DatabaseのBLOBとCLOBのマッピング

Oracle Database環境で、JDBCTemplateのColumnMapRowMapperを利用しています。このとき、BLOBは`byte[]`、CLOBは`String`にそれぞれマッピングされます。

```java
try (Stream<Map<String, Object>> stream = jdbcTemplate.queryForStream(query, new ColumnMapRowMapper())) {
    stream.forEach((row) -> {
        byte[] blob = (byte[]) row.get("blob_col");
        String clob = (String) row.get("clob_col");
    });
}
```

**環境情報**

- Spring boot 3.2.10
- com.oracle.database.jdbc.ojdbc11
毎日write up 1日目 Power Cookie

# 問題
### Description
Can you get the flag?
Additional details will be available after launching your challenge instance.
![スクリーンショット 2025-05-05 23.53.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853234/17f295c7-8743-473a-8280-6b01c145d282.png)

# 解法
普通にクリックすると以下のようになる。
名前と遷移先の文から、クッキーにてゲストかそうでないか判断しているのではとメタ読み
![スクリーンショット 2025-05-05 23.54.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853234/2878a78a-45b0-4a01-b2c2-b80ddd9251dc.png)
Burp suite等のプロキシツールで見てみる
![スクリーンショット 2025-05-05 23.56.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853234/3499ba74-18aa-4438-a343-b3b4748d212a.png)
するとguest.jsなるものがあることがわかる。
```js
function continueAsGuest()
{
  window.location.href = '/check.php';
  document.cookie = "isAdmin=0";
}
```
cookieにisAdmin=0をセットしていることがわかる
check.phpのリクエストを見るとたしかにCookie: isAdmin=0の記述がある。
そのままプロキシツール等でisAdmin=1に書き換えるとflagゲット
EC2にプライベートリポジトリをクローンしてみる

久しぶりのエンジニアブログです。

自作したWebアプリケーションを、現在使っているMacだけでなく、スマホからも手軽に利用したいと考えました。そこで、Amazon EC2インスタンス上でアプリケーションを動かすことにし、そのための設定作業を行いました。
その過程のGit cloneをする方法を知らなかったことがあったので、ブログにします。


## EC2インスタンスの作成し準備を整える

今回はEC2インスタンスの作成方法は省略します。

### アップデートを行う
```
sudo yum update -y
```

今回のアプロケーションはPythonで動いているので、下記を実行し、環境を整える。
```
sudo yum install -y python3 python3-pip git
```
インストールが終了したら自分のGit Hubからクローンしてきます。

## git clone をする
```
git clone <リポジトリのURL>
```
上記をHTTPSで行おうとしたらエラーになるためPTAで行う。そのための準備を下記に示す。
### 起動経路
1. マイページのsettingに移動。

2. 左側から[setting]-[<>Developer setting]

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812002/3605858b-7174-410b-bc40-dc191fdb5166.png)
3. [personal access tokens] - Tokens(classic)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812002/110ec823-924b-4eb3-af5a-9553512a8b1a.png)
4.「Generate new token」>「Generate new token (classic)」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812002/b3ac166b-81a9-404c-b42a-69be2050e992.png)
5. 日にちを設定し、repoをチェック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812002/374c7380-2604-411b-bf1c-cde8bf26094e.png)
6. 下の方にいき作成を押下。

**表示されたトークン (ghp_... から始まる長い文字列) をコピーして、安全な場所に一時的に保管してください。この画面を閉じると二度と表示されないので注意。**

EC2に戻り、`git clone <URL>`を実行。（httpsのURLをコピーし実行）

git hubのユーザー名とパスワードが聞かれるので、パスワードはGitHubのパスワードではなく、コピーしたパーソナルアクセストークン(PAT)を貼り付けてEnter。

無事にgit cloneされます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812002/f9d973ce-2fc4-48bd-93d6-29069b1bd7e6.png)

以上でEC2インスタンスにgit cloneする内容は終了になります。
Databricks AppsからAWSリソースへのアクセス方法

# はじめに
Databricks AppsからAWSリソースにアクセスする際、セキュアな方法で認証情報を管理する必要があります。この記事では、Databricksのシークレット管理機能を使用してAWSアクセスキーを安全に管理し、Databricks AppsからAWSリソースにアクセスする方法について説明します。

# 前段
- [Databricks Secretsによるシークレット管理とDatabricks Appsでの利用方法](https://qiita.com/kei1-dev/items/dd79b483a769daab292f)

# AWSアクセスキーの管理

## 1. シークレットスコープの作成
AWSアクセスキーを管理するための専用のスコープを作成します。

```bash
databricks secrets create-scope aws
```

## 2. AWSアクセスキーの追加
作成したスコープにAWSアクセスキーを追加します。

```bash
# AWSアクセスキーIDの追加
databricks secrets put-secret --json '{
  "scope": "aws",
  "key": "AWS_ACCESS_KEY_ID",
  "string_value": "<access-key>"
}'

# AWSシークレットアクセスキーの追加
databricks secrets put-secret --json '{
  "scope": "aws",
  "key": "AWS_SECRET_ACCESS_KEY",
  "string_value": "<secret-access-key>"
}'
```

## 3. シークレットの確認
追加したシークレットを確認します。

```bash
databricks secrets list-secrets aws
```

# Databricks Appsでの設定

## 1. app.yamlの設定
アプリの設定ファイル（app.yaml）でAWSアクセスキーを参照するように設定します。

```yaml
env:
  - name: 'AWS_ACCESS_KEY_ID'
    valueFrom: 'AWS_ACCESS_KEY_ID'
  - name: 'AWS_SECRET_ACCESS_KEY'
    valueFrom: 'AWS_SECRET_ACCESS_KEY'
```

## 2. Databricks Appsの設定
Databricks Appsの設定画面で、以下の設定を行います：

- scope: aws
- secret key: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
- 権限: 読み取り可能
- リソースキー: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY

![databricksAppsConfig.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/e55703f8-1c09-47cd-9958-73c43fed79df.png)

# アプリケーションでのAWSリソースアクセス

## 1. boto3を使用したAWSリソースへのアクセス
AWSアクセスキーは環境変数として自動的に設定されるため、特別な設定は不要です。

```python
import boto3

# S3クライアントの初期化
s3 = boto3.client('s3')

# S3バケット一覧の取得
response = s3.list_buckets()
print(response)
```

## 2. その他のAWSサービスへのアクセス
同様の方法で、他のAWSサービスにもアクセスできます。

```python
import boto3

# EC2クライアントの初期化
# 自動で環境変数からAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEYを取得し、インスタンス化
ec2 = boto3.client('ec2')

# EC2インスタンス一覧の取得
response = ec2.describe_instances()
print(response)
```

# まとめ

Databricks AppsからAWSリソースにアクセスする際は、以下の点に注意して実装することで、セキュアな運用が可能になります：
1. Databricksのシークレット管理機能を使用して、AWSアクセスキーを安全に管理する。
2. Databricks Appsの設定で、シークレットを参照するように設定する。
3. boto3を使用して、AWSリソースにアクセスする際は、環境変数から自動的に認証情報を取得する。

この方法により、AWSリソースへの安全なアクセスと、アプリケーションのセキュアな運用が実現できます。

# 参考資料
- [Databricks Secrets](https://docs.databricks.com/security/secrets/index.html)
- [Databricks Apps](https://docs.databricks.com/aws/ja/dev-tools/databricks-apps/configuration#databricks-%E3%82%B7%E3%83%BC%E3%82%AF%E3%83%AC%E3%83%83%E3%83%88%E3%82%92%E5%8F%82%E7%85%A7%E3%81%99%E3%82%8B) 
- [AWS boto3 Documentation](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html#configuring-credentials)