OmniAICreator/Qiita-1.07M huggingface dataset:
Elixir/PhoenixでJSONパーサーAPIを作ってみる。

# はじめに

naritomoと申します。

本職はインフラエンジニアを行っています。
これまでアプリ領域の技術習得のため、各種言語の開発環境Dockerの構築を行ってきましたが、Phoenixでのアプリ第一号を作ってみましたので、公開したいと思います。

いろいろアドバイスいただけると嬉しいです。

## 開発概要

以下の仕様とします。

* API稼働フレームワークはElixir/Phoenixを使用する。
* API入力は、以下のものを入力する。
  - URLにクエリでJSONキーを指定する。(?key=key1)
  - POSTボディーにJSONデータを入れる。
* API出力は以下のものとする。
  - クエリで指定したJSONキーに対応した値をプレーンテキストで出力する。

## 事前準備

以下の記事を参考にElixir/Phoenix開発環境を構築してること。
Appコンテナにログインしてること。

https://qiita.com/naritomo08/items/fecf4ace7b9ca9078102

## API構築方法

### プロジェクト作成

プロジェクトを作成する。

```bash
mix phx.new my_api --no-ecto
→yを選択する。
cd my_api
```

### APIソース作成

コントローラファイルを作成する。

```bash
vi lib/my_api_web/controllers/json_value_controller.ex
```

ファイル内容

```bash
defmodule MyApiWeb.JsonValueController do
  use MyApiWeb, :controller

  def extract(conn, %{"key" => key} = params) do
    json_data = Map.delete(params, "key")

    case Map.fetch(json_data, key) do
      {:ok, value} ->
        text(conn, to_string(value))
      :error ->
        json(conn, %{error: "Invalid JSON data or key not found"})
    end
  end
end
```

ルートファイルを開く。

```bash
vi lib/my_api_web/router.ex
```

編集内容

```bash
defmodule MyApiWeb.Router do
  use MyApiWeb, :router

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/api", MyApiWeb do
    pipe_through :api
　　# 以下の1行を追記
    post "/json_value", JsonValueController, :extract
  end
```

コンフィグファイルを開く

```bash
vi config/dev.exs
```

以下のように編集する。

```bash
12行目を以下のように編集する。
http: [ip: {0, 0, 0, 0}, port: 4000],
```

### API立ち上げ

以下のコマンドで立ち上げる

```bash
mix phx.server
```

### 動作確認

新しいターミナルを立ち上げ、以下のコマンドを入力する。

```bash
curl -X POST -H "Content-Type: application/json" -d "{"name": "John", "age": "30"}" "http://localhost:4000/api/json_value?key=age"
```

30という値が返ってくること。

# おわりに

Phoenixでのアプリ開発第一歩として、JSONパーサーAPIを構築してみました。

この作成にはchatgptも利用して構築しています。

この記事がPhoenixでのAPIを作ってみたい方の助けになればと思います。
ChatGPTと協力してcommit-msgを作った

## はじめに
昔からコミットメッセージをおしゃれにしたいなーって思っていました。
しかし、やる気が出ず後回しにしていました。

そんなときに、ChatGPTというものが出てきたので、実験台としてペアプロをしてみました。
ついでにQiitaのイベントに乗っかりました。

https://qiita.com/official-events/b80ebe828fa453edf260

## どういうものを作ったか

1. `prefix/コミットメッセージ本文`の形式でcommitする
1. commit-msgが絵文字を装飾したり見やすいように整えてくれる

例えば`update/ファイル更新`, `add/ファイル追加`, `remove/ファイルの中身を削除`のフォーマットでcommit→pushしたら下図のようになります。  

![スクリーンショット 2023-03-23 222243.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2716775/ce8936cb-b912-000d-1f79-e16e7942af66.png)

書いたコードはこちら。  
※色々見やすい方向に書き換えているため、上図のような形式になっているとは限りません。
この記事では上図のようなcommit-msgを作る方法になっています。

https://github.com/valusun/my_commit_msg  

## ChatGPTとのペアプロの進め方

### Step1. どういうものを作りたいのか要件整理をする

いくらChatGPTが万能だとは言え、要件が決まってないとモノは作れません。  
作りたいモノの要件は粗方決まっていたので、下記の通り整理しました。

```text
# Goal
決まったフォーマットで入力したときに、絵文字を装飾してお洒落にする。
決まったフォーマット以外は、エラーで弾く。

## フォーマット
`prefix/commit-msg`の形式。

### prefixの種類
下記の4つを対象にする
- add: 新規ファイルの追加などで使用する。クラッカーの絵文字を付ける。
- update: ファイルの更新などで使用する。キラキラの絵文字を付ける。
- remove: ファイルの削除などで使用する。爆発(?)の絵文字を付ける。
- fix: バグの修正などで使用する。虫の絵文字を付ける。

## 変換後  
`[{絵文字}prefix{絵文字}] コミットメッセージ本文` の形式に変換する
(上の画像を参照)
```

### Step2. ChatGPTにお願いする。

この時、自分はまだcommit-msgについて何も知らなかったので、まずは下記のように質問してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2716775/940f80e0-4431-fc63-7903-33a7ef67358e.png)

それっぽいコードが出てきましたが、それ以上に自分はcommit-msgがPythonで書けることに驚きました。  
(bashが出てくることを想定していたので、bashを解説してもらいながら進めるつもりでした)

コードを読むと何となくやっていることが見えてきました。
1. 何らかのファイルを読み込む
1. `update/`から始まっていれば`[update] hoge`を生成する
1. ファイルの先頭に移動して、2.で作った文言を追加する
1. 現在の位置にある(追加した文言)以降の文字列を削除する(変換前の文言を削除)

では、手順1で読み込んでいるファイルは何でしょうか？
ここはChatGPTに聞いてもへーで終わりそうだったので、自分で調べてみました。    

https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA-Git-%E3%83%95%E3%83%83%E3%82%AF

> commit-msg フックは、開発者の書いたコミットメッセージを保存した一時ファイルへのパスをパラメータに取ります

### Step3. 絵文字を追加する

調べたら一瞬で出てきました。これをコミットメッセージに追加すれば出来そうですね。

https://qiita.com/Jung0/items/0a9a7a97a2c17f92d3c5

こんな感じ
```python
new_commit_msg = "[:sparkles:update:sparkles:] " + commit_msg.split("/", 1)[1]
```


### Step4. リファクタリングと拡張  

ChatGPTが書いたコードは下記の理由から動きません。
withを抜けているのにもかかわらず、`f.seek(0)`と操作をしようとしているためです。  
なので、最低限下記のように改善させる必要があります。

```python
with open(commit_msg_file, "r+") as f:
    commit_msg = f.read().strip()
    if commit_msg.startswith("update/"):
        new_commit_msg = "[update] " + commit_msg.split("/", 1)[1]
    f.seek(0)
    f.write(new_commit_msg)
    f.truncate()
```

さて、次は拡張ですね。
毎回`startswith(...)`を書くのはめんどくさいので、`match/case`にしてみました。
```python
prefix, msg = commit_msg.split("/", 1)
match prefix:
    case "update":
        emoji = ":sparkles:"
    case "add":
        emoji = ":tada:"
    case "remove":
        emoji = ":boom:"
    case "fix":
        emoji = ":bug:"
    case _:
        raise SyntaxError("Commitメッセージに構文の誤りがあります")
    new_commit_msg = f"[{emoji}{prefix}{emoji}] {msg}"
```

後は良い感じにコードを整えて完成しました！  
  
## ChatGPTを使った感想

知見外の何かを作る際のペアプロ相手としてはちょうどいいかもしれません。  
しかし、上のコードのように甘い部分があるので鵜呑みにはできません。
そのあたりも「本当か？」と思いながら調べつつ進めていけば知識も付いていくのではないか、と思います。  

***

追記: ChatGPTから案だけ貰って改良したからペアプロとは呼ばないなと思ったのでタイトルを変えました
Python3: ChatGPT API の使い方

こちらのページを参考にしました。
[遂に公開されたChatGPT APIとは？ 利用するまでの流れ【ハンズオンで徹底解説】](https://saasis.jp/2023/03/06/%E9%81%82%E3%81%AB%E5%85%AC%E9%96%8B%E3%81%95%E3%82%8C%E3%81%9Fchatgpt-api%E3%81%A8%E3%81%AF%EF%BC%9F-%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B%E3%81%BE%E3%81%A7%E3%81%AE%E6%B5%81%E3%82%8C%E3%80%90/)

## プログラム

```py:fujisan.py
#! /usr/bin/python
#
#	fujisan.py
#
#						Apr/02/2023
#
# --------------------------------------------------------------------
from dotenv import load_dotenv
import openai
import os
import sys

# --------------------------------------------------------------------
sys.stderr.write("*** 開始 ***\n")

dotenv_path = '.env'
load_dotenv(dotenv_path)
API_KEY = os.environ.get("API_KEY")

openai.api_key = API_KEY

response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "user", "content": "富士山の高さは"},
    ]
)
print(response["choices"][0]["message"]["content"])

sys.stderr.write("*** 終了 ***\n")
# --------------------------------------------------------------------
```

```text:.env
API_KEY="sk-11******************************************"
```

## 実行結果

```text
$ ./fujisan.py 
*** 開始 ***
3,776.24メートルです。
*** 終了 ***
```

## 確認したバージョン

```text
$ python --version
Python 3.10.10
```
商談録音アプリ「キクカチ」にchat GPTで文章を要約する機能を追加してみた

# はじめに
社内で活用している「キクカチ」という音声録音アプリには、長時間にわたる会議や講演の音声を録音・共有する機能があります。しかしながら、大量の録音データを扱う場合には、データの内容を把握することが困難になることがあります。
そこで、音声データを文字に起こし、要約する機能を追加しました。これにより、データを簡潔にまとめることができ、情報を把握するのにかかる時間を短縮できます。

*私がインターンをしている、株式会社PeerLodgeの社内ハッカソンで開発したものです。

# 機能
* firebaseに保存されている、音声を文字に起こしたデータを要約して、firebase上に保存&アプリ上に表示
* 音声データを文字に起こす機能は[こちら](https://qiita.com/katsuya12321/items/c087154366219cbbe010)の記事で説明しています。

# 環境
Swift

使用したOpenAI APIのモデル
* Whisper
* gpt-3.5-turbo

# 準備
* OpenAISwiftをインストール
    * File > Add Packagesで検索窓に下記を入力する。
    https://github.com/adamrushy/OpenAISwift
    * OpenAISwiftを追加

# 実装
## APIを使用して文章を要約するファイル
```Swift
import OpenAISwift
import Firebase

// OpenAI APIを使用して、与えられたテキストを要約する関数
func generatedAnswer(text: String) async -> String! {
    let env = ProcessInfo.processInfo.environment
    guard let openAI_API_Key = env["OPENAPIKEY"] else {
        print("環境変数にOpenAI API Keyを設定してください")
        return nil
    }

    let openAI = OpenAISwift(authToken: openAI_API_Key)
    do {
        let chat: [ChatMessage] = [
            // ChatMessageオブジェクトを生成して配列に追加
            ChatMessage(role: .system, content: ""),
            // ユーザーの発言をChatMessageオブジェクトに入れて配列に追加
            ChatMessage(role: .user, content: "以下の文章を200字程度で要約してください。" + text),
            // 要約された文章をChatMessageオブジェクトに入れて配列に追加
            ChatMessage(role: .assistant, content: "")
        ]
                    
        // OpenAI APIにChatMessageオブジェクトの配列を送信して要約を取得する
        let result = try await openAI.sendChat(with: chat)
        // 要約されたテキストを出力して返す
        print(result.choices.first?.message.content ?? String.self)
        return result.choices.first?.message.content
    } catch {
        // エラー処理
        print("error")
        return nil
    }
}

// Firebase上のデータを更新する関数
func updatePost(_ postId: String, _ summary: String, completion: @escaping (Bool) -> ()) {
    // UserDefaultsからcompanyIdを取得する
    let ud = UserDefaults.standard
    guard let companyId = ud.string(forKey: "companyId") else {
        return
    }
    // Firebase上のデータを更新する
    Firestore.firestore().collection("companies").document("\(companyId)").collection("posts").document("\(postId)").updateData([
        "summary": summary,
    ]) { err in
        if let err = err {
            // エラー処理
            print("Error update documet: \(err)")
            completion(false)
        }
        else {
            // 成功時の処理
            print("Document successfully update")
            completion(true)
        }
    }
}
```

# おわりに
「キクカチ」に要約機能を追加することで、長時間の会議や講演の音声データを簡潔にまとめることができ、情報の把握にかかる時間を大幅に短縮できるようになりました。
今後AIへの指示の仕方を変えることで、要約だけではなく、内容の評価や開演点を提案することができるようになります。
これにより、ビジネスシーンやプライベートな場面での「キクカチ」の活用価値が一層高まることが期待されます。

# 参考
https://dev.classmethod.jp/articles/open-ai-swift-example/
TypeScript mysqlからzodの型を取得するスクリプトをnpmに公開

mysqlからzodの型を取得するスクリプトを書きました。

https://www.npmjs.com/package/mysql-to-zod

## 使い方

```sh
npx mysql-to-zod mysql://root:root@localhost:3306/db
```

mysqlToZodフォルダ内のscheme.tsにDBの型が生成されます。
## 出力結果

```schema.ts
import { z } from "zod";

export const USERSchema = z.object({
  ID: z.number(),
  NAME: z.string(),
  AGE: z.number(),
  EMAIL: z.string(),
});
export type USER = z.infer<typeof USERSchema>;
```

yarnでinstallした際はオプションもいろいろあります。
rootdirにmysqlToZod.config.jsを作成します。

```ts:mysqlToZod.config.js
const options = {
  isAddType: true, //export type A = z.infer<schema>を追加するかどうか
  isCamel: true, //tableNameをcamelにするかどうか
  isTypeUpperCamel: true, //upperCamelにするかどうか
  outFilePath: "mysqlToZod", //dir
  fileName: "schema.ts", //fileName
  dbConnection: "mysql://root:root@localhost:3306/mydb", //実行時第一引数が優先。第一引数がないときはconfigを見に行く。どちらもないときはエラー。
  tableNames: [], //空のときは全テーブルを取得。テーブルが指定されたときは、そのテーブル名で見に行く。
};
module.exports = options;
```

ちなみにmysqlの型からzodに変換するところはこんな感じです。

```ts
export const convertToZodType = (type: string) => {
  switch (type) {
    case "TINYINT":
    case "SMALLINT":
    case "MEDIUMINT":
    case "INT":
    case "BIGINT":
    case "FLOAT":
    case "DOUBLE":
      return "z.number()";
    case "BIT":
      return "z.boolean()";
    case "DATE":
    case "TIME":
    case "DATETIME":
    case "TIMESTAMP":
    case "YEAR":
      return "z.date()";
    case "CHAR":
    case "VARCHAR":
    case "DECIMAL":
    case "NUMERIC":
    case "TINYTEXT":
    case "TEXT":
    case "MEDIUMTEXT":
    case "LONGTEXT":
    case "ENUM":
    case "SET":
      return "z.string()";
    case "BINARY":
    case "VARBINARY":
    case "TINYBLOB":
    case "BLOB":
    case "MEDIUMBLOB":
    case "LONGBLOB":
      return "z.buffer()";
    default:
      return "z.unknown()";
  }
};
```

注1：JSのDate型はJSONで送ろうとするとISOstringになる(はず)。superjsonなどのライブラリを使用するか、型をstring型にするか。
注2:enumはzodのunionにするべきだと思うが、まだ未作成。

YEARはnumber型のlength4だな、とかいろいろ思うところはあるが未調整……。そのうちつくる。

本当はzodのnonnegativeとか、text255だったらlength設定するとか、いろいろやらんといかんのだけれど、ひとまず自分なりに業務で使えるところまでつくったので仮完成。あとは少しずつ完成度を高めていこう。

README書いたりしないとね……。
MT5ストラテジーテスターレポートをPython「QuantStats」ライブラリで分析する

この記事は、MT5ストラテジーテスターレポート(HTML)を、パフォーマンス分析ライブラリ「QuantStats」で詳細な分析レポートを作成するための前処理のメモです。
ソースコードの品質に関してあまり気にしていないのでムダなところがあるかもしれませんが、予めご了承下さい。

MT5ストラテジーテスターレポート(HTML)とはこのようなものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1882169/9d1c2238-e168-d181-2c16-a97687213cd8.png)
今回はこのレポートをPythonで読み取って、QuantStatsで詳細分析してみましょう。

# データ取得と前処理
QuantStatsでは、このような日時と残高データが必要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1882169/6a052ec6-9fb2-1b78-d481-86fb539e6d3d.png)

### HTML読み取り
MT5ストラテジーテスターレポート(HTML)を読み取って前処理をしていきます。
まず、MT5ストラテジーテスターレポート名を指定してread_html関数でpandasデータフレームに取得します。
```Python
import pandas as pd
df = pd.read_html('EA_IntradayPatternsEURUSD.html') # ファイル名を指定
```

### 約定情報の取得
次に取得したデータフレームから約定情報のみを取得します。今回は"時間"と"損益"、"残高"以外のデータは必要ないですが、ついでに他のも含めて型変換しておきます。
```Python
df=df[1]

# 最初のカラムの中身が'約定'である行のインデックスを取得
index = df.index[df.iloc[:, 0] == '約定'].tolist()[0]

# '約定'である行より下の行を別のデータフレームに格納
deals = df.iloc[index+1:].reset_index(drop=True)
deals = deals.iloc[0:-2].reset_index(drop=True)# 上から2行と下から1行を削除
deals.columns = deals.iloc[0]# 一番上の行を列名とする
deals = deals.iloc[2:].reset_index(drop=True)

deals['時間'] = pd.to_datetime(deals['時間'])
deals['約定'] = deals['約定'].astype(int)
deals['注文'] = deals['注文'].astype(int)
deals['数量'] = deals['数量'].astype('float64')
deals['価格'] = deals['価格'].astype('float64')
deals['損益'] = deals['損益'].str.replace(' ', '').astype('float64')  # 半角スペースを削除してからfloat64型に変換
deals['残高'] = deals['残高'].str.replace(' ', '').astype('float64')  # 半角スペースを削除してからfloat64型に変換
```
これで"deals"という名前のデータフレームに約定情報を格納できました。

### Daily損益に変換
今回は、単一ポジションのEAと複数ポジションのEAを同じように処理するため、日別損益に変換してからQuantStatsにデータを渡すようにしてみます。
```python
# 日別損益に変換する
results = deals[['時間', '損益']]
results['時間'] = pd.to_datetime(results['時間']).dt.normalize()
results = results.groupby('時間')['損益'].sum().reset_index()
results.columns = ['date', 'pl']

# 'pl'カラムの累積データを計算し、'balance'カラムに追加する
results['balance'] = deals['残高'].iloc[0]
results['balance'] = results['balance'] + results['pl'].cumsum()
results = results.set_index('date')
results = results['balance']
```
ここで作成されたデータフレーム"results"の中身はこんな感じです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1882169/4665eb7b-b91e-9564-7286-cf4a4929752c.png)

### QuantStatsでレポート作成
QuantStatsが受け取れる形式に変換できたので早速使用してみましょう。
```python
import quantstats as qs

# Jupyter Notebook上で出力する場合はこっち
qs.reports.full(results)

# HTML形式のQuantStatsレポートを作成する場合はこっちです
qs.reports.html(results, output='report.html', title="Performance Report")
```

QuantStatsから出力されたレポートがこれです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1882169/11554654-c058-a330-7d24-112094d0317e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1882169/82a7dc6e-5d75-aea0-1e45-6a5c4cf6fce8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1882169/66b7b579-a368-9910-ecb9-9fded5a915b2.png)

QuantStatsについての詳細はこちらから確認してください。
https://github.com/ranaroussi/quantstats
Vue/React開発環境をdocker環境で立ち上げてみる。

# はじめに

naritomoと申します。

本職はインフラエンジニアを行っています。
最近フロント技術にも興味があり、React/VueについてDockerコンテナとして
立ち上げてみました。

いろいろアドバイスいただけると嬉しいです。

## 立ち上げ概要

mac環境にて、
docker-composeを使用してVue/Reactコンテナを立ち上げるものになります。

完成しているソースは以下にあります。

https://github.com/naritomo08/vue-docker

https://github.com/naritomo08/react-docker

## なぜ、あえてDockerなのか？

インフラエンジニアとしてDockerから触れたほうが扱いやすく、
以下の利点を感じられたため、開発環境構築ではDockerを使用することを
推しています。

* OS問わず同じ開発環境での開発が可能
* 独立したフロントエンドコンテナを構築することにより、
　バックエンドと分離した開発検証が可能。　 

## 事前準備

mac+DockerCompose+vscode+gitでの環境を構築してること。

## 開発環境構築方法(Vue)

### docker構成フォルダ構築

ルートフォルダを作成する。

```bash
mkdir vue-docker
cd vue-docker
```

Dockerfileを作成し、以下の内容を入れる。

```bash
# Node.jsイメージをベースにする
FROM node:latest

# アプリケーションのディレクトリを作成する
WORKDIR /app

# アプリケーションの依存パッケージをインストールする
COPY package*.json ./
RUN npm install

# アプリケーションのソースコードを追加する
COPY . .

# アプリケーションをビルドする
RUN npm run build

# アプリケーションを起動するコマンドを指定する
CMD ["npm", "run", "serve"]
```

Docker-compose.ymlを作成し、以下の内容を入れる。

```bash
version: "3.9"
services:
  vue-app:
    build: .
    ports:
      - "8080:8080"
    volumes:
      - .:/app
      - /app/node_modules
```

### コンテナ立ち上げ

```bash
docker-compose build
docker-compose up -d
```

### サイト確認

以下のURLにアクセスし、Vueトップ画面が出てくること。

```bash
http://localhost:8080/
```

以下のファイルを編集し、トップ画面内容が変わることも確認してください。

```bash
vue-docker/src/App.vue
```

## 開発環境構築方法(React)

### docker構成フォルダ構築

ルートフォルダを作成する。

```bash
mkdir react-docker
cd react-docker
```

Dockerfileを作成し、以下の内容を入れる。

```bash
# 公式Node.jsイメージをベースにする
FROM node:14

# 作業ディレクトリを設定する
WORKDIR /app

# package.jsonとpackage-lock.jsonをコピーする
COPY package*.json ./

# 依存関係をインストールする
RUN npm install

# アプリケーションのソースコードをコピーする
COPY . .

# 開発用サーバーを実行する
CMD ["npm", "start"]
```

Docker-compose.ymlを作成し、以下の内容を入れる。

```bash
version: "3.9"
services:
  react-app:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
```

### コンテナ立ち上げ

```bash
docker-compose build
docker-compose up -d
```

### サイト確認

以下のURLにアクセスし、Reactトップ画面が出てくること。

```bash
http://localhost:3000/
```

以下のファイルを編集し、トップ画面内容が変わることも確認してください。

```bash
react-docker/src/App.js
```

## 開発環境操作

### 開発環境コンテナ起動/設定再読み込み

```bash
docker-compose up -d
```

### 開発環境コンテナ停止

```bash
docker-compose stop
```

### 開発環境コンテナ破棄

```bash
docker-compose down
```

# おわりに

フロント技術習得の第一歩として、Vue/React稼働dockerを構築してみました。

この作成にはchatgptも利用して構築しています。

この記事がVue/Reactを扱う方の助けになればと思います。
etherswitchのATUサポート

FreeBSDのethernet switchサポートフレームワークのetherswitchはetherswitchcfgというコマンドで設定を行えます。

```
# etherswitchcfg help
usage: etherswitchctl
        etherswitchcfg [-f control file] info
        etherswitchcfg [-f control file] config command parameter
                config commands: vlan_mode
        etherswitchcfg [-f control file] phy phy.register[=value]
        etherswitchcfg [-f control file] portX [flags] command parameter
                port commands: pvid, media, mediaopt, led
        etherswitchcfg [-f control file] reg register[=value]
        etherswitchcfg [-f control file] vlangroupX command parameter
                vlangroup commands: vlan, members
```

実はadrianさんは最後にATUサポートを入れたのですが、helpにはでてきません。

ATUサポートはswitchに格納されてるMAC Addressのdumpとflushを行う機能です。

```
# etherswitchcfg atu dump
 [0] 00:18:84:00:00:01: portmask 0x00000004
 [1] d4:94:a1:00:00:02: portmask 0x00000010
 [2] 00:18:84:00:00:03: portmask 0x00000008
```

portmaskのビットでどのポートに接続されているか確認できます。

flushはすべてとportのMACアドレスのエントリーを消すことが出来ます。

ATUのサポートはatherosのswithだけ実装されていて、蟹さんやRalinkでは実装されていません。

```
# etherswitchcfg atu dump
etherswitchcfg: ioctl(IOETHERSWITCHGETTABLE): Device not configured
```

すべてのswitchでATUのdumpが出来て回収できれば、どのポートにどのPCやスイッチが接続されているか、解析できるのではないでしょうか。
reactとtesting-libraryで単体テスト実行時のみ"Module 'useNavigate() may be used only in the context of a <Router> component."とエラーが出る

## 概要
```"Module '"react-router-dom"' has no exported member 'useHistory'"```というエラーがテスト実行時のみ永遠に出て、1日以上苦しんだので同じく苦しんでいる人がいれば救いたいと思います。

今考えると状況整理がちゃんとできていればすぐ解決できたんじゃないかと思います><

## 環境
- react-router-dom@6.10.0(当時のlatest)
- react@18.2.0

## 結論
急いでいる人のために一旦結論だけ書いちゃいます！

**下記のようにしてテストファイルのコンポーネントレンダリング時に<Router>コンポーネントでラップしないといけなかった。。。**
```
render(<Router><AddMembers /></Router>);
```


## 全然出てこなかった
### useNavigate() may be used only in the context of a <Router> component.でググる
エラー文でググると、大抵ルートコンポーネントで全部のコンポーネントをRouterでラップするようにしようという記事が大量に出てきた。

いやもうそれはとうにしてるんじゃ！！！

### バージョンの問題
react-router-domがv18系から色々と変更があったようで、それも混乱の原因の一つだった。
関連するところで言うと、
- 元々はuseHistory()を使ってナビゲーションをおこなっていたが、v18からはuseNavigateを使うようになった
- useHistoryはpushを利用しなければならなかったが、不要になった
など

なので、まず本記事を読んでいる方はバージョンとあった書き方をしている公式を絶対に確認すること


## 解決法
ひっっっったすらChat-GPT(GPT4)に聞きまくった。
1. 該当ファイルを丸々コピペ→問題ないと言われる
1. 関連するファイルを全てコピペ→問題ないと言われる
「オワタ。。。あ、そういえばこれテスト時だけエラーなの念の為伝えておこっと(笑)」
ワイ) "Btw I get the error on the console only when running unit test using testing-library. Does it matter??"
GPT4先生) "It's possible that the issue you're experiencing is related to how your tests are set up. When using testing-library for testing components that use React Router, it's important to wrap the component being tested with a <Router> component in the test itself."
→「まさにそれや。たわけ」

```jsx
render(
    <Router>
      <Content setOpen={setOpen} setAlertLabel={setAlertLabel} />
    </Router>
  );
```

## 終わりに
やっぱりGPTさんはおま環の質問でも情報を与え続けることで状況を把握して、かなり精度の高い回答をしてくれるので本当に助かってます。
LPWA

:::note info
この記事は [マスタリングTCP/IP　入門編（第6版）](https://amzn.asia/d/2qksld3)を読んだメモです。
:::

Low Power, Wide Area.という以上に明確な定義はない。
1回の通信量が小さく、長距離通信できるネットワーク。

無線LANなのかWANなのかといった明確な線引が難しく、無線LANの一部がLPWAに含まれたり、WANの一部がLPWAに含まれたり色々する。
なので自称してたらそれはもうLPWAくらいの感じ。

* 無免許OK（特定小電力無線）の規格
* 無線局免許必須の規格
の2種類がある。

### LoRaWAN
* 免許不要920MHz帯
* 送信データは11バイト
* 最大10kmくらいまでいける

LoRaWANゲートウェイでLoRaWAN端末と通信すれば、自前でネットワークを構築できる。

### Sigfox
* Sigfoxって会社がつくった独自規格
* 帯域、範囲は LoRaWANと同じ
* 送信データは12バイト

自前でネットワークを構築できない。

### NB-IoT
* LTEを使う
    * 自前ではネットワークを構築できない。携帯電話事業者のサービスを使う。
* 上り62kbps、下り21kbps
* 半二重通信
無線MAN

:::note info
この記事は [マスタリングTCP/IP　入門編（第6版）](https://amzn.asia/d/2qksld3)を読んだメモです。
:::

Metropolitan Area Network
Metropolitan = 大都市圏。 結構広範囲を対象にする規格。

## WiMAX
Worldwide Interoperability for Microwave Access.
マイクロ波で無線接続する、ラストワンマイルのための通信方式。

同類：DSL、FTTH 

IEEE802.16の一部。
携帯端末向けはIEEE802.16e。
無線LAN

:::note info
この記事は [マスタリングTCP/IP　入門編（第6版）](https://amzn.asia/d/2qksld3)を読んだメモです。
:::

Local Area Network.
100メートル程度の、建物内は十分カバーするレベルの範囲を対象とする。


# 規格定義たち
## IEEE802.11
無線LANプロトコルの物理層＋MAC層（データリンク層の一部）の規格定義。
これを礎にしたあらゆる関連規格があるのだ。（802.11aとかそんなかんじ。802.11jでは日本での4.9GHz-5GHzの通信規格を指すぞ。）

「IEEE802.11」と言うと、
* 規格の総称を指す場合
    * 802.11*シリーズみたいな感じ
* 無線LANのひとつの通信方式を指す場合
    * 802.11*シリーズの中でも802.11を指す

の2つがあるため注意。

### 関連規格の礎としての仕様
*  MAC層ではイーサネットと同じMACアドレスが使われる
*  CSMA/CA方式でアクセスする
*  無線の基地局を立て、基地局を介して通信する

:::note info
memo CSMA/CA方式

無線LANだって有限。媒体共有型のネットワークだ。ということで↓の手順で衝突回避する方式がCSMA/CA方式。
1. Carrier Senseを使ってアイドル状態を確認
2. バックオフ（ランダム時間）の間待つ
3. データ送信開始
:::

### 802.11という通信方式としての仕様
* 物理層で電波か赤外線を使う
* 1Mbps or 2Mbpsを実現する
    * 802.11b/g/a/nより遅いのでおはなしにならない

## IEEE802.11b,IEEE802.11g
* 2.4GHz帯の無線LAN
    * 電子レンジとかも使うので生活する中で干渉がおきやすい
* 最大11Mbps, 54Mbps
* 30~50m程度
* CSMA/CA方式
* 基地局を介する

## IEEE802.11a
* 5GHz帯を物理層とする無線LAN
* 最大54Mbps
* 先述のIEEE802.11b/gとは互換性がない

## IEEE802.11n
* MIMOで高速化したIEEE802.11a/g
    * MIMO = 複数のアンテナを同期させて通信する技術
* 物理層は2.4GHz or 5GHz帯
* 状況に合わせて使う帯域幅を変更して最大600Mbpsを生み出す

## IEEE802.11ac
* MU-MIMOによってギガビットスループットする激速規格
    * 80MHzは必須とする
    * IEEE802.11nよりもさらに帯域を増やす
* 物理層は5GHz帯のみ
* 第1世代と第2世代があるよ

:::note info
ここまでは伝送速度の改善に目を向けた規格たち
:::

## IEEE802.11ax
* Wi-Fi6と呼ばれるもの
* 平均スループットに注目した規格
    * 接続端末が高密度になる場面で周波数の利用効率を高めたい
* 物理層は2.4GHz or 5GHz
* 変調方式1024QAMに対応して速度を向上
    * QAM = Quadrature Amplitude Modulation(直角位相振幅変調)
* OFDMAを使用して周波数の割り当てをより効率的に
* 8ストリームのMU-MIMOで同接数を増やし、アップリンク/ダウンリンクどちらでもMU-MIMOを使用する
* 最大9.6Gbps

:::note info
「Wi-Fi」とは

特定の仕様、規格そのものを指すのではなくて、
IEEE802.11規格を満たしていることに対してつけられたブランド名。

つまり「Wi-Fiの機械」というものはなくて、「IEEE802.11規格をちゃんと満たしていると認定された無線LAN機器」というのが正しい。
:::

# 注意点
### 無免許帯域
無線LANが使うのは無免許で使える周波数帯域。
そのため狭くて干渉しやすい。

### 広く自由に繋がれるためのもの
つまり届く範囲ならみんな受信できるので盗聴、改ざんされうる。
対策も取られているが、破られることもある。
対策としては今はWPA2が主流。WPA3も使われてきてる。

#### WPA2
WPA = Wi-Fi Protected Access + IEEE802.1i
AESベースの暗号化プロトコルを用いた規格。

#### WPA3
WPA2の拡張。

* WPA3-Personal
    * SAEでパスワードベースの認証を強化
    * SAE = Simultaneous Authentication of Equals
* WPA3-Enterprize
    * 192ビットセキュリティモードでさらに強化
無線PAN

:::note info
この記事は [マスタリングTCP/IP　入門編（第6版）](https://amzn.asia/d/2qksld3)を読んだメモです。
:::
Personal Area Network.
10メートル程度といった、狭い範囲を対象とする。

## Bluetooth
2.4GHz帯で通信する。
データ転送速度は3Mbps、実際は最大2.1Mbps程度。
範囲は電波強度によりけりで、1m〜400m。

ピコネット（1台のマスターと7台のスレーブが通信する）方式で、最大8台が通信できる。

小型で電源容量の小さい機器が対象。
特に省電力に特化してBLEが生まれた。

## ZigBee
低消費電力で短距離用の無線通信規格。
最大65536端末間をつなげるらしい。家電とか向け。

日本では2.4GHz帯をつかい、最大250kbps。
無線通信にもいろいろあるのよ

:::note info
この記事は [マスタリングTCP/IP　入門編（第6版）](https://amzn.asia/d/2qksld3)を読んだメモです。
:::

無線通信 ＝ 電波、赤外線、レーザー光線などいろんな手段を含む、通信ケーブルを物理的に接続せずに通信すること全般。

携帯する機器に便利→場所をとらない＆コスト削減　と利点が移り変わってきた。

## 種類
規格としては以下がある。

| 種別 | ざっくりとした違い |
|:-:|:-|
|　短距離無線 | * 数メートル程度<br>* RF-ID |
| [無線PAN](https://qiita.com/masaozi3/items/504e34a43d46a0a7e5d5)<br>(IEEE802.15) | * Personal Area Network<br>* 10メートル程度<br>* Bluetoothとか |
| [無線LAN](https://qiita.com/masaozi3/items/9bc61cb3753ea98f439d)<br>(IEEE802.11) | * Local Area Network<br>* 100メートル程度 |
| [無線MAN](https://qiita.com/masaozi3/items/be0f394a0e193c4d47e2)<br>(IEEE802.16, IEEE802.20)  | * Metropolitan Area Network<br>* 数キロ〜100キロ程度<br>* WiMAXとか |
| 無線RAN<br>(IEEE802.22)  | * Regional Area Network<br>* 200キロ〜700キロ程度 |
| 無線WAN<br>(3GPP) | * Wide Area Network<br>* 携帯電話の通信とか<br>* とてもひろいねぇ |

これらに分類が難しいものとして、 [LPWA](https://qiita.com/masaozi3/items/d196b900746582c66892) というのも存在する。
ZXingで画像からQRコードを読み込む【Kotlin】

## 内容
Zxingを利用して端末内に保存された画像のQRコードを読み込む方法について書いています。
言語はKotlinです。この記事は該当部分を抜き出して掲載しています。

## コード
最初に画像を読み込むための権限設定を書きます。Android13以降では権限関連の設定が変わったようです。（[公式ドキュメント](https://developer.android.com/about/versions/13/behavior-changes-13?hl=ja)）今回は画像アクセスを行いたいのでManifest内に下記のように書きました。公式ドキュメントによるとAndroid13以降の画像取得には[写真選択ツール](https://developer.android.com/about/versions/13/features/photopicker?hl=ja)の使用を推奨していました。この仕組みを利用したことがないので時間があるときに試してみようと思います。

```xml:AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
```
下記コードを画像の読み込みを行いたい部分（ボタンクリック時など）に指定します。こうすることで画像選択のアクティビティが表示されます。

```kotlin
val intent = Intent(ACTION_PICK)
intent.type = "image/*"
receivePicture.launch(intent)
```
Zxingを利用したQR読み込み部分

```kotlin
private val receivePicture =
    registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) {
        if (it.resultCode == Activity.RESULT_OK) {
            val uri = it.data?.data
            val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, uri)
            val source = RGBLuminanceSource(
                bitmap.width,
                bitmap.height,
                IntArray(bitmap.width * bitmap.height).apply {
                    bitmap.getPixels(this, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
                })
            val bitmapBinaryBitmap = BinaryBitmap(HybridBinarizer(source))
            val reader = MultiFormatReader()
            val result = reader.decode(bitmapBinaryBitmap)
            //result.text内に取得したデータが入っているため次のアクティビティに渡す等の処理をここに書く
        } else {
            // アクティビティが失敗した場合の処理をここに書く
        }
    }
```
-----
簡単な解説です。


`registerForActivityResult`はアクティビティ内での動作結果を受け取っています。（[公式ドキュメント](https://developer.android.com/training/basics/intents/result?hl=ja)）


取得したuri先の画像（Bitmap）を取得します。このgetBitmapは**deprecated**です。API Level 29以降ではImageDecoder#createSource(ContentResolver, Uri)とImageDecoder#decodeBitmap(Source)の利用が推奨されています。OSごとの分岐処理をおすすめします。（[公式ドキュメント](https://developer.android.com/reference/android/provider/MediaStore.Images.Media#getBitmap(android.content.ContentResolver,%20android.net.Uri))）

```kotlin
val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, uri)
```
取得した画像をZXingで読み込むためにBinaryBitmapへ変換します。
```kotlin
val source = RGBLuminanceSource(
                bitmap.width,
                bitmap.height,
                IntArray(bitmap.width * bitmap.height).apply {
                    bitmap.getPixels(this, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
                })
val bitmapBinaryBitmap = BinaryBitmap(HybridBinarizer(source))
```
画像からデータを読み込みます。読み込んだ結果をresult内に入れます。

```kotlin
val reader = MultiFormatReader()
val result = reader.decode(bitmapBinaryBitmap)
```
言語別ハローワールド

自分は普段JSかTSしか使わないのですが、
ふと、ほかの言語のハロワの文法がきになったので、メモ代わりに。

とくに苦手な低レイヤー(?)を中心に

また環境はすべて[paiza.io](https://paiza.io/)で行っています。せっかく学校が使われてくれるのでね :D

# C

ワタクシの苦手言語第二位であるCです。
普段JavaやTSなどのオブジェクト指向やコンポーネントベースばかりの言語を扱っている私にとっては苦痛です…

```c

#include <stdio.h>
int main(void){
    // Your code here!
    printf("Hello World\n");
}

```

シンプルといえばシンプルなんですが...

GUIばかり作っているのでCLIは新鮮です。

# C#
C#はWindowsアプリ開発者であれば一度は使ったことがあると思います。

またUnityのスクリプトは基本C#ですし、切っても切れない関係性ですね。(それが故に私は嫌いです :( )

```cs
public class Hello{
    public static void Main(){
        // Your code here!
        
        System.Console.WriteLine("Hello World");
    }
}

```

# Java

最近java20が発表された、そうJavaです。
JavaSEの他Jakarta EE JavaMEなど様々なバージョンがあり、
JavaCardやAndroidJavaなど特殊なものも含め幅広い環境で使えるのがウリの言語です。

```java

import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        // Your code here!
        
        System.out.println("Hello world");
    }
}

```

今回は簡単にこんな感じですが、気が向いたらあたらしくやりますゥ...


最後に私のPJのリンク張っときます。よろしければご覧ください

https://github.com/nknighta/V
gpt4all : Benchmarking LLM on CPU

# 概要
gpt には計算量が必要とは聞くが, 体感がわからない.
そのため以下環境での動作速度を検証する

- linux
    - ryzen 1700 8core 16thread
    - mem 64GB. 2133M Hlz
    - m.2 1T
- mac
    - m1 mac 8core
    - mem 16GB




# 実験概要
- 以下の prompt を実行する
    - Can you tell us one famous comic book in 20 words or less?
- 速度計測
    - 画面上に文章を書き始めるまでの時間
    - prompt 実行から書き終わるまでの時間



# ryzen

| thread | batch | write start | write end |                                              |
|:-------|-------|-------------|-----------|----------------------------------------------:|
|      2 |     8 | 20 sec      | 40 sec    | 実用性なし                            |
|      4 |     8 | 12 sec      | 27 sec    | 実用性がこの辺りから出てくる |
|      8 |     8 | 6 sec       | 13 sec    | 数単語/sec 程度。                              |
|     16 |     8 | 6 sec       | 13 sec    | 同上                                          |
|     16 |    16 | 6 sec       | 14 sec    | 同上                                          |
|     16 |    32 | 9 sec       | 16 sec    | 同上. 性能は若干劣化                                          |
|     32 |    16 |        |    | 未計測。起動に1分以上かかる                     |




# m1 mac

| thread | batch | write start | write end |                          |
|:-------|-------|-------------|-----------|-------------------------:|
|      2 |     8 |       5 sec | 13 sec    | 実用性のある速度           |
|      4 |     8 |           3 | 7 sec     | 体感だいぶ早い             |
|      8 |     8 |           6 | 10sec     | 体感速度がだいぶ落ちる      |
|     16 |     8 |             |           | 未計測。起動に１分以上要する |




# 所管
- 計算量
    - 現状のLLMはだいぶと計算量が必要と思える
- ryzen 1700
    - 恐らく古いCPUと環境なので遅い
    - 8thread 以上は若干性能劣化したが, core が8個だからだろうか.
- m1
    - 4core のみが高性能のため, 8core だと性能が劣化するとも捉えれる
    - 高性能コアの性能が垣間見れる
vite を build したら `Maximum call stack size exceeded` エラーが出た

config で！？と目を疑ったログはこちら。

```cli
failed to load config from /var/www/html/vite.config.js
error during build:
RangeError: Maximum call stack size exceeded
    at String.replace (<anonymous>)
    at removeColors (node:internal/util:80:10)
    at isBelowBreakLength (node:internal/util/inspect:2014:22)
    at reduceToSingleString (node:internal/util/inspect:2059:13)
    at formatRaw (node:internal/util/inspect:1090:15)
    at formatValue (node:internal/util/inspect:841:10)
    at inspect (node:internal/util/inspect:365:10)
    at formatWithOptionsInternal (node:internal/util/inspect:2292:40)
    at formatWithOptions (node:internal/util/inspect:2154:10)
    at console.value (node:internal/console/constructor:339:14)
```

vite.config.js の中身は以下
```vite.config.js
import { defineConfig, loadEnv } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig(({ mode }) => {
    const env = loadEnv(mode, process.cwd())
    return {
        server: {
            host: true,
            hmr: {
                host: env.VITE_HOST,
            },
        },
        plugins: [
            laravel({
                input: [
                    'resources/sass/app.scss',
                    'resources/js/app.js',
                ],
                refresh: true,
                watch: {
                  usePolling: true,
                },
            }),
        ],
        resolve: {
            alias: {
                '@': '/resources/js',
                '$': 'jQuery',
            },
        },
    }
})
```

## 原因
`.env` とサーバの環境変数が問題だった。
```.env
APP_HOST="${APP_HOST}"
VITE_HOST="${APP_HOST}"
```
上記のように、 `.env` 内でサーバの環境変数が使われるようにしていたのだが、それが設定されていなかった。
サーバに環境変数を設定したら治った。
rbenvでruby3.2.2をインストールするとBUILD FAILEDになる

rbenvでruby3.2.2をインストールしようとしたら、BUIDL FAILEDが発生しました。

## 環境
macOS 12.1(Monterey)

## 成功するコマンド
一旦、システム直下にruby3.2.2をインストールする。
```
brew install ruby
```
こうすることで、ruby3.2.2に必要な依存関係が整備される（執筆当時はruby3.2.2が最新なので自動的に対象のバージョンがインストールされるが、本来は`brew install ruby@3.2.2`のような指定が必要かもしれない）。

続いて、先ほど入れたrubyは不要なので削除する。
```
brew uninstall ruby
```
最後に、rbenvでruby3.2.2をインストール。
```
rbenv install 3.2.2
```
こちらで成功しました。

## （参考）最初に出たエラー文
```
❯ rbenv install 3.2.2
To follow progress, use 'tail -f /var/folders/vp/l949bc451wd16xjszv_qvnsr0000gn/T/ruby-build.20230402152243.50133.log' or pass --verbose
Downloading openssl-3.1.0.tar.gz...
-> https://dqw8nmjcqpjn7.cloudfront.net/aaa925ad9828745c4cad9d9efeb273deca820f2cdcf2c3ac7d7c1212b7c497b4
Installing openssl-3.1.0...
Installed openssl-3.1.0 to /Users/***/.rbenv/versions/3.2.2

Downloading ruby-3.2.2.tar.gz...
-> https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.2.tar.gz
Installing ruby-3.2.2...
ruby-build: using readline from homebrew

BUILD FAILED (macOS 12.1 using ruby-build 20230330)

Inspect or clean up the working tree at /var/folders/vp/l949bc451wd16xjszv_qvnsr0000gn/T/ruby-build.20230402152243.50133.R8PbbK
Results logged to /var/folders/vp/l949bc451wd16xjszv_qvnsr0000gn/T/ruby-build.20230402152243.50133.log

Last 10 log lines:
	Check ext/psych/mkmf.log for more details.
*** Fix the problems, then remove these directories and try again if you want.
Generating RDoc documentation
/private/var/folders/vp/l949bc451wd16xjszv_qvnsr0000gn/T/ruby-build.20230402152243.50133.R8PbbK/ruby-3.2.2/lib/yaml.rb:3: warning: It seems your ruby installation is missing psych (for YAML output).
To eliminate this warning, please install libyaml and reinstall your ruby.
uh-oh! RDoc had a problem:
cannot load such file -- psych

run with --debug for full backtrace
make: *** [rdoc] Error 1
```
よくわからないけど動いたからヨシ！
## 参考にした記事
https://github.com/rbenv/ruby-build/discussions/2178
セッションのロケール情報を変更

セッションのロケール情報が「ja」である事を確認して処理が進むシステムで、ロケール情報「en」が送信されたことでアクセス出来ない事象があり、ロケール変更するための対応を行った

----------------------------------------------------------------------------------------------
<table>
  <tr>
    <td> ① Edgeのロケール設定を変更<br/> ② Edgeの変更だけで変わらなかった場合windowsの地域設定を変更　　　　　　</td>
  </tr>
</table>

----------------------------------------------------------------------------------------------

## Edgeの言語設定を変更する
①Edge右上の三点リーダー「・・・」をクリックし、「設定」をクリック。
　　<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/2374686e-254e-ce71-e987-034151224d9a.png">

②左メニューから「言語」をクリック。
　優先する言語設定の最上位に「日本語」が来ている事を確認。
　　<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/bf96abf7-cae1-ea08-f88c-a430d5f284a5.png">

③日本語右端の三点リーダー「・・・」をクリックし
　「Microsoft Edge をこの言語で表示」にチェックを入れる。
　　<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/264bd409-dbbb-bd5d-d305-9242ae7a37ee.png">

## windowsの地域設定を変更する
①[スタート]→[設定(歯車)]→[時刻と言語]を選択
　地域に「日本語(日本)」を選択
　「推奨[日本語(日本)]」だとロケールが「ja」にならなかった
　旧Edge（Chromium版以前）の場合、Windowsの言語設定が反映される仕様らしい
　　<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/e51b6ae3-1893-1c9e-db3d-78a283d1fa8f.png">
メールヘッダーの各項目解説

# メールヘッダーの項目と内容の解説
## はじめに
メールヘッダーについて調べることがあったので、メールヘッダーにかかれている項目と各項目の意味を一覧でまとめることにしました。
システムによって付与される情報も多少異なってくると思うので、ここに書かれていない項目もあります。
「こんな項目もあるよ！」とコメントいただけると幸いです。

## 一覧

|項目名|内容|
|----|----|
|From|送信元メールアドレス|
|To|宛先メールアドレス|
|Cc|カーボンコピーに指定されたアドレス|
|[Reply-To](#reply-to)|返信先メールアドレス|
|Subject|件名|
|Date|送信日時|
|Return-Path|メール送信エラー時のエラーメッセージ送信先|
|[Received](#received)|メールの送信経路|
|Message-ID|電子メールの識別番号|
|[Content-Type](#content-type)|メッセージ本文の形式及び文字コード|
|[MIME-Version](#mime-version)|MIMEのバージョン|
|Authentication-Results|送信ドメイン認証（SPF・DKIM）による認証結果|

## 一部解説
### Reply-To
「返信」機能を使用したとき、基本的に送信先は「From」のアドレスになるが、このパラメータが指定されていると、送信先がこのパラメータで指定されたアドレスになる。
自動応答メッセージなど、返信ができないメッセージに使用される。
### Received
from：送信側メールサーバの名前
by：受信側メールサーバの名前
with：メールの送受信に用いられたプロトコル(SMTP,HTTP,ESMTPなど)
for：送信先メールアドレス
id：メールサーバが任意でつけるID
via：経由地点の環境とそのプロトコル
### Content-Type
例
- text/plain
    - 文字だけのメール
- multipart/mixed
    - 添付ファイル付きのメール
### MIME-Version
1.0以外見かけたことがないですが、他のversionもあるんですかね…？


## 参考
https://dream.jp/support/techinfo/mail/header/header01.html

https://www.dekyo.or.jp/soudan/contents/ihan/header.html

https://support.so-net.ne.jp/supportsitedetailpage?id=000011738

https://wa3.i-3-i.info/word11118.html

https://baremail.jp/blog/2020/06/03/728/

https://www.mew.org/~kazu/doc/newsletter/3.html
【enum】列挙型の使い方

# はじめに

enumを使うときに、エラーが出てしまい、すぐに解決できなかったので
使い方と実際に出たエラーをまとめます。

enumを使うことで
・レコードが取り出しやすくなるので、開発をしやすくする
・他のプログラマーにも読みやすくできる
・誤った数値を使うことを事前に防ぐことができる
などのメリットがあります

# enumを使用するカラムを用意

shiftsテーブルにstatusカラムを追加していきます。
このstatusカラムがenumを使用するカラムです。

statusカラムは今回、integer型にします。
string型でも可能です。

##### モデルを作成する場合
```:ターミナル
$ rails g model Shift status:integer
```

```db/migrate/yyyymmddhhmmss_create_shifts.rb
class CreateShifts < ActiveRecord::Migration[6.1]
  def change
    create_table :shifts do |t|
      t.integer :status, default: 0

      t.timestamps
    end
  end
end
```

##### カラムを追加する場合
```:ターミナル
$ rails g migrate add_column_to_shifts
```

```db/migrate/yyyymmddhhmmss_add_column_to_shifts.rb
class CreateShifts < ActiveRecord::Migration[6.1]
  def change
    add_column :shifts, :status, :integer, default: 0
  end
end
```

これで、enumを使用するカラムの用意ができました。

# モデルにenumの定義をする

あとはモデルにenumの定義をすれば完成です。

```app/models/shift.rb
class Shift < ApplicationRecord
  enum status: { unapproved: 0, approved: 1, rejected: 2 }
end
```

配列でも定義することが可能との記事がありますが、
integer型の場合は必ずハッシュで定義してください。

integer型かつ配列で定義した場合は以下のエラーが出ます。

##### [注意点]エラー

```:rails console
`enum': wrong number of arguments (given 2, expected 1) (ArgumentError)                             
```

最初、上記エラーが出てどうすればいいかわからず困りました。


# コンソールで確認する

最後に、確認をしておきます。

```:rails console
$ Shift.new
```

お読みいただき、ありがとうございました！
MacでターミナルエミュレータにHyperを使ったらNvChadでoptionキーを使ったキーショートカットが反応しなかった

ターミナルエミュレータをHyperに乗り換えてみたらNvChadでoption + hでターミナルの表示・非表示が動かなかったので軽くググってみたらそれっぽいissueを見つけたので試してみたら解決しました。

英語ネイティブじゃないくせに斜め読みしかしてないので詳しいことは把握してませんが、
```javascript:~/.hyper.js
"use strict";
// Future versions of Hyper may add additional config options,
// which will not automatically be merged into this file.
// See https://hyper.is#cfg for all currently supported options.
module.exports = {
    config: {
        （中略）
        modifierKeys: { altIsMeta: true },
    },
    （後略）
```
というように、modifierKeysの項目を追加したら動くようになりました。

参考文献：https://github.com/vercel/hyper/issues/330
[Linux]ファイル操作



# catコマンド
ファイルの中身を確認するコマンドです。

-nオプションで行頭に、行番号が表示されます。

# lessコマンド
ファイルの中身をスクロール表示するコマンドです。

### スクロール操作

|コマンド|内容|
|:--:|:--:|
|スペースキー、f|一画面下スクロール|
|b|一画面上にスクロール|
|j|一行下にスクロール|　
|k|一行上にスクロール|
|q|lessコマンドの終了|

### 検索
|コマンド|内容|
|:--:|:--:|
|/<文字列>|下方向に向かって検索|
|?<文字列>|上方向に向かって検索|
|n|次の検索結果に移動|
|N|前の検索結果に移動|


# touchコマンド
空のファイルを作成するコマンドです。

# rmコマンド
ファイルを削除するコマンドです。「-r」オプションで、ディレクトリ内のファイルやディレクトリをまとめて削除します。

# mvコマンド
ファイルの移動と、ファイル名を変更するコマンドです。このコマンドで注意すべきところは、移動先がファイルの場合は、ファイルの名前を変え、移動先がディレクトリの場合は、そのディレクトリにファイルが移動します。
```
$ mv [オプション] <移動元> <移動先>
```

# cpコマンド

ファイル・ディレクトリをコピーするコマンドです。
```
$ cp [オプション] <コピー元> <コピー先>
```
ディレクトリをコピーする時は、以下のようになります。
```
$ cp -r dir1 dir2
```

# lnコマンド
リンクを張るコマンドになります。

Linuxでは、ファイルに別名をつけることができます(つまりショートカット)。その中で、ハードリンクとシンボリックリンクがあります。

前者は、1つのファイルに対して、複数の名前をつけることができます。実際のファイル元を削除しても、ハードリンクはなくならないため、削除を行う場合は全てのハードリンクを削除する必要があります。後者は、リンク先のパス名が書かれた特殊ファイルです。ここにはあくまでもリンク先のパス名が記載されているため、リンク先がファイルの実体になります。ここで、シンボリックリンクを削除しても元のファイルには何も影響を与えませんが、逆に元のファイルを削除すると、ファイルの参照ができないため、エラーがでます。

```
ln [オプション]　<リンク元ファイル> <リンク名>
```
ハードリンクの張り方
```
$ ln file1 file2
```
シンボリックリンクの張り方
```
$ ln -s file1 file2
```
## どういった状況で使うのか?

- 長いパス名を省略したい時

- 複数バージョンを共存させて、最新なものと区別したい時
(例えば、プログラミング言語を複数バージョンによって、開発を行いたい時など...)

# findコマンド
ファイルを検索するコマンドです.

```
$ find . <検索条件> -print
```

「.」 => 検索開始ディレクトリ(カレントディレクトリを表します)
例えば、libディレクトリ以下のファイルやディレクトリを探す場合は、「/lib/」といったように表します。

「-print」 => 検索アクション

### 検索条件の種類
- -name
ファイル名を指定して、ファイルを検索します。ただし、大文字小文字は区別されます。また、「-iname」とするとファイル名の大文字小文字の区別はしません。

- -type
ファイルの種類で検索を行います。ファイルは「f」、シンボリックリンクなら「l」、ディレクトリなら「d」で表されます。
```
$ find .-type f -print
```

- -a
複数の検索条件をしてする場合に使います。
```
$ find .-type d -a -name dir1 -print
```
[Linux]ディレクトリ構造

# ディレクトリ構造

ディレクトリにはファイルが保存されており、ディレクトリは入れ子構造になっています。ルートディレクトリ「/」を頂点とした階層構造になっているため、これをディレクトリーツリーと呼ばれます。

# linuxの主要なディレクトリ
### /bin
全てのユーザーが使用する実行ファイルが保存されているフォルダ。基本的なlinuxコマンドが保存されており、ルートユーザーや一般ユーザーともにアクセスできます。

### /dev
ハードウェアをファイルとして扱えるようにしたファイルが保存されています。このファイルのおかげで、周辺機器(ハードディスク、キーボードなど)の周辺機器上のリソース(ディスク、パーティンションなど)にアクセスできます。

### /etc
linux設定のための各種ファイルが保存されているファイルです。プログラムの起動、終了や再起動などのコントロール機能やプログラム本体などが保存されている。

### /home
ユーザーホームディレクトリのことで、useraddコマンドで新しいユーザーが生成されると、自動的にこのディレクトリに追加されます。

### /sbin
/binと似ていますが、ここには管理者向けのコマンドが保存されいます。

### /tmp
アプリケーション実行時の結果を一時的にファイルとして保存します。システムを再起動すると、このディレクトリに存在するファイルはすべて消去されます。

### /usr
全てのユーザーが使えるアプリケーションやそれらに付随するファイルをインストールするディレクトリです。インストールにはroot権限が必要になります。

### /var
アプリケーションを動作する上で作成されたログなどを保存します。例えば一般的には、/var/logはログファイルが保存されます。

# ディレクトリコマンド
## cdコマンド
ディレクトリの移動に使われるコマンドです。

### その他オプション
「.」 カレントディレクトリ => 今いるディレクトリ
「..」 親ディレクトリ => 一つ前のディレクトリに移動
「~」 ホームディレクトリ　=> ホームディレクトリに移動
「/」 ルートディレクトリ => リートディレクトリに移動

## pwdコマンド

今自分が作業しているディレクトリ(カレントディレクトリ)を確認できます。

## lsコマンド
ファイルやディレクトリの一覧を表示するコマンドです。
### パス名展開
複数のファイルを表示したい場合に使います。

|記号|意味|
|:--:|:--:|
|*|任意の文字列|
|?|任意の一文字|

(例)
```
$ ls *.html 
  index.html header.html footer.html
```

### よく使うオプション
ファイルの詳細を表示する「-l」オプションです。
```
$ ls -l
  drwxr-xr-x 2 hoge hoge 6 3月 25 12:00 dev
```
「d」 => ディレクトリを表します(「-」ファイル、「|」シンボリックリンク)
「rwx」 => ユーザーに対する権限です。r：読み取り、w：書き込み、x：実行を意味します。
「r-x」 => グループに対する権限です。読み取りと実行が可能です。
「r-x」 => その他の設定です。
「hoge」「hoge」 => 所有者と所有者グループを表しています。
「6」 => ハードリンクの数(ファイルやディレクトリに複数の名前をつけたもの)
「3月 25 12:00」 => タイムスタンプ
「dev」 => ファイル名、ディレクトリ名
```
$ ls -a
  . .bash_history .bashrc desktop
```
「-F」オプションは、隠しファイルを含めた全てのファイルを表示します。
```
$ ls -F
  bin@ dev/ home/ lib64@
```

「/」　ディレクトリ
「@」　シンボリックリンク
「*」　実行可能なファイル
「記号なし」　通常ファイル

### --helpオプション
---helpオプションを入力すると、コマンドのヘルプ(使用方法やオプション一覧)など、コマンドの概要を確認できる。

## manコマンド
コマンドのマニュアルを確認できます。ヘルプよりも詳しい使い方を確認したい場合は、manコマンドの方が有用です。

## mkdirコマンド
ディレクトリを作成するコマンドです。削除する場合は、rmdirコマンドで削除できます。しかし、ディレクトリのなかにファイルがある場合は、削除できないため注意が必要です。「-r」オプションをつけることによって、再帰的にディレクトリ内のファイルも含めて全て削除されます。

```
$ rm -r <ディレクトリ名>
```

### -pオプション
```
$ mkdir -p user/2023/hoge
```
「-p」をつけることによって、複数のディレクトリを作成しえてくれます。上記のは、userと2023のディレクトリを作成してくれます。


# 参考
https://www.udemy.com/course/unscared_linux/

https://qiita.com/nys9302/items/a8ddeedd3cd9d0deb332
[matplotlib]論文や研究発表用に好みのグラフを作ったメモ


matplotlibの設定値をいじって，下のような自分好みのグラフを作ったメモです．

![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669376/898f92d5-1611-ac87-a445-e9e5f9aa80a5.png)


## 設定方法

メモ書きみたいなものなので，詳しくは解説しません．
他の親切な記事や，
[公式のページ](https://matplotlib.org/stable/tutorials/introductory/customizing.html)など見てください．

最低限の説明としては，
コード中で`plt.rcParams["キー"]`から直接設定するか，

設定値が書かれたmatplotlibrcというファイルを，
Macなら`~/.matplotlib/matplotlibrc`，linuxだと`~/.config/matplotlib/matplotlibrc`に置くとデフォルト値として反映されます．

または，`style.mpl`みたいなstyle fileとして保存しておいて，コード内で`plt.style.use("style.mpl")`とすると設定が反映されます．

## 設定

matplotlibのデフォルトのグラフは，
- 色が薄い
- 文字が小さい
 
ため，オンサイトの研究発表時に，スクリーンに投影して発表すると薄くて見づらいことが多いです．

そのため，例えば，下記のような設定をします．

```style.mpl


## font：少し大きめ
font.family : arial unicode ms
mathtext.fontset : cm  
font.size : 11
axes.labelsize : large 

## figure：画像サイズは8cm以内にする．bitmapなら高解像度に
figure.figsize: 3.0,2.25
# figure.constrained_layout: True
figure.dpi: 300
savefig.format: pdf

## ticks：両側につけて内向きにする．少し太くする
xtick.direction : in
ytick.direction : in
xtick.top   : True      
ytick.right : True
axes.linewidth   : 1.2

## 凡例：非透明の黒四角で囲う
legend.fancybox   : False
legend.framealpha : 1
legend.edgecolor  :  black                        
legend.fontsize : 10

## 目盛り線を太くする．
xtick.major.pad: 5.0
xtick.major.size: 7
xtick.major.width: 1.0
xtick.minor.pad: 5.0
xtick.minor.size: 3.5
xtick.minor.width: 1.0
ytick.major.pad: 5.0
ytick.major.size: 7
ytick.major.width: 1.0
ytick.minor.pad: 5.0
ytick.minor.size: 3.5
ytick.minor.width: 1.0

## プロット線は太く，マーカーは白抜き
lines.linewidth  : 1.2
lines.markersize : 5
markers.fillstyle: none
lines.markeredgewidth: 1.2

## 色を原色にする．
axes.prop_cycle: cycler("color",["k","r","b","g"])

```

## 例

上記の設定を`style.mpl`として保存します．
これを用いてグラフを作ります．
```Python
import numpy as np
import matplotlib.pyplot as plt

plt.style.use("style.mpl")

fig,ax = plt.subplots(layout="constrained")
x = np.linspace(-8,8,40)
plt.plot(x,1./(1.+np.exp(-x)),"o-",label="sigmoid")
plt.plot(x,x>0.0,"s--",label="step")

ax.set(**{
  "xlabel" : r"$x$", 
  "ylabel" : r"$f(x)$", 
  "xlim" : (-8.8,8.8), 
  "ylim" : (-0.1,+1.1), 
  "yticks" : [0.0,0.5,1.0],
})
ax.grid()
ax.legend()
plt.savefig("sample")

```
出力は，

![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669376/898f92d5-1611-ac87-a445-e9e5f9aa80a5.png)

となります．

最近は`science_plot`とかのライブラリで設定するのもあるみたいですね．

本当は，3年前くらいに作ったレシピです．

## 追記

Chatgptにも聞いて見ました．

```me
please make matplotlibrc satisfying the Springer Nature requirements.
```

結果がこちら．
![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669376/061d6229-18c8-441a-046f-e21b13e736f5.png)

こういうのがいいんでしょうかね?
ABC296回答メモ

0.はじめに
　Cまでは順調に解けましたが、DがTLEで撃沈。
　全体的にDを解けた人は少ないようで
　意外といい成績でした。

1.A - Alternately
　文字列の一文字目をまず変数chkに格納。
　2文字目以降、chkと比較し、一緒だったらNoを出力して終了
　違っていたら、その文字をchkに入れて次の文字をチェック・・・
　といった感じで解きました。

　https://atcoder.jp/contests/abc296/submissions/40211763

2.B - Chessboard　
　”*”の座標i,jを求め、以下の定数をもとに
　出力するべきマス名を求めました。
　N1="abcdefgh"
　N2="87654321"

　https://atcoder.jp/contests/abc296/submissions/40222100

3.C - Gap Existence
　まずリストAの値をキーとしてすべて辞書に登録。
　その後、リストAを頭から読み込み、A[i]-Xの値が
　辞書に存在するかをチェック。
　あればYesを出力して終了。リストの最後まで見てなければNoを出力。

　https://atcoder.jp/contests/abc296/submissions/40226653

4. 	D - M<=ab
　試験中は試行錯誤してもとけず、試験後解説をみながら
　ACはもらえたのですが、なんでそうなるのかが今一わかりませんでした。。。
　解説放送を待とうと思います・・・。

　【考え方１】（TLE）
　　引数Xについて、X=A*Bとなる、A・Bのうち、差が最小となる
　　組み合わせを返す関数big_pairを用意。
　　引数にMをいれ、戻り値A・Bのうち、大きい方がNを超えないかをチェック。
　　Nを超えなければ、Mがを出力して終了。
　　Nを超えていれば、Mに1を加えて終了するまで繰り返し。
　　→TLEになりました。

　【考え方２】（TLE）
　　Xを1ずつ増やしていくループを用意
　　その中で、Nを一つずつ減らしてくループを回す。
　　X％Nが割り切れたらその時のXを表示して終了。
　　→TLEになりました。

　【考え方３】（解説を参考にしAC）
　　不明・・・


　https://atcoder.jp/contests/abc296/submissions/40273868

以上
【Vue.js/JavaScript】export defaultとexportの違い

変数、関数、処理の受け渡しに使用する双方の違いについてまとめました。

# 双方の主な違い

export default
渡せるのは1つのみ

export複数渡せる

# export default
変数、定数、関数などの処理を1つの機能として渡すモジュール。

渡す
```vuejs:
export default 処理
```

受け取る
```
import モジュール名 from 'ファイルパス'

// asで別名を付ける
変数名 as 変更後の名前
```

# export 
変数、定数などを複数渡せる。

渡す
```
export { 変数名1, 変数名2, 変数名3,,,}
```

受け取る
```
import { 変数名1、変数名3 } from 'ファイルパス'

// asで別名を付ける
 { 変数名１ as 変数名A', ,,}
```
【Cloudformation】EKS on EC2でAMIを指定した起動テンプレートを使う

## はじめに
EKSマネージド型ノードグループにおいて、自動生成された起動テンプレートを使用することは便利なのですが、デプロイされるEC2に設定されるセキュリティグループはEKSによって自動生成されるものになってしまいます。

また、公式資料にもある通り、自動生成された起動テンプレートを変更すること推奨されていません。

> 自動生成された起動テンプレートを変更することは推奨しません。したがって、柔軟性を高めたい場合は、最初にマネージド型ノードグループを作成するときにカスタム起動テンプレートを指定するようにしてください。

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/launch-templates.html

## Cloudformationでの実装方法
今回は、EKSマネージド型ノードグループで使用する起動テンプレートを、Cfnで作成してみます。
※Amazon Linuxを使用

Userdataに関して、公式資料を初見した際に少しハマったたので、以下にポイントをまとめます。

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/launch-templates.html

・起動テンプレートにおいてAMI ID を指定しない場合：
　Userdataは、MIME マルチパートアーカイブ形式である必要がある
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3191704/f7f5ad00-996f-a9b9-e78c-49c2ef3582c7.png)

・起動テンプレートにおいてAMI ID を指定した場合
　EKS はUserdataのマージを行わないため、 bootstrap.sh スクリプトの実行を定義する必要がある
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3191704/22c978cf-5ea7-cda4-5bf6-5e38e90b3ad2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3191704/6a6a3585-5e04-b0d9-023c-18db1d987b78.png)

## Cloudformationテンプレート
上記を踏まえ、AMIを指定した起動テンプレートをCfnで作成しました。
以下、起動テンプレートのYamlです。

```
AWSTemplateFormatVersion: "2010-09-09"
Description: "LaunchTemplate-test"
Parameters:
#===============================================================================
# Parameter
#===============================================================================
  InstanceTypes:
    Type: String

  AmiType:
    Type: String

  DiscSize:
    Type: String
Resources:
#===============================================================================
# Launch Template
#===============================================================================
  LaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateName: "Test-LaunchTemplate"
      LaunchTemplateData:
        ImageId: !Ref AmiType
        InstanceType: !Ref InstanceTypes
        SecurityGroupIds:
          - sg-xxxxxxxxxx
        BlockDeviceMappings:
          - DeviceName: /dev/xvda
            Ebs:
              VolumeSize: !Ref DiscSize
              VolumeType: gp2
              DeleteOnTermination: true
        UserData:
          Fn::Base64:
            !Sub |
              #!/bin/bash
              set -o xtrace
              /etc/eks/bootstrap.sh sa-clstr
              /opt/aws/bin/cfn-signal --exit-code $? \
                --stack  ${AWS::StackName} \
                --resource NodeGroup  \
                --region ${AWS::Region}}
      TagSpecifications:
      - ResourceType: "launch-template"
        Tags:
        - Key: Env
          Value:  "test"
```