OmniAICreator/Qiita-1.07M huggingface dataset:
Javaのエントリーポイントをざっくりまとめてみた[java初心者]

## はじめに
こんにちは。
プログラミング初心者Wakinozaと申します。
Java勉強中調べたことを記事にまとめています。

十分気をつけて執筆するつもりが、なにぶん初心者が書いた記事なので、理解が浅い点などあるかと思います。
記事を参考にされる方は、初心者の記事であることを念頭において、お読みいただけると幸いです。
間違い等あれば、指摘いただけると助かります。

## 対象読者
Javaを勉強中の方。
Java SE Bronze試験を勉強中の方。
mainメソッドの仕様など、Javaの基礎知識を知りたい方。

## 目次
1\. プログラム起動の開始位置
2\. mainメソッドの仕様
3\. コマンドライン引数
4\. JavaSEBronze試験対策の補足情報

## 本文
### 1\. プログラム起動の開始位置
多くのプログラムは複数の関数やメソッドを持っているため、起動するためには、プログラムの開始位置を示す必要があります。
このプログラムの開始位置は、プログラムによって規定されるのではなく、言語仕様によって規定されています。

開始位置のルールは、言語によっても異なり、大きく２種類に分けられます。
- コードの先頭から始まる言語
- 特定の仕様の関数やメソッドから始まる言語

Python・Ruby・PHPが前者で、Javaをはじめ、C・Goなどが後者にあたります。

開始位置となる「特定の仕様の関数やメソッド」のことを「エントリーポイント」とも言われます。

Javaのエントリーポイントは、「main」メソッドです。
mainメソッドは、文字通りプログラムの起点となる重要な部分です。
そのため、厳密に使用が定められています。

### 2\. mainメソッドの仕様
mainメソッドに適用されるルールは主に５つあり、その全てを満たしていないとmainメソッドと見なされません。
ルールは以下の５つです。

- アクセス制限がpublicであること
- インスタンスがいらないstaticであること
- 戻り値はvoidであること
- メソッド名は「main」（全て小文字）であること
- 引数はString配列型を受け取ること
  
この５つのルールを満たした記述が、以下の通りです。
```Java:main.java
public static void main(String[] args){
  //何らかのコード
}
```

このうち「public static void main」の部分は仕様で決まっているため、ほぼ定型文です。

その後の()内はmainメソッドの引数で、「String[]」が引数の型を、「args」が引数の変数名を表します。
ちなみに「args」は、「引数」を意味する英単語argumentsの省略形です。
引数の変数名は、仕様で定められていないため、「args」以外の変数名でも問題ありません。

### 3\. コマンドライン引数
仕様を確認すると、mainメソッドは引数を受け取れるようになっていると言えます。
しかし引数は、通常「呼び出し元のメソッド」が指定するものです。
プログラムで一番最初に起動し、「呼び出し元のメソッド」が存在しないはずのmainメソッドが、なぜ引数を受け取る仕様になっているのでしょう？
それを説明するのが、「コマンドライン引数」です。
（コマンドラインとは、Windowsではコマンドプロンプト、Macではターミナルと呼ばれるあの黒い画面のことです。）

コマンドラインでJavaプログラムを起動するとき、「追加情報」を指定することができます。
この追加情報を「コマンドライン引数」と言います。
プログラム起動時に追加情報があった場合、JVMが追加情報をString配列型に変換し、mainメソッドに引数として渡します。

mainメソッドは、コマンドライン引数を受け取るために、String配列型を引数として受け取る仕様になっているのです。

### 4\. JavaSEBronze試験対策の補足情報
- javaでは、同じシグニチャ（名前と引数のセット）のメソッドを複数記述することができないため、mainメソッドもプログラム内に複数記述することはできません
- mainメソッドの引数は、String配列型以外に、可変長引数のString型にすることも可能です。可変長引数をコンパイルすると最終的に配列型に変換されるため、可変長引数のString型でもmainメソッドのルールを満たせるのです
---------------

記事は以上です。
最後までお読みいただき、ありがとうございました。

##  参考文献
この記事は以下の情報を参考にして執筆しました。

- [徹底攻略 Java SE Bronze 問題集]
- [Javaのmainメソッドとは？処理実行のエントリーポイントとなるmainメソッドについて解説](最終更新日 2024-09-01)(https://www.bold.ne.jp/engineer-club/java-main)(参照 2025-03-30)
- [スッキリわかるJava入門 第４版]
Android Studio でGemini を無効にする

# はじめに
Android Studio内でGeminiが使えるようになりましたが、チャットGPTやGeminiなどのAIを使ったプログラミング・コーディングも便利だと感じますよね。
ですが、プロジェクトによってはGeminiやチャットGPTの使用を禁止して、ソースコードの分析や漏洩を防ぐこともあると思います。
そこで、Geminiを完全に無効にする方法を記事にします。

# 実践

AndroidStudioの設定でPluginsを選択し、Installedeの中にあるGeminiのチェックを外します。


![スクリーンショット 2025-03-30 19.47.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/0990cec3-fe22-4faa-99cf-6982c7ea38cc.png)





# 参考
https://stackoverflow.com/questions/78412736/how-to-protect-my-source-code-from-gemini-in-android-studio/79539769#79539769
GMO payment Gateway - リンクタイプPlus / キー型

前にパラメータ型を書いたが、キー型も実装できたのでメモしていく

キー型はGMOにAPIを投げて、レスポンスとして決済URLをもらう。
同じorderIdでのURL発行は一度きりなのでDB等に保存する必要がある。

```
 const params = {
    "geturlparam": {
      "ShopID": SHOP_ID,
      "ShopPass": SHOP_PASSWORD,
    },
    "configid": CONFIG_ID,
    "transaction": {
      "OrderID": orderId,
      "Amount": amount,
      "Overview": "決済テスト",
      "PayMethods": [
        "credit",
      ],
      "RetUrl": `${RETURN_URL}/return-url`,
      "CompleteUrl": `${RETURN_URL}/complete-url`,
      "CancelUrl": `${RETURN_URL}/cancel-url`,
      credit: {
      //params...
      }
    },
  }

  // console.log(params);

  try {
    const result = await axios.post(`https://pt01.mul-pay.jp/payment/GetLinkplusUrlPayment.json`, {
      ...params
    })

    const {
      // OrderID,
      LinkUrl,
      // ProcessDate,
    } = result.data

    // console.log(result.data);
    return LinkUrl
  } catch (e) {
    console.error(e);
    throw e
  }
}
```

 各決済方法別パラメータ
 https://docs.mul-pay.jp/linkplus/payment/credit/interface
【読書メモ】現場で役立つシステム設計の原則

## まえがき
読みかけ。
本格的にDDD？を導入する気概はないけど、参考になる箇所は多々あるなという印象。
せっかく読むので、参考になった個所をメモに残しておくことにした。
（すでに半分くらい読んでしまったが。。）

## ドメインモデルとは
データとロジックを持つクラス


## ドメインモデルのメリット
・データとロジックを同じクラスに持たせることで、同じロジックをいろんな個所に実装するのを防げる。
・ロジックがどこに書いてあるかわかりやすい。
・ドメインモデル変更時の影響範囲が狭い
・データとロジックを同じクラスに持たせることで、クラス本来の力を最大限に活かせる。（基本的にSpringBootのServiceクラスでは状態を持たないので。。）

## ドメインモデルの開発
関心ごとを小さな単位に分けて、その狭い範囲で必要なデータとロジックを集めることを繰り返す。

クラス名やメソッド名は業務の名前と一致させる。（HowではなくWhatということかな。）

業務を学びながらドメインモデルを成長させていく。開発の初期段階では開発者はドメインモデルを設計するための知識が不足している。（自分のPJに適用するのは難しいが、開発の初期段階では業務知識が不足しており、業務知識がアップグレードされるにしたがってドメインモデルを見直すという視点を持つことは大事だなと感じる。）

## 業務知識を引き出す
業務の専門家の業務知識は言語化されていない。
そのため会話で引き出す必要がある。
会話の中で出てくる「聞きなれない言葉」「使い方に違和感がある言葉」が業務を理解する手掛かりとなる。
業務の専門家と会話し、業務用語を習得することがドメインモデルを設計する活動の基本となる。
「聞きなれない言葉」「使い方に違和感がある言葉」は、聞き逃したり、自分の知っている言葉に変換したりしてしまう。そのため自分がドメインについて理解したことを書き出し、言葉の使い方が適切か専門家に見てもらう。
こういうやりとりをしながら専門家と同じ意味や言い回しで使える言葉を増やしていく。
**業務の経験者にとって自然な言い回しになって、かつ、それが業務の重要な関心ごとなら、業務の専門家の反応が積極的になってくる。**
この段階になれば、よいドメインモデルを設計できる。

## 業務の専門家と話す前に
いきなり業務の専門家と話をしても話が通じず時間の無駄となることが多い。
まずは自分なりに業務の勉強をする必要がある。
・業務の用語に慣れる（マニュアル、書籍など）
・業務について大まかに理解する（書籍、画面、帳票など）

## ⭐この本の応用方法

現実的にどうやって応用するかなと考えた場合、以下のような感じになるかと思う。

domainsというフォルダを用意しておき、

・データを保持するクラス
・データと業務ロジックを保持するクラス
  
を作りたくなった時は、そこに作成する。

こうすることで、DataクラスやDtoクラスを作らなくてよくなるし、業務ロジックの場所が集約される。

ドメインオブジェクトのfromEntityメソッドでDB検索結果をドメインオブジェクトのインスタンスに変換するという感じかな。

Entity、Form、Request、Response、EnumsあたりはDomainとは別でフォルダを作成して、ロジックもそれらに書く。
Domainフォルダはあくまで業務ルールに関するデータ型を格納する。
どれにも当てはまらないデータ型を作りたいときはDto or Dataフォルダを作ってそこに格納かなあ。
[Power BI]カレンダーテーブル作成で使用するCALENDAR関数

### 背景
Power BIでカレンダーテーブルを作成する際、一般的に`CALENDAR`関数を使用します。しかし、**`CALENDAR`関数では手動で日付範囲を指定する必要があり、データ更新時にメンテナンスが必要となるため、手間がかかります**。この問題を解決する方法を見つけたので、投稿しておきます。
※カレンダーテーブル作成手順については、下記参考リンクを参照お願いします。

### 解決策
**`CALENDARAUTO`関数**を使用することで、**日付範囲を手動で指定する必要がなくなります。この関数は、Power BIのモデル内で使用されている日付型の最小日付と最大日付を自動的に検出し、その範囲を基にカレンダーテーブルを作成します**。これにより、日付範囲を手動で設定する手間が省け、データ更新時も自動的に対応できます。

#### CALENDAR、CALENDARAUTO関数の比較

**CALENDAR関数**
- **手動設定**で開始日と終了日を指定します。
- 日付範囲が固定されるため、データの日付範囲が変わったとき、手動で修正する必要があります。
```DAX
日付テーブル = 
VAR StartDate = "2025/01/01"
VAR EndDate = "2025/12/31"
VAR BaseCalendar = CALENDAR(StartDate, EndDate)
RETURN
    ADDCOLUMNS(
        BaseCalendar,
        "年月_yyyyMM",FORMAT([Date],"yyyyMM")
    )
