OmniAICreator/Qiita-1.07M huggingface dataset:
論文に載らないMS-DIAL Tips #2

この記事はtuat-sysbiolab advent calendarの15日目です。

# はじめに

本記事では[前回](https://qiita.com/YukiMatsuzawa/items/efc4b898a9126fd8b327)に引き続き、MS-DIALのあまり知られていなさそうな機能を紹介していこうと思います。

今回はExport機能について紹介していこうと思います。



# 機能紹介

実際のところMS-DIALを使用してくださっている方なら、出力はしていると思いますが、あまり使ったことのない機能もあると思いますので、ちょっと細かく紹介していきます。

まず、MS-DIALの結果の出力は上部のリボンのExportからすることができます。

![ribbon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3944004/bc48af9b-d515-42d6-1ea8-45f7226580e8.png)

ここで「Peak list result」と「Alignment result」の2つのボタンがありますが、これらはそれぞれサンプルごとの結果と、アライメントされたピークの出力に対応しています。基本的にはアライメント後の結果を出力することが多いと思いますので、アライメントの結果の出力機能についてオプションなどを説明していきます。

まず、「Alignment result」のボタンをクリックするとダイアログが開くので、そこから出力要素を選択していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3944004/888d5bf4-d5c3-645e-e3a7-95780c14c971.png)


画面上部に配置されているのは、全出力フォーマットに共通の設定になります。

まず、出力フォルダの選択用のテキストボックスがあります。右のBrowseボタンからフォルダを選択するか、直接フォルダのパスを入力してください。アライメント結果の出力の際にはファイル名は自動で決まるようになっているため、ファイル名の指定はできません。フォルダ名で指定してください。ただし、Windowsのドキュメントやダウンロードなどのフォルダを選んだ場合、フォルダのパスが正しく認識されない場合があるので、C, Dドライブからの絶対パスを入力するようにすることをお勧めします。

次にアライメント結果の選択ボックスがあります。アライメントはパラメータを調整しつつ複数回実施するので、出力する結果を選択できるようにしています。

共通の設定の最後にあるのが、フィルタリングの適用オプションです。MS-DIAL5では出力するピークスポットにフィルタリングを適用することができるようになりました。これにより、特定の脂質クラスのピークのみを出力するだとか、キュレーションを実施したピークのみを出力するなど、自身の目的に応じた出力が可能となっています。



## Peaks

まず紹介するのはPeaksカテゴリの出力です。

こちらのカテゴリの結果はすべて同様の出力フォーマットになっており、1行に1ピークで、メタデータと各サンプルにおける定量値を並べたタブ区切りのテーブルフォーマットになっております。Excelなどで解析を行う方はRaw dataもしくはNormalized dataの定量値を選択して出力していただければよいかと思います。また、たまに使うのはPeak IDの出力です。ここで出力されるPeak IDは各サンプルのピークピッキングの結果に紐づいているので、アライメント後のピークと紐づけたいケースで利用可能です。

オプションとしては、Long format、Excel向けの切り詰めと、マルチクラス出力の３つがあります。

Long formatは主に、出力したデータをPythonやRなどでする方向けで、メタデータの情報を別ファイルにして、複数の定量データを出力した際の出力の重複を減らすことができます。また、ファイル上部のスキップの必要もないので、データフレームとしても読みやすくなります。

Excel向けの切り詰めは、Excelで読み込んだ際に長すぎると途中で改行が入ってしまう問題に対処するために、おもにスペクトルの結果が途中で切り取られています。Excelで読まず、スペクトルの情報を利用したい場合は、チェックボックスを外しておくとよいと思います。

マルチクラス出力は設定したサンプルのクラス名がアンダースコア（＿）で区切られている場合に、分割して出力する機能です。別の機能のために実装しましたが、あまり使う必要があることもないのかなと思います。



## Spectra & MassBank

次はSpectraとMassBankカテゴリについてです。

SpectraカテゴリにはMSPやMGFといった化合物レコードフォーマットでの出力ができます。インハウスライブラリの作成にご利用ください。

オプションの「Export peaks individually」は主にMATファイル向けのオプションになっております。MATファイルはMS-FINDERでの利用を想定していますが、MS-FINDERが1ファイル1レコードを要求するため、個別のファイルに出力できるようにしています。MS-FINDERに投げたいピークをフィルタリングをかけつつ、まとめて出力してあげると、個別にMS-FINDERにかけるより便利かと思います。

MassBankフォーマットも同様にMassBankレコードを出力する機能となっています。単純に出力するだけだと、一部の必須のフィールドが埋まらないですが、リボンの"Option" > "Project property setting"から分析機器などのフィールドを埋めておくと、MassBankに登録するための最低限のフィールドは埋められます。MassBankに標品スペクトルなど登録したい場合はご利用ください。



## その他

最後は"Deconvoluted spectra and reference"カテゴリです。

自分たちも普段使わない出力オプションですが、各ピークのスペクトルとそのピークに紐づいた化合物ライブラリの情報をXMLフォーマットで出力できます。

XMLなので慣れていないと読むのは少し難しいかもしれませんが、リファレンスの情報も含めて出力したいときにいいんじゃないかと思います。



# 終わりに

必要に応じて追加してきたこともあり、様々な出力フォーマットがありますが、自分に必要なフォーマットで出力していただければと。

個人的なおすすめ機能は出力するピークのフィルタリングです。見たいものだけ出力できるので、便利なケースは多いかなと思います。
FlutterのTextFieldで日本語入力が重複する現象への対応

# 事象
FlutterのMacOSアプリで、TextFieldを使用して日本語入力した場合、日本語に変換すると末尾の変換結果が２重に入力されてしまう。

例えば、「日本語を入力する」と入力して日本語変換すると、「日本語を入力する入力する」とTextFieldに入力される。

# 発生する条件
- macOS
- IMEのライブ変換を無効にしている
- 日本語の変換対象が２箇所以上の文字列を一度に確定する場合
  - 例えば、上記の「日本語を入力する」の入力を「日本語を」と「入力する」に分けた場合、本現象は再現しない

# Flutterのissue
本件は、すでにFlutterに[issue](https://github.com/flutter/flutter/issues/149379)が登録されているが、対応する予定はなさそう。

# 回避策
公式の対応が期待できないので、以下のようなカスタムTextFieldを作成して、本件を回避する
```dart
// Flutter imports:
import 'package:flutter/material.dart';

// Package imports:
import 'package:flutter/material.dart';

class MyTextField extends StatefulWidget {
  const MyTextField({super.key});

  @override
  _MyTextFieldState createState() => _MyTextFieldState();
}

class _MyTextFieldState extends State<MyTextField> {
  String? _current;
  final TextEditingController _controller = TextEditingController();

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: _controller,
      onChanged: (value) {
        // 前回の入力値との末尾の差分を取り、末尾が繰り返されていれば、前回の入力を維持する
        if (_current != null && _current!.length < value.length) {
          final suffix = value.substring(_current!.length);
          if (suffix.length > 1 && value == "$_current$suffix") {
            _controller.text = _current!;
            return;
          }
        }
        _current = value;
      },
    );
  }
}
```

# おわりに
あくまで回避策としての暫定的な実装のため、もっと良い対応方法があれば教えていただければ幸いです。
Jetpack GlanceをActivity上に表示する

RemoteViewsはViewに変換し、Activity上に表示することができます。

https://qiita.com/ryo_mm2d/items/34fe4cf13cee3a5cb209

Jetpack Glanceの実体はComposeの構文を使ってRemoteViewsを作成する仕組みなので、同様にActivity上に表示することができます。

適当にGlanceAppWidgetを実装してみます。

```kotlin
class MyGlanceWidget : GlanceAppWidget() {
    override suspend fun provideGlance(context: Context, id: GlanceId) {
        provideContent {
            Box(
                modifier = GlanceModifier
                    .fillMaxSize()
                    .padding(24.dp)
                    .background(Color(0xFF0000FF))
                    .cornerRadius(16.dp),
                contentAlignment = Alignment.Center
            ) {
                Text(
                    modifier = GlanceModifier
                        .padding(16.dp)
                        .background(Color(0xFFFF0000))
                        .cornerRadius(16.dp),
                    text = "Hello World"
                )
            }
        }
    }
}
```

ウィジェットとして表示すると以下のようになります。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/e4821a50-1e0e-797f-d1a2-66855007f75d.png)

`GlanceAppWidget`のロジックを通してRemoteViewsを作成するには、拡張関数 [compose](https://developer.android.com/reference/kotlin/androidx/glance/appwidget/package-summary#(androidx.glance.appwidget.GlanceAppWidget).compose(android.content.Context,androidx.glance.GlanceId,android.os.Bundle,androidx.compose.ui.unit.DpSize,kotlin.Any))を使います。

RemoteViewsを作ることができたら、あとはRemoteViewsを表示する場合と同じです。

```kotlin
lifecycleScope.launch {
    val views = MyGlanceWidget().compose(this@MainActivity)
    val view = views.apply(applicationContext, binding.container)
    binding.container.addView(view)
}
```

Activity上にウィジェットと同じレイアウトが表示されました。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/6491cb2b-5943-4bba-14cf-4bd9a9ceb48d.png)

以上です。
Roo-Cline: AIが導く次世代の開発エクスペリエンス

