OmniAICreator/Qiita-1.07M huggingface dataset:
FlutterでX (旧Twitter) のリンクからOGP情報を取ってくる

以下の記事を参考に、FlutterでOGP情報の表示ビューを作成しました。

https://qiita.com/popy1017/items/732229abc14e73933269

しかし、x.comのポストのリンクについてはOGPの取得に失敗し、正常に表示できませんでした。これを表示できるようにするまでの流れを共有します。

OGP取得を成功させるために必要なポイントは２つありました。
1. リクエストヘッダに"User-Agent: bot"をつける
1. リダイレクトの処理にもヘッダーをつける

# プログラム
最終的にうまく行ったプログラムは以下です。
metadata_fetchというライブラリを使っているので、
```bash
flutter pub add metadata_fetch
```
で追加してください。

```dart:get_ogp.dart
import 'package:metadata_fetch/metadata_fetch.dart';
import 'package:http/http.dart' as http;

Future<http.StreamedResponse> httpGetWithoutAutoRedirect(Uri uri) async {
    http.Request req = http.Request("Get", uri);
    req.followRedirects = false;
    req.headers["User-Agent"] = "bot";
    http.Client baseClient = http.Client();
    return await baseClient.send(req);
}

Future<Metadata> fetchMetaData(String url) async {
    var streamedResponse = await httpGetWithoutAutoRedirect(Uri.parse(url));
    
    //無限リダイレクトの回避のため最大5回までのループにしています
    for (var i = 0; streamedResponse.isRedirect && i < 5; i++) {
      final redirectURL = streamedResponse.headers["location"];
      if (redirectURL == null) {
        safePrint('fetching redirect url failed $url');
        break;
      }
      streamedResponse =
          await httpGetWithoutAutoRedirect(Uri.parse(redirectURL));
    }
    
    final response = await http.Response.fromStream(streamedResponse);
    
    final document = MetadataFetch.responseToDocument(response);
    return MetadataParser.parse(document, url: url);
    }
}
```
# 注意点
## リクエストヘッダに"User-Agent: bot"をつける
twitter.comに普通にアクセスすると、ヘッダーにOGPのmetaデータが付いてこないようです。リクエスト時にヘッダーに"User-Agent: bot"をつけると付いてくるようになります。
↓こちらを参考にさせていただきました。

https://qiita.com/JunkiHiroi/items/f03d4297e11ce5db172e

## リダイレクトの処理にもヘッダーをつける
現在、Xの共有URLはx.comですが、これはtwitter.comへのリダイレクトURLになっています。Dartで普通にhttpリクエストを送るときは、
```dart
http.get(Uri.parse('https://example.com'), headers:{"User-Agent" : "bot"});
```
のようにな書き方になります。
この関数は与えられたURLがリダイレクトURLであれば、自動的にリダイレクト先まで辿ってレスポンスを返してくれます。しかし、どうやら辿る際に指定したヘッダーは無視されてしまうようです。これでは、Twitterのよううなmetaデータの取得に"User-Agent: bot"のヘッダーを要するサイトに対応できません。
そこで、リダイレクト時にもちゃんとヘッダーを送信し直してくれるような関数を自作する必要があります。
以下の部分がその関数です。
```dart:get_ogp.dart
Future<http.StreamedResponse> httpGetWithoutAutoRedirect(Uri uri) async {
    http.Request req = http.Request("Get", uri);
    req.followRedirects = false;
    req.headers["User-Agent"] = "bot";
    http.Client baseClient = http.Client();
    return await baseClient.send(req);
}
```

参考にした記事はこちら↓

https://stackoverflow.com/questions/62024717/how-to-get-redirect-url-in-dart
androidでkotlinからCを呼び出す

## AndroidStudioにndkをインストール
1. ツール＞SDK Manager を開く。
2. 外観＆振る舞い＞システム設定＞Android SDKから、SDK Toolsタブを開く。
3. 任意のNDKをインストールする。
![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72197/1bd667cb-62a6-44c0-e361-b0227d6abba4.png)

4. インストールしたndkにパスを通す。
  windowsの設定→システム→詳細情報＞システムの詳細設定
![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72197/560a36a2-1c1d-bd85-3687-6f3193a87d66.png)
環境変数→システム環境変数＞Pathを選択し、編集→新規
![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72197/9168281c-c307-a4e6-0166-2c779f288715.png)

## ndkを使えるようにするための設定
1.build.gradleにsourceSetsを追記する
```gradle:build.gradle
android {
   /* (中略)*/

    defaultConfig {
       /* (中略) */

        sourceSets {
            main {
                jni.srcDirs = []
                jniLibs.srcDir "src/main/libs"
            }
        }
    }
}
```
2\. AndroidStudioのプロジェクトビューから、mainフォルダ配下に「jni」ディレクトリを新規作成。
![004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72197/cefff71f-429c-31ad-d888-8a5112facbf4.png)
3\. 作成したjniフォルダ内に、Android.mkファイルを作成する。
```Makefile:Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := jni_main
LOCAL_SRC_FILES := jni_test.c

include $(BUILD_SHARED_LIBRARY)
```
## kotlinからjniを呼び出す
1. 呼び出される側のソースを、jniフォルダに新規作成
```c:jni_test.c
#include <string.h> 
#include <jni.h> 
// 「jp_co_jnipkg」＝パッケージ名
// 「MainActivity」＝呼出し元
// 「TestJNI」　　　＝メソッド名
jstring Java_jp_co_jnipkg_MainActivity_TestJNI( JNIEnv* env, jobject thiz ) {
    return (*env)->NewStringUTF(env, "JNIを呼び出しました!");
}
```
2\.MainActivityにjni呼出し処理を記述
```kotlin:MainActivity.kt
public class MainActivity extends AppCompatActivity {
    //JNI
    public native String TestJNI();
    static {
        System.loadLibrary("jni_test");
    }

    @Override 
    protected void onCreate(Bundle savedInstanceState{
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //JNIの呼び出し
        val result = TestJNI(); //"JNIを呼び出しました!"
    }
}
```

3\. jniフォルダ右クリック→パス/参照のコピー→絶対パス　で、jniフォルダの絶対パスをコピー。
AndroidStudio下部のターミナルウィンドウを開き、コピーしたパスにcdコマンドで移動し、
ndk-buildを実行する。
![005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72197/9c98c82f-99c9-c81b-bd23-5511cc5455c7.png)

4\. 通常どおりビルドして、実行
AZ-104試験対策のまとめ「ポート番号編」

## はじめに
Microsoft Azure Administrator(AZ-104)合格に向けた勉強でまとめた内容を本記事では投稿しています。
試験範囲の内容を私が勉強していく中で、
・忘れてしまっていた内容
・他の知識と絡めて理解した方が良い内容
・Microsoft Learnの読解に苦戦した内容
などをできるだけ分かりやすく簡潔にまとめることを意識しています。
Azureの勉強を一から始め、AZ-104取得を目指している方の参考になれば幸いです。
※本記事の内容が必ず試験に出るわけではないこと、ご注意ください

## 試験対策のまとめ
### **Azure Files**
* 445：SMBファイル共有はポート445を介して通信
* 参考
    - https://learn.microsoft.com/ja-jp/azure/storage/files/storage-files-networking-overview

### **ハイブリッドID**
* 80：TLS/SSL証明書を検証するためのCRL(証明書失効リスト)をダウンロードするために使用
* 443：Azure ADとの同期に使用
* 5671：Azure ADに正常性情報を送信するために使用(推奨されるが最新バージョンでは不要)
* 参考
    - https://learn.microsoft.com/ja-jp/azure/active-directory/hybrid/connect/reference-connect-ports

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/6eda24728c9c03c36bc3
【3D Object Detection】Behind the Curtain

# 概要
Point CloudのOcculusion問題を解決する為にデータをAugmentする
以下の2つを仮定する
- 物体は左右対称である
- 同じカテゴリーの物体は大体同じ形をしている

左右に反転させた点と他のサンプルを一つのデータに統合する事が出来る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/7cd03400-69d9-36ac-8203-73805821c6be.png)

この方法を利用する事で(a)の入力データに対して(b)のOccupancy Ground Truthを作る事が出来る。(c)の球体の3D Convolutionのネットワークを使って、(d)のようなOccupancy Probabilityを推定する事が出来る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/6468bcc7-f501-645f-18f6-b913df5f64cd.png)
Kotlin の例題　（HTTP クライアント と JSON)

## 例題

```text
次のプログラムを kotlin に変換して下さい
http https://example.com/api/v1/ex01 | jq .data
```

## プロジェクトの作成
プロジェクト名を try02 にしました。

