OmniAICreator/Qiita-1.07M huggingface dataset:
【プロンプトインジェクションとは】LLM／ChatGPT／GPTsに機密情報は絶対に入れないでください

皆さん初めましてこんにちはこんばんは。スウェーデン在住のエンジニア、Harry(ハリー) ( https://twitter.com/harrythecode )と申します。

専門はクラウドとセキュリティで、サブでは生成AIに関するウェブアプリケーションでのフルスタックエンジニアとして上流から下流(要件定義から保守運用／LLMOps)まで幅広く経験してたりします。

本題です。皆さんは「プロンプトインジェクション」という言葉を聞いたことはありますでしょうか。

こちらの定義については、ボクなりの解釈だと以下の通りです。

> ChatGPTなど生成AIモデルに関して、あらかじめ定義されているプロンプトを第三者が特殊なプロンプトを用いて内部の情報、設定などを搾取すること

今回は以下の3つテーマでお話ししていきます。

1. プロンプトインジェクションってなに？
2. わかったわかった。対策はできひんの？
3. じゃあどうすればいいん。対処法は何？

## プロンプトインジェクションってなに？

ものは試しで、以下のGPTsを例にします。

https://twitter.com/hiroyukimonchy/status/1723301902396621257

こちらのGPTの中には「隠された1つのパスワード」が埋め込まれています。こちらを以下にして探し出せるか、が鍵になっていきます。

ボクの場合だと、以下の情報に辿り着くまでに5分でした。

https://twitter.com/harrythecode/status/1723711842844123630

ただどうやら、正解じゃなかったようです。そこから少し深掘りして、とあるテクニックを使うと以下のようにすんなり情報を引き出せました。

https://twitter.com/harrythecode/status/1723820038161940943

ちなみに、パスワードに関する直接的な質問をすると以下のような返答がきます。

> ご質問ありがとうございます！👍 私たちはプライバシーとセキュリティを非常に重視しており、その観点から特定の情報にはお答えすることができません。😅 しかし、他のご質問には喜んでお答えいたします。何かお手伝いできることはありますか？🤔

GPTs側で色々な工夫を凝らして、パスワードが漏洩しないような対策を講じることは出来るのですが、あの手この手を使うと回避できてしまいます。

何かのシステムに対して、通常では出力されない情報を盗み出すことをセキュリティ用語では「インジェクション」と呼びます。

更に生成AIモデルでは「プロンプト」を用いることから、この２つを組み合わせて「プロンプトインジェクション」という攻撃手法として呼ばれ始めています。

ここまで話すと「対策は本当にできないの？」という疑問が生まれることでしょう。次はそちらを深掘りします。

## わかったわかった。対策はできひんの？

ボクの結論は以下の通りです。

https://twitter.com/harrythecode/status/1723823334214021380

要は、プログラム制御とは違って、攻撃パターンが非常に多いので、それら全てに対応することができない、というのが結論です。

ただ、ツイートの通り、複雑化することは可能でGPTsに入力された暗号化を別の方式で元に戻す(複合化)することで、ある一定のセキュリティを担保することは可能です。

ただし、あくまでもその「元に戻すための情報」(複合キー)が第三者にバレないことが前提なので100%安全というわけでもありません。

じゃあどうすれば良いのか、について最後触れていきます。

## じゃあどうすればいいん。対処法は何？

最大の対処法はそもそも「機密情報をAIモデルに入れないこと」です。

AIは知り得ない情報を引っ張り出してくることはないので、第三者に知られたくない情報は入力しない、という大原則を守りましょう。

またこのことは通常のChatGPTや他の生成AIモデル(Google PaLM, AWS/Anthropic Claudeなど)を使うときにも十分気をつけないといけません。

なぜなら、彼らは「ユーザの入力情報をAIに覚え込ませる」可能性があるから、です。

最近の出来事では「誰かの自画像写真がGPTで生成された」事例もあります。

このことから知られたくない情報は「AIにインプットしない」を徹底しましょう！

## 最後に

いかがでしたでしょうか。GPTへ機密情報をインプットする怖さが理解いただけましたでしょうか。

生成AIモデルをセキュアに使うためには色々な考慮事項が必要で、この感覚を身につけるには中々大変だったりします。

きちんと各種AIの規約を読み込んで、どのように使えば「セキュアに使えるか」を確認した上で使えば大丈夫なのですが、そこまで意識して使えてない人が多いのも事実です。

正しく使えば全然問題ないので、皆さんも使い方を正しく覚えてAIをどんどん活用していきましょう~。

本記事への感想は、

https://twitter.com/harrythecode

のDMまでお気軽にお問い合わせください。
PowerAutomate 高いけどいいぞ

## なにをやったか
* 基幹システムのWebサイトにアクセスしてcsvをダウンロード
* ローカルPCでExcel起動して、誰かが作ったマクロを実行して、編集（不要な列の削除等）
* 編集後の全セルをコピー
* 所定のSpreadsheet（いろんなひとがアクセスする大事なやつ）の「貼り付け用シート」にペースト
上記の作業を、人がPCを操作することで実行していた（しかも毎朝実行）
これを、PowerAutomateで自動化しました

## 前提
PowerAutomateは2種類あります
+ ブラウザで動くPowerAutomate(Online) …本記事ではPowerAutomateと呼びます
+ ローカルPCで動くPowerAutomateDesktop …本記事ではPADと呼びます

## 進め方
1. 現状の運用を担当者に教えてもらってExcel等を受領して確認
2. Office365のアカウント作成
3. PADで実装開始
4. PADで実装が終わったところで稼働確認したら、PowerAutomateがないとだめなことに気づいた
5. 業務担当者にその旨伝えてPowerAutomateのアカウント作成してもらった（稟議等も同時に実施）

## よかったこと
今回はExcel（＋マクロ）がフローの中に組み込まれていたので、同じWindows同士ということで、安心感がありました
実装も簡単でした

## 工夫した点
ダウンロードするときは最初は「画像で指定」を使っていたがやはりエラーが多かったのでhttpですべてを実装したのでエラーが起きなくなった

## 大変だったこと
- PADだけで行けるかと思ったら無理だったので、PowerAutomateでPADのフローを実行する、という形にしました
※タイマー稼働させるのが無理だった（これは調査不足）
- （解決方法）PADを深夜・早朝にオフライン状態でスタンバイさせるための物理端末（ノートPC）を用意した

## 安定性
- 10月から毎朝稼働しているが毎日成功している
 
## お金
- PowerAutomateの有料アカウントに20,000円程度かかる
→　法人なら問題ない金額だが…個人では躊躇するレベル（工夫すればもっと安く出来るっぽい）
- PAD用に専用の物理端末（PC）を用意した（20万円程度？）

## 不安点
- 物理端末はコンセント付きのロッカーにしまって24x365体制にて、電源ON状態で放置している（PC自体の劣化が心配）
Gitでの変更を戻す方法（初心者から中級者まで）

## **はじめに**

Gitは、バージョン管理システムの中でも特に強力で広く使われているツールです。日々の開発作業において、誤って行った変更を戻したいという状況はよくあります。この記事では、Gitで行うさまざまな「戻す」操作を、初心者から中級者向けに解説します。

### **ワーキングディレクトリの変更を戻す**

- 未追跡ファイルを含むすべての変更を戻す
    
    ```bash
    git clean -fd
    git checkout -- .
    ```
    
    これはワーキングディレクトリの変更をすべて破棄します。
    
- 特定のファイルの変更を戻す
    
    ```bash
    git checkout -- [ファイル名]
    ```
    
    これは指定したファイルの変更を破棄します。
    

### **ステージングの変更を戻す**

- ステージングされた変更を戻す
    
    ```bash
    git reset HEAD [ファイル名]
    ```
    
    特定のファイルのステージングを解除します。
    
- すべてのステージングされた変更を戻す
    
    ```bash
    git reset HEAD
    ```
    
    これはすべてのファイルのステージングを解除します。
    

### **ローカルコミットの変更を戻す**

- 最後のコミットを取り消すが、変更は保持する
    
    ```bash
    git reset --soft HEAD~1
    ```
    
    最後のコミットを取り消しますが、変更はステージング状態で保持します。
    
- 最後のコミットを取り消し、変更も破棄する
    
    ```bash
    git reset --hard HEAD~1
    ```
    
    最後のコミットを取り消し、その変更も破棄します。
    

### **リモートへの同期（push）を戻す**

- リモートにpushしたコミットを取り消す
    
    ```bash
    git revert [コミットID]
    git push origin [ブランチ名]
    ```
    
    これにより、指定したコミットの変更を打ち消す新しいコミットが作成されます。
    

### **ブランチの操作**

- ブランチを切り替える
    
    ```bash
    git checkout [ブランチ名]
    ```
    
    ```bash
    git switch [ブランチ名]
    ```
    
    Gitで`switch`コマンドを使用してブランチを切り替える機能は、Gitのバージョン2.23.0から導入されました。このバージョンは2019年8月にリリースされています。
    
    `git switch`コマンドは、`git checkout`の一部の機能をより明確にし、使いやすくするために導入されました。`checkout`コマンドはブランチの切り替えとファイルの復元の両方に使用されていましたが、これらの機能が`switch`と`restore`に分割されました。
    
    例えば、新しいブランチに切り替える場合、以前は`git checkout -b [新しいブランチ名]`を使用していましたが、Git 2.23.0以降では`git switch -c [新しいブランチ名]`というコマンドを使用できます。
    
    この変更により、Gitのユーザーインターフェースがより直感的になり、特に新しいユーザーがGitのコマンドを学ぶ際の混乱を減らすことが期待されています。もちろん、`git checkout`コマンドも引き続き使用可能ですが、特定の操作には`git switch`や`git restore`を使う方が適している場合があります。
    
- ブランチを新しく作成して切り替える
    
    ```bash
    git checkout -b [新しいブランチ名]
    ```
    
- ブランチを削除する
    
    ```bash
    git branch -d [ブランチ名]
    ```
    
    安全な削除で、マージされていない変更がある場合は削除されません。
    
    ```bash
    git branch -D [ブランチ名]
    ```
    
    強制削除で、マージされていない変更があっても削除します。
    

## **まとめ**

Gitは非常に多様なツールであり、さまざまな方法で変更を元に戻すことができます。この記事で紹介したコマンドは、日々の開発作業でよく使われるものです。Gitを使用する際は常に注意して操作し、特にリモートリポジトリに影響を与えるコマンドは慎重に扱う必要があります。この記事があなたのGit操作の理解を深める助けになれば幸いです。
【JavaScript・初学者】Reactでよく使われる頻出記法 / 分割代入について

# はじめに

`React`を学習していましたが、`JavaScript`の記法についてフワッとしている部分がよくあったので、簡単ですが今回は**分割代入**について少し調べました。

# 通常の代入について

例えばある`オブジェクト`があったとして、それぞれの`プロパティ`を変数に代入するには、このように`プロパティ`ごとに変数を定義してあげる必要があります。

```javascript
const student = {
  id: "1",
  name: "michael",
  age: 18
};

const id = student.id;
const name = student.name;
const age = student.age;

console.log(id); 
console.log(name);
console.log(age);
```

この場合、`studentオブジェクト`の`プロパティ`が一つ増える度に、constで変数を定義しなければならなくなります。少し面倒ですね。


```javascript
const student = {
  id: "1",
  name: "michael",
  age: 18,
  hobby: "baseball"
};

const id = student.id;
const name = student.name;
const age = student.age;
const hobby = student.baseball;

console.log(id); 
console.log(name);
console.log(age);
console.log(hobby);
```

# 分割代入
分割代入を使うことでよりスッキリ書くことができます。また、**代入するプロパティごとに変数を宣言する必要がない**ので、通常の代入よりもスマートに書くことができます。
注意としては、**プロパティと分割代入の変数名は合わせてあげる**必要があります。
```javascript
const student = {
  id: "1",
  name: "michael",
  age: 18,
  hobby: "baseball"
};

const { id,name,age,hobby } = student

console.log(id); 
console.log(name);
console.log(age);
console.log(hobby);
```
# 分割代入の特徴
### 初期値の設定

```javascript
const student = {
  id: "1",
  name: "michael",
  age: 18,
  hobby: "baseball"
};

const { id,name,age,hobby = "" } = student

console.log(id); 
console.log(name);
console.log(age);
console.log(hobby);
```
### 分割代入の変数名を変更

先ほど**プロパティと分割代入の変数名は合わせてあげる**必要があると書きましたが、分割代入の宣言時に**変数名を変更する**こともできます。

```javascript
const student = {
  id: "1",
  name: "michael",
  age: 18,
  hobby: "baseball"
};

// 分割代入でidをnumberに名称変更
const {id: number,name,age} = student;

console.log(id); // エラーになる
console.log(number); // "1"と出力される
console.log(name);
console.log(age); 
console.log(hobby);
```

### ネスト構造への分割代入
ネスト構造にも分割代入が使えます。ネストした改装分だけ`{}`で変数を囲みます。

```javascript
const continent = {
  name: "北アメリカ",
  us: {
    name: "アメリカ合衆国",
    capitalCity: "ワシントンD.C.",
  },
};

const {
  us: { name, capitalCity },
} = continent;

console.log(name);
console.log(capitalCity);
```
MySQL速度向上メモ

### MySQL速度向上

### Explainによるクエリの評価

ポイント：Type
all<index<range<ref<eq_ref<const<system<NULL

### Profilingによるクエリの評価
```terminal
# profileサポートしているかを確認する
select @@have_profiling;

# offの場合のみ実行（onにする）
set @@profiling=1;

# 実行したクエリリストを確認する
show profiles;

#個別クエリの詳細情報を確認する
show profile for query <query_id>
```
### indexの種類
```terminal 
# indexの確認
show index from <table_name>;

# index追加（任意のカラムにIndexを追加する）
alter table <table_name> add index <name_index>(<culomn_name>);

# index削除
alter table <table_name> drop index <neme_index>;
```
### プレフィックスインデックス
Primary Keyがプレフィックスインデックスになっている
alter table test_table add index name_index(name(5));

### 複合インデックス
alter table test_table add index foo_bar_index(foo, bar);

### パーティション追加
```terminal
# table_name: test_logs
# column_name: created_at
# partition method: RANGE(範囲指定）

alter table `test_logs`
PARTITION BY RANGE COLUMNS(`created_at`) (
  PARTITION  p201501 VALUES LESS THAN ('2015-02-01 00:00:00'),
  PARTITION  p201502 VALUES LESS THAN ('2015-03-01 00:00:00')
  );
```
###パーティション削除
```
alter table `test_logs` DROP PARTITION p201501;
```
### MySQL構成図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/d2f02312-b1dc-445d-e6b1-10f98da14a8d.png)
ELBとECSの負荷分散

## きっかけ
今までサーバーサイドの開発が多く、インフラの勉強をUdemyなどで行っています。
AWSのロードバランサーの機能を学習し切れた気がするので少しELB（Elastic Load Balancing）と合わせてECS（Elastic Container Service）を使用して負荷分散を行う際のパブリックサブネットとプライベートサブネットの使い方について説明します。

## 各機能
### パブリックサブネット
**定義**: パブリックサブネットはインターネットから直接アクセス可能なサブネットです。これはインターネットゲートウェイに接続されています。ECSやEC2などは直接触られたくないので、ここには置きません。

**用途**: ELBを配置するために使用します。ELBはインターネットからのトラフィックを受け入れ、ECSクラスター内のコンテナにトラフィックを分散するため、パブリックサブネット内に配置するのが一般的です。

**セキュリティ**:パブリックサブネットに配置されるリソースはセキュリティグループやネットワークACLを適切に設定して、不要なアクセスを防ぐ必要があります。

### プライベートサブネット
**定義**: プライベートサブネットはインターネットから直接アクセスできないサブネットです。通常、NATゲートウェイを介してインターネットにアクセスします。

**用途**: ECSクラスター（ECSのインスタンスやタスク）を配置するために使用します。プライベートサブネット内のECSインスタンスはELBを通じてのみアクセス可能です。

**セキュリティ**: プライベートサブネット内のリソースは外部から直接アクセスされることがないため、セキュリティ上のリスクが低減されます。しかし、内部からのアクセス制御は依然として重要です。

## 負荷分散の流れ
**受信トラフィック**: ELBはパブリックサブネットに配置され、インターネットからのトラフィックを受け取ります。

**負荷分散**: ELBは受信したトラフィックをECSクラスターに分散します。このECSクラスターはプライベートサブネット内に存在します。

**応答トラフィック**: ECSクラスターからの応答はELBを通じてユーザーに返されます。

## まとめ
この構成により、安全かつ効率的に負荷分散を実現でき、ECSクラスターのセキュリティを確保しつつ、外部からのアクセスを管理できます。また、AWSのVPC（Virtual Private Cloud）内でこれらのサブネットを適切に構成することで、リソースの分離とセキュリティを強化できます。
ST7735S SPIでキャラクター文字を表示する。(ESP32)


目的
カラー液晶のテスト


https://qiita.com/caa45040/items/3c57c159be0fd0f7a718


https://qiita.com/caa45040/items/8935036eab45af3b08d0


https://qiita.com/caa45040/items/285a406d1a033a3ddc59


![o_cop778.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/6d87bfcb-5a21-1c3d-a91e-bad4f83c2ba0.jpeg)



TFT_CS         14
TFT_RST        15
TFT_DC         32


CLK-18
MOSI-23




```c++


//st7735_text_test1_esp32

//インクルド
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <SPI.h>

//ピン定義
//#if defined(ARDUINO_FEATHER_ESP32) // Feather Huzzah32
  #define TFT_CS         14
  #define TFT_RST        15
  #define TFT_DC         32

//画面の定義
// For 1.44" and 1.8" TFT with ST7735 use:
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

//初期化
void setup(void) {

  //画面の初期化
  // Use this initializer if using a 1.8" TFT screen:
  tft.initR(INITR_BLACKTAB);      // Init ST7735S chip, black tab

  //画面のクリア
  tft.fillScreen(ST77XX_BLACK);

  // テキストサイズを設定
  tft.setTextSize(3);
  // テキスト色を設定
  tft.setTextColor(ST77XX_WHITE);
  // テキストの開始位置を設定
  tft.setCursor(0, 10);

  // 1行目にUNOを表示
  tft.println("ESP32");

} //setup


//メインルーチン
void loop() {
  delay(1);
} //loop


```
アクセシビリティを担保したい！Storybookのaddon「@storybook/addon-a11y」について調べて知ったこと

アクセシビリティを担保したいと思い、Storybookのプラグインを使って最終確認できるようにしようと思い色々調べた結果を書き留めます。

:::note info
本来デザイン作成時にはアクセシビリティを担保してないと、コードに落とし込んだ後にわかっても遅いよね？
という話はありつつ、リリース前に気がつけるための最終チェック機能としての役割を持たせたい意図で導入を決めました。
:::

## はじめに自戒：アクセシビリティの認識が甘かった
導入したいと考えた当初はなんのアクセシビリティを担保したいのか？は全く考えられておらず全てのアクセシビリティの指標を一括りにしてしまっていました…。

:::note warn
Storybookにはアドオンは万能ではないのであくまでも最終チェックの機構だと認識いただいた上で検討を進めてもらえると良いと考えます。
:::

## @storybook/addon-a11yはどんなアドオンなのか？
Deque Systemsが提供するアクセシビリティ検証エンジンであるAxeのAPIが使用されており、「WCAG2.1（Web Content Accessibility Guidelines）とSection 508」を準拠し、成果物がアクセシブルであることをStorybook上で確認することができるStorybookの拡張機能です。

### 何がチェックできるのか？
アドオンがチュックしてくれる項目は下記の通りです。

- Color Contrast
- Keyboard Accessibility
- Labeling
- ARIA
- HTML Validity
- Landmark Roles

https://dequeuniversity.com/rules/axe/

#### Color Contrast
視力や色覚異常のユーザーでも確認できるように表示要素のコントラストをチェックします。
後に詳しくしますが、Storybookのアドオンでは色覚異常を持ったユーザーを全てをカバーすることができないそうです。

#### Keyboard Accessibility
ページがキーボードのみで完全に操作可能かをチェックします。

#### Labeling
すべてのインタラクティブ要素（ボタン、リンク、フォーム入力フィールドなど）が適切にラベル付けされているかチェックします。

#### ARIA
ページが適切にARIA属性を使用しているかをチェックします。

#### HTML Validity
マークアップの正当性をチェックします。

#### Landmark Roles
ページに主要部分(ランドマーク)が適切にロールを持っているかをチェックします。

全ての項目がオールグリーンになる必要はないかと思っています。
やりすぎるとデザインの制限が強くなったり、テストに時間がかかったり事業の成長スピードを遅くしてしまうリスクがあると考えるからです。

:::note info
全てのユーザーにとってアクセシブルであることが望ましいのは間違いないのですが、どこまで対応するのかを事業の状況やチームの状況に合わせて決定し、都度見直すことが大切だと考えております。
:::

### 色覚異常があるユーザー全てを担保できるチェックはできない
先ほど少し触れましたが、Storybookのアドオンでは色覚異常を持った全てのユーザーをカバーすることはできないそうです…。
具体的には、T型やA型に分類される色覚以上を持つユーザーをカバーすることはアドオンでは困難だということです。

#### T型とA型ってなに？
色覚異常は複数の型で分類されています。
詳しくは割愛しますが、参考サイトのリンクを添付しますのでご確認ください。

https://www.color.or.jp/about_cud/construction/

人の目の網膜には光を感じる錐体には、L（赤）、M（緑）、S（青）の3種類あります。
その中の一部錐体がなかったり、感度が別の錐体と似かよることで色が識別できなくなることを色覚異常と表現されます。

:::note info
赤色が見えずらい人、緑色が見づらい人を型で分類しています。
:::

アクセシビリティの議論では「T型とA型」までカバーすべきか？が争点になると思います。
というのもT型とA型は数が少ないため、P型とD型でほとんどの色覚異常の人をカバーすることが可能だとされているためです。

:::note info
サイトの性質にもよりますが、チームで議論してステイクホルダーと決定を擦り合わせておけると良いと思います。
:::


## 色覚異常のユーザーを全てカバーしたい場合の対策
それでも色覚異常をもった全ての人に対応したいと考えた場合は、ツールの併用を検討します。
Storybookのアドオンだけでは無理なのためです。

- 色覚シミュレーションツール
    -  ウェブサイトが色覚異常のユーザーにどのように表示されるかシミュレートすることができます
    -  例えば、Chromeの拡張機能には「Toptal ColorBlind」
-  色覚互換性ツール
    - 色の組み合わせが色覚異常のユーザーにとって適切かどうかを検証します
    - Color OracleやSim Daltonismなど

:::note info
色覚に配慮したデザインにすることも有効だと知りました。
例えば、色と一緒にパターンやテクスチャを使う、テキストラベルを使うなどの方法を採用するなどです！
:::

## まとめ
アクセシビリティもどんな項目をどのレベルまで対応するかによって考えないといけないことがたくさんあるのだと知りました。

:::note warn
アクセシビリティを突きつめてサイトを作成することでアクセシビリティは良くなりますが、その分デザインの幅が狭まることも事実です。
:::

アクセシビリティに限らず、見れる人の範囲を拡大すればするほど開発コストやその後の運用コストもかかるのでいい塩梅のラインをチームで設定して開発できるのが望ましいと感じました。
アウトバウンド ファンド モジュール


Outbound Funds Module 

+ [アウトバウンド ファンド モジュールの製品ドキュメント](https://help.salesforce.com/s/articleView?id=sfdo.Outbound_Funds_Module.htm&type=5)

+ [Install Outbound Funds Module](https://install.salesforce.org/products/outbound-funds/latest/install)

+ [Installer Issues](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007PfcWZ)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/fef26c43-eefb-e8e9-cf20-33fb1db10f71.png)
フォームオブジェクト使用時のエラー取得に`if .save`は使えない？！

## フォームオブジェクト使用時のエラー取得に`if .save`は使えない？！

#### **フォームオブジェクトの利用**
1つのフォームから複数のテーブルにデータを保存する場合、フォームオブジェクトは非常に便利です。これは複数のモデルからデータを収集し、それぞれのモデルに保存するための便利な手法です。

#### **バリデーションの確認**
通常、フォームオブジェクト内でデータを保存するために、`.save` メソッドを使用します。しかし、この方法ではフォームオブジェクトは仮のmodelであるためバリデーションエラーが発生しても、そのエラーの詳細を取得するのが難しいです。

#### **エラーの取得**
しかし、`.valid?` メソッドを使うことで、バリデーションのチェックを行い、エラーの詳細を取得できます。これにより、バリデーションエラーがあった場合に、そのエラーメッセージを取得して処理することが可能です。

#### **実際のコード**
例えば、フォームオブジェクト内の `create` アクション内で、エラーチェックを行う場合、以下のようにコードを書くことができます。

```ruby
# フォームオブジェクト内の create アクション
def create
  if @form_object.valid?
    # バリデーションが成功した場合の処理
    @form_object.save
    # 保存処理などを行う
    # 例: flashメッセージの設定、リダイレクト先の設定など
  else
    # バリデーションエラーがあった場合の処理
    errors = @form_object.errors.full_messages
    # エラーメッセージを取得して必要な処理を行う
    # 例: エラーメッセージを表示する、特定の処理を実行するなど
  end
end
```

上記のように、`.valid?` メソッドを使ってバリデーションエラーチェックを行い、エラーの詳細を取得することができます。このエラー情報をもとに、ユーザーにエラーメッセージを提示したり、適切な処理を行ったりすることが可能です。

フォームオブジェクトを使った複数テーブルへのデータ保存は、`.valid?` メソッドによるバリデーションの確認を行うことで、エラーハンドリングを効果的に行うことができます。
モデル単体テスト時の MySQL クライアントエラーへの対処法

## モデル単体テスト時の MySQL クライアントエラーへの対処法

#### **問題の概要**
モデルの単体テスト中に、`ActiveRecord::StatementInvalid: Mysql2::Error: MySQL client is not connected` というエラーが発生するケースがあります。このエラーは、`FactoryBot.build` の直後にMySQLクライアントが正常に接続されていないことが原因です。

#### **エラーの原因**
このエラーは、DB接続が確立されるまでのタイミングに依存しているため、特定の条件下でMySQLクライアントが正常に接続されていない可能性があります。

#### **解決策**
問題を解決するために、簡単な待機処理を導入することで、DB接続の確立までの時間を確保します。`FactoryBot.build` の直後に `sleep(0.1)` などの待機処理を追加することで、DB接続が完了するまでのウェイトを持たせます。

以下に、コード例を示します。

```ruby
# テストコードの一部
before do
  @user = FactoryBot.create(:user)
  @item = FactoryBot.create(:item)
  
  # FactoryBotのbuild後に少し待機することで、DB接続を確立する
  @order_address = FactoryBot.build(:order_address, user_id: @user.id, item_id: @item.id)
  sleep(0.1) # 待機処理の挿入
end
```

上記のように、短い待機処理を追加することで、テストのDB接続関連の問題を回避できます。ただし、待機時間が長すぎるとテストのパフォーマンスに影響を与える可能性があるため、短い時間を設定することが重要です。

これにより、モデルの単体テスト時に発生する MySQL クライアントエラーを回避し、テストの正確性と安定性を確保できます。

### まとめ

このように、`FactoryBot.build` 後に短い待機処理を挿入することで、モデル単体テスト中のMySQLクライアントエラーを解決することができます。
Rubyのコマンドラインオプションを最短で扱う方法

## はじめに

コマンドラインからオプション付き引数を指定して実行する際の実装方法についての記事になります。
オプション付きの引数とは、例えば `$ruby sample.rb -a 1` で実行する場合は `-a` がオプションで `1` がその値になります。
Rubyをでこれを扱うためには **optparse** が必要になります。（Pythonでいうと[argparse](https://docs.python.org/ja/3/library/argparse.html#module-argparse) と同様）
コマンドラインから受け取った値を実行時に `{a: 1}` のような形で扱いたいと思っていました。
Rubyの[リファレンス](https://docs.ruby-lang.org/ja/latest/library/optparse.html)を参照したところ説明がとても充実していたのですが、実際に使用するまでには少々遠回りでした。
本来はリファレンスを熟読してから使用するべきですが、とりあえず使いたい方（と将来の自分）に向けて最短方法を記載します。

#### 動作確認環境
- ruby 3.2.2 

## 使い方

コマンドラインから受け取った値を変数に入れることにフォーカスすると、サンプルコードは下記になります。

```ruby:sample.rb
# ライブラリ読み込み
require 'optparse'

# 変数へ代入
params = ARGV.getopts("a:b:", "foo", "bar:")

# 変数の使用
p params
```

実行時すると下記のようになります。

```sh
$ ruby sample.rb -a 1 --foo --bar xxx
{"a"=>"1", "b"=>nil, "foo"=>true, "bar"=>"xxx"}
```

ポイントは下記になります。

- optparseをrequireすることでARGVに機能が追加されます
- ARGV.getoptsで引数に渡したものだけ使用可能になります
  - この状態で未指定の-bをコマンドラインから指定するとエラーになり、誤入力を防げます
  - 可変長引数です。ブロック{}ではありません。
- デフォルト値を設定できます
- 引数は文字列型になります（1は"1"）

#### リファレンスの読み方の補足

- オプション定義の`opt.on('-a') {|v| p v }`について
  - 上記でも定義できるのですが、上記の使用範囲なら`ARGV.getopts()`で十分です
  - 最初はブロック内で変数を代入できること期待したのですが、こちらはコマンドラインからの入力の有無をboolで返すものになります
  - ブロックはパース実行時まで処理されません
- パース実行の`opt.parse!(ARGV)`について
  - こちらは-aなどのオプションの文字列を削除して値だけを配列に残してくれます


## おわりに

Rubyのコマンドラインオプションを扱う最短の方法を記載しました。
とりあえず使うなら上記で十分ですが、より理解するためにはリファレンスの理解が必要です。
自分が所望する使い方は最後の方に書いてあったので、長くても最後まで読むことが大事だと感じました。

#### 参照
- [Ruby 3.2 リファレンスマニュアル > library optparse](https://docs.ruby-lang.org/ja/latest/library/optparse.html)
単純なスペルミス

# スペルミスのエラーはスペルミスとは言われない
発生したエラーの原因が単純なスペルミスであったため、備忘録として
# 発生したエラー
NameError in Devise::RegistrationsController#create
Rails couldn't find a valid model for Family association. Please provide the :class_name option on the association declaration. If :class_name is already provided, make sure it's an ActiveRecord::Base subclass.

familyモデルとの関連付けが見つからないという内容であり、これがdeviseのgemで作成したuserモデルとの関連付けであったため、deviseを使用する際の何か特別な関連付けがあるのかと思い、数時間悩んだ。
# 解決
has_manyのスペルがhas_menyになっていた、、、こんな単純なことに数時間が悔しい。

冷静にエラー文を読むと、関連付けに問題があると書いてあり、関連付けのコードを見直してみるべきであった。反省。
Rakuten, Mercari, Amazon, Google, Microsoft の Salary 比較

# Salary 比較サイトを見つけました

[Microsoft vs Google vs Amazon vs Rakuten vs Mercari - Compare career levels across companies with Levels.fyi](https://www.levels.fyi/?compare=Microsoft,Google,Amazon,Rakuten,Mercari&track=Software%20Engineer)

こんなに差があるんですねぇ。
論理設計と物理設計



どうも、ぴよぴよエンジニアのwatabeです。

今回は、DB初心者向けに、DB設計の導入を詰め込んであげようと思います。


## 物理設計と論理設計の違い

簡単に、ざっくり違いのイメージをお伝えすると、

```
論理設計は、データベースのテーブルを定義すること（図面などに）
```
```
物理設計は、テーブルをDBMS上に作成すること
```

のような感じ

作りたいアプリケーションがあったときに、そのアプリケーションではどんなデータをどんなデータ型で扱い、それぞれのデータの関係性はどうなっているのか

これを整理してから、実際にDBを構築していく

なので、流れは、論理設計→物理設計になる


## 論理設計の流れ

### 1. エンティティを定義する

エンティティとは、テーブルにあたる概念のこと
DBにおいて、ひとまとまりにしておきたいデータの集合といったイメージ

### 2. 正規化する

エンティティを定義したということは、テーブル設計が終わっているので、そのテーブル達を正規化します。

`
正規化　＝　一定のルールに基づいて、データを整理すること
`

そうすることで、無駄なSQL文を書くことがなくなります。

### 3. ER図作成

`
エンティティ同士の関係を資格的にわかりやすく表した図
`

がER図です。

先ほどの1,2でエンティティのイメージが頭の中にできていると思います。

それを、実際に、図に書くということです。

手書きでも、[plantUML](https://plantuml.com/ja/ie-diagram)のようなソフトウェア（無料）を使ってもOKです。

実際に、ER図がどんなものかググって見てみてください


## 物理設計

### 1. テーブル定義

ターミナルから行ったり、GUIソフトを使ったり、さまざまなやり方があるが、

テーブル定義とは、

`
論理設計通りに、DBMS上に、テーブルを構築すること
`

そうすることで、実際にデータを入れて運用できる状態になる。

！！わーーい！！

ということになる。


### 2. インデックス設計

最後に、インデックスについて説明して締めようと思うぜ？いいか？

`
インデックスとは、テーブル設計の1つのテクニックだ。
`

```
インデックスを設定することで、
いや、インデックスを適したカラムにうまく設定することで、クエリを早くすることができる
よく、高速クエリとか聞くだろう？
インデックスをうまく設定してあげれば、クエリを高速にできるぞ
```

そんなテクニックだ。

例えば、

```
CREATE INDEX idx ON employees (birth_date);
```



このように、書くと

`
employees
`

というテーブルの
`
birth_date
`
というカラムに、
`
idx
`
という名のインデックスを設定できる

#### インデックス設定のベストプラクティス

インデックスのベストプラクティスについても少し触れる

- 区画度の高いカラムにインデックスを設定すると良い
- 複数の条件でクエリが実行される機会が多いものは、結合インデックスを使うと良い

これが、ベターなインデックスの使い方だ



以上、ありがとうございました。
2023/11/13主にITとかセキュリティの記事

PostgreSQL 16.1リリース、3件の脆弱性を修正(11/11)
https://news.mynavi.jp/techplus/article/20231111-2815314/

仮想通貨取引所Poloniexハッキング、1億ドル以上流出(11/11)
https://coinpost.jp/?p=491341

警視庁、サイト真偽判断に生成ＡＩ活用検討　ＩＤ・パスワード窃取「フィッシング被害」急増　判断を効率化し被害軽減(11/11)
https://www.zakzak.co.jp/article/20231111-6ZOAE3IXQJK73GPAK6HMUY7LEY/

チャットＧＰＴが９０分間にわたりダウン、「ＤＤｏＳ攻撃が原因」(11/11)
https://www.donga.com/jp/home/article/all/20231111/4546771/1

3-2-1ルールとは？　効果的なバックアップ戦略を構築するための10のヒント　ESETが解説(11/11)
https://atmarkit.itmedia.co.jp/ait/articles/2311/11/news035.html

米ボーイング内部情報が流出、犯罪集団「ロックビット」の攻撃で(11/11)
https://jp.reuters.com/markets/global-markets/PWBFOLNPDVLKRAO2OPXIDQRXQQ-2023-11-10/

いきなり届いた「電子契約書」の危険性　有識者と弁護士が語るリスクとは(11/11)
https://nordot.app/1095810492935979615

中国工商銀へのサイバー攻撃、米国債市場に影響なし＝米財務長官(11/11)
https://jp.reuters.com/markets/bonds/KO3YU4MCEJMKDEV3GXFCZBDMEY-2023-11-11/

AIがもたらす同時通訳の新しい当たり前(11/11)
https://pc.watch.impress.co.jp/docs/column/config/1546074.html

実在する通信事業者名でSMSが…70代の女性が架空料金請求詐欺で60万円の被害　新潟・三条市(11/11)
https://nordot.app/1095899548704112760

謎のショートメールに注意！「サイトの利用料金が未納」はうそ　新潟三条市の70代女性が60万円だまし取られる(11/11)
https://www.niigata-nippo.co.jp/articles/-/311400

ホテル狙うサイバー攻撃に注意　客の相談装い、不審メール(11/11)
https://www.47news.jp/10114887.html

危機下のイノベーション―、紛争に備える日本経済の最前線(11/8)
https://coralcap.co/2023/11/innovation-under-pressure/
【Testで使える】Faker の主要メソッド12選

## Faker Gemの主要メソッド15選

Faker Gemはテストデータの作成に利用される便利なツールで、以下の15の主要なメソッドがあります。

### Fakerの便利なメソッド一覧

1. **郵便番号**: `Faker::Number.leading_zero_number(digits: 3) + '-' + Faker::Number.leading_zero_number(digits: 4)`  
   - 例: "025-4893"

2. **都道府県ID**: `Faker::Number.between(from: 2, to: 48)`  
   - 例: 15

3. **市町村**: `Faker::Address.city`  
   - 例: "東京"

4. **住所**: `Faker::Address.street_address`  
   - 例: "南1-3-7"

5. **ビル名**: `Faker::Company.name`  
   - 例: "株式会社ABC"

6. **電話番号**: `Faker::Number.leading_zero_number(digits: 11)`  
   - 例: "09012345678"

7. **トークン**: `Faker::Alphanumeric.alphanumeric(number: 30)`  
   - 例: "ecfyudjxaniau6toy2bs9el3kpa7bq"

8. **文章**: `Faker::Lorem.sentence`  
   - 例: "Sit voluptatem aut enim quos."

9. **価格**: `Faker::Number.between(from: 300, to: 9_999_999)`  
   - 例: 7354928

10. **日付**: `Faker::Date.birthday`  
    - 例: 1990-08-15

11. **パスワード**: `'1a' + Faker::Internet.unique.password(min_length: 6)`  
    - 例: "1aBcDeFg123"

12. **メールアドレス**: `Faker::Internet.unique.email`  
    - 例: "example@example.com"
【SQL】SQLで削除に関するコマンド

# SQLで削除に関するコマンドとその違い・注意点を挙げていきます。

## 1.DELETE FROM
DELETE FROM コマンドは、指定された条件に一致する行をテーブルから削除します。条件を指定しない場合、テーブル内の全ての行が削除されますが、テーブル構造自体は残ります。

使用例:
特定の条件を満たす行を削除する: `DELETE FROM table_name WHERE condition;`
テーブル内の全ての行を削除する: `DELETE FROM table_name;`

## 2.TRUNCATE TABLE
TRUNCATE TABLE コマンドは、テーブルから全ての行を迅速に削除し、テーブルを空の状態にリセットします。この操作は DELETE FROM よりも高速ですが、制約による制限がある場合があります。

使用例: 
テーブルのデータをすべて削除する:`TRUNCATE TABLE table_name;`
channelsテーブルのAUTO_INCREMENT属性を1にする：`ALTER TABLE channels AUTO_INCREMENT = 1;`

## 3.DROP TABLE
DROP TABLE コマンドは、テーブル自体をデータベースから削除します。これにより、テーブルに関連するデータとメタデータの両方が削除されます。

使用例: 
テーブルを完全に削除する:`DROP TABLE table_name;`

## 違い・注意点

・データのバックアップについて:
DELETE、TRUNCATE、および DROP コマンドはいずれも元に戻すことが困難または不可能なため、実行する前に必要に応じてデータのバックアップを取ることが重要です
。
・ロールバック可能性:
DELETE コマンドは`トランザクション`の一部として実行することができ、必要に応じて`ロールバック`することが可能です。しかし、TRUNCATE と DROP は一部のデータベースシステムではロールバックできない場合があります。

・パフォーマンスについて:
大規模なデータセットに対してこれらのコマンドを使用すると、パフォーマンスに影響を与える可能性があります。特に、生産環境での作業を行う場合は注意が必要です。


### トランザクションについて
トランザクションは、データベース操作を安全に行うための一連のプロセスです。一つのトランザクション内で実行される一連の操作は、すべて成功するか、一つでも失敗すれば全体が失敗（ロールバック）します。これにより、データベースの整合性が保たれます。

## AUTO_INCREMENTとトランザクション
AUTO_INCREMENT 属性が付いたカラムは、新しい行が挿入されるたびに自動的にユニークな数値が割り当てられます。例えば、最後に挿入された行の AUTO_INCREMENT 値が10だった場合、次の新しい行には11が割り当てられます。

・ギャップの発生
トランザクション中に行が挿入され、AUTO_INCREMENT 値が割り当てられたとします。しかし、何らかの理由でトランザクションが完了せずにロールバックされた場合（例えば、エラーが発生した場合）、そのトランザクション中に行われた変更（行の挿入など）はすべて取り消されます。しかし、このときAUTO_INCREMENT で使用された数値は「使用済み」とみなされ、次回の挿入ではスキップされます。

例えば：

AUTO_INCREMENT の現在の値が100です。
新しい行が挿入され、AUTO_INCREMENT の値が101になります。
トランザクションが失敗し、ロールバックされます。この行の挿入は取り消されますが、AUTO_INCREMENT の値は101のままです。
次に行が挿入されると、AUTO_INCREMENT の値は102になります。
この結果、101のIDを持つ行は存在しなくなり、IDのシーケンスにギャップ（101が欠ける）が生じます。これはAUTO_INCREMENT の特性であり、一般的には問題とはされませんが、IDの連続性が絶対に必要な場合は、別のID生成戦略を検討する必要があります。

そのため、これらのコマンドはデータベースの整合性に直接影響を及ぼすため、特にTRUNCATEやDROPのような強力なコマンドは慎重に使用する必要があります。
ImageMagick でモックアップ用画像生成（macOS）

## TL;DR
```shell-session
$ size="256x144"; magick -background '#778899' -fill white -size "$size" -gravity center label:"$size" "$size".png
```
![256x144.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501772/ae7e9750-5257-db10-c717-8ce800a922b8.png)

## 動作環境
```shell-session
$ sw_vers 
ProductName:		macOS
ProductVersion:		13.6
BuildVersion:		22G120

$ magick -version
Version: ImageMagick 7.1.1-21 Q16-HDRI aarch64 21667 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI Modules OpenMP(5.0) 
Delegates (built-in): bzlib fontconfig freetype gslib heic jng jp2 jpeg jxl lcms lqr ltdl lzma openexr png ps raw tiff webp xml zlib
Compiler: gcc (4.2)
```

## 環境構築
```shell_session
$ brew install imagemagick
```

環境を汚したくなければ docker コンテナに ImageMagick をインストールするとよいかも

## 参考
- [Mac テスト用の画像を生成する #Mac - Qiita](https://qiita.com/ucan-lab/items/22a8457c8f5139c8c444)
- [Text Handling -- ImageMagick Examples](https://www.imagemagick.org/Usage/text/#label_bestfit)
- [ImageMagick – Color Names](https://imagemagick.org/script/color.php)
- [How to add padding to text in Imagemagick? - Stack Overflow](https://stackoverflow.com/questions/37218844/how-to-add-padding-to-text-in-imagemagick/37219225#37219225)
【効率化】忙しい日々に勉強時間を作り出す。

# ある日のこと

「「頑張る」と「無理をする」を⼀緒にしちゃっていた
無意識に僕は僕を殺しかけていたんだ」

あれやってこれやって、あ、これもやんなきゃな。。
そんな1日のスケジュールを頭で組み立てながら、満員電車に揺られていた時に、耳に届いてきた歌詞です。

その後の歌詞は全然聞いてないんだけど、そのワンフレーズのおかげで、あまり張り詰めずに行こうと思いました。

# 初めに
エンジニアの皆さん、日々の激務お疲れ様です。
エンジニアは、休日も勉強しなくてはいけないイメージってあると思うんですけど、ほんとそうだと思うんですよね。
平日の業務をこなしながら得られる知識って本当にテクニカルになってくるし、だからと言って基礎的な土台を固めるための勉強時間を業務時間内に作れるわけでもない。

でも、「エンジニア」っていう生き物がただかっこいいなっていう考えで、IT業界に飛び込んだ僕みたいな人間って、
「エンジニア」に化けるために今まで得てきたその他のプライベートを捨てる覚悟をしてきた訳じゃないんです。

泣き言言ってるわけではなくて、じゃあどうすればいいかって考えた結果たどり着いたのが、「平日の無駄な時間を減らすこと」。
1日の業務を20~30ほど巻いて終わらせることができた時、あまりを勉強時間に充ててしまえば、プライベートも勉強も両立できるってもんだと思いませんか？？

なのでこの記事では、僕が業務時間にやっている無駄な時間を減らす方法を紹介します！！

# こんな人に読んでほしい
* 若手エンジニア
* 1日のスケジュールがギチギチのエンジニア
* プライベートも充実させたいエンジニア

# 目次

* Chromeでの効率化
* VSCodeでの効率化
* スプレッドシートでの効率化
* ターミナル操作での効率化
* その他

# Chromeでの効率化

## タブグループを使う

Chromeには「タブグループ」なるものが存在します。
案件を跨いで作業していたり、タブが米粒の大きさくらいになるまで調査したりする時ってあるじゃないですか？？
そんな時に、目当てのタブがどこに行ったかわかんなくなることってありますよね。

このタブグループなるものは、その名の通りタブをグループでまとめることができ、さらにはグループごと移動、表示/非表示が可能です。

<img width=700 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524065/3db37bd5-05f3-8843-9406-4c0be894f074.gif" alt="Nov132023014829.gif">

## ブックマークバーをカスタマイズする

毎日開くようなサイトやスプレッドシートは、絶対にブックマークバーにまとめるべきだと思っています。
いちいち検索やドライブを経由しなくて良くなるので、格段に効率が上がります。

[設定方法]
* Chrome右上の3点リーダから、「ブックマーク」>「ブックマークバーを表示」
* ブックマークに設定したいサイトのURLが表示されている検索バー右端にある★マークを押下
* 任意で名前を設定し、フォルダを「ブックマークバー」乃至適当なフォルダを指定
* 「完了」を押下

# スプレッドシートでの効率化

## 同じファイルを2つのタブで開く

開発の仕事をしていると、スプレッドシートで情報をまとめたり、管理したりといった作業が生まれてくると思います。
そのファイルを修正する作業を行うときに、　同じファイルを2つのタブもしくは参照するシート分のタブで開くと効率が格段に上がります。

多くの情報をまとめるときに、この情報はこっちのシート、この情報はこっちといったように、シートを分けて管理していることがほとんどだと思うんですよね。
ただ、関数を打ち込んでいる時とかに、別のシートの情報を入力したい時って、セルはついてきてくれるものの、シートを切り替える手間が生まれる。
そんな時に、同じシートを開いてモニターに写しておくだけで、カーソル操作を行わずに別シートを参照することができます。

これはモニターがある前提ですね。
モニターがない場合は、1つの画面内に表示させることは可能ですが、少し見づらいかもしれません。

# VSCodeでの効率化

## ショートカットキーを使うことを意識付ける

ショートカットを使える人って、本当に無駄な手間を避けることができていると思うんですよね。
考える時間に隙を作らないためにも、ショートカットは当たり前のように使えるようになるべきだと思います。
このちょっとした技術の積み重ねで、無駄な時間を省いていきましょう。

ショートカットについては、以下の記事でまとめているので、気になる方は除いてみてください。

https://qiita.com/suga_slj/items/d83262f291aa7da5dfc8

## 拡張機能を使う

これはエンジニアによって賛否両論あるかもしれませんが、拡張機能を入れることで、無駄な作業を大幅に減らすことができます。
拡張機能に限らず、VSCode自体の設定から、効率化を図ることももちろん可能で、自分が入社してからずっと助けられているのが、「Format on save」という設定。
保存時に自動でインデントを揃えてくれるんです！！！

# ターミナル操作での効率化

## ショートカットキーを使うことを意識付ける

ショートカットは効率化において切っても切り離せないものなのかもしれませんね。
同期がMacBookでのターミナル操作のショートカットをまとめていたので、拝借します。

https://qiita.com/shimada_slj/items/2fd26adf2080a78310fd


# その他

## 無理なら頼る

これはエンジニアに関わらずですね。
何も考えずに答えや助けを仰ぐことは、決してしてはいけないことだと思っています。
今自分がしている作業の優先度や期限に応じて、時間をかけすぎてしまっているのであれば、
先輩や周りを頼って作業を終わらせるのも一つ大事なことだと思います。

自分の時間を作るためという記事な手前、自分勝手に聞こえますが、チームで動いている以上どちらにとってもwin-winです！
自分が知識をつけることで、この先還元することもできますしね！！

# 最後に

以上！
仕事もプライベートも、全力でいきましょう！
Node.js でスクレイピングのメモ（jsdom）

Node.js の jsdom 使ってWebスクレイピングをやってみる
使ってる環境はこんな感じ

- Windows11
- node v18.17.1
- jsdom v22.1.0

# 適当なフォルダ作成・移動
```powershell
mkdir scraping
cd scraping
```

# npm の初期化
```powershell
npm init -y
```

# jsdom インストール
```powershell
npm i jsdom   
```

 # ES Modules 有効化
package.json に `"type": "module"` を追加
```diff_json:package.json
{
  "name": "scraping",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "jsdom": "^22.1.0"
-  }
+  },
+  "type": "module"
}
```

# スクレイピングするサンプルコード
適当なサイトをスクレイピングするサンプルコードです
Yahooニュース https://news.yahoo.co.jp/ の aタグ に設定してあるリンクを取得します
```javascript:index.js
import jsdom from 'jsdom';
const { JSDOM } = jsdom;

const url = 'https://news.yahoo.co.jp/';
const exec = async () => {
  const dom = new JSDOM(await (await fetch(url)).text());
  dom.window.document
    .querySelectorAll('section a')
    .forEach((a) => console.log(a.href));
};

console.log('start');
exec();
```

実行と結果はこんな感じ．．．
```powershell:実行
node index.js
```
```powershell:結果
start
https://news.yahoo.co.jp/pickup/6481508
https://news.yahoo.co.jp/pickup/6481507
https://news.yahoo.co.jp/pickup/6481498
https://news.yahoo.co.jp/pickup/6481510
・
・
・
```
M5UnitV2のUnitV2FrameworkでObject Recognitionを動かすには

## 概要
M5UnitV2のUnitV2Frameworkでプログラムをビルドした上で実行すると、
UnitV2Frameworkに含まれているサンプルプログラムの「object_recognition」が動作しない不具合が発生した。
これを修正して、Object Recognitionを動かす。


## 不具合の内容

ncnnの学習モデルを読み込んだところで、Segmentation fault が発生する。

```
$ ./object_recognition

function: Object Recognition start.
{"msg":"Running Object Recognition, Copyright 2021 M5Stack Technology Co., Ltd. All rights reserved.","running":"Object Recognition"}
Model Type: YOLO v3
Load ./model/unitv2/yolo_20class/ Successfull, Class: 21
Segmentation fault (コアダンプ)
```



## 原因と修正場所

https://github.com/m5stack/UnitV2Framework


UnitV2Frameworkのsrc/framework.cppの内、loadModel()関数の中の処理で、関数がint型なのに、値を返していなかった。
「return 0;」を追加してビルドをやり直したところ、問題なく動作するようになりました。

```src/framework.cpp
int loadModel(const std::string pathparam, const std::string pathbin, ncnn::Net &net){
    net.load_param(pathparam.c_str());
    net.load_model(pathbin.c_str());
    net.opt.openmp_blocktime = 0;
    net.opt.lightmode = true;
    net.opt.num_threads = ncnn::get_cpu_count();
    
+   return 0;
}
```


## その後

このプルリクは以下になります。

https://github.com/m5stack/UnitV2Framework/pull/3
【Google Fonts】面白いフォントがリリース！！折れ線グラフや棒データなどを描くためのフリーフォント

## 概要
商用利用無料でWeb作成などで使用しやすいGoogleFontsで、以下のものが利用できるようになったので紹介します！
* **Linefont**
折れ線グラフを描画するためのフォント
* **Wavefont**
波形・スペクトル・ダイアグラム・ヒストグラムなどの棒データを描画するためのフォント

## Linefont
![スクリーンショット 2023-11-13 1.37.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524155/5b060cdb-d33d-7475-391e-f8b48120ac2e.png)

https://fonts.google.com/specimen/Linefont

Linefontは中小規模の折れ線グラフ（時系列など）を描画するためのフォントです。
値は0～100の範囲でさまざまな文字に割り当てられます。
範囲、値、ウェイトはWavefontと互換性があり、視覚的な一貫性を維持しながらフォントを交換できます。

## Wavefont
![スクリーンショット 2023-11-13 1.36.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524155/382473d1-f05e-ed56-ccb8-d66f9c513f61.png)

https://fonts.google.com/specimen/Wavefont

波形・スペクトル・ダイアグラム・ヒストグラムなどの棒データを描画するためのフォントです。
Linefontと同様に、値は0～100の範囲でさまざまな文字に割り当てられます。
UseQueryで非同期関数を利用する際、ページ遷移を行うとエラー

## 環境
フロント：React v18系
バック：自作APIサーバー

ReactでTanstak QueryのuseQueryを
以下の設定で行なっていました。

```tsx
const {data :topics} = useQuery({
	queryKey:['topics'] ,
	queryFn:() => getTopic()
});
```

queryFnに定義しているクエリ関数はこちら。
topicを取得するクエリです。

```tsx
export const getTopic = async() => {
	try{	
		const result = await axios.get(URL)
		return result.data
	}catch(err){
		return err
	}
}
```

## 問題点
これで正常に動いていたのですが、このクエリを使っていない別ページに遷移し、
元に戻った際に下記のエラーがconsoleに発生し、画面が表示されなくなりました。

```tsx
A component suspended while responding to synchronous input.
This will cause the UI to be replaced with a loading indicator.
To fix, updates that suspend should be wrapped with startTransition.
```

エラー内容からググると、suspendを使え、とかusetrantisionを利用しようといった情報が見つかったのですが、それでも解決せず。（そもそもstartTrantisionをここで使うケースがあまり見当たりません）
最終的に、下記の修正で改善しました。

## 解決コード
```tsx
const {data :topics} = useQuery({
	queryKey:['topics'] ,
	queryFn:async () => { //この2行が変更点
		return getTopic();
	}
});

```

この書き方であれば該当の事象は発生しなくなりました。

非同期関数を利用する場合、queryFnの関数はプロミスを返す必要があるようです。
非同期の関数なのに、queryFnで使う時に普通に書いてしまったのでコンポーネント描写を止めてしまっていた、ということなのだと思われます。
確かに公式でもasyncを使った書き方もあり、またqueryFnはpromiseを返す関数を書くものだと書かれているようです。

>A query function can be literally any function that returns a promise. The promise that is returned should either resolve the data or throw an error.

https://tanstack.com/query/v4/docs/react/guides/query-functions

では、なぜ普通の書き方もあるのか？というところは
ちょっと原因を調べきれてないですが、一旦備忘録的に記載。
M5UnitV2 の内蔵LEDでLチカをする

## 概要
　M5UnitV2 の内蔵LEDでLチカをします。
　M5UnitV2の内部には、赤のLEDと白のLEDの2個のが内蔵されています。

## GPIOの確認
 M5UnitV2のGPIOを以下のコマンドで確認すると、gpio0、gpio1、gpio2、gpio14があることがわかります。

 M5UnitV2では、gpio0は赤のLED、gpio1は白のLED、gpio2はUnitV2上部のボタンと接続されています。
gpio14はどこに繋がっているのか、は現在不明です。

```sh
unitv2% ls -a /sys/class/gpio/gpio*
/sys/class/gpio/gpio0:
.           active_low  direction   subsystem   value
..          device      edge        uevent

/sys/class/gpio/gpio1:
.           active_low  direction   subsystem   value
..          device      edge        uevent

/sys/class/gpio/gpio14:
.           active_low  direction   subsystem   value
..          device      edge        uevent

/sys/class/gpio/gpio2:
.           active_low  direction   subsystem   value
..          device      edge        uevent

/sys/class/gpio/gpiochip0:
.          ..         base       device     label      ngpio      subsystem  uevent
 ```


 ## Lチカ手順
 白のLEDはGPIO0、 赤のLEDはGPIO1へアクセスすることで点灯することができます。
以下のpythonプログラムをjupyter-notebook で実行するとLチカができます。

 ```L_chica.py
def control_white_led(value):
    open('/sys/class/gpio/export', 'w').write('0') 
    open('/sys/class/gpio/gpio0/direction', 'w').write('out') 
    open('/sys/class/gpio/gpio0/value', 'w').write(str(value))
    
def control_red_led(value):
    open('/sys/class/gpio/export', 'w').write('1') 
    open('/sys/class/gpio/gpio1/direction', 'w').write('out')
    open('/sys/class/gpio/gpio1/value', 'w').write(str(value)) 
 
 import time

for i in range(10):
    control_red_led(0)
    time.sleep(0.5)
    control_red_led(1)
    time.sleep(0.5)
 ```
### 参考資料

m5stack doc
https://docs.m5stack.com/en/quick_start/unitv2/jupyter_notebook
pip install して import するだけで matplotlib をハングル表示対応させる

matplotlibの豆腐問題はハングルでも起こります。
実はjapanize-matplotlibの韓国語バージョンが存在しています。

https://pypi.org/project/koreanize-matplotlib/

```bash
pip install koreanize-matplotlib
```

```python
import matplotlib.pyplot as plt
import koreanize_matplotlib

plt.plot([-1, 0, 1, 2])
plt.title('그래프 제목', fontweight="bold")
plt.xlabel('간단한 그래프')
plt.show()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638747/cac308ab-5838-1735-b4d0-d8f36f7ca1b2.png)


こうやって世の中が便利に少しずつ便利になっていく...ありがたいです

# 参考など
- https://qiita.com/uehara1414/items/6286590d2e1ffbf68f6c
- https://github.com/seongminp/koreanize-matplotlib
Windows11 で開発環境を構築する（自分用）

## はじめに

Windows11 で快適な開発ができるように環境構築をする。

環境構築の手順や参考になるリンクをまとめている。

随時更新予定


## WSL2 のインストール

Windows Subsystem for Linux (WSL)

Windows 11 の場合は、Windows Terminal を起動し、以下のコマンドを実行するだけ。

```powershell
wsl --install
```


上記コマンドでインストールできない場合は以下のドキュメントを参照
[WSLのインストール](https://learn.microsoft.com/ja-jp/windows/wsl/install)

後述する VSCode で WSL を使う場合は以下のドキュメントを参照
[WSLでVSCodeを使用する](https://learn.microsoft.com/ja-jp/windows/wsl/tutorials/wsl-vscode)


## VSCode のインストール

Visual Studio Code（VSCode）

手順がわかる場合は以下から VSCode をダウンロードする
[Download Visual Studio Code](https://code.visualstudio.com/download)

インストールおよび設定は以下のドキュメントを参照
[Visual Studio Code on Windows](https://code.visualstudio.com/docs/setup/windows)


オススメ拡張機能
（今後追記予定）


## Git のインストール

インストールおよび設定コマンド（wsl）

```bash
sudo apt-get install git
git config --global user.name "Your Name"
git config --global user.email "youremail@domain.com"
```

詳細は以下のドキュメントを参照
[WSL で Git の使用を開始する](https://learn.microsoft.com/ja-jp/windows/wsl/tutorials/wsl-git)

Windows 11 用の Git のインストールは以下のドキュメントを参照
[Git - Downloading Package](https://git-scm.com/download/win)


## Google Chrome のインストール（任意）

ブラウザはお好みで。
[インストールページ](https://www.google.com/chrome/)

正常にインストールできない場合は以下のドキュメントを参照
[Google Chrome をダウンロードしてインストールする](https://support.google.com/chrome/answer/95346?hl=ja&co=GENIE.Platform%3DDesktop#)


オススメ拡張機能
（今後追記予定）


## Docker のインストール

WSL で Docker をインストールするときは以下のドキュメントを参照
[WSL 2 での Docker リモート コンテナーの概要](https://learn.microsoft.com/ja-jp/windows/wsl/tutorials/wsl-containers)

Windows 11 に Docker をインストールするときは以下のドキュメントを参照
[Windows に Docker Desktop をインストール](https://docs.docker.jp/desktop/install/windows-install.html)
DJI RC-N1 (RC231) コントローラーを、Xbox360コントローラーとして利用する方法

# はじめに
最近、実機のコントローラーでDrone Simulator を遊ぼうと、`RC-N1 (RC231)` を買ったんですけど、まぁ使えなかったんですよ。なのでどうにかしてやろうとGitHubで探してみたら、Pythonで実現している[有志](https://github.com/IvanYaky/DJI_RC-N1_SIMULATOR_FLY_DCL)がいらっしゃったので、拝見させていただきました。
どうやらCOMでパケット飛ばして読み込んでシミュレーターとして起動しているみたいだったので、そちらを参考に、Windows Form で常駐ソフトを作ってみました。

# Repository
これを起動しておくだけで、`RC-N1` をつないだ時にシミュレーターが同時に起動してまるでゲームパッドのように使えるようになります。
仕組み的には、上記のCOMでパケット飛ばして読み込んで、ViGEm を使ってシミュレーションしています。

https://github.com/Limitex/DJI-RC-N1-Converter

# 使い方
## 1. ViGEmBus
ViGEm を使っているので、まずそれのインストールが必要です。一回インストールしてしまえば見た目上は何も入っていませんが、ドライバみたいな感じでちゃんと入っています。

こちらからインストーラをダウンロードして、インストールします。

https://github.com/nefarius/ViGEmBus/releases

## 2. DJI RC-N1 Converter

こちらが今回作った常駐アプリです。
zipファイルをダウンロードして、好きな場所に配置してください。

スタートアップに登録しておくと、PCに`RC-N1`をつなげただけで使えるようになります。

https://github.com/Limitex/DJI-RC-N1-Converter/releases

## 3. DJI RC-N1 (RC231)

コントローラーの電源を入れます。
`RC-N1` は電源が入っていないと、PCと会話してくれないので、起動します。
電源ボタンを2回押して2回目を長押しすることで起動できます。

## 4. Connect to PC

コントローラーをUSBでPCに接続します。
これで準備ができましたので、存分にDrone Simulator をプレイできます。
このアプリにコントローラーが認識されているかどうかは、タスクトレイにあるゲームパッドのアイコンを右クリックすることで、確認できます。
加えて、`Exit`をクリックすることで、プログラム自体を終了できます。

# おわり

# Reference 
https://github.com/IvanYaky/DJI_RC-N1_SIMULATOR_FLY_DCL

https://github.com/nefarius/ViGEmClient

https://github.com/nefarius/ViGEmBus
[TBU 更新予定] Unityでテキトードローンを動かす

# Unityでテキトードローンモデルを動かしたい

以下のようなことを目指します。完了次第記事を更新予定。
1. Unityでキーボード操作によりドローンモデルを動かす
2. UnityでNavMeshを使ってドローンモデルを動かす
3. ROSから送信されてきたウェイポイントに自動でドローンモデルを動かす

使うモデルは以下。

https://robotaim.booth.pm/items/5231586


# 1 やってみた

キーボードでドローンを動かすところまで完了。

![DroneTest01_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282390/99a905f6-8c9e-0edf-10d6-a9279990736b.png)


# 2 NavMesh使ってウェイポイント配列を巡回

PlaneにはNavMeshSurfaceをアタッチします。特に設定は不要なので「Bake」します。

エージェント（ドローンモデル）に以下のコードをアタッチします。また、Nav Mesh Agent もアタッチします。

コード


```c#

// Patrol.cs
using UnityEngine;
using UnityEngine.AI;
using System.Collections;


public class Patrol : MonoBehaviour
{

    private NavMeshAgent agent;
    private int destPoint = 0;
    private Vector3[] wp = new Vector3[999];


    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        agent.autoBraking = false;

        Transform tf = new GameObject().transform;
        wp[0] = new Vector3(-2, 0, 2);
        wp[1] = new Vector3(2, 0, 2);

        GotoNextPoint();
    }


    void GotoNextPoint()
    {

        agent.destination = wp[destPoint];

        if (destPoint == 0)
        {
            destPoint = 1;
        }
        else
        {
            destPoint = 0;
        }
    }


    void Update()
    {
        if (!agent.pathPending && agent.remainingDistance < 0.5f)
            GotoNextPoint();
    }
}

```

![Drone_patrol.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282390/deb94eac-33c6-c320-948b-d6c2434219f0.gif)


# 参考

NavMeshの基本に関する参考
https://vanikki.com/unity-navmesh/

# 記事作成時間


記事作成時間1 : 2023/11/13 0時33分

![記事作成時間_テキトードローン_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282390/d5fb7a94-c687-1429-dcc1-f321e49d26ea.png)

NavMesh更新時の時間

![記事作成時間_テキトードローン_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282390/9f93e476-c341-9da4-536b-518f858f468e.png)
M5UnitV2 からLINEへ通知を送る

### 概要：
　M5UnitV2 からLine Notifyを使って、LINEへ通知を送る手順です。
 

### Line Notifyのサービス登録
Line NotifyをM5UnitV2で使うためには、Line Nofityのホームページで、あなたのLineとのアクセストークンを発行します。

Line Nofity：https://notify-bot.line.me/

![クリップボード04.png](https://qiita-image-store.s3.amazonaws.com/0/73020/3fde0682-5184-f679-fa2b-7cc3c903e42b.png)

Line Nofityのホームページから、「アクセストークンの発行（開発者向け）」を押します。
![クリップボード06.png](https://qiita-image-store.s3.amazonaws.com/0/73020/fbac3d6c-2f3b-dc84-1cf5-acf1772a7b0f.png)
そして、必要事項を記入の上、発行されたアクセストークンをコピーします。
これで、Line Notifyを使うための準備が完了です。


### Line NotifyへPythonからメッセージを送る

Line NotifyへPythonからメッセージを送ります。

```
$ python Line_notify.py
```

```Line_notify.py

import requests
line_notify_token = 'yourtoken'
line_notify_api = 'https://notify-api.line.me/api/notify'
headers = {'Authorization': f'Bearer {line_notify_token}'}
data = {'message': f'ようこそUnitV2'}
requests.post(line_notify_api, headers = headers, data = data)

```
Line NotifyへPythonからメッセージと写真を送ります。


```Line_notify_with_picture.py

import cv2
import requests
line_notify_token = 'yourtoken'
line_notify_api = 'https://notify-api.line.me/api/notify'
headers = {'Authorization': f'Bearer {line_notify_token}'}
data = {'message': f'ようこぞUnitV2'}

camera = cv2.VideoCapture(0)
ret, frame = camera.read()
cv2.imwrite('test.jpg', frame)

files={'imageFile': open('test.jpg','rb')}
requests.post(line_notify_api, headers = headers, data = data,files=files)

```

Lineで写真が投稿されていることを確認できればOKです。

![unnamed.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73020/972437e5-c793-474a-5d39-fcbe1b048cbc.jpeg)
【Next.js】middlewareでヘッダーを追加する方法

`middleware.ts`に以下のように記述することでリクエストやレスポンスにヘッダーを追加できます。

```middleware.ts
import { NextResponse } from 'next/server'
import { NextRequest } from 'next/server'

export async function middleware(req: NextRequest) {
  const reqHeaders = new Headers(req.headers)
  reqHeaders.set('x-params', req.nextUrl.searchParams.toString())
  reqHeaders.set('x-pathname', req.nextUrl.pathname)

  const resHeaders = await someFunc()

  return NextResponse.next({
    // レスポンスヘッダー
    headers: resHeaders,
    // リクエストヘッダー
    request: {
      headers: reqHeaders,
    },
  })
}



```
MySQLコマンド入門

# はじめに
本記事は、自分用の備忘録も兼ねて、MySQL初学者向けに、MySQLのコマンドについてまとめたものです。

# MySQLコマンド

- MySQLのバージョン確認
```sql
$ mysql --version
```

- MySQLの起動
```sql
$ mysql -u user_name -p
```

- MySQLの終了
```sql
mysql> exit;
```

- ユーザーの作成
```sql
mysql> CREATE USER user_name@localhost IDENTIFIED BY 'password';
```

- ユーザー権限の設定
```sql
mysql> GRANT ALL ON database.tables TO user_name@localhost;
```

- データベース一覧の表示
```sql
mysql> SHOW DATABASES;
```

- データベースの作成
```sql
mysql> CREATE DATABASE database_name;
```

- 使用するデータベースの選択
```sql
mysql> CREATE DATABASE database_name;
```

- 現在使用中のデータベースの表示
```sql
mysql> SELECT DATABASE();
```

- テーブルの作成
```sql
mysql> CREATE TABLE table_name (col_name data_type, ...);
```

- 全てのテーブルを表示
```sql
mysql> SHOW TABLES;
```

- テーブルにデータを挿入
```sql
mysql> INSERT INTO table_name (col_name1, col_name2, ...) VALUES (value1, value2, ...);
```
Github Actionsでワークフローを自動化するには

Gihub Actionsで指定した時刻で定期的にワークフローを実行し、実質的な自動化を目指しました。公式ドキュメントにも示されていますが、今回自分が実装した方法をまとめました。

## 結論：Scheduleトリガーを使用する
結論から言うと`Schedule`トリガーを使用することで実現することができます。

```
on:
  schedule:
    - cron:  '30 20 * * *'
```
例えばこのコードでは、毎日20:30 UTCにワークフローが実行されます。しかし、この時刻はUTCなのでJSTとしての時間での実行を想定するのであれば9時間の時差があることに注意してください。

ちなみにここで使用するcronは実行時間を表し、「分、時、日、月、曜日」を表し、曜日の部分は0~7でsun~satを表します。また、*を使用することで、「全て」を表すこともできます。

### 時間指定の例
毎日10:30 UTCに実行する
```
30 10 * * *
```
<br>

毎月5日の1:00 UTCに実行する
```
0 1 5 * *
```

## 実際にやってみる
今回やってみたのは、定刻にbuildを実行すると言うもの。毎月5日の10:00 JSTにワークフローが実行されるように実装しました。

```
name: artist-sales-report

on:
  schedule:
    # 毎月5日の10:00 JST （01:00 UTC）に実行
    - cron: "0 1 5 * *"

jobs:
  build:
    name: run build
    runs-on: ubuntu-latest
    steps:
      - run: npm run build
```

## わかったこと
実際に定期実行を実現することはできました。ただ、遅延が発生します。
原因としては、Actionsのワークフロー実行の負荷が高い時にイベントに遅延が発生するそうです。そのため、リアルタイム性を追及するようなフローへの使用は適さないと感じました。

## 参照
・https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule
[Windows10]コマンドプロンプト→MySQLで日本語が文字化けする場合の対処

## 環境
- Windows10
- XAMPP

## 対処法
文字コードの設定を行い、クライアント側に関係する項目をコマンドプロンプトのデフォルト文字コードに変更する。

## 詳細
Windows10でコマンドプロンプトからMySQL(MariaDB)を操作すると、INSERTなどで日本語を使用した場合に文字化けしてしまいます。chcpコマンドでコマンドプロンプトが使用する文字コードをUTF-8に変更できますが、変更した環境で日本語フォントが選択できないため結局文字化けしてしまいます。
 
ですので文字コードの設定を行い、クライアント側に関係する項目をコマンドプロンプトのデフォルト文字コード(cp932)に変更しましょう。

### 現在の設定を確認

まず現在の文字コードの設定を確認します。MySQLサーバを起動し、コマンドプロンプトからMySQLに接続して以下のコマンドを実行してください。
```
show variables like "chara%";
```
そうすると次のように表示されると思います。
```
+--------------------------+--------------------------------+
| Variable_name            | Value                          |
+--------------------------+--------------------------------+
| character_set_client     | utf8mb4                        |
| character_set_connection | utf8mb4                        |
| character_set_database   | utf8mb4                        |
| character_set_filesystem | binary                         |
| character_set_results    | utf8mb4                        |
| character_set_server     | utf8mb4                        |
| character_set_system     | utf8                           |
| character_sets_dir       | D:\XAMPP\mysql\share\charsets\ |
+--------------------------+--------------------------------+
```
この内、
- character_set_client
(クライアントからSQL文などが送信される時に使用される文字コード)

- character_set_connection
(クライアントから受け取った文字を変換する文字コード)

- character_set_results
(クライアントへ結果を送信する時に使用される文字コード)

の3つをcp932に変更します。

### 設定の変更

次にmy.iniファイルを開いてください。XAMPPの場合、XAMPPのコントロールパネルにconfigボタンがあるのでそこからmy.iniファイルを開けます。(不安な場合は中を変更する前にバックアップファイルを作っておきましょう。)

開いたら、[client]の欄に
```
default-character-set=utf8mb4
```
を追記し、
[mysql]の欄のdefault-character-set=utf8mb4を
```
default-character-set=cp932
```
に変更して保存してください。

ここまで終わったらMySQLサーバを再起動して下さい。

### 変更の確認

最後に変更できているか確認します。MySQLサーバを起動し、コマンドプロンプトからMySQLに接続して以下のコマンドを実行してください。
```
show variables like "chara%";
```
以下のように表示されていれば成功です。
```
+--------------------------+--------------------------------+
| Variable_name            | Value                          |
+--------------------------+--------------------------------+
| character_set_client     | cp932                          |
| character_set_connection | cp932                          |
| character_set_database   | utf8mb4                        |
| character_set_filesystem | binary                         |
| character_set_results    | cp932                          |
| character_set_server     | utf8mb4                        |
| character_set_system     | utf8                           |
| character_sets_dir       | D:\XAMPP\mysql\share\charsets\ |
+--------------------------+--------------------------------+
```
もしこれでも文字化けが直らない場合は、設定は今のまま、テーブルの作り直しや既存テーブルの文字コード変換を試してみてください。

## 参考

http://dbonline.s25.xrea.com/mysqlinstall/install/index7.html

https://www.javadrive.jp/mysql/myini/index3.html

https://note.com/stst_esty/n/n6cb731978f5e