OmniAICreator/Qiita-1.07M huggingface dataset:
【ChatGPT】fetchでAPIを利用する方法

ChatGPTはPythonライブラリやNode.jsライブラリを使用する方法もあるが、エンドポイントへ直接POSTリクエストを送っても使用できる。


https://platform.openai.com/docs/api-reference/completions/create

下記コードをそれぞれ、適当なフォルダに置いて、index.htmlをブラウザで開く。

## HTML

```HTML:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>タイトル</title>
    <link rel="stylesheet" href="styles.css">
    <script src="main.js" defer></script>
</head>
<body>
    <h1>ChatGPTをfetchでリクエストする方法</h1>
    <form id="input-form" method="POST">
        <label for="input_text">適当に入力してください</label>
        <input type="text" id="input_text" name="input_text">
        <button type="submit">リクエスト</button>
    </form>
    <div id="output">
        <p id="generated-sentence"></p>
    </div>
</body>
</html>
```

## CSS

```css:styles.css
h1 {
    text-align: center;
}

form {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-bottom: 20px;
}
input[type="text"], button {
    transition: all 0.3s ease;
  }

  input[type="text"]:focus, button:hover {
    transform: scale(1.05);
  }
input {
    font-size: 16px;
    padding: 5px 10px;
    margin-bottom: 10px;
}

button {
    font-size: 16px;
    padding: 5px 10px;
    background-color: #4fc3f7;
    color: #fff;
    border: none;
    cursor: pointer;
    transition: background-color 0.3s;
}

button:hover {
    background-color: #039be5;
}

#output {
    display: flex;
    flex-direction: column;
    align-items: center;
}
```

## Javascript

```Javascript:main.js
window.onload = function() {
    const form = document.getElementById("input-form");
    const output = document.getElementById("generated-sentence");
    const apiKey = '***************************************';
    const endpoint = 'https://api.openai.com/v1/chat/completions';

    form.addEventListener("submit", async (event) => {
        event.preventDefault();
        const input = document.getElementById("input_text").value;
        fetch(endpoint, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${apiKey}`
                },
                body: JSON.stringify({
                    messages: [{"role": "system", "content": "これは何ですか？"},
                    {"role": "system", "content": "日本語で答えてください"},
                    {"role": "user", "content": input}],
                    model: "gpt-3.5-turbo",
                    max_tokens: 500,
                    temperature: 1,
                    n: 1,
                    stop: '###'
                })
            })
            .then(response => response.json())
            .then(data => {
                const text = data.choices[0].message.content;
                output.textContent = text;
            })
            .catch(error => console.error(error));
    });
};
```

## まとめ
今回は、CharGPT APIをfetchでエンドポイントへリクエストを送ることで使用する方法を紹介した。
【Python】教師なしクラスタリング k-means法

k-means法は古典的な非階層的クラスタリング手法で、サンプルデータをK個のクラスターに分け、中心点からの距離の近さにより分類するという方法です。

クラスタリングの流れ
1. クラスタ数をk個指定して、セントロイド(中心点)をランダムにk個配置する
1. 各サンプルを近接するセントロイドに割り当てる
1. セントロイドに割り当てたサンプルの中心を求め、セントロイドを移動させる
1. 2.と3.を繰り返し、中心点が変わらなくなったら、クラスタリング終了

## 1. Numpyで実装


```python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets

iris = datasets.load_iris()       # irisを読み込む関数
df = pd.DataFrame(        
    iris.data,                    # データフレームの要素
    columns = iris.feature_names  # 各列の名前に特徴名を使う
)

# iris.target には種類が格納されている
df["label"] = iris.target         # わかりやすくするためにlabel列を追加、ここにクラス番号を入れておきます。

print(df)

input_data = df.iloc[:,:-1].values # インスタンス属性valuesにアクセスすると、np.arrayが取得できます。

def kmeans(k, X, max_iter=300):
    X_size,n_features = X.shape # 150 4
    
    # ランダムに重心の初期値を初期化
    centroids  = X[np.random.choice(X_size,k)] # X[ 17 105  56]

    # 前の重心と比較するために、仮に新しい重心を入れておく配列を用意
    new_centroids = np.zeros((k, n_features))
    
    # 各データ所属クラスタ情報を保存する配列を用意
    cluster = np.zeros(X_size)
    
    # ループ上限回数まで繰り返し
    for epoch in range(max_iter):
        
        # 入力データ全てに対して繰り返し
        for i in range(X_size):
            
            # データから各重心までの距離を計算（ルートを取らなくても大小関係は変わらないので省略）
            distances = np.sum((centroids - X[i]) ** 2, axis=1)
            
            # データの所属クラスタを距離の一番近い重心を持つものに更新
            cluster[i] = np.argsort(distances)[0]
            
        # すべてのクラスタに対して重心を再計算
        for j in range(k):
            new_centroids[j] = X[cluster==j].mean(axis=0)
            
        # もしも重心が変わっていなかったら終了
        if np.sum(new_centroids == centroids) == k:
            print("break")
            break
        centroids =  new_centroids
    return cluster

cluster=kmeans(3, input_data)

df["cluster"] = cluster
df.plot(kind="scatter", x=0,y=1,c="label", cmap="winter") # cmapで散布図の色を変えられます。
plt.title("true label")
plt.show()

df["cluster"] = cluster
df.plot(kind="scatter", x=2,y=3,c="label", cmap="winter") # cmapで散布図の色を変えられます。
plt.title("true label")
plt.show()

df.plot(kind="scatter", x=0,y=1,c="cluster", cmap="winter") # cmapで散布図の色を変えられます。
plt.title("clustering relust")
plt.show()

df.plot(kind="scatter", x=2,y=3,c="cluster", cmap="winter") # cmapで散布図の色を変えられます。
plt.title("clustering relust")
plt.show()
```
## 2. skleanで実装

```python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
import seaborn as sns
from sklearn.cluster import KMeans

iris = datasets.load_iris()
df = pd.DataFrame(        
    iris.data,
    columns = iris.feature_names
)

df['target'] = iris.target
sns.pairplot(df, hue="target")
plt.show()

df["label"] = iris.target
print(df)

input_data = df.iloc[:,:-1].values

n_clusters = 2
clf = KMeans(n_clusters=n_clusters, init='k-means++', n_init=10, max_iter=300,tol=0.0001)
pred = clf.fit_predict(input_data)

df['label'] = pred
df.plot(kind="scatter", x=0,y=1,c="label", cmap="winter")
plt.title("clustering relust")
plt.show()
```

## まとめ
今回は、非階層的なクラスタリング手法であるk-mean法を、Numpyとskleanを用いて実装する方法を紹介した。
np.meshgridを使って格子配列を生成する

# はじめに

とりあえず調べたことを何かしらの形にするための記事なのでまずは殴り書きからはじめる
[参考](https://deepage.net/features/numpy-meshgrid.html)

# np.meshgridとは

配列の各要素から格子配列を作成するもの
`np.meshgrid(arg1,arg2)`
arg1: 横軸
arg2: 縦軸
というふうに考えることができる．
最終的にはarg1*arg2の大きさの配列が返ってくる．
2次元の例:
```python
x = [0,1,2,3]
y = [0,1,2,3]
xx, yy = np.meshrod(x,y)

###
xx = [[0,1,2,3],
      [0,1,2,3],
      [0,1,2,3],
      [0,1,2,3]]

yy = [[0,0,0,0],
      [1,1,1,1],
      [2,2,2,2],
      [3,3,3,3]]
```
3次元の例 `indexing='ij'`として行列形式にしたもの:
```python
x = [0,1,2,3]
y = [0,1,2,3]
z = [0,1,2,3]
xx, yy, zz = np.meshrod(x,y,z)

###
xx = [[[0,0,0,0],
       [0,0,0,0],
       [0,0,0,0],
       [0,0,0,0]],

      [[1,1,1,1],
       [1,1,1,1],
       [1,1,1,1],
       [1,1,1,1]],

      [[2,2,2,2],
       [2,2,2,2],
       [2,2,2,2],
       [2,2,2,2]],

      [[3,3,3,3],
       [3,3,3,3],
       [3,3,3,3],
       [3,3,3,3]]]