## 概要
Roo-Clineは、人気の高いClineをベースに開発された革新的な自律型コーディングアシスタントです。Claude 3.5 Sonnetの強力なエージェント機能を活用し、コードの作成から編集、テスト、デバッグまでを包括的にサポートします。従来のAIコーディング支援ツールとは一線を画し、より深い文脈理解と自律的な問題解決能力を備えています。

<blockquote class="twitter-tweet" data-media-max-width="800"><p lang="ja" dir="ltr">roo-clineでMCPサーバーをフルオートで作ってみる②<br>開発用にgithubのMCPをクローンしてきて、そこからの設定をお願いしたら普通にやってくれた。。。ホントにMCP系はトンデモナイな。。。 <a href="https://t.co/usIFrSO9jA">https://t.co/usIFrSO9jA</a> <a href="https://t.co/HBVUWtLGeM">pic.twitter.com/HBVUWtLGeM</a></p>&mdash; Maki@Sunwood AI Labs. (@hAru_mAki_ch) <a href="https://twitter.com/hAru_mAki_ch/status/1868161208593084919?ref_src=twsrc%5Etfw">December 15, 2024</a></blockquote> 

## 主要機能

### 1. 強化された自動化機能
- **コマンド自動承認**: ターミナルコマンドの実行を自動的に承認
- **ファイル操作の自動化**: ファイルの作成・編集を自動的に処理
- **ブラウザ操作の自動化**: Webアプリケーションのテストや動作確認を自動実行
- **MCPツールの自動承認**: Model Context Protocolツールの承認プロセスを効率化

### 2. プロジェクト管理の柔軟性
- **.clinerules対応**: プロジェクトごとにカスタム指示を設定可能
- **既存Clineとの共存**: 従来のClineと並行して使用可能
- **ファイル差分管理**: 変更履歴の追跡と管理が容易

### 3. 開発支援機能
- **自動ユニットテスト生成**: テストケースの自動作成と実行
- **インテリジェントな編集**: 
  - コードの文脈を理解した適切な修正提案
  - 差分表示による変更管理
  - 切り捨てられた全体ファイル編集のスマートなハンドリング

### 4. UI/UX機能
- **サウンド通知**: 重要なイベントを音で通知
- **プロンプト管理**: 
  - 履歴画面からのプロンプトコピー機能
  - 過去のプロンプトの再利用が容易
- **画像サポート**: チャットへの画像ドラッグ＆ドロップに対応

### 5. 最新技術への対応
- **先進的なAIモデル対応**: 
  - Gemini最新モデル（gemini-exp-1206、gemini-2.0-flash-exp）
  - OpenRouter圧縮機能による効率的な処理
- **ブラウザ連携**: 
  - ヘッドレスブラウザによる自動テスト
  - スクリーンショットの自動取得
  - コンソールログの監視

## 実践的な使用例

### 1. Webアプリケーション開発
```plaintext
- モックアップから実装までの自動化
- UIバグの自動検出と修正
- レスポンシブデザインの検証
```

### 2. デバッグ支援
```plaintext
- エラーログの解析と問題箇所の特定
- 修正案の提示と実装
- 修正後の自動テスト実行
```

### 3. コード最適化
```plaintext
- パフォーマンス改善箇所の検出
- リファクタリング提案
- ベストプラクティスの適用
```

## MCPツール拡張機能

Roo-Clineは、Model Context Protocol（MCP）を活用して機能を拡張できます：

- **カスタムツールの作成**: タスクに特化したツールを自動生成
- **Jira連携**: チケット情報の取得と管理
- **AWS管理**: EC2インスタンスの監視と制御
- **障害監視**: PagerDutyインシデントの取得と対応

## コンテキスト管理

### 効率的な情報収集
- **@url**: ドキュメントURLからの情報取得と変換
- **@problems**: ワークスペースのエラーと警告の収集
- **@file**: 個別ファイルの内容取得
- **@folder**: フォルダ単位での一括取得

## 免責事項

Roo Veterinary, Inc.は、Roo-Clineおよび関連ツールについて、明示的または黙示的な保証を一切提供しません。利用に関連するすべてのリスク（知的財産権の侵害、サイバー脆弱性、バイアス、不正確性、エラー、欠陥、ウイルス、ダウンタイム、財産の損失・損害、人身傷害を含むがこれらに限定されない）は、ユーザーが負担するものとします。

## コミュニティと貢献

- **[GitHub Issues](https://github.com/RooVetGit/Roo-Cline/issues)**: バグ報告や機能改善の提案
- **[機能リクエストボード](https://github.com/cline/cline/discussions/)**: 新機能のアイデア共有
- **[Discord](https://discord.gg/cline)**: 開発者コミュニティへの参加

## 最新情報の入手

- **[GitHub Releases](https://github.com/RooVetGit/Roo-Cline/releases)**: 最新版のリリース情報
- **[CHANGELOG.md](Roo-Cline/CHANGELOG.md)**: 詳細な変更履歴

Roo-Clineは、開発者の生産性を飛躍的に向上させる強力なツールとして、現代のソフトウェア開発に革新をもたらします。人間の創造性とAIの処理能力を組み合わせることで、より効率的で質の高い開発プロセスを実現します。


<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
[備忘録]　Youtubeを見ながらUnityの勉強　6日目

# はじめに
　こんにちは，Umamusume22です。最近、業務でUnityを使っているのですがUnityが分からないので自主的に勉強を始めました。とりあえず、Youtubeを見ながらUnityの勉強を行います。学んだことはここの記事にアウトプットしていきます。
 今日は以下の動画を見てUnityの勉強を行いました

https://youtu.be/7-xHtYfMilk?si=j9W4XyS61_Iw7Ul0

 
 # 備忘録
 - 作成したScriptの変数の値をInspectorから修正する場合は一度Game画面を停止させてから修正を行う
 - 物体をHirerchyウィンドウから追加する場合はコードを実行していない時に行う
 - classに同じ名前を付けた場合はエラーが出力される
 - ファイル名とスクリプト名が同じでなければアタッチが出来ない
 

# 実装したソースコード (オブジェクトが指定位置まで達したらオブジェクトが折り返す)
```Move.cs
using UnityEngine;

public class Move : MonoBehaviour
{

    public float speed;  // 変数名はInspectorから手動で設定
    public int returnPoint;

    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        transform.Translate(Vector3.forward*speed);

        if (transform.position.z >=returnPoint){

            speed = -speed;

        }
    }
}


```

# 実装したソースコード (オブジェクトが指定位置まで達したらオブジェクトが消滅)
```Move1.cs
using UnityEngine;

public class Move1 : MonoBehaviour
{

    public float speed;  // 変数名はInspectorから手動で設定
    public int destroyPoint;

    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        transform.Translate(Vector3.forward*speed);

        if (transform.position.z >=destroyPoint){

            //このゲームオブジェクトを消滅させる　アタッチされているオブジェクトを消滅
            Destroy(gameObject);

        }
    }
}
```


# 最後に
　勉強した内容を備忘録にしました。後、ソースコードも記載しました

 

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

※ウマ娘の声をフーリエ変換した記事や水栓の開閉判定をLineに通知する記事も書いています．suzuが私です．興味がある方はぜひご覧ください！
https://vigne-cla.com/31-1/#toc5

※noteもやっています．
https://note.com/madoka235/n/nbba2153326e1

ぜひフォローよろしくお願いします!
【UE5】TOptionalがUHTでサポートされた


Unreal Engine5.4からTOptionalがUnrealHeaderToolでサポートされました！！  
ただ、UnrealHeaderToolでサポートされただけで、Blueprint側で任意に型をOptionalに設定する事が現状できないので注意してください！！

# 公式ドキュメント

[ReleaseNote Unreal Engine5.4](https://dev.epicgames.com/documentation/ja-jp/unreal-engine/unreal-engine-5.4-release-notes?application_version=5.4)

> UHT に TOptional 型のサポートを追加しました。

# 使って見た例


```cpp:インクルードに必要なヘッダーファイル
#include "Misc/Optional.h"
```

```cpp:変数定義部分
	UPROPERTY(EditAnywhere, Category = "Test")
	TOptional<int32> Value;
```

C++側でメンバー変数でTOptional型がサポートされました。
上記のような表記をする事でToptionalを使って詳細タブで設定を行う事ができます。

## 値が未設定の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66029/49ea2644-ebdc-eb7e-5f63-34f82c2082dd.png)

## 値が設定済みの場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66029/4957dc1b-5f59-77ee-c334-094f6f890abe.png)


現状はBlueprint側に専用ノードは容易されていなさそうです。
今後に期待しましょう！


# リフレクションで使うには！

```cpp:ヘッダーファイル

UCLASS(Blueprintable)
class AMyActor : public AActor
{
	GENERATED_BODY()

public:

	virtual void BeginPlay() override;

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Test")
	TOptional<FString> OptionalValue;
};

```

> Engine\Source\Runtime\CoreUObject\Public\UObject\PropertyOptional.h

```cpp:Optionalにアクセスした例
if (OptionalValue.IsSet())
{
	const FString& ValueRef = OptionalValue.GetValue();
	UE_LOG(LogTemp, Log, TEXT("%s"), *ValueRef);
}
OptionalValue.Reset();
```


```cpp:リフレクションを使ってアクセスした例
auto* OptionalProperty = FindFProperty<FOptionalProperty>(GetClass(), TEXT("OptionalValue"));
void* OptionalData = OptionalProperty->ContainerPtrToValuePtr<void>(this);

if (OptionalProperty->IsSet(OptionalData))
{
	FStrProperty* ValueProp = CastField<FStrProperty>(OptionalProperty->GetValueProperty());
	const FString* ValuePtr = ValueProp->ContainerPtrToValuePtr<FString>(OptionalData);

	if (ValuePtr)
	{
		const FString& ValueRef = *ValuePtr;
		UE_LOG(LogTemp, Log, TEXT("%s"), *ValueRef);
	}
}

OptionalProperty->MarkUnset(Data);
```
JavaでAPI叩いた時のserialVersionUIDについてと警告の消し方


# serialVersionUIDって必要なの？
今回調べた中で、一番分かりやすい言葉をお借りすると
>インターフェースjava.io.Serializableを実装した場合に必要。
親クラスが実装していた場合にも必要になる。
シリアライズなクラスのバージョンを管理するためにある。

とのことでした。

また、設定したserialVersionUIDを変更すると例外が発生するみたいです。

# 警告を消す方法１
```
@SuppressWarnings("serial")
```
このアノテーションをSerializableをインターフェースとして実装したクラスの上に追記する

# 警告を消す方法２
```
@Serial
```
このアノテーションをserialVersionUIDを変数として定義した際に追記する


# 参考

https://docs.oracle.com/javase/jp/15/docs/api/java.base/java/io/Serial.html



https://blog.retheviper.com/posts/java-enter-to-17/#serial-14

https://java-study.blog.jp/archives/1021151333.html
nestjs dockerで立ち上げたpostgresにアクセスできなかった

以下は、NestJSアプリケーションとDockerコンテナ内のPostgreSQLデータベースが接続できなかった問題について解決策をまとめた記事です。

---

## タイトル: NestJS Dockerで立ち上げたPostgreSQLにアクセスできなかった

### 問題の背景

NestJSで開発したアプリケーションが、ローカルのPostgreSQLデータベースに接続できない問題が発生しました。Docker上に立ち上げたPostgreSQLコンテナと通信できなかったことが原因です。この問題を解決するために、環境設定の見直しと正しい接続設定を行いました。

### 原因

問題の主な原因は以下の点です：

- **データベース名、ユーザー名、パスワードの不一致**：設定ファイルと実際にDockerコンテナで設定した値が一致していませんでした。
- **ポート番号の不一致**：Dockerコンテナのポートと、NestJSアプリケーションが使用するポートが異なっていました。

### 解決策

1. **.envファイルの確認**：まず、NestJSアプリケーションで使用するデータベースの接続情報を正しく`.env`ファイルで設定しました。

2. **Docker Composeファイルの設定**：Docker Composeで立ち上げたPostgreSQLコンテナの環境変数を確認し、データベース名、ユーザー名、パスワードを正しく設定しました。また、コンテナのポートとローカルのポートを一致させました。

以下が最終的に問題なく動作する設定です。

### 1. NestJSアプリケーションの設定

まず、NestJSで使用する`typeormConfig`を以下のように設定しました：

```typescript
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import { config } from 'dotenv';
import { join } from 'path';
import { TaskEntity } from 'src/task';

config({ path: '.env' });

export const typeormConfig: TypeOrmModuleOptions = {
  type: 'postgres',
  host: 'localhost',
  port: 5432,
  database: 'demo',
  username: 'root',
  password: 'root',
  schema: 'public',
  entities: [TaskEntity],
  synchronize: true,
  logging: true,
};
```

- **`host`**：`localhost`に設定。Dockerコンテナ内のPostgreSQLに接続するためには、ホストを`localhost`とする必要があります。
- **`port`**：コンテナの5432ポートを使用（`5432:5432`でマッピングしているため）。
- **`database`、`username`、`password`**：これらの設定は、Docker Composeファイルで設定したものと一致させる必要があります。

### 2. Docker Composeファイルの設定

次に、`docker-compose.yml`を以下のように設定しました：

```yaml
version: '3.9'

services:
  db:
    image: postgres:15
    container_name: postgres-db
    ports:
      - '5432:5432'
    environment:
      POSTGRES_PASSWORD: root
      POSTGRES_USER: root
      POSTGRES_DB: demo
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
```

- **`POSTGRES_USER`**、**`POSTGRES_PASSWORD`**、**`POSTGRES_DB`**：これらは、NestJSアプリケーションで設定した接続情報（`root`、`root`、`demo`）と一致させる必要があります。
- **ポートの設定**：`5432:5432`とすることで、ホストの5432ポートをコンテナにマッピングし、ローカルのPostgreSQLインスタンスとして接続できるようにしました。

### 3. 実行

これらの設定を反映させた後、以下の手順でDockerコンテナを再起動しました。

1. Docker Composeでコンテナをビルド・立ち上げます。
   ```bash
   docker-compose up --build
   ```
2. NestJSアプリケーションを起動します。
   ```bash
   npm run start
   ```

### 結果

これで、NestJSアプリケーションがDockerコンテナ内のPostgreSQLデータベースに正しく接続できるようになり、エラーなく動作しました。

### まとめ

NestJSアプリケーションがDocker上のPostgreSQLに接続できなかった原因は、データベース設定の不一致とポート番号の不一致にありました。設定を見直すことで、無事接続できるようになりました。このように、Docker環境でアプリケーションを動かす際は、コンテナとアプリケーションの設定が一致しているかを再確認することが重要です。

--- 

これで、NestJSとDockerを使ったPostgreSQLの接続問題が解決できました。
画像からざっくり断面二次モーメントを計算する

任意断面の二次モーメントを求めたくなることがある
CADや外部ツールを使わずにサクッとやりたいので、画像から求めてみた

## 使用ツール
* Python 3.12.4 (Pillow, NumPy)
* 任意のお絵描きツール
## お絵描き
計算する断面の画像をつくる
今回はGoogleスライドで H-100×100×6×8(r=8)の断面を描いた

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917871/d3455203-c74e-1659-5523-8f4e63d7c661.png" width=60%>

jpgでダウンロードしておく

## 画像の読み込み
グレースケール画像をnumpy配列で読み込み、適当なしきい値でブール配列にする
```python:moment.py
from PIL import Image
import numpy as np

image = Image.open("H-100x100x6x8.jpg").convert('L')
image_array = np.array(image)
image_bool = image_array < 128
```
## 準備
* 図心軸
簡単のために画像の中心とする
```python:moment.py
axis = image_array.shape[0] / 2
```
* 1ピクセル当たりの長さ
1ピクセルが何ミリになるのかをセット
今回は標準的な 1px=0.26458mm
ピクセル当たりの面積も出しておく
```python:moment.py
millimeter_per_pixel = 0.26458
area_of_pixel = millimeter_per_pixel**2
```
* 断面二次モーメント
英語で断面二次モーメントは moment of inertia of area というらしい
初期値0をセット
```python:moment.py
moment_inertia_area = 0
```

## ループで計算
ピクセルごとに断面が存在(True)すれば図心軸からの距離を求め、面積と掛けて moment_inertia_area に足していく
```python:moment.py
for y in range(len(image_bool)):
    for x in range(len(image_bool[y])):
        if image_bool[y][x]:
            dist_y = abs(axis - y) * millimeter_per_pixel
            moment_inertia_area += dist_y**2 * area_of_pixel
```
## 結果
```
>python moment.py
3712979.0451532584
```
解析値は 3780000mm<sup>4</sup> 程度になるので、2%弱の誤差がある
他の断面でも解析値より 1～2%小さくなった

とりあえずざっくりは使えるが、どこかで誤差が出ているのか気になる
numpyっぽい書き方にもしたいが分からず

## スクリプト全体

```python
from PIL import Image
import numpy as np

image = Image.open("H-100x100x6x8.jpg").convert('L')

image_array = np.array(image)
image_bool = image_array < 128

axis = image_array.shape[0] / 2
millimeter_per_pixel = 0.26458
area_of_pixel = millimeter_per_pixel**2

moment_inertia_area = 0

for y in range(len(image_bool)):
    for x in range(len(image_bool[y])):
        if image_bool[y][x]:
            dist_y = abs(axis - y) * millimeter_per_pixel
            moment_inertia_area += dist_y**2 * area_of_pixel

print(moment_inertia_area)
```
MUIのSelectコンポーネントで青色の枠線を消す方法

# はじめに
今回は、MUIのSelectコンポーネントで青色の枠線を消す方法を紹介します。

消すために割と時間を使ってしまったので、被害者がこれ以上出ないように...

![スクリーンショット 2024-12-15 20.58.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/3c5603be-f4f6-4c91-8bbc-cf912be748c2.png)


## 解決法
sxに以下の記述をする
```jsx
<Select
  sx={{
    // 青い枠線を消す
    '& > fieldset': {
      border: 'none !important',
    },
  }}
/>
```
fieldsetで制御されていることに気づくのが時間かかりました...

## ちなみに
fieldsetというのは、`label`タグのようにフォームを管理するタグだそうです。

https://developer.mozilla.org/ja/docs/Web/HTML/Element/fieldset

`label`と違う点は、複数フォームの管理に使われることです。

```html
<form>
  <fieldset>
    <legend>好きな猫を選んでください🐈</legend>

    <input type="radio" id="kraken" name="cats" value="S" />
    <label for="Scottish Fold">スコティッシュフォールド</label><br />

    <input type="radio" id="sasquatch" name="cats" value="A" />
    <label for="american shorthair">アメリカンショートヘア</label><br />

    <input type="radio" id="mothman" name="cats" value="M" />
    <label for="munchkin">マンチカン</label>
  </fieldset>
</form>
```
MUIのSelectは、このタグを利用してフォームの管理をしているということですね！

## 参考

https://stackoverflow.com/questions/61344448/remove-blue-outline-from-select-box-react-material-ui

https://developer.mozilla.org/ja/docs/Web/HTML/Element/fieldset
Next.js15のVSCodeでのデバッグ方法（Windows環境）

Next.js 15を試してみたところデバッグ設定がそれまでと変わっていて上手くいきませんでした。
基本は公式サイトのドキュメントを見れば良いはずなのですが、Windows環境だとそのままでは上手くいかなかったので解決方法を書いておきます。

公式サイト
https://nextjs.org/docs/app/building-your-application/configuring/debugging

まず公式サイトでもページの下部に書いてあるように、`cross-env` をインストールします。

```bash
 npm install --save-dev cross-env
```

そして、`package.json` の scripts -> dev 設定を次のように上書きします。
```json
    "dev": "cross-env NODE_OPTIONS='--inspect' next dev",
```

`launch.json` は次の通りです。
```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Next.js: フルスタックデバッグ",
      "type": "node",
      "request": "launch",
      "program": "${workspaceFolder}/node_modules/next/dist/bin/next",
      "runtimeArgs": ["--inspect"],
      "skipFiles": ["<node_internals>/**"],
      "serverReadyAction": {
        "action": "debugWithChrome",
        "killOnServerStop": true,
        "pattern": "- Local:.+(https?://.+)",
        "uriFormat": "%s",
        "webRoot": "${workspaceFolder}"
      }
    },
    {
      "name": "Next.js: サーバサイド用のデバッグ",
      "type": "node-terminal",
      "request": "launch",
      "command": "npm run dev"
    },
    {
      "name": "Next.js: クライアントサイド用のデバッグ",
      "type": "chrome",
      "request": "launch",
      "url": "http://localhost:3000"
    },
    {
      "name": "Next.js: クライアントサイド用のデバッグ (Firefox)",
      "type": "firefox",
      "request": "launch",
      "url": "http://localhost:3000",
      "reAttach": true,
      "firefoxExecutable": "C:\\Program Files\\Mozilla Firefox\\firefox.exe",
      "pathMappings": [
        {
          "url": "webpack://_N_E",
          "path": "${workspaceFolder}"
        }
      ]
    }
  ]
}

```
公式サイトとの違いは、フルスタックデバッグの `program`の設定です。
`.bin/next` はUNIX系OS (Linux, macOS) 用の設定なのでWindowsでは上手く動作しません。

```json
"program": "${workspaceFolder}/node_modules/next/dist/bin/next",
```

もう一つの違いはクライアントサイドのFirefox の設定です。`firefoxExecutable` を追加してあります。

```json
"firefoxExecutable": "C:\\Program Files\\Mozilla Firefox\\firefox.exe",
```
この設定は無くても、FireFoxが通常インストールで、この場所 `Program Files\Mozilla Firefox`にある場合は上手くいきます。
しかし、FireFox.exeがこの場所にないパターン、私の例では Microsoft Store からインストールした時は`firefoxExecutable` で指定する必要があります。

```json:Microsoft Storeからインストールした時のfirefox.exeのパス指定例
 "firefoxExecutable": "C:\\Program Files\\WindowsApps\\Mozilla.Firefox_133.0.3.0_x64__n80bbvh6b1yt2\\VFS\\ProgramFiles\\Firefox Package Root\\firefox.exe",
```
そのため、あえて上記のように設定を追加してあります。

**Q. Storeからインストールした場合、どこのパスで実行されているか分かりません**

**A. タスクマネージャーからプロセスを選択して右クリックで「ファイルの場所を開く」で分かります。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/694c7a97-15d8-ba4d-cdb0-054b8fc09f3c.png)

あとVSCodeの拡張機能に Debugger for Firefoxをインストールする必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/95ec03ad-6db7-75b7-1f57-676c580924ad.png)

以上、ご参考になれば幸いです。
最悪のChrome拡張機能を作ってみた【三半規管ぶっこわし】

# はじめに
今回は、「最悪のChrome拡張機能を作ってみた」と題して、作成したChrome拡張機能の紹介とコードの解説をしていきます。

https://chromewebstore.google.com/detail/drunk/ikinjkmhgbppafhdjgodobebohkdpgbn?hl=ja&utm_source=ext_sidebar

## どんなものか(閲覧注意)

https://x.com/hikagami210/status/1868252784157716667

画面の要素を揺らしまくります。それだけ。

どんな人も数十秒で酔わせる強い決意をもって作りました🫡

## どうやってやっているのか
拡張機能のアイコンをクリックしたとき、ページのBlock要素を全部とってきて、`Animate.css`を使用して揺らしています。

### manifest.json

```json
{
  "manifest_version": 3,
  "name": "drunk",
  "version": "1.0",
  "description": "絶対に酔わせる拡張機能。体調の悪い方、酔いやすい方はご注意ください",
  "permissions": ["activeTab", "scripting"],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_title": "アニメーション開始"
  },
  "icons": {
    "16": "icon.png",
    "32": "icon.png",
    "48": "icon.png",
    "128": "icon.png"
  }
}

```
`permissions`には権限を設定しています。
どちらもスクリプトを流し込むための権限です。

アイコンは色々なサイズが必要かと思いきや、128px*128pxの画像１つで審査は通ります(豆知識)

### background.js

```js
chrome.action.onClicked.addListener((tab) => {
  chrome.scripting.executeScript({
    target: { tabId: tab.id },
    files: ["content.js"],
  });
});
```
`chrome.action.onClicked.addListener`は拡張機能アイコンのクリックを監視するものです。
`chrome.scripting.executeScript`で、アイコンクリック時に`content.js`を流し込むことができます。

### content.js
```js
// Animate.cssを使えるようにlinkタグを挿入
const link = document.createElement("link");
link.rel = "stylesheet";
link.href =
  "https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css";
document.head.appendChild(link);

// body、main、header以外のブロック要素を選択
const elements = document.querySelectorAll("*:not(body):not(main):not(header)");

// Animate.cssの速度を変化させるクラスをランダムに取得
function getRandomSpeedClass() {
  const speedClasses = ["animate__slow", "animate__fast"];
  const randomIndex = Math.floor(Math.random() * speedClasses.length);
  return speedClasses[randomIndex];
}

// 各ブロック要素にAnimate.cssのクラスを追加
elements.forEach((element) => {
  if (window.getComputedStyle(element).display === "block") {
    element.classList.add(
      "animate__animated",
      "animate__shakeX",
      "animate__infinite",
      getRandomSpeedClass()
    );
  }
});

```

割とみたまんまのコードです。
特に難しいことはしていませんが、割とキレイにまとめられたんではないかと思います。

Animate.cssについては以下の記事も併せてご覧いただくといいかと思います！

https://qiita.com/hikagami/items/f63f249e2f16ac3a65b9

## さいごに
お読みいただきありがとうございました！
ぜひこの拡張機能を使用して、三半規管をぶっこわしてみてください！
なぜなぜ分析を助けるGPTを作ってみた話

この記事は[ChatGPT Advent Calendar 2024](https://qiita.com/advent-calendar/2024/chatgpt)の16日目の記事です。

## はじめに
最近、GPTsを試している中で非常に興味深いGPTを見つけました。それは、なぜなぜ分析を誘導してくれるGPTです。この詳細については、[こちらの記事](https://note.com/hima2b4/n/n97a525ff1adb)で紹介されています。

このGPTsは、ユーザーが抱える課題について、なぜなぜ分析を進めてくれるというユニークなものでした。さらに感動したのは、なぜなぜ分析を進めていく途中で、対策案を提示するように振る舞いが切り替わる点です。この「スイッチング」がどのように実現されているのか、非常に興味をそそられました。そして、自分でも同じような仕組みを試してみたくなったのです。

## 自分だけのGPTを作成する方法
GPTsには「指示」を書き込むセクションがあり、ここにやってほしいことを書くだけで、自分専用のGPTを作成できます。これは、いわゆるシステムプロンプトのようなものです。

今回の作成にあたり、@hima2b4さんからヒントをいただき、自分なりにプロンプトを書いてみました。それが以下の内容です。

```
あなたは、Five whysに関するコンサルタントです。
あなたの目標は、私が抱えている課題に合わせて、課題の深堀をし、課題の解決策を探っていくことです。

次のプロセスに従ってください。

1. まず最初に、抱えている課題について私に確認してください。
私が質問の答えを提供するので、次のステップを経て、継続的な反復を通じて改善してください。

2. 私の入力に基づいて、次のように応答してください。
・確認（課題の内容について反復して確認してください。私に共感するような文章にしてください。）
・N回目の深堀り質問をしますと言います。
・課題の深堀質問（課題の内容を深堀するために、なぜその課題が生じているのか質問をしてくだい。このとき、あなたからなぜその課題が生じているのかの理由候補を水平思考で5つ挙げてください。）

3. 2のプロセスは、私があなたに追加情報を提供し、あなたが課題の深堀を「5回」まで反復して続けます。「5回」まで反復したら、必ず次のステップ4に移ってください。

4. 3の反復プロセスが終了したら5のプロセスに移ってください。

5. 深堀した課題に対して対策を水平思考で候補を5つ挙げてください（私は候補外の答えをするかもしれません）。

6. 5のプロセスは、私があなたに追加情報を提供し、あなたが課題の深堀を「私から終了と言うまで反復して繰り返してください」。

7. 6のプロセスが終了したら、今まで深堀した課題点と対策案を要約してまとめて出力してください。

※全体的に次の事項を遵守してください。
・私が出力を読みやすいように、適切に改行してください。
・私は課題の深堀や対策の深堀をしていき、疲れていきます。そこであなたは、私を励ますように優しい文章にすることを心がけてください。
"""
```

このプロンプトを書き込むことで、なぜなぜ分析に特化したGPTを構築できるようになります。

## 実際に困りごとを入力してみた

課題の掘り下げはこんな感じ。掘り下げ候補も出してくれるので、自分で考えなくても番号を指定するだけでも深堀できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211712/89c838ae-780d-2e26-15d0-35bbca8ab938.png)

なぜなぜを5回ほど繰り返すと、対策案の立案に移ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211712/295ec068-baa2-4bc7-6232-aaefb7d68c7f.png)

なぜなぜ分析から対策案の立案までを行うGPTが完成！
プロンプトを使って作成したこのGPTを試したところ、課題の深堀を行いながら、対策案を提示してくれる素晴らしいGPTを作ることができました。[こちらに公開](https://chatgpt.com/g/g-R4BCsnS4k-five-whys)しています。

さらに、gpt4-o-miniを使用したAPIを活用して、Streamlitでアプリケーション化することにも成功しました。このアプリケーションの[ソースコード](https://github.com/ground0state/five_whys)も公開していますので、興味のある方はぜひ参考にしてみてください。

## 最後に
私自身、今回の体験を通じて、GPTsを活用する面白さを改めて実感しました。特にプロンプトの設計次第で、様々なタスクに特化したGPTを作成できる可能性は無限大です。

もし皆さんも「こんな面白いGPTを作った」「こんな興味深いGPTを見つけた」という体験があれば、ぜひ教えてください！

## 参考文献

なぜなぜ分析のGPTs開発者様
https://note.com/hima2b4/n/n97a525ff1adb

streamlitのアプリのコードはこちらを参考にしました
https://tech.route06.co.jp/entry/2024/01/04/143058
TCPスライディング・ウインドウ

### バッファに空きがあると送信できる
>TCPのウインドウ管理は直接、確認通知に束縛されるものではない。例えば、受信者が4096バイトのバッファを持っていると仮定しよう。送信者が2048バイトのセグメントを送り、それが、正常に受信されると受信者はそのセグメントの確認通知をする。受信者にはこのとき2048バイトのバッファ・スペースが存在するので（アプリケーションがバッファからデータを取り込んでくれないと空きが増えない)、次の受信することを期待するバイトの順序番号2048とウインドウ幅として2048バイトを通知するだろう。

### ウインドウ通知が０になると送信できない
>送信者がさらに2048バイトを送り、それが、確認通知され、ウインドウ通知が０になったとしよう。送信者は受信ホスト上のアプリケーション・プロセスがバッファからデータを取り込むまで停止していなければならない。空きがでると、TCPは０でないウインドウを通知できる。

### 遠隔マシン上のプロセスの削除、受信者に順序番号とウインドウ幅を聞く場合のみ０でも送信できる
>ウインドウが0の時送信者はセグメントを送っていけない。しかし、二つの例外がある。一つは緊急データで、ユーザーが遠隔マシン上のプロセスを消すなどの目的に使われる。もう一つは、受信者に順序番号とウインドウ幅をもう一度通知させるための1バイトのセグメントである。このパケットをウインドウ・プローブ(window probe)と呼ぶ。TCP標準はこのオプションを明示的に提供している。ウインドウ通知が毎回ロスしてしまうようなデッドロックを回避するためである。

### 応答を遅らせてまとめてまとめて確認通知する
>1文字が送信TCPエンティティに到着し、TCPが21バイトのTCPセグメントを生成し、IPがそれを41バイトのIPデータグラムとして送ってしまう。

>確認通知とウインドウ更新を５００ミリ秒遅らせて、なるべく複数のデータを一つのパケットで送ろうとしている。これを遅延ACK(delayed acknowledgement:遅延確認応答)と呼ぶ。

### Nagleのアルゴリズムでバッファする
>送信者がたった1バイトのデータを41バイトのパケットで送ってしまうという非効率さに変わりはない。

>送信者に１バイトずつデータがやって来る時、とにかく最初のバイトを送信し、それが、確認通知されるまで、やってくるデータ全てをバッファするというものである。確認通知されタラ、それまでバッファされたそれまでバッファされた文字を一つのTCPセグメントで送信し、再び送信したデータ全てが確認通知されるまで、バッファリングを開始する。

https://bookplus.nikkei.com/atcl/catalog/23/03/16/00728/
【TryHackMe】Search Skills：Walkthrough

# 概要

TryHackMe「Search Skills」のWalkthroughです。

https://tryhackme.com/r/room/searchskills

# Task2

## **Q1**.*What do you call a cryptographic method or product considered bogus or fraudulent?*

**Hint**.*Use your favourite search engine.*

https://en.wikipedia.org/wiki/Snake_oil_(cryptography)

**A**.**Snake oil**

## **Q2**.*What is the name of the command replacing netstat in Linux systems?*

**Hint**.*Use your preferred search engine.*

**A**.**ss**

# Task3

## **Q1**.*How would you limit your Google search to PDF files containing the terms cyber warfare report?*

**Hint**.*Express your query as the search filter followed by the search terms.*

`filetype:`で拡張子をフィルタリングできます。

**A**.**filetype:pdf cyber warfare report**

## **Q2**.*What phrase does the Linux command ss stand for?*

**Hint**.*Use your favourite search engine.*

https://ysatoautonomous.github.io/jm-draft/man2html/iproute2/iproute2-5.1.0/draft/man8/ss.8.html

**A**.**socket statistics**

# Task4

## **Q1**.*What is the top country with lighttpd servers?*

**Hint**.*Use shodan.io*

`shodan`で`lighttpd`を検索します。

https://www.shodan.io/search?query=lighttpd

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3005822/99ddac1e-4b6b-bf44-95f6-5660e73f8fc0.png)

**A**.**United States**

## **Q2**.*What does BitDefenderFalx detect the file with the hash 2de70ca737c1f4602517c555ddd54165432cf231ffc0e21fb2e23b9dd14e7fb4 as?*

**hint**.*Use virustotal.com*

`virustotal`で該当のハッシュ値を検索します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3005822/4edb1455-7eda-9aa4-f8b0-1750210155a6.png)

https://www.virustotal.com/gui/file/2de70ca737c1f4602517c555ddd54165432cf231ffc0e21fb2e23b9dd14e7fb4

**A**.**Android.Riskware.Agent.LHH**

# Task5

## **Q1**.*What utility does CVE-2024-3094 refer to?*

`XZ Utils`に関する脆弱性です。

https://nvd.nist.gov/vuln/detail/cve-2024-3094

**A**.**xz**

# Task6

## **Q1**.*What does the Linux command cat stand for?*

**Hint**.*Check its manual page.*

`man cat`コマンドでマニュアルを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3005822/addd7a2c-2f10-c56f-8702-848e28956031.png)

**A**.**concatenate**

## **Q2**.*What is the netstat parameter in MS Windows that displays the executable associated with each active connection and listening port?*

`-b`オプションで確認できます。

https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/netstat

**A**.**-b**

# Task7

## **Q1**.*You are hired to evaluate the security of a particular company. What is a popular social media website you would use to learn about the technical background of one of their employees?*

**A**.**LinkedIn**

## **Q2**.*Continuing with the previous scenario, you are trying to find the answer to the secret question, “Which school did you go to as a child?”. What social media website would you consider checking to find the answer to such secret questions?*

**A**.**Facebook**
024 AI屋さんの　LLMで物体認識　GEMINI2.0


024 AI屋さんの　LLMで物体認識　GEMINI2.0


折角なので　大規模言語モデルの物体認識もお試しです。
若干　揺らぎが気になりますが
設定を調整すれば、もっと良くなりそうです。

作り方は簡単です。

　１、google AI studio
　２、ローカルで開発
　３、streamlitのdockerイメージ
　４、cloudrun　でデプロイ

動作確認くらいなら、１番で完成です。
４番も　streamlitなら既存のcloudrunのpagesに
アップロードするだけで　アプリのブログを使えます。

アプリのブログは、
結構　役に立ちます。

 
 


はい、あっという間に完成です。


![スクリーンショット 2024-12-15 18.26.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237930/af290871-466b-de57-35c3-5f668417af8e.png)

ソースコードも簡単です。
画像処理部は、全部これだけでやってくれます。
あとは、画像の入力、出力、表示を　webアプリで実装してあげます。
物体認識のハードルが、完全に消滅しています。


https://aistudio.google.com/app/prompts/new_chat

![スクリーンショット 2024-12-15 19.11.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237930/bf6ba139-70cc-be5c-d7aa-8f8dbd98b372.png)





下記も、gemini2.0で　物体認識してみました。

　yoloかよ。

でも、自動車向け完全自律自動運転のリアルタイム処理とは、スピードやサイズやコスト感が・・
そもそも、主たる用途が違うかとは思いますので
大規模言語モデルの物体認識は　どこで使おうか
考えちゃいますよね。




![スクリーンショット 2024-12-15 18.32.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237930/0c8adb62-6967-b6d2-cc63-54b3767c9f46.png)



クラウドwebapi前提の
屋内・対人向け自律二足歩行ロボット　くらいのイメジーですかね。
つまり、お話ししながら　歩き回る　人型ロボットです。
と言うことは、

　！！！　ボク野良右衛門　！！！
 
降臨です。
まさかの、私のための新機能ではありませんか。



目次

https://qiita.com/bono0/items/dc1d000c98af7e07c9a7



無事に　yoloみたいなこともできました。
おめでとうございます。



ー続くー
ログに出力されている処理時間を New Relic の NRQL で簡単に集計できた話

# TL;DR

New Relic Query Language (NRQL) の `capture()`, `numeric()`, `sum()` 関数を利用すると、New Relic Logs にある、ログメッセージ内に処理時間が含まれたログから、処理時間を簡単に合計できます。

# はじめに

New Relic で利用できる [NRQL (New Relic Query Language)](https://docs.newrelic.com/jp/docs/nrql/get-started/introduction-nrql-new-relics-query-language/) は超強力です。

頻繁に確認するようなデータは [Dashboard](https://docs.newrelic.com/jp/docs/query-your-data/explore-query-data/dashboards/introduction-dashboards/) にまとめておくとして、随時必要になったデータを探しに行くとき、UI から辿るよりも NRQL をサクッと書いた方が早かったりします。

そんなわけで、基本 Dashboard を見つつ NRQL を叩くというのが、筆者の New Relic の使い方になっています。
最近のアップデートで、[クエリビルダーがタブ機能に対応](https://qiita.com/MarthaS/items/71de539504175f21e6d0)したのには大歓喜しました🎉

さて、今回はその NRQL で感動的に便利なことが最近あったので共有したいと思います。

# やりたかったこと

ログに各処理の処理時間が出力されているシステムがありました。  
イメージとしてはこんな感じです。  
```plaintext:ログの例
2024-12-25T09:00:00+09:00 [INFO] Process "hoge" successfully completed. [123 ms]
2024-12-25T09:00:01+09:00 [INFO] Process "fuga" successfully completed. [456 ms]
```

このログをベースに、 **「処理が走っていた合計時間を取得したい」** というのが今回の目的になります。  
上記の例でいうと、`hoge` 123ミリ秒 + `fuga` 456ミリ秒 = **579ミリ秒** を取得したいという感じです。

素直にやろうとすると、ログ件数が多いだけでなく、ログファイルも複数サーバの複数ディレクトリに散らばっており、ファイル加工して云々……など気が遠くなるような作業です。

しかし、幸いなことにログは [New Relic Logs](https://docs.newrelic.com/jp/docs/logs/get-started/get-started-log-management/) に収集していたため、New Relic の NRQL で集計が可能でした。

# NRQL で簡単に実現できました
やりたいことを平たく言うと、 **ログのメッセージから処理時間の部分だけを抜き出して合計する** ということです。

例にはなりますが、以下のような NRQL でサクッと実現可能です。
```:NRQL
FROM Log
SELECT sum(numeric(capture(message, r'.+ successfully completed\. \[(?P<time>\d+) ms\]')))
WHERE logtype = 'example'
SINCE 30 minutes ago
```
`WHERE` 句や `SINCE` 句はあくまで例なので、適宜変更してください。

やっていることとしては、
- `capture()` 関数を使い、ログ内の処理時間部分のみをキャプチャ
- `numeric()` でキャプチャした文字列を数値に変換
- `sum()` で数値を合計

になります。

ポイントとなる `capture()` の使い方は、[リファレンス](https://docs.newrelic.com/jp/docs/nrql/nrql-syntax-clauses-functions/#func-capture)にも説明があるほか、Qiita の New Relic Organization で公開されている下記の記事もわかりやすいですね。

https://qiita.com/ktst79/items/56e49f71487928c5bca1

NRQL 上の注意点としては、
- 正規表現文字列の前には `r` プリフィックスが必要だった
- 正規表現のキャプチャグループには名前が必要(上記の例の `<time>` の部分)だった

といったところでしょうか。  
([RE2](https://github.com/google/re2/wiki/Syntax) 構文に慣れている方は迷わないのでしょうが、筆者はハマりかけました)

# おわりに

今回のシステムの場合、素直にやると、各サーバからのログファイル集めから始めなければならず、最低数時間はかかったと思います。

New Relic Logs と NRQL を利用したことで、(クエリの書き方を調べる時間を含め)数分で実現できました。

冒頭にも書いた通り NRQL は日常的に叩いているのですが、今回の件はかなり感動的で、  
改めて強力さを実感しました！
【初心者向け解説】VARモデルとは？具体例と数式で分かりやすく解説！

統計やデータ分析の世界では「VARモデル（Vector AutoRegressive Model）」という手法がよく使われます。この記事では、VARモデルを中学生にもわかるような具体例や数式を使いながら、丁寧に解説していきます！

---

## 1. VARモデルとは？

VARモデルは、**複数の変数（データ）の間にある関係性**を分析するためのモデルです。特に、ある変数が**過去の自分や他の変数にどんな影響を受けているか**を調べることができます。

たとえば次のような関係を考えます：

- 宿題をした時間（データA）が翌日のゲームの時間（データB）に影響する。
- ゲームの時間が、また翌日の宿題の時間に影響する。

VARモデルでは、こうした複数のデータの影響を数式で表して分析します。

---

## 2. 実生活の例で理解しよう

具体例を使って説明します。「宿題の時間」と「ゲームの時間」がどう影響し合うのかを考えてみましょう：

- $x_t\$：今日の宿題をやった時間
- $y_t\$：今日のゲームをやった時間

これらが過去の値（昨日の宿題やゲーム時間）から影響を受けているとします。

---

### 基本の数式

VARモデルでは、次のような数式を使います：

$\
x_t = a_1 x_{t-1} + a_2 y_{t-1} + u_{x,t}
\$

$\
y_t = b_1 x_{t-1} + b_2 y_{t-1} + u_{y,t}
\$

それぞれの要素の意味は以下の通りです：

- $x_t, y_t\$：今日の宿題時間とゲーム時間
- $x_{t-1}, y_{t-1}\$：昨日の宿題時間とゲーム時間
- $a_1, a_2, b_1, b_2\$：係数（どれくらい影響を与えるかを示す数字）
- $u_{x,t}, u_{y,t}\$：予測できない誤差（ランダムな要素）

---

## 3. 具体例で計算してみよう

仮に、昨日の宿題時間とゲーム時間が以下のようなデータだったとします：

| 時間 $\(t\)$ | 宿題 $\(x_t\)$ | ゲーム $\(y_t\)$ |
|:---:|:---:|:---:|
| 1 | 2 | 3 |
| 2 | 3 | 2 |
| 3 | 4 | 1 |

次に、具体的な係数を設定して、時間 $\(t = 3\)$ の宿題時間とゲーム時間を計算してみます。

### 宿題時間の計算

宿題時間の数式は以下の通りです：

$\
x_t = a_1 x_{t-1} + a_2 y_{t-1} + u_{x,t}
\$

係数 \(a_1 = 0.5\), \(a_2 = -0.2\) とすると：

$\
x_3 = 0.5 \cdot x_2 - 0.2 \cdot y_2 + u_{x,3}
\$

データを代入すると：

$\
x_3 = 0.5 \cdot 3 - 0.2 \cdot 2 + u_{x,3}
\$

$\
x_3 = 1.5 - 0.4 + u_{x,3} = 1.1 + u_{x,3}
\$

最後に、誤差 $\(u_{x,3}\)$ を考慮して実際の値を調整します。

### ゲーム時間の計算

同じようにゲーム時間を計算します。ゲーム時間の数式は：

$\
y_t = b_1 x_{t-1} + b_2 y_{t-1} + u_{y,t}
\$

係数 $b_1 = -0.3\$, $b_2 = 0.7\$ を代入します：

$\
y_3 = -0.3 \cdot x_2 + 0.7 \cdot y_2 + u_{y,3}
\$

データを代入して計算：

$\
y_3 = -0.3 \cdot 3 + 0.7 \cdot 2 + u_{y,3}
\$

$\
y_3 = -0.9 + 1.4 + u_{y,3} = 0.5 + u_{y,3}
\$

---

## 4. 行列を使った表現

複数のデータを扱うとき、行列を使うとスッキリ書けます。上記の数式を行列で表すと：

$\begin{bmatrix}
x_t \newline
y_t
\end{bmatrix}
$ = $\begin{bmatrix}
a_1 & a_2 \newline
b_1 & b_2
\end{bmatrix}
$$\begin{bmatrix}
x_{t-1} \newline
y_{t-1}
\end{bmatrix}
$ + $\begin{bmatrix}
u_{x,t} \newline
u_{y,t}
\end{bmatrix}
\$

ここで：

- 左のベクトルは、今日の宿題とゲームの時間。
- 中央の行列は、各データがどれだけ影響を与えるかを示す係数。
- 右のベクトルは、昨日の宿題とゲームの時間。
- 最後のベクトルは誤差です。

---

## 5. VARモデルでできること

VARモデルを使うと、以下のことが可能になります：

1. **未来の予測**  
過去のデータから「明日はどうなるか」を予測できます。

2. **因果関係の発見**  
「どの変数が他の変数に強い影響を与えているか」を分析できます。

例えば、「宿題を増やすとゲームの時間が減るのか？」という疑問を検証できます。

---

## 6. まとめ

VARモデルは、**複数のデータの関係性を分析して未来を予測する**ための便利な手法です。今回紹介した例のように、身近なデータでもその仕組みを理解することができます。

ポイントをおさらいすると：

- 過去のデータを使って、現在や未来の変化を予測。
- 数式や行列を使って、データ間の関係を表現。
- 応用すれば、経済学や気象学、マーケティングでも活躍！

少し数学的な部分もありますが、データ分析に興味がある方はぜひチャレンジしてみてください！
【YCNE Basic★】Yamaha Certified Network Engineer Basic 合格体験記

YCNE Basic★を受験してきた。同試験についての勉強方法やナレッジ(合格体験記)がネット上に少ないため記事を作成

# 試験について
受験料：13,200円（税込）※2024年12月時点
試験方法：テストセンターでのCBT方式
出題：出題形式（択一式）
問題数：50問
試験時間：60分
合格基準：70%以上
※結果はテスト終了後、CBT試験のパソコンに表示される

# 勉強方法・勉強時間・受験結果
■勉強方法
ヤマハネットワークエンジニア会の模擬問題を解く(1週ほど)
ネットワーク 入門・構築の教科書(マイナビ出版)を読む(こちらも1週)

■勉強時間
８時間程度

■受験結果
合格 得点：82点

# これから受験する方へのアドバイス(注意して学習すべき点)
・ヤマハ製品知識問題
→ヤマハネットワークエンジニア会の模擬問題に出題されたコマンド等を、ネットワーク 入門・構築の教科書で確認し理解を深める

・IPv6や無線LAN
→無線LANアクセスポイントに対する問題が出題される。正答率が50/100だった。また、IPv6関係のコマンドや知識を等問題が出題されたが自身を持って解答できなかった。

# 備考
試験の申込みと受験時にOdyssey IDが必要。受験時は同IDをメモ書きし会場に持参する必要がある（正直煩わしい）
https://cbt.odyssey-com.co.jp/ycne/basic.html
不安定なE2Eテスト

本記事はAdvent Calendar 2024、「テスト自動化あるある言いたい by T-DASH」シリーズ15日目の記事です。

今回は不安定なE2E（End-to-End）テストについてデメリットや対応策の話させていただきます。

https://qiita.com/advent-calendar/2024/t-dash03

## フレーキーなテスト
E2Eテストは、アプリケーションの全体的な機能やユーザーエクスペリエンスを検証する強力な手法ですが、テストが不安定になりやすいです。

不安定なテストが多くなると下記のような問題があります。

1. テスト結果の信頼性が低下する

E2Eテストが頻繁に失敗していると、「失敗＝問題ではない」という心理がチームに浸透してしまいます。その結果、実際に重大な不具合が発生しても見過ごされる可能性があります。
「あ、このテストはいつも失敗してるから無視でいいよ」といった状況が日常化してしまいます。

2. デバッグコストが増加する

テストが失敗するたびに調査が必要になると、開発チームの負担が増加します。E2Eテストは全体の機能をテストする分調査対象も大きく、原因がテストコードの問題なのか、本番コードのバグなのかが曖昧だと、根本的な解決には至らず、同じ問題が何度も発生します。

3. 開発のスピードと品質に悪影響

テスト失敗が常態化すると、E2Eテスト自体の目的である「プロダクト品質の担保」が揺らぎます。結果的に、チーム全体の信頼と開発スピードが低下します。

### 対応策
それではフレーキーなテストの対応策を紹介します。

1. E2Eテストを必要以上に多用しない

上記でも記述した通り E2Eテストはその性質上不安定になりやすいです。単体テストや統合テストと組み合わせることで、効率よくプロダクトの品質を担保しましょう。単体テスト、統合テストでカバーできるのであればE2Eテストは不要かと思います。
同値分割法や強化位置分析を使ったテストなど網羅的なテストなど単体テストでカバーできることが多いかと思います.



2. 失敗したテストをそのままにしない

失敗したテストがあれば、その原因を必ず特定しましょう。
原因は大きく以下の3つに分けられます：
	•	テストコードの不具合
	•	アプリケーションコードのバグ
	•	外部要因（ネットワークや環境の問題）

それぞれに適切な対応を取り、再発防止策を検討することが重要です。

## テストがフレーキーになる原因

テストコードがフレーキー（Flaky）になりやすい要因はいくつかあります。以下にフレーキーになりやすい要因とその例を挙げます。

1. 固定秒数の待機処理
 例えばテスト中ページ遷移などを待つ時にsetTimeoutやThread.sleep、waitForのように固定の秒数だけ待機するコードを使うと、想定より処理に時間がかかった場合に失敗しますし、長く取った場合は時間が多くかかってしまいます。

例:
```javascript
// 不安定な例
await page.waitForTimeout(2000); // DOMがレンダリングされるのを2秒待つ
await page.click('#submit-button');
```


#### 解決策: 固定秒数待機を避け、特定の条件（要素の可視化やAPIレスポンスの完了）を待つようにする。

```javascript 
await page.waitForSelector('#submit-button', { state: 'visible' });
await page.click('#submit-button');
```

2. テストデータや環境への依存
 テストが動的なデータや特定の環境（ネットワーク、データベースの状態など）に依存していると、不安定になります。

#### 解決策
- E2Eテストで使うものは専用のデータを準備
- モックデータを使用: APIレスポンスやデータベースのクエリをモック化する
- 隔離された環境を作る: Dockerや専用のテストデータベースを使用する

# まとめ
今回は不安定なE2Eテストのデメリットや対応策など紹介させていただきました。
ここで紹介下以外にも色々なアンチパターンがあると思います。ご参考になれば幸いです。
【備忘録】Azure Firewall 


# Azure Firewallとは　

Azureが提供しているクラウドベースのファイアウォールです。
SKUによって性能が異なります。

https://learn.microsoft.com/ja-jp/azure/firewall/overview

# SKUによる機能差　

### Standard

L3-L7 フィルタリングと脅威インテリジェンスを提供してくれます。
脅威インテリジェンスとは↓
> 既知の悪意のある IP アドレスやドメインとの間のトラフィックを警告したり拒否したりすることができます。


### Premium

Standardプランの機能に加えて特定パターンの通信内容を読み取り、攻撃を検知することができます。
Azure側で怪しい通信のパターンをリアルタイムに更新してくれており、そのパターンにあった通信を検知してくれます。

> シグネチャ ベースの IDPS などの高度な機能が備わっています。
> リアルタイムに更新されている 50 以上のカテゴリに分類された 67,000 以上のシグネチャにより、新たに出現した悪用方法から保護します。

###  Basic

小～中規模企業向けのサービス
お手頃価格で最低限Firewallとしての機能を使いたい方向けって印象です。

Standard に似ていますが、一部機能が使えません。
脅威インテリジェンスの例↓
> 脅威インテリジェンスの "アラート モード" のみをサポートします

全体的な機能差の詳細はこちら↓

https://learn.microsoft.com/ja-jp/azure/firewall/choose-firewall-sku

# 強制トンネリング

オンプレミス、AzureFirewallそれぞれからインターネット向け通信が可能な場合はどの通信をどっちから通信させるか制御したい場合があります。

例えばAにアクセスする際はオンプレ、BはAzureFirewallからなど　

そう言った時に使用する技術です。

https://learn.microsoft.com/ja-jp/azure/firewall/forced-tunneling

# 管理NIC 

元々強制トンネリングという名前だったのですが、名称が変更になったようです。

https://learn.microsoft.com/ja-jp/azure/firewall/management-nic

例えばAzureFirewallにpip(パブリックIPアドレス)を付けたくない場合は以下のようなことができます。

> パブリック IP アドレスをインターネットに直接公開しないことが望ましい場合があります。 この場合、パブリック IP なしで管理 NIC を有効にして Azure Firewall をデプロイできます。

https://learn.microsoft.com/ja-jp/azure/firewall/forced-tunneling

# 既知の問題

こちらにまとまっており、一通り目を通しておくとよいです。

https://learn.microsoft.com/ja-jp/azure/firewall/firewall-known-issues

気になった点を抜粋

> SNAT ポートの枯渇。パブリック IP アドレスごとに 2,496 個のポートがサポートされます。
→大規模な設計をする際はチェックしておくべきかもしれません。

> クライアント証明書認証はサポートされていません
→他にも記載がありましたが証明書関係を使う際は注意する必要がありそうです。

# 構成例

ハブアンドスポーク

https://learn.microsoft.com/ja-jp/azure/architecture/networking/architecture/hub-spoke?tabs=cli

DMZ

https://learn.microsoft.com/ja-jp/azure/architecture/reference-architectures/dmz/secure-vnet-dmz?tabs=portal
ElixirでDifyを使う

# 前提
Difyにログインできること

# Dify側のワークフローを作る

開始に`in`変数を作る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/f2c48afe-3eb1-d423-d9df-a341a49c9266.png)

LLMにSYSTEMプロンプトを入力
プロンプトの中に開始の`in`変数を含める
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/ee383328-a0ec-5723-7832-1e71919e5043.png)

終了に出力変数`text`を作る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/1c6fc031-cb61-2abd-da75-cf76f3637eae.png)

# APIキー取得方法
画面の赤矢印のように操作してください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/d98f0f4c-e5f8-f385-9a72-63dd024f8e84.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/3d12ef79-1048-2f9a-90e3-419d3670f145.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/26f84ab4-d1d0-20ab-5aba-ede40d0a33f7.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/d79e9230-0ed2-3750-c605-544384958832.png)



# Elixir側


ポイント　Authorization:にAPIキーを設定
あとは、Difyの`開始にin変数を作る`と同じ変数を
`{"in": "#{str}"}`をjsonとして指定する


```elixir:lib/data/lib.ex
defmodule Data.Lib do
  def llm(str) do
    headers = [
      "Content-Type": "application/json",
      Authorization: "Bearer app-xxxxxxxxxxxxxxxxxxxxxxxx"
    ]

    json = """
    {
      "inputs": {"in": "#{str}"},
      "response_mode": "blocking",
      "user": "abc-123"
    }
    """

    "https://api.dify.ai/v1/workflows/run"
    |> Req.post!(headers: headers, body: json)
    |> Map.get(:body)
    |> Map.get("data")
    |> Map.get("outputs")
    |> Map.get("text")
    |> IO.puts()
  end
end
```

reqをdepsに設定
```elixir:mix.exs
# 省略
  defp deps do
    [
      {:req, "~> 0.5.8"}
    ]
  end
# 省略
```

# 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/de20c637-cf52-6a30-d07e-23f484c4378e.png)
Ubuntu 24.04 lts で　Arduino IDE であそぶまとめ(リンク集)


目的
古い中古PCを再利用してArduino開発マシーンを安価に作る



https://qiita.com/caa45040/items/b1c363c42685159de4c8



https://qiita.com/caa45040/items/1a148f72aa3a4ba6b8d8



https://qiita.com/caa45040/items/6597b86f47f30f96a70d



https://qiita.com/caa45040/items/f127452ed03d54203146



https://qiita.com/caa45040/items/55635477687bf3294aa9
GitHubプルリクエスト本文の見出しや任意の箇所にアンカーリンクを付ける方法

# はじめに

GitHubでプルリクエスト（PR）を作成する際、例えば以下のような4つの見出しをMarkdownで記載することがあると思います。
- `# チケット`
- `# 背景`
- `# 対応内容`
- `# 動作確認結果`

そして、これらの見出しのうち「`# 動作確認結果`」の部分へ直接アクセスできるアンカーリンク（URL）を取得して、外部ツール（Notionなど）に貼り付けて共有したい場合があります。

イメージ：
![スクリーンショット 2024-12-14 15.40.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/47bde20e-85d4-7801-b0a9-e85689a26f80.png)


しかし、PR画面で「`# 動作確認結果`」という見出しにマウスカーソルを合わせても、通常は🔗マークが表示されず、アンカーリンクが簡単に取得できません。
また、Markdownで書いた見出しがHTMLに変換されても、その`<h1>`タグにid属性は付与されていないようです。

```markdown
# 動作確認結果

↓ MarkdownからHTMLに変換後 ↓

<h1 dir="auto">動作確認結果</h1>
```

もしこれがQiita記事やリポジトリのREADME.mdであれば、見出しの左側に🔗マークが表示され、そのリンクをコピーして共有できます。
しかし、プルリクエスト画面では同様の挙動が行われません。

README.mdの場合のイメージ：
![スクリーンショット 2024-12-15 11.51.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/e0cb64b9-6ca1-b73c-b86c-dd19c1eb40b0.png)


そこで、今回はPR上の見出しにもアンカーリンクを設ける方法をご紹介します。

# カスタムアンカーを使う方法

GitHubのMarkdownでは、HTMLタグを直接埋め込むことができます。
これを利用し、`<a>`タグで任意のアンカーポイント設定するという方法があります。

具体的には、`# 動作確認結果`という見出しの直前に、id属性付きの`<a>`タグを挿入します。
例えば、以下のように記述します。
（id属性の値は、適当に`"test"`とします。）

```markdown
<a id="test"></a>
# 動作確認結果
```

これで、
`https://<PRのURL>#test`
というリンクから、この`<a>`タグを置いた箇所へページ内リンクが可能になります。

ただし、実際にこのURLにアクセスすると、PRページの固定ヘッダーと見出しが重なり、見出し部分が隠れてしまいます。

- Before（`<br>`を入れる前）
![スクリーンショット 2024-12-15 12.53.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/cef15535-0767-cd94-1b66-bf6c8175c25f.png)

この問題は、`<a>`タグのあとに`<br>`などを入れて少し余白を確保することで解消できます。

```markdown
<a id="test"></a>
<br>

# 動作確認結果
```

`<br>`を挿入すると、リンク先へ移動した際に余白ができ、見出しがヘッダーに隠れず綺麗に表示されるようになります。

- After（`<br>`を入れた後）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/547e1fd9-9e23-3e1b-8b01-34f4fc4f6ac7.png)

実際のサンプル：
[https://github.com/ngsw877/git_tutorial/pull/19#test](https://github.com/ngsw877/git_tutorial/pull/19#test)

このように簡単なHTMLタグの挿入と余白調整で、プルリクエスト本文中の任意の箇所にアンカーリンクを作成し、その場所へ直接アクセスできるようになります。

# 参考

- [GitHub Docs カスタムアンカー](https://docs.github.com/ja/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#custom-anchors)
  - ※ ドキュメント内では`<a name="my-custom-anchor-point"></a>`のようにname属性を使用する例が紹介されていますが、HTML5でname属性は非推奨となったため当記事ではid属性を使用しています。（以下のリンク参照） 
- [HTML < a >タグ - MDN](https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#name)
Clojure: RingでTodoアプリを作る - エラーハンドリング

![advent_calendar_2024.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/f4cd8ce0-6352-a1d8-4cae-f39dd44f4def.png)

[*Advent Calendar 2024 Day 18*](https://qiita.com/advent-calendar/2024/clojure)

昨日は作ったTodoアプリのログが出せるようになりました
今日はエラーのハンドリングを行います

今日もエラーをキャッチするようなミドルウェアを作成してみます

## ミドルウェア作成

`wrap-error-handling`という名前のミドルウェアを作成し、エラーハンドリングしてみようと思います

今回は以下2パターンに関してエラーを実装していこうと思います

1. `clojure.lang.ExceptionInfo`の時は実装されたエラーを返す
1. それ以外の例外ケースは500エラーを返す

```clojure:core.clj
(defn wrap-error-handling
  [handler]
  (fn [req]
    (try
      (handler req)
      (catch clojure.lang.ExceptionInfo e
        (let [{:keys [status]} (ex-data e)
              message (ex-message e)]
          (res/status (res/response {:message message}) status)))
      (catch Exception e
        (let [message (str "Internal Server Error: " (.getMessage e))]
          (res/status (res/response {:message message}) 500))))))
```

こんな感じで実装してみました

実際に `GET /v1/todos/{id}` で存在しないTodoを指定したときには404エラーになるようにしてみます

```clojure:handler.clj
(defn get-todo [id]
  (-> (driver/find-todo id)
      (or (throw (ex-info (str "Todo id: " id ", Not found") {:status 404})))
      (res/response)))
```

これでTodoがなかった時には`clojure.lang.ExceptionInfo`を `throw` するようにできました


実際にリクエストを送ってみます

```bash
# 存在する場合
$ curl localhost:3000/v1/todos/1 -v
*   Trying 127.0.0.1:3000...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /v1/todos/1 HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.81.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Mon, 16 Dec 2024 13:43:07 GMT
< Content-Type: application/json;charset=utf-8
< Transfer-Encoding: chunked
< Server: Jetty(11.0.24)
< 
* Connection #0 to host localhost left intact
{"id":1,"title":"朝食を食べる","completed":false}

# 存在しない場合
$ curl localhost:3000/v1/todos/123 -v
*   Trying 127.0.0.1:3000...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /v1/todos/123 HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.81.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Date: Mon, 16 Dec 2024 13:42:46 GMT
< Content-Type: application/json;charset=utf-8
< Transfer-Encoding: chunked
< Server: Jetty(11.0.24)
< 
* Connection #0 to host localhost left intact
{"message":"Todo id: 123, Not found"}
```

存在するTodoを取るときは`200`、
存在しない場合は`404`エラーになりました