OmniAICreator/Qiita-1.07M huggingface dataset:
授業のために早押しクイズサイトを作った話

# 授業のために早押しクイズサイトを作った話

## 初めに

この記事は、[Aizu Advent Calendar 2021](https://adventar.org/calendars/6636)の12日目の記事です。
あと、誕生日です。

## 早押しクイズサイトとは

質問者が自由に、問題と解答を用意し、複数の解答者たちが早く答えるといったものです。  

質問者用画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467463/2ba7b475-26d8-50a8-49b2-8d0bd948c438.png)

解答者用画面(左が名前を入れるところ、右が解答を書くところ)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467463/89681a6d-65b8-2c5f-1e9c-03e38430261e.png)

## なぜ作ったの?

授業でチームで動画を撮ることになったのだが、自分では面白い動画を撮ることが難しいと思いました。(結構、成績に響く)
そこで、他のチームとの差として技術力で殴ろうと思い、クイズサイトを作りました。

## 使い方と簡単な仕組みについて
使い方と簡単な仕組みについて、質問者側と解答者側で分けて、話していきます。

### 質問者側について
1. 問題選択画面で問題ファイルを選択します。
問題ファイルの形式は、問題と解答をコロンで区切って、番号はカンマで区切ります。
このとき問題と解答が2次元配列に読み込まれます。
> 問題1:解答1,問題2:解答2,・・・  

1. 開始ボタンを押します
開始ボタンを押すと、HTTPリクエストが送られ、サーバー側の`flg`が`true`になります。

1. 解答が送られてくると、下に名前と答え、答えるまでの秒数が表示されます。
定期的に、HTTPリクエストをして、解答者の全データをもらってきます。
もらったデータをうまいことパースして表示をしています。

1. 「答えを表示」を押すと、
答えを表示を押すと、あらかじめ用意していた答えと解答を比較をして、同じならばCSSを変更します。

### 解答者側について
1. 質問側で開始ボタンが押されると解答者側でタイム計測が始まります。
定期的に、HTTPリクエストを送り、`flg`を確認することで、開始ボタンが押されたかどうかの判断をしています。

1. 解答をすると、タイマーが止まります。
解答をするとタイマーが止まり、HTTPリクエストによって、名前・答え・タイム送られ、記録されます。

## 作った結果

* 作ってて楽しかった
* 結果的に良い作品として、授業のサイトで紹介された(成績的にも良いだろう)

## 最後に

今回作ったサイトのプログラムは以下のリポジトリに置いてあります。
https://github.com/suzakutakumi/QuizSite/blob/master/main.go
また、今回のサイトのCSSに関しては友達に作ってもらいました。
pandas DataFrameで最大最小値の行名,列名を取得(argmax/argmin)

こんな感じでとれます


```py
import pandas as pd
import numpy as np

def argmaxdf(table):
    argmax=lambda A: np.unravel_index(np.array(A).argmax(), np.array(A).shape)
    row, col = argmax(table.values)
    row, col = table.index[row], table.columns[col]
    return row, col

table = pd.DataFrame(pd.DataFrame(np.random.rand(5,8),
                                  index=list("abcde"),
                                  columns=list("fghijklm")))

display(table,
        argmaxdf(table)
       )
```
![Screen Shot 2021-12-12 at 16.27.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/7fbb3bd9-6bd1-97ad-ede4-6fc12c1edb1e.png)
Pythonでsuper()の呼び出し時、selfは暗黙的に渡される

久しぶりにpython書いてるとよく間違えちゃうんのでメモ。

**python3 でsuper()を使う場合、第一引数としてselfは暗黙的に渡される。**

なので下記２例はどちらも同じ意味

```python:super()で親クラスのメソッド呼び出す場合
class A(Base):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs) # self引数は不要
```

```python:super()を使わない場合
class B(Base):
    def __init__(self, *args, **kwargs):
        Base.__init__(self, *args, **kwargs)
```
【EC2】minecraft1.18のサーバーをEC2で立ち上げてみた

# はじめに
minecraftの1.18がリリースされました。空や地下が拡張されてより世界が広がったようで、マイクラ世界の拡張は止まるところを知りませんね。
せっかくなので、こちらのバージョンをEC2でサーバー構築してみました。Java17のインストールなど、いくつか躓いたポイントがあったので、その辺りを重点的にまとめたいと思います。

(2021/12/12 追記)
Javaのログ制御系ライブラリ、「Log4j」から脆弱性が発見されました。minecraftもこちらのライブラリを使用しており、外部から攻撃される可能性があります。
今回はそちらの対策についても書いていきたいと思います。


# この記事の対象者

- AWSのEC2でサーバーの立ち上げ・停止を行なったことがある方
- IaaSを使って minecraftのサーバーを立ち上げてみたい方
- AmazonLinux2にJava17を導入したい方


# 環境
- マシンスペック
  - t2.medium
- OS
  - Amazon Linux 2 (amzn2-ami-kernel-5.10-hvm-2.0.20211201.0-x86_64-gp2)
- Javaバージョン
  - Amazon Corretto 17
- Minecraftバージョン
  - 1.18.1(もともとは1.18.0で設置しましたが、Log4j対策のため1.18.1にアップデートしました。)


# 構築手順
若干実際に行った作業より順番が前後していますが、実施したこととしては以下の通りです。

## EC2立ち上げ
minecraftはメモリが最低2GB必要なため、今回は **t2.medium** を選択しました。
今のところ問題なく動作していますが、同時接続人数が増えたらインスタンスのアップグレードも検討しています。
参考：[Minecraft wiki サーバー/要件](https://minecraft.fandom.com/ja/wiki/%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC/%E8%A6%81%E4%BB%B6)
### セキュリティグループ
インバウンドルールでマインクラフトサーバー用のポートを解放します。
![スクリーンショット 2021-12-12 161413.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1586001/948197a7-d93a-4c00-312e-653322d3cecd.png)

## Javaのインストール
minecraft 1.18 では Javaのクラスバージョンが**61.0以上**でなければ起動することができません。こちらのクラスバーションはJava17以上が対応しているので、そちらをサーバーにインストールしたいと思います。
### Amazon Corretto 17
> Amazon Correttoは、Open Java Development Kit（OpenJDK）の無料、マルチプラットフォーム、本番環境対応のディストリビューションです。Correttoには、パフォーマンスの強化やセキュリティの修正を含む長期的なサポートが付属しています。Correttoは、Java SE標準との互換性があると認定されており、Amazonの内部で多くの本番サービスに使用されています。
引用：https://docs.aws.amazon.com/corretto/latest/corretto-17-ug/what-is-corretto-17.html

AWSではJava環境をあらかじめ準備してくれています。以下のコマンドを実行してサーバーにインストールを行います。プラットフォーム・タイプごとのダウンロードリンク一覧は[こちら](https://docs.aws.amazon.com/corretto/latest/corretto-17-ug/downloads-list.html)にあるので、詳しく知りたい方はリンク先を見てください。

- インストール

```bash
$ sudo yum install -y https://corretto.aws/downloads/latest/amazon-corretto-17-x64-al2-jre.rpm
```

- Javaのバージョンチェック

```bash
$ java --version
```


## Minecraft Serverソフトのダウンロード
マインクラフト公式で配布しているサーバー用の```jar```ファイルを取得します。詳しくは以下の公式ページに書いてあります。
参考：[DOWNLOAD THE MINECRAFT: JAVA EDITION SERVER](https://www.minecraft.net/en-us/download/server)

- マインクラフト用ディレクトリの作成

```bash
$ mkdir minecraft
```

- jarファイルの取得
  - こちらは1.18を構築した時点でのリンクです。1.18.1で建てたい方は、リンクを公式ページに書いてある最近のモノにしてください。

```bash
$ cd minecraft
$ wget https://launcher.mojang.com/v1/objects/3cf24a8694aca6267883b17d934efacc5e44440d/server.jar
```


## 実行
```bash
$ java -Xmx1024M -Xms1024M -jar server.jar nogui
```
こちらを実行すると、```eula.txt```というファイルが生成されます。
そのファイルの中の``false``部分を``true``に書き換えます。(ここを変えることで、利用規約に同意したことになり、サーバー用スクリプトが実行できるようになります。)
マイクラサーバーを停止するときは、``stop``と入力してあげれば終了処理が実施されます。

```bash
$ vi eula.txt
# false部分をtrueに書き換えて上書き保存します
$ java -Xmx1024M -Xms1024M -jar server.jar nogui
```

(2021/12/12 追記)
Log4jの脆弱性が発見されたため、マイクラサーバーを立ち上げる時のコマンドに変化があります。以下のように修正しましょう。

```bash
$ java -Xmx1024M -Xms1024M -Dlog4j2.formatMsgNoLookups=true -jar server.jar nogui
```

# まとめ

今回はEC2を使ってマイクラサーバーを立ち上げてみました。Java17のインストール方法で少し手こずりましたが、とても良い勉強になりました。サーバーの勉強をしたい方には、ちょうど良い題材だと思います。立ち上げた直後にLog4jの脆弱性が発見されたため少々焦りましたが、脆弱性の対策なども含めてよい勉強になりました。

次回はこのマイクラサーバーの立ち上げ、停止をdiscordからできるようにしていきたいと思います(もともとこれがやりたかった)。
システムの通知設定からアプリを起動させる方法

Androidではシステム設定にあるアプリの通知設定画面にアプリの設定画面を起動するリンクを設置することができます。
「アプリ内のその他の設定」というのがそれになります。
残念ながら「**アプリ内のその他の設定**」というテキストを変更することはできません。

|設定なしの場合|設定ありの場合|
|:-:|:-:|
|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/e547ca1f-2298-521b-3775-e0c8772b8136.png)|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/af360f0b-0e58-6bd2-114f-18262137d777.png)|

また、通知チャンネルごとの設定画面にも同様のリンクを表示させることができます。

|設定なしの場合|設定ありの場合|
|:-:|:-:|
|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/1ba1d1e1-42a7-2f46-8a3c-d633a5f85869.png)|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/5c183ce9-4f3b-a7ad-e713-f2558ba32a49.png)|