yy = [[[0,0,0,0],
       [1,1,1,1],
       [2,2,2,2],
       [3,3,3,3]],

      [[0,0,0,0],
       [1,1,1,1],
       [2,2,2,2],
       [3,3,3,3]],

      [[0,0,0,0],
       [1,1,1,1],
       [2,2,2,2],
       [3,3,3,3]],

      [[0,0,0,0],
       [1,1,1,1],
       [2,2,2,2],
       [3,3,3,3]]]

zz = [[[0,1,2,3],
       [0,1,2,3],
       [0,1,2,3],
       [0,1,2,3]],

      [[0,1,2,3],
       [0,1,2,3],
       [0,1,2,3],
       [0,1,2,3]],

      [[0,1,2,3],
       [0,1,2,3],
       [0,1,2,3],
       [0,1,2,3]],

      [[0,1,2,3],
       [0,1,2,3],
       [0,1,2,3],
       [0,1,2,3]]]
```

あんまりスッと歯理解できないが雰囲気でわかる

### 今回やりたかったこと
[0,0,0], [0,0,1], [0,0,2] ... [2,1,0], [2,1,1], [2,1,2], ...[3,3,3]
という格子点群を作りたかった

これらの点群座標を作成する方法を以下に示す

```python
x = np.arange(0, 4)
y = np.arange(0, 4)
z = np.arange(0, 4)

xx, yy, zz = np.meshgrid(x, y, z, indexing='ij')
result = np.vstack((xx.flatten(), yy.flatten(), zz.flatten())).T
pcd.points = o3d.utility.Vector3dVector(result)
# 可視化
o3d.visualization.draw_geometries([pcd])
```
作った点群を可視化した結果が以下となる．
![スクリーンショット 2023-04-08 19.55.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675330/dddf0e6b-39b5-f084-f5ea-50f887e0ee9d.png)


# さいごに
初めて知ったメソッドだったが点群処理などの座標情報を用いる必要がある時に有用だと感じた
この記事の日本語のタイトルは、「Chat GPTの最新アップデート：Veefの紹介」です。

最新版のChat GPTのアップデートであるVeefは、OpenAIによってGPT-3.5のアーキテクチャに基づいて開発されました。これは現在最も一般的なスマート自動回答技術の一つです。

Veefの導入により、Chat GPTは、質問に対する処理と回答、情報検索、アドバイスの提供、そしてよりスマートで自然な方法でユーザーと対話する能力が向上しました。

また、Veefの導入により、Chat GPTは、より多くの言語を理解し、より高度な文脈理解を備えています。これにより、より正確で適切な回答が可能になり、ユーザーのニーズにより適したアドバイスや情報提供ができるようになりました。

Veefは、Chat GPTの最新のアップデートであり、今後もOpenAIによって定期的にアップデートされることが期待されます。これにより、Chat GPTは常に最新の技術と情報を取り入れ、より優れたユーザー体験を提供できるようになるでしょう。
ShellScriptの練習

# はじめに
シェルスクリプトの練習として以下のような処理を書いてみました。

・第１引数に性別、第２引数に年齢を入れる
・男性と女性について、２０歳未満、男性２０歳以上６０歳未満、６０歳以上で出力する文字を変える。（６区分）
・第１引数、第２引数に適切な値が入力されていなかった場合、エラーを返す。

# 実装
```sh:sample.sh
# 引数が２つなかったらエラーを返す
# -neはnot equall
if [ $# -ne 2 ];
then
# exitと1の間にスペース必要、最後はセミコロンを忘れない
  exit 1;
fi

# $1（第１引数）には性別、$2(第２引数)には年齢を入れる
# 年齢が負の数の場合エラー出力
if [ $2 -lt 0 ];
then
  exit 1;
fi

# 男性の年齢区分
if [ $1 = "man" ];
then
  if [ $2 -le 20 ];
    echo "Man:Child"
  elif [ $2 -le 60 ];
    echo "Man:Adult"
  else
    echo "Man:Elderly"
fi

# 女性の年齢区分
if [ $1 = "woman"];
then
  if [ $2 -le 20 ];
    echo "Woman:Child"
  elif [ $2 -le 60 ];
    echo "Woman:Adult"
  else
    echo "Woman:Elderly"
fi
```

# 参考
https://www.udemy.com/course/linuxlpic
Linqでクエリ使ってみる

Linqのクエリ使ってみる

とりあえずデータ作る
```c#
Dictionary<string, string> hogeDic = new Dictionary<string, string>()
{
    {"1","" },
    {"2","" },
    {"3","" },
    {"4","" },
};

DataTable dt = new DataTable("DataTable");

dt.Columns.Add("d1");
dt.Columns.Add("d2");

dt.Rows.Add("1", "10");
dt.Rows.Add("2", "20");
dt.Rows.Add("3", "30");
dt.Rows.Add("4", "40");
```

今回は上記のデータを使ってhogeDicのデータを下記のようにしたい
```c#
1,10
2,20
3,30
4,40
```

Linqにあるクエリを使ってやってみる
```c#
var result = from dic in hogeDic
             join data in dt.AsEnumerable()
             on dic.Key equals data.Field<string>("d1")
             select new { dic, data };

Dictionary<string, string> d = new Dictionary<string, string>();
foreach (var item in result)
{
    d.Add(item.dic.Key, item.data.Field<string>("d2"));
}
hogeDic = d;

foreach (KeyValuePair<string,string> item in hogeDic)
{
    Console.WriteLine($"{item.Key},{item.Value}");
}

```
結果
```
1,10
2,20
3,30
4,40
```
できたー
Cannot find 'resource' in class org.apache.maven.plugins.shade.resource.ManifestResourceTransformer

# この手順どおり実施するとエラーとなる。
https://spring.pleiades.io/guides/gs/maven/

## エラー内容
```
Cannot find 'resource' in class org.apache.maven.plugins.shade.resource.ManifestResourceTransformer
```

## 対応
executionタグ内にidタグを追加する。
【基本情報】用語集①

# はじめに
基本情報技術者試験の勉強で学んだ用語を少しずつアウトプットしていきたいと思います。

# 用語集
|用語|内容|
|-|-|
|桁落ち|ほぼ同じ数同士の減算で有効桁数が減ってしまうことによる誤差|
|オーバーフロー|演算結果が、処理できる数値の最大値を超えてしまうこと|
|丸め誤差|四捨五入や切り捨て、切り上げによる誤差|
|情報落ち|大きな数と小さな数を加算したとき、小さな数が演算結果に反映されないことによる誤差|
|サンプリング周波数|アナログデータを1秒間に何回サンプリングするか|
|量子化ビット|サンプリングデータ1個当たりのサイズ|
|リスト|各要素は値とポインタの組で構成され、各要素のポインタに次の要素のアドレスが格納されているデータの集合|
|MIPS|プロセッサが1秒間に実行する命令数を百万単位で表したもの|
|ホットスタンバイシステム|待機系が現用系と同時に稼働|
|コールドスタンバイシステム|待機系はふだん現用系と違う処理を担当|
|射影|特定の列を取り出す|
|選択|特定の行を取り出す|
|結合|複数の表を共通する項目をキーにして結合する|
Windowsの共用PCからGitHubにpushしたいけど認証が通らない時

　色々と調べて知見が湧いたので。

# 想定する状況

　例えば共用PCで作業したとして、それを自分のリポジトリに反映させたい。しかし、ブラウザでは GitHub にアクセスできても、`push` しようとすると `Permisson Denied` と出る。

# 方法

## ブラウザのプロフィールタブから `Settings` を選ぶ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/3852ef58-8637-6671-cafd-67ff335fcf64.png)

## `Developer settings` を選ぶ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/b445e031-c01a-e60b-85f2-4c983421fddd.png)

## `Personal access tokens` のタブから `Tokens(classic)` を選ぶ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/ff5e3f72-b6a2-94c9-e66c-1b0278841214.png)

## `Generate new token` から `Generate new token(classic)` を選ぶ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/cde377e7-fb17-7792-83fa-63a7e2f9152c.png)

## `Note`に適当な名前をつけ、`repo`にチェックを入れる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/7c12ce19-b7ae-fd35-c13b-8d2d366d6d19.png)

## トークンが生成されるのでコピーする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/f15ab2d1-13bd-00d3-a0a2-eaff665cc23e.png)

　これは一度表示を消したら再表示できないのでメモする。もちろん他人に知られてはいけない。

## Windows の資格マネージャーを開く

　スタートメニューに「資格情報」と打つとサジェストされるはず

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/23b38a7a-3d0a-6d05-5341-1775242a1ee0.png)

## 「Windows 資格情報」の「汎用資格情報」から`git:https://github.com`の「編集」を選ぶ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/8862d552-2e8b-d77a-f090-3a4d37545210.png)

　もしなければ、「汎用資格情報の追加」を選ぶ。この場合、次の操作は「編集」ではなく「追加」となる。

## ユーザー名とパスワードを入れる

　ユーザー名は自分の GitHub 上のユーザー名、パスワードはさっき生成されたトークンをコピペする。

# 完了

　これでリポジトリに編集を加えられるようになったはず。

　共用PCに認証情報が残っていると危ないので、編集が終わったら資格情報は「削除」しておいた方がいい。
Kubernetes expose TCP service with nginx ingress controller

# Background

In our case we build a kubernetes cluster with some linux virtual machines. Some of services in our cluster need layer 4 transport access from outside of cluster such as database and redis etc. However the default kubernetes ingress dose not support this. So we need use other ingress controller to achieve it. One of the famous ingress controll is nginx ingress controll. Here we will introduce a way to expose a tcp service with nginx ingress controller. 

# Requirements 

- Nginx Ingress Controller
Before expose your tcp service you need install the nginx ingress controller. Nginx Ingress Controller provided a helm chart, with the helm chart we can easily install the ingress controller, for the detailed information, please refer the official document [here](https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-helm/).

- Open the Port
You need to ensure the exposed port should be abled to be accessed outside from the cluster.

# Steps to setup
## Create ConfigMap
As the official document metioned, we can not directly setup from ingress, we need specify a config map and let the ingress controller refer the config map. So we need create a config map and specify the port which will be exposed and the backend service.

> Ingress does not support TCP or UDP services. For this reason this Ingress controller uses the flags --tcp-services-configmap and --udp-services-configmap to point to an existing config map where the key is the external port to use and the value indicates the service to expose using the format: <namespace/service name>:<service port>:[PROXY]:[PROXY]

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: tcp-services
  namespace: ingress-nginx
data:
  3306: "mynamespace/mysql:3306"
```

## Add args from ingress controller

Confirm if your ingress controller pod has `--tcp-service-configmap` argument and the value is pointed to the config map you just created. If No you need to edit the ingress controller deployment and add it and deploy the ingress controller.

```yaml
apiVersion: v1
kind: Pod
spec:
  containers:
  - args:
    - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
```

If the argument `--tcp-services-configmap` has been configured before. When you create/edit the config map. The ingress controller will load it automatically. And you will see some logs like this from ingress controller pods.
```log
I0404 06:40:50.714239       7 controller.go:168] "Configuration changes detected, backend reload required"
I0404 06:40:50.818643       7 controller.go:185] "Backend successfully reloaded"
``` 

# References

https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-helm/
https://lokie.wang/article/126
Google Calendar APIを叩いて予定を追加する

色々調べてやってみたけど404って突き返されたりして困ったから書いとく。
# 1. 下準備
## 1.1. API諸々を作成

[Google Server Platform](https://console.cloud.google.com/)で作業を進める。

### 1.1.1. APIを有効化

1. 真ん中上の検索窓で”**Calendar API**”を検索
2. “**Google Calendar API**”を選択
3. 「有効化」

### 1.1.2. サービスアカウント作成

1. 検索窓で”**サービス アカウント”**を検索
2. 「サービスアカウントを作成」から適当に作る

### 1.1.3. 秘密鍵を取得

1. 1.2.で作成したアカウントを選択
2. 「キー」を選択し「鍵を追加」→ 「新しい鍵を作成」 
3. JSONを選択し作成
4. 秘密鍵がダウンロードされるため任意のフォルダに配置

### 1.1.4. ****サービスアカウントの****メアドをコピー

「詳細」タブにあるメールアドレスをコピーしておく。(次で使う)

## 1.2. Google Calendarでアカウントを追加

1. [Google Calendar](https://calendar.google.com/)の設定へ行く。
2. マイカレンダーの設定から予定を追加したいカレンダーを選択
3. “特定のユーザーまたはグループと共有する”の「ユーザーやグループを追加」を選択
4. さっきコピーしたメアドをペーストして権限を”変更および共有の管理権限”にする

そのまま下に行って”カレンダー ID”のメアドをコピー(後で使う)

# 2. APIを叩く

Pythonでやってく

## 2.1. ライブラリを入れる

```bash
pip3 install google-api-python-client google-auth
```

## 2.2. 書く
こんなかんじ

```python
import datetime
from google.oauth2 import service_account
from googleapiclient.errors import HttpError
from googleapiclient.discovery import build

creds = service_account.Credentials.from_service_account_file('ここで鍵のパスを指定')
service = build('calendar', 'v3', credentials=creds)

calendar_id = 'ここにさっきのID(メアド)を入れる'  

def create_event(summary, start_time, end_time):
    event = {
        'summary': summary,
        'start': {
            'dateTime': start_time.strftime('%Y-%m-%dT%H:%M:%S'),
            'timeZone': 'Asia/Tokyo',
        },
        'end': {
            'dateTime': end_time.strftime('%Y-%m-%dT%H:%M:%S'),
            'timeZone': 'Asia/Tokyo',
        },
    }
    try:
        event = service.events().insert(calendarId=calendar_id, body=event).execute()
        print(f'Event created: {event.get("htmlLink")}')
    except HttpError as error:
        print(f'An error occurred: {error}')
        event = None
    return event

start_time = datetime.datetime(2023, 4, 9, 9, 0, 0)
end_time = datetime.datetime(2023, 4, 9, 10, 0, 0)
create_event('Meeting with John', start_time, end_time)
```
# できた！
proxmoxのインストール中にWaiting for /dev to be fully populated...で止まる

手持ちのノートPCにprxmmoxをインストールしようとしたところ、
```
Waiting for /dev to be fully populated...
```
で止まり進まなかった。

# 対応
このページを参考にdebianをインストールした後にproxmoxをaptからインストールしたところインストールに成功した。
https://computingforgeeks.com/how-to-install-proxmox-ve-on-debian-bullseye/

なお、debianセットアップ時にパーティションを設定するが、
このときルートのext4パーティションは極力小さくし別にlvm用パーティションを切ることをおすすめする。
これを行うことで後ほど利用するproxmoxのlvmボリュームへの割り当てを行うことができる

[公式のインストール手順](https://pve.proxmox.com/wiki/Install_Proxmox_VE_on_Debian_11_Bullseye)もあったが私の環境ではうまく動かず、再起動でフリーズし復帰しなかった。
`apt install pve-kernel-5.15`を実行するとだめらしい。これを実行せずに次の`apt install proxmox-ve postfix open-iscsi`だけで上手くいった。


# 他の対応
うまくいかなかったが調査の過程で試したもの

https://forums.debian.net/viewtopic.php?t=96090

https://www.antixforum.com/forums/topic/another-case-of-waiting-for-dev-to-be-fully-populated/

これらを参考に起動オプションに`nomodeset`や`nomodeset nosplash`を設定したがうまく動作しなかった。
今回使用したノートPCにはAMD Ryzen 5 5625Uが搭載されており、CPU内蔵のGPUあたりがうまく動かなかったのではないか、と予想している。
【SIGNATE】渋滞予測チャレンジコンテストに挑戦しました

# はじめに
Data Science League エンジニアのエザワです。
2023年1月25日～3月31日に開催されていたNEXCO東日本・東京大学大学院情報学環が主催する≪[渋滞予測チャレンジコンテスト](https://signate.jp/competitions/932#abstract"渋滞予測チャレンジコンテスト")≫に参加しました。
DSLからは3チーム＋個人3人の合計15名が挑戦しました。

https://signate.jp/competitions/932#abstract

# コンペの内容
このコンペは、データを使用して渋滞予測を行うモデリング部門と、データ活用した新規サービスを考えるアイデア部門があり、DSLはモデリング部門に参加しました。

モデリング部門は、トラフィックカウンターによって計測される速度や交通量のデータや、[高速道路ルート検索](https://www.driveplaza.com/dp/SearchTop"高速道路ルート検索")データを利用して、高速道路が渋滞しているかどうかを1時間毎に予測するというもので、精度評価はF1scoreが使用されていました。
### F1scoreとは？
二値分類の予測において、適合率と再現率の調和平均を取った値。

|予測\正解  |正  |負 |
|:---:|:---:|:---:|
|**正**  |TP(True Positive)<br>真陽性|FP(False Positive)<br>偽陽性|
|**負**  |FN(False Negative)<br>偽陰性|TN(True Negative)<br>真陰性|

TP : 正と予測し、その予測が正しい
FP : 正と予測し、その予測が誤り
FN : 負と予測し、その予測が誤り
TN : 負と予測し、その予測が正しい

**適合率(precision)**
正と予測した中で正解が正だった割合
```math
   \frac{TP}{TP+FP}
```

**再現率(recall)**
正解が正の中で正と予測した割合
```math
\frac{TP}{TP+FN}
```

**F1score**
```math
\frac{2*recall*precision}{recall+precision}
```

# データについて

トラフィックカウンターによって計測されたデータ、道路構造データ、「ドラぷら」ルート検索データが用意されていました。
    トラフィックカウンターデータは平均速度や通過台数、「ドラぷら」ルート検索データは検索時刻、出発ICと到着ICなどのデータがありました。
私は免許を持ってないため、高速道路に関する知識や仕組みが全然分からず、チームメンバーに沢山助けてもらいました、、、

# 提出までの流れ
今回のコンペでは、学習済みモデルと予測プログラムを一つのフォルダにまとめたものを提出するという形式でした。

特徴量生成は、チームで仮説を立てながら色々作ってみました。
・連休初日は渋滞しやすそう
・都心に近づくほど渋滞しやすそう
・深夜は渋滞しにくい
などなど、、

モデルには、前回（[金融データ活用チャレンジ](https://qiita.com/Data_Science_League/items/d9c6260f3c8b139edd5a"金融データ活用チャレンジ")）でもお世話になった最強LightGBMを使用しました。

今回は時系列データだったので、バリデーションの際にはscikit-learnに入っているTimeSeriesSplitを使用して分割をしてみました。
時系列データは、時間的に近いデータが似た傾向を取ることが多く、単純にランダムに分割してしまうと、バリデーションデータと同じ期間のデータで学習できてしまいます。そうすると、予測が簡単になり、モデルの性能を過大評価してしまう可能性が高くなってしまいます。
TimeSeriesSplitも時間情報を使って分割するわけではなく、データの並び順だけで分割するので、時系列データに良い分割方法とは言えませんが、ランダム分割よりは精度が上がりました。
TimeSeriesSplitに関する詳しい内容と改良については[こちらの記事](https://blog.amedama.jp/entry/time-series-cv"TimeSeriesSplit")がとても分かりやすいです。

https://blog.amedama.jp/entry/time-series-cv

金融データ活用チャレンジに参加したときの記事↓↓↓

https://qiita.com/Data_Science_League/items/d9c6260f3c8b139edd5a


# 感想
今回もチームメンバーのおかげで最後まで走り切ることができたなあと思っています。最終日はzoomで話しながら23時59分まで粘ったのも楽しかったです。（スコアは上がりませんでしたが）
チームの枠を超えて、エラー解消などみんなでワイワイ話しながらできて楽しかったです。
もう全部楽しかったです。
反省点は、コンペに割く時間が少なかったことです。最終日にもっと色々やっておけばよかったと大後悔しました。次はチームでも個人でももっと作業時間を増やして挑戦します。

# 最後に
今回は初の試みとして初心者向けのフォローアップ会を開催しました。
これのおかげか、コンペに参加したことがない、Pythonを使ったことがないメンバーも参加してくれてとても嬉しかったです。
次回以降もコンペに参加する際はフォローアップ会開催しようと思うので、初心者の方でもコンペに参加したい！という方は是非DSLに入っていただきたいです。


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">塾生注目❗️📢<br><br>私たちDATA SCIENCE LEAGUEは、これから<br><br>毎週土曜日20:00〜の日時で説明会を開きます！<br><br>深層学習・生成系AI(Generative AI)が世界を席巻している今、私たちと共にデータサイエンス・AIの世界に飛び込みましょう！🔥<br><br>参加リンクは以下から👇<a href="https://twitter.com/hashtag/%E6%98%A5%E3%81%8B%E3%82%89%E6%85%B6%E6%87%89?src=hash&amp;ref_src=twsrc%5Etfw">#春から慶應</a> <a href="https://t.co/HZnD7swtM9">pic.twitter.com/HZnD7swtM9</a></p>&mdash; DSL | データサイエンス特化型学生団体 (@DSL_Tw) <a href="https://twitter.com/DSL_Tw/status/1643908736921243648?ref_src=twsrc%5Etfw">April 6, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
レイマーチングに関するメモ書き<随時更新>

## 法線のアーティファクト解消
レイマーチングのノーマルのアーティファクトがひどい時はeの係数を大きくするといい感じになる。例えば以下の実装だといつもは0.001とするところを0.1としている。もしかしたら他の係数のとこも大きくするとアーティファクトがいい感じに収まるのかもしれない
```
vec3 gn(vec3 p)
{
  vec2 e = vec2(0.1,0.0);
  return normalize(vec3(
      map(p+e.xyy)-map(p-e.xyy),
      map(p+e.yxy)-map(p-e.yxy),
      map(p+e.yyx)-map(p-e.yyx)
  ));
}
```
if(1)if で整列、気持ち良いコードに

### これが
```js
if (opt.range === ENUM.dsasdf) {
} else if (opt.range === ENUM.sdf) {
} else if (opt.range === ENUM.asdfadsf) {
} else if (opt.range === ENUM.zxvv) {
}
```
### こう
```js
if (1) if (opt.range === ENUM.dsasdf) {
} else if (opt.range === ENUM.sdf) {
} else if (opt.range === ENUM.asdfadsf) {
} else if (opt.range === ENUM.zxvv) {
}
```

### こちらも
```js
if (0) { }
else if (opt.range === ENUM.dsasdf) { }
else if (opt.range === ENUM.sdf) { }
else if (opt.range === ENUM.asdfadsf) { }
else if (opt.range === ENUM.zxvv) { }
```
※賛否有り
【Unity】LoopScrollRect をスナップさせる試み


# 概要

LoopScrollRect にスナップ機能が無かったので、拡張メソッドを作ってみました。

https://github.com/qiankanglai/LoopScrollRect

### 注意点

Padding や Spacing を利用すると正しく機能しなくなります。
Cell 内に余白を設ければ一応 Spacing のような事ができます。
実装メモから記事化まで半年以上経っていたので、不具合があったり正式にスナップ機能が実装されていたりするかもしれません。コメントをいただけると助かります。

# コード

お手持ちの LoopScrollRectEx に追加してご利用ください。

``` C#
using UnityEngine;
using UnityEngine.UI;

public static class LoopScrollRectEx
{
    public static void Snap(this LoopScrollRectBase scrollRect, float width, int defaultViewCount = int.MaxValue, float duration = 0.2f)
    {
        scrollRect.StopMovement();
        if (scrollRect.content.childCount <= defaultViewCount) return;

        var firstIndex = scrollRect.GetFirstItem(out var offset);
        scrollRect.SrollToCellWithinTime(firstIndex + (offset >= -width * 0.5f ? 1 : 0), duration);
    }
    public static void SnapX(this LoopScrollRectBase scrollRect, GameObject cell, int defaultViewCount = int.MaxValue, float duration = 0.2f)
    {
        scrollRect.StopMovement();
        if (scrollRect.content.childCount <= defaultViewCount) return;

        var firstIndex = scrollRect.GetFirstItem(out var offset);
        var width = (cell.transform as RectTransform).rect.size.x;
        scrollRect.SrollToCellWithinTime(firstIndex + (offset >= -width * 0.5f ? 1 : 0), duration);
    }
    public static void SnapY(this LoopScrollRectBase scrollRect, GameObject cell, int defaultViewCount = int.MaxValue, float duration = 0.2f)
    {
        scrollRect.StopMovement();
        if (scrollRect.content.childCount <= defaultViewCount) return;

        var firstIndex = scrollRect.GetFirstItem(out var offset);
        var width = (cell.transform as RectTransform).rect.size.y;
        scrollRect.SrollToCellWithinTime(firstIndex + (offset >= -width * 0.5f ? 1 : 0), duration);
    }
}
```
PythonでSQLiteに接続してみた

SQLiteでデータベースを作成し、Pythonで作成したデータベースに接続してみた

# 使うもの
・DB Browser for SQLite
https://sqlitebrowser.org/dl/

上記のURLを開いてスクロールしていくと、インストーラーがダウンロードできます。
Macの方は、お使いのPCに合わせてAppleSiliconかIntelを選択してください

# データベースの作成
1.DB Browser for SQLiteを開きます

2.「新しいデータベース」をクリックします
![スクリーンショット 2023-04-08 17.17.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/539961ef-4250-9248-8eab-581aeec2091e.png)

3.ウインドウが開くので、Save Asに適宜データベース名を入力します
これがファイル名になります。
例： sample → sample.db

4.テーブルを作成します
こちらを参考にしてください
https://shigeblog221.com/sqlite-dbbrowser/#:~:text=%E5%85%A5%E5%8A%9B%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82-,%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90,-%E7%B6%9A%E3%81%91%E3%81%A6
レコードも作成しておいてください

5.Pythonでデータベースに接続
データベースとテーブルが作成できたのでPythonで接続したデータベースに接続してみます
接続してテーブルをselectしてレコードを参照してみます

・ディレクトリ構成
```
sample.db
sqlite.py
```
.dbファイルとPythonファイルが同じ階層にあるとします

```python:sqlite.py
import sqlite3

# データベースファイルのパスを設定
db_name = 'sample.db'

# データベースに接続
con = sqlite3.connect(db_name)

# データベースを操作するカーソルを作成
cur = con.cursor()

# Select文を作成
sql = 'select * from sample_table1' # テーブル名は適宜設定してください

# SQLを実行
cur.execute(sql)

# SQLの結果を出力
for row in cur:
    print(row[0], row[1]) # カラム数に応じてrow[x]を変更してください

# データベース接続を終了
con.close()
```

久しぶりにプライベートでSQLiteを使用してみました。
かなり期間が空くと使い方を忘れていますが、ネットに使い方を解説したサイトがあるのでググれば解決するのは助かります。
Qiitaに記事を投稿するにあたり，書いた方がいいこと(フォーマット)

# 概要
　今年(2023年)から，Qiitaを使用し，学んだ知識を残していこうと思っている。これまで，ITエンジニアQ&Aサイトで質疑したことはあるが，一度も記事を投稿しことがない。記事を投稿する前に，記事に記載すべき項目を他人の記事を閲覧して調査した。

# 記事を投稿するにあたり，書いた方がいいこと(フォーマット)
1. タイトル
　[良い記事を書くためのガイドライン](https://qiita.com/predora005/items/342b50859e2aeafc39b6)に記載してあるように，「具体的で簡潔なタイトル」を記載する。

1. 概要
　記事内容を投稿する前に，「目的」や「経緯」などを記載する。

1. 開発・実行環境(前提条件)
　投稿内容が，環境に依存する場合は記載する。依存しない場合は，記載しなくてよい。

1. 内容
　タイトルに沿った「内容」を記載する。「内容」のボリュームが大きい場合は，「見出し」や「箇条書きリスト」，「番号付きリスト」を使用して，見やすいように記載する。

1. 参考サイト・図書
　参考にしたサイトや図書がある場合は記載する。なければ記載しなくてよい。

1. 所感
　投稿記事に対する所感を記載すると良い。なければ記載しなくてよい。

# 参考サイト
[テンプレート機能とは](https://qiita-team.zendesk.com/hc/ja/articles/4640664960399-%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E6%A9%9F%E8%83%BD%E3%81%A8%E3%81%AF)
[Qiitaアカウント作成方法、記事の書き方、投稿手順](https://qiita.com/predora005/items/342b50859e2aeafc39b6)
[Qiitaで簡単に記事を書くためのフォーマット](https://qiita.com/kenseitogari1/items/1dcf4328d54e9f2c087c)
[Markdown記法 チートシート](https://qiita.com/Qiita/items/c686397e4a0f4f11683d)

# 所感
　他人が投稿している記事を閲覧して，記載したほうがいい内容が分かった。次回以降は上記で記載したフォーマットで投稿していこうと思う。
macでのxmgraceのインストール

備忘録として残します。

## 動作環境
- macOS Monterey
- Mac mini (M1, 2020)
- メモリ 16GB

## インストール
まず、homebrewでxmgraceのパッケージをインストールします。
```
brew install grace
```
このままxmgraceを起動させようとしても以下のエラーが出ます。
```
Can't open display
Failed initializing GUI, exiting
```

これはxmgraceはX Window System上でGUIを提供しているため、macOSで動かすにはXQuartzが必要だかららしいです。
従って、私は[こちら](https://www.xquartz.org/index.html)からXQuartzバージョン2.8.5を直接ダウンロードしました。

以上の手順でmacOSでxmgraceを起動させることができました!

## 追記
エラーを調べている際に
```
DISPLAY=:0.0 xmgrace 
```
でDISPLAY環境変数を変更するという対処法も見ましたが、私の場合変化はありませんでした。
DDD初心者でも仲良くなりたい ~ CQRS（コマンドクエリ責務分離）編 ~

## はじめに
CQRSは決してDDDのみで用いられる設計パターンという訳ではありません。しかし、一覧画面の表示のように複数の集約から値を取り出すような場面ではDDDで効果を発揮する設計パターンになります。
※初学者の学習メモです。

## 課題
DDDの実装パターンでは、基本的には永続化層との入出力はRepositoryを使うことになります。更新系の処理ではEntityやValue Objectでドメインの知識を表現し、Repositoryを使って集約単位で永続化するとう構成をとるとメンテナンス性が高まります。

一方、参照系の処理、特に一覧画面では、複数集約の値を組み合わせた結果を画面に返すことが多くなります。
もし、複数の集約がありそれぞれにRepositoryがある場合、1つのUseCase(Application Service)で実装しようとすると、Repositoryからそれぞれの値を取得し、戻り値のオブジェクトに詰め替えるような実装にせざるを得ません。

このデメリットとして、
- 複数の集約から値を取得して戻り値に詰め替える処理が、ループが増えて読みにくくなる
- 画面に返す必要のない値を一度取得するのでパフォーマンスが悪化する
- 複数集約の条件（where）で絞り込んでのページングができない
などが挙げられます。

## 対策
CQRS（コマンドクエリ責務分離）を導入します。CQRSは「情報の参照に使用するオブジェクトと更新に使用するオブジェクトは異なるものを使う」アーキテクチャになります。

>書き込み(コマンド）と読み込み（クエリ）は別々に取り扱うべきと考える設計方法。
>- 書き込み->データの入力のような記憶領域に保管すること。
>- 読み込み->データの出力で、記憶領域からデータを取り出すこと。

![model_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969534/bac6c1e3-8e11-e794-6dfd-3ff71971138e.png)
DDDのアーキテクチャでは、QueryServiceのInterfaceとをUseCase層に、実装クラスはRepositoryと同様にインフラ層に配置します。UseCaseは抽象的な知識だけ持ち、実装の知識はインフラ層に隠蔽します。
![model_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969534/fcf1aa46-f7c3-604f-71ba-d15002f6bbc0.png)
上記図の更新系では、Repositoryを用いて集約単位でデータの永続化を行い、参照系はQueryServiceで複数のテーブルをjoinして取得するクエリを書き、シンプルに結果をDTOに詰め替えるような構成にします。

これによって、
- 複数集約にまたがるデータを取得する際のコードがシンプルになりメンテナンス性が高まる
- クエリパフォーマンスが上がり、チューニングしやすくなる
- 複数集約の条件（where)で絞り込んでのページングができるようになる
などが見込めます。


>参考文献：　https://little-hands.hatenablog.com/entry/2019/12/02/cqrs
> PHPフレームワークLaravel Webアプリケーション開発
Qiitaで記事を書く時のMarkdownテンプレートコピペ用


# 目的

目的を書く


# 今回やること

今回の目標は以下のnつ。
* 目的1
* 目的2


# 環境
* MacBook Air(M2チップ)
* rails 7
* ruby 3.2

# いざ出陣

### 中タイトル1

```html:テンプレート

```

### 中タイトル1

```html:テンプレート

```

# 余談
M1 Macでのgcc環境構築

gccをhome brewで環境構築した際のメモ
このpathはMacに標準で入ってるもの

```
$ brew install gcc
$ which g++
/usr/bin/g++
```

` brew` でインストールしたものは `/opt/homebrew/bin/` にインストールされる

```
$ ls /opt/homebrew/bin | grep g++
```

シンボリックリンクを貼る

```
$ ln -s /opt/homebrew/bin/g++-12 /opt/homebrew/bin/g++
$ export PATH=/opt/homebrew/bin:$PATH # パスが通ってなかったらパスを通す
```

```
$ which g++
/opt/homebrew/bin/g++
```
VSCode機能拡張で行末をそろえる「LineEnd Straighten」

# はじめに
なぜないの
VSCodeの
行末そろえる機能

というわけで、作ってみました。
一部の行末をそろえたいときってありませんか。ありますよね。特に、SQLを書くとき！

```
SELECT
    XXX_ID,
    USER_NAME,
    ORGANIZATION_CODE
FROM
    PERSON
;
```
からの
```
SELECT
    XXX_ID              AS ID,
    USER_NAME           AS NAME,
    ORGANIZATION_CODE   AS CODE
FROM
    PERSON
;
```
とか書くために、ASの前までスペースやタブで埋めたいこと、ありますよね？？
スペースさえ埋まれば、そのあとはマルチカーソル（Ctrl+下とか）で書いていけばいいんです。行末のカンマを消すとかも、マルチカーソルでいけます。

でも"埋める"がなくて、ググってもパッとしないので、作りました。

使ってみたい方は、VSCodeの機能拡張の検索で「LineEnd Straighten」で！行末をまっすぐに揃える、という感じの意味です。`LineEnd`で検索すれば出るからフルスペル覚えなくていいですよ。

# インストール方法
1. VSCodeの左の機能拡張から、`LineEnd Straighten`(LineEnd)を検索してインストール

（簡単）

# 使い方

1. スペースで埋めたい行を選択して
1. Ctrl+K

（簡単）

# 作り方～公開まで
1. `npm` の `yo generator-code`を使って、HelloWorldアプリを作り
    - 参考：[VSCode Extensions(拡張機能) 自作入門 〜VSCodeにおみくじ機能を追加する〜 - Qiita](https://qiita.com/HelloRusk/items/073b58c1605de224e67e)
1. 関数を作って
    - 参考：[VSCodeの拡張開発に入門してみました | GMOアドパートナーズ TECH BLOG byGMO](https://techblog.gmo-ap.jp/2020/12/28/vscode-extension-dev/)
1. 公開しました。
    - 参考：[VSCodeの拡張機能の公開手順](https://zenn.dev/ryo_kawamata/scraps/986c4466c02013)

（簡単）

ソースは下記においておきました。

https://github.com/yo16/vscode_lineend_straighten


# まとめ
私なりの工夫点なんて無いんです。あえていえばアイデアくらいなので、Qiitaに書くべきか迷うレベルです。
簡単なので、皆さんも思い付きでVSCodeの機能拡張作ってみてはいかがでしょうか。公開せず、自分や周囲の人までにとどめるのなら本当に簡単です。
AWS Glueとは何か？

こいつに入門します。

https://aws.amazon.com/jp/glue/


# 一言でいうと…
マネージドETLサービスです。

- ETLとは「Extract/Transform/Load」の略で、分析用に様々なデータを集める際に発生する「取り出す/変換する/取り込む」というプロセスを表しています。
- Glueとは「糊」のことで、ETLにおいてAWSのリソースとリソースを繋ぐことの比喩になっているようです。

※ややこしいですがDevOps Guruというサービスも最近出現しています。このGuruは「賢者」を表す別単語で、機械学習を活用した賢いサービスを比喩しているものと思われます。


# Glueの概念図
データソースから取り込んだデータをETLジョブで加工し、ターゲットに格納して分析などに利用します。
![スクリーンショット 2023-04-08 15.59.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/42e22d35-a00c-45e2-0002-1f4db1b48a5b.png)



# Glueのコンポーネント
### データカタログ
ETL処理をしたいデータのメタデータを管理するもの。元データ（データソース）からGlueのクローラーで抽出してきたもの。

### ETLジョブ
ETL処理そのもの。Glueのサーバーレスエンジンにて実行される。

ジョブ形式
- Python
- Spark：Kinesis Data Streamsをデータソースとしてストリームデータを取り込むことが可能。


# 便利機能
### ビジュアルETL（Glue Studio）
GUIを使ってノーコードでETLジョブを作成できます。

### ワークフロー
複数のクローラー、ジョブ、トリガーを使う複雑なETL処理を作成し、可視化できる。
位置付けはStep Functionと少し似ています。


# 似たAWSサービス

### Glue DataBrew
https://aws.amazon.com/jp/glue/features/databrew/

分析データの前準備（クリーンアップや正規化）をノーコードで簡単に行えるサービス。
GlueにもビジュアルETL（Studio）があるが、DataBrewの方が完全ノーコードで出来ることが多い。

Glue Studioはスキーマ操作寄り、DataBrewはデータの中身の処理寄り。



# 利用料金
- ジョブ/クローラー：使用したリソース量と時間で課金
- データカタログ：データ量とアクセス量で課金


# その他、勉強に役立つページ
### AWS Black Belt
https://aws.amazon.com/jp/blogs/news/webinar-bb-aws-glue-2019/


### ハンズオン（Glue Studio）
https://aws.amazon.com/jp/blogs/big-data/making-etl-easier-with-aws-glue-studio/
RubyでAtCoder ABC286(A, B, C, D)を解いてみた

# はじめに
Webエンジニアを目指して、RubyやRailsをいじってます。
今回は、RubyでAtCoder ABC286のA, B, C, Dを解きました。備忘録として解き方をまとめていきたいと思います。

# A - Range Swap
https://atcoder.jp/contests/abc286/tasks/abc286_a
```ruby:a-286.rb
N, P, Q, R, S = gets.split.map{ |x| x.to_i - 1}
a = gets.split(" ")
a[P..Q], a[R..S] = a[R..S], a[P..Q]
puts a.join(" ")
```
## 解説
問題文の通りに実装すればOKです。

# B - Cat
https://atcoder.jp/contests/abc286/tasks/abc286_b
```ruby:b-286.rb
gets
s = gets.chomp
puts s.gsub(/na/, "nya")
```
## 解説
gsubメソッドを使って文字列に含まれるすべての"na"を"nya"に置換しています。

# C - Rotate and Palindrome
https://atcoder.jp/contests/abc286/tasks/abc286_c
```ruby:c-286.rb
n, a, b = gets.split.map(&:to_i)
s = gets.chomp.chars * 2
ans = 10 ** 18
n.times do|i|
    sum = a * i
    (n / 2).times do|j|
        l = i + j
        r = i + n - j - 1
        sum += b if s[l] != s[r]
    end
    ans = [ans, sum].min
end
puts ans
```
```ruby:別解
n, a, b = gets.split.map(&:to_i)
s = gets.chomp.chars * 2
ans = Float::INFINITY
n.times do|i|
    count = (0...n / 2).count{ |j| s[i + j] != s[i + n - j - 1] }
    sum = (a * i) + (b * count)
    ans = [ans, sum].min
end
puts ans
```
## 解説
（公式解説を参考にしました）

まず、A円払って左端の文字を右端に移動するという操作を再現するために与えられた文字列に自身を連結しています。なお、配列にしないとTLEしてしまいます（配列にすればTLEしないということがたまにあります）。また、N回繰り返すと元の文字列に戻るという性質とNが5000以下と小さいことから、A円を支払う操作の回数について全探索することができます。

sumの初期値をA円*（支払った回数）とします。そして、置き換える必要があればB円をsumに加算していき、ansをsumが最小値であったものに更新していきます。最後に、最終的なansを出力すればOKです。

# D - Money in Hand
https://atcoder.jp/contests/abc286/tasks/abc286_d
```ruby:d-286.rb
# 修正前
n, x = gets.split.map(&:to_i)
a_array, b_array = [], []
n.times do
    a, b = gets.split.map(&:to_i)
    a_array << a
    b_array << b
end 

dp = Array.new(n + 1){Array.new(x + 1, false)}
dp[0][0] = true
n.times do|i|
    (x + 1).times do|j|
        (b_array[i] + 1).times do|k|
            dp[i + 1][j] = true if j - a_array[i] * k >= 0 && dp[i][j - a_array[i] * k]
        end
    end
end
puts dp[n][x] ? "Yes" : "No"
```
```ruby:d-286.rb
# 修正後
n, x = gets.split.map(&:to_i)
a_array, b_array = Array.new(n) { gets.split.map(&:to_i) }.transpose

dp = Array.new(n + 1){Array.new(x + 1, false)}
dp[0][0] = true
n.times do|i|
    (x + 1).times do|j|
        (b_array[i] + 1).times do|k|
            dp[i + 1][j] = true if j - a_array[i] * k >= 0 && dp[i][j - a_array[i] * k]
        end
    end
end
puts dp[n][x] ? "Yes" : "No"
```
## 解説
（公式解説を参考にしました）

この問題は、DPを使って解くことができます。dp[i][j]：A[1], A2[2], ..., A[i]硬貨を使ってちょうどj円支払えるならtrue、支払えないならfalseとして考えます。

まず、i=0のときはdp[0][0]=true、それ以外はfalseとします。そして、順にj-kA[i]>=0かつdp[i][j-kA[i]]=trueならdp[i+1][j]=trueと更新していきます。最後に、dp[N][X]=trueならYesを、falseならNoを出力すればOKです。

# 終わりに
C問題とD問題が解けませんでした...悔しい。

https://qiita.com/shoya15/items/50fd17e37d7c64f2b166
JUnit5 annotation @MethodSource

## @MethodSource

It allows us to load the inputs from one or more factory methods of the test class or external classes. Each factory method must generate a stream of arguments.

- Explicit method source 
    The test will try to load the supplied method.

```Java
@ParameterizedTest
@MethodSource("checkExplicitMethodSourceArgs")
void checkExplicitMethodSource(String word) {
  assertTrue(StringUtils.isAlphanumeric(word), "Supplied word is not alpha-numeric");
}


static Stream<String> checkExplicitMethodSourceArgs() {
  return Stream.of( "a1" , "b2" );
}
```

- Implicit method source
  it will search for the source method that matches the test-case method name.


```Java
@ParameterizedTest
@MethodSource
void checkImplicitMethodSource(String word) {
  assertTrue(StringUtils.isAlphanumeric(word), "Supplied word is not alpha-numeric");
}


static Stream<String> checkImplicitMethodSource() {
  return Stream.of( "a1" , "b2" );
}
```

- Multi-argument method source
  We must pass the inputs as a Stream of Arguments.
  It will automatically map arguments based on the index.


```Java
@ParameterizedTest
@MethodSource
void checkMultiArgumentsMethodSource(int number, String expected) {
  assertEquals(StringUtils.equals(expected, "even") ? 0 : 1, number % 2);
}


static Stream<Arguments> checkMultiArgumentsMethodSourceArgs() {
  return Stream.of(Arguments.of(2, "even"),
                   Arguments.of(3, "odd"));
}
```

- External method source
  It will try to load the external method.

```Java
@ParameterizedTest
@MethodSource("source.method.ExternalMethodSource#checkExternalMethodSourceArgs")
void checkExternalMethodSource(String word){
   assertTrue(StringUtils.isAlphanumeric(word), "Supplied word is not alpha-numeric");
}
```

```Java
package source.method;
import java.util.stream.Stream;

public class ExternalMethodSOurce {
    static Stream<String> checkExternalMethodSourceArgs() {
         return Stream.of("a1",
                          "b2");
    }
}
```
Azure で postfix のインストールを試す

「Azure で最初のクラウドサーバを無料枠で作成する」
https://qiita.com/nanbuwks/items/120858191caf3b0a3f1c

で作成した、Ubuntu22.04サーバに、postfix をインストールしてローカルでの動作を確認してみます。


# 環境

サーバ Microsoft Azure 上の Ubuntu 22.04

今回は、サーバは Azure 上の Virtual Server を使っていますが、特に Azure の機能は使っていません。

# postfix

メール関連のソフトウェアの種類として、MUA/MTA/MRAがあります。

一般にメールクライアントソフトと言われているものは MUA、
メールサーバと言われているもののうち、SMTPサーバとして馴染みがあるのが MTA、
メールサーバと言われているもののうち、POP3サーバとして馴染みがあるのが MRA となります。

今回は、まず MTA としての postfix をインストールします。


# インストール

```
$ sudo apt install postfix
```
以下の設定では、今回は「Internet Site」を選びます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/bfc53032-bb56-352f-4ac7-ef40f32537ca.png)

以下はそのまま
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/ca3f9c8b-2271-56cd-bddf-a4fe7cd56e20.png)


インストールが終わりましたが、Azureの送信ポートが開いていないので、外部にメールを送ることはできません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/44444fac-961d-4e58-16c2-0cd2c0697d3b.png)

# メールを送ってみる

外部にメールを送ることはできませんが、サーバ内部のユーザ同士でメールを送ってみます。
今 ssh で azureuser としてログオンしています。
「Azure/Ubuntu/Apache2 で PHP と VirtulaHost を設定する」
https://qiita.com/nanbuwks/items/d3a1a148e597f5c5df1c
で追加した example ユーザにメールを送ってみます。


```
$ echo "Hello postfix" | sendmail example
```

メールを送りましたが、メールソフトとして Thunderbird や gmail 
などを使って読むことはできません。サーバー内部でメールを読むために、メールユーティリティをインストールします。

```
$ sudo apt install mailutils
```

example ユーザになってメールを読んでみましょう
```
azureuser@test-azure-gen:~$ su - example
Password: 
example@test-azure-gen:~$ mail
"/var/mail/example": 1 message 1 new
>N   1 Ubuntu             Sat Apr  8 06:06  11/635   
?
```
メールが届いているのがわかります。メールリストとして1通しかありませんが、それを指定して読んでみます。

```
? 1
Return-Path: <azureuser@test-azure-gen.d5vkxbztwwse1dua0e2ybepgyg.phxx.internal.cloudapp.net>
X-Original-To: example
Delivered-To: example@test-azure-gen.d5vkxbztwwse1dua0e2ybepgyg.phxx.internal.cloudapp.net
Received: by test-azure-gen.d5vkxbztwwse1dua0e2ybepgyg.phxx.internal.cloudapp.net (Postfix, from userid 1000)
	id 0C1B03F9A1; Sat,  8 Apr 2023 06:06:41 +0000 (UTC)
Message-Id: <20230408060641.0C1B03F9A1@test-azure-gen.d5vkxbztwwse1dua0e2ybepgyg.phxx.internal.cloudapp.net>
Date: Sat,  8 Apr 2023 06:06:41 +0000 (UTC)
From: Ubuntu <azureuser@test-azure-gen.d5vkxbztwwse1dua0e2ybepgyg.phxx.internal.cloudapp.net>

Hello postfix

? 
```
メールを読むことができました。
q でMUAを抜けます。

```
? q
Saved 1 message in /home/example/mbox
Held 0 messages in /var/mail/example
```
python で ProcessPoolExecutor を使ったマルチプロセスのサンプル

# はじめに
タイトルの通り。ProcessをThreadに変更するとマルチスレッドにできるので、使い勝手が良い。

# 環境
- Windows10
- Docker(WSL)
- Python 3.10.7

# コード
```python
import logging
from concurrent.futures import ProcessPoolExecutor
from concurrent.futures import as_completed

# デバッグログ出力設定（どのプロセスでの実行かがわかるので便利）
logging.basicConfig(level=logging.DEBUG, format="%(processName)s: %(message)s")

# 1からmaxまで、かつmultipleの倍率のみ、値を出力する
def counter(index=-1, multiple=1, max=1):
    for i in range(1, max + 1):
        if i % multiple == 0:
            logging.debug(f"index={index}, number={i}")

    return index


# entry point
if __name__ == "__main__":

    # 値のループ用
    params = [
        {"multiple": 1, "max": 25},
        {"multiple": 2, "max": 8},
        {"multiple": 3, "max": 9},
        {"multiple": 4, "max": 20},
        {"multiple": 5, "max": 20},
    ]
    # プロセスの戻り値格納変数
    results = []

    # start the process pool
    with ProcessPoolExecutor(3) as executor:
        # マルチプロセスでcounterを実行
        futures = [executor.submit(counter, i, **param) for i, param in enumerate(params)]
        # 各プロセスの完了処理
        for future in as_completed(futures):
            # 終わった処理のindexを追加
            results.append(future.result())        
    
    # 処理が終わった順番を表示
    print(results)  
```

# 終わりに
リソースが貧弱な環境ではマルチスレッドの方が良いんじゃないかという雑な方針しかない人ですが、いつか役に立つことを願って、、
nuxt3 provideを使ったログ実装のTry

nuxt3でログ出力したいとき、provideを活用するといいのでは？というのを思ってtry中です.

## 期待すること

将来的にOSSのログモジュールを使用することになっても変更が最小で済むこと。
またはログをバックエンドに送る場合にも変更が最小で済むこと。
（pageやcomponentといったロガーの使用者側に影響がないこと）

## 実装

provide

```typescript 
// /plugins/logger.ts
type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal'

/** 公開される型 */
export interface ILogger{
  debug(...obj: any[]): void
  info(...obj: any[]): void
  warn(...obj: any[]): void
  error(...obj: any[]): void
  fatal(...obj: any[]): void
  /** logLevelの変更 */
  setLevel(level: LogLevel):void
  /** 現在のlogLevelの取得 */
  getLevel(): LogLevel
}

/** インターフェースの実装は公開されない */
abstract class BasicLogger implements ILogger{
  private level:LogLevel = 'info'
  private whiteList:Set<LogLevel> = new Set<LogLevel>(['info', 'warn', 'error', 'fatal'])
  
  constructor(level:LogLevel = 'info') {
    this.setLevel(level)
  }

  getLevel(): LogLevel {
    return this.level
  }

  setLevel(level: LogLevel): void {
    this.level = level
    switch (this.level){
      case 'debug':
        this.whiteList = new Set<LogLevel>(['debug', 'info', 'warn', 'error', 'fatal'])
        return
      case 'info':
        this.whiteList = new Set<LogLevel>(['info', 'warn', 'error', 'fatal'])
        return
      case 'warn':
        this.whiteList = new Set<LogLevel>(['warn', 'error', 'fatal'])
        return
      case 'error':
        this.whiteList = new Set<LogLevel>(['error', 'fatal'])
        return
      case 'fatal':
        this.whiteList = new Set<LogLevel>(['fatal'])
        return
    }
  }

  debug(...obj: any[]): void {
    if (this.whiteList.has('debug')){
      this.log('debug', obj)
    }
  }
  info(...obj: any[]): void {
    if (this.whiteList.has('info')){
      this.log('info', obj)
    }
  }
  warn(...obj: any[]): void {
    if (this.whiteList.has('warn')){
      this.log('warn', obj)
    }
  }
  error(...obj: any[]): void {
    if (this.whiteList.has('error')){
      this.log('error', obj)
    }
  }
  fatal(...obj: any[]): void {
    if (this.whiteList.has('fatal')){
      this.log('fatal', obj)
    }
  }

  abstract log(logLevel: LogLevel, ...obj:any[]): void
}

/** インターフェースの実装は公開されない */
class ConsoleLogger extends BasicLogger{
  constructor(logLevel: LogLevel) {
    super(logLevel)
  }

  log(logLevel: LogLevel, ...obj: any[]): void {
    // 
    // productionではログ出力しないなど
    // 

    switch(logLevel){
      case "fatal":
        console.error(logLevel, obj)
        return
      case "error":
        console.error(logLevel, obj)
        return
      case "warn":
        console.warn(logLevel, obj)
        return
      default:
        console.log(logLevel, obj)
        return
    }
  }
}

export default defineNuxtPlugin(nuxtApp => {
  const logger: ILogger = new ConsoleLogger('debug')
  return {
    provide: {
      logger: logger
    }
  }
})

```

page側

```vuejs 
<setup lang="ts" setup>
const {$logger} = useNuxtApp()

$logger.debug("message")

</setup>
```
JUnit5 annotation @ValueSource

## @ValueSource

It accepts a single array of literal values.

The literal values supported by @ValueSource are : short, byte, int, long, float, double, char, boolean, String and Class.

```Java
@ParameterizedTest
@ValueSource(strings = { "a1" , "b2" })
void checkAlphanumeric(String word) {
    assertTrue(StringUtils.isAlphanumeric(word), "Supplied word is not alpha-numeric");
}
```
AI-900対策勉強

# AI-900受験について

先日、無事にAI-900に合格しました！そこで試験までに行った対策について記載していきたいと思います。
受験の動機は、人工知能について研究しているのでとってみよう！くらいの軽い気持ちで受験しました。
前提知識はある程度ありますが、Azureまだ勉強中なのでしっかりと対策はして臨みました。

https://learn.microsoft.com/ja-jp/certifications/exams/ai-900/

### 行った対策

私が試験までに行った対策を記載します。
・「Microsoft Azure Virtual Training Day : 基礎」への参加
・「Microsoft Learn」での学習
・Udemyの模擬試験
期間は実質3週間程度で取得できました。
対策本はあまり販売されていないようでした。ですが、上記3つの試験対策で合格に充分な力がつきました。

## 受験までの道のり
以下、詳しく受験までのスケジュールを記載していきます。

### 「Microsoft Azure Virtual Training Day : 基礎」への参加
最初にMicrosoftが提供する試験対策講座である「Microsoft Azure Virtual Training Day : 基礎」を半日で受講しました。
試験突破のための全体像を知ることができるので、はじめにこの講座を受けるのはとてもおすすめです。

https://www.microsoft.com/ja-jp/events/top/training-days/azure?activetab=a1:primaryr4

★また、この講座を受講することで試験を無料で受けることができます。まだ学生なので受験料がちょっと高くて痛手だと思っていたのですが、この講座のおかげで無料で受けることができました。

### 「Microsoft Learn」での学習
講座を受講したら、「Microsoft Learn」で週間程度かけて学習を行いました。
試験対策講座で学んだ知識の増強というイメージで、詳しいシステムの詳細や名称などを覚えました。
少し分かりづらい表現が多く、理解して落とし込むまで時間がかかってしまいました。

https://learn.microsoft.com/ja-jp/training/paths/get-started-with-artificial-intelligence-on-azure/

### Udemyの模擬試験
最後に直前対策としてUdemyで問題集を購入し、2週間程度かけて学習を行いました。
（私が購入した問題集は今販売されていなかったので、他の問題集のリンクをつけておきます。）
体感では9割以上とれていれば合格するための力は充分備わっているかと思います。

https://www.udemy.com/course/microsoft-ai-900-l/

★またUdemyは定期的にセールを行っているので、セールしているタイミングで買った方が断然お得です。私も安く買いました！

## 結果
満点が1000点、合格点が700点で私は850点/1000点で一発合格することができました。
AZ-900と比較したら、AI-900のほうがやや易しいように感じました。
人工知能について少しでも学んでいる方は、力試しに一度受けてみるのはおすすめです。

![microsoft-certified-azure-ai-fundamentals.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949441/f48e31b3-d52c-4783-f574-0aa968882f6c.png)

学生のうちは無料でAzure使えるので暇なときにいじってみようかと思います。
最後までご覧いただきありがとうございました。

### AZ-900の対策勉強はこちら

https://qiita.com/rika45/items/3b1cbda07ea24369f288
XORで大文字小文字を入れ替える

既出な気もしますが、AND演算とOR演算を使ったASCIIコードの大文字小文字変換の勉強中にXORで大文字と小文字を行ったり来たりできることを見つけたのでそのメモです。

`0b0010_0000`とXORすることで大文字なら小文字に、小文字なら大文字に変換できます。

```python:サンプルコード.py
// 2進数表記
print("0b" + format(0b0100_0001 ^ 0b0010_0000, "08b"))
// -> 0b01100001

print("0b" + format(0b0110_0001 ^ 0b0010_0000, "08b"))
// -> 0b01000001


// 16進数表記
print(hex(0x41 ^ 0x20))
// -> 0x61

print(hex(0x61 ^ 0x20))
// -> 0x41
```
Parameterized Test   - Comparison of writing style between JUnit4 and JUnit5 -

```Java
public class ValueSourceTest {

 @ParameterizedTest

 @ValueSource(int = { 2, 4 })
   void checkEvenNumber(int number) {
       asserEquals(0, number % 2, "Supplied number is not an even number");

  }
}
```

In the above example, the annotation @ValueSource provides multiple inputs to the checkEvenNumber() method. Let's say we are writing the same using Junit4, we had to write 2 test cases to cover the inputs 2 and 4 even though their result(assertion) is exactly the same.


When we execute the ValueSourceTest, what we see:

```Java
ValueSourceTest

  checkEvenNumber
    [1]2
    [2]4
```

It means that the checkEvenNumber() method is executed with 2 input values.