```bash
mkdir try02
cd try02
gradle init
```

## 環境設定
Retrofit2 を使うための設定

```kts:app/build.gradle.kts
（省略）
dependencies {
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
（省略）
```

## ソースコードの編集

```kt:app/src/main/kotlin/try02/App.kt
/*
 * This Kotlin source file was generated by the Gradle 'init' task.
 */
package try02


import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.Call
import retrofit2.http.GET

import com.google.gson.JsonObject

class App {
    val greeting: String
        get() {
            return "本日は晴天なり!"
        }
}

fun main() {
	println("*** start ***")
    val baseUrl = "https://example.com/api/v1/"

    // Retrofitを設定
    val retrofit = Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    // Retrofitサービスを作成
    val service = retrofit.create(ApiService::class.java)

    // HTTPリクエストを送信
    val response = service.getData().execute()

    if (response.isSuccessful) {
        val jsonData = response.body()
        val data = jsonData?.getAsJsonObject("data")
        println(data)
    } else {
        println("HTTPリクエストが失敗しました。ステータスコード: ${response.code()}")
    }
	println("*** end ***")
}

// Retrofitインターフェースを定義
interface ApiService {
    @GET("ex01")
    fun getData(): Call<JsonObject>
}
```

## Build

```bash
./gradlew build
```

## 実行

```bash
./gradlew run
```

実行結果

```text
$ ./gradlew run

> Task :app:run
*** start ***
{"url":"http://example.com/abcdef0123.jpg"}
*** end ***

BUILD SUCCESSFUL in 1s
2 actionable tasks: 1 executed, 1 up-to-date
```

## JSON の処理の追加

次のような処理をするには、

```bash
http https://example.com/api/v1/ex01 | jq .data.url
```

次を、App.kt に加えます。

```kt:app/src/main/kotlin/try02/App.kt
(省略）
    val url = data?.get("url")?.asString
	println(url)
（省略）
```
【3D Object Detecion】SE-SSD

# 概要
- Teacherの検出結果をGlobal Transformation(Flip/Scaling/Rotate)させてStudentのGroud Truthとして学習させる。
- 3D Bouding Box内の点を減らしたりして、Data Augmentationを行う


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/0a095031-7ca5-6291-7da4-92dd15bde5da.png)

# 参考文献
[SE-SSD: Self-Ensembling Single-Stage Object Detector From Point Cloud](https://arxiv.org/pdf/2104.09804.pdf)
vbファイルを削除

```vb
Dim targetFolder, fs, folder, file, currentDate, sevenDaysAgo

' 対象のフォルダパスを指定
targetFolder = "C:\Path\To\Your\Folder"

' FileSystemObject を作成
Set fs = CreateObject("Scripting.FileSystemObject")

' 現在の日付を取得
currentDate = Date



' 7日前の日付を計算
sevenDaysAgo = DateAdd("d", -7, currentDate)

' 対象フォルダを開く
Set folder = fs.GetFolder(targetFolder)

' フォルダ内の各ファイルに対して処理
For Each file In folder.Files
    ' ファイルの更新日を取得
    fileDate = file.DateLastModified
    
    ' 更新日が7日前よりも古い場合は削除
    If fileDate < sevenDaysAgo Then
        fs.DeleteFile file.Path
        WScript.Echo "File deleted: " & file.Path
    End If
Next

' メッセージ表示（任意）
WScript.Echo "Files older than 7 days have been deleted."
```

```vb
Imports System.IO

Module Module1
    Sub Main()
        Dim targetFolder As String = "C:\Path\To\Your\Folder"
        Dim currentDate As DateTime = DateTime.Now
        Dim sevenDaysAgo As DateTime = currentDate.AddDays(-7)

        Dim directoryInfo As New DirectoryInfo(targetFolder)

        For Each file In directoryInfo.GetFiles()
            Dim fileDate As DateTime = file.LastWriteTime

            If fileDate < sevenDaysAgo Then
                Try
                    File.Delete(file.FullName)
                    Console.WriteLine("File deleted: " & file.FullName)
                Catch ex As Exception
                    Console.WriteLine("Error deleting file: " & ex.Message)
                End Try
            End If
        Next

        Console.WriteLine("Files older than 7 days have been deleted.")
    End Sub
End Module
```
Error: listen EADDRINUSE: address already in use :::3000 とError: querySrv EREFUSED _mongodb._tcp.cluster0.3ngq6dv.mongodb.netの解決方法

## エラー内容(Error: listen EADDRINUSE: address already in use :::3000)
```
Error: listen EADDRINUSE: address already in use :::3000
    at Server.setupListenHandle [as _listen2] (net.js:1316:16)
    at listenInCluster (net.js:1364:12)
    at Server.listen (net.js:1450:7)
    at Function.listen
```
Node.jsでhttpサーバー起動時にエラーが発生した。
要は「当該ポート(3000)は既に使用中だから使えない」というエラーである。

上記のコマンド(“npm start”)を実行する前にも同じコマンドを実行しており、そのときのプロセスが生き残っていることが原因なので起動中のプロセスをkillする。


## 解決方法(Error: listen EADDRINUSE: address already in use :::3000)
```
# port3000を利用してるプロセスの確認
sudo lsof -i:3000
```
上記のコマンドでプロセスIDを確認する。

```
kill -9 [該当のPID]
```
上記のコマンドで該当プロセスをkillする。
再度、httpサーバー起動を行うとエラーが発生せず起動を行うことができる。

## エラー内容(Error: querySrv EREFUSED _mongodb._tcp.cluster0.3ngq6dv.mongodb.net)
```
Error: querySrv EREFUSED _mongodb._tcp.cluster0.3ngq6dv.mongodb.net
    at QueryReqWrap.onresolve [as oncomplete] (internal/dns/promises.js:167:17) {
  errno: undefined,
  code: 'EREFUSED',
  syscall: 'querySrv',
  hostname: '_mongodb._tcp.cluster0.3ngq6dv.mongodb.net'
}
```
MongoDBとNode.jsとの接続の際にエラーが発生した。
調べてみるとバージョンを変更することで解決することができる。

## 解決方法(Error: querySrv EREFUSED _mongodb._tcp.cluster0.3ngq6dv.mongodb.net)
![スクリーンショット 2023-10-19 2.00.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3568441/a62343a1-10d3-70e2-f45a-e73fccd2b7ce.png)
version 5.5 or laterを選択していた際にエラーが発生した。
このversionを2.2.12 or laterを選択することで問題のエラーを解決することができた。
![スクリーンショット 2023-10-19 2.03.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3568441/c1cc3afd-650f-4565-4068-b296469b0905.png)
【VB.NET】DataTableについて

## きっかけ
VB.NETでデータベースのデータを扱ったときに、DataSetやDataTableが出てきて違いがわからなかった。
DataTableを使用してセルの値を取得する方法を理解することに苦労したため、備忘録としてまとめる。
<br>
## DataSetとDataTableの違い
Excelに例えた場合
DataSet：Bookにあたる
DataTable：Sheetにあたる
![DataSet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/ee216c43-a4da-fd88-fcbd-58a187bf5d8e.png)
<br>
## その他
・行(Rows)と列(Columns)は0から数える。
・列の指定は列名でも可能。(例：Columns("name"))
<br>

## DataTableの値を出力する方法
DataTableの例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/e8a35786-ec77-b822-281e-4d5eba085cbd.png)

```vb
dim dt as DataTable = ds.Tables(0)

for Each row as DataRow In dt.Rows
    Console.Write(row("id").ToString & " ")
    Console.Write(row("名前").ToString & " ")
    Console.Write(row("年齢").ToString & " ")
Next
```
<出力結果>
1 鈴木 10
2 佐藤 20
3 田中 30
4 天野 40
5 武藤 50
<br>

## 特定のセルの値を取得する方法
```vb
dim val as String = dt.rows(1).item(1).ToString
```
<出力結果>
佐藤
<br>

## 特定の列の値を集計する方法
```vb
'書き方1 
Dim totalAge As Integer = dt.Rows.Cast(Of DataRow).Sum(Function(row) CInt(row("年齢")))

' 書き方2
Dim totalAge As Integer = 0
 For Each row As DataRow In dt.Rows
     totalAge += row("年齢")
 Next
```
<br>

## デバッグでDataTableの中身を確認する方法
1.任意の位置で実行を止める。
2.DataTableが入っている変数にカーソルを合わせる、または
　ウォッチを見たときに`虫眼鏡アイコン 表示`　をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/2bd67eb0-1daf-7a01-d463-27b2df65c257.png)
3.DataTable Visualizerが起動し、DataTableの中身を確認できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/21b717c8-78de-6e39-921f-c36967413d9b.png)
<br>