```
**CALENDARAUTO関数**
- **自動的に範囲を決定**するため、開始日と終了日は設定しません。
- モデル内の日付型の最小・最大日付を自動で取得し、それに基づいてカレンダーテーブルが生成されます。
```DAX
日付テーブル = 
VAR BaseCalendar = CALENDARAUTO()
RETURN
    ADDCOLUMNS(
        BaseCalendar,
        "年月_yyyyMM",FORMAT([Date],"yyyyMM")
    )
```
### まとめ
**`CALENDARAUTO`関数を使用することで、手動で日付範囲を設定する必要がなくなり、データの更新や変更に対応するためのメンテナンス作業を大幅に減らすことができます**。カレンダーテーブルを作成する際には、`CALENDARAUTO`関数の使用を検討することをおすすめします。
この記事が皆さんの役に立てば幸いです！
疑問点何かありましたら、コメントいただけると幸いです。
記事をご覧いただきありがとうございます。

### 参考リンク
[カレンダーテーブル作成手順](https://qiita.com/y-komuro/items/de3e2cb3dea129260079)
[CALENDARAUTO関数](https://learn.microsoft.com/ja-jp/dax/calendarauto-function-dax)
正規表現


```ruby:完全一致 は ^ と $ 
    ^(ヘルプデスク$
```

<br>

```ruby:条件複数   "| で区切る + ()で囲む"
^(ヘルプデスク|【未経験歓迎】ITルート営業（SES）|ソリューション営業|SES営業|カスタマーサポート)$
```

<br>

```ruby:部分一致 前株のみ
   "株式会社[\w一-龯々〆〤]" 
```

<br>

```ruby:部分一致 後ろ株のみ
r"|[\w一-龯々〆〤]+株式会社"
```
ローカルのソースコードをGitHubに登録する

## GitHubでリモートリポジトリを作成する
* GitHubにログインし、新しいリポジトリを作成
* リポジトリ名は、ローカルのコードに合わせて適切な名前をつけておく
* リポジトリの初期化は行わず、空のリポジトリを作成
    * 今回変更したのは、リポジトリを非公開に設定した部分のみ
* 一番下にあるCreate repositoryをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/3a357a38-821d-4b39-9802-62ec4c282aac.png)


## ローカルリポジトリの初期化
* ターミナルまたはコマンドプロンプトを起動
* ローカルのコードがあるディレクトリに移動
* ローカルリポジトリを初期化
```shell:
git init
```

## ファイルの追加とコミット
* すべてのファイルをステージングに追加
```shell:
git add .
```
* 変更をコミット
    * "1st commit"のところは任意に設定
```shell:
git commit -m "1st commit"
 ```

## リモートリポジトリの追加
* リモートリポジトリを追加
```shell:
git remote add origin [リモートリポジトリのURL]
```

##  リモートリポジトリへのプッシュ
* ローカルリポジトリの内容をリモートリポジトリにプッシュ
```shell:
git push -u origin main
```
## GitHubで確認
* GitHubのWebサイトで、作成したリポジトリにコードがプッシュされていることを確認

## 注意点
pushする時に、sshの設定をしておく必要がありました
鉄道駅LOD GeoJSONデータをNeo4jに入れる

[鉄道駅LOD GeoJSON ダウンローダー](https://uedayou.net/jrslod-geojson-downloader/)から取得した路線位置情報のJSONデータを、メジャーなグラフDBであるNeo4jに格納するということをやってみた。

## 環境
- Python 3.13.2
- Neo4j Aura
- Neo4j Python driver

## 準備

### Neo4j Aura
Neo4jを使うのが初めてだったので、手軽に使えるAuraのフリーアカウントを利用しました。[Neo4jのサイト](https://neo4j.com/)から「Get Started Free」→ログイン→「Creating your instance」。
自分用のURLやパスワードが書かれたファイルをダウンロードできるので保存しておく。

### Pythonライブラリ
- pip install neo4j

### GeoJSONファイル
鉄道駅LOD GeoJSON ダウンローダーから様々な鉄道会社の様々な路線のデータをダウンロードできるが、ここではとりあえず京急の逗子線のみ対象にします。
京浜急行電鉄京急逗子線.geojson をダウンロードして保存しておく。

## 実装

### グラフの設計
- Pointノード：緯度経度で示される点
  - 経度longitude、緯度latitudeというプロパティを持つ
  - 駅がある地点の場合はstation_nameというプロパティで駅名を保持
- Connectedリレーションシップ：線路で直接つながっているPoint同士

### データ登録用コード
```Python:register.py
from neo4j import GraphDatabase
import json

AURA_CONNECTION_URI="neo4j+s://xxxxxxx.databases.neo4j.io" # 自分用URL
AURA_USERNAME="neo4j"
AURA_PASSWORD="yyyyyyy" # 自分のパスワード

class Driver:
    driver = GraphDatabase.driver(AURA_CONNECTION_URI, auth=(AURA_USERNAME, AURA_PASSWORD))

    @classmethod
    def get_session(cls):
        return cls.driver.session()

# GeoJSONデータをJSONファイルから読み込む
with open('../京浜急行電鉄京急逗子線.geojson', 'r', encoding='utf-8') as f:
    geojson = json.load(f)

# geojsonのデータをNeo4jに登録
with Driver.get_session() as session:
    # 既存のノードを削除
    session.run("MATCH (n) DETACH DELETE n")

    # GeoJSONデータをNeo4jに登録
    for feature in geojson['features']:
        type = feature['geometry']['type']
        name = feature['properties']['name']
        coordinates = feature['geometry']['coordinates']

        if type == 'Point':
            session.run(f"""
                MERGE (p:Point {{longitude: '{coordinates[0]}', latitude: '{coordinates[1]}'}})
                SET p.station_name = '{name}'
            """)
        elif type == 'MultiLineString':
            for line_string in coordinates:
                # 各座標をPointノードとして登録するとともに、座標間をLineノードで結ぶ
                for i in range(len(line_string) - 1):
                    start_coord = line_string[i]
                    end_coord = line_string[i + 1]
                    session.run(f"""
                        MERGE (p1:Point {{longitude: '{start_coord[0]}', latitude: '{start_coord[1]}'}})
                        MERGE (p2:Point {{longitude: '{end_coord[0]}', latitude: '{end_coord[1]}'}})
                        MERGE (p1)-[:Connected]-(p2)
                    """)
```

GeoJSONにはMultiLineStringだけでなくLineStringというtypeのデータも含まれるのだが、MultiLineStringに包含される冗長なデータのようなので使っていない。

## 結果
Auraのコンソールで例えば六浦と神武寺の間のデータを見ると、下記の通り表示される：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2468443/75b5712d-1248-4df1-adc9-48f9e1b9b472.png)

なお、ノード間の位置関係はAuraが適当に描画しているだけで緯度経度に基づいている訳ではないです。

## おわりに

### なぜこんなものを作ったか
呑み鉄メインみたいなゆるーい乗り鉄をやっていこうと思っていて、そのための記録アプリを探していたのだが、どうもしっくりくるものがなかった。なので自分で作ってしまおうかと思っている。この記事の内容は、その実現に向けた最初の一歩という感じ。共感いただける方がいたら、連携できそうなことがあれば教えてください。
正規化の要点整理

# 正規化の要点を理解する

## 正規化の背景
データベース設計において「正規化」は、データの冗長性を排除し、一貫性と整合性を保つための基本的な手法です。正規化が不十分だと、データの重複や矛盾が発生しやすくなります。以下の例を見てみましょう。

### 矛盾の発生例
社員の所属部署と部長を管理するテーブルを考えます。

| 社員名 | 所属部署 | 部長名 |
|--------|----------|--------|
| 田中   | 営業部   | 佐藤   |
| 鈴木   | 営業部   | 佐藤   |
| 佐藤   | 経理部   | 吉田   |

ここで、人事異動により営業部の部長が「中山」に変更されたとします。この際、営業部のレコード全てを「中山」に更新しなければなりませんが、更新漏れが発生すると以下のようになります。

| 社員名 | 所属部署 | 部長名 |
|--------|----------|--------|
| 田中   | 営業部   | 中山   |
| 鈴木   | 営業部   | 佐藤（更新漏れ！） |
| 佐藤   | 経理部   | 吉田   |

このように、部長名の更新漏れが発生するとデータに矛盾が生じます。正規化を適切に行うことで、このような矛盾を設計段階で防ぐことができます。

## 正規化を理解する

### 正規化の目的
正規化の最大の目的は、データの重複を排除し、データベース内の「矛盾」の発生を「設計レベル」で防ぐことです。これにより、データの一貫性が保たれ、メンテナンスが容易になります。

### 正規化によって得られるもの
正規化を正しく行うことで、以下のメリットがあります。
- **データ整合性の向上:** 矛盾が発生しにくくなります。
- **冗長性の削減:** 重複データを排除し、ストレージの効率化。
- **メンテナンスの容易さ:** データの更新や削除が簡単になります。

### 正規化を行わない場合の対応コスト
正規化を行わない場合、以下のような方法で矛盾を防ごうとしますが、いずれもコストがかかります。
1. **実装で対処する:** アプリケーション側でデータの整合性を保つためのロジックを追加する必要があります。
2. **運用でカバーする:** 手動でデータの整合性をチェックし、修正する作業が発生します。
3. **仕様でカバーする:** 矛盾が発生しないようなシステム設計を行う必要があります。

正規化を行うことで、これらのコストを削減し、システムの信頼性を高めることができます。

## 正規化の手順

### 正規化手順の理解に必須の用語
正規化を理解するために、以下の用語を押さえておきましょう。
- **候補キー:** テーブル内の任意のレコードを一意に特定できるカラムの集合。主キーやユニークキーが該当します
- **非キー属性:** 候補キーに含まれないカラム
- **関数従属性:** カラムAの値が決まれば、カラムBの値も一意に決まる関係（A → B）
- **部分関数従属性:** 非キー属性が候補キーの一部に依存している関係
- **推移関数従属性:** 非キー属性が他の非キー属性に依存している関係（X → A, A → B ⇒ X → B）

### 正規化の手順
正規化は、以下の順序で進めていきます。今回は第3正規形（3NF）までを対象とします。

#### 第1正規形（1NF）
**条件:**
- テーブル内の各セルに単一の値のみが存在する
- 各レコードが一意である

**例:**

非正規形：

| 社員名 | 所属部署 | 電話番号 |
|--------|----------|-----------|
| 田中   | 営業部   | 090-1234-5678, 080-9876-5432 |

第1正規形：

| 社員名 | 所属部署 | 電話番号 |
|--------|----------|-----------|
| 田中   | 営業部   | 090-1234-5678 |
| 田中   | 営業部   | 080-9876-5432 |

#### 第2正規形（2NF）
**条件:**
- テーブルが1NFを満たしている
- すべての非キー属性が主キーに対して完全に従属している

**例:**

非正規形（部分依存）：

| 注文ID | 顧客ID | 顧客名 | 注文日 |
|--------|---------|---------|---------|
| 1001   | 1       | 山田    | 2023-01-01 |
| 1002   | 1       | 山田    | 2023-01-02 |

第2正規形：
* 顧客情報を別テーブルに分割

顧客テーブル：

| 顧客ID | 顧客名 |
|--------|---------|
| 1      | 山田    |

注文テーブル：

| 注文ID | 顧客ID | 注文日 |
|--------|---------|---------|
| 1001   | 1       | 2023-01-01 |
| 1002   | 1       | 2023-01-02 |

#### 第3正規形（3NF）
**条件:**
- テーブルが2NFを満たしている
- すべての非キー属性が主キーに対して直接従属している（推移依存がない）

**例:**

非正規形（推移依存）：

| クラス | 担任 | 経験年数 |
|--------|------|----------|
| 2-A    | 田中 | 3        |
| 1-C    | 鈴木 | 11       |

第3正規形：
* 担任情報を別テーブルに分割

クラステーブル：

| クラス | 担任 |
|--------|------|
| 2-A    | 田中 |
| 1-C    | 鈴木 |

担任テーブル：

| 担任 | 経験年数 |
|------|----------|
| 田中 | 3        |
| 鈴木 | 11       |

## まとめ
正規化は、データベース設計においてデータの整合性と効率的な管理を実現するための重要な手法です。以下のポイントを押さえておくことで、基本的な正規化の理解と実践が可能になります。

1. **正規化の目的を理解する:** データの冗長性を排除し、矛盾を防ぐ
2. **各正規形の要点を押さえる:** 第1正規形から第3正規形までの条件とその適用方法を理解する
3. **正規化のメリットを活用する:** データ整合性の向上、冗長性の削減、メンテナンスの容易さを享受する
4. **実務での適用を考える:** 正規化を通じて設計レベルで問題を防ぎ、後々のコストを削減する

正規化を適切に行うことで、堅牢で効率的なデータベース設計が可能となります。初心者の方はまず第3正規形までを目指し、実際のプロジェクトで応用してみましょう。

---

*この記事が正規化の要点を理解する助けとなれば幸いです。質問やフィードバックがあれば、ぜひコメント欄でお知らせください。*
Excel VBA 任意ファイルのシートをコピーする

### はじめに
任意ファイルのシートをコピーします。

### プロシジャーの説明
任意のファイル内の任意のシートを現在のワークブックの任意のシートに丸々コピーし、コピー後にそのファイルを閉じます。

#### サンプル１ 
``` VB
Option Explicit

Sub CopySheetToActiveWorkbook()
'　-------------------------------------------------------------
'　任意のファイル内の任意のシートを現在のワークブックの任意のシートに
'　丸々コピーし、コピー後にそのファイルを閉じる方法を示しています。
'　-------------------------------------------------------------

    Dim SourceWorkbook As Workbook
    Dim TargetWorkbook As Workbook
    Dim SourceSheet As Worksheet
    Dim TargetSheet As Worksheet
    Dim SourceFilePath As String
    Dim SourceSheetName As String
    Dim TargetSheetName As String
    
    ' 任意のファイルのパスとシート名を設定
    SourceFilePath = "C:\Your\Folder\Path\SourceFile.xlsx" ' ソースファイルのフルパス
    SourceSheetName = "Sheet1" ' ソースシート名
    TargetSheetName = "DestinationSheet" ' コピー先のシート名
    
    ' 現在のワークブックを設定
    Set TargetWorkbook = ThisWorkbook
    
    ' ソースファイルを開く
    Set SourceWorkbook = Workbooks.Open(SourceFilePath)
    
    ' ソースシートを設定
    Set SourceSheet = SourceWorkbook.Sheets(SourceSheetName)
    
    ' コピー先のシートを作成
    Set TargetSheet = TargetWorkbook.Sheets.Add
    TargetSheet.Name = TargetSheetName
    
    ' ソースシートの内容をコピー
    SourceSheet.Cells.Copy Destination:=TargetSheet.Cells
    
    ' ソースファイルを閉じる
    SourceWorkbook.Close SaveChanges:=False
    
    MsgBox "シートのコピーが完了しました！"
End Sub

```
Excel VBA 指定した文字列を検索し対象ファイルを開きます

### はじめに
指定した文字列を検索し対象ファイルを開きます

### プロシジャーの説明
B列を検索対象にして、指定した文字列がフルパスに含まれている場合そのExcelファイルを開く

#### サンプル１ 
``` VB
Option Explicit

Sub SearchAndOpenFile()
'　-------------------------------------------------------------
'　B列を検索対象にして、指定した文字列がフルパスに含まれている場合、
'　そのExcelファイルを開く仕組みになっています。
'　-------------------------------------------------------------

    Dim ws As Worksheet
    Dim LastRow As Long
    Dim SearchTerm As String
    Dim i As Long
    Dim FilePath As String
    
    ' 検索対象の文字列を設定
    SearchTerm = "代入"
    
    ' ワークシートを設定
    Set ws = ThisWorkbook.Sheets(1)
    
    ' B列の最終行を取得
    LastRow = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row
    
    ' B列を1行目から最終行まで検索
    For i = 1 To LastRow
        FilePath = ws.Cells(i, "B").Value
        
        ' フルパスに検索対象の文字列が含まれているか確認
        If InStr(FilePath, SearchTerm) > 0 Then
            ' ファイルがExcelファイルかどうか確認
            If Right(FilePath, 5) = ".xlsx" Or Right(FilePath, 4) = ".xls" Then
                ' 対象のファイルを開く
                Workbooks.Open FilePath
                MsgBox "ファイルを開きました: " & FilePath
                Exit Sub ' マクロを終了
            End If
        End If
    Next i
    
    MsgBox "該当するデータはありませんでした。"
End Sub

```
Excel VBA 任意フォルダ内のファイル情報を取得しリストアップする

### はじめに
指定したフォルダ内のファイル情報を取得しリストアップする。

### プロシジャーの説明
サブフォルダも3階層まで調べることができます。このコードは、指定フォルダ内とそのサブフォルダ内のファイル情報（ファイル名、パスなど）をリストアップするものです。

#### サンプル１ 
``` VB
Option Explicit

Sub GetFolderFileInfo()
'　-------------------------------------------------------------
'　指定したフォルダ内のファイル情報を取得し、
'　サブフォルダも3階層まで調べることができます。
'　このコードは、指定フォルダ内とそのサブフォルダ内のファイル情報
'　（ファイル名、パスなど）をリストアップするものです。
'　-------------------------------------------------------------
    Dim FolderPath As String
    Dim ws As Worksheet
    Dim RowIndex As Long
    
    ' フォルダパスを指定
    FolderPath = "C:\ALLlib\エクセルマクロ"
    Set ws = ThisWorkbook.Sheets(1) ' 結果を出力するシート
    RowIndex = 1 ' データの開始行
    
    ' シートのヘッダー
    ws.Cells(RowIndex, 1).Value = "ファイル名"
    ws.Cells(RowIndex, 2).Value = "ファイルパス"
    RowIndex = RowIndex + 1
    
    ' フォルダ内のファイルをリスト化
    Call ListFiles(FolderPath, ws, RowIndex, 1)
    
    MsgBox "完了しました！"
End Sub

Sub ListFiles(ByVal FolderPath As String, ByRef ws As Worksheet, ByRef RowIndex As Long, ByVal Depth As Integer)
    Dim FSO As Object
    Dim Folder As Object
    Dim SubFolder As Object
    Dim File As Object
    
    ' FileSystemObjectを設定
    Set FSO = CreateObject("Scripting.FileSystemObject")
    Set Folder = FSO.GetFolder(FolderPath)
    
    ' フォルダ内のファイルを取得
    For Each File In Folder.Files
        ws.Cells(RowIndex, 1).Value = File.Name
        ws.Cells(RowIndex, 2).Value = File.Path
        RowIndex = RowIndex + 1
    Next File
    
    ' サブフォルダを再帰的に処理 (3階層まで)
    If Depth < 3 Then
        For Each SubFolder In Folder.Subfolders
            Call ListFiles(SubFolder.Path, ws, RowIndex, Depth + 1)
        Next SubFolder
    End If
End Sub

```
個人用備忘録：MVCモデルとは？その基本構造と役割をわかりやすく整理してみた

## はじめに
アプリケーション開発における設計パターンとして広く使われているのが「MVCモデル」です。Model-View-Controllerの頭文字を取ったもので、処理の役割を分離することで、保守性や再利用性の高い設計が可能になります。

本記事では、MVCの各構成要素とその役割を自分用にまとめておきます。

---

## 書こうと思ったきっかけ
Webアプリケーション開発を進めていく中で、「このロジックって本来どこに書くべきなんだっけ？」と迷うことが増えてきました。

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

そこでMVCモデルの基本に立ち返り、構成要素ごとの役割を明確にしておきたいと思い、備忘録としてまとめました。

---

## MVCとは何か？
MVCモデルとは、以下の3つの役割を分けてアプリケーションを設計するパターンです。

| 要素       | 役割の概要                                              | 例え              |
|------------|-----------------------------------------------------------|-------------------|
| Model      | アプリケーションのデータやロジックを管理               | 台所（材料と調理）|
| View       | ユーザーに見せる部分（UI）                               | 食卓（見た目）    |
| Controller | ユーザーの操作を受け取り、ModelとViewをつなぐ仲介役   | ウェイター（操作指示）|

**参考文献**

https://www.geekly.co.jp/column/cat-technology/1911_040/

---

## 各構成要素の詳細

### Model（モデル）
- データ構造、ビジネスロジック、DBとのやり取りなどを担当
- ユーザーに見せることはないが、アプリの中核
- 例：ユーザーの情報を保存・取得する処理

### View（ビュー）
- HTMLやテンプレートファイルに相当
- Modelの情報を元に画面を構成
- 例：ユーザー情報を一覧表示するHTMLページ

### Controller（コントローラー）
- ユーザーの入力を受け取り、Modelを操作
- 処理結果をViewに渡して表示
- 例："新規ユーザー登録"ボタンを押したときの処理

---

## まとめ
MVCモデルは「見える部分（View）」と「ロジック部分（Model）」を分離し、その橋渡しを「Controller」が担う構造です。**これによって、責任の分離が明確になり、コードの再利用性や保守性が大きく向上します。**

今後の開発で、「この処理はModel？View？Controller？」と迷ったときに立ち返るためにも、こうした基本構造を整理しておくことは非常に有効だと思いました！
「AtCoder Beginner Contest 254B - Practical Computing」メモ

これは個人的備忘録です。
## 問題
AtCoder Beginner Contest 254

https://atcoder.jp/contests/abc254/tasks/abc254_b

## 考察
```py
ans = [[0]*i for i in range(1,n+1)]
```
これによってサイズ`i`で初期値が`0`の配列をn+1回重ねて二次元配列をつくることによって回答に使う二次元配列を生成できる。このとき`0`のサイズを`n`にしないように注意する。
```py
for a in ans:
    print(*a)
```
で答えの出力ができる
$ans_{ij}$は$i=0$のとき$j$は存在しないがそれは最初の条件分岐でカバーできる。
## ACコード
```py
n=int(input())

ans = [[0]*i for i in range(1,n+1)]

for i in range(n):
    for j in range(i+1):
        if j == 0 or j == i:
            ans[i][j] = 1
        else:
            ans[i][j] = ans[i-1][j-1] + ans[i-1][j]

for a in ans:
    print(*a)
```
サーバー証明書のデジタル署名とTLSの鍵交換の違いとは？

## はじめに
SSL/TLSの仕組みを勉強していると、「サーバー証明書の公開鍵」と「TLSの共通鍵を交換するための公開鍵」がゴッチャになって混乱することがよくあります。

この記事では、

✅ **サーバー証明書のデジタル署名とは？**  
✅ **サーバー証明書の構造と公開鍵の役割**  
✅ **TLSの鍵交換時に使う公開鍵との違い**  
✅ **なぜ今の主流では「証明書の公開鍵を鍵交換に使わない」のか？**  

を、できるだけ分かりやすく解説します。

---

## 1. サーバー証明書のデジタル署名とは？
サーバー証明書には、認証局 (CA) による**デジタル署名**が含まれています。  
この署名の役割は、「この証明書はCAが発行し、改ざんされていない」ことを証明することです。

### 🔹 署名の仕組み
1. **証明書のハッシュ値を計算** (SHA-256 など)
2. **CAの秘密鍵でハッシュ値を署名**
3. **証明書に署名を埋め込む**
4. **クライアントは、CAの公開鍵で署名を復号して検証**

✅ **ポイント**
- **デジタル署名は証明書のハッシュ値に対して行われる**
- **クライアントは、CAの公開鍵を使って署名を検証する**
- **証明書の公開鍵とは別のもの (CAの鍵ペア)**

---

## 2. サーバー証明書の構造と公開鍵
サーバー証明書は **X.509** 形式で、以下のような情報が含まれています。

| 項目 | 説明 |
|------|------|
| **バージョン** | X.509 のバージョン (通常は v3) |
| **シリアル番号** | 証明書ごとに異なる一意の番号 |
| **署名アルゴリズム** | 署名に使用されたアルゴリズム (例: RSA-SHA256) |
| **発行者 (Issuer)** | 証明書を発行した認証局 (CA) |
| **有効期限 (Validity)** | 証明書の開始日・終了日 |
| **主体 (Subject)** | 証明書の対象 (ドメイン名など) |
| **公開鍵 (Public Key)** | **サーバーの公開鍵** |
| **拡張情報 (Extensions)** | SAN (Subject Alternative Name) などの追加情報 |
| **デジタル署名** | **証明書のハッシュに対する CA の署名** |

✅ **ポイント**
- サーバー証明書には**サーバーの公開鍵**が含まれている。
- **この公開鍵は、TLSでの鍵交換に使う場合と使わない場合がある**。
- **証明書のデジタル署名は、この公開鍵ではなくCAの秘密鍵で行われる**。

---

## 3. TLSの鍵交換と証明書の公開鍵は別物？
TLSの鍵交換時に使う公開鍵は、**鍵交換方式によって異なります**。

| **方式** | **証明書の公開鍵を使う？** | **鍵交換の方法** |
|----------|----------------|----------------|
| **RSA鍵交換** (古い方式) | ✅ 使う | クライアントがTLS共通鍵を証明書の公開鍵で暗号化 |
| **ECDHE鍵交換** (現在主流) | ❌ 使わない | サーバーとクライアントが一時的な鍵を生成・交換 |

---

## 4. TLSの鍵交換方式の違い
### ① RSA鍵交換 (古い方式)
1. クライアントは、TLSの「共通鍵 (セッション鍵)」を**サーバー証明書の公開鍵で暗号化**し、サーバーに送る。
2. サーバーは、**自分の秘密鍵**で復号し、共通鍵を取得する。
3. 以降の通信を共通鍵で暗号化。

✅ **特徴**
- 証明書の公開鍵がそのまま鍵交換に使われる。
- ただし、**Forward Secrecy (前方秘匿性) がない**ため、秘密鍵が漏れると過去の通信が解読されるリスクがある。

---

### ② ECDHE鍵交換 (現在主流)
1. サーバーとクライアントが、それぞれ**一時的な鍵 (Ephemeral Key)** を生成し、交換する。
2. **サーバー証明書の公開鍵は「サーバーの正当性を証明するため」だけに使われ、鍵交換には使わない！**
3. 交換した鍵を使って、共通鍵を生成し、以降の通信を暗号化する。

✅ **特徴**
- **Forward Secrecy (前方秘匿性) あり** → 秘密鍵が漏れても過去の通信は解読されない！
- サーバー証明書の公開鍵は「鍵交換のため」ではなく、「サーバーの正当性の証明」に使われるだけ。

---

## 5. まとめ
- **サーバー証明書の公開鍵 = TLS共通鍵の暗号化に使うとは限らない！**
- **RSA鍵交換では証明書の公開鍵を使うが、ECDHE鍵交換では使わない！**
- **今のTLSは ECDHE が主流なので、証明書の公開鍵は鍵交換には使わないことが多い！**
- **証明書のデジタル署名は、証明書のハッシュに対してCAの秘密鍵で行われる！**
terraform initを行うべきタイミング


## 背景

最近たまたま機会が重なり、ずっとterraformを触ってます。
（3月はterraform集中月間でした）

module追加したり大きな変更をした場合にとりあえず実行していたinit。そろそろちゃんと理解したかったので整理してみました。

## 結論

とりあえず結論から。以下が主要な実行タイミングです。

### ①新規プロジェクト開始時

- Terraformプロジェクトを最初にセットアップする際
- main.tfやversions.tfなどの基本設定ファイルを作成後に実行

### ②プロジェクト構成の変更時
- Backend設定の変更（ex. ローカルからリモートに変更する場合）
- Providerバージョンの更新（ex. AWS Providerのバージョンアップをする場合）
- 新しいModuleの追加や既存Moduleのバージョン変更

## `terraform init`が行っていること

`terraform init`では、主に以下の4つの主要な処理が行われます。

1. **Backendの設定**
  a. Terraformの状態管理（state）の保存場所を設定
  b. `terraform.tfstate`の保存方法を決定
  c. 既存のBackend設定と新しい設定の一貫性を確認
2. **Moduleのインストール**
  a. 定義されたすべてのモジュールをダウンロード
  b. .terraform/modulesディレクトリに保存
  c. モジュール間の依存関係を解決
3. **Providerのインストール**
  a. required_providersブロックで指定されたプロバイダーをインストール
  b. .terraform.providersディレクトリに保存
  c. バージョンの整合性を確認
4. **Lockファイルの生成**
  a. `.terraform.lock.hcl`ファイルを作成
  b. 使用するProviderとModuleのバージョンを固定
  c. チーム開発でのバージョンの一貫性を保証

## 各ステップで生成されるファイルとディレクトリ構造について

`.terraform.lock.hcl`ファイルは一見バージョン管理すべきかどうかわかりにくいですが、使用するProviderとModuleのバージョンを固定するため、含める必要があります。

.terraformに生成されるディレクトリ構造と概要は以下の通りです。

```
.terraform/
├── modules/          # モジュールの保存場所
│   └── ...
├── providers/        # プロバイダーのインストール先
└── terraform.tfstate # Backend設定情報
```



## 参考資料

https://zenn.dev/ishii1648/articles/e3464a668978cb

https://dexall.co.jp/articles/?p=2274

https://rurukblog.com/post/terraform-lock-hcl/
良いコード／悪いコードで学ぶ設計入門 第８章

# 第8章 密結合 ─ 絡まって解きほぐせない構造 ─

ソフトウェア設計において、モジュール間の依存関係の強さは「結合度」として表される。結合が強すぎると、一部を変更するだけで他の部分にまで影響が及び、保守性が著しく低下する。この章では、密結合の問題と、それを解消するための設計手法について学ぶ。

## 8.1 密結合と責務

密結合の典型的な例として、以下のようなクラス構造が挙げられる。

- 一部のクラスに処理が集中している
- 何も処理を持たないクラスが存在する
- 他のクラスの一部のメソッドを無理やり流用している

これは単一責任の原則 (Single Responsibility Principle; SRP) に違反している状態であり、様々な問題を引き起こす。

### 単一責任の原則 (SRP)

SRP とは、「クラスが担う責任は、たったひとつに限定するべき」という原則である。この原則を守らないと、次のような問題が発生する。

- 偶然同じ処理だからと使い回すと、意図しない責任の重複が発生する
- データだけを持ち、処理を持たないクラスは、そもそも責務を果たしていない
- なんでもやるクラスを作ると、コードの重複が増え、変更が困難になる

「Manager クラス」を安易に作らず、一つのことに集中する Value Object を設計することが重要だ。共通化の判断は慎重に行うべきであり、異なる概念を無理に DRY (Don't Repeat Yourself) にしないよう注意する。

実際の開発でも、共通化したつもりが後々異なる概念へと分岐し、結果的に無理な条件分岐を増やしてしまうケースは多い。仕様変更の際には、過去に共通化した部分が本当に正しいのかを再評価し、場合によっては「共通化を解く」ことも視野に入れるべきだ。

## 8.2 密結合の各種事例と対処方法

### 継承による密結合

継承 (is-a 関係) は便利な機能だが、強い依存関係を生み出すため、推奨されない。

- サブクラスはスーパークラスの構造に依存し続ける
- スーパークラスの変更によって、サブクラスの動作が壊れやすい
- 共通ロジックの置き場としてスーパークラスを利用すると、仕様変更の際に不自然な構造になりがち

そのため、継承よりも **コンポジション (has-a 関係)** を優先するべきである。スーパークラスがサブクラスの存在を意識せずに済む設計のほうが、影響範囲を限定できる。

開発の現場でも、継承を使った設計が後に足枷になることは多い。共通ロジックを持たせたいときは、まずは **値オブジェクトやコンポジション** を検討し、それでも難しい場合に継承を考えるようにするべきだろう。

### クラス分割による密結合の解消

一つのクラスが複数の異なる責務を持っている場合、そのクラスは分割すべきである。特に、

- メソッドが互いに無関係なインスタンス変数を使用している
- private メソッドが異常に多い

このような状況では、責務の分離を行い、それぞれの関心事を独立したクラスにするのが望ましい。

現場では、つい private メソッドを増やしてしまいがちだが、それは往々にして「クラスが本来持つべきでない責務を抱え込んでいる」証拠である。Controller クラスなどは特に責務が集中しやすいため、意識的に整理することが重要だ。

### アクセス修飾子の適切な使用

何でも `public` にしてしまうと、影響範囲が広がり、密結合を助長する。Java では `package private` (デフォルトのアクセス修飾子) によってパッケージ内の依存を制御できるが、PHP ではこの仕組みがないため、特に注意が必要だ。

また、public メソッドを増やしすぎると、外部のクラスからの過剰な依存を生みやすくなる。内部で完結すべきロジックは、適切にカプセル化するべきだ。

### 高凝集の誤解と密結合

高凝集を意識するあまり、異なる概念のロジックを一箇所にまとめてしまうことがある。結果として、コードの可読性が低下し、修正が困難になる。

- **概念が異なるものは別のクラスにする**
- **ある概念の値を使って別の概念の値を算出する場合は、適切なコンストラクタを用意する**

このような原則を意識し、適切なクラス設計を心がけることが大切だ。

## 8.3 密結合の具体例

密結合が発生しやすい典型的なケースを紹介する。

- **スマート UI**：UI 層に計算や分岐ロジックが実装されている
- **巨大データクラス**：すべてのユースケースで扱うデータクラスを定義し、結果的にグローバル変数のように扱われる
- **トランザクションスクリプト**：長大なメソッドの中で手続き的な処理がダラダラと続く
- **神クラス**：責務の集約が進みすぎて、あらゆる処理を担う巨大クラスが誕生する

これらを防ぐには、**クラスを適切に分割し、単一責任を守ること** が最も重要である。一般的に、適切に分割されたクラスのサイズは 100~200 行程度になる。

## まとめ

密結合は、ソフトウェアの柔軟性を大きく損なう要因となる。本章で述べたように、**継承を避けてコンポジションを使う、単一責任を守る、適切なクラス分割を行う** ことで、密結合の問題を解消できる。

実務では、つい短期的な実装のしやすさを優先してしまいがちだが、その積み重ねが将来の技術的負債につながる。本章で学んだ原則を意識しながら、日々の設計を見直していくことが重要だ。
LWCクイックアクションのモーダルの横幅を変更する

## はじめに

Salesforceでレコードの詳細画面からカスタムのレコード操作をする際にクイックアクションを作成します。現在、クイックアクションはLWC (Lightning Web Components)で開発するのがナウでヤングでイケイケとされていますが、一つの欠点としてモーダルの横幅が難しいという問題があります。

これを根本的に解決するには、クイックアクションの設定画面かLWCのメタデータあたりから横幅を指定できるようになるのが正着です。が、全然できるようにしてくれないのである程度強引な方法をとります。

## 解決方法

3案くらいあります

### 1. 静的リソースからグローバルにスタイルを読み込み

静的リソースとしてモーダルのclassのスタイルを上書きするcssをアップロードしておき、`loadStyle()`することでモーダルのスタイルを上書きする方法です。
が、この方法は「静的リソースに資材のアップロードが必要」「クイックアクション以外のモーダルに影響を及ぼす可能性がある」という点でちょっと微妙です。

参考: https://www.salesforcebolt.com/2021/08/increase-size-width-of-lightning-web.html

### 2. インラインスタイルを自分の親モーダルに当てる

1.の微妙な点を払拭すべく、今回はこの方法をとります。親モーダルの判定は最近出てきたcssセレクタである`:has()`を使えば簡単に実現できるので、親モーダルをlwcから取得してインラインスタイルを当てます。
自分の親のモーダルのみに影響範囲を留められ、LWCに閉じて外部リソースを必要としない点において1.よりスマートな感じがします。

### 3. ヘッドレスアクションから`lightning-modal`を開く

[`lightning-modal`](https://developer.salesforce.com/docs/component-library/bundle/lightning-modal/documentation)は開くときに横幅を指定することができるので、クイックアクションの種別を画面アクションからヘッドレスアクションに変更して`lightning-modal`として開く方法です。
これはスマートな方法ですが、画面アクションとはナビゲーションの挙動が違う（「戻る」でアクションが閉じるか元画面が戻るか）点は注意する必要があります（History APIから吸収すればいいのかもしれませんｇ）。

## できあがり

クイックアクションのLWCの`connectedCallback()`にて、自分の先祖のモーダルコンテナの`width`を変更します。

```js
export default class QuickAction extends LightningElement {
  connectedCallback() {
    const query = `.slds-modal__container:has(${this.tagName})`;
    document.querySelectorAll(query).forEach(elem => {
      const style = elem.style;
      style.width = '90%';
      style.maxWidth = '90%';
    });
  }
}
```

### 適用前

![適用前.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4047729/308890fb-c4da-480e-ac4f-f86f8f92b3eb.png)

### 適用後

![適用後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4047729/39ec04c1-e01c-4bc3-a3d5-1ca516e10adc.png)

## もう少しアップグレードする

`connectedCallback()`にいちいちこれを書くのはめんどいです。こんな感じの関数としてUtilityとかのモジュールから公開されているとより便利そうです。

```js
const MODAL_WIDTH_STYLES = {
  large: {
    width: '90%',
    maxWidth: '90%'
  },
  small: {
    width: '60%',
    maxWidth: '60%'
  },
  ......
};

export const changeModalWidth = (target, size) => {
  const styles = MODAL_WIDTH_STYLES[size];
  if (!styles) return;

  const query = `.slds-modal__container:has(${target.tagName})`;
  document.querySelectorAll(query).forEach(elem => {
    Object.entries(styles).forEach(([key, value]) => {
      elem.style[key] = value;
    });
  });
};
```

```js
import { changeModalWidth } from 'c/someUtils';

export default class QuickAction extends LightningElement {
  connectedCallback() {
    changeModalWidth(this, 'large');
  }
}
```
【暗号技術整理】共通鍵暗号・公開鍵暗号・鍵交換・RSA・AES・DHの関係を理解する

# はじめに
暗号技術を勉強していると、共通鍵暗号方式、公開鍵暗号方式、鍵交換、RSA、AES、DH、素因数分解の困難性、離散対数問題の解決困難性などが絡み合い、「何が何のために使われるのか？」分からなくなることがあります。
# 1. 共通鍵暗号と公開鍵暗号
暗号技術には大きく分けて共通鍵暗号方式（対称鍵暗号）と公開鍵暗号（非対称暗号）があります。
## 共通鍵暗号方式（対称鍵暗号）
* 送信者と受信者が同じ鍵を使う
* 例：AES
* 特徴：高速だが、鍵の受け渡しが問題になる
## 公開鍵暗号方式（非対称鍵暗号）
* 公開鍵と秘密鍵のペアを使う
* 例：RSA
* 公開鍵で暗号化 → 秘密鍵で復号(逆も可能)
* 鍵交換やデジタル署名に使われる
# 2. 共通鍵の受け渡し方法
共通鍵暗号(AESなど)は速くて便利ですが、「鍵の受け渡し」が課題です。
## RSAを使う方法
* 共通鍵をRSAの公開鍵で暗号化して相手に送る
* 受信者はRSAの秘密鍵で復号して共通鍵を取得
* 例：TLS（HTTPSの仕組み）で使われることがある
## Diffie-Hellman（DH）を使う方法
* 共通鍵を直接送らずに、情報を交換して同じ鍵を生成する
* RSAは不要！
* 例：TLSの鍵交換（ECDHなど）
# 3. DH法と公開鍵暗号の違い
|方法|仕組み|特徴|
|---|---|---|
|RSA方式|共通鍵を公開鍵で暗号化して送る|簡単だが前方秘匿性がない|
|DH方式|お互いの情報を交換して共通鍵を導出|直接鍵を送らないので安全|

# 4. 暗号技術の安全性の根拠
|技術|安全性の基盤|
|---|---|
|RSA|素因数分解の困難性|
|DH|離散対数問題の困難性|

# 5. TLS1.3ではなぜRSA鍵交換が廃止されたのか？
TLS1.3では、RSA鍵交換は廃止され、ECDH（楕円曲線DH）が標準になった。
## その理由
### 1. 前方秘匿性（Forward Security、FS）がない
* RSA鍵交換だと、サーバーの秘密鍵が漏れると過去の通信が全て解読可能になる
* 一方、DH（特にECDH）は各セッションごとに異なる共通鍵を作るので、過去の通信は守られる
### 2. 計算コストが高い
* RSA鍵交換はサーバー側の処理負荷が大きい
* ECDHの方が軽量でセキュア
### 3. 量子コンピュータ対策
* RSA（2048bitなど）は素因数分解の困難性に依存
* 量子コンピュータが発展するとSnorのアルゴリズムで破られる可能性がある
* ECDHの方が比較的影響を受けにくい
# TLS1.3での変更点
* 鍵交換 → ECDH（楕円曲線DH）が標準
* 暗号化 → AES-GCM/Cha-Cha20-poly1305などの共通鍵暗号
* 認証 → サーバー証明書の署名には RSA or ECDSA（楕円曲線署名）
※ RSA鍵交換は廃止されたが、RSA自体は証明書の署名に使われている！
# まとめ
|方式|役割|例|
|---|---|---|
|AES|メッセージの暗号化|TLS通信のデータ暗号化|
|RSA|共通鍵の受け渡し or デジタル署名|TLSハンドシェイク（RSA方式）|
|DH|共通鍵を作る（鍵交換）|TLSハンドシェイク（ECDH方式）|
|素因数分解の困難性|RSAの安全性の基盤|RSA|
|離散対数問題の困難性|DHの安全性の基盤|Diffie-Hellman|
【SQL】ユーザーの作成と削除(CREATE USER / DROP USER)

## ユーザーを作成する

```SQL:Oracleの場合
CREATE USER [ユーザー名] IDENTIFIED BY [パスワード];
```

```SQL:PostgreSQLの場合
CREATE USER [ユーザー名] WITH PASSWORD [パスワード];
```

```SQL:SQL Serverの場合【SQL Serverログインの作成】
CREATE LOGIN [ログイン名 / Windowsのログイン名];
```

```SQL:SQL Serverの場合【データベースユーザーの作成と紐付け】
CREATE USER [ユーザー名] FOR LOGIN [SQL Serverログイン];
```

```SQL:MySQLの場合
GRANT [権限] ON [データベース名].[テーブル名]
    TO [ユーザー名] @ [ホスト名] IDENTIFIED BY [パスワード];
```

## ユーザーを削除する

```SQL:
DROP USER [ユーザー名];
```


## おわりに
ここまで読んでいただきありがとうございます！

## 参考文献
・図解 SQL これからはじめる基本の知識 (知りたい！テクノロジー) 単行本（ソフトカバー） – 2010/12/11
島田 裕二 (著)
p.68-69
RDSエンジンバージョンアップ時のルート証明書期限切れエラーの対処法について

## はじめに
RDSのエンジンバージョンアップ作業を進める際、ルート証明書の期限切れエラーの影響で少しつまづいてしまったことがありました。
同じ状況でお困りの方に、本記事が少しでもお役に立てれば幸いです。

## 問題点
RDSのエンジンバージョンを8.0.34から8.0.41にバージョンアップをしようとしたところ
「 Certificate not found: rds-ca-2019」のエラーが発生し
バージョンアップすることができませんでした

![【エラー画像】スクリーンショット 2025-03-18 233947.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3677761/de143584-e741-46b6-a1bb-7132d9094221.png)

## 前提
・現在設定されているルート証明書は「rds-ca-2019」※期限切れの状態
・RDSのエンジンバージョンは8.0.34
・作業の目的は「8.0.34」のエンジンバージョンを「8.0.41」にバージョンアップすること

## 原因
はじめにも記載していますが、原因は、ルート証明書を更新していなかったことにありました。
SSL/TLSを使用していなかったためルート証明書の更新を行っていませんでしたが、その影響で今回のバージョンアップ時に想定外の手間が発生してしまいました。
※落ち着いてエラー画面を見ると、RDSのバージョンアップなだけなはずなのに、証明書も一緒に更新されているのがわかります。

また8.0.41のバージョンに対応している証明書を確認しました。

```php:AWSCLI
aws rds describe-db-engine-versions --engine mysql --engine-version 8.0.41
～内容抜粋～
SUPPORTEDCACERTIFICATEIDENTIFIERS       rds-ca-ecc384-g1
SUPPORTEDCACERTIFICATEIDENTIFIERS       rds-ca-rsa4096-g1
SUPPORTEDCACERTIFICATEIDENTIFIERS       rds-ca-rsa2048-g1
```

上記の出力からもエンジンバージョン「8.0.41」に「rds-ca-2019」のルート証明書は対応していない事がわかります。

## 解決方法
まずはルート証明書を更新して、その後バージョンアップを行う必要があることが分かりました。
そのため、以下の手順で作業を実施しました。
①ルート証明書を更新※今回は「rds-ca-rsa2048-g1」に変更します。
②エンジンバージョンアップ


以下が証明書の簡単な更新手順です。
　　　1.AWS Management Console にサインインし、RDSを選択
　　　2.対象のRDSを選択し、「変更」を押下※DB エンジンバージョンは変更しない
　　　3.証明期間でデフォルト「rds-ca-rsa2048-g1」が選択されていることを確認
　　　4.「続行」を押下
　　　5.「すぐに適用」を選択し変更を押下
　　　6.「接続とセキュリティ」タブの証明機関が「rds-ca-rsa2048-g1」となっていることを確認
   
※なお今回更新した「rds-ca-rsa2048-g1」は「40年間」有効なルート証明書になります。

https://aws.amazon.com/jp/blogs/news/rotate-your-ssl-tls-certificates-now-amazon-rds-and-amazon-aurora-expire-in-2024/#:~:text=40%20%E5%B9%B4%E9%96%93%E6%9C%89%E5%8A%B9%E3%81%AA%E8%A8%BC%E6%98%8E,%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%BE%E3%81%99%E3%80%82

ルート証明書を更新した後、RDSエンジンバージョンのバージョンアップ(8.0.34→8.0.41)作業を実施。

　　　7.対象のRDSを選択し「変更」を押下
　　　8.DB エンジンバージョンで「8.0.41」を選択
　　　9.「続行」を押下
　　　10.「すぐに適用」を選択し変更を押下
　　　11.RDSのステータスが「アップグレード」になることを確認
　　　12.ステータスが「利用可能」となることを確認
　　　13.「設定」タブのエンジンバージョンが「8.0.41」となっていることを確認

これで無事本来の目的のRDSのバージョンアップ作業を行うことができました。

## まとめ
今回の作業で手間取ってしまったのは、RDSのバージョンアップ作業と証明書の更新作業について、十分に内容を理解していなかったことが根本的な原因でした。
SSL/TLS通信を行っていなかったため、ルート証明書の更新が不要だと誤認していましたが、バージョンアップ時に予期しない手間が発生してしまいました。
この経験を通じて、証明書管理は期限内に更新するよう心がけ、同じような手間がかからないようにしていきたいと思います。

## 参考URL

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL-certificate-rotation.html

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html#UsingWithRDS.SSL.RegionCertificateAuthorities

https://repost.aws/ja/questions/QUhWPx72h6ROq-KWbsaG1fbg/2024-%E5%B9%B4-8-%E6%9C%88-22-%E6%97%A5%E3%81%BE%E3%81%A7%E3%81%AB-amazon-rds-%E3%81%A8-amazon-aurora-ssl-tls-%E8%A8%BC%E6%98%8E%E6%9B%B8%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%97%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84-%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6
【SQL】データベースの作成と削除(CREATE DATABASE / DROP DATABASE)

## 名前を指定してデータベースを作成する

```SQL:名前を指定してデータベースを作成する
CREATE DATABASE [データベース名];
```

・データベース名を最初に付ける必要がある。
・原則として後から変えることは出来ない。

そのほかのデータベース作成時に指定出来る主な項目
・キャラクタセット
・データのパス
・最大ファイルサイズ
・表領域自動拡張の有無

## データベースを削除する

```SQL:データベースを削除する
DROP DATABASE [データベース名];
```
（Oracleの場合、データベース名の指定は不要）

データベースを削除すると、テーブルやデータも削除される。




## おわりに
ここまで読んでいただきありがとうございます！

## 参考文献
・図解 SQL これからはじめる基本の知識 (知りたい！テクノロジー) 単行本（ソフトカバー） – 2010/12/11
島田 裕二 (著)
p.66-67
【Python】初心者が仮引数と実引数で迷子になったけど解決した話

## わからなかったこと
仮引数・実引数の各役割と関係性
(仮引数`name`と、関数を呼び出す際の引数`player_name`がなぜ一致するのか)

### 仮引数と実引数とは？
- 仮引数とは
	関数を定義するときに使う変数の名前のこと
	実際に関数を呼び出すときに受け取る「器」のような役割
- 実引数とは
	実際に関数を呼び出すときに渡す値のこと

### それらの関係性は？
- 仮引数は実引数を受け入れることができる変数 (器のようなもの)
- 実引数は、関数の実行時に渡すことのできる変数もしくは値
つまり、用意された箱本体と箱の中身みたいなイメージ

### コードで確認
```python
def print_hand(hand, name='ゲスト'):  # name が仮引数
    print(name + 'は' + hand + 'を出しました')

player_name = input('名前を入力してください：')

if player_name == '':
    print_hand('グー') 
    # 実引数を1つだけ渡す ↓ 
    # 仮引数 name にはデフォルト値の 'ゲスト' が入る
else:
    print_hand('グー', player_name) 
    # 実引数を2つ渡す ↓
    # 仮引数 name には 実引数 player_name の値が入る
```

#### 解説
**~nameとplayer_nameが一致する理由~**
1. 関数を定義するとき（仮引数） `def print_hand(hand, name='ゲスト'):`
ここでの `name` は仮引数で、デフォルト引数値として `'ゲスト'` が設定されている。
2. 関数を呼び出すとき（実引数） `print_hand('グー', player_name)`
このとき、`player_name` の値が 上記1.の`name` に代入される。

🔽上のPythonコードを日本語で書いてみるとこんな感じ！🔽
```python
# そもそもname は仮引数である
if 引数が指定されている:
	呼び出された関数内で参照される
else:
	呼び出された関数内で参照できる引数がないため仮引数の初期値が参照される
	ただし初期値がない場合はコードを実行できない
```
#### 実際のコードの流れ
1. ユーザーが名前を入力する
2. 名前が入力されない（空文字）の場合：
実引数がないため、name='ゲスト' が使われる
3. 名前が入力された場合：
player_name が実引数として使われ、name に代入される

## まとめ  〜今回わからなかったことの解決のポイント〜
- そもそもname = player_nameという定義付けが行われたわけではない
nameとplayer_nameは、ある関数の中での仮引数と実引数という関係性である
- 関数を呼び出すときに実引数を渡すと、その値が仮引数に代入される
- 実引数を渡さない場合、デフォルト引数値があるときはそれが参照される
ただし、デフォルト引数値がないときはエラーになり、コードが実行されない

:::note
キーワード：デフォルト引数値、仮引数、実引数
:::

## 参照
> [4. その他の制御フローツール — Python 3.13.2 ドキュメント](https://docs.python.org/ja/3.13/tutorial/controlflow.html#default-argument-values)
Azure Logic Apps で、Trigger/Action のバグがあった時は自分で対処出来るのね

# 背景

RSS の Trigger で上手く動かない事象があった。

で、
- Contribute Chance :laughing: 

と思ったけど、Power Automate とは違って、編集出来たので、それはそれとして対処法として記録

https://github.com/Azure/logicapps

## RSS Trigger での問題詳細

- あれ？RSS発行されてるので、なんも処理できない、なんで？
- Triggerがきてない
- Triggerがerrorになっとる
- URLが怪しい
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1645569/05d76d3d-1d58-4fdf-821b-1badde96d05a.png)
- RSS URL は単純にテキスト貼り付けるだけだよな？ :thinking: 
- Code View でみてみるか・・
    - URL Encode が二回かかってる :baby: 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1645569/042794f8-1d50-4aab-b575-72342f523d2d.png)

# 修正方法

単純に、Designer の上にあるメニューから、Code View で編集可能でした。

:::note
Trigger/Action のとこの Code View は閲覧だけなので、勘違いしやすい・・ :(
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1645569/e1d9b215-b5c8-40f1-ab1e-ff36daace240.png)

で、無事、削除したものが動きましたとさ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1645569/d1820ecb-7e7c-49e2-8242-11ebcc921586.png)


# あとがき

あとは、Contribute をやってみるかなぁと思ったけど、どうやら、issue あげるだけかな？
devcontainer でコンテナの名称を指定する

# Motivation

devcontainer を docker compose で起動するとコンテナ名称が docker compose の name 属性と一致して何のコンテナかわかりやすい。他方で `devcontainer.json` 単独での devcontainer を作成して起動するとコンテナ名称がランダムでわかりにくいと思っていた。

# Solution

`devcontainer.json` で `runArgs` プロパティを以下のように使うことでコンテナ名称を指定できる。

```json
{
    "runArgs": ["--name", "your container name"],
}
```
Proxmox ver8.3でOVA/OVFから仮想マシンを作成しよう

Proxmox ver 8.3からGUI上でOVA/OVFから仮想マシンを作成できるようになりました。
今まではCLIから qm importovf でVMを作成する必要がありました。
まあ、今までとやっていること自体は同じなのですが、GUI上から操作できるようになったよというだけです、、、

## 手順1
データセンター > ストレージ からOVA/OVFファイルをインポート及び展開する作業用のディレクトリを選択し、内容に「インポート」と「ディスクイメージ」を含めます。
デフォルトのストレージ設定の場合はどちらも「local」になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3768522/e9afe441-43ae-41ce-a8ca-55930f9e658c.png)

## 手順2
先ほど設定変更したディレクトリ（今回は"local"）> インポート からOVA/OVFファイルをアップロードします。
アップロードしたファイルは一覧に表示されます。
自分の環境だとciscoのACIシミュレータが表示されていますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3768522/c8db4732-eebf-4fc1-8413-380116ef92a4.png)

## 手順3
アップロードしたファイルを選択するとポップアップが表示されます。
「デフォルトストレージ」はVMのストレージで、「作業用ストレージのインポート」はインポート作業で使用するストレージです。
詳細設定からディスク、ネットワークインターフェースの設定が可能です。VM作成後に編集することもできます。
設定に問題がなければ「インポート」を押下してインポートを開始します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3768522/1e038a40-696f-46b2-b40d-1a75fdb6d911.png)

「インポート」を押下するとログが流れます。「TASK OK」が表示されればインポート完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3768522/c3bcce3d-b6a0-48b6-8881-205121e43e15.png)
ソースコードレビューについて

## 概要

ソースコードレビューは開発プロセスにおいて欠かせない重要な工程です。本記事では、コードレビューの基本概念から実践的なテクニックまで、体系的にまとめています。

## 1. ソースコードレビューとは

ソースコードレビューとは、開発チームのメンバーが他者のコードを客観的に確認する作業です。新規コードや既存コードの変更を対象とし、潜在的な問題を早期に発見して修正することを目的としています。

主な目的は:
- バグやエラー、セキュリティ脆弱性の発見
- コードの可読性・保守性の向上
- チーム内での知識共有の促進
- コーディング規約やベストプラクティスの遵守確認

## 2. なぜソースコードレビューが重要なのか

- **品質向上**: 潜在的な欠陥や脆弱性、パフォーマンス問題の早期発見
- **バグの早期発見と防止**: 開発後期のバグ修正コスト削減
- **知識共有とスキル向上**: チームメンバー間の技術共有と学習
- **保守性と可読性の向上**: 将来的なコード変更や理解を容易に
- **セキュリティの強化**: 潜在的な脆弱性の早期発見と対策
- **コミュニケーション促進**: チーム内の理解深化と協力体制強化
- **技術的負債の削減**: 持続可能なコードベースの維持

## 3. ソースコードレビューのメリット

- **バグの検出**: コーディング担当者が気づかなかった問題の発見
- **コードの最適化**: より効率的で洗練された実装方法の提案
- **知識共有**: チーム全体の技術理解度向上
- **スキルアップ**: レビューする側・される側双方の成長
- **コミュニケーション促進**: チーム内の相互理解深化
- **技術的負債の削減**: 長期的な保守コスト削減
- **ドキュメント改善**: コードの理解を助ける説明の促進
- **一貫性の向上**: コーディング規約の統一的な適用
- **セキュリティリスクの低減**: 脆弱性の事前防止
- **より良い設計の実現**: 堅牢で柔軟なアーキテクチャの推進

## 4. ソースコードレビューの重要な観点

- **可読性**: 変数名・関数名の適切さ、コードフォーマット、コメント
- **保守性**: モジュール化、設計パターン、アーキテクチャ原則の遵守
- **安全性**: セキュリティ脆弱性、機密データ処理の適切さ
- **パフォーマンス**: 効率性、アルゴリズム選択、ボトルネック
- **機能性**: 仕様要件の充足、論理エラー、エッジケース対応
- **テスト**: 適切なテストカバレッジ、テストコードの保守性

## 5. 効果的なソースコードレビューのベストプラクティス

### コード作成者向け

- 明確で簡潔なコードを書く
- レビュー前に十分なテストを行う
- 変更内容を明確に記述する
- プルリクエストを小さく保つ
- フィードバックに迅速かつ丁寧に対応する
- コードフォーマッターや静的解析ツールを活用する
- レビュー前に自身のコードを再確認する

### レビュー担当者向け

- タイムリーなフィードバックを提供する
- コードではなく、作成者に焦点を当てる
- 建設的で具体的なコメントをする
- 提案の根拠を説明する
- 良いコードには肯定的なフィードバックを与える
- レビュー時間を制限する
- チェックリストを活用する
- 理解できない点は質問する
- 自身のバイアスを意識する
- コード作成者の努力を認める

### チーム・組織向け

- 明確なコーディング規約とレビューガイドラインを定める
- 建設的なフィードバックと学習の文化を育む
- 効果的なレビューのためのトレーニングを提供する
- コードレビューツールを活用する
- レビューの効果を測定する指標を追跡する

## まとめ

ソースコードレビューは単なるバグ発見の手段ではなく、チームの知識共有、スキル向上、コミュニケーション促進など多くの価値をもたらします。効果的なレビューを行うには、適切な種類のレビューを選択し、重要な観点から評価し、ベストプラクティスを実践することが重要です。

レビューを批判の場ではなく、共に成長するための建設的な機会と捉え、チーム全体で取り組むことで、コードの品質向上だけでなく、開発者の成長とチームの連携強化にもつながります。
【発売前レビュー】Difyで作る生成AIアプリ完全入門

# 大人気のローコード開発ツールの書籍が今週刊行！

生成AIを仕事で使っている方なら、昨年一度は「Dify」というツールの名前を聞いたことがあるのでは？

2024年に大ブームを巻き起こし、今も多くのユーザーに使われているDifyの入門書が今週4/4に出版されます。

![IMG_4395.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/b5d92f97-98d9-43c6-b282-d452edd70457.jpeg)

ありがたいことに著者のお一人である吉田真吾さんより、発売前に本書をご恵贈いただきましたので、レビューをみなさんに共有します！

https://www.amazon.co.jp/dp/4296071106


# そもそもDifyって何？

生成AIを組み込んだアプリケーションを、プログラミングなしで開発できるツールです。
2024年の春に登場した「ワークフロー」という機能が大ヒットし、今でも多くのアプリケーション開発現場で利用されています。

https://qiita.com/minorun365/items/4c5dba1de7977c386249

本書を執筆されているお二人は、Generative Agents社というAIエージェントに特化したビジネスを展開されているスタートアップ所属の[吉田真吾さん](https://x.com/yoshidashingo)と[清水れみお](https://x.com/lemilemilemio)さんです。

生成AI界隈は、雨後の筍のように多くの方が商業書籍を出版されており、どれを手に取るべきか読者の判断が試されます。そういう意味で、日頃から定評のある技術発信をされており、技術者コミュニティからも信頼されているお二人の著作ということで、安心して購入できる書籍といえます。


# この本の良いところ

そもそもDifyがローコードの開発ツールのため、プログラミングやアプリケーション開発に慣れていない方でも理解しやすいよう、平易で分かりやすく書かれているのが特徴です。

フルカラーで図解とスクリーンショットがたっぷりで、開発初心者でもストレスなくサクサク読むことができます。
技術書というより「業務効率化ツールを解説するビジネス書」に近いテイストなので、非エンジニアの同僚にも勧めやすいですね。

![IMG_4396.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/3525404b-da80-44d8-aa8a-0c10fe9e5334.jpeg)


また、生成AIアプリケーションを開発する際に課題となりやすいのが「そもそもユースケースが見つからない」ことではないでしょうか？

本書の大部分は、実際の仕事への当てはめ方を例にしながら、Difyでアプリケーションを開発する手順が解説されています。「領収書の処理」「稟議レビュー」「議事録の作成」など、多くの人が自分の仕事でそのまま使えそうなユースケースを紹介してくれているのが嬉しいです。


# 実際に試してみた

私は普段、コードを書いてLLMアプリを開発しているため、Difyをしばらく触っていませんでした。

本書を読んで、Slackと接続できる機能が最近追加されていたことを知ったので、第7章を参考にして「URLを渡すと内容をサマリーしてくれるSlackボット」を作ってみました。

![スクリーンショット 2025-03-30 17.24.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/d8cb4810-86a3-42b9-97a0-cc41e3277187.png)

一億年ぶりにDifyを触りましたが、直感的なUXがすごく良いですね。

ユーザーから与えられたURLをFirecrawlというSaaSでスクレイピングして、内容を要約してくれるワークフローを作りました。LLMにはAmazon BedrockのClaudeを使ったのですが、プラグインが用意されておりAWSアカウントとの連携も簡単でした。

![スクリーンショット 2025-03-30 17.05.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/bdf0bfd1-799b-4d23-82b8-6fea07a7aa16.png)

実際にSlackから利用すると、必ずハルシネーションが発生するバグに遭遇しました。デバッグのために監視ツールのLangfuseを使ったのですが、これもDifyで簡単に連携できるようになっており驚きました。

トレースを確認したところ、ユーザーから渡されたURLに `@メンション名` や `< 不要なカッコ >` などの余計な文字列が混じるせいでFirecrawlがスクレイプに失敗していたことが分かりました。
そこで、URL抽出用の軽量LLM（Amazon Nova Pro）を挟み、Few-shotプロンプティングでURLだけを抽出するようにしました。

![スクリーン ショット 2025-03-31 に 16.08.32 午後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/b6d46b3a-b781-4dad-a5a4-fa1932266319.png)


Slackアプリの開発って、Slackの管理画面上で必要になる細かい権限設定などが初心者にはかなりとっつきづらいのですが、本書に細かい手順が掲載されていたため、記載どおりに進めるとスムーズにアプリを完成させることができました。


# いよいよ今週末に発売！

生成AIが流行っていますが、自社でのAI推進や事業企画を任されているのに、ほとんど実機に触れずにパワポばかり睨めっこしている方、周りにも多いのではないでしょうか？

Difyを使えば非エンジニアのビジネスマンでも簡単にアプリを作って業務に使えます。今のうちに予約して、職場の同僚や新人さんたちに配って布教してあげましょう。

https://bookplus.nikkei.com/atcl/catalog/25/03/21/01919/
#電子メール #迷惑メール対策 #Thunderbird # 気づいたものを見かけなかったので公開

**本内容を利用した場合の一切の責任を私は負いません。**

# 本題
大抵の人がフィルタをかけてると思う。
大抵のメーラーができると思うが、Thunderbirdは任意ヘッダにフィルタをかけれる。
自分の場合、中国、詐欺拠点のあった東南アジアからが多い。
でも、当然送信元アドレスは簡単に回避されちゃうし、経路もバラバラ。
で、気づいたのは時差。
Dateヘッダで「+0800」や「+0700」のフィルタをかける。

# 補足
Receivedヘッダ等と違ってDateヘッダはメールシステムではなくクライアントが付ける。
このため、クライアントの設定を変えれば簡単に回避されちゃう。
ただ、現時点ではかなり効果があったため。
GeminiとReactで簡単なAI質問アプリを作る

# GeminiとReactで簡単なAI質問アプリを作る
質問に対してAIが回答してくれるアプリを作ります。

## Gemini API Keyの用意
googleのアカウントを所有していることが前提になるので、アカウントがなければ作って下さい。
このサイトを参考に、APIキーを取得します
https://monomonotech.jp/kurage/memo/m240725_get_gemini_api_key.html

## ライブラリのインストール
GeminiのAPI キーを取り扱うためのライブラリをReactプロジェクトにインストールします。
"@google/generative-ai"というライブライを使います。
https://www.npmjs.com/package/@google/generative-ai

インストールは、下記のコマンドで実行します。
```
npm install @google/generative-ai
```

## 完成コード
以下が完成したコードです。
APIキーは外部に漏れないよう、env環境変数で取り扱うことを強く推奨します。

```typescript:App.ts
import React, { useEffect, useState } from 'react'; // useEffectとuseStateを追加
import logo from './logo.svg';
import './App.css';

function App() {
  const [resultText, setResultText] = useState(""); // 結果を格納するstate
  const[question,setQuestion] = useState<string|undefined>();

  //モデルをイニシャライズ
  const { GoogleGenerativeAI } = require("@google/generative-ai");
  const genAI = new GoogleGenerativeAI(process.env.REACT_APP_API_KEY); // 環境変数からAPIキーを取得
  const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash" });


  const generateResponse = async ({prompt}:{prompt:string|undefined}) => {
    
    try {
      const result = await model.generateContent(prompt);
      const response = await result.response;
      const answer = response.text();
      setResultText(answer); // 結果をstateに設定
    } catch (error) {
      console.error("エラーが発生しました:", error);
      setResultText("エラーが発生しました。");
    }
  };

  return (
    <div className="App">
      <header className='header'>
        Gemini + React 質問アプリ
      </header>
      <main className="App-header">

        <div>
          <p>
            {resultText ? resultText : "Geminiからの応答を待っています..."}
          </p>

          <textarea 
            name="question" 
            onChange={(e:any) => setQuestion(e.target.value)}
          >
          </textarea>     

          <button onClick={() => generateResponse({prompt:question})}>
            質問
          </button>   

        </div>

      </main>
    </div>
  );
}

export default App;
```

簡単ではありますが、以上です。
応用すれば、色々作れそうですね。
sudoでasdfをインストールしてハマった話（権限エラー）

## 経緯

asdfをインストールする際、うっかり `sudo` を使ってしまいました。  
.bashrcにPATHを通した後、その場では特にエラーもなく進んだのですが、後々プラグイン追加時に以下のようなエラーが出て気づきました。

## エラーメッセージ

```bash
$ sudo asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git
sudo: asdf: command not found

$ asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git
mkdir: cannot create directory ‘/home/ユーザ名/.asdf/plugins’: Permission denied
fatal: could not create leading directories of '/home/ユーザ名/.asdf/plugins/nodejs': Permission denied
```

## 原因

sudoでasdfをインストールしたため、.asdfディレクトリ以下の所有者が root になっていました。asdfは一般ユーザの環境でコントロールすべきツールなので、本来 sudo は不要です。

## ちなみに…

```bash
$sudo asdf
$asdf
```
が両方とも機能したのは、間違って作った.asdf/のパーミッションが`-rwxr-xr-x`でその他グループにも`x`があるからでした。

ただプラグインとなると、rootが所有者なので一般ユーザでは書き込み(ディレクトリ作成）できず失敗。
またsudoコマンドは効かないのは、PATHを通した.bashrcは一般ユーザで通したから。

## 解決方法

所有グループ, 所有者を自分のユーザに変更してあげればOK
```bash
$sudo chgrp -R $(whoami) ../.asdf
$sudo chown -R $(whoami) ../.asdf
```

## 感想
* 作業は丁寧に。開発環境のセットアップ時は、つい sudo で強引に進めてしまいがちですが、後々のトラブルの元になるので要注意でした（自戒）