OmniAICreator/Qiita-1.07M huggingface dataset:
【AWS】CloudWatchLogsサブスクリプションフィルタ＋Lambdaによるログデータの確認

# 目次
<!-- タイトルとアンカー名を編集 -->

1. [はじめに](#はじめに)
1. [CloudWatchLogsサブスクリプションフィルタとは](#Chapter1)
1. [Lambdaでパラメータを受け取る](#Lambdaでパラメータを受け取る)
1. [改善してほしいところ](#改善してほしい点)


<!-- 各チャプター -->
<a id="#Chapter1"></a>
# はじめに
WindowsServer内でバッチファイルを実行し、その処理結果(ログ)に基づいて成功・失敗通知を行いたかったのですが、Lambda呼び出しのとこでいきなり躓いたので備忘録としてまとめました。

(EventBridge＋Lambdaの構成と同じようにLambdaハンドラーのEventから取り出せばいいだろうと思っていたらちょっと違った...)

<a id="#Chapter2"></a>
# CloudWatchLogsサブスクリプションフィルタとは
CloudWatchLogsに指定した文字列が記録されたら特定のアクションを実行させるようなトリガーを設定できる機能です。
サブスクリプションフィルタは***ロググループ***ごとに作成出来ますが、***ログストリームごと***には設定できないようなので注意してください。

サブスクリプションフィルタでトリガー可能なアクションは以下の4つです。
* **OpenSerch Serviceサブスクリプションフィルタ**
* **Kinesis サブスクリプションフィルタ**
* **Kinesis Firehoseサブスクリプションフィルタ**
* **Lambdaサブスクリプションフィルタ**

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# Lambdaでパラメータを受け取る
早速ですが、Lambda関数を作成していきます。
サブスクリプションフィルタにLambdaを指定することで、
CloudWatchLogに書き込まれたログがLambdaにパラメータとして渡されます。

以下の文字列に対してサブスクリプションフィルタを設定したとします。
* 検知する文字列：**end_time**


ログファイルに「**end_time**」が書き込まれるとサブスクリプションフィルタによってLambdaが呼び出されます。
Lambdaハンドラーの引数:eventに上記ログが渡されるのですが、Lambdaでeventの中身を出力してみると以下のようになってます。
``` Create-CloudwatchAlarm-List.sh
{'awslogs': {'data': 'H4sIAAAAAAAA/zWQPU7DMBhAr1J9c6La/uL4R2KIoHRiaiUGVFVp4gZLSRzFLlWpunRADFyACXEBNha4DgWOgQpif+8NbwuN8T6vzHTTGdBwlk2z+cVoMsnGI4jArVvTgwbKkWHCKAqZQgS1q8a9W3WgYZg1+a1rT2u3Ki/zUFzHtat8MD7Ea9uWbu2Htati19abP3ESepM3oMHGpJDLHPkSmVwopbCECPxq4YvedsG69tzWwfQe9BUcXp6+nx++Xvcfb3efj/vD/TvMfnOjG9OGI7IFW4IGFIpiigQJESlLKeVKCEppolgqqRRcMcmQUWSEk1RIqmSCXCYQQbCN8SFvOtBUEEIJV5Iil9H/I9Bg2nJ+5AYnA0I0StjNdj81GMMwRAEAAA=='}}
```

このメッセージをどんなログが書き込まれたのか判断できません。
実はこのデータはデコードすることで正しいデータを取り出せます

以下のコードで中身を取り出せます
データの中身は「end_time = 00:38」というログメッセージです

``` decode.py
import json
import base64
import gzip

#サブスクリプションフィルタで検知した文字列を取得
def decode_function(event):
    decoded_message = base64.b64decode(event['awslogs']['data'])
    decompressed_data = gzip.decompress(decoded_message)
    json_data = json.loads(decompressed_data)
    log_message = json_data['logEvents'][0]['message']
    
    return log_message
    
def lambda_handler(event, context):
    print(event)
    log_message = decode_function(event)
    print("log_messageを取得しました:{}".format(log_message))

```
実行してみるとこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2615865/9e2d2669-942e-a4d9-106f-eecbbeb2b077.png)


これでサブスクリプションフィルタから受け取ったデータの中身を確認できるようになりました。
あとはこのメッセージを基に、SNS通知したり別のLambdaを呼び出したり,etc...作りこめばOKです。

<a id="#reference"></a>
# 改善してほしい点
EventBridgeとの大きな違いとしてイベント検知後にSNSが指定できない点があるかと思います。実際私もサブスクリプションフィルタで検知→SNS通知という処理をやりたかったのですが、上記4つのアクションしか指定できないため、仕方なくLambdaを間に挟みました。
多くの人が不便に感じてるポイントな気がするのでそのうちアップデートが入ってくれる日を心待ちしています...w

# さいごに
EventBridgeトリガーの感覚でデータの中身を取り出そうとすると躓くポイントになるかも。。。と思い書きました。

社内ブログのほうではCloudWatchAgentのインストールからCloudWatchLogへのログ出力設定、サブスクリプションフィルタ作成、LambdaによるSNS通知までを一気に紹介しようと思っていますので気になる方は読んでいただけると嬉しいです。

今回は以上になります。
最後まで読んでいただきありがとうございました！
Chat Completions APIで京都旅行プランを考える

# はじめに
昨日の記事「[OpenAI APIの使い方講座【公式Quickstart】](https://qiita.com/Isaka-code/items/b50983796636503b44c5)」に引き続き、OpenAI APIを扱います。
本日のお題は、「**Chat Completions APIで京都旅行プランを考える**」です。

**Chat Completions API**

https://platform.openai.com/docs/guides/text-generation/chat-completions-api

# 出来上がったソースコード

```text_generation.py
from openai import OpenAI

def generate_text(model_name, system_message, user_message):
    client = OpenAI()

    completion = client.chat.completions.create(
        model=model_name,
        messages=[
            {"role": "system", "content": system_message},
            {"role": "user", "content": user_message}
        ]
    )

    return completion.choices[0].message.content

if __name__ == "__main__":
    model_name = "gpt-4"
    system_message = "あなたは旅行計画の専門家で、特定の都市に関する詳細な旅行プランを提案するのが得意です。"
    user_message = "3日間の京都旅行プランを作成してください。文化的な場所と美味しい食事を楽しみたいです。"

    generated_text = generate_text(model_name, system_message, user_message)

    print(generated_text)
```

昨日の記事で使用した公式Quickstartのサンプルコードをベースにしていますが、下記の変更を行いました。
- 関数化し、入力を汎用的に変更できるようにしました。
- 課題を達成するための`system`, `user`を入力として与えています。
- `completion.choices[0].message`を`completion.choices[0].message.content`に変更し、中身の文字列を取り出しています。
- モデルを`GPT4`にしました。


# 実行結果

```
もちろんです、素晴らしい旅行プランをご提案させて頂きます。

**1日目：古都の文化を探索**
- 朝：新幹線またはフライトで京都に到着後、ますまずは京都駅周辺で一息ついてください。京都タワーに登ると、京都市の全景を眺めることができます。
- 昼：昼食には地元で愛される名物「京都らーめん」を食べに行きましょう。ええぜん 京都駅前店はおすすめです。
- 昼後：昼食後は、京都市バスで金閣寺へ。金色に輝く美しい建物と庭園を探索しましょう。
- 夜：夕食は、伝統的な日本料理「季節の会席料理」が楽しめる「京釜料理 百八」で。こちらは予約をオススメします。

**2日目：歴史ある寺院へと足を運ぶ**
- 朝：東山区にある清水寺へ。ここからの眺望は絶景です。その後、周辺の町並みを散策し、伝統的なお茶屋で一服しましょう。
- 昼：昼食は、清水寺近くの「千利休清水道店」で「おばんざい」を楽しみましょう。
- 昼後：バスまたはタクシーで伏見稲荷大社へ。千本鳥居はフォトジェニックなスポットです。
- 夜：夕食は、鴨川沿いにある「川床料理 みよし」で。ここは予約が必要です。

**3日目：和食文化とショッピング**
- 朝：早朝に「錦市場」へ。新鮮な食材や京漬物を見ることができます。その後、「祇園」に移動し、町並みを散策しましょう。
- 昼：昼食には、祇園近くの「通富士屋」で「すき焼き」または「しゃぶしゃぶ」を楽しむことをおすすめします。
- 昼後：バスで西陣区へ移動し、「西陣織会館」で京都の伝統工芸品を見学しましょう。その後、周辺のお店でお土産を探します。
- 夜：最後の夜は、京都駅近くの「京都迎賓館」で最高級の和食を楽しみましょう。美味しい料理とともに、京都での素晴らしい時間を振り返りましょう。

これが3日間の京都旅行の提案です。文化的な場所はもちろん、お食事も現地の味を楽しむことができます。どうぞお楽しみください。
```

# おわりに

それっぽいプランが出力されましたが、実はハルシネーションで実在しないお店ということもあるのでしょうか。
ちなみに、GPT4のハルシネーション確率は3.0%とのことです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627015/260290e7-a619-1816-0891-f16105b0d09a.png)


https://github.com/vectara/hallucination-leaderboard

情報がどこまで正しいかはわかりませんが、参考になる京都旅行プランだと思いました。文化的な場所と美味しいごはんを楽しもうと思います😋


### ソースコード

本記事で使用したソースコードは、下記のGitHubレポジトリに格納しています。

https://github.com/Isaka-code/openai-api-hands-on
1ボタンでディスプレイ設定をトグルしたい

# はじめに
リモートワークプレイヤーの[にわのわ](https://twitter.com/niwa_nowa)です。
3枚あるうちの1枚をディスプレイをリモートワーク用PCと普段使いしているPCとで共有しています。
これをいちいちNvidiaコントロールパネルを開いて無効化したり、ケーブルを抜いたりと
いちいち切り替えるのが面倒なので、1ボタンでできるようにしていきます。

# MultiMonitorToolのダウンロード
コマンドライン上でディスプレイ設定を変更するために、
こちらのページの下の方からMultiMonitorToolをダウンロードします。

https://www.nirsoft.net/utils/multi_monitor_tool.html

# 切り替え用コンフィグの作成
MultiMonitorToolを起動し、切り替えたい設定を作り、保存します。
自分の場合は全てのディスプレイがアクティブの設定と、一番下のディスプレイだけノンアクティブにする設定を作成しました。

File -> Save Monitors Configuration 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590707/fdaaff7a-72f8-94d5-aba3-160b9de04a3d.png)
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590707/d0726fa8-3ca5-d0b2-43ad-103bc7e1be02.png)

無効化したいディスプレイを選択して赤枠をクリック
その後File -> Save Monitors Configuration
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590707/a5f7bc44-629f-ed59-ded8-17aa23a65ac5.png)
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590707/69c8c1d6-e024-712e-8b26-4b63e1f2627d.png)