# 設定画面にリンクを設定する方法

アプリ内のActivityに`android.intent.category.NOTIFICATION_PREFERENCES`というカテゴリーのintent-filterを設定すると、システム設定からアプリが起動できる画面を持っていると認識されるようになり、リンクが表示されます。

```xml
<activity
    android:name=".SettingActivity"
    android:exported="true"
    >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.NOTIFICATION_PREFERENCES" />
    </intent-filter>
</activity>
```

このカテゴリーの値は[`Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES`](https://developer.android.com/reference/android/app/Notification#INTENT_CATEGORY_NOTIFICATION_PREFERENCES)で定義されています。

チャンネル設定内から起動した場合は、`android.intent.extra.CHANNEL_ID`というKeyでチャンネルIDが、また、NotificationChannelGroupを設定している場合は、`android.intent.extra.CHANNEL_GROUP_ID`というKeyでチャンネルグループIDがExtraに格納されています、通知設定のルートからの場合はExtraは設定されていません。
これらも[`Notification.EXTRA_CHANNEL_ID`](https://developer.android.com/reference/android/app/Notification#EXTRA_CHANNEL_ID)、[`Notification.EXTRA_CHANNEL_GROUP_ID`](https://developer.android.com/reference/android/app/Notification#EXTRA_CHANNEL_GROUP_ID)で値が定義されています。
Intentを受けて何らかの処理を行う場合は、以下のように実装することになると思います。

```kotlin
if (intent.hasCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)) {
    val channelId = intent.getStringExtra(Notification.EXTRA_CHANNEL_ID)
    val groupId = intent.getStringExtra(Notification.EXTRA_CHANNEL_GROUP_ID)
    ...
}
```

似たような定義値で、アプリからシステム設定を開くときにチャンネルIDを指定する`Settings.EXTRA_CHANNEL_ID`は`android.provider.extra.CHANNEL_ID`という値になっていて、違う値なのでご注意ください。

以上です。
ブロードバンド とは？

## 勉強前イメージ

そのまま行くと広い帯域的な？

## 調査

### ブロードバンド とは

具体的な定義はないですが、大容量のデータを高速で通信できる回線のことを指します。
ブロードバンドに対して遅い回線のことをナローバンドと言います。

### ブロードバンドの種類

- ADSL

`Asymmetric Digital Subscriber Line` の略で、
電話線を利用して行うインターネット接続になります。
光回線よりも遅いです。

- CATV

`Cable Television` の略で、ケーブルテレビの回線を利用したインターネット接続になります。
こちらも光回線よりも遅いです。

- 光回線

インターネット専用のブロードバンドの回線です。
ADSLやCATVより速度が早く安定してインターネットを接続することができます。

## 勉強後イメージ

イメージ感早い回線のこと？

## 参考

- [ブロードバンドとは？意味や種類をご紹介]https://quick-wifi.com/column/%E3%83%96%E3%83%AD%E3%83%BC%E3%83%89%E3%83%90%E3%83%B3%E3%83%89%E3%81%A8%E3%81%AF%EF%BC%9F%E6%84%8F%E5%91%B3%E3%82%84%E7%A8%AE%E9%A1%9E%E3%82%92%E3%81%94%E7%B4%B9%E4%BB%8B/)
基本的なReactの使い方めも

#React覚え書き
モダンなフロントエンドかけるようになりたくて、とりあえずReact始めました。
Reactを覚え中なので、そのメモを書くだけの内容です。

##propsとstate
プロパティと状態。stateは動的に変化していく

##props
呼び出し側からコンポーネントに渡すパラメータ。コンポーネント側でpropsを受け取り、使用する。

以下のように、呼び出し側からcolorを渡し、cssを動的に設定するなどできる。
childrenはcomportnentタグの中身。

```react:呼び出し側
<comportnent color="red">タグの中身</compornent>
```

```react:コンポーネント側
const comportnent = (props) => {
 const { color, children } = props;
 const compornentStyle = {
   color
 };
 return <p style={compornentStyle}>{children}</p>;
};
```

上記のコードで<font color="red">タグの中身</font>が赤文字で表示される。

##useSate(初期値);
stateの変数とその値をセットする関数（setter）を取得する。
useState()の引数として初期値を渡す。

```react:useState()
  // 初期値で"おはよう"を表示し、ボタンクリックで表示を"こんにちは"に変更する
  const [message, setMessage] = useState("おはよう");

  const changeMessage = () => {
    setMessage("こんにちは");
  };

  return (
    <>
      <button onClick={changeMessage}>changeMessage</button>
      <h1>{message}</h1>
    </>
  );
```

##再レンダリング
ReactではuseStateなどで変更がある度に、再度初めから読み込まれる。（再レンダリング）
複数の処理を記述していると何度もレンダリングされることになるため、エラーが発生することがある。
↓こういうの。


```
Error
Too many re-renders. React limits the number of renders to prevent an infinite loop.
```

React側で無限ループを防ぐ仕組みとして、再レンダリングの回数を制限してくれているらしい。
参考 ⇒ https://qiita.com/katsuomi/items/5a062dc1e4d0ab64ae21

##useEffect(function(), [var...])
"この変数が変わったときだけ処理を実行する"ということができたら便利そうです。
そこで使えるのが、useEffect()です。
第1引数で実行する関数を受け取り、第2引数に変更がされる変数を配列で指定します。
配列に指定された変数が変更されたとき、第1引数の関数を実行します。

```react:useEffect()
  const [message, setMessage] = useState("おはよう");

  const changeMessage = () => {
    setMessage("こんにちは");
  };

  // messageが変更されたときに、コンソールにメッセージを出力します。
  useEffect(() => {
   console.log({message});
  }, [message])

  return (
    <>
      <button onClick={changeMessage}>changeMessage</button>
      <h1>{message}</h1>
    </>
  );
```

##exportとdefalut exportの違い
###・defalut export
defalutでexportする場合、importの記述は上記のようになります。
import側のAppはimport側で宣言している変数なので、コンポーネントの名称と異なっていても問題ありません。
defalutの場合、1ファイルに1つしかexportできません。

```react:defaultの場合（App.jsx)
export default App;
```
```react:defaultの場合(import側)
import App from "./App";
```
```react:defaultの場合(import側)
// この書き方でもok
import Appli from "./App";
```
###・通常のexport　(どっちが通常か知りませんが。。。)
関数宣言の前にexportを記述する場合は異なります。
{}で囲って記述する必要があり、このとき記述したコンポーネント名が異なっていた場合エラーが発生します。
こちらの通常のexportの場合、1ファイルの複数のexportができます。

```react:関数宣言の前に書く場合(App.jsx)
export const App = () => {}
```
```react:関数宣言の前に書く場合(import側)
import {App} from "./App";
```
```react:関数宣言の前に書く場合(import側)
// この場合エラー
import {Appli} from "./App";
```

コンポーネント名が確約されることや、1ファイルに複数exportできることを考えると通常のexportの方が扱いやすそう。
NRF Connect for VSCode を MBP2021で使ったときにハマった所メモ

環境
pc: MacBook Pro 2021 14inch
debugger:J-link mini edu
board: adafruit feather nrf52840

VSCode以外にインストールするもの三つ
1. NRF Connect for desktop
2. NRF Connect Command line tool
3. J-Link関連ソフトウェア

どハマりポイント
M1 Mac用にビルドされたVSCodeだとデバッグはできるがJ-LinkのDLLの読み込みに失敗してフラッシュはできない。
Intelアーキテクチャ用のVSCodeとJ-Linkソフトウェアをインストールする必要がある。
Intelアーキテクチャ用でもM1Mac上で動作は問題なかった

Application作成時のボード選択のところでadafruit_nrf52840_featherを選ぶとフラッシュする所でnrfjprogがエラーが吐くので、

/opt/nordic/ncs/v1.7.1/zephyr/boards/arm/adafruit_feather_nrf52840/board.cmake　に

include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

↑を書き加えておくこと
Ethernetってなに？

## 勉強前イメージ

ネットワークのこというけど、実際はわからない・・・
規格な感じはする

## 調査

### Ethernet とは

コンピュータや電子機器をケーブルで繋いで接続する有線LANの規格になります。
IEEE802.3系とも言われています。
Ethernetがあるおかげで、メーカーが違う機器同士でも接続することができるようになりました。

### Ethernetの種類

- 同軸ケーブル

バス型(中央のバスに各端末がぶら下がってる構成)で使用されるethernetで
テレビのアンテナ線やケーブルテレビの接続で使用されています。

- 光ファイバー

インターネット回線に使用されるスター型のethernetで、
従来の方式よりも大容量のデータを高速で送受信できることで高速に通信することができます。

- LANケーブル

スター型のethernetで、機器を有線接続する際に使用します。
光ファイバーより低価格で、いろんな箇所で使われています。

### 速度

それぞれ通信速度を以下に記載しています。

- Ethernet : 10Mbps
- Fastethernet : 100Mbps
- Gigabitethernet : 1Gbps

`bps` とは伝送速度の単位で bit per secondの略になります。
1秒間に転送できるbit数を表しています。

### 10BASE-T とか・・・・

よく、伝送速度とケーブルとかによって規格を更に分けることができます。

![12021-12-12 # Ethernetってなに？ - diagrams.net - Google.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/f08c70ec-5747-b7f6-9317-ecf315bc8f4f.png)

`a` については以下が入ります。
10BASE-T だと、 10Mbpsの伝送速度だということがわかります。

| -    | 伝送速度 | 
| ---- | -------- | 
| 1    | 1Mbps    | 
| 10   | 10Mbps   | 
| 100  | 100Mbps  | 
| 1000 | 1Gbps    | 
| 10G  | 10Gbps   | 

`b` については以下になります。
10BASE-T だと、 ツイストペアケーブルが使われていることがわかります。

| -   | 伝送媒体               | 
| --- | ---------------------- | 
| 5   | 最大500mの同軸ケーブル | 
| 2   | 最大195mの同軸ケーブル | 
| T   | ツイストペアケーブル   | 
| E   | 1550nmの長波長レーザー | 
| L   | 1310nmの長波長レーザー | 
| S   | 850nmの短波長レーザー  | 
| C   | シールドケーブル       | 
| 36  | 最大3600m同軸ケーブル  | 

`c` については以下になります。
10GBASE-SR だと、 64B66B変換になります。

| -   | コード化手法     | 
| --- | ---------------- | 
| X   | 4B5B, 8B10B 変換 | 
| R   | 64B66B変換       | 
| W   | SONET準拠        | 

`d` については以下になります。
記載がない場合はシリアル伝送になります。
100BASE-T2 だと2ペア・パラレル伝送になります。

| -   | シリアル/パラレル   | 
| --- | ------------------- | 
| 2   | 2ペア・パラレル伝送 | 
| 4   | 4ペア・パラレル伝送 | 

## 勉強後イメージ

有線の規格ってことか・・・
しかも10BASE-Tとか分かればすごいわかりやすいのね。

## 参考

- [ネットワークインターフェース層の規格](https://www.pc-master.jp/words/ethernet.html)
- [有線ネットワーク規格のいろいろ](https://www.cqpub.co.jp/interface/sample/200902/if02_088.pdf)
リモートワーク化で学んだ、DX推進に必要なドキュメンテーション能力の話

2020年、2021年とコロナ禍でリモートワークが当たり前になり
誰もがオンライン上で仕事を進めなければいけない状況下にありました。
「強制的にDX化を進められた」そんな2年間だったと思います。

この2年間ひしひしと感じたのはDX化を進めるために大切なのは「ツール」でも「ITリテラシー」でもなく「ドキュメンテーション能力」だと感じました。

なのでコロナ禍で感じたドキュメンテーション能力の大切さについて書きます。

#文章を書けないと、DXできない
みなさんもこんな経験ありませんか？

- 上司から送られてきたslackのメッセージの意味がわからなく、結局オンラインミーティングをセットすることになった
- メッセージ上で合意が取れていたはずなのに、いざ話してみると認識の相違があった
- しっかりと情報を伝えなきゃと思いメッセージが長文になった。結果誰も読んでもらえなかった。

私はたくさん上記のような経験をしました。
どれだけツールが発達し、リモートワークが当たり前になったとしても、オンライン上でのコミュニケーションのメインとなる「ドキュメンテーション能力」が低いと必ず上記のようなことが起きてしまいます。
なので私は
**「DX化を進められる会社・チーム=ドキュメンテーション能力が高い」**
と考えております。

# ドキュメンテーションで心掛けていること3選
- 一文は短く
    - 一文一文が長くなると読み手は意味の理解が困難になります。そのためできるだけ一文の文量を少なく、かつ一文あたりの意味の含有量を増やすように心がけています。
- 簡単な図や表を使う
    - 文字より図や表の方が情報量を増やすことができます。そのためちょっとしたことでも構造化できるものではれば図や表を使うよう心がけています。図や表を作るのが苦手という人は箇条書きでも問題なありません。ただ文章を書くより確実に意思疎通ができるようになります。
- 強調したい箇所を明確にする
    - 「」や【】を使って囲んだり、◎や■で箇条書きをしたりなど装飾文字を使い強調したい箇所を明確にしています。「ここを読んでほしい！」という意思を明確にすることで情報伝達の効率がかなり上がります。

※ただし使い過ぎには要注意。使いすぎるとごちゃごちゃしてわかりづらくなります。

# 終わりに
上記を踏まえて最近はロジカルシンキングなどの思考法を学び直し構造的・論理的に考える力を養い、それをドキュメントに落とし込めるよう、学習を進めています。
またおすすめの書籍などご紹介できればと思います。

PS：Qiita初投稿かつアドベントカレンダー初参加でした。
Gitへ.envファイルを上げてしまったときの対処法

誤ってGitへ.envファイルを上げてしまったときの対処方
.envファイルの場所をunmachの後ろに指定してください。

```
$ git filter-branch --force --index-filter "git rm --cached --ignore-unmatch .env" --prune-empty --tag-name-filter cat -- --all
```
.gitignoreに記入してから下記を実行。

```
 git push origin --force --all
```
【PostgreSQL】SQLコマンドまとめ

## はじめに

DB検索・操作したいときに知っていると良いオプションや基礎的なことのまとめです。

少しずつ更新していきます。


## 目次

- [はじめに](#はじめに)
- [目次](#目次)
- [コマンド](#コマンド)
    - [find](#find)
    - [INSERT](#insert)
    - [UPDATE](#update)
    - [DELETE](#delete)
- [オプション](#オプション)
    - [WHERE](#where)
    - [BETWEEN](#between)
    - [ORDER BY](#order-by)

## コマンド

### find

- レコードの検索

```sql
SELECT * FROM <テーブル名>;
```

- `users` テーブルを検索

```sql
SELECT * FROM users;
```

- `*` のところはカラム名の指定もできます。

- usersテーブルの id, name にしぼって検索をする。

```sql
SELECT id, name FROM users;
```

### INSERT

- レコードの追加

```sql
INSERT INTO <テーブル名> <(カラム名1, カラム名2)> VALUES <(値1, 値2)>;
```

- `users` テーブルにレコードを追加

```sql
INSERT INTO users (id, name) VALUES (1, 'suzu');
```

### UPDATE

- レコードの内容を変更する

```sql
UPDATE <テーブル名> SET <カラム名>='<値>' where <カラム名>='<値>';
```

- `users` テーブルのidが1のレコードのnameカラムを `takahashi` に変更する。

```sql
UPDATE users SET name='takahashi' WHERE id='1';
```

### DELETE

- 指定したレコードを削除する

```sql
DELETE FROM <テーブル名> WHERE <カラム名>=<'値'>;
```

- `users` テーブルの idが1のレコードを削除

```sql
DELETE FROM users WHERE id='1';
```

## オプション

### WHERE

- `users` テーブルの `id` が `1` のレコードを検索

```sql
SELECT * FROM users WHERE id='1';
```

さらに絞り込みしたいとき

- `users` テーブルの `id` が `1` かつ `name` が `taro` のレコードを検索

```sql
SELECT * FROM users WHERE id='1' AND name='taro';
```

### BETWEEN

- 指定した範囲内のレコードを検索

```sql
SELECT * FROM <テーブル名> WHERE <カラム名> BETWEEN <値(Low)> AND <値(High)>;
```

- users テーブルの `id` が `1 ~ 10` のレコードを検索

```sql
SELECT * FROM users WHERE id BETWEEN '1' AND '10';
```

### ORDER BY 

- 指定したカラムで `sort` して検索

```sql
SELECT * FROM <テーブル名> ORDER BY <カラム名>;
```

- 昇順

```sql
SELECT * FROM users ORDER BY id;
```

- 降順

```sql
SELECT * FROM users ORDER BY id DESC;
```
Dockerのインストールでエラーが出た時の対処

# 環境
Macbook Pro(13-inch, 2018 MacOS 12.0.1)

# 実行したコマンド
`brew install --cask docker`

# 出ていたエラー
```
It seems there is already a Binary at '/usr/local/share/zsh/site-functions/_docker'.
```

# 原因
先に`brew install docker`をしていた

# 解決方法
先に`brew remove docker`をしてから`brew install --cask docker`を行う
【React】 コンポーネントが破棄されたときに変数を初期化する。

今回のテスト
カウントされるタイマーを表示し、ボタンをクリックすると、タイマーが消える。
再度ボタンをクリックすると、タイマーが表示され、カウントが開始される。

■以下親コンポーネントのコード
①子コンポーネントのTimerをインポート
②タイマーの表示有無を管理するstateであるdisplayを定義
③②のdisplayをボタンをクリックする度に変更(true,false)する処理を実装

```react:TimerContainer.js
import React,{useState} from 'react'
import Timer from './Timer'
const TimerContainer = () => {
    const [display,setDisplay] = useState(true)
    return (
        <div>
            <button onClick={()=>setDisplay(!display)}>switch timer</button>
            {display && <Timer />}
        </div>
    )
}

export default TimerContainer
```

■以下子コンポーネントのコード
①useState,useEffectをインポート
②タイマーの値を格納するstateであるcntを定義
③呼び出される度に1を足していくtime関数を作成
④初めの一回しかよばれれないuseEffectを定義する
　また、③のtime関数を1秒ごとに呼び出して、その値を格納するinterval変数を定義する
⑤Timerコンポーネントが破棄されたときに、④のintervalを破棄するclearIntervalを実装
⑥経過秒数を格納しているCntをブラウザに表示する処理を実装

```react:Timer.js
import React,{useState,useEffect} from 'react'

const Timer = () => {

    const [cnt,setCnt] = useState(0)

    const time = () =>{
        setCnt(prevCnt => prevCnt+1)
    }
    useEffect(()=>{
        const interval = setInterval(time,1000)
        return () => {
            clearInterval(interval)
            console.log("cleared")
        }
    },[])
    return (
        <div>
            {cnt}
        </div>
    )
}

export default Timer
```

■結果
カウントされるタイマーを表示され、ボタンをクリックすると、タイマーが消える。
再度ボタンをクリックすると、タイマーが表示され、カウントが開始される。
■補足
注意として、clearIntervalをコメントしても表面上の処理は同じです。
では、なぜclearIntervalをするのかというと、
一度目のコンポーネント(カウント処理)と、二度目のコンポーネント（カウント処理）は別の世界線なので、一度目のコンポーネントを破棄しているのに内部でカウント処理（setInterval）が実行されつづけ、目には見えないがブラウザの負担が増えていくことになるため。
Bookmarkletで会社の勤怠登録を効率化する

# はじめに
「バイバイ タイムカード」、「マネーフォワードクラウド勤怠」...　この世の中に星の数ほどある勤怠管理ツール。
皆様は何を使われおりますでしょうか。

私が勤める会社では「KING OF TIME」を使用しています。

# KING OF TIMEの使い心地
KING OF TIMEの使い方は簡単です。以下の用に日付の一覧が並んでいるので、各日付を選択して入力するだけです。

- 日付の一覧
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/2080dc5a-dc62-32a3-85a5-ec987a924ddd.png)

- 勤怠入力画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/4941bb2b-a3ba-2ac9-2b6b-ee0b28288193.png)

ただし...

勤怠入力の欄は手入力しなければなりません。

私が働く時間は基本的に10時〜19時で毎日同じ。

テンプレートがほしい...

# 勤怠登録効率化スクリプト
ということで、スクリプトを書いて対応します。

以下のコードをBookmarkletに登録し、勤怠入力画面で実行します。

```javascript
javascript: (function () { 
    let attendance = ['10:00', '19:00', '12:00', '13:00'];
    let i = 0;
    while(i < 4){
        document.getElementsByName(`recording_type_code_${i+1}`)[0].options[i+1].selected = true;
        timestamp = document.getElementById(`recording_timestamp_time_${i+1}`);
        timestamp.value = attendance[i];
        timestamp.focus();
        timestamp.blur();
        i++;
    };
    document.getElementById("recording_timestamp_time_1").focus();
    onClickActionButton('action_01');
}
)();
```

勤務時間に変更があるときは`attendance`をいじります。

以上で完成です。

# おわりに
あっさり終わってしまいましたが、最後までご覧いただきありがとうございました。
いいねと思った方はLGTMをいただけると幸いです。
EqualumのFS機能を試す！（検証編2）

####前回は、Equalumのファイルシステム連携機能を検証する為の、CSV利用の際のポイント（カラム属性のキャスト）と、実際に使用するストリーミングFLOW作成を行いました。今回は事前に作成済みのPythonによるCSVファイル作成ツールを使って実際に機能の動作検証を行ってみようと思います。

##まずはツールを動かします！
今回の検証は、CSVファイルを10個（それぞれのファイルはデータ10行とカラム情報の11行）作成する事にします。
![スクリーンショット 2021-12-12 9.37.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/25edf792-7ca1-874e-61b0-76f03adb65f6.png)
Equalumがストリーミング処理の結果をテーブルに処理する**「ターゲット側のテーブル」**を初期化・作成します。
![スクリーンショット 2021-12-12 10.13.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/37406e4c-8f72-e0da-fac9-eb1e4a0dfb81.png)
ツールのボタンを選択すると、ターゲット側のMySQL上に指定された名前で空のテーブルが作成されます。
ここでファイル数とデータ数を10に設定し、CSVファイルの作成ボタンを選択するとファイルの生成処理が開始されます。
![スクリーンショット 2021-12-12 10.13.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/40570d4b-5956-153b-83a6-bfab165afdb1.png)
Equalumが反応してストリーミング処理を行っている事が解ります。
![スクリーンショット 2021-12-12 9.36.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/f92b4e3f-6626-a179-69b3-0f4264714654.png)
##処理されたデータの状況をDBeaverで確認してみる
まずは、前半部分の確認・・・
![スクリーンショット 2021-12-12 12.17.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/e0992014-7081-f23d-ce3e-6ed6afbd3a59.png)
後半部分を確認・・・・
![スクリーンショット 2021-12-12 12.18.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/7096dd5a-6a87-fef6-c89a-a28ade997528.png)

無事に処理されている事が確認出来ました。

因みに、ローカルのMBP上に設置してあるCSVフォルダーは想定通りに無事に空っぽになっていました。

##まとめ
過去数回に渡り、**Equalumのファイルシステム機能を使ったCSVファイルのストリーミング処理**を検証しましたが、特に難しい箇所も無く**ノーコード**でサクッ！と利用出来ることが確認頂けたかと思います。

因みに、CSVファイルの処理状況を可視化するとこんな感じになります。

![CSV_Demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/e8586235-960b-97be-35eb-b18ba3281054.gif)

意外にリアルタイム処理されている事が解るかと思います。

参考までにCDC処理で5個のサイロDBを1個に統合し、その統合DBから用途別3個と複製1個を生成する、The CDC処理の例はこんな感じです。

![Demo5 (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/87a821c7-e357-2c9b-8fb5-162a8eb8f0a8.gif)

流石にEqualumを使った場合は、CDC処理の方が圧倒的に機能・性能ともに優秀ですが、逆に言えばCDC処理が出来ない構成でも「それなりにデータ統合や利活用が出来る！という事が解ります。

ポイント的には文字列ファイルの場合における、カラム属性の調整作業になりますが、これもGUI上で設定を行うだけで簡単に処理が行われますので、特段CSVファイルやファイスシステム機能を使う際でも、引き続き**「ノーコードで高度なデータパイプライン作成が誰でも出来る！」**という事をご理解頂けたかと思います。

CDCが効くデータベースであれば、CDC経由の即時同期（Exactly Onceサポート）が利用できますが、現実的にはデータベースのでバージョンが少し古いというケースで、CDC対応が出来ない場合が有るかと思います。またデータ頻度的にはバッチ処理からのCSVファイル渡しで問題無い！というケースも結構出てくるかと思います。

今までのアプローチであれば、機能・用途別に異なる仕組みを導入したり（コスト高要因）、苦労されて作り込まれたりしてきたかと思いますが、今後はシンプルにEqualumの統一プラットホーム上で透過的に適材適所・適宜適量的なデータ同期の環境が構築出来る様になります。

ノーコードでシンプルだけど確実・高性能なデータプラットホームが・・・という場合や、変化に即応出来るデータ利活用環境が必要・・、また複数の異なるデータ関連環境の導入・維持管理コストの高騰に悩まれている場合には、Equalumは十分検討対象になれる仕組みである！と断言出来ると思います。

因みに、ターゲットを昨今成長著しい「クラウド系サービス」に接続する事も、同じ様な手順で簡単に実現する事ができますので、利活用環境を取り合えすロケットスタートでクラウドサービスを使って・・・・という場合でも同様にノーコード環境を構築する事が可能となります。

何かのご参考になれば幸いです。
css設計の上で心がけるべきルールの考察

一人で完結する仕事が多いときはあまり感じられなかったのですが、
チームで大規模なサイトを制作するときや、お客様に制作サイトを渡して作業してもらうような
多くの人と関わるサイト制作では、コーディングの奥深さをとても感じられるようになります。


自分が設計したものを他の人に渡したときに、わかりにくかったり触りづらかったりしないように、あれこれ考えなければなりません。


そこで先輩から学んだ「設計方法ガイド」を元にcss設計の理解を深め、また現在のトレンドも考慮しつつ自分なりに理想的なcss設計を考察していこうと思います。


<h2>■CSS設計におけるルール

css設計する上でこれは守りたい、目指したいというルールです。

css設計の基礎知識であり、css設計はこれらを目的としているといえます。


・予測しやすい
・再利用しやすい
・メンテナンスしやすい
・スケールしやすい



<h2>■予測しやすい

チーム開発において、非常に重要な要素でもあるのが、コードが予測しやすこと。
これは、そのままの意味でCSSコードが予測した通りに動いてくれることを意味しています。
複雑なサイトになればなるほど、CSSも複雑化し、思い通りに機能してくれなかったり、コード同士が悪影響を及ぼす場合もあります。
そのようなことを避けるためにも、他者が読んで予測しやすいcss、class名を書く必要があります。

メインヴィジュアルの要素なら.mainvisual、記事要素なら.articleや.cardといった、ある程度具体性のあって予測がしやすいネーミングです。
別記事で書きますがコンポーネント思考を取りえれ、具体的過ぎず抽象的すぎないネーミングがいいと思われます。

抽象的すぎないネーミング、というのは最近はユーティリティファースト(※)というcss設計が注目されていますが、
ユーティリティファーストの設計は全classの共有や把握が大変なのと、htmlコードからどこがどの要素なのか、どういったパーツなのか理解しづらい、コンポーネント化するにはreact.js等が必要な為新人エンジニアや他社と連携・共有しづらい、など、私としては使いづらい印象です。

ある程度具体的で予測しやすいネーミングが理想と私は考えます。
そして後述しますが、コンポーネント設計＋ユーティリティ設計の２つを上手く組み合わせる事が効率性や共有性において理想的であると考えます。

※ユーティリティファースト・・・u-fs16で文字サイズ16px、u-boldで太字、など、各スタイルの機能をclass名とし、それらをhtmlコード上で組み合わせることでページを組み上げるというもの。


<h2>■再利用しやすい　～使いまわしやすい～

例えば異なる2ページ同士の中に似たようなパーツがあった場合、似たようなcssコードを書く場面が出てきます。
そういった場合、同じようなコードを各ページのcssに書くのではなく、1つのコードをなるべく使いまわせるように(再利用できるように)設計する。
そうすることで必要以上にコードが増えること、記述の手間が増えることを減らそうというルールです。
c-titleやc-thumbnailといったように、コンポーネント思考が大切になってきます。

<h2>■メンテナンスしやすい　(拡張しやすい)

サイトを制作していると、追加でデザインの修正依頼があったり、制作後も更新案件があったりします。
そういう時には制作者本人が修正するとは限らず、チームの他のメンバーがメンテナンスを行う場合もあります。
そういった場合に、誰がコードをいじっても修正しやすく、また管理しやすいようになっているべきでしょう。

<h2>■スケールしやすい　～スケーラブルなcss～

サイトが大規模になればなるほど、複雑になればなるほど、通常より多くのエンジニアが必要になります。
スケーラブルなcssとは、一人または大規模なエンジニアチームがそういったサイトであっても簡単に管理できることを意味します。
また、膨大な学習を必要とせずに、サイトのcss構造を簡単に理解できることも含まれます。
大規模であったり複雑なサイトであっても、共有しやすいcss設計を目指すことです。

<h2>etc..保守しやすい

他にも「保守しやすい」という要素があげられることがあるので参考までに。
Webにおいて、短期的にキャンペーンをうったりして新しい機能やルールが増えることがあります。
そういった場合に、CSSを毎回リファクタリング(※)する必要のないように日頃から設計するべきだという考えです。

(※リファクタリングとは、ソフトウェアの外部的振る舞いを保ちつつ、理解や修正が簡単になるように、内部構造を改善することです。)


参考サイト
https://philipwalton.com/articles/css-architecture/
自作ピクミンブルームLINE Botを永続化する際のメモ

この記事は、[プロトアウトスタジオ](https://protoout.studio/)の[アドベントカレンダー2021](https://qiita.com/advent-calendar/2021/protoout)の12日目です！

## LINE Botを実際に生活で使いたいよぉ

以前の記事（ https://qiita.com/tkyko13/items/335277b376c99dcc50be ）ではIFTTTとfitbitを利用して、その日歩いた結果で色々な花瓶が届くものを作ってみました。引っこ抜きボタンでその花瓶にあったピクミンが生まれるというものです。

そこで利用していたのが、[localtunnel](https://github.com/localtunnel/localtunnel)というもので、ngrokのような一時的に自分のPCをサーバにするものでした。

実際の生活で使うにはずっとPCでlocaltunnelを実行しておくのも大変なので、別のサーバを用意しないといけません。

何も自分のPCを用意する必要もなく、最近では無料で使えるクラウドサービスを使ってずっと使えるようにできるので、そちらのメモを残していこうと思います。

## LINE Botで使えそうなサービス
* [Vercel](https://vercel.com/)
* [heroku](https://jp.heroku.com/)
* [Netlify functions](https://www.netlify.com/products/functions/)
* [GoogleAppsScript](https://workspace.google.co.jp/intl/ja/products/apps-script/)
* [Firebaseのfunctions](https://firebase.google.com/?hl=ja)
* [AWSのLambda](https://aws.amazon.com/jp/lambda/)

### LINE Bot永続化参考サイト
https://qiita.com/tomosukesan/items/357c05ec58574b639089

今回は自分もVercelを使ってみたいと思います

## やったこと
* dotenv導入
* GitHubへコミット
* Vercelでプロジェクト作成
* プロジェクト、ソースコードの編集
* IFTTT、LINE developでURL編集

### dotenv導入

シークレットキーなどみんなに見られてはいけない文字列を別ファイルで管理できる

参考：https://qiita.com/ozaki25/items/3e2cf94f29bd0edc1979

いったん導入後、今まで動作させていたlocaltunnelを使ったやり方で動作確認しておきましょう

### GitHubへコミット

https://github.com/ でリポジトリを作ってコミット

忘れずに「.gitignore」に'.env'を書き加えましょう

[.gitignoreについて
](https://qiita.com/y_minowa/items/e3d8513dc31c1b378e0d)

Vercelへデプロイする際も連携してできるので、予めGitHubリポジトリから作っておくと楽です

### Vercelでプロジェクト作成

https://vercel.com/ からユーザ登録 or ログイン、プロジェクト作成します

GitHub（もしくは、GitLab、Bitbucket）のリポジトリ一覧から選ぶとすぐにできます

### プロジェクトの編集

[![Image from Gyazo](https://i.gyazo.com/6a6762f51c9c84575257814d7db46dd8.png)](https://gyazo.com/6a6762f51c9c84575257814d7db46dd8)

* apiフォルダ内に前回作ったプログラムを入れる
* vercel.jsonを作る
    * 内容は以下のような感じにIFTTTからやLINEから実行されるパスを記述する（ここらへんは上述した参考サイトを参考に）
* server.jsの編集
    * 最後の2行をVercel用に編集
    * 編集後でも普通に今まで通り動かせます

```json
{
  "version": 2,
  "routes": [
    { "src": "/", "dest": "api/server.js" },
    { "src": "/webhook", "dest": "api/server.js" },
    { "src": "/ifttt", "dest": "api/server.js" }
  ]
}
```

```js:server.js
// 略
// app.listen(PORT);
// console.log(`Server running at ${PORT}`);
(process.env.NOW_REGION) ? module.exports = app : app.listen(PORT);
console.log(`Server running at ${PORT}`);
```

編集後、改めてGitHubにプッシュしましょう

自動的にVercelにもデプロイされるはずです

「Deployments」タグを見るとちゃんとできてるか確認できます

[![Image from Gyazo](https://i.gyazo.com/66ff982f5a3db20aeb08f0a72df338aa.png)](https://gyazo.com/66ff982f5a3db20aeb08f0a72df338aa)

### IFTTT、LINE developでURL編集

[![Image from Gyazo](https://i.gyazo.com/9a1c45d8c9c97b06a5a13526fa6bcd05.png)](https://gyazo.com/9a1c45d8c9c97b06a5a13526fa6bcd05)

Vercelのダッシュボードトップを見るとDOMAINSがあり、すでにURLがもらえている状態です

まずはそのURLにアクセスし、ページが見れたらOK

その後IFTTTには、「VercelのURL + /ifttt」、LINE developには「VercelのURL + /webhook」に変更

もちろんこのURLは変更されないのでこれで永続化できました

## 使ってみて

実はなぜかまだうまく通知が来てないです…

IFTTTのActivetyではうまくいっているように見えるのですが…

もうちょっと見ている途中です〜
Windowsでgcloud コマンド起動するとpythonのエラーになるとき

# 発生したこと
Windows 10 に Cloud SDK をインストールして `gcloud components update`を実行すると、Pythonのエラーが表示される。

```
$ gcloud compnents update
ERROR: gcloud failed to load: module 'collections' has no attribute 'Mapping'
    gcloud_main = _import_gcloud_main()
    import googlecloudsdk.gcloud_main
    from googlecloudsdk.calliope import cli
    from googlecloudsdk.calliope import actions
    from googlecloudsdk.calliope import markdown
    from googlecloudsdk.calliope import usage_text
    from googlecloudsdk.calliope import parser_arguments
    from googlecloudsdk.calliope import parser_completer
    from googlecloudsdk.core.console import progress_tracker
    class _BaseStagedProgressTracker(collections.Mapping):

This usually indicates corruption in your gcloud installation or problems with your Python interpreter.

Please verify that the following is the path to a working Python 2.7 or 3.5+ executable:
    C:\Users\[username]\AppData\Local\Programs\Python\Python310\python.exe

If it is not, please set the CLOUDSDK_PYTHON environment variable to point to a working Python 2.7 or 3.5+ executable.

If you are still experiencing problems, please reinstall the Cloud SDK using the instructions here:
    https://cloud.google.com/sdk/
```

## もうちょっと詳細な状況

- 環境変数 `PATH` には `C:\Users\[username]\AppData\Local\Programs\Python\Python310` を定義しており、 ターミナル等での`python`はそちらが起動するようになっている
- `Python 3.8`はインストールしていない

# 対処法

エラーメッセージには表れていないが、環境変数 `CLOUDSDK_PYTHON` に`Python3.8`のパスを記載する。インストールしていない場合は、Python3.8をインストールして、上記の環境変数にパスをセットすればよい。

https://cloud.google.com/sdk/docs/install?hl=JA に記載があるバージョンのPythonを使用すればよい。

# 詳細解説
Cloud SDK が要求するPythonのバージョンと、ローカルにあるPythonのバージョンがずれたため、Cloud SDKがエラーを出しています。「デフォルトのPython使ったけど無理だわ！ `CLOUDSDK_PYTHON` に、動きそうなバージョンのPython指定して！（要約）」というのがエラーメッセージの内容です。

というわけで [Pythonのダウンロードページ](https://www.python.org/downloads/windows/) から必要なPythonをインストールして、そのパスを指定したらよいです。

ただ、デフォルトで動作するPythonは最新にしておきたいため、環境変数`PATH`の書き換えなどは実施していません。Pythonの仮想環境にも頼りたくなかったので、この方法になりました。

# そもそも
Cloud SDKにはPythonがバンドルされているので、面倒を避けたかったらそちらを使うほうが楽だと思います。
Word Pressのプラグインの削除方法

1. ワードプレスの管理画面から、プラグインをクリックします。
1. アンインストールしたいプラグインを無効化します
1. そうすると削除ボタンが出てくるので、削除をクリックします


以上でプラグインを削除することが可能です。
STM32L010とI2CでIOエキスパンダー化(Mbed)

x Mbed2リビジョン125

x 過去ログを見よ



目的
I2CでIOを拡張する。
金銭的には、ほぼ意味は、無い。
たまたまSTM32L010F4P6がある場合、買いに行く手間が省ける。

x まだ試していない 確認済2021/12/28

![810AA778-C5DD-48E5-A75A-330F4675E0E8.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/365dd8fe-aff5-1110-ddc1-59a61e64508c.jpeg)


おまけ


https://qiita.com/caa45040/items/28a5a23fb6e28676c1a2



```c++


//I2C_EXPANDER_1

#include "mbed.h"

//GPIOの初期化
DigitalOut myled(PB_1);//D7

//GPIOポートの初期化
//                       76543210
PortOut ledport(PortA, 0b11111110); //D0 - D6

//I2Cの初期化
I2CSlave slave(PA_10, PA_9); //010

//メイン関数
int main()
{

    char buf[10]; //I2Cバッファー

    //I2Cスレーブのアドレスの設定
    slave.address(0x80);

    //無限ループ
    while(1) {

        //I2Cの状態の読み出し(ポーリング)
        while (slave.receive() != I2CSlave::WriteAddressed) {}


        buf[0] = 0;//バッファーのクリア

        //I2Cスレーブの受信バッファーを読み取る
        slave.read(buf, 1);

        ledport = buf[0]<<1;

        myled =( ((buf[0] & 0x80) == 0)  ? 0 : 1 );

    }//while

}//main

//容量削減
void error(const char* format, ...) {}






```
【Flutter】7日間のスキマ時間で日記アプリをリリース

<a href="https://apps.apple.com/jp/app/dailyscore/id1599887461" ref="noopener noreferer" target="_blank">
  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170251/bc3fdc4b-4fe0-ffcc-b5fd-d49e474b53f4.png">
</a>

## はじめに
この記事はGAOGAO Advent Calendar 2021 ことしもGAOGAOまつりです の11日目の記事です。
昨日は、「[エンジニアの自分がなぜデザインに目覚めたのか](https://note.com/shimataro/n/n2955689946b9)」でした。

こんにちは。
世界中でモノつくりの連鎖を起こすスタートアップスタジオGAOGAOでソフトウェアエンジニアをしているしまむら([@smtrdev](twitter.com/smtrdev))です。

記事の公開が遅れてしまい申し訳ありません。実は表題の通り、1週間でアプリをリリースするチャレンジに挑戦していました。
Flutterはずっと興味があったのですが、なかなか触れる機会がなく、ないのなら機会を自分でつくってしまえとのことではじめました。

## 結論
できませんでした。
が、<b>8日間あれば</b>申請まではできました。

~~現在はストア申請中です。~~
~~公開次第ここにリンクを掲載させていただきます。。~~

承認されました。以下からDLできます。
https://apps.apple.com/jp/app/dailyscore/id1599887461


## 内容

毎日を点数（とひとこと）でコメントして、それをグラフで表示するだけのシンプルな記録アプリをつくりました。
https://dailyscore.studio.site/

<a href="https://apps.apple.com/jp/app/dailyscore/id1599887461" ref="noopener noreferer" target="_blank">
  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170251/bc3fdc4b-4fe0-ffcc-b5fd-d49e474b53f4.png">
</a>

## なぜ作ったか
理由は3つあります。
- 毎日を簡潔に振り返る仕組みを作りたかった
- コンフォートゾーンを突破したかった
- 自分のモノを作りたかった

### 毎日を簡潔に振り返る仕組みを作りたかった
今まで、Apple純正のノートに、日々の振り返りをメモしていました。

その日の点数を100点満点として自己採点した数字も、そこに記録していました。

しかし、そうすると数字をたどるのも難しいし、自分の状態に波があったとしても把握しづらいことが若干不便に感じていました。

また、このご時世で1日1日が一瞬で過ぎ去っていく感覚が怖くなり、少しでも良い明日を生きるために、毎日きちんと振り返ろう。そう思い、作成しました。

### コンフォートゾーンを突破したかった
しかし最近、自分の友人が、もしも仮にSNSで公表したらとんでもなく称賛されるような結果を残したことを知りました。
それに触発されて、自分もさらに、「実はチャレンジできるのにやれていないこと」があるのではないか。
小さなことでもいいから、頑張ってみようと思い立ちました。

7日間、しかも普通に業務もある日程を選んだのもあえてそうしました。

理由は、どうせ7日間しかないのなら、大したモノは作れません。

本当に必要なものだけを、最短で、どう作り上げるか、それだけを意識して過ごした週でした。
本業もあるので、その他以外の時間はほとんどこれの開発（企画）に時間を費やしました。

## 自分のモノを作りたかった

実は、これは自分のプロダクトです、と胸を張って言えるものを作ったことが（どうしようもないクソアプリしか）ありませんでした。

なので、まずは実際に自分が使ってみたいと思えるようなものを、形として1つ持っておきたい。
できるなら、2021年内にそれを達成したい。

その思いで、今回、アドベントカレンダーと紐付けてチャレンジしてみました。
実際に本格的に作業を始めたのは12/5(日)です。

当初は3画面ほど想定していましたが、画面遷移を極力減らしたり、UIの作り込みを諦めたり、Dartの仕様に少し戸惑いながらも、本当に最低限のモノは作れたかなと思いました。

## どう取り組んだか
本業の業務終了後に、ガッツリ調査、開発をしていました。
一方で、睡眠だけはきちんと取るようにして、無理のない範囲で進めました。


## 今後
まずは、本当に使いたいようなレベルに仕上げるところから引き続き、合間を縫って改善、メンテナンスをしていこうと思っています。

以上、7日間でアプリはリリースできなかったけど、8日間あればできた、というお話でした。
もっと具体的なことは、リリースが完了してから改めて記事として残してみようと思います。

現場からは以上です。
EqualumのFS機能を試す！（準備編）

####以前にEualumという高度なCDC技術を実装し、Kafka等の技術を上手く活用する形で「Exactly Once」のサポート等を実現した、ノーコード・データパイプライン作成・管理ソリューションを紹介しましたが、今回はある意味で「地味」に「でも、しかし！堅実に」ファイルシステム機能を使った、CSVファイル収集＆自動ストリーミングで指定されたDB上に集約テーブルを作成する検証を行いたいと思います。

##先ずは環境の準備から・・・
Equalumのファイルシステム内に直接CSVファイルを送り込んでも良いのですが、現実的には定期的で細かいCSVファイルが大量に書き込まれたりするケースが想定されるので、外部のサーバに実態を送り込んで「その状況をNFS経由で読んで処理する」方式で試してみたいと思います。

検証環境的には、仮想マシンを複数台使い（OSはCentOS7)、MBP上のPythonからCSVファイルの連続生成＆検証環境ノードへの自動転送を行います。
また、極めて私的限定環境での作業ですので、通常普通に存在いしている「ファイアーウォール」などのセキュリティが無い状況だという事をご理解頂ければ幸いです。

まずは、nfs環境の導入を関係するノードに対して行います。今回の場合は試用環境のEqualumノードと、CDCテストで利用しているMySQLノードに対して作業を行います。

~~~shell

# yum -y install nfs-utils

~~~

MySQLノード側に実態を送り込むディレクトリを作成します。今回は/var配下にcsvというディレクトリを設置しました。

~~~shell

# mkdir /var/csv

~~~

次に、このディレクトリを公開する為の設定を記述します。

~~~shell

# vi /etc/exports

公開する相手側の情報を記述します
/var/csv xxx.xxx.xxx.0/24 (rw,no_root_squash,async)

~~~

MySQLノード側の関連サービスを起動します。

~~~shell

# systemctl start rpcbind
# systemctl start nfs

~~~

次回以降に自動起動するようにしておきます。

~~~shell

# systemctl enable rpcbind
# systemctl enable nfs

~~~

無事に起動できているかを確認します。

~~~shell

# systemctl status rpcbind
● rpcbind.service - RPC bind service
   Loaded: loaded (/usr/lib/systemd/system/rpcbind.service; enabled; vendor preset: enabled)
   Active: active (running) since 月 2020-02-03 22:21:22 JST; 41s ago
 Main PID: 1711 (rpcbind)
   CGroup: /system.slice/rpcbind.service
           mq1711 /sbin/rpcbind -w

 2月 03 22:21:22 cent77-01 systemd[1]: Starting RPC bind service...
 2月 03 22:21:22 cent77-01 systemd[1]: Started RPC bind service.


# systemctl status nfs
● nfs-server.service - NFS server and services
   Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled; vendor preset: disabled)
  Drop-In: /run/systemd/generator/nfs-server.service.d
           mqorder-with-mounts.conf
   Active: active (exited) since 月 2020-02-03 22:21:30 JST; 41s ago
 Main PID: 1751 (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/nfs-server.service

 2月 03 22:21:29 cent77-01 systemd[1]: Starting NFS server and services...
 2月 03 22:21:30 cent77-01 systemd[1]: Started NFS server and services.

~~~

同様の手順でEqualumノード側を準備します。
Equalumノード側にFS接続で利用するディレクトリを作成してマウントします。今回は取り急ぎのコマンドベースで処理しましたが、/etc/fstabに記述しておけば次回以降も起動すれば使えるようになります。

~~~shell

# mkdir /var/csv

# mount -v -t nfs xxx.xxx.xxx.xxx:/var/csv /var/csv

~~~

~~~shell

# vi /etc/fstab

この行を追加（xxx.xxx.xxx.xxxはサーバ側のIPで今回はMySQLが動いているノード）
xxx.xxx.xxx.xxx:/var/csv /var/csv nfs rw,auto 0 0

~~~

無事にMySQLノード側のディレクトリと連携できている様です。

***MySQLノード側***
![スクリーンショット 2021-12-12 10.08.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/14abb8ac-7159-c24d-95f1-9efb481761eb.png)

***Equalumノード側***
![スクリーンショット 2021-12-12 10.05.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/65d4dc2d-3f55-6d29-d727-42f805a3b439.png)

##今回のまとめ
今回は、検証環境で使うNFS構成を取り急ぎ行いました。ファイアーウォールを外した環境ですので、実際の多くのケースでは**「この周辺の設定作業が必要」**だと思いますが、それらの部分については適宜作業を行うように御願い致します。

次回は、今回の検証で使用するCSVファイル作成ツールをPythonで作る作業を行います。
Amazon DevOps Guru for RDSを使ってみる

この記事は株式会社ナレッジコミュニケーションが運営する[ Amazon AI by ナレコム Advent Calendar 2021 ](https://qiita.com/advent-calendar/2021/knowcom-cloudai)の 22日目にあたる記事になります。
今回はRDSデータベースパフォーマンスのボトルネックとオペレーション問題を検出、診断する事ができるAmazon DevOps Guru for RDSについて調べてみました。

## Amazon DevOps Guru for RDSとは
Amazon DevOps Guru は機械学習 (ML) を活用したサービスで、すべてのAmazon Relational Database Service（RDS）エンジンで利用でき、アプリケーションのオペレーションパフォーマンスと可用性の改善を容易に実現できます。
具体的には、ホストリソースの過剰使用、データベースのボトルネック、SQL クエリの誤動作など、パフォーマンスに関連するさまざまなデータベースの問題を自動的に特定して分析します。
そして問題が検出されると、DevOps Guru for RDS はその結果を DevOps Guru コンソールに表示し、Amazon EventBridge またはAmazon Simple Notification Service (SNS) を使用して通知を送信します。これにより、デベロッパーは課題を自動的に管理し、リアルタイムでアクションを取ることができるというものになります。

料金は1インスタンスにつき $0.0042/h

## DevOps Guruを使うには
DevOps Guruの新機能を使うにはAmazon Aurora DB インスタンスで Performance Insights が有効になっていることが条件となります。
ちなみに東京リージョンでも利用可能です！

## 実際にさわってみる
今回はAmazon DevOps Guruの設定まで行ってみたいと思います。

使ってみるにあたり、もちろんRDSが必要になります。
現在DevOps GuruではAurora（MySQL / PostgreSQL）のみ対応しているのでテスト用を作成する場合はAuroraで作成しましょう。
（2021/12/15時点）

ダッシュボードに入りたての状態だと以下の画面のような状態でした。
分析されているリソースがない事がわかります。

![A_2021-12-12_12h30_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954355/dd34a8ed-109a-78fb-12c7-440629a25519.png)

ここで分析するリソースを指定する必要がありますが、方法はいくつかありそうです。
今回はタグをつける事でリソースを指定しようと思います。

RDSに「Devops-Guru-RDS」の名称でタグをつけました。
（「Devops-Guru-」の文字が含まれている必要がある）
次にDevOps GuruのAnalyzed resourcesのページへ移行し、Tagsを設定し、保存します。

![B_2021-12-12_12h31_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954355/e637fdb1-559b-2a4e-f675-3dfd4d2c1ff4.png)

これで準備は完了です。
データ収集を待ちましたが、大体15分ほどかかった気がします！

![C_2021-12-12_12h31_50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954355/ee498d50-2ffe-efae-391a-50eeaecbfd65.png)

正常に認識されたようです！

![D_2021-12-12_14h08_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954355/6f284fb4-b867-e4af-63fa-67df9955fd55.png)

## ■最後に
DevOps Guru for RDSの設定について記載してみました。
今回は実証できませんでしたが、DevOps Guru for RDSでは定期的な負荷上昇ではなく異常値を検出することができます。
異常値検出に関してはAWSの膨大な内部運用データでトレーニングされている機械学習モデルとなる為とても心強いですね。
次は負荷をかけてみて実際の動作も確認したい所です。
【TryHackMe】Advent of Cyber3 (2021)を続けてみた Day10

# Welcome to Advent of Cyber 2021
クリスマスまでの25日間、毎日基本的な知識を学び、初心者向けの新しいセキュリティ演習を行うことで、サイバーセキュリティを始めることができます。

https://tryhackme.com/room/adventofcyber3

# day10
攻撃者がどのようにしてネットワークに侵入するかを学びます。

`nmap`を使って、基本的なネットワークポートスキャンを実行できます。

```
┌──(kali㉿kali)-[~]
└─$ nmap -sT 10.10.16.140 -o nmap-log
Starting Nmap 7.92 ( https://nmap.org ) at 2021-12-12 12:44 JST
```


# Answer
Help McSkidy and run nmap -sT MACHINE_IP. How many ports are open between 1 and 100?
<font color="White">2</font>
What is the smallest port number that is open?
<font color="White">22</font>
What is the service related to the highest port number you found in the first question?
<font color="White">http</font>
Now run nmap -sS MACHINE_IP. Did you get the same results? (Y/N)
<font color="White">Y</font>
If you want Nmap to detect the version info of the services installed, you can use nmap -sV MACHINE_IP. What is the version number of the web server?
<font color="White">Apache httpd 2.4.49</font>
By checking the vulnerabilities related to the installed web server, you learn that there is a critical vulnerability that allows path traversal and remote code execution. Now you can tell McSkidy that Grinch Enterprises used this vulnerability. What is the CVE number of the vulnerability that was solved in version 2.4.51?
<font color="White">CVE-2021-42013</font>
You are putting the pieces together and have a good idea of how your web server was exploited. McSkidy is suspicious that the attacker might have installed a backdoor. She asks you to check if there is some service listening on an uncommon port, i.e. outside the 1000 common ports that Nmap scans by default. She explains that adding -p1-65535 or -p- will scan all 65,535 TCP ports instead of only scanning the 1000 most common ports. What is the port number that appeared in the results now?
<font color="White">20212</font>
What is the name of the program listening on the newly discovered port?
<font color="White">telnetd</font>
テスト分析は素因数分解と 合同・MOD (余り) のグループ化という考え方

# はじめに
製品やサービスのテスト設計をするまえに、様々な機能においてテスト分析をしていくと思います。
(機能だけではなく、非機能とかあったり品質全般的な話もありますが、ここでは省略します。あくまで機能的なところだけを話します。)

20年弱前まで開発者であったテスター & QA ですが、そんな私が開発視点よりでテスト分析するときに考えていることを少し書いてみます。


# 結論
結論を先に出しておきますが、テスト対象を分析するときで以下のことを考えてみればどうでしょうか。
それを考えるために中学生の数学 (因数分解と 合同・MOB) を使って説明してみようと思います。

* テスト対象を細かく分解すること (可能であればクラス設計と同じ視点で考えてみる)
* テスト対象をほかのものと比較して同じもの、異なるものを探すこと


# 素因数分解とは？
中学生の数学で習う「素因数分解」ですが、ある正の整数を素数のかけ算で表すことです。
素数とは primary number とも言われて、1 とそれ自体でしか割り切れない数字のことです。

たとえば、「12」という数字を素因数分解すると「2*2*3」です。

このように 1 を除いて自分自身でしか割り切れない数字に分解したものです。

# 合同・MOD (余り)
MOD (余り) とは、割り算の余りのみに注目した等式のことです。
例えば、合同式で書くと以下のようになります
7≡4(mod 3)
7≡6(mod 1)


# テスト対象の素因数分解
さて、数学的なことはさておき、機能の素因数分解を考えてみます。
テストをするときに例えば、「設定を保存する」とか書かれていた時にどのように考えるでしょうか？

こいつを素因数分解のように分解して、これ以上分解できない(と思える)ぐらいにしていきます

* どこに保存するのか
* 何の設定を保存するのか
* どのように保存するのか
* いつ保存するのか
* ...etc

どれだけ分解してこれ以上分解できないまでにしていきます。
分解するにあたって 5W1H が役に立つかと思います。


# テスト対象の合同・MOD
たとえば「設定を保存する」というテスト対象ですが、製品 (サービス) には、1つではなく複数あると思われます。

その対象をすべてテストするのは非常にコストがかかるため、いずれか1つをテストすればあとは同じだからテストしなくてもいいとしたいはずです。

そこで出てくるのが合同・MOD です。対象 A はファイルに、対象 B は DB に保存するとしましょう。
そのときに考えられるのが例えば以下のように分解できます。

そこで、標準出力する部分は共通になるので、どちらかをテストすればよいという判断になります。

対象A 設定を保存 ≡ 標準出力 (mod ファイル)
対象B 設定を保存 ≡ 標準出力 (mod DB)

このように、テスト対象の共通項を見出して、テストを絞り込んでいきます。
経験談からいうと、特に余りの部分に「バグ」が潜んでいます。

# まとめ
テスト対象の機能をテスト分析をするときには、素因数分解のように細かくしていくことをお勧めします。
そして、テスト対象の機能がほかの製品や機能と共通項と仲間外れをみつけて重点的にテストしてみましょう。


# 余談
テスト対象がモノリシスすぎて、分解できないことがあります。
たとえば、「127」が素数か？と聞かれると多分素数と感覚になりますが、「67280421310721」が素数か？と聞かれたらわからん。。。となります。(素数らしいですが)

テスト対象も同じで、あまりにも大きすぎると分解できるのかどうか(何をもって分解するのか)判断できなくなります。
製品 (サービス) が大きくなるとリファクタリングできなくなるのと同じです。(プログラムだけではなくテスト設計も日々のリファクタリングが必要です)

このような状況にならないためには、もちろん設計が大事ですが、日々のリファクタリングを怠らずに実施することです。


「67280421310721」みたいな大きな機能がひとまとめでやってきてテストしろ (バグをみつけて) というのはイケてないです。

イケてない状況になるのには、様々な要因があると思いますが、テスト担当者は常に対象物を素因数分解と合同・MOD を考えて開発担当者にフィードバックをかけて、リファクタリングできる間に実施してもらいましょう。
Splunk: BY句のフィールド名を列名にした時系列統計データを作成したい場合はtimechartコマンドではなくstatsコマンドを使用するべし

しばしば必要となるのでメモ。

###### 実施環境： Splunk Free 8.2.2

###### やりたいこと

以下のデータから、時系列統計データを作成することを考えます。

```Splunk:Splunk
| makeresults count=5
| streamstats count AS CNT
| eval _time = _time - CNT * 60 * 30
| eval TEST = "A"
```

![スクリーンショット 2021-11-28 17.46.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/47453659-de3b-f542-85e1-0de509bc01b5.png "元データ")

このような場合、一般的には timechart コマンドを使用して統計を作成します。

```Splunk:Splunk
| makeresults count=5
| streamstats count AS CNT
| eval _time = _time - CNT * 60 * 30
| eval TEST = "A"
| timechart span=1h count BY TEST 
```

![スクリーンショット 2021-11-28 17.48.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/7c690c82-e18d-9970-8174-65cf8a507ffc.png "timechart")

上記の例を見ると、 timechart コマンドを使用した場合、作成されるデータは以下のように BY 句のフィールドの「値」(今回は `TEST = "A"` の A )を列名にした形になります。

| _time | A |
|:-----------|------------:|
| 2021/11/27 23:00 | 0 |
| 2021/11/28 00:00 | 0 |
| 2021/11/28 01:00 | 2 |
| 2021/11/28 02:00 | 2 |
| 2021/11/28 03:00 | 1 |

ここからグラフにしたりする場合はこの方が都合がよいですが、サマリーとして別のインデックスに格納する場合等、以下のように BY 句のフィールドの「フィールド名」(今回は `TEST = "A"` の TEST )を列名にした形にしたいことがあります。

| _time | TEST | count |
|:-----------|:-----------|------------:|
| 2021/11/28 01:00 | A | 2 |
| 2021/11/28 02:00 | A | 2 |
| 2021/11/28 03:00 | A | 1 |

このような場合はどうすればよいでしょうか。

###### 実現方法

答えは、「 timechart コマンドではなく stats コマンドを使用する」です。
ただし、ただ単に timechart コマンドを stats コマンドに入れ替えても求めるデータは得られません。
 bin コマンドを使用して、 _time の値を一定時間(今回は1時間)毎にまとめる必要があります。

```Splunk:Splunk
| makeresults count=5
| streamstats count AS CNT
| eval _time = _time - CNT * 60 * 30
| eval TEST = "A"
| bin span=1h _time
```

![スクリーンショット 2021-11-28 17.53.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/041e6d58-3a17-720d-eafe-43e3d7aea33b.png "bin")

まとめた _time を BY 句に指定することで、求めるデータが得られます。

```Splunk:Splunk
| makeresults count=5
| streamstats count AS CNT
| eval _time = _time - CNT * 60 * 30
| eval TEST = "A"
| bin span=1h _time
| stats count BY _time, TEST
```

![スクリーンショット 2021-11-28 17.53.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/16ba988b-abfa-97da-378e-90bfcfda3bfc.png "stats")
[Node.js] Nodemailerで２通以上同時にメールを送信する

この記事は、【 [可茂IT塾 Advent Calendar 2021](https://qiita.com/advent-calendar/2021/kamo-it) 】の17日目の記事です。

Webの作成で実装したことを記事にしました。
誰かのお役に立てれば、幸いです。

お問い合わせフォームに入力した内容を入力者と企業に２通同時に確認メールを送るAPIを作成しました。
そこで`nodemailer`を使用したので、まとめて記事にしました。

## Nodemailerでメールを送信する。

Nodemailerをインストールします。

https://www.npmjs.com/package/nodemailer

```
npm i nodemailer
```

### フォーム側

```typescript
  const [fieldValues, setFieldValues] = useState<FieldValues>({
    // 各フォームの初期値
  })

  const onSubmit = async () => {
    const url = `/api/contact` //apiを作成したディレクトリ
    await axios.post(url, fieldValues) //axiosを使って送信
  }
```

数行ですが、Typescriptで書いてます。
今回の記事はAPIについてなので、フォームについては必要な部分のみとさせていただきます。

### API側

```javascript
const nodemailer = require('nodemailer')

// SMTPサーバの設定
const mailer = nodemailer.createTransport({
  host: 'mail.example.com', // ホスト名
  port: 465, //ポート
  secure: true,
  auth: {
    user: process.env.MAIL_AUTH_USER, // 環境変数（ユーザ名）
    pass: process.env.MAIL_AUTH_PASS, // 環境変数（パスワード）
  },
})

export default async (req, res) => {
  const {
    // フォームから送信された情報
  } = req.body

  const senderEmailAddress = 'from_test@example.com'
  const receiverEmailAddress = 'to_test@example.com'

  // メールの内容
  const mailOptions = {
    from: `送信元名 <${senderEmailAddress}>`, //　送信元メールアドレス
    to: receiverEmailAddress, //　送信先メールアドレス
    subject: '{件名}',
    text: '{本文}',
  }

  // メール送信
  mailer.sendMail(mailOptions, function (error, success) {
    if (error) {
      console.log(error)
      res.status(500).send('送信に失敗！')
    } else {
      console.log(success)
      res.status(200).send('送信に成功！')
    }
  })
}
```

## メールを２通以上同時に送る場合

### 同じ内容のメールを複数の人に送る場合

この場合は、送信先を配列にするだけです。

```javascript
const receiverEmailAddressList = ['to_test1@example.com','to_test2@example.com','to_test3@example.com']

  // メールの内容
  const mailOptions = {
    from: `送信元名 <${senderEmailAddress}>`, //　送信元メールアドレス
    to: receiverEmailAddressList, //　送信先メールアドレスリスト
    subject: '{件名}',
    text: '{本文}',
  }
```

### 違う内容のメールを複数の人に送る場合

下記では、`Promise.all`を使って`mailer.sendMail`をそれぞれ実行させています。

```javascript
  const senderEmailAddress = 'from_test@example.com'
  const testMailAddress_1 = 'to_test1@example.com'
  const testMailAddress_2 = 'to_test2@example.com'

  // メールの内容
  const mailOptions1 = {
    from: `送信元名 <${senderEmailAddress}>`, //　送信元メールアドレス
    to: testMailAddress_1, //　送信先メールアドレス
    subject: '{件名}',
    text: '{本文_1}',
  }

  const mailOptions2 = {
    from: `送信元名 <${senderEmailAddress}>`, //　送信元メールアドレス
    to: testMailAddress_2, //　送信先メールアドレス
    subject: '{件名}',
    text: '{本文_2}',
  }

  // メール送信
   Promise.all([mailer.sendMail(mailOptions1), mailer.sendMail(mailOptions2)])
    .then((respose) => {
      console.log(respose)
      res.status(200).send('送信に成功！')
    })
    .catch((error) => {
      console.log(error)
      res.status(500).send('送信に失敗！')
    })
```

## 最後に

いろいろと情報収集して、この形になりました。参考にしたサイトは、下に貼ってあります。たいへん助かりました。
もし、間違っているところやよりよい方法をご存知の方がいれば、ご指摘いただけると助かります。

## 参考
https://qiita.com/shun_xx/items/623ca176511aa0e4c49d

https://qiita.com/yanchi4425/items/f722a18ecc483d7f5e1b

https://nodemailer.com/about/