## 参考サイト
DataTableに関する内容
https://dreamparadaisu.com/visualbasic_12/
https://hironimo.com/prog/vbnet/datatable/

DataTableのループ処理
https://zukucode.com/2017/10/vbnet-datatable-loop.html

特定のセルの値を取得する
https://rikaix.hatenablog.com/entry/2019/07/27/234831

特定の列を集計する
https://zukucode.com/2019/11/vbnet-datatable-sum.html

DataTableの中身の確認方法
http://ht-jp.net/blog/pc/c/vs-dataset-v
ぼくがAzureを嫌いな１０の理由

ただの愚痴といちゃもんなので、Azure大好きマンは回れ右してください

以下のようなご指摘は受け付けません。

- AWSでも同じですよ（笑）
- お前のレベルが低いだけ

# 1. Azure Bastionが高い

まあ、セキュアな踏み台ってのはわかるんだけど、時間$0.29 は高くない？
その割にネットワーク費用も取るんでしょ？
そしてデプロイが遅い。

# 2. 使わせる気ないSDKとドキュメント

なんなんあれ？ 
Microsoft殿のお家芸、自動生成APIドキュメント。
ぽんっとクラスとメソッド名だけが書いてある、開発初心者がドキュメンテーションしたんか？　と言いたくなるような、引数も返値の意味も、そもそもメソッドの役割の記載もない羅列。

サンプルをいじってできる範囲は サンプルが **動けば** まあOK.
それ以上のことをやりたいなら、SDKを使わない方法を考えた方がいいレベル。

さらに個人的なことを言わせてもらうと、``xxxx.list()`` でオブジェクト（Iterableでない）が帰ってくるのが意味わからん。

# 3. サービスは制限があるが、記載はドキュメントのどこか隅っこにしか書いていない

特に、他のサービスと組み合わせた時に影響が出るような、ネットワーク周りの制限がクッソわかりにくい。

# 4. 課金が予測できない

通常のネットワークのインバウンドとアウトバウンドだけでもきついのに、Site Recoveryだののトランジット量なんか見積もれるか？ Azure Firewallの処理量を見積もれるか？
いっぺん動かさないとわからんし、動かしてもわからん。なのに一番金がかかる。

クラウドのいいところはスモールスタートできるところです！ なんてのは嘘であり、本番に使いたい機能はお高いプレミアプランでしか使えず、しかもプラン間で変更ができないサービスもある。
従量課金はどこいった従量課金は

# 5. 構成管理

Desired State Configuration一択。
こんなドキュメントも少ないマイナーツール誰が使うんじゃ誰が。

# 6. 謎ドキュメント

機械翻訳しているのはまあいいとして、原文（英語）も言葉遣いが意味わからんのはなんやねん。

# 7. ルールを継承できないネットワークセキュリティグループ

純粋にめんどくさい。タグベースとかにならんの？

# 8. ドキュメントに記載がない動作

Timer TriggerのFunctionをPythonで作ってみようとした時、TimerObjectの中身がドキュメントの内容に一致しないことがあった

```json
{
    "Schedule":{
        "AdjustForDST": true
    },
    "ScheduleStatus": {
        "Last":"2016-10-04T10:15:00+00:00",
        "LastUpdated":"2016-10-04T10:16:00+00:00",
        "Next":"2016-10-04T10:20:00+00:00"
    },
    "IsPastDue":false
}
```
``ScheduleStatus`` がNoneになる。
CoreToolで作ったプロジェクトが生成したテンプレートでは、関数の引数に`func.TimerRequest`が設定されるが、そもそもこいつに``ScheduleStatus``に該当するプロパティすらない。
``azure.function.timer`` の ``TimerRequest``を使えば良いわけだが、元を正せば、2022年までこのバグを持ち越しているうえにテンプレの修正を見落としているのはどうなの

# 9. ドキュメントに記載がない動作２

Application Gatewayのリスナー設定。ポータル上は削除できても、API経由で見ると残っている。Application Gateway自体が好かん。待受IP複数つけられないのもな

# 10. 10は欠番
laravel Dockerのローカル開発環境でもタスクスケジューラーを定時実行させたい

## 概要

- Dockerを使ったローカル開発環境にてタスクスケジューラーベースの定時コマンド実行をするための設定を簡単にまとめる。

## 前提

- 下記の方法を参考に`php artisan`コマンドを実行するコンテナのタイムゾーンをJST（Asia/Tokyo）に変更しておく。

https://qiita.com/miriwo/items/27ea2a66bc08131be118

- すでにコマンドが登録され、laravelのタスクスケジューラーの設定も完了しているものとして話を進める。「cron」「laravelのタスクスケジューラー」「laravelコマンド」の関係性については下記記事で簡単にまとめている。

https://qiita.com/miriwo/items/7cb79adefd67b06b9f0e

- 本方法はDockerの「1プロセス1コンテナ」の考え方に違反していると思う。
- しかしながら手軽さを取って本方法を取った。

## 方法

1. Dockerfileと同階層に下記のファイルを作成する。
    - ファイル名: `crontab`
1. 作成したファイルに下記の内容を記載する。

    ```
    * * * * * cd コンテナ内のphp artisanコマンドを実行するディレクトリのフルパス && php artisan schedule:run >> /dev/null 2>&1
    ```

1. `php artisan`コマンドを実行できるコンテナのDockerfileに下記の内容を記載する。

    ```Dockerfile
    # corn
    COPY crontab /etc/cron.d/my-cron
    RUN chmod 0644 /etc/cron.d/my-cron
    RUN crontab /etc/cron.d/my-cron
    ```

1. コンテナをビルドして起動する。

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

1. `php artisan`コマンドを実行できるコンテナにターミナルで入り、crontab -lを実行し下記が出力されればcronの設定ができている。
【俺のための備忘録】pythonで上位n件の類似度が高いペアを保存する

# はじめに
この記事は完全に自分用の備忘録ですが、同じことやってる人は一定数いそうなので、シェアします。
おそらく、もっと良い方法があると思うので、コメント等で教えてくれると嬉しいです！

# 前提
自分は自然言語処理で文書間の類似度を測っているときに利用しました。全ペアの中から類似度の高い上位n件とその文書idを保持する必要がありました。

# 実装
以下のようなclassで実装しました。
```py:
class TopData:
    def __init__(self, top_n=3):
        self.top_n = top_n
        self.data = []

    def add(self, i, j, sim):
        self.data.append((i, j, sim))
        self.data.sort(key=lambda x: x[2], reverse=True)
        self.data = self.data[:self.top_n]

    def get_top_data(self):
        return self.data
```

使用例はこんな感じです。
```py
top3 = TopData()

top3.add(1, 2, 0.5)
top3.add(3, 4, 0.8)
top3.add(5, 6, 0.2)
top3.add(7, 8, 0.9)

print(top_sim_data.get_top_data())  # [(7, 8, 0.9), (3, 4, 0.8), (1, 2, 0.5)]
```
使い勝手としては良くも悪くもない感じですが、これで最低限自分がやりたいことはできました。

# 最後に
もっといい書き方、実装方法教えてください🥺
Next.jsでtype Propsを使ってコンポーネントにプロパティを渡す

# type Propsとは
type Props を使用してコンポーネントにプロパティを渡す方法があります。

# メリット
TypeScriptにおけるtype Propsのメリットです。

#### ①型安全性
TypeScriptはコード内のエラーやバグを前もって検出できるプログラミング言語です。
type Propsを使用することで、コンポーネントに渡すべきプロパティ（データ）やその型（データの形式）をわかりやすく指定できます。

#### ②コードの理解がしやすい
 type Propsを使用すると、コンポーネントがどのようなプロパティを受け入れ、それらのプロパティの型が何であるかが明示的になります。これは、他の開発者やあなた自身がコードを読んだりメンテナンスしたりする際に、コードの理解が容易になります。つまり、他の人がコードを読んで「このコンポーネントは何を受け入れるのか？」という疑問を解消できます。

#### ③リファクタリングのサポート
コードを整形する時に　type Propsを使用すると変更に関連する箇所を効果的に特定できます。つまり、コードの変更が効率的にできます。

#### ④エディタの補完支援
TypeScriptをサポートするエディタ（例: Visual Studio Code）は、type Propsを使用することで、プロパティの名前や型を自動的に補完してくれます。これにより、プロパティ名や型を正確に入力する手間を省くことができ、タイプミスを防げます。

#### ⑤ドキュメンテーション
type Propsを使用することは、コンポーネントのインターフェースをわかりやすくドキュメント化する手段としても役立ちます。他の開発者やチームメンバーにとって、コンポーネントがどのようなプロパティを期待し、どの型を要求するのかを一目で理解できるようになります。

要するに、type Propsを使うことで、TypeScriptの力を借りて、コードの品質を高めることができるます。

# なぜtype Propsを使うといいか小学生にもわかる説明
type Propsを使ってコンポーネントにプロパティを渡すとなぜいいのか小学生でもわかるようにしてみます。

例えば、お寿司屋さんで注文をする時に、お客さんが食べたいメニューはそれぞれ違うかもしれないです。
それぞれのお客さんが欲しいメニューを伝えるのが、```プロパティの役割```です。

以下は、Reactコンポーネントを使った具体例で、以下のようなコンポーネントがあるとします。

```tsx
function Order(props) {
  return <p>注文内容：{props.menu}</p>;
}

function App() {
  return (
    <div>
      <h1>ようこそ、React寿司へ</h1>
      <Order menu="マグロ" />
      <Order menu="ウニ" />
      <Order menu="えび" />
　　　　　　　　　　　　<Order menu="　サーモン" />
    </div>
  );
}
```
***Orderコンポーネントにmenuというプロパティを渡し、Appコンポーネント内で、違うメニューをOrderコンポーネントに渡すことができます。このプロパティによって、それぞれの注文は違うメニューを表示できます***。

ここで、***<Order menu="マグロ" /> のようにmenuプロパティにさまざまな値を指定することで、同じOrderコンポーネントを再利用しながら、違うメニューを注文できます。
これによって、同じコンポーネントを様々な状況で再利用することができ、コードを効果的に管理できています。

# どう使ったか
実際にNext.jsを使った開発でtype Propsを使いました。
具体例を出して見ていきます。エンジニアの管理情報を例に出していきます。
```interfaces/index.tsx
export type User = {
    id: number;
    No:number;
    name: string;
    age: number;
    department: string;
    labels: string;
};
```
のようなデータをとってくる時に使いました。

```users/List.tsx
//省略
import { User } from "../../interfaces";


const users: User[] = [
    {
        id: 1,
        No: 1,
        name: ハリー,
        age: 27,
        department: 開発,
        role: バックエンド,
    },
    {
        id: 2,
        No: 2,
        name: メアリ,
        age: 23,
        department: 開発,
        role: フロントエンド,
    },
    {
        id: 3,
        No: 3,
        name: ジョージ;
        age: 25;
        department: インフラ;
        role: クラウド;
    },
];

type Props = {
     user: User;
};

const List: React.FC<Props> = ({ user }: Props) => {
        //省略

}
export default List;
```
上のように実務で使いました。(コードの中身は違っています。)


# 参考
ChatGPT参照
T5Tokenizerのis_split_into_wordsが日本語だと役に立たない

## あらすじ
固有表現抽出(NER)などのタスクの際に、tokenizerへの入力として`str`型のテキストではなく、予め単語区切りされた`list`型を入力したくなる機会があると思います。私はDAE(Denoise Auto-Encoder)を学習させようと思ったときに、入力単語列に対して単語削除や並び替えを行ったため、`list`形式でencodeしたいと考えました。

## Sentencepiece tokenizerの問題
huggingface transformersのtokenizerには、こうした状況のために、call関数などに`is_split_into_words`
という引数が用意してあります。
[説明](https://huggingface.co/docs/transformers/main_classes/tokenizer#transformers.PreTrainedTokenizer.__call__.is_split_into_words)を見てみると、
>・is_split_into_words (bool, optional, defaults to False) — Whether or not the input is already pre-tokenized (e.g., split into words). If set to True, the tokenizer assumes the input is already split into words (for instance, by splitting it on whitespace) which it will tokenize. This is useful for NER or token classification.

とあり、空白区切りなどの分割が成されていることを理解してencodeしてくれそうです。

ところが、日本語のT5モデルでは`is_split_into_words = True`にしても意図したencodeをしてくれません。
以下は、[sonoisaさんの事前学習済みモデル](https://huggingface.co/sonoisa/t5-base-japanese-v1.1)を用いた例になります。
```
tokenizer: T5Tokenizer = T5Tokenizer.from_pretrained("sonoisa/t5-base-japanese-v1.1", legacy=False)
text: str = "今日は良い天気ですね。"
split_text: str = " ".join(tokenizer.tokenize(text))
>>split_text: ▁ 今日は 良い 天気 ですね 。
input_ids = tokenizer(split_text, is_split_into_words=True).input_ids
>>input_ids: [261, 10017, 261, 2198, 261, 14255, 261, 3849, 261, 260, 1]
```
encodeしたinput_idsに度々`261`というidが生じ、明らかにトークン数 < id数になっています。これは半角スペースのトークンで、空白区切りしていることを考慮してくれていないことが分かります。


tokenizerには`list[str]`を入力することもできるので、今度はそれを試してみたいと思います。
```
text: str = "今日は良い天気ですね。"
split_tokens: list[str] = tokenizer.tokenize(text)
>>split_tokens: ['▁', '今日は', '良い', '天気', 'ですね', '。']
input_ids = tokenizer(split_tokens, is_split_into_words=True).input_ids
>>input_ids: [261, 10017, 261, 2198, 261, 14255, 261, 3849, 261, 260, 1]
```
はい、さっきと同じ結果になりました。おそらく英語など元々半角スペースで区切られている言語では上手く動作するのだと思いますが、日本語ではスペースも単語としてエンコードされてしまいます。

## 解決策
`str`や`list[str]`でエンコードすると上記の問題が生じてしまうので、ids(`list[int]`)として与えることで回避したいと思います。
しかし、tokenizerのcall関数は`list[int]`を入力として受け付けてくれません。
```
text: str = "今日は良い天気ですね。"
ids: list[int] = tokenizer.encode(text)
>>ids: [261, 10017, 2198, 14255, 3849, 260, 1]
input_ids = tokenizer(ids, is_split_into_words=True).input_ids
>>ValueError: text input must of type `str` (single example), `List[str]` (batch or single pretokenized example) or `List[List[str]]` (batch of pretokenized examples).
```

一方で、[`batch_encode_plus`関数](https://huggingface.co/docs/transformers/v4.34.0/en/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.batch_encode_plus)は入力として`list[list[int]]`を受け付けてくれます。
なので、以下のようにすることでT5のinputを生成することができます。
```
text: str = "今日は良い天気ですね。"
ids: list[list[int]] = [tokenizer.encode(text, add_special_tokens=False)]
>>ids: [[261, 10017, 2198, 14255, 3849, 260]]
inputs: BatchEncoding = tokenizer.batch_encode_plus(ids, is_split_into_words=True)
# NERの場合
labels: LongTensor = LongTensor([[0, 0, 1, 1, 0, 0, 0]])
inputs["labels"] = labels
>>inputs
{'input_ids': [[261, 10017, 2198, 14255, 3849, 260, 1]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1]], 'labels': tensor([[0, 0, 1, 1, 0, 0, 0]])}
```

## 環境
transformers==4.31.0
GitHubで作業する手順~Webpacker::Manifest::MissingEntryErrorに当たってよけた~

# 目的

GitHubで管理しているコードを変更する手順をまとめたい


# 今回やること

今回の目標は以下の1つ。
* 進捗の生やし方をまとめる


# 環境
* windows 11
* ruby 3.0.6p216
* Rails 6.1.7.6
* node v16.20.2


# いざ出陣

### branchを作る

```cmd:cmd
git branch                  #今のリポジトリを確認
git checkout -b yyyymmdd    #今日のリポジトリを作成
git fetch -p
code .                      #VScodeを開く
```
`git fetch -p` はリモートリポジトリの最新情報を取得し、同時にリモートで削除されたブランチをローカルリポジトリから削除します。


### 作業する

今回はpost_listモデルの作成と、コントローラーの作成
```cmd:cmd
rails g model Post_list body:text
rails g controller post_lists
```

命名規則は以下を拝見

https://qiita.com/gakkie/items/3afcd505c786364aa5fa

### 困る

`rails s` して `http://localhost:3000/` を見るとapplication.html.erbで以下がエラー
packsにmanifest.jsができないよー。

```ruby:application.html.erb
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
```

まだ何もしてないが...？

バージョンの互換性の問題ぽい。

2時間悩んでわかんなかったので、コメントアウトしちゃいました...てへ(/ω＼)
```ruby:application.html.erb
<%#= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
```

### Push

今回はpost_listモデルの作成と、コントローラーの作成
```cmd:cmd
git add -A
git commit -m "コミットメッセージ"
git push -u origin yyyymmdd
git checkout main   #mainにマージするため
git merge yyyymmdd
git push -u origin main
```
`-u origin yyyymmdd` `-u origin main` は最初だけ
ブランチで登録されるので今後は `git push` でいける
ブランチ初のpushには必要そう


# 余談

↓この辺は見たんだけどね...。

https://github.com/rails/webpacker/issues/2674

https://roomer.hatenablog.jp/entry/2023/04/12/083904

https://wild-outdoorlife.com/ruby-on-rails/webpack5-error/

※なんか知らんけど解消した
QuantLibのYeildTermStructureの機能を確認する

イールドカーブを取り扱う抽象クラス`ql.YieldTermStructure`の機能を、具象クラス`ql.ZeroCurve`で確認する。



# カーブ構築
`ql.ZeroCurve`オブジェクトを生成する。`ql.ZeroCurve`は、与えられたノードからノード間のゼロレートを線形補間したイールドカーブ。

```python:カーブ構築
import math
import QuantLib as ql

# spot_datesの最初の日付はカーブの基準日、つまりDF=0となる日とすること。
spot_dates = [ql.Date(18, 1, 2020), ql.Date(18, 7, 2020), ql.Date(18, 1, 2021), ql.Date(18, 7, 2021), ql.Date(18, 1, 2022), ql.Date(18, 7, 2022), ql.Date(18, 1, 2023)]
spot_rates = [0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07]

zero_curve = ql.ZeroCurve(spot_dates, spot_rates, ql.Actual365Fixed())
zero_curve.enableExtrapolation() #node外を補外
```

```python:ノードを表示
zero_curve.nodes()
```

# ゼロ レート
ゼロ レートの計算を確認する。
```python:ゼロ レート 
date_m = ql.Date(18, 4, 2021)
rate_m = zero_curve.zeroRate(date_m, zero_curve.dayCounter(), ql.Continuous).rate()
print(rate_m) # 0.034972375690607786
```

```python:先のゼロ レートが線形補間で計算されていることを確認
date_l = ql.Date(18, 1, 2021)
rate_l = zero_curve.zeroRate(date_l, zero_curve.dayCounter(), ql.Continuous).rate()
t_l = zero_curve.dayCounter().yearFraction(zero_curve.referenceDate(), date_l)

date_r = ql.Date(18, 7, 2021)
rate_r = zero_curve.zeroRate(date_r, zero_curve.dayCounter(), ql.Continuous).rate()
t_r = zero_curve.dayCounter().yearFraction(zero_curve.referenceDate(), date_r)

t_m = zero_curve.dayCounter().yearFraction(zero_curve.referenceDate(), date_m)
rate_m2 = rate_l + (rate_r - rate_l) / (t_r - t_l) * (t_m - t_l)
print(rate_m2) # 0.034972375690607675
```


# ディスカウント ファクター
ディスカウント ファクターの計算を確認する。
```python:ディスカウント ファクター
date_m = ql.Date(18, 4, 2021)
df = zero_curve.discount(date_m)
print(df) # 0.9572492080611358
```

```python:ディスカウント ファクターの計算方法を確認
rate_m = zero_curve.zeroRate(date_m, zero_curve.dayCounter(), ql.Continuous).rate()
t_m = zero_curve.dayCounter().yearFraction(zero_curve.referenceDate(), date_m)
df2 = math.exp(-rate_m * t_m)
print(df2) # 0.9572492080611358
```

# フォワード レート
時点$t_1$スタート、時点$t_2$エンドのフォワードレート$fwd(t_1, t_2)$は、ディスカウント ファクターの関係式

$$
e^{-r_2 t_2} = e^{-fwd(t_1, t_2)\times(t_2 - t_1)} \times e^{-r_1 t_1}
$$

より、

$$
fwd(t_1, t_2) = \frac{r_2  t_2 - r_1 t_1}{t_2-t_1}
$$

となる。

```python:forwardRateメソッド
d_1 = ql.Date(18, 1, 2021)
d_2 = ql.Date(18, 7, 2021)

print(zero_curve.forwardRate(d_1, d_2, zero_curve.dayCounter(), ql.Continuous).rate()) 
# 0.06022099447513828
```

```python:forwardRateの計算方法を確認
t_1 = zero_curve.dayCounter().yearFraction(zero_curve.referenceDate(), d_1)
r_1 = zero_curve.zeroRate(d_1, zero_curve.dayCounter(), ql.Continuous).rate()

t_2 = zero_curve.dayCounter().yearFraction(zero_curve.referenceDate(), d_2)
r_2 = zero_curve.zeroRate(d_2, zero_curve.dayCounter(), ql.Continuous).rate()

fwd = (r_2 * t_2 - r_1 * t_1) / (t_2 - t_1)
print(fwd)
# 0.060220994475138234
```

# フォワード カーブ
フォワード レートで、時点$t_1$を固定して、時点$t_2$を動かせば、時点$t_1$のイールド カーブとみなせる。これがフォワード カーブ。

```python:ql.ImpliedTermStructure
fwd_curve = ql.ImpliedTermStructure(ql.YieldTermStructureHandle(zero_curve), d_1)
```

このフォワード カーブからゼロ レートを計算。

```python:ql.ImpliedTermStructureから ゼロレートを計算
print(fwd_curve.zeroRate(d_2, fwd_curve.dayCounter(), ql.Continuous).rate())
# 0.06022099447513828
```

これは先ほどのフォワード レートと一致する。
【VB.NET】データベースのデータをDataGridViewで表示する方法

## 開発環境
Windows11
VisualStudio2019
VB.NET 4.7.2
MySQL 8.0.34

## 1.MySQLに接続する
```vb
Imports MySql.Data.MySqlClient
:
Try
    Dim builder = New MySqlConnectionStringBuilder()
    ' データベース接続に必要な情報をbuilderに与える
    builder.Server = "localhost"
    builder.Port = 3306
    builder.UserID = "ユーザー名"
    builder.Password = "パスワード"
    builder.Database = "データベース名"
    Dim conStr = builder.ToString()

    ' データベースに接続
    Dim con As New MySqlConnection
    con.ConnectionString = conStr
    con.Open()
Catch ex As Exception
    MessageBox.Show("エラーが発生しました。error:" & ex.Message)
End Try
```
<br>

## 2.データベースのデータを取得,DataGridViewに表示する
```vb
Dim sqlStr As String = "SELECT id AS ""ID"", subject AS ""科目"" FROM subject ORDER BY id"
Dim dt As DataTable
Dim adapter = New MySqlDataAdapter(sqlStr, con)            ' データ取得のためのアダプタ設定
Dim data As New DataSet
adapter.Fill(data)                                         ' データを取得し、アダプタにセットする
dt = data.Tables(0)                                        ' DataSetからDataTableを取得する 
listSubject.DataSource = dt                                ' データをDataGridViewに表示する
Con.Close()
```
`listSubject`...DataGridViewコンポーネントのname
<br>

## 上記のコードをまとめたもの
```vb
Imports MySql.Data.MySqlClient
Public Class DgvSubjectMaster
    Try
        Dim builder = New MySqlConnectionStringBuilder()
        ' データベース接続に必要な情報をbuilderに与える
        builder.Server = "localhost"
        builder.Port = 3306
        builder.UserID = "ユーザー名"
        builder.Password = "パスワード"
        builder.Database = "データベース名"
        Dim conStr = builder.ToString()
    
        ' データベースに接続
        Dim con As New MySqlConnection
        con.ConnectionString = conStr
        con.Open()
        
        Dim sqlStr As String = "SELECT id AS ""ID"", subject AS ""科目"" FROM subject ORDER BY id"
        Dim dt As DataTable
    
        ' データ取得のためのアダプタ設定
        Dim adapter = New MySqlDataAdapter(sqlStr, con)             
        Dim data As New DataSet
        ' データを取得し、アダプタにセットする
        adapter.Fill(data)
        ' DataSetからDataTableを取得する
        dt = data.Tables(0)
        ' データをDataGridViewに表示する
        listSubject.DataSource = dt                                
        Con.Close()
        Catch ex As Exception
            MessageBox.Show("エラーが発生しました。error:" & ex.Message)
        End Try
    End Sub

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/cca9e585-2f2c-9c70-4448-186e017e91aa.png)
<br>

## 参考サイト
https://pan-blog.com/vb-net-mysql-beginner.html/

https://lab.unicast.ne.jp/2014/06/03/vb-net%E3%81%A7mysql%E3%82%92%E6%8E%A5%E7%B6%9A/
なぜ「画像アップロード機能」はしんどいのか

# 概要

画像アップロード機能ってそれだけ聞くと１つの機能なのですが、実は終わりが見えづらい機能ですよね。どこまでもリッチに機能追加できるし、セキュリティ対策も山ほどありますし、見積もりが難しい。
（もちろん仕様がカッチリきまっていればそれでOKです）

# なぜなのか

## １. 画像をどこに置くんだ問題

ローカル環境なら全然問題ないですよ。本番環境だと複数台構成前提でしょうからS3やGCSなどに置く前提になりますよね。そうなると、

- 「APIキー発行して」
- 「あっ権限なかった..○○さんにSlackで連絡っと...」
- 「次に本番用とステージング用とフォルダ構成を考えて...」
- 「あ〜〜！（むしゃくしゃ） >< （Yahooニュースみよう！）」

## ２. 良さげなライブラリを探すの面倒問題

- 「このライブラリいいね評価も高い。あ、でもメンテナンスもうされてないか...」
- 「おっと、こっちのはドキュメントがすごくわかりやすい」
- 「やっぱり前使ってたあれにするか〜」
- 「あ〜〜！（むしゃくしゃ） >< （ホッテントリみよう！）」

すみません。先人の方たちのライブラリには大変お世話になっております。
皆様のおかげで日々飯が食べれております。本当に感謝です。

## ３. UI・UXをどうするんだ問題

- ドラッグ&ドロップあり？ 
- 複数枚同時？
- キャンセル処理は？
- プレビュー機能は？
- アップロード中の見せ方どうする？

無限にあります。おそらくここが一番大変。イケてるサイトを参考にするしかない。

## ４. エラーハンドリングはどこまで頑張るんだ問題

- JPEG、PNG、HEIC/HEIF、WebP...
- ファイルサイズ
- ファイル選択直後のJS側によるバリデーションどうする

無限にあります。バリデーションはある程度こっちで実装しちゃいましょう。

## ５. 画像のリサイズ等を対応するのか問題

- アップロード時に自動（バックエンド側）で自動圧縮する？
- リサイズする？
- アップロード前にユーザ側のクロッピング（切り取り）機能搭載する？

う〜んヒットしたら搭載しましょう...

## ６. NGな画像をアップロードされたらどうする問題

- 運営側の承認後に掲載されるルールにする？

いや運用でカバーしよう...

## ７. Chrome以外のブラウザでちゃんと動くのか問題

これは特に　３ の UI/UX の部分の事。

# 総括

リストアップしてみると、まだまだありそうですが、とりあえず７つ。
「当たり前にやりなさい」という内容なのだが、やっぱり（仕様が決まっていないと）大変。
react-hook-form

```react
import React from 'react';
import { useForm, Controller } from 'react-hook-form';
import { DatePicker, Stack, PrimaryButton, TextField } from '@fluentui/react';

type FormData = {
  datePicker1: Date | null;
  textField1: string;
  textField2: string;
};

function App() {
  const { control, handleSubmit } = useForm<FormData>();

  const onSubmit = (data: FormData) => {
    console.log('Form data:', data);
  };

  return (
    <div className="App">
      <h1>Fluent UI Date Picker and TextFields Form</h1>
      <form onSubmit={handleSubmit(onSubmit)}>
        <Stack tokens={{ childrenGap: 15 }}>
          <Controller
            name="datePicker1"
            control={control}
            defaultValue={null}
            render={({ field }) => (
              <DatePicker
                label="Select a date"
                value={field.value}
                onSelectDate={(date) => field.onChange(date)}
              />
            )}
          />
          <Controller
            name="textField1"
            control={control}
            defaultValue=""
            render={({ field }) => (
              <TextField
                label="Text Field 1"
                value={field.value}
                onChange={(_, value) => field.onChange(value)}
              />
            )}
          />
          <Controller
            name="textField2"
            control={control}
            defaultValue=""
            render={({ field }) => (
              <TextField
                label="Text Field 2"
                value={field.value}
                onChange={(_, value) => field.onChange(value)}
              />
            )}
          />
          <PrimaryButton text="Log to Console" type="submit" />
        </Stack>
      </form>
    </div>
  );
}

export default App;

```
このコードは、TypeScriptで書かれており、FormData型を使用してフォームデータの型を定義しています。useForm<FormData>()を使用してフォームを設定し、Controllerコンポーネントを使ってフォームの各フィールドを制御しています。データを送信する際には、onSubmitハンドラでフォームデータをログに出力しています。
findコマンドで、現在のディレクトリ以下のファイルを検索したい時

コマンド操作に慣れようと、現在のディレクトリ以下にあるファイルを検索して削除しようとしたところ思うように検索ができなかったので、備忘録として残します。

# ディレクトリ構成

```
project-root-directory/←現在地
│
├── database/            
│   ├── factories/       
│   ├── migrations/      
│   └── seeders/ 
│		├──PostsTableSeeder.php
└── ...
```

こんな感じで、project-root-directory以下にある**PostsTableSeeder.php**を検索→削除という流れで、実行しようとした。

# 試したこと


### 1回目

```python
find ./ -name PostsTableSeeder | rm PostsTableSeeder.php
```

```python
rm: PostsTableSeeder.php: No such file or directory
```

ファイルがないよ〜って言われた。

rmの前に、findで検索できてるかもわからなかったので、findのみ実行。

### 2回目

```python
find ./ -name PostsTableSeeder
```

何の表示も出てこん。

.で、カレントディレクトリ配下の検索になっているはずなので、書き方に問題はないはず。

nameは、部分一致で該当ファイルがあれば、表示してくれるオプション。

### 3回目

```python
find ./ -type f -name PostsTableSeeder.php
```

typeのオプションを加えて、fとしてファイルを指定してみた。

```python
./database/seeders/PostsTableSeeder.php
```

表示がされた！！！

### 4回目

```python
find ./ -type f -name PostsTableSeeder.php | rm -rf PostTableSeeder.php
```

```python
rm: PostsTableSeeder.php: No such file or directory
```

検索できてるはずなのに、ダメだった。

どうやら、findとrmをパイプで繋ぐことができないらしい。

ということで、**findで見つかったファイルに対してrmコマンドを実行**していくことにした。

### 5回目

```python
find ./ -type f -name PostsTableSeeder.php -exec rm -f {} \;
```

削除できた〜！！！

※`exec`は、`find`コマンドにおいて見つかった各ファイルに対して特定のコマンドを実行するためのオプション。具体的には、`-exec`オプションの後に実行するコマンドを指定し、その末尾に `\;` を置くことでfiindの終了を意味する。`{}` は `find` によって見つかったファイルに対するプレースホルダで、これを記述することで、特定の値が入るべき場所を示すらしい。

# まとめ


検索結果に出てこない時は、typeなどのオプションを駆使して、条件絞った方が検索結果に表示されやすいかもですね〜

## 参考

https://pg.brain-studio.com/00/a-linux-find.html
herokuへのデプロイで使用したGitコマンドの備忘録

<h1>はじめに</h1>
<h3>こんにちは、@syutechprojectです！</h3>
<h4>herokuへのデプロイで使用したGitコマンドをメモしておきます。</h4>
<p>普段の業務では<b>Git</b>は<b>TortoiseGit</b>を使ってGUIで操作しているので、恥ずかしながらCLIで操作したことがあまりありませんでした。</P>
<b>heroku</b>では<b>Git</b>を使ってデプロイするため、CLIで操作する機会があり嬉々として使いました(笑)

<h1>Gitコマンド</h1>
<p><b>・ステージに変更を追加</b></p>

```
$ git add .
```

<p><b>・ローカルリポジトリに変更を記録</b></p>

```
$ git commit -am "適当なコメントをここに書く"
```

<p><b>・herokuにデプロイ</b></p>

```
$ git push heroku master
```
以上となります。
Kino 0.11 の破壊的変更

## はじめに

少し離れている間に、 Livebook 0.11 がリリースされました！

https://livebook.dev/

というわけで私の Elixir 学習用リポジトリーも諸々更新しました

https://github.com/RyoWakabayashi/elixir-learning

その更新作業の中で、 Kino に破壊的更新があったのでメモとして残しておきます

## Kino 0.11

Kino は Livebook の UI/UX を提供してくれるモジュールです

https://github.com/livebook-dev/kino

Livebook 0.11 に伴い、 Kino も 0.11 にアップグレードされています

CHANGELOG はこちら

https://github.com/livebook-dev/kino/blob/main/CHANGELOG.md

CHANGELOG の先頭に書かれている通り、画像入力の `Kino.Input.image` を使う場合、入力された画像を取得する際のコードを修正する必要があります

## 修正内容

Livebook 上に画像入力を作成する場合、以下のように記述します

```elixir
image_input = Kino.Input.image("IMAGE")
```

このコードを実行すると、以下のような UI が表示されます

![スクリーンショット 2023-10-19 0.40.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/7a79d52e-429d-5ee8-c205-e805ebb472c8.png)

画像を選択すると以下のような表示になります

![スクリーンショット 2023-10-19 0.40.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/e0fb46fb-9f55-c701-976e-fa48df83a3a6.png)

この画像入力から画像データを取り出す場合、以下のようにファイル入力を読み込みます

```elixir
image = Kino.Input.read(image_input)
```

Kino 0.10 以前では `Kino.Input.read` の戻り値に直接画像のバイナリデータが入っていました

```elixir
`%{data: <<0 0 0 ...>>, width: 100, height: 100}
```

そのため、バイナリデータを取得する場合 `image.data` だけで取得できていました

Kino 0.11 以降ではファイルへの参照が入るようになりました

```elixir
%{file_ref: "5i7t...", width: 100, height: 100}
```

そのため、ファイルへの参照から `Kino.Input.file_path` でファイルのパスを取得し、 `File.read!` でバイナリを読み込む必要があります

```elixir
image.file_ref
|> Kino.Input.file_path()
|> File.read!()
```

### Evision で画像を読み込む場合（Nx経由）

https://github.com/cocoa-xu/evision

Kino 0.10 以前では以下のようなコードで読み込んでいました

```elixir
image = Kino.Input.read(image_input)

image_cv =
  image
  |> Map.get(:data)
  |> Nx.from_binary(:u8)
  |> Nx.reshape({image.height, image.width, 3})
  |> Evision.Mat.from_nx_2d()
  |> Evision.cvtColor(Evision.Constant.cv_COLOR_RGB2BGR())
```

Kino 0.11 では以下のコードに変更しなければいけません

```elixir
image = Kino.Input.read(image_input)

image_cv =
  image
  |> Map.get(:file_ref)
  |> Kino.Input.file_path()
  |> File.read!()
  |> Nx.from_binary(:u8)
  |> Nx.reshape({image.height, image.width, 3})
  |> Evision.Mat.from_nx_2d()
  |> Evision.cvtColor(Evision.Constant.cv_COLOR_RGB2BGR())
```

差分で示すと以下のようになります

```diff_elixir
image = Kino.Input.read(image_input)

image_cv =
  image
- |> Map.get(:data)
+ |> Map.get(:file_ref)
+ |> Kino.Input.file_path()
+ |> File.read!()
  |> Nx.from_binary(:u8)
  |> Nx.reshape({image.height, image.width, 3})
  |> Evision.Mat.from_nx_2d()
  |> Evision.cvtColor(Evision.Constant.cv_COLOR_RGB2BGR())
```

### Elixir Image で画像を読み込む場合

https://github.com/elixir-image/image

Kino 0.10 以前の場合は以下のようなコードです

```elixir
image =
  image_input
  |> Kino.Input.read()
  |> Image.from_kino!()
```

Kino 0.11 以降では以下のように変更してください

```elixir
file = Kino.Input.read(image_input)

image =
  file
  |> Map.merge(%{data: file.file_ref |> Kino.Input.file_path() |> File.read!()})
  |> Image.from_kino!()
```

## まとめ

一旦ファイルのパス取得、読み込みを挟む必要があるため、以前よりコードは長くなります

おそらく他のファイル入力との統一したものだと思われますが、少し不便ですね
【VB.NET】DataGridViewのセルの空白部分をダブルクリックしてもイベントが発生しない

バージョン：VB.NET 4.7.2
## 発生した問題
DataGridViewを使用したフォームが2つあり、1つはセルの空白部分をダブルクリックしても
イベントが発生するが、もう1つはセル内の文字をダブルクリックしないとイベントが発生しない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/5d68bd00-a041-ddc2-624b-9eb49db543a0.png)
## 原因
使用しているイベントが違った。
CellContentDoubleClick：セル内の内容をダブルクリックするとイベントが発生する。
CellDoubleClick：セルのどこかをダブルクリックするとイベントが発生する。

CellDoubleClickを使用することで問題を解消することができた。
一部のDockerfileでパッケージがインストールできない

## 概要

- タイムゾーンのパッケージをインストールするために`RUN apk add --no-cache tzdata`をDockerfileに記載して実行したが、エラーがでてインストールできなかった。解決方法を簡単にまとめる。

## 詳細

- Dockerイメージ
    - mailhog/mailhog:v1.0.1
- エラー内容

    ```
     > [mailhog 2/3] RUN apk add --no-cache tzdata:
    #0 0.208 ERROR: Unable to lock database: Permission denied
    #0 0.208 ERROR: Failed to open apk database: Permission denied
    ```

## 原因

- コマンド実行ユーザーの権限不足らしい。
- 基本Dockerfileのコマンドはrootユーザーが実行する用になっているが、セキュリティ的観点からroot以外のユーザーでコマンドを実行しているDockerイメージがあるらしい。
- apkコマンドを実行する前にrootユーザーに切り替えてあげればいいらしい。

## 方法

- 下記のように記載されたDockerfileを使ってコンテナを作る。

    ```Dockerfile
    FROM mailhog/mailhog:v1.0.1
    
    USER root
    # タイムゾーンのパッケージをインストール
    RUN apk add --no-cache tzdata
    
    ENV TZ Asia/Tokyo
    RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
    
    USER mailhog
    ```
【HTML】段落の間に水平線を引く方法 

以下のように記述すると段落の間に水平線を引けます。

```html
<p>第一段落のテキスト。</p>

<hr />

<p>第二段落のテキスト。</p>
```

水平線の中央にテキストを表示するには以下のようなCSSを記述します。

```css
hr {
  border: none;
  border-top: 3px double #333;
  color: #333;
  overflow: visible;
  text-align: center;
  height: 5px;
}

hr:after {
  background: #fff;
  content: '§';
  padding: 0 4px;
  position: relative;
  top: -13px;
}
```
同じLANに接続しているPCでローカルのMySQLにリモート接続する方法

## きっかけ
社内でMySQLを使用したアプリを提出した際に、他のPCでexeファイルを起動すると、
MySQLに接続できないという旨のエラーが出たため。

## やり方
環境：Windows11、MySQL8.0.34
### 1.Windowsの場合、MySQLのmy.iniで以下を設定する
ファイルパス：C:\ProgramData\MySQL\MySQL Server 8.0\my.ini
```my.ini
#
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
# bind-address            = 127.0.0.1
bind-address            = 0.0.0.0
```
※bind-addressがない場合は、一番下に追加する。
<br>

### 2.Mysqlのサービスを再起動する
・windowsでサービスを起動し、MySQL80を再起動する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/3399a870-d957-ebff-49df-bf2d99b65151.png)
<br>

### 3.リモート接続するMySQLのユーザーを作成する
MySQLにログインしてから以下のコマンドを実行する。
```
CREATE USER 'ユーザー名'@'%' IDENTIFIED WITH caching_sha2_password BY 'パスワード';
```
・ユーザー名、パスワードは任意の文字列を入力する。
・パスワードは大文字小文字の英字、数字、記号をすべて1つ以上使用したパスワードを入力する。
　簡単なパスワードにすると後でエラーが出るため。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/c5697234-9d89-c09c-bf82-69a2a1ad70c0.png)

<br>

### 4.権限を付与する
```
GRANT ALL PRIVILEGES ON データベース名.* TO 'ユーザー名'@'%';
```
・データベース名は使用するデータベース名にする
・ユーザー名は3で登録したユーザー名にする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/c5d36733-f68e-ec01-cc77-7dc7afa5c466.png)
<br>

### 5.MySQLサーバーに変更を反映させる
```
FLUSH PRIVILEGES;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/72a20c13-0bd3-4171-dec3-30ca6a07e475.png)
<br>

### 6.登録したユーザーでログインできるか確認する
```
mysql -u ユーザー名 -p
```
ユーザー名は登録したユーザー名にする。
ログインできると以下のように表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/b64d7efd-08eb-2b8f-cfac-8c7023ca3de8.png)

### 7.アプリ側でMySQLの接続情報を変更する
※VB.NETの場合
```○○.vb
Dim builder = New MySqlConnectionStringBuilder()
builder.Server = "接続先のIPアドレス"
builder.Port = 3306
builder.UserID = "MySQLに登録したユーザー名"
builder.Password = "MySQLに登録したパスワード"
builder.Database = "グラントしたDB名"
Dim conStr = builder.ToString()
```
接続先PCのIPアドレスの確認方法は以下の通り。
コマンドプロンプトで以下のコマンドを実行する。
```
ipconfig
```
Wi-Fiに接続している場合、Wireless LAN adapter Wi-Fi: IPv4アドレス
がIPアドレスになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/494020e1-82b1-0d12-fcda-01b97c4cf1e9.png)
<br>

### 8.他のPCでMySQLサーバーに接続できるか確認する
同じLANに接続している他のPCでもexeファイルを動作させることができた。

## 参考サイト
https://tutorialcrawler.com/database/mysql%E3%81%B8%E3%81%AE%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E6%8E%A5%E7%B6%9A%E3%82%92%E8%A8%B1%E5%8F%AF%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/

https://self-development.info/%e3%80%90%e3%82%b3%e3%83%94%e3%83%9a%e3%81%a0%e3%81%91%e3%81%a7ok%e3%80%91mysql%e3%81%b8%e3%81%ae%e5%a4%96%e9%83%a8%e6%8e%a5%e7%b6%9a%e3%82%92%e8%a8%b1%e5%8f%af%e3%81%99%e3%82%8b%e6%96%b9%e6%b3%95/
Correction of Errors について

### 概要

以前のプロダクト開発で
インシデントレポートとしてCoEの形式を
採用していた。
今後に役立つと思われるので以下まとめます。

自分のために。。。


### CoE (Correction of Errors)について

1. **意味:**  
   CoEは「Correction of Errors」の略で、エラーや不具合、誤りを訂正するための手続きやプロセスを指します。

2. **使用される場所:**  
   - **金融・会計:** 会計帳簿における過去のエラーや誤計上を訂正するための手続きや記録として使われる。
   - **IT・ソフトウェア開発:** ソフトウェアやシステムに存在するバグや不具合を訂正する過程やその文書化。
   - **ヘルスケア:** 診療や治療に関連するエラーを認識し、それを訂正する行動。

3. **なぜ必要なのか:**  
   - **信頼性の確保:** エラーや誤りを正確に訂正することで、利用者や顧客の信頼を確保・維持する。
   - **正確な情報の提供:** 誤った情報やデータに基づいた判断を防ぎ、正確な情報で意思決定をサポートする。
   - **法的・規制上の要件:** 一部の業界では、エラーの訂正やその過程の文書化が法的・規制上必要とされる場合がある。

4. **利点:**  
   - **誤りの迅速な修正:** CoEのプロセスを有効に活用することで、誤りを迅速に特定し修正することが可能となる。
   - **学習の促進:** 過去のエラーや失敗から学ぶことができ、同じ誤りを繰り返すリスクを低減する。
   - **透明性の向上:** エラーが発生した際の訂正のプロセスや結果を公開・共有することで、組織の透明性を向上させる。
   - **組織文化の育成:** エラーを隠蔽するのではなく、公然と取り組むことで、エラーから学び成長する組織文化を育む。

CoEは、エラーや不具合が発生したときにそれを効果的に取り扱い、組織の持続的な成長や改善を促すための重要なプロセスです。

---

### CoEテンプレート

1. **What happened?**  
   - **概要:** 発生した事象やバグの詳細を説明する部分。
   - **サンプル:** 特定の操作を行った際にシステム内で誤ったデータが生成された。

2. **What was the impact on customers and your business?**  
   - **概要:** 事象が顧客やビジネスに及ぼした具体的な影響を述べる部分。
   - **サンプル:** お客様に再度情報提供を求める手間が生じ、一部のユーザーの信頼を失った。

3. **What was the root cause?**  
   - **概要:** 事象の主要な原因や背景を解説する部分。
   - **サンプル:** システム内の特定の関数の処理が不完全であり、その結果としてデータの不整合が生じた。

4. **What lessons did you learn?**
   - **概要:** 事象を通じて得られた学びや認識を挙げる部分。
   - **サンプル:** システムの核心部分を改修する際は、より詳細なテストを実施する必要がある。

5. **What corrective actions are you taking?**
   - **概要:** 今後の同様の事象を防ぐための具体的なアクションや改善策を示す部分。
   - **サンプル:** テストの手順や範囲の見直し、コードのリファクタリング、レビュープロセスの強化など。

---

### Appendix

- Amazon Web Services ブログ
correction of error (COE) を開発すべき理由
https://aws.amazon.com/jp/blogs/news/why-you-should-develop-a-correction-of-error-coe/
Docker PHPのコンテナでタイムゾーンをAsia/Tokyoに変更する方法

## 概要

- Dockerイメージの[](https://hub.docker.com/layers/library/php/8.2.3-fpm-alpine3.17/images/sha256-4bdd9b91217fe6c30d81ee560b589b1c4c8d476c27e11f5f8e56fe9dc981d498?context=explore)を使って立てるコンテナのタイムゾーンをJSTにする方法を簡単にまとめる。

## 方法

1. Dockerfileに下記の内容を記載してコンテナを作るだけ。

    ```Dockerfile
	FROM php:8.2.3-fpm-alpine3.17
	
	# タイムゾーンのパッケージをインストール
	RUN apk add --no-cache tzdata
	
	ENV TZ Asia/Tokyo
	RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
    ```

1. 当該のコンテナにターミナルから接続し`date`コマンドを実行することでタイムゾーンを確認する事ができる。
【Chrome118】Tab Hover Card Imagesを消す

Chrome118で突如[Tab Hover Card Images](https://qiita.com/rana_kualu/items/b16a10861b8b5ca8b2b4)が復活しました。

これを削除する方法が引っかけになっているので注意が必要です。

# 削除する方法

まずURL欄に[chrome://flags/](chrome://flags/)と打ち込む。

検索欄にhoverとか入れると`Tab Hover Card Image Setting`という項目が出てくるので、これを**Enabled**にします。
Disabledではありません。

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/4dd7d227-22c8-1130-5732-311ac1af520a.png)

再起動すると、設定→デザインに『タブ マウスオーバーのプレビュー カードに画像を表示する』という項目が出てくるので、これをオフにします。

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/1f25003f-1a47-4412-0ab9-0ee460817136.png)

これで消えました。
めでたしめでたし。

クソか！！！！！！！！！！！！！！！
OpenAPIについて調べてみた。


#はじめに
最近gRPCやOpenAPIなどのコード生成ツールが気になってるので雑に調べてみた。

## OpenAPIの歴史

OpenAPIは、もともと`Swagger`として知られていました。Swaggerは、2010年に開始され、REST APIの定義、ドキュメンテーション、そしてクライアントSDK生成のためのフレームワークとして急速に普及しました。2015年、Swaggerの仕様はLinux Foundationに寄贈され、OpenAPI Initiative (OAI) が設立されました。

## OpenAPIの主な特徴

1. **標準化**: APIのエンドポイント、パラメータ、レスポンス、セキュリティの定義など、RESTful APIに関連する多くの側面を標準化します。
2. **バージョニング**: APIのバージョン管理をサポートします。
3. **再利用可能なコンポーネント**: 同じ定義を複数の場所で再利用することができます。

## 詳細な記述例

```yaml
openapi: 3.0.0
info:
  title: User API
  version: 1.0.0
servers:
  - url: https://api.example.com/v1
security:
  - ApiKeyAuth: []
paths:
  /users:
    get:
      summary: Get all users
      tags:
        - Users
      parameters:
        - name: limit
          in: query
          required: false
          description: Max number of results to return
          schema:
            type: integer
            format: int32
            minimum: 1
            maximum: 100
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
        '400':
          description: Bad request
        '401':
          description: Unauthorized
        '404':
          description: Not found
        '500':
          description: Server error
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
          format: int32
          description: Unique identifier for the user
        name:
          type: string
          description: Full name of the user
          maxLength: 255

```
このOpenAPIの定義は、ユーザ情報を取得するAPIを表現しています。APIのエンドユーザは、単一のエンドポイント/usersにアクセスすることでユーザ情報を取得できます。要求する際、リクエストのヘッダーにX-API-KEYという名前でAPIキーを提供すること。



### OpenAPIとツールの連携
OpenAPIの仕様は多くのツールと連携することができます。例えば:
1. Swagger UI: 仕様からインタラクティブなAPIドキュメントを生成します。
2. Redoc: 高度なビジュアルでAPIドキュメントを表示します。
3. Swagger Codegen: 仕様からクライアントやサーバのコードを自動生成します

### 活用シーンとベストプラクティス
1. APIの設計時: OpenAPIでAPIの仕様を最初から定義することで、開発の方針を明確にし、チーム内でのコミュニケーションを促進します。
2. ドキュメントの自動生成: OpenAPIを使ってドキュメントを自動生成することで、ドキュメントのメンテナンスコストを削減できます。
3. モックサーバーの利用: OpenAPI仕様からモックサーバーを立てることで、フロントエンドの開発やAPIのテストが効率的に行えます。