ちなみに、```MultiMonitorTool.exe /switch 3```のようにswitchオプションでモニターのオンオフを切り替えることができますが、
モニター配置やデスクトップのアイコンがぐちゃぐちゃになってしまうので、設定ファイルを使うことをおすすめします。

# バッチファイルの作成
作成した設定ファイルを使って、ディスプレイの設定を切り替えるバッチファイルを作成します。
MultiMonitorToolの場所は適宜変更してください。

また、counter.txtは以下のような内容で作成しています。
```counter.txt
1
```

```bat
@echo off
setlocal enabledelayedexpansion

set "countFile="E:\multimonitortool-x64\counter.txt""

if not exist %countFile% (
    echo 0 > %countFile%
)

set /p count=<%countFile%
set /a count+=1

echo %count% > %countFile%

set /a remainder=count %% 2

if %remainder% equ 1 (
    E:\multimonitortool-x64\MultiMonitorTool.exe /LoadConfig "E:\multimonitortool-x64\on.cfg"
) else (
    E:\multimonitortool-x64\MultiMonitorTool.exe /LoadConfig "E:\multimonitortool-x64\off.cfg"
)

endlocal
```

あとは作成したバッチをデスクトップやスタートメニューなどに配置して完成です。

# おわりに
以上でMultiMonitorToolの紹介を終わります。
WindowsのシステムAPIとかNvidiaコントロールパネルでコマンドが提供されてるのかなと思ってたら全然そんなことありませんでした。
なんで提供されてないんですかね。
【組み込み開発】関数ポインタと構造体または配列を組み合わせて使いたいときに参考になる記事

### はじめに
今回は、組み込み開発でよく使用されている関数ポインタについて、定義方法から使い方まで説明してみたいと思います。

### この記事の対象読者
* 学校などでC言語の基礎知識を学んだことがある方
* ポインタ変数を理解している方

### この記事を理解する上での前提知識
* 変数や関数はメモリ上に存在している
* メモリ上のアドレスを取得したい場合は、変数名や関数名に&を付ける
* 構造体のメンバー変数は、構造体の変数名.メンバー変数名でアクセスできる

### 関数ポインタとは？
関数のアドレスを格納する変数です。

### 関数ポインタの定義方法
関数ポインタを定義するときには以下の3つを考える必要があります。
① 関数のアドレスを格納する変数名
② ①が参照する先の関数の戻り値
③ ①が参照する先の関数の引数の個数とデータ型

例えば、①がg_functionPointer、②がuint8_t、③の個数が2、データ型が2つともuint8_tの場合、以下のように定義します。

```C:
uint8_t (* g_functionPointer)( uint8_t, uint8_t )
```

:::note warn
注意点として、②と③両方とも一致していないと①から呼び出すことができません。
上記の例を用いると、呼び出し先の関数について、②はあっているが、③があっていない（例えば、引数の個数が0でvoid型など）もしくは、③はあっているが②はあっていない（例えば、戻り値がdouble型など）です。
:::

関数ポインタは配列と構造体と組み合わせて使われることが多いです。
次から例を見ていきましょう。

### 例①：関数ポインタと配列を組み合わせる
```C:Ex1.c
#include <stdint.h>
#include <stdio.h>
#include "Ex1.h"

// 関数ポインタの定義
uint8_t (* g_functionPointer[2] ) ( uint8_t, uint8_t ) = { &funcA, &funcB };

int main()
{
    uint8_t value1 = 0;
    uint8_t value2 = 0;

    // funcAの呼び出し
    value1 = g_functionPointer[0](3,5);

    // funcBの呼び出し
    value2 = g_functionPointer[1](3,5);

    // value1の値を表示
    printf("value1の値：%d\n", value1);

    // value2の値を表示
    printf("value2の値：%d\n", value2);
    
    return 0;
}

uint8_t funcA(uint8_t a, uint8_t b)
{
    return a + b;
}

uint8_t funcB(uint8_t a, uint8_t b)
{
    return a * b;
}
```

```C:Ex1.h
#include <stdint.h>

uint8_t funcA(uint8_t a, uint8_t b);

uint8_t funcB(uint8_t a, uint8_t b);

```

```C:実行結果
value1の値：8
value2の値：15
```
### 例②：関数ポインタと構造体を組み合わせる
```C:Ex2.c
#include <stdint.h>
#include <stdio.h>
#include "Ex2.h"

stExample g_functionPointer[2] = {
	{funcA1, funcB1},
	{funcA2, funcB2}
};

// グローバル変数の定義
uint8_t g_number1 = 0;
uint8_t g_number2 = 0;

int main(void)
{
	// ローカル変数の定義
	uint8_t value1 = 0;
	uint8_t value2 = 0;

	// 値をセットする関数の呼び出し
	(*(g_functionPointer[0].setValue))(3);

	// 値を表示する
	value1 = (uint8_t)(*(g_functionPointer[0].getValue))();
	printf("g_number1の値：%d\n",value1);

	// 値をセットする関数の呼び出し
	(*(g_functionPointer[1].setValue))(5);

	// 値を表示する
	value2 = (uint8_t)(*(g_functionPointer[1].getValue))();
	printf("g_number2の値：%d\n.", value2);

	return 0;
}

void funcA1(uint8_t number)
{
	g_number1 = number;
}

uint8_t funcB1(void)
{
	return g_number1;
}

void funcA2(uint8_t number)
{
	g_number2 = number;
}

uint8_t funcB2(void)
{
	return g_number2;
}
```

```C:Ex2.h
typedef struct{

    void (* setValue )( uint8_t );
    uint8_t (* getValue )( void );

}stExample;

void funcA1(uint8_t number);

uint8_t funcB1(void);

void funcA2(uint8_t number);

uint8_t funcB2(void);
```
```C:実行結果
g_number1の値：3
g_number2の値：5
```

### 関数ポインタの定義方法と呼び出し方のまとめ
* 定義時に関数名の前に&をつけると、呼び出し時は変数名だけで呼び出せる（例①のパターン）
* 定義時に関数名の前に&をつけないときは、呼び出し時は変数名の前に*を付けて呼び出す（例②のパターン）

### おわりに
関数も変数と同じようにメモリ上に存在していることが分かれば、関数ポインタを理解することも難しくないかと思います。
関数ポインタの使いどころとして、組込み開発では、コールバック関数で使われています。
これについてはまた別に記事にしようと思います。
最後までご覧いただきありがとうございました。
【os】業務効率化で使うosモジュールのあれこれ

## はじめに
表題の通り，（個人的に）よく使用するosモジュールのコマンドを紹介しようと思います．備忘録．
超超初学者向けです．

## 動作環境情報
- Python 3.12.0<br><br>
osモジュールを使用する際は下記のコマンドでimportしてください．
```
import os
```

## 紹介・使用例
### ファイル / フォルダの存在確認
- os.path.isfile(path) -> True / False（戻り値）
引数で指定したファイルパスが存在するかどうかを判別．<br><br>
- os.path.isdir(path) -> True / False（戻り値）
引数で指定したディレクトリ（フォルダ）パスが存在するかどうかを判別．<br><br>
- os.path.exists(path) -> True / False（戻り値）
引数で指定したパスが存在するかどうかを判別．<br><br>

1個目，2個目と3個目何が違うねん，って思ったそこのアナタ！
os.path.isfile(path)はファイルのパスのみ，os.path.isdir(path)はディレクトリ（フォルダ）のパスのみ，os.path.exists(path)はパスさえ存在していればTrueを返します．
状況に応じて使い分けるといいが，とりあえず3個目使っておけば問題無さそう．
```sample.py
import os

dir_path = r"C:\Work\Qiita"
file_path = dir_name + r"\hojihoji.py"
if os.path.isfile(file_path):
    print("ファイルあるよ！")
else:
    print("ファイルないよお")

if os.path.isdir(dir_path):
    print("フォルダあるよ！")
else:
    print("フォルダないよおq_q")

if os.path.exists(file_path):
    print("パスあるお^q^")
```

### ディレクトリ（フォルダ）作成
- os.mkdir(path)
引数で指定したディレクトリ（ファイル）を作成．
既にフォルダが存在している場合エラーが出ます．上記のファイル / フォルダの存在確認するコードで存在確認してから使用しよう．
```sample.py
import os

dir_path = r"C:\Work\Qiita"
# フォルダが無ければ新規作成
if not os.path.exists(dir_path):
    os.mkdir(dir_path)
```

### ファイルを削除
- os.remove(path)
引数で指定したファイルを削除．
ファイルが存在しない場合エラーが出ます．こちらも上記のファイル / フォルダの存在確認するコードで存在確認してから使用しよう．
```sample.py
import os

file_path = r"C:\Work\Qiita\hojihoji.py"
# ファイルがあれば削除
if os.path.exists(file_path):
    os.remove(file_path)
```

### ファイルのタイムスタンプを取得
- os.path.getatime(path)
引数で指定したファイルの最終アクセス日時を取得．<br><br>
- os.path.getmtime(path)
引数で指定したファイルの最終内容更新日時を取得．<br><br>
- os.path.getctime(path)
引数で指定したファイルの作成日時を取得．<br><br>

戻り値は全て<INS>[UNIX時間](https://qiita.com/ayumi_imai/items/06810a5ab9f34dd866ca)</INS>で返されます．
```sample.py
import os

file_path = r"C:\Work\Qiita\hojihoji.py"
print(os.path.getatime)
print(os.path.getmtime)
print(os.path.getctime)
#---------------------------------------#
1700463253.0382283 (getatime)
1700463221.9840796 (getmtime)
1700463221.8750641 (getctime)
```
「共有フォルダ内の特定のファイルが更新されていたら通知を出す」ような処理が可能です．
### ファイルやディレクトリの一覧を取得
- os.walk(path)
引数で指定したディレクトリのファイルを走査．
以下の構造でWorkディレクトリを走査します．

Work
├ Qiita1
│├test1.txt
│└test2.txt
└ Qiita2
　└test3.txt

```sample.py
import os

dir_path = r"C:\Work"
for folder, subfolder, file in os.walk(dir_path):
    print("*****")
    print(folder)
    print(subfolder)
    print(file)
#---------------------------------------#
*****
C:\work
['Qiita1', 'Qiita2']
[]
*****
C:\work\Qiita1
[]
['test1.txt','test2.txt']
*****
C:\work\Qiita2
[]
['test3.txt']
```
「特定のフォルダ下の.〇〇ファイルに対して××という処理を行う」というような場合に役立ちます．

## おわりに
今回はほんの一部しか紹介できていません．osモジュールは他にもできることが多いのでぜひ調べてみてください！
osモジュール詳細（https://docs.python.org/ja/3/library/os.html）
VSCodeでPrettierきかんやーんって方へ

## これは何？
タイトル通りです。
onSaveも設定した、Dafault formatってどう設定するの？って方へ向けてます。

## やり方
ほぼ参考文献2つ目のサイトと同じですが、私がわからなかったのはprettierの選び方です。
**スクロールする** or **pを該当箇所で打つ**と選択できます！画像だと③のところです。


![スクリーンショット 2023-11-20 21.46.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316097/80e1e790-7713-f42e-00b9-e0d873d99713.png)



## 参考文献
- https://qiita.com/KKKKK/items/3b9dba55653cb7993bf5
- https://ralacode.com/blog/post/vscode-prettier/
【Django】DBにある「変数」をプログラムの指定された「変数」に代入して一つの文字列として連結させる方法

# 概要
Djangoアプリケーションにて、DBにある変数をプログラムの指定された変数に代入して一つの文章に連結させる、ということが必要になったので実装しました。

# 実現すること

DBには以下のように登録されている前提です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710373/94b9cba9-ebad-84a4-505c-76d1c6408faf.png)

それぞれの`sample_syntax`において、`part_1`や`part_2`にはプログラム側から文字列が入ります。
それらを連結させて一つの文章にしたい、ということです。

モデル定義は以下の通りです。

```models.py
class Syntax(models.Model):
    sample_syntax = models.TextField(null=True, blank=True)

    class Meta:
        db_table = 'syntax'
```

## サンプルコード


```py
from sample.models import Syntax

# 例えばの変数
sample_1 = "1番目!"
sample_2 = "2番目!"
sample_3 = "3番目!"
sample_4 = "4番目!"

sample_syntax1 = Syntax.objects.get(id=1).sample_syntax
sample_syntax2 = Syntax.objects.get(id=2).sample_syntax

syntax_variables = {
    'part_1': sample_1,
    'part_2': sample_2,
    'part_3': sample_3,
    'part_4': sample_4
}
print(syntax_variables)
# {'part_1': '1番目!', 'part_2': '2番目!', 'part_3': '3番目!', 'part_4': '4番目!'}

# ただ繋げるだけで良い場合
def syntax_just_join(syntax, syntax_variables):
    syntax = {key: syntax_variables[key] for key in syntax.split(' + ') if key in syntax_variables}
    syntax_comment = ''.join(str(syntax[key]) for key in syntax)
    print(syntax_comment)
    # 1番目!2番目!3番目!4番目!
    
syntax_just_join(sample_syntax1, syntax_variables)


# 文字列を含めて繋げる場合
def syntax_join_with_strings(syntax, syntax_variables):
    syntax_parts = syntax.split(' + ')
    syntax_comment = ''.join(str(syntax_variables.get(key, key)) for key in syntax_parts)
    print(syntax_comment)
    # 1番目!固定の文言を入れます！2番目!3番目!4番目!

syntax_join_with_strings(sample_syntax2, syntax_variables)
```

`print`の出力結果は上記の通りです。

もし登録したレコードの中に固定の文字列がない場合は、指定された変数を参照していくだけなので1番目の方でも問題ありません。

しかし、もし固定文言をDB側で持たせておく場合は、2番目の場合のようにする必要があります。具体的には`.get()`メソッドを使って`syntax_variables`辞書から変数を取得し、もし辞書内にキーが存在しない場合はそのままキーを返すようにしています。これは`get`メソッドの「デフォルト値」と呼ばれるものです。

ちなみに、以下のコードでも同じように実現できました。
ただし、上述の方がコードの可読性が高いかなと思います。

```py
def syntax_join_with_strings(syntax, syntax_variables):
    syntax_comment = ''
    for key in syntax.split(' + '):
        if key in syntax_variables:
            syntax_comment += str(syntax_variables[key])
        else:
            syntax_comment += key
    print(syntax_comment)
    # 1番目!固定の文言を入れます！2番目!3番目!4番目!

syntax_join_with_strings(sample_syntax2, syntax_variables)
```
テスト107

```vb
Sub OlMail_Move()

'ExcelからOutlookを操作し、受信トレイから件名でメールを振り分け
'件名が「test」の場合はテスト1フォルダへ、件名が「テスト」の場合はテスト2フォルダへ移動させる
'(テスト1、テスト2フォルダは受信トレイと同じ階層に事前につくっておく)...〆(･ω･ )ﾒﾓﾒﾓ

Dim ol As outlook.Application
Dim INmail As Folder
Dim Fol1 As Folder
Dim Fol2 As Folder
Dim i As Variant
Dim cnt As Variant

Set ol = outlook.Application

With ol.GetNamespace("MAPI")
    '受信ボックスの取得
    Set INmail = .GetDefaultFolder(olFolderInbox)
    
    'Outlook内のテスト1フォルダの取得
    Set Fol1 = .Folders.Item(1).Folders.Item("テスト1")
    
    'Outlook内のテスト2フォルダの取得
    Set Fol2 = .Folders.Item(1).Folders.Item("テスト2")

End With


cnt = INmail.Items.Count
For i = cnt To 1 Step -1

    If InStr(INmail.Items(i).Subject, "test") > 0 Then
        '件名が「test」の場合はテスト1フォルダへ移動する
        INmail.Items(i).Move Fol1
        
    ElseIf InStr(INmail.Items(i).Subject, "テスト") > 0 Then
        '件名が「テスト」の場合はテスト2フォルダへ移動する
        INmail.Items(i).Move Fol2
            
    End If

Next i


End Sub

'Sub SearchGALForNameDirect()
'
'Dim olApp As outlook.Application
'Dim olNamespace As outlook.Namespace
'Dim olAddrList As outlook.AddressList
'Dim olAddrEntries As outlook.AddressEntries
'Dim olAddrEntry As outlook.AddressEntry
'Dim strName As String
'
'' 名前を設定します
'strName = "指定の名前"
'
'Set olApp = New outlook.Application
'Set olNamespace = olApp.GetNamespace("MAPI")
'Set olAddrList = olNamespace.AddressLists("グローバル アドレス一覧")
'Set olAddrEntries = olAddrList.AddressEntries
'
'On Error Resume Next
'Set olAddrEntry = olAddrEntries.Item(strName)
'If Not olAddrEntry Is Nothing Then
'    Debug.Print olAddrEntry.Name & " was found in the GAL."
'    Debug.Print "Email: " & olAddrEntry.GetExchangeUser.PrimarySmtpAddress
'Else
'    Debug.Print strName & " was not found in the GAL."
'End If
'On Error GoTo 0
'
'Set olAddrEntry = Nothing
'Set olAddrEntries = Nothing
'Set olAddrList = Nothing
'Set olNamespace = Nothing
'Set olApp = Nothing
'
'End Sub
'------------------------------------
'Sub SearchAddress()
'
'' Outlook.Application オブジェクトを作成
'Dim olApp As Object
'Set olApp = CreateObject("Outlook.Application")
'
'' Namespace オブジェクトを取得
'Dim olNS As Object
'Set olNS = olApp.GetNamespace("MAPI")
'
'' グローバルアドレス一覧を取得
'Dim olGAL As Object
'Set olGAL = olNS.GetGlobalAddressList
'
'' 検索キーを設定（ここでは例として "example@example.com"）
'Dim SearchKey As String
'SearchKey = "example@example.com"
'
'' グローバルアドレス一覧から検索キーに一致するアドレスを検索
'Dim olItem As Object
'Set olItem = olGAL.AddressEntries.Find("[SMTPAddress]='" & SearchKey & "'")
'
'' 検索結果を表示
'If Not olItem Is Nothing Then
'    MsgBox "Found: " & olItem.Name
'Else
'    MsgBox "Not Found"
'End If
'
'End Sub

'完全にOutlookを閉じてから処理を実行してみる
AtCoder初心者 DailyTrainingメモ 2023/11/20

# ABC252 B-問題
https://atcoder.jp/contests/adt_easy_20231115_1/tasks/abc252_b

![252b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547298/f4adcafe-4d09-a571-64e4-5f4bb24603a2.png)

**ポイント**
リスト内の最大値を求めるには、max()を使う。
並び順にリストのインデックスを活用する。

````Python:252B.py
N,K = map(int,input().split())
A = list(map(int, input().split()))
B = list(map(int, input().split()))

# 美味しさの最大値
MA = max(A)

# 美味しさの最大値の位置を記録する
M_idx = []

for i in range(N):
    if A[i] == MA:
        M_idx.append(i + 1)

# 一致した場合は、嫌いな食品を食べる可能性がある
for i in range(K):
    if B[i] in M_idx:
        print("Yes")
        exit()

print("No")
````
別の方の回答を参考にする

````Python:252B2.py
<入力>
N,K = map(int,input().split())

# 並び順として揃えるために先頭に[0]を格納
A = [0] + list(map(int, input().split()))
B = list(map(int, input().split()))

# おいしさの最大値
MA = max(A)

for i in range(K):
    # リストBから何番目の食品を食べるか
    b = B[i]

    # 一致した場合は、嫌いな食品を食べる可能性がある
    if A[b] == MA:
        print("Yes")
        exit()

print("No")
````
# ABC310 C-問題
https://atcoder.jp/contests/adt_easy_20231115_1/tasks/abc310_c

![310C.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547298/6336639f-3ad9-a8ac-7fe8-d526aebe59a6.png)

**ポイント**
・文字列と反転した文字列の両方を　in で存在を確認する。
・何種類かという問題は、set で重複を削除する。

````Python:310C.py
N = int(input()) 

# set を利用して重複を削除する
ST = set()

for _ in range(N):
    S = str(input())
    # 文字を反転する
    T = S[::-1]

    # S or T がSTに含まれたらスルー
    if S in ST or T in ST:
        continue
    else:
        # 含まれない場合は、ST に格納する
        ST.add(S)

print(len(ST))
````
Pythonでカラフルなファイルシステムを作ってみた

今回は、Pythonでカラフルなファイルシステムを作ってみました。

最近、Pythonでオリジナルのファイルシステムを作っています。色付けと簡単なフォーマットを適用するだけで見栄えが良くなることに気づいたので、そのコードを紹介します。

## Decoderの準備

まず、色付けとログ記録を自動で行ってくれるデコレータの`fuse_method`関数です。この関数はデコレートされたメソッドを実行し、例外が発生した場合には`error`関数を呼び出します。

```python
def fuse_method(f):
    def wrapped_func(*args, **kw):
        try:
            return f(*args, **kw)
        except:
            error('Unhandled error')
    return wrapped_func
```

次に、エラーメッセージを表示するための`error`、警告メッセージを表示するための`warn`、情報メッセージを表示するための`info`、デバッグメッセージを表示するための`debug`関数です。

```python
def error(*args, **kw):
    from traceback import format_exc
    print(f'{Fore.RED}ERRO{Fore.RESET}', *args, *kw)
    for line in format_exc().splitlines():
        print(f'{Fore.RED}   *{Fore.RESET}', line)

def warn(*args, **kw):
    print(f'{Fore.YELLOW}WARN{Fore.RESET}', *args, **kw)

def info(*args, **kw):
    print(f'{Fore.GREEN}INFO{Fore.RESET}', *args, **kw)

def debug(*args, **kw):
    print(f'{Fore.***}DEBG{Fore.RESET}', *args, **kw)
```

これらの関数を使うと、簡単にログを出力できます。以下はファイルシステムの一部のコード例です。

```python
class OreOreFS(Fuse):
    ...
    @fuse_method
    def readlink(self, path):
        ....
```

このようにしてログ出力を自動化することができます。

## オレオレファイルシステム
「オレオレファイルシステムって何？」と思われるかもしれませんが、これは私が考えた最強のファイルシステムです。実際には新しいファイルシステムを作ることはなく、既存のWebサービスをファイルシステムにマウントするフィルタドライバを作ることが多いです。特にWindowsでは、WebDAVのリダイレクタを作るだけで済む場合があります。ただし、WindowsでのFUSEの開発は少し難しいです。WSLで開発するか、Dokanを使うかを検討する必要があります。

PythonのFUSEライブラリである`python-fuse`を使用しています。以下は`python-fuse`のサンプルコードの一部です。

[https://github.com/libfuse/python-fuse/blob/master/example/hello.py](https://github.com/libfuse/python-fuse/blob/master/example/hello.py)

なお、`pyfuse`を使いたかったのですが、GentooのPortageには存在しなかったため、断念しました。

FUSEは以前、Dokanが全盛期の頃にたくさん開発したので、短期間で開発することができそうです。また、言語バインディングも豊富です。ただし、一番の問題は「どのようなファイルシステムにするか」ということです。ハードウェアから自作することも考えられますが、かなり手間がかかります。

さらに、ファイルシステムを作るために、さまざまなハードウェアの実験を行っています。例えば、ESP32のBLE LL周りのテストは非常に面倒ですが、ファイルシステムにすることで簡略化できるかもしれません。EEPROMなどのデバイスにアクセスすることもできますが、利用方法によっては少し手間がかかる場合があります。

コマンドを送信してデバイスに直接アクセスすることが好きなので、デバイスのドライバレベルの高度な操作はあまり詳しくありません（笑）

以前、遊びで購入したハードウェアのリンクを共有します。

[https://jp.robotshop.com/products/devantech-usb-to-i2c-module](https://jp.robotshop.com/products/devantech-usb-to-i2c-module)

これはUSBを使用してさまざまなデバイスと通信するためのデバイスです。Cのサンプルコードのリンクも忘れてしまいましたが、どこかにあるはずです（笑）探してみて、見つかったら教えてください。
HTTPステータスコードとWebアプリの設計

## オフショア開発チームとの協業の悩み

オフショアのエンジニアの管理・育成として、私はここ数年間、オフショアのチームをサポートさせていただいています。最近、 **「君たちなんでこれが理解できないの？」** と思わざるを得ないんです。
知識を集約化して共有するしかないのかな？というところに辿り着きました。

## HTTP Status コード
そこで、今更ですが、HTTP Status コードについて解説したいと思います。HTTP Status コードは、Webアプリ開発において非常に重要な概念です。しかし、実装の中でこのコードを適用せずにエラーハンドリングを行っている場合には意味がないということもあります。

Webアプリを開発する際には、クライアントにエラーを返す必要がある場合に、HTTP Status コードを適切にマッピングしてエラーハンドリングを行うことで、設計がよりクリーンになります。

## Microsoft Graph
さて、RESTful API などが枯れた技術になっている現代においては、この知識は当然のものかもしれませんが、まだまだ外部サービス連携においては重要な要素となっています。

例えば、Microsoft のドキュメントを見る限り、彼らも非常に綺麗な設計で RESTful API を提供しています。詳細はこちらのリンクをご覧ください。

[Microsoft Graph API](https://learn.microsoft.com/ja-jp/graph/overview)

## 最近の主流
GraphQL や gRPC が主流になろうとしている中で、今更感はありますが、この知識は常に抑えておいてほしいものですね。

さて、余談ですが、買い物をしようと思っていつも忘れてしまうものを、ネタ枠としてメモしておきたいと思います。笑

[買おうと思っていつも忘れるこれネタ枠](https://llminatoll.booth.pm/items/1036373)

いらない情報かもしれませんが、笑いのネタにでもどうぞ。
wslでnerves その25

# 概要
wsl(wsl2じゃない)でnervesやってみる。
qemu(x86_64エミュレータ、ラズパイじゃない)でやってみた。
生成したnerves_livebook.imgを、quemで起動してテストしてみた。

# 動作するモジュール

- nx
- VintageNet
- Toolshed
- req
- jason


# 動作しないモジュール


- kino.html
- kino.tree
- kino.datatable
- socket
- explorer
- maplibre
- vegalite


以上。
コードレビューと自動デプロイの注意点

## コードレビューの重要性と Code Owners の活用

こんにちは、みなさん！今日は開発現場でよくあるトラブルについてお話ししましょう。実は、コードレビューを怠ることによって起こるバグです。 さらに、GitHub の便利な機能である CODEOWNERS の機能を活用することで、このような問題をある程度回避する方法もご紹介します。

## ある日の開発現場

山田さん：プルリクエストを作成しました。
高橋さんと下田さん：レビューして "Approve" しました！
山田さん：小さい修正だったため、担当の浦田さんに修正箇所を詳しく説明せずマージしました。

その後、CI/CDによる自動デプロイが実行されるわけですが、浦田さんから30分後slackにて
「なんでそれマージしちゃったの？」とご連絡。
浦田さんによると、修正した部分が他のファイルにも影響を与えるため、修正すべき箇所があったとのことです。

そして、デプロイが完了した瞬間、バグが発生してしまいました。バグが周囲を駆け巡り、開発チームは大慌てです！:bomb:

本番環境へのデプロイの方法もまずい気がするんですけど、あるあるっちゃあるあるです。

## CODEOWNERS
このような事態を避けるために、私たちは CODEOWNERS という機能を利用することができます。Code Owners を使用すると、各ファイルやディレクトリの所有者を指定できます。したがって、修正する必要のあるファイルが明確になり、誰がレビューするべきかも明確になります。

具体的には、`.github/CODEOWNERS` というファイルを作成し、所有者を指定します。たとえば、`*.html` ファイルを担当するのはDさんであると指定することができます。これにより、プルリクエスト作成者が修正する必要のあるファイルを確認できるようになります。

CODEOWNERS の活用によって、開発現場での混乱やバグ発生のリスクを最小限に抑えることができます。そして、開発チーム全体が効率的にプログラミングに取り組むことができるのです。

## 注意点
最後に、Code Owners を利用するためには、GitHub の課金プランが必要です。ですが、この便利な機能を使うことで、バグ発生のリスクを減らすことができるので、チームの生産性向上につながること間違いありません！

開発現場でのコードレビューは、バグ予防や品質向上に欠かせない重要なステップです。ぜひ、CODEOWNERS を活用しながら、効果的なプロジェクト管理を行いましょう。

それでは、Happy Coding！:rocket:
メモ [CDK] Secrets Manager から値を取得してCDKで利用する

例えば、 AWS Secrets Manager に以下のようの保存されていれば

シークレットの名前: secretName
シークレットキー: /hoge/fuga
シークレットの値: xxx


以下のようにCDKで値を取り出すことができる

``` .ts
    const secret = SecretValue
      .secretsManager(`secretName`, { jsonField: `/hoge/fuga` })
      .toString() // xxx
```

公式：

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.SecretsManagerSecretOptions.html
文系新米エンジニアが半年に1回資格を取得する方法

# はじめに:raising_hand_tone1:

私は現在入社2年目の新米インフラエンジニアです！
これまで半年に1回は資格取得を行っており、計5つの資格を取得しています。
自分語り多めになりますが聞かれることもあるので、今回は継続した資格取得を目指している新米エンジニア向けに、普段自分がしている資格取得までの流れをまとめました。

# 1.試験6か月～4か月前

取得予定の資格の選定を行います。
モチベーションのためにも大体は現場で使う技術分野の初心者向けのものを選ぶようにしています。

基本的に自分のモチベーションは
**「現場でしていることがよくわからん…基本的なことを大まかに勉強したい…
せや！どちらにせよ勉強するなら資格勉強したろ！」**
の気持ちがあるためです。

人によってモチベーションが異なるので、モチベーションにつながるものを取得するのが1番だと思います。

またここで<ins>試験の形式、合格ライン、平均的な勉強時間</ins>を把握しておきます。

# 2.試験4か月～2か月前

教材集めをします。
私の場合は基本的に書籍がメインなので、大きい本屋さんに行き、中身を見つつ数時間かけて数冊購入します。

**1冊は試験内容理解用の書籍
2冊目は問題集
3冊目は実践的に学習できるものかスピード問題集なもの**

で買うことが多いです。
選ぶ基準は読みやすいかどうかのみです。
試験にバージョンなどがあれば最新のものを選びます。

ここでは本を買うと同時に<ins>試験の勉強内容や全体の雰囲気</ins>をとらえておきます。

# 3.試験2か月前～1.5か月前

試験内容理解用の書籍を読み始めます。
ここではあまり時間をかけたり問題を解いたりせず、<ins>なんとなく試験範囲に目を通すように</ins>読みます。

ただし、読んでいてよく分からないものや似たようなものが複数あって違いが分からない等、深堀が出来そうなものはここで調べておきます。
また実践的に触っておきたい場合も、のちのち時間が足りなくなるのでここで触りますが本来の目的から逸れることを避けるためにあまり時間はかけないようにします。

# 4.試験1.5か月～0.5か月前

試験内容理解用の書籍を読むついでに付属の問題を解いたり、問題集を解き始めます。
ここでのポイントは以下です。

**・解くときは1問ごとや単元ごとより模擬試験など一気にできるものだとよい
・時間はあまりかけずに解く
・解いた問題全体の点数と単元ごとの点数を出しておく
・間違えた問題は必ず解説を読む(+できれば試験内容理解用の書籍も該当箇所は改めて読み返す)
・間違えた問題が読み込む用の書籍に載っていなかった場合は、別でノート等を用意してそこに書き溜めておく
・時間がないときは正答率が悪い単元を集中して学ぶ**

上記のポイントを押さえながらひたすらアウトプットとインプットを繰り返します。
繰り返すうちに点数が徐々に上がってきたら学べていると思って繰り返し学習してください。
あまり点数が上がらない場合は、これまでの勉強法が自分に合っていないか勉強不足の可能性があります。

その場合は以下のように対処してみてください。

**・同じような問題をいつも間違えている
　＋解答を見て「これこれ！」となるとき**
　　→シンプルに学習不足なので本に付箋を貼るなどして意識して繰り返し勉強する

**・同じような問題をいつも間違えている
　＋解答を見て「いつも何言ってるかよくわからん」となるとき**
 　　→内容を理解できるまで自分で内容をネット等で調べてみるor実践してみる

**・全体的に問題を間違えている
　＋解答を見てなんとなく見覚えがあるとき**
　　→学習不足のため継続

**・全体的に問題を間違えている
　＋解答を見ても「何言ってるかわからん」となるとき**
　　→教材や勉強方法が自分に合っていない可能性があるので変えてみる

試行錯誤を繰り返して点数の様子を見てみてください！

# 5.試験0.5か月前

これまでは全体を意識するために、何か読むにしても問題を解くにしてもあまり時間をかけないようにしていましたが、ここからは最後の仕上げとして丁寧に問題を解くことと調べ学習を行ってください。
大体は最後まで苦手な分野があるはずなのでそれらをノートにまとめるのもよいと思います。

# 6.試験当日:muscle_tone1:

あとはこれまでの成果をぶつけるだけです！
ただしケアレスミスには気を付けることと、時間が余ったらすべて見直しに使ってください。

これだけ試験対策を行えば、初級の資格取得は大体問題無いと思います！

今後試験がある方はご参考までに！
応援してます:crossed_flags:
さくらのクラウドNFSアプライアンスをSNMPで情報収集する

## 前置き
[さくらインターネット　アドベントカレンダー](https://qiita.com/advent-calendar/2023/sakura)の9日目の記事です

この記事では、さくらのクラウドの[NFSアプライアンス](https://manual.sakura.ad.jp/cloud/appliance/nfs/index.html)のディスクリソースを、[snmp_exporter](https://github.com/prometheus/snmp_exporter)を使って情報を収集する方法について説明します

### この記事の対象者
- PrometheusからNFSアプライアンスのディスクリソースの情報を収集したい方
- さくらのクラウドのAPIキー発行にハードルのある方

### 今回の構成

<img width="400" alt="構成図" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282233/bfde2fd0-b539-7d0b-8d1f-75e18754874e.png">

- さくらのクラウド NFSアプライアンス 1台
- サーバー 1台(Ubuntu 22.04 2Core 4GB)
    - dockerがインストールされていること
- ローカルスイッチ 1台

## snmp.ymlの作成
SNMPのパッケージをインストールする
```
$ apt install snmp snmp-mibs-downloader
```

MIBをダウンロードする
```
$ download-mibs
```

download-mibsでダウンロードしたMIBを./mibsへコピーする
```
$ mkdir ./mibs
$ cp /usr/share/snmp/mibs/ietf/* ./mibs
$ cp /usr/share/snmp/mibs/iana/* ./mibs
$ find /usr/share/snmp/mibs/ -type f -exec cp {} ./mibs \;
```

generator.ymlを作成する
```generator.yml
---
auths:
  public_v2:
    version: 2
    community: sacloudnfs # コミュニティ名「sacloudnfs」固定

modules:
  nfs_snmp: # 任意のモジュール名
    walk: [dskEntry]

```

ファイル構成は下記
```
.
├── generator.yml
└── mibs
    ├── ACCOUNTING-CONTROL-MIB
    ├── ADSL2-LINE-MIB
    -----省略-----
    ├── VRRP-MIB
    └── WWW-MIB

1 directory, 335 files
```

generatorを実行して、snmp.ymlを作成する
```
$ docker run -it -v "${PWD}:/opt/" prom/snmp-generator generate
$ ls
generator.yml  mibs  snmp.yml
```

## snmp_exporterの起動
コンテナの起動
```
$ docker run -it -v "${PWD}/snmp.yml:/etc/snmp_exporter/snmp.yml" \
    -p 9116:9116 prom/snmp-exporter
```

`http://<IPアドレス>:9116/` にアクセスすると下図のような画面になります
- Target: NFSアプライアンスのIPアドレス
- Auth: public_v2
- Module: nfs_snmp
を入力して、Submitボタンを押します
<img width="400" alt="SNMPExporter" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282233/e0387d0a-8e0b-f54a-c328-2bfadabdfb17.png">


メトリクス一覧が表示されます
<img width="400" alt="SNMPmetrics" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282233/15aed9e9-e978-5096-80b5-cbd285d0a875.png">


## 終わり
以上でSNMPで情報が取得できるようになりました!!
任意でPrometheusから参照することで、ディスクの空き容量などを監視することができます

ここまで読んでいただきありがとうございました


## 参考文献
- [prometheusでSNMP監視をする](https://qiita.com/engishoma/items/0d6a0cb95d0d00cb5e53)
- [SNMP ExporterからのメトリクスをPrometheusで表示する](https://techstep.hatenablog.com/entry/2019/01/12/195059)
- [NFSアプライアンス](https://manual.sakura.ad.jp/cloud/appliance/nfs/index.html)
- [SNMP Exporter Config Generator](https://github.com/prometheus/snmp_exporter/tree/main/generator)
【Swift】PlaygroundでPreviewできるらしい

# はじめに
PlaygroundでViewをPreviewする事ができることを知りました。
![スクリーンショット 2023-11-20 20.22.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/42988a25-a24f-caf0-ce50-897d7591a80c.png)

# 実装
```swift
import SwiftUI
import PlaygroundSupport

struct PlaygroundView: View {
    var body: some View {
        VStack {
            Text("Hello, World!")
            Text("Hello, World!")
            Text("Hello, World!")
            Text("Hello, World!")
            Text("Hello, World!")
        }
        .frame(width: 300, height: 300)
    }
}

PlaygroundPage.current.setLiveView(PlaygroundView())
```

# やりかた
① 右上の5本線のボタンをタップします。
② 「Live View」をタップします。
![スクリーンショット 2023-11-20 20.28.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/eb5d640f-dca7-48e9-4e9c-37377918d949.png)

③ 再生ボタンを押して実行します。
![スクリーンショット 2023-11-20 20.29.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/3de588a9-9f89-1580-0abd-09e9c0910ea9.png)

# おわり
簡単なUIの確認とかはPlaygroundで良さそう
今まで毎回新規プロジェクト作ってた、、、
[Haskell] 3 種類の <-

Haskell では以下の 3 種類の `<-` があります:

- `do` 記法
- リスト内包表記
- パターンガード

参考「[10 Syntax Reference](https://www.haskell.org/onlinereport/haskell2010/haskellch10.html)」

# 1. `do` 記法の `<-`

`do` 記法の `<-` は演算子 `=<<` および `>>=` のような動作をします。

右辺が `Monad m => m a` 型のとき、左辺は `a` 型です。

```haskell
main :: IO ()
main = do

    do
        x :: Int <- pure 23 :: IO Int
        print x

    print =<< (pure 23 :: IO Int)
```

```text:実行結果
23
23
```

参考「[3.14 Do Expressions - 3 Expressions](https://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-470003.14)」

# 2. リスト内包表記の `<-`

リスト内包表記の `<-` はリスト内の要素を表すような条件を意味し、「ジェネレータ」と呼ばれます。

右辺が `[a]` 型のとき、左辺は `a` 型です。

単純な例では `map` 関数のような動作をします。

リスト型はモナドのため、モナドの演算子や `do` 記法でも似たような書き方ができます。

```haskell
main :: IO ()
main = do

    -- 
    print $ do
        [x * 2 | x <- [1..3]] :: [Int]

    -- 
    print $ do
        map (* 2) [1..3] :: [Int]

    print $ do
        (* 2) <$> [1..3] :: [Int]

    print $ do
        x <- [1..3]
        pure $ x * 2 :: [Int]
```

```text:実行結果
[2,4,6]
[2,4,6]
[2,4,6]
[2,4,6]
```

参考「[3.11 List Comprehensions - 3 Expressions](https://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-420003.11)」

# 3. パターンガードの `<-`

ガードの `<-` はパターンや `case` 式の選択肢のような動作をし、「パターンガード」と呼ばれます。

右辺と左辺の型は等しくします。

```haskell
data T = Foo | Bar

f :: T -> String
f x
    | Foo <- x = "Foo"
    | Bar <- x = "Bar"

g :: T -> String
g Foo = "Foo"
g Bar = "Bar"

main :: IO ()
main = do

    let x = Foo :: T

    -- 
    putStrLn $ f x

    putStrLn $ case x of
        y
            | Foo <- y -> "Foo"
            | Bar <- y -> "Bar"

    -- 
    putStrLn $ g x

    putStrLn $ case x of
        Foo -> "Foo"
        Bar -> "Bar"
```

```text:実行結果
Foo
Foo
Foo
Foo
```

パターンガードを用いた変数束縛も可能です。

```haskell
data T = Foo Int | Bar

f :: T -> Int
f x
    | Foo y <- x, y > 0 = y
    | otherwise         = 0

g :: T -> Int
g (Foo x)
    | x > 0     = x
    | otherwise = 0
g Bar = 0

main :: IO ()
main = do

    let x = Foo 23 :: T

    -- 
    print $ f x

    print $ case x of
        y
            | Foo z <- y, z > 0 -> z
            | otherwise         -> 0

    -- 
    print $ g x

    print $ case x of
        Foo y
            | y > 0     -> y
            | otherwise -> 0
        Bar -> 0
```

```text:実行結果
23
23
23
23
```

参考「[4.4.3 Function and Pattern Bindings - 4 Declarations and Bindings](https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-830004.4.3)」
参考「[3.13 Case Expressions - 3 Expressions](https://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-460003.13)」
AMIから新規インスタンスを起動したらミドルウェアが勝手に更新されてた話

docker v18がインストール済みのEC2インスタンスについて、v20にアップデートしようと思い、検証のためにAMIを作成後インスタンスを作成した
起動後すぐはv18のままだったが、5分くらいするとv20になるという事象が発生

なぜかと思い色々と調べたら、どうやらデフォルトでは初回起動時にyum update --securityが実行されるようだった
しっかりドキュメントにも記載がありました
https://aws.amazon.com/jp/amazon-linux-ami/faqs/

```/etc/cloud/cloud.cfgを編集
repo_upgrade: security
↓
repo_upgrade: none
```

ちなみに、「repo_upgrade: all」という設定もある
【MySQL,Rails】アプリケーションの動作を改善したい（INDEX）

どうもこんにちは。

今回はRailsでデータベースにインデックスを貼る方法をまとめます。

# インデックスとは

インデックスは、データベース内のデータを迅速に検索するための構造です。データベースにおいて、特定の列（フィールド）に対してインデックスを作成することで、その列を使った検索やソートが高速になります。

# インデックスの構造

## データのポインター

インデックスは、実際のデータの場所を指し示すポインターの集まりです。これにより、データベースは全ての行を調べるのではなく、必要なデータを迅速に見つけることができます。

## 構造

多くのデータベースシステムでは、インデックスはB-Treeという特殊な木構造で作成されます。これにより、大量のデータの中からも効率的に検索が可能になります。

# インデックスの利点と欠点

## 利点

### 高速な検索

インデックスがあると、データベースは特定の値を持つ行を迅速に見つけることができます。
効率的なソートと集計: インデックスされた列を使ってデータをソートや集計する操作が高速になります。

## 欠点

### 追加のストレージ要件

インデックスは追加のディスクスペースを必要とします。

## 書き込みの遅延

データの挿入、削除、更新の際にインデックスも更新する必要があるため、これらの操作が遅くなる可能性があります。

# いつインデックスを使用するか？

## 頻繁に検索される列

よく検索条件に使われる列にはインデックスを設定すると良いでしょう。

## 大量のデータが含まれるテーブル

データが多いほど、インデックスの効果は顕著になります。

## 一意性が高い列

重複する値が少ない列（例えば、ユーザーID）にインデックスを設定すると効果的です。

# Railsで使用してみる

Railsアプリケーションで以下のSQLが実行されたとします。

```sql
SELECT `childs`.`id` AS t0_r0, `childs`.`created_at` AS t0_r1, `childs`.`updated_at` AS t0_r2, `childs`.`parent_id` AS t0_r3, `childs`.`name` AS t0_r4, `childs`.`age` AS t0_r5,
`childs`.`birthday` AS t0_r6, `parents`.`id` AS t1_r0, `parents`.`created_at` AS t1_r1, `parents`.`updated_at` AS t1_r2, `parents`.`name` AS t1_r3, `parents`.`age` AS t1_r4, `parents`.`birthday` AS t1_r5
FROM `childs`
LEFT OUTER JOIN `parents` ON `parents`.`id` = `childs`.`parent_id`;
```

この場合、`childs`テーブルの`parent_id`にインデックスは貼ります。

## 手順1. ターミナルでコマンドを実行

Railsのルートディレクトリでターミナルを開いて以下のようにコマンドを実行してください。

```
rails g migration AddIndexesToChildsAndParents
```

以下のコマンドを実行すると、マイグレーションファイルが作成されます。

## 手順２. マイグレーションファイルの確認

以下のように記述されたマイグレーションファイルが作成されます。

```ruby
class AddIndexesToChildsAndParents < ActiveRecord::Migration[6.0]
  def change
    add_index :childs, :parent_id
  end
end
```

## 手順3. マイグレーション実行

以下のコマンドを実行します。

```
rails db:migrate
```

# まとめ

以上にように実行すると、DBにインデックスを貼ることができ、動作の改善をすることができます。
AVTOKYO Open xINT CTF 2023 mural writeup

# レンズ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/11d9c520-345f-4065-ce8b-943b4a8fd263.png)

# 写真販売サイト「alamy」で地名を発見
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/d5b256a9-1774-3e51-9ad1-26fdaefba656.png)

Enghelab (Revolution) avenue

※はまりポイント
「革命通り」では、検索できない。

# Enghelab avenue
GoogleマップでEnghelab avenueを検索すると約6.5kmある。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/09246760-be1e-8a94-b436-2786eb7b962e.png)

ストリートビューで歩くの大変なので。。。

# Google Earth を活用

ジョージアの戦車のOSINTで培ったテク、Google Earth活用。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/9f039bd5-3332-03a1-8a8b-dca9c75bc124.png)

有名な写真スポットっぽいのに無い。

# ストリートビュー最高

中心から右へ左へうろうろ。
地道にがんばれば必ず見つかる。

![あったーーーー.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/7fbbac6d-ae0a-e10b-c504-3df363b68be6.png)

# Google Earth で解けなかった理由

カメラの高度を上空31kmから19kmまで拡大したら見つかった。

![19km.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/78e57677-1824-ac20-f84c-cd72328c002b.png)

Google Earthの写真リンクは、GPSがある程度絞り込めた場合に使うべきだな。
【Felica】Pasori RC-S300×WebUSBで学生証を読む（Read Without Encryptionする）

# はじめに
現在、12/12日の23時5分ですが、何としてもアドカレ12日目に間に合わせるんだ！！！という決意のもと、とんでもなく端折った記事を公開します。
後日必ず追記しますのでお許しください。

# 本題の導入
弊学ではFelicaタイプの学生証が導入されており、タッチして校舎内に入ったり出席管理を行う仕組みになっています。
この学生証タッチの仕組みをWebアプリに組み込めば私の所属する部で部員管理が楽にできるな～と思い立ったのが始まりです。
しかし、開発にあたって調べてみると、Felicaは国内の色々な所で使われているにもかかわらず、ネット上の情報が意外と少ないという壁がありました。特に、今回取り上げるRC-S300とWebUSBの組み合わせの記事はほぼありません。なので今回取り上げます。

# やりたいこと
カードリーダーをPCに繋ぎ、学生証をWebアプリから読み取りたい。
すなわち、学生証から学籍番号を読み取りたい。

# 技術的にはどうする？
Pasori RC-S300というSONY製のカードリーダーとPCを繋ぎます。繋いだら、ブラウザからWebUSB APIを使用してPasoriと通信し、JavaScroptでカード情報の読み取りを行えるようにします。


# カードについて
「ピッ」とタッチするタイプの非接触ICカードには当然規格があります。これがNFCと呼ばれるものです。また、NFCの中にもタイプがあり、NFC Type-A・Type-B・Type-Fなどがあります。
日本国内ではSuicaに代表されるようにFelica規格が普及しています。「Felica」は別名で、Type表記で書くのであればNFC Type-Fとなります。

まずカードを読み取る際には、まず最初にカードに対してポーリングという作業をしてあげる必要があります。ここで、カードの固有のID（という建前）であるIDmを入手します。

その後、カードの中のデータ、本記事でいえば認証不要な領域を読み取りたい場合、そのコマンド中には入手したIDmを追加する必要があります。「○○さんに話しかけてるんですよ～」と名前を呼ぶイメージです。

では、カードのどこに学籍番号のような情報が収められているのでしょうか？
それは認証不要の領域になります。

Felicaカードは色々なことに使えるように設計されており、例えば交通系ICカードなどの決済に関する機能は認証が必要な領域で保護されていますし、その仕様も一般には公開されていません(サイバネ規格などと呼ばれる)。
ただ、一般にも使いやすいように認証なしで書き込み・読み込みできる領域も用意されています。
Felicaカードを使った学生証や社員証などは、この認証不要な領域に必要な情報を書き込んでおいて、「ピッ」でその情報を読み込むというわけです。

この認証不要な領域を読み取るコマンドを、「Read Without Encryptionコマンド」といいます。

では、Read Without Encryptionをするのには何の情報が必要でしょうか？
それは、先ほど述べたIDmとアドレスです。

さっきから「領域」と書いていますが、この「領域」の住所にあたるのがアドレスです。
特定の領域を読み取るにはやはり場所を指定してあげる必要があるのです。

ではアドレスはどうやって入手するのか？
それは事前に知っている必要があります。

felicalibなど、Felicaカードをダンプするツールがあるので、これを使用して探します。

# 本題（というか結論）
以下のコマンドをRC-S300に送ってください。
XXの部分は読み取りたいカードのIDmに置き換えてください。

またダンプの結果、弊学の場合、学籍番号が抑えられているアドレスが0x1A8Bだったので、これをリトルエンディアンで8B 1Aというようにしてコマンド中に記載しています。
```
6B 25 00 00 00 00 05 00 00 00 FF 50 00 01 00 00 1B 5F 46 04 A0 86 01 00 95 82 00 10 10 06 XX XX XX XX XX XX XX XX 01 8B 1A 01 80 00 00 00 00
```
本当はコマンドを組み立てるにあたってリクエストの長さなどを調べてコマンドに付加するといった工程が必要ですが、これはまた後日書きたいと思います。。。

帰ってきたレスポンスがこちらです。
```
83 2D 00 00 00 00 05 02 00 00 C0 03 00 90 00 92 01 00 96 02 00 00 97 1D 1D 07 XX XX XX XX XX XX XX XX 00 00 01 [ここにブロックデータ] 90 00
```
ブロックデータ中に学籍番号がhexで収められています。

# 参考にした記事
本題に入る前に、以下の記事をめちゃくちゃ参考にしました。

以下の記事は概要を把握するのに非常に役立ちます。
https://qiita.com/MarioninC/items/97b82e8eeb3f626a5875
https://qiita.com/MarioninC/items/b5c59e78f3e23c06b83f
こちらの記事は連載になっています。プロトコルの詳細な解説やプログラム面で非常に参考になります。
 https://sakura-system.com/?p=2892
💸 [Roblox] ゲーム内外で収益を得る！最新4選

# Roblox で収益を得る方法

1. ゲーム内アイテム販売
    自作のゲーム内でBadge, DeveloperProductを販売して収益化💰

1. ゲーム外アイテム販売
    ゲーム内外で使えるアイテムやコスチュームを提供👕
1. 有名になるとボーナス
    ゲームが有名になれば、運営からボーナス金が支払われる🌟
1. Roblox内広告
    [Roblox in-game ads](https://www.gamesindustry.biz/roblox-to-launch-in-game-advertisements-next-year)で広告収益を得る📢

おしまい
cursorをインストールしたはいいが、Windows上でしか使えないうえに、既存のWSLが開かなくなった。困ったので備忘録

表題の通り。

WSL上では環境変数Pathにてより優先度の高いポジションにcursorがあり、既存のcodeコマンドは上書きされてしまう。
さらにはwslでcodeがcursorで動くかといわれるとコマンドの起動に失敗する模様。

## やったこと
まず、環境変数のcursorどうするか。wsl上ではwindows環境変数が引き継がれる。
Windowsでのシステム環境変数のPathで一番下にcursorが追加されており、それが優先されている。もしcursorなんていいよ、vscodeに戻してよっていうのであればこれを消す（もしくはvscodeの優先度を上げる）だけでvscodeが起動するようになる。

wsl上でコマンドを書き換えたければ以下のパスにあるコマンドを書き換えること（もちろん念のためバックアップとること）


``` bash
hoge@Mb:~$ which cursor
/mnt/c/Users/hoge/AppData/Local/Programs/cursor/resources/app/bin/cursor
```

コマンド
https://gist.github.com/ddwang/0046da801bcb29d241869d37ad719394
【flutter】ボタンを押したら色が変わる！？

こんにちは！
今回は三項演算子を使って、ボタンを押したらボタンの色が変わる処理の仕方を紹介したいと思います！
最後まで読んでいただけたら嬉しいです！

![div_image5.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524127/ac215901-e129-c80f-f4c1-0d12de5cf444.jpeg)


## 1,最初のコード
```php

 ElevatedButton(
          onPressed: () {},
          style: ElevatedButton.styleFrom(
           backgroundColor: Colors.red
          ),
          child: Text(
            'タップしてください！',
            style: TextStyle(
              color: Colors.white,
              fontSize: 20,
            ),
          ),
        )
```
このように最初は一つ簡単なボタンを用意します。

## 2,boolを使う
### boolとは？
bool（ブール）は、プログラミングにおいて真（true）または偽（false）の2つの値のみを持つデータ型です。ブール型は、条件を表現したり、条件分岐や制御フローを操作するために使われます。

今回は”ButtonPush”という変数を定義します。
```
bool buttonPush = false;
```

## 3,SetStateを使って状態管理
### SetStateって何？
ウィジェットがStatefulWidgetである場合、そのウィジェットが保持するデータや状態が変更されたとき、これをフレームワークに通知する必要があります。setState メソッドがその通知を行います。
主な役割として、
ステートの変更： setState メソッドの中に記述されたコードが実行され、ウィジェットのステートが変更されます。

再描画のスケジュール： フレームワークは、ステートが変更されたことを検知し、そのウィジェットを含む部分（サブツリー）を再描画することをスケジュールします。

再描画： スケジュールされた再描画が実際に行われ、ウィジェットが新しい状態で再描画されます。

## 4,実際に実装してみて
### コード
```php3

class _MyHomePageState extends State<MyHomePage> {
  bool buttonPush = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Color Changing Button'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            setState(() {
              // ボタンが押されたらisButtonPressedの値を切り替える
              buttonPush = !buttonPush;
            });
          },
          style: ElevatedButton.styleFrom(
            primary: buttonPush? Colors.red : Colors.blue,
            // ボタンの色をbuttonPushの値に応じて変更
          ),
          child: Text(
            'タップしてください!',
            style: TextStyle(
              color: Colors.white,
              fontSize: 20,
            ),
          ),
        ),
      ),
    );
  }
}
```

## 5,最後に
以上で、紹介を終わります！
今回も最後まで読んでいただきありがとうございました！
では、また次の記事で〜！
これやばい！📸 ストアスクショを簡単に！おしゃれな自動生成ツールで一発完了！


ストアのスクショを作成するのがめんどい！そんな時はこれで解決！🚀

https://studio.app-mockup.com

App Mockup を使えば、iOSとAndroidのストア用スクリーンショットを一瞬で完成できます！

![Screenshot 2023-11-20 at 18.35.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1900756/7068dd41-65ac-ff71-be31-10d593d7fd78.png)

無料✨
簡単⚙️
豊富なテンプレ🎉

App Mockupで試してみる　https://studio.app-mockup.com

もうストアのスクリーンショット作成には悩まなくてOK
🕵️‍♂️ Robloxチーター排除！一定時間操作なしでkickする簡単スクリプト

Roblox にはチーターがかなりいますが、簡単にkick する方法があります。

大抵の場合、チーターは一定時間の間、ゲーム内のキャラクターの操作をせずに、別ツールでゲームをハックしようと試みます。

そこで、例えば「５分間操作がなければ自動的に kick する」というスクリプトを書いてみます。
（割と効果があった）


以下のファイルを　StarterPlayer > StarterPlayerScripts　に挿入してください。

```lua: LocalScript
local UserInputService = game:GetService("UserInputService")
local AFKSeconds = 0 
local idleMaxSeconds = 60 * 5 - 2 -- The AFK seconds to be kicked
local IdleReason = "there's no input for 5 mins" -- Reason to be kicked

local PlayersService = game:GetService("Players")
local player = PlayersService.LocalPlayer


UserInputService.InputBegan:Connect(function()
    AFKSeconds = 0
end)

while wait(1) do
    AFKSeconds += 1
    if AFKSeconds == idleMaxSeconds then
        game.Players.LocalPlayer:Kick(IdleReason)
        AFKSeconds = 0
    end
end
```

おしまい。
🚀 日本語で検索するクセを卒業！TOEIC 800点達成と英語力向上の秘訣

悪癖の一つ、日本語での検索。これをやめた瞬間、様々な発見が！💡 

# 前提

以下のルールを以前立てた。そこから二ヶ月経ってみて。。。

- 日本語で検索する話題は「英語の勉強の仕方」に限る
- その他は英語で調べる！

https://qiita.com/kaedeee/items/088fb1a6e7fb2184d5c3

# 発見したメリット

- TOEICのスコアが上がった（800になった）
- 英語への耐性がついた
- 速読力がついた
- 検索結果の質が上がった
    - アフィカスサイトや怪しいサイトに触れる機会が下がった
    - 一つ一つの記事の質が上がった
    - 何を調べても基本出てくるようになった

# 最後に

日本語での検索クセを卒業してから、TOEICスコアは800点達成！英語への抵抗も薄れ、速読力も向上。検索結果も質が上がり、信頼性の高い情報に出会えるように。

おすすめ。
局所的タイピング練習 with Python and ChatGPT

プログラミングにおいて、AIを使うメリットは、
１．単純作業、繰り返し作業の簡略化
２． **変数名を考えなくてよい！！** 
という２点があると考えました。


 ## ソフトウェア概要

GithubのREADMEまんま参照ですが

[iruka-crow/Typing](https://github.com/iruka-crow/Typing/tree/main "Github")
>母音のみ、子音のみ、英文字すべて、日本語それぞれ１文字のみ早く打つためのタイピング練習 ブラインドタッチの練習かキーボードの場所を覚えたいときに

寿司打で「あと少しで3秒ボーナス！」って瞬間にタイプミスをしてしまう。
手がかじかむこともあるでしょうが、まだ正確にキーボードを入力できてない証拠だ！
...と思いこれを作りました。

6つのモードがあり、
<dl>
    <dt>１．母音モード</dt>
    <dd>母音だけを攻めます</dd>
    <dt>２．子音モード</dt>
    <dd>子音だけを攻めます</dd>
    <dt>３．☆全複合モード</dt>
    <dd>これがメインだと思います。a-zの文字に加え、感嘆符なども出てきます</dd>
    <dt>４．日本語かなモード</dt>
    <dd>あ-ん、濁点入りも含めた日本語かなが1文字ずつ出てきます</dd>
    <dt>５．英文入力モード</dt>
    <dd>5-8単語くらいの簡単な文が出題されます</dd>
    <dt>６．日本語文入力モード</dt>
    <dd>簡単な日本語文が出題されます</dd>
</dl>

:::note info
日本語文は未実装
:::


問題数を設定でき、初期設定では「30問」になっています。
問題をすべて解き終わったらかかった時間が出てきます。30秒切れたらまあいい方でしょう。

改善点は、エンターキーをいちいち押す必要があることです。Pythonではそういった直接的なキー入力受付方法は見つからず、getch()という「1文字入力＋Enter」という方法で実現しているらしいですが、日本語もつかうので今は見送りました。




 ## (無関係談)AIで時短を感じた

こんな誰でも作れるようなプログラムですが、実は私半分ほどしか書いていません。いやー、AIは便利ですね！
５番目の英文入力では、100個の英文を載せてこれと入力文を照合しています。仕事でも100個の英文を考えるのなんてやりたくないです。
ChatGPT3.5さんにお願いしたところ、快く数秒で100個も考えてくれました。しかもリスト形式で！
もう乗るしかないですよね、このビックウェーブに

各モード(条件分岐)は自分で書きましたがほぼコピーだし、入力ワードの確認でもChatGPTに書いてもらいました。

こう長くなると、グローバル変数やローカル変数にダブりが生じたりします。どう考えても原因は、英語が得意でない人が「この処理(変数)、英語で書きたいけどスペルわからん！」となり、適当に i や a,b,c,d...などとおいて、今度for文が出たときループカウンタ変数に「i」を使い訳がわからなくなる。。。という症状が多発すると思います。

ですがChatGPTは勝手にそれっぽい名前を付けてくれますし、VSCodeなどを使ってれば簡単に予測変換で打つこともできるはずです。

もっと技術的なAI利用もありますが、こういう身近な時にも役に立つのではないかと思ったりしました。
おしまい。
RustのVersionを固定せずにいたらAPIのlatencyが悪化していた話

## 結論
muslを使用するのをやめた

## 経緯
1. DockerfileでVersionを指定せず、`FROM rust:slim-bullseye`の形でmusl build
1. 負荷テストで問題なかったのでリリース
1. この間にRustのバージョンが上がる
1. 機能追加して再リリース
1. latency悪化に気づく
1. latencyが許容範囲だったRustVersion 1.70.0に固定

## どのくらい悪化したか
BuildするRustのVersionのみを変更してGatlingで負荷テストを行った。version1.71から悪化し始める。1.74.1は2023/12/12時点の最新Version。
| RustVersion| 99th ptc | Max |
|:-----------|:--------:|:---:|
|1.70.0      |23ms      |92ms |
|1.71.0      |25ms      |117ms|
|1.74.1      |32ms      |327ms|

## latency悪化の原因
`musl`が原因。
[Why does musl make my Rust code so slow?
](https://andygrove.io/2020/05/why-musl-extremely-slow/)この記事を見て、バイナリを配布する事はなく`musl`にこだわる必要もないので、使用しないことにした。

## 改修前後のBuild部分Dockerfile
改修前:
```Dockerfile
FROM rust:1.70.0-slim-buster as builder
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    musl-tools \
    perl
RUN rustup target add x86_64-unknown-linux-musl
RUN cargo build --release --target x86_64-unknown-linux-musl

```
改修後:
```Dockerfile
FROM rust:slim-bullseye as builder
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential
RUN cargo build --release
```

## latencyの変化
gnuにするとlatencyは想定した値に戻った。
| RustVersion |99th ptc|Max|
|:------------|:------:|:----:|
|1.70.0（musl） |23ms    |92ms |
|1.71.0（musl） |25ms    |117ms|
|1.74.1（musl） |32ms    |327ms|
|1.71.0（gnu）  |18ms    |83ms |
|1.74.1（gnu）  |17ms    |73ms |

## 教訓
当たり前だが、環境が更新されたらパフォーマンステストしよう。
Oversized Silk Scrunchies & Bohemian Hair Accessories | WOS

Oversized Silk Scrunchies and Bohemian Hair Accessories for the free-spirited soul. Shop now to elevate your everyday look with our widest range of accessories. For the free-spirited soul, oversized silk scrunchies and bohemian hair accessories. Shop now to use our largest selection of accessories to improve your everyday appearance.
Visit: https://worldofscrunchique.com/ to know more!![Scrunchique.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624893/e834499e-2ff4-a340-7352-598e10f0ec6f.jpeg)
🔥 英語を極めし「ガイ」になりたい！ストイックな自分ルールで攻略

Narutoのガイ先生のように、英語を極めるためのストイックな自分ルールを作ってみるぞ！🚀

- 日本語で検索する話題は「英語の勉強の仕方」に限る
- その他は英語で調べる！

これだけで、英語学習がより充実したものになるかもしれないぞ！💪
Laravel10にmaatwebsite/Excel:^3.1.50をインストール

# Laravel10にmaatwebsite/Excelをインストール
Debian12にLaracel10を入れてmaatwebsite/Excelを入れようとすると１.０系が入る。
新しいバージョンを入れようとすると、モジュールが足りないのが原因で入らないようである。
足りないモジュールは、php-gd と php-zipが入っていないと怒られるようなので以下rootで操作
```
apt-get install php-gd php-zip
```
でインストール
続いてcomposerでphpspreadsheetとExcelを入れる
```
composer require phpoffice/phpspreadsheet
composer require maatwebsite/excel:^3.1.50
```
でインストールできる