OmniAICreator/Qiita-1.07M huggingface dataset:
【生成AIアプリ100チャレンジ】（15）返信メール生成・校正アプリ

https://ai.nuevo.jp/response_mail/


# 開発環境

|              |              |
|:------------:|:------------:|
| Server       | lightSail    |
| Language     | Python3.11   |
| Framework    | Django       |
| DB           | sqlite3      |

ローカル環境ではPythonのvenvを使用。エディタはvs codeです。

# 目的
メールの文章を考えるのがめんどくさいので、雛形を生成AIに書いてもらって楽しようというアプリです。
会社と名前は、ChatGPTに送らないよう、最低限のセキュリティだけ行なっています。

返信メールの内容と簡単な返信メールの内容をチャットGPTにリクエストとして送信。
最適な文書に生成・校正していただけるというアプリです。
実際に私も同じ内容の処理をChatGPTに問い合わせていたので、これで時間短縮になります。
同じ指示をなん度もしていたので、これでとても楽になります。

個人情報を送らないように気をつけてください。

# コード
```python:qiita.rb
    chat_results = ""
    if request.method == "POST":
        form = ChatForm(request.POST)
        if form.is_valid():
            company = form.cleaned_data['company']
            name = form.cleaned_data['name']
            received_mail = form.cleaned_data['received_mail']
            response_mail = form.cleaned_data['response_mail']

            client = OpenAI(
                api_key = OPENAI_API_KEY,
            )
            response = client.chat.completions.create(
                model="gpt-4",
                messages=[
                    {
                        "role": "user",
                        "content": "ここに新しいユーザーの入力を置く"
                    },
                    {
                        "role": "system",
                        "content": f"""
                        常に新しいユーザーです。履歴は忘れてください。
                        名前も会社名も忘れてください。
                        あなたは日本語が詳しい優秀な校正編集者です。

                        受信メッセージ
                        \nーーーーーーーーーーーーーーーーーーーーーー\n
                        {received_mail}
                        \nーーーーーーーーーーーーーーーーーーーーーー\n
                        メールから受信したメッセージです。内容を把握してください。

                        返信メッセージ
                        \nーーーーーーーーーーーーーーーーーーーーーー\n
                        {response_mail}
                        \nーーーーーーーーーーーーーーーーーーーーーー\n
                        受信メッセージの内容を把握した上で、返信メッセージのテキストを丁寧にわかりやすくなるように日本語で校正してください。
                        必ずメール文章の構成をキープしてください。
                        説明などは不要ですので、校正した文章のみをレスポンスしてください。
                        """
                    }
                ],
            )
            chat_results = response.choices[0].message.content
            chat_results = chat_results.replace("\n", "<br>")
            chat_results = company + "<br>" + name + "<br><br>" + chat_results

    else:
        form = ChatForm()

```

実際に私がよく使うプロンプトを採用しています。
実用検証済みです。

# アプリ画面
![スクリーンショット 2024-04-14 13.53.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398694/6afda950-f9d2-9c6c-13ea-c8dfb6468717.png)

# 感想
送信メールの応用で返信メールを作成しました。こちらの方がより実用的です。
少なくとも私は頻繁に使うことになるでしょう。
Cloud Functions（HTTPトリガー）をローカルから呼び出す

# 背景

Cloud Functionsをデプロイしたあと、テスト実行したい。  
そんなときにコマンド一発で実行できる方法があったのでこちらにメモとして記載する。

# やりかた
前提として以下を想定
- HTTPトリガーはPOST（他のでもできるはず）
- 呼び出しに[認証が必要](https://cloud.google.com/functions/docs/securing/authenticating?hl=ja)な関数

## gen1の場合
```SHELL
FUNCTION_NAME=hogehoge

curl -X POST \
$(gcloud functions describe ${FUNCTION_NAME} --region asia-northeast1 --format="value(httpsTrigger.url)") \
-H "Authorization: Bearer $(gcloud auth print-identity-token)" \
-H "Content-Type: application/json" \
-d '{"key": "value"}'
```

## gen2の場合
```SHELL
FUNCTION_NAME=hogehoge

curl -X POST \
$(gcloud functions  describe ${FUNCTION_NAME} --gen2 --region asia-northeast1 --format="value(serviceConfig.uri)") \
-H "Authorization: Bearer $(gcloud auth print-identity-token)" \
-H "Content-Type: application/json" \
-d '{"key": "value"}'
```

# 解説
## gcloud functions describe
関数のURLを取るためのコマンド。  
Cloud Functionsのgen1/gen2でちょっと違うコマンドになるので注意。

## gcloud auth print-identity-token
認証用トークンを取得するコマンド。  
ローカルに設定してあるアカウントでトークンを取得するので、事前にアカウントに対して権限が付与されている必要がある。

### 必要な権限
- gen1: `cloudfunctions.functions.invoke` （`roles/cloudfunctions.invoker`ロールをつけとけばOK）
- gen2: `run.routes.invoke` （`roles/run.invoker`ロールをつけとけばOK）

# 参考
- https://cloud.google.com/functions/docs/calling/http?hl=ja#url
- https://cloud.google.com/functions/docs/securing/authenticating?hl=ja
Virtual Box/Alma Linux ダウンロード➁

Virtual Box/Alma Linux ダウンロード➁

Virtual BoxとAlma Linuxのダウンロードに思いのほか手間取ったので備忘のため記録。

AlmaLinuxダウンロード

1.下記URLへアクセスし、少し下にスクロールしたら添付の画面が出てくる。
https://almalinux.org/

![スクリーンショット 2024-04-14 131849.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875259/052ea666-3b87-775c-05c7-3cff9c9edd40.png)

2."ISO Images"の"Download ISO from mirrors"を押下。

3.今回は"x86_64"の"9.3"を選択。

![スクリーンショット 2024-04-13 234624.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875259/3322a3fb-52b0-776d-882f-2a26c3702c37.png)

4.どこからダウンロードしてくるかの画面が出てくるので、"JP"の"ftp.sakura.ad.jp"を選択。(場所はぶっちゃけどこでも大丈夫だがインストール時間が多少変わってくるみたい)

![スクリーンショット 2024-04-13 234802.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875259/eed37ff5-b85b-2348-9139-a7af3b53f6b1.png)

5.次に何をダウンロードするかの選択が出てくる。
自分はAlmaLinux-9.3-x86_64-minimal.isoを選択した。

![スクリーンショット 2024-04-13 234850.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875259/79637e6e-9899-f5b2-d042-8c96ca61950a.png)

6.ダウンロードが始まって問題なくファルダに落とせたら完了。
wfuzzのエラーを解決する方法

# 概要

wfuzzを実行したが下記エラーで動かない。

```
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
```

# 解決策

解決策の一つとして下記コマンド3つを実行する方法があります。

```
sudo apt --purge remove python3-pycurl
```

```
sudo apt install libcurl4-openssl-dev libssl-dev
```

```
sudo pip3 install pycurl wfuzz
```
【ChatGPT＋DALL-E3】過去記事の画像処理のツールがなくなりました。


　どうも、カーブミラーです。

　今回は、過去記事の画像処理のツールがなくなったことを書きます。

:::note info
本記事は、ChatGPT（有料版）
＋DALL-E3で行なっております。
画像はありません。あしからず。
:::

　ニュースもないので、
　　本題です。

　以前の記事で
[【ChatGPT有＋DALL-E3】造形師にこそ、使って欲しい。ちと長いかも](https://qiita.com/kabumira/items/e5f0e48770dc5804fc5b)
　　というのを書きました。

　そこで
　　画像の背後を削除して
　　　透明化するツールと
　　　　3Dモデリングツールを
　　　　　紹介しました。

　ところが、
　　このツール、両方とも
　　　すでに削除されていました。

　確か、
　　Hugging Face上のものだったので
　　　新しいものが登場したか
　　　　事業化したかしたのだろう。

　ちなみに、Hugging Faceは
　　AI開発・機械学習のための
　　　プラットフォームの運営を
　　　　行っている会社です。

　それはさておき、
　　必要になったので、
　　　アクセスしようと
　　　　したわけですが、
　　　　　ツール自体がなくては
　　　　　　作業が続けられません。

　まぁ、
　　ググれば、
　　　それなりに出てきます。

　と思ったのですが、
　　背景除去は
　　　アプリがあったのですが、
　　　　画像から3Dモデリングする
　　　　　ツールがあるにはあるが
　　　　　　作ったファイルを
　　　　　　　見つけられない
　　　　　　　　という有り様。

　作業続行は
　　ダメですねぇ。　
　
　今回は、
　　みなさんの糧になる情報を
　　　用意できませんでした🙇

　今回は、ここまで。
Virtual Box/Alma Linux ダウンロード①

Virtual BoxとAlma Linuxのダウンロードに思いのほか手間取ったので備忘のため記録。

Virtual Boxダウンロード

1.下記URLへアクセスし画像の"Download VirtualBox7.0"を押下。
　https://www.virtualbox.org/
　![スクリーンショット 2024-04-13 235710.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875259/5f4fb769-a8e1-5ef8-1499-8da9ee2a4a6d.png)

2.プラットフォームを選択(画像ではwindowsを選択)

![スクリーンショット 2024-04-13 235746.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875259/1076598e-2a2c-d30e-f699-310d52ec44f8.png)

3.インストール先、機能選択に変更がない場合や、ネットが切れるなどの注意事項が出るが問題なければ"next","Install"を押下していく。

![スクリーンショット 2024-04-13 235851.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875259/3e3b0182-b6b0-5189-da75-ee9f2d2bd1d7.png)

![スクリーンショット 2024-04-13 235918.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875259/9f522cca-8d80-1a5c-785f-74316014f356.png)

![スクリーンショット 2024-04-14 001503.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875259/75a4a004-1889-3034-216c-b5d3f4a802bc.png)

![スクリーンショット 2024-04-14 001607.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875259/d9055bde-32d5-4abd-3218-51088026c4a2.png)

![スクリーンショット 2024-04-14 001622.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875259/54b5a21a-ebf5-17ea-325a-4d732c048be1.png)

4.無事"Finish"まで行ったことを確認。

![スクリーンショット 2024-04-14 001650.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875259/7d2cc325-a220-7d31-e841-eb621d71b268.png)

5.以下画面が出たらVirtual Boxのインストールは完了。

![スクリーンショット 2024-04-14 001906.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875259/f660a4d2-25c1-b21e-be65-0d38b38b84ad.png)
Nvidia GPUのPower Comsumptionを下げてみる

# 概要
GPUの電気代を節約したいので、色々と試してみた。

# 環境
GPU: Nvidia RTX2060
OS: Ubuntu18.04


# 解像度を下げる
Nvidia X Sever Settingを開く。
defaultがFull Resolution(1920x1080)になってたので、Scaled(1366x768)に下げてみた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/4bbe23f9-b963-8463-0057-0a6b1a5fd2a0.png)

# Powerを制限してみる
Poformanceを落とさずpower comsumptionを下げるのは25%くらいとの事だったので、160Wから120Wへ下げてみる事に。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/ec66ed94-69c8-7d7d-ed21-1e5038839909.png)

125W以上にしろと言われたので、125Wに設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/3a1cef72-a99d-9832-ceab-9f034c9b66c4.png)

# PowerMizer
元からAdaptiveだったのでそのままに
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/85910521-24ab-f9d0-828a-f2b32a203fe8.png)

# 結論
手っ取り早く、あまりデメリットが無い、解像度を下げるのが一番効果的なような。
Pythonを用いてURLからファイルをダウンロードする

# はじめに
Pythonと「Requests」ライブラリを用いて、定義したURLのファイルをダウンロードするコードを作成してみました。

# サンプルコード
## 概要
ファイルのURLが作成されている「list.txt」ファイルを読み込んで、改行ごとのURLのファイルをダウンロードします。


## コード例
「list.txt」ファイルは、以下のように改行でURLを区分します。
```text:list.txtの例
https://www.~~~.com/~~~/sample_img1.png
https://www.~~~.com/~~~/sample_img2.png
https://www.~~~.com/~~~/sample_pdf1.pdf
```
Pythonのサンプルコードは、以下のように作成しました。
```python:サンプルコード
import requests


def main():
    # テキストファイルからURLを取得する（改行で区分）
    with open("list.txt", "r") as txt_f:
        file_url_list = txt_f.read().splitlines()

    # 取得したURLごとにファイルをダウンロードする
    # file_urlの例：https://www.~~~.com/~~~/sample_img1.png
    for file_url in file_url_list:
        # URLを「/」に分割して、最後の文字列をファイル名にする
        # 例：sample_img1.png
        file_name = file_url.split("/")[-1]

        # ファイルをダウンロードする
        with open("./" + file_name, "wb") as w_f:
            response = requests.get(file_url, stream=True)

            if not response.ok:
                print(response)

            # chunk_sizeを1024(bytes)に設定する
            for chunk in response.iter_content(1024):
                if not chunk:
                    break

                w_f.write(chunk)


if __name__ == "__main__":
    main()
```
Ruby で解く AtCoder ABC 043 D - アンバランス (ARC 059 D)

# はじめに
- [AtCoder Problems](https://kenkoooo.com/atcoder/#/table) の ABC042 以降の問題を解いています
- 勉強のために Ruby で解いています
    - 速度的な面で他の言語には劣りますが、あくまで勉強のためです
# お題
- 今回のお題は、 [ABC 043 Dのアンバランス](https://atcoder.jp/contests/abc043/tasks/arc059_b) という問題です
- 入力文字列の部分文字列がアンバランスかどうかを判定し、アンバランスなら具体的な区間を答えるというもの

# 考えたこと
- 何も考えずに作ろうとすると、時間計算量は$O(n^3)$になる
    - 部分文字列の列挙で$O(n^2)$
    - 判定で$O(n)$
- 位置を1つ示せば良い
    - 答えは複数あるのだが、少なくとも1つのアンバランスな区間を示せれば良い
- アンバランスな文字列は以下のパターンのどちらかを含む
    - 長さ2の"XX"というパターン
    - 長さ3の"XYX"というパターン
- 上記踏まえ、入力文字列を先頭から走査していき、走査位置と走査位置の1個先、2個先を見るだけで、アンバランスな部分文字列を含むか判定できるので、$O(n)$で求めることができる
# コード

```ruby
s = gets.chomp.chars
len = s.size
found = false

(0...len-1).each do |i|
  # 隣接する同じ文字のチェック
  if s[i] == s[i+1]
    puts "#{i+1} #{i+2}"
    found = true
    break
  end

  # 1文字を飛ばして同じ文字のチェック
  if i+2 < len && s[i] == s[i+2]
    puts "#{i+1} #{i+3}"
    found = true
    break
  end
end

# アンバランスな部分文字列が見つからなかった場合
puts "-1 -1" unless found

```
【生成AIアプリ100チャレンジ】（14）送信メール校正アプリ

https://ai.nuevo.jp/send_mail/


# 開発環境

|              |              |
|:------------:|:------------:|
| Server       | lightSail    |
| Language     | Python3.11   |
| Framework    | Django       |
| DB           | sqlite3      |

ローカル環境ではPythonのvenvを使用。エディタはvs codeです。

# 目的
メールの文章を考えるのがめんどくさいので、雛形を生成AIに書いてもらって楽しようというアプリです。
会社と名前は、ChatGPTに送らないよう、最低限のセキュリティだけ行なっています。

目的、送信先の相手との関係、挨拶の要不要、送り先の相手人数を指定します。
簡単な平文を短い文章で書いて、生成AIに送れば、それなりの文書にして返してくれます。

# コード
```python:qiita.rb
    OPENAI_API_KEY = os.environ['OPENAI_API_KEY']
    chat_results = ""
    if request.method == "POST":
        form = ChatForm(request.POST)
        if form.is_valid():
            company = form.cleaned_data['company']
            name = form.cleaned_data['name']
            purpose = form.cleaned_data['purpose']
            relation = form.cleaned_data['relation']
            greeting = form.cleaned_data['greeting']
            number = form.cleaned_data['number']
            message = form.cleaned_data['message']
            client = OpenAI(
                api_key = OPENAI_API_KEY,
            )
            response = client.chat.completions.create(
                model="gpt-4",
                messages=[
                    {
                        "role": "user",
                        "content": "ここに新しいユーザーの入力を置く"
                    },
                    {
                        "role": "system",
                        "content": f"""
                        常に新しいユーザーです。履歴は忘れてください。
                        名前も会社名も忘れてください。
                        あなたは日本語が詳しい優秀な校正編集者です。
                        このメールの目的は‘{purpose}’です。
                        このメールの送り先の相手との関係は‘{relation}’です。
                        このメールには挨拶は‘{greeting}’です。
                        このメールを送る相手の人数は‘{number}’です。
                        下記のテキストが元になる送信テキストです。

                        送信テキスト
                        ーーーーーーーーーーーーーーーーーーーーーー
                        ‘{message}‘
                        ーーーーーーーーーーーーーーーーーーーーーー
                        上記のテキストを丁寧にわかりやすくなるように日本語で校正してください。
                        必ずメール文章の構成をキープしてください。
                        説明などは不要ですので、校正した文章のみをレスポンスしてください。
                        """
                    }
                ],
            )
            chat_results = response.choices[0].message.content
            chat_results = chat_results.replace("\n", "<br>")
            chat_results = company + "<br>" + name + "<br><br>" + chat_results

    else:
        form = ChatForm()
```

最初は、セレクトされた内容ごとにプロンプトの分岐をさせようと考えていたが、そこまでしないでも役割を与えるだけで生成AIには十分なんだと気づいた。情報を与え過ぎても、思うように生成してくれるわけではないので、あくまで効率化してくれるのを目的としただけのアプリです。

# アプリ画面
![スクリーンショット 2024-04-14 12.49.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398694/80bfdd5e-9d01-f285-127a-3c3a3c9737f5.png)

# 感想
メール送信のあとはメール返信アプリを作成したい。
受信メールの内容を理解させて、返信内容について簡単な平文を送ることで、適切な返信文を返してくれるとなおいい。
もしかしたら校正分の校正みたいな処理をいれると、よりいいテキストを返してくれるのではないか、とも思っている。
【初心者】TypeScript文法を理解していくvol.3

## はじめに

引き続きTypescriptを学ぶ

## エラーが発生した場合の対処法
Typescirptはコンパイル時にエラーが発生しないかチェックしてくれる

### 例外が発生してきた時にnullを返却する
便利だけどなぜnullが返ってきたのかわからない（隠蔽できちゃう）

```.ts
const selectRoulette = (index: number): boolean | null => {
    if (index < 0 || index > 37) {
      return null
    }
    // 0~36のランダムな数字を取得する
    const winNumber = Math.floor(Math.random() * 37);
    return winNumber === index
  }
  console.log(selectRoulette(1))
  // 正常
  console.log(selectRoulette(500))
  // nullが返却される
```

### 例外をthrowしていく。
特定のエラーであることを示すために例外をthrowする。

```.ts
const selectRouletteWithThrowingError = (index: number): boolean => {
    if (index < 0 || index > 37) {
      // RangeError を throw する
      // 想定の範囲外ですよと言う意味
      throw new RangeError(`Invalid index: ${index}. Roulette allows betting on numbers from 0 to 36`);
    }
    // 0~36のランダムな数字を取得する
    const winNumber = Math.floor(Math.random() * 37);
    return winNumber === index
  }

  // throw された例外は try/catch で処理
  try {
    // 問題なく進めばこっちが処理される
    const ret = selectRouletteWithThrowingError(500)
    console.log("rouletteResult"+ ret)
  } catch (e) {
    // instanceof 演算子を用いることでエラーの型を判定できる
    // catchしたらエラーがどんなエラーかを確認する
    if (e instanceof RangeError) {
      console.error(e.message)
      // OutPut: Invalid index: 500. Roulette allows betting on numbers from 0 to 36
    }
  }
```

### 【Tsの強み】 Errorオブジェクト
`try~catch`を用いて、`throw`されたエラーを処理するかは開発者による。
例外を処理するプログラムを書く必要があるときは、`Error型`の返り値を指定すると便利。

```.ts
// ルーレットの結果を受け取ってメッセージを出力する関数
  const getResultMessage = (ret: boolean): void => {
    if (ret) {
      console.log("Congratulation!")
    } else {
      console.log("Tough luck...")
    }
  }

// ルーレットの選択肢をチェックする関数
// ここでError型を指定してしまう！　=> boolean | RangeError
const selectRouletteReturnError = (index: number): boolean | RangeError => {
    if (index < 0 || index > 37) {
      // RangeError を throw する
      return new RangeError(`Invalid index: ${index}. Roulette allows betting on numbers from 0 to 36`);
    }
    // 0~36のランダムな数字を取得する
    const winNumber = Math.floor(Math.random() * 37);
    return winNumber === index
}

// 関数の実行
const ret = selectRouletteReturnError(5)

// ret は boolean | RangeError なので、RangeErrorではないことを検証しないと getResultMessage の引数として渡せない
  if (ret instanceof RangeError) {
    console.error(ret.message)
  } else {
    getResultMessage(ret)
  }
```
## おわりに
`try~catch`を用いない場合、関数の返却値に型をつけられるのは非常に便利だと思いました。もっとTypescriptを知っていきたい！

## Error型について参考

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Error

https://typescriptbook.jp/reference/builtin-api/error
【備忘録】Next.jsをDockerで起動する

# はじめに
**Next.jsアプリケーション** を **コンテナ上で起動** する方法についての備忘録です。


## 気になること
node.js単体で実行出来るアプリケーションならチーム開発時にvoltaみたいなバージョン管理ツールでバージョン合わせれば良いのでは？(Dockerってそんなに必要なんでしょうか？)
コメントで教えてほしいです。

## Dockerfile と next.config
```Dockerfile:/Dockerfile
FROM node:18-alpine AS base

FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app

COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
  if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
  elif [ -f package-lock.json ]; then npm ci; \
  elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
  else echo "Lockfile not found." && exit 1; \
  fi


FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# 収集を拒否
ENV NEXT_TELEMETRY_DISABLED 1

RUN \
  if [ -f yarn.lock ]; then yarn run build; \
  elif [ -f package-lock.json ]; then npm run build; \
  elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
  else echo "Lockfile not found." && exit 1; \
  fi

FROM base AS runner
WORKDIR /app

ENV NODE_ENV production
# こちらも収集を拒否
ENV NEXT_TELEMETRY_DISABLED 1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public

RUN mkdir .next
RUN chown nextjs:nodejs .next

COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD HOSTNAME="0.0.0.0" node server.js
```

```js:/next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
    output: "standalone"
};

export default nextConfig;
```

:::note info
**nextConfig** に 記述していないと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/a47abaad-d53e-47d3-6e69-105b0f0e08d8.png)
**ビルド時** にこのような **エラー** が発生しました。
:::
## ビルドコマンド
```console
docker build -t nextjs-docker .
```

## 起動コマンド
```
docker run -p 3000:3000 nextjs-docker
```

## さいごに
学習させていただいた先・ライブラリの公式ドキュメント・リンクです。

https://nextjs.org/docs/pages/building-your-application/deploying#nodejs-server

https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile

https://stackoverflow.com/questions/70608086/i-am-getting-error-while-converting-my-next-js-project-to-docker
C# IEnumerable型とList型の違い

C#のコードを書いていて、IEnumerableをなんとなく使っていたため、
List型・Collection型と比較しながらまとめてみました。

## IEnumerableとは
コレクションの要素を順番に取り出すことができるインターフェース
ひとことで言うと`foreach`で繰り返しをするためのイテレータを表す型

特徴
* 遅延評価: IEnumerableは要素を順次取り出すため、必要な要素だけが評価される。これにより、大量のデータを効率的に処理できる
* 読み取り専用: コレクションの要素を追加や削除するができない。要素の変更は行えない
* インデクサアクセスなし: IEnumerableにはインデクサがないため、特定の要素にランダムアクセスすることができない
:::note info
インデクサとは
配列型と同様に [] を用いた要素の読み書きが行えるような仕組み
:::
* 継承可能: IEnumerableはインターフェースなので、独自のコレクションクラスを定義することができる

## ICollection型
IEnumerableを継承したものなのでコレクションの要素を順番に取り出すことができる。
IEnumerableと異なり、要素数のカウントを行うことができる

## IList型
コレクションに対する、追加・変更・削除も含めた、全ての操作が可能である。
ICollection型を継承しているので、要素数のカウント、コレクションの列挙を行うことができる。

## まとめ
IEnumerableはコレクションの列挙のみ可能、ICollectionは加えてコレクションの要素数のカウントが可能である。IListは２つの特徴に加えて、コクションの追加・変更・削除を含めた全ての操作が可能

:::note info
まとめ

継承の流れ
IEnumerable　→ ICollection → IList

IEnumerableはコレクションの列挙のみ可能、ICollectionは加えてコレクションの要素数のカウントが可能である。IListは２つの特徴に加えて、コクションの追加・変更・削除を含めた全ての操作が可能
:::
【分析】計量テキスト分析

# ０.はじめに
大学で計量テキスト分析の講義を受講している者です。
用語や概念をまとめて以下の項目に分類しています。

# １．計量テキスト分析とは
テキストデータを量的データへと変換し計量的分析を行う方法のこと

## 定義
計量的分析手法を用いてテキスト型データを整理もしくは分類し内容分析を行う方法
不可能ではないが手作業より遥かに円滑なため``PC利用``による分析が望ましい

### 内容分析
コミュニケーションから分類し特徴を導き出し客観化する研究方法
内容を記述するだけでなく内容を送信する側ないし受信する側の状況を鑑み推論する方法
分析において分類をする際、基準の規定が困難でこれまで誰もが簡単にできるものではなかった

## 手法
- １．問題に着目	
- ２．計量的なモデルに変換	
- ３．モデルを数学的・統計的に分析	
- ４．３を現実的な言語へと変換	


## 種類
### 仮説検証型		
データを探し可能な範囲のデータでできるだけの分析を行う	
### 問題発見型		
データに基づき可能な範囲のデータで結果を導く分析を行う	

## アプローチ法
### Dictionary-basedアプローチ
分類の基準を分析者自らが指定し分類するアプローチ

### Correlationalアプローチ
頻繁に発生する言葉を多く含む分類を分析し自発的に発見・分析するアプローチ	
探索的解析のことをテキストマイニングという	

### 統合アプローチによる柔軟性
第一段階で``Correlationalアプローチ``を行いデータを要約・提示する
第二段階で``Dictonary-basedアプローチ``でコーディング規制を図ることで仮説や検証の追及を行う

# ２．備考
## KH Coder
テキストマイニングするためのソフトウェア

--- 
##### 参考文献
黒橋 禎夫 (自然言語処理〔改訂版〕 (放送大学教材))
吉村賢治 (自然言語処理の基礎)
奥野 陽 (自然言語処理の基本と技術)
fletフレームワークの環境構築っぽいなにか（Mac環境）

以下内容は公式ドキュメントから抜粋
https://flet.dev/docs/
https://flet.dev/docs/getting-started/

メインのファイルに以下の記述を記載するだけで使用可能
基本的にはこっちでOK
<pre>import flet as ft</pre>

一式（バージョン情報など）ダウンロードするなら以下の順にコマンドを実行する
<pre>mkdir first-flet-app
cd first-flet-app
python3 -m venv .venv
source .venv/bin/activate
pip install flet
flet --version</pre>

最後にプロジェクトを作成して完了
<pre>flet create project-name</pre>

コマンドを叩き、以下の画面が表示されればOK
デフォルトはアプリ起動のようなので
ブラウザ起動に変更したい場合は「main.py」を修正すれば良い
<pre>flet run</pre>

![スクリーンショット 2024-04-14 12.31.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1389309/f0eec5bf-c84e-01b7-24bd-7ebdbff59311.png)
ジェネリクスのワイルドカード

## ジェネリクスとは
異なるデータ型に対して同じ処理を行うための仕組み。
→データ型ごとにメソッドを作る必要がなくなる


## ワイルドカードとは
より柔軟に扱うための構文。
IntegerはNumberのサブクラスなので
``` java
Number num = Integer.valueOf(10);
```
↑はOK
``` java
List<Number> list = new ArrayList<Number>();  
List<Integer> integerList = new ArrayList<Integer>();  
list = integerList;
```
↑はNG

変数には親クラス型で宣言したものに、サブクラスのインスタンスを格納することができる。
ジェネリクスを使ったものについては、サブクラスのインスタンスを格納することはできない。

### 非境界ワイルドカード型
あらゆる型のオブジェクトを受け入れる型。
`<?>`と記載する。
``` java
List<?> myList = new ArrayList<>();  
List<Integer> list1 = new ArrayList<>();  
List<String> list2 = new ArrayList<>();  
  
myList = list1;  
myList = list2;
```
### 上限境界ワイルドカード型
ある型をサブクラスのみを受け入れる型。
`<? extends E>`と記載する。
``` java
List<? extends Number> myList = new ArrayList<>();  
List<Integer> list1 = new ArrayList<>();  
List<String> list2 = new ArrayList<>();  
  
myList = list1;  
myList = list2;　// error
```

### 下限境界ワイルドカード型
ある型のスーパークラスのみを受け入れる型。
`<? super E>`と記載する。

``` java
List<? super Number> myList = new ArrayList<>();  
List<Object> list1 = new ArrayList<>();  
List<Integer> list2 = new ArrayList<>();  
  
myList = list1;  
myList = list2;　// error
```
【Windows】【MySQL】環境変数の設定

# 目的／背景
WindowsにMySQLをインストールして、PowerShellでバージョン確認を行ったが、コマンドを受け付けなかった。
コマンドを受け付けるように改善したい。

```powershell:MySQLバージョン確認時のエラー
PS C:\> mysql --version
mysql : 用語 'mysql' は、コマンドレット、関数、スクリプト ファイル、または操作可能なプログラムの名前として認識されませ
ん。名前が正しく記述されていることを確認し、パスが含まれている場合はそのパスが正しいことを確認してから、再試行してくだ
さい。
発生場所 行:1 文字:1
+ mysql --version
+ ~~~~~
    + CategoryInfo          : ObjectNotFound: (mysql:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

PS C:\>
```

# 概要
Windowsのシステムプロパティより環境変数を設定し、MySQLコマンドを利用できるようにします。

# 手順１．システムプロパティを開く
Windowsの検索バーにて`sysdm.cpl`を入力実行して、システムプロパティを開きます。
その後、「詳細設定」タブの「環境変数」ボタンを押下します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2628353/77ce6d23-3027-aaf0-ea87-6cede9da11e1.png)

# 手順２．Path編集画面を開く
システム環境変数の「Path」を選択した状態で「編集」ボタンを押下します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2628353/c4a55b26-d311-aaa1-128d-950af9a2c11f.png)

手順３．環境変数にMySQLを追加する
「新規」ボタンを押下し、MySQLの実行ディレクトリを追加します。
 * 実行ディレクトリ：mysql.exeが格納されているディレクトリ

MySQLの実行ディレクトリはデフォルトのままであれば、下記になります。
　`C:\Program Files\MySQL\MySQL Server 8.0\bin`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2628353/bd2458ed-45f0-2985-eaca-fcf18526c98d.png)

追加したら「OK」ボタンを押下してシステムプロパティを閉じます。

# 手順４．PowerShellの再起動
PowerShellを再起動してMySQLコマンドを試してみます。
結果が返ってくれば成功です。

```powershell:再起動後、MySQLコマンドの確認
PS C:\> mysql --version
C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql.exe  Ver 8.0.36 for Win64 on x86_64 (MySQL Community Server - GPL)
PS C:\>
```
SalesforceのSessionIdをPostmanで取得

### 要件
PostmanでSalesforceのログインがさせる。セッションIDを取得する
またSalesforceのSOAPAPIを試す
### Login
#### Step1 URLとヘッダー設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/801991/bc217520-ba55-833c-9c30-8d2d28d8a9a6.png)

※SOAPActionは空白できない。''は可
　URL:　　https://login.salesforce.com/services/Soap/c/59.0

#### Step2 ID/password+Token とTokenの設定
Body部にRawデータでXMLを指定

```
<?xml version="1.0" encoding="utf-8" ?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
  <env:Body>
    <n1:login xmlns:n1="urn:enterprise.soap.sforce.com">
      <n1:username>useridxxxxx</n1:username>
      <n1:password>password+Token</n1:password>
    </n1:login>
  </env:Body>
</env:Envelope>

```
送信したら、ServerURLとSessionIDを貰える

#### QUERY
URLは上と同じ、SessionIDは上のもの
POSTする

```
<?xml version="1.0" encoding="utf-8"?>   
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
   xmlns:urn="urn:enterprise.soap.sforce.com">
  <soapenv:Header>
     <urn:SessionHeader>
        <urn:sessionId>00D4W000000FDql!ARsAQNrUfETTQnROXFeBTbBf2tpwKv_8SvnA4uJjlob9MvUkSoOJt09mc1Y_er45qxJ24jeDsQ_hVjv.RRhY8L21W.EWW4gu</urn:sessionId>
     </urn:SessionHeader>
  </soapenv:Header>
  <soapenv:Body>
     <urn:query>
        <urn:queryString>SELECT id,AccountNumber,Name FROM Account </urn:queryString>
     </urn:query>
  </soapenv:Body>
</soapenv:Envelope>

```
#### Insert
複数Insertの場合、 <urn:updateMru>true</urn:updateMru>
シングルの場合、False

```
<?xml version="1.0" encoding="utf-8"?>   
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:urn="urn:enterprise.soap.sforce.com"
  xmlns:urn1="urn:sobject.enterprise.soap.sforce.com"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Header>
     <urn:SessionHeader>
        <urn:sessionId>00D4W000000FDql!ARsAQNrUfETTQnROXFeBTbBf2tpwKv_8SvnA4uJjlob9MvUkSoOJt09mc1Y_er45qxJ24jeDsQ_hVjv.RRhY8L21W.EWW4gu</urn:sessionId>
     </urn:SessionHeader>
     <urn:MruHeader>
         <urn:updateMru>true</urn:updateMru>
     </urn:MruHeader>
  </soapenv:Header>
  <soapenv:Body>
    <urn:create>
        <urn:sObjects xsi:type="urn1:School__c">
           <Name>Good Shephard Public School</Name>
           <Fees__c>200</Fees__c>
           <School_Address__c>North Carolina</School_Address__c>
           <School_Phone__c>6790985555</School_Phone__c>	
        </urn:sObjects>
          <urn:sObjects xsi:type="urn1:School__c">
           <Name>Sacred Heart Convent School</Name>
           <Fees__c>200</Fees__c>
           <School_Address__c>India</School_Address__c>
           <School_Phone__c>6754328888</School_Phone__c>	
        </urn:sObjects>
          <urn:sObjects xsi:type="urn1:School__c">
           <Name>Nosegay Public School</Name>
           <Fees__c>500</Fees__c>
           <School_Address__c>Jaipur, India</School_Address__c>
           <School_Phone__c>8907654444</School_Phone__c>	
        </urn:sObjects>
    </urn:create>
  </soapenv:Body>
</soapenv:Envelope>
```
[Gemini+LINE Bot] Vertex AI API(GCP)の設定手順

https://linedevelopercommunity.connpass.com/event/310494/

本資料はこちらのイベントの事前準備資料となります。
Geminiを搭載したAI LINE Botを一緒に作りましょう！

**GCP(Google Cloud Platform)のAPI** は今現在Open AI APIと違い**従量課金制**
(24年4月14日現在)
チャージして使うのめんどくさいので、こちらの方が便利ですよね。

用語の説明やおおよその料金体系は[こちら](https://zenn.dev/harappa80/articles/vertexai_gemini)をご覧ください

https://zenn.dev/harappa80/articles/vertexai_gemini

## GCPの設定とクレジット登録

下記のページを開き、コンソールへ移動してください。

https://cloud.google.com/

利用規約を問われたらOKをチェック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/b35e3090-032a-c34b-41c7-feaab64dfb8a.png)

図の通り進めていきます

①
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/3f4b221f-40de-5d49-59a1-a1884da9d829.png)
②
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/8717a5b8-faa9-7e32-4b73-f84973214dda.png)
③
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/0f7eeaa6-a578-52e9-81bd-33bc70e3048f.png)
④
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/d0ddfa6b-5abc-0aaf-f9c3-4b768f2dd2c5.png)

## Vertex AI API設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/a35cffc4-01e0-ffb5-adbf-f5aba7c143f1.png)

``Vertex AI API``を検索して有効にすれば完了

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/50830e32-5e09-e6d6-0a60-3740079504e4.png)

## こんな感じで月末に請求が来ます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/4cb68e23-2f4d-d529-5ecd-d579f0fdb835.png)

料金や用語の説明は[こちら](https://zenn.dev/harappa80/articles/vertexai_gemini)を参照ください

https://zenn.dev/harappa80/articles/vertexai_gemini

https://cloud.google.com/vertex-ai/generative-ai/pricing?hl=ja

事前準備ができたら👇本編へGO！

https://qiita.com/okinakamasayoshi/private/488c66c2c96eb93929e7

## おまけ LINE公式アカウントの作り方

https://qiita.com/okinakamasayoshi/items/bf9593b2af20148c4d19
クローリングとスクレイピング

## クローリング
初めにクローリングについて記載する。

#### クローリングとは
クローリングとは、クローラーというプログラムがリンクをめぐってWebサイトを巡回し、Webページにある情報を複製・保存すること。
Web上からデータを収集する手段の1つ

##### メリット
- 大量のデータを収集できる
ビッグデータ解析をはじめとするデータサイエンス業務などに活かせる
ビジネス展開や、研究機関での資料としても利用できる

- 業務効率の向上
システムを開発すれば自動でデータ収集を行える
より正確なデータの傾向を調べることができる

##### 注意点
- 著作権に触れる可能性がある
- Webサイトへの負荷がかかる

## スクレイピング
続いてスクレイピングについて記載する。

#### スクレイピングとは
取得したデータの解析方法の１つ。
クローリングと併用することでWeb上から特定データの抽出が行える。

##### メリット
- データ活用の効率アップ
自動化を行うことで、データ収集効率を高め、工数を減らすことができる

- Web上からの特定データの抽出
取得したデータのうち必要なデータを抽出することで、不要な情報を除外できる。

##### 注意点
- 収集したデータをそのまま公開や複製すると著作権違反になる可能性がある
- Webサイトへの負荷がかかる
- スクレイピング禁止サイトがある

## クローリングとスクレイピングの併用手順
クローリングとスクレイピングを使用したデータ抽出手順として以下のような流れを行う必要がある。

1. クローリングを使用してURLからデータを取得
1. スクレイピングを使用して取得したデータを解析
1. 必要なデータを抽出
1. ファイルもしくは、標準出力にて出力

簡単ではあるが大まかな流れとしてはこのようになる。
DateTimeクラス

## はじめに

DateTimeクラスに関して整理する。

### DateTimeクラスとは

日付/時刻の演算や整形を行うためのクラス。

### 現在の日付/時刻から生成

```php.datetime_now.php
$now = new DateTime();
print $now->format('Y年m月d日 H:i:s'); // 2024年4月14日 12:00:00
```

### 日付/時刻文字列から生成

```php.datetime_strtotime.php
$now = new DateTime('2024/04/14 12:00:00');
print $now->format('Y年m月d日 H時i分'); // 2024年4月14日 12時00分
```

### タイムゾーンを指定する

```php:datetime_tz.php
$dt1 = new DateTime(null, new DateTimeZone('Asia/Ulan_Bator'));
print $dt1->format('Y年m月d日 H時i分'); //2024年04月14日 10時21分
$dt2 = new DateTime(null, new DateTimeZone('America/Virgin'));
print $dt2->format('Y年m月d日 H時i分'); //2024年04月13日 22時21分
$dt3 = new DateTime(null, new DateTimeZone('Europe/London'));
print $dt3->format('Y年m月d日 H時i分'); //2024年04月14日 03時21分
```

### 年月日、時分秒を個別に設定する

```php:datetime_set.php
$now = new DateTime();
$now->setDate(2024, 4, 14);
$now->setTime(11, 24, 30);
print $now->format('Y年m月d日 H:i:s'); //2024年04月14日 11:24:30
```

### タイムスタンプ値を設定する

```php:datetime_ts.php
$now = new DateTime();
$now->setTimestamp(time());
print $now->format('Y年m月d日 H:i:s'); //2024年04月14日 02:30:56
```

### 日付/時刻値を指定のフォーマットで整形する

```php:Datetime_format.php
$now = new DateTime();
print $now->format('Y年m月d日 (D) g:i:s a'); // 2024年04月14日 (Sun) 2:35:27 am
print $now->format('当月の日数は t 日です。'); // 当月の日数は 30 日です。
print $now->format('L') ? '閏年です。' : '閏年ではありません。'; // 閏年です。
print $now->format(DateTime::RSS); // Sun, 14 Apr 2024 02:35:27 +0000
```

### 日付/時刻文字列を解析する

```php:datetime_fromformat.php
$fmt = 'Y年m月d日 H時i分s秒';
$time = '2024年04月14日 11時39分50秒';
$dt = DateTime::createFromFormat($fmt, $time);
print $dt->format('Y-m-d H:i:s'); // 2024-04-14 11:39:50
```

### 日付/時刻文字値を加算/減算する

```php:datetime_add_sub.php
$dt = new DateTime('2024/4/14 11:42:30');
print $dt->format('Y年m月d日 H時i分'); // 2024年04月14日 11時42分
$dt->add(new DateInterval('P1YT10H'));
print $dt->format('Y年m月d日 H時i分'); // 2025年04月14日 21時42分
$dt->sub(new DateInterval('P3MT20M'));
print $dt->format('Y年m月d日 H時i分'); // 2025年01月14日 21時22分
```

### 日付/時刻値の差分を取得する

```php:datetime_diff.php
$dt1 = new DateTime('2024/4/14 11:42:30');
$dt2 = new DateTime('2024/12/04');
$interval = $dt1->diff($dt2, true);
print $interval->format('%Y年%m月%d日 %H時%i分%s秒'); // 00年7月19日 12時17分30秒
```
Go言語でブロックチェーンのシステムを作成する（その４）

## はじめに
前回は、transactionsの実装までやりましたが、今回はnonceの実装をしていきます。

- 前回までの記事

https://qiita.com/jun_11/items/a1adf93ba02292321b25

https://qiita.com/jun_11/items/259f0a777e12b3fa1b32

https://qiita.com/jun_11/items/61adfc340792cdb2af08

- バージョン
  - Go 1.22.0

## nonceとは
nonceは、新しいブロックを作成する時に、そのブロックが正しいものだと証明するために使われます。
下の図のように新しいブロックを作成する時に、challenge、prev hashとtransactionsを使用してハッシュを生成します。このときchallengeはnonceに入れる候補となる値です。
例えば下の図では、生成したハッシュの先頭が000となるまでchallengeを増やしていって、challengeが10の時ハッシュの先頭が000になったので、challengeの値である10をnonceに入れてブロックを作成します。
今回は、先頭3文字が0になるまで計算する実装にしています。この先頭何文字までが0になるまで計算するかの値をdifficultyと呼び、実際はもっと大きな値が設定されます。
<img width="600" alt="ブロックチェーン5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676504/920cd741-8370-81e0-7033-b56b26d48888.png">

## 実装
### イメージ図
下の図のnonceの実装をしていきます。

<img width="600" alt="ブロックチェーン2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676504/bb0ad399-3d61-1134-2910-054fc889f08d.png">

### nonceの実装
まず、nonceの実装をしていきます。

```golang
const MINING_DIFFICULTY = 3

func (bc *Blockchain) CopyTransactionPool() []*Transaction {
	transactions := make([]*Transaction, 0)
	for _, t := range bc.transactionPool {
		transactions = append(transactions,
			NewTransaction(t.senderBlockchainAddress,
				t.recipientBlockchainAddress,
				t.value))
	}
	return transactions
}

func (bc *Blockchain) ValidProof(nonce int, previousHash [32]byte, transactions []*Transaction, difficulty int) bool {
	zeros := strings.Repeat("0", difficulty)
	guessBlock := Block{0, nonce, previousHash, transactions}
	guessHashStr := fmt.Sprintf("%x", guessBlock.Hash())
	return guessHashStr[:difficulty] == zeros
}

func (bc *Blockchain) ProofOfWork() int {
	transactions := bc.CopyTransactionPool()
	previousHash := bc.LastBlock().Hash()
	nonce := 0
	for !bc.ValidProof(nonce, previousHash, transactions, MINING_DIFFICULTY) {
		nonce += 1
	}
	return nonce
}
```
今回は、difficultyを3として実装するので、MINING_DIFFICULTY=3で定数を定義します。
CopyTransactionPoolでは、Poolにあるtransactionsをコピーしています。
ValidProofでは、引数で受け取ったnonceとpreviousHashとtransactionsを使ってハッシュを生成し、そのハッシュが有効なものか（今回の実装では、生成されたハッシュの先頭3文字が000であるとき有効）を求めています。
ProofOfWorkでは、nonceを1ずつ増やしながら、ValidProofをループさせて実行して、解答となるnonceを求めています。

## おわりに
今回は、nonceの実装をしていきました。
次回は、マイニングの実装をしていきます。

次の記事

https://qiita.com/jun_11/items/f87025c6d801a3b18f1b

# 参考

https://www.udemy.com/course/go-blockchain/?couponCode=ACCAGE0923
libusbのインストール

# 動機
libusb を入門しようとしたのですが、いろいろ躓いた点についてメモとして書いておきます。
# 現状の問題点
”libusb インストール”などと調べると、
```
sudo apt install libusb-1.0-0
```
してね、
と出てくるけど、これがよくない。
公式のGithubにあるExamplesを実行しようとすると、躓いきます。

libusb1.0.27

から、初期化の方法として
```
libusb_init_context(ctx, options, num_options)
```
という関数が追加されたようなのですが、
上記のaptを使ってインストールする方法だと、

libusb1.0.25

が入ってしまっていたようで、Examplesのコンパイルが通りませんでした。
以下に正しいインストール手順を示しておきます。

（参考：実行環境）
```
$: cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.3 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.3 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
```

# ちゃんとGit cloneしたほうがいい
```
$: git clone https://github.com/libusb/libusb.git
（↓いるかわからないけど、一応実行しました。）
$: git checkout tags/v1.0.27 -b V1.0.27
$: ./configure --enable-udev --disable-static
$: make
#: make install
```


　L ./bootstarp.shを実行
　L ./Installを実行
　L ./configureファイルができるので、実行
↓
1.0.27が入る。

バージョンはLIBUSB_API_VERSIONで定義されているので、
printf("%x\n", LIBUSB_API_VERSION);
すればよく、
これから、
https://libusb.sourceforge.io/api-1.0/group__libusb__misc.html#gaabe4bc36a83358685d36a6c853cbb4de
と比較してやれば、バージョンがわかります。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3572881/d6718fff-beab-f289-9085-9c234aba0cd9.png)

注意；
また、一度1.0.25などを入れてしまった場合はautoremoveするなどしておきましょう。

# おまけ
・コンパイルオプション
```
$: gcc testlibusb.c -l usb-1.0
```
エラー対処　You must call JobHandle.Complete()

以下エラーが出た時の解決方法について

InvalidOperationException: The previously scheduled job TriggerVolumePortalSystem:TriggerVolumePortalJob writes to the ComponentLookup<Unity.Transforms.LocalTransform> TriggerVolumePortalJob.JobData.LocalTransformLookup. You must call JobHandle.Complete() on the job TriggerVolumePortalSystem:TriggerVolumePortalJob, before you can read from the ComponentLookup<Unity.Transforms.LocalTransform> safely.

エラーの説明の通り、JobHandle.Complete()する必要があるようですが、
解決に手間取ったため、メモを残します。

私の場合、以下2行実施時にエラーが発生しました。

    var transformLookup = SystemAPI.GetComponentLookup<LocalTransform>();
    var startPosition = transformLookup[_playerEntity].Position;

どうやら、.PositionでEntityの情報にアクセスするのと、既存のJOBの動作が干渉してしまっているようです。

解決としては、

    state.Dependency = new TriggerVolumePortalJob()
    {
        LocalTransformLookup = SystemAPI.GetComponentLookup<LocalTransform>(),
    }.Schedule(state.Dependency);

    [BurstCompile]
    partial struct TriggerVolumePortalJob : IJobEntity
    {
        public ComponentLookup<LocalTransform> LocalTransformLookup;        
        LocalTransformLookup[portalEntity].Position);

のように記述する。
state.Dependency　が肝のようです。海外のUNITYマニュアルとか、Discordの技術トピックとか色々調査しましたが、コードの意味は完全にはわかりませんでした。とりあえずはおまじないだと思って注意していくしかなさそうです。




### もう一つ別パターンで、以下エラーが出た時の対処
ArgumentException: The previously scheduled job DamageCalculateJob writes to the Unity.Entities.EntityCommandBuffer DamageCalculateJob.JobData.ECB2. You must call JobHandle.Complete() on the job DamageCalculateJob, before you can write to the Unity.Entities.EntityCommandBuffer safely.

以下コードの追加により、エラーが回避された。（なお理由は不明...）

    [RequireMatchingQueriesForUpdate]
    [UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
    [UpdateAfter(typeof(PhysicsSystemGroup))]
        public void OnCreate(ref SystemState state)
        {
            state.RequireForUpdate<TriggerDamage>();
            state.RequireForUpdate<SimulationSingleton>();
            state.RequireForUpdate<EndSimulationEntityCommandBufferSystem.Singleton>();
        }

今後勉強が必要だが、一旦メモとして残す。
routerとコントローラを追加してエンドポイントにアクセスしたときにテキストを表示する

こんにちは！
プログラミング未経験文系出身、Elixirの国に迷い込んだ？！見習いアルケミストのaliceと申します。
今回はPhoenixのrouterとコントローラの追加について学んだことをまとめます。2024/4/6に開催したイベント[piyopiyo.ex #29：『Elixir実践入門』を読んでみよう！](https://piyopiyoex.connpass.com/event/312997/)の成果です。

# 目的
エンドポイント/usersにアクセスした時、テキスト`"Hello! This is the result of piyopiyoex #29"`を画面に表示する

## 実行環境
Windows 11 ＋ WSL2 ＋ Ubuntu 22.04
Elixir v1.16.2-otp-26
Erlang v26.0.2

# 仮説
`resources "/users", UserController`をrouterに追加+アクセス時対応する処理を書く。

# 結果
## Phoenixプロジェクト作成
`hello`という名前でPhoenixプロジェクトを作成します。
```bash:bash
mix phx.new hello
cd hello
mix ecto.create
```

## routerにエンドポイントを追加
```diff_elixir:lib/hello_web/router.ex
 scope "/", HelloWeb do
     pipe_through :browser

     get "/", PageController, :home
+    resources "/users", UserController
   end
```

## コントローラへアクセスした時に何をしてほしいか(index関数)を追加
```diff_elixir:lib/hello_web/controllers/user_controller.ex
defmodule HelloWeb.UserController do
  use HelloWeb, :controller

  def index(conn, _params) do
    text(conn, "Hello! This is the result of piyopiyoex #29")
  end
end
```

## できました(^▽^)/
```bash:bash
mix phx.server
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677280/3d9381f0-2aeb-5b9f-d208-933d0eb2a179.png)



# ～Elixirの国のご案内～
↓Elixirって何ぞや？と思ったらこちらもどぞ。Elixirは先端のアレコレをだいたい全部できちゃいます:laughing::sparkles::sparkles:

https://qiita.com/piacerex/items/09876caa1e17169ec5e1

↓ゼロからElixirを始めるなら「エリクサーチ」がおすすめ！私もエンジニア未経験から学習中です。

https://elixir-lang.info/topics/entry_column


↓[We Are The Alchemists, my friends!:bouquet:](https://qiita.com/torifukukaiou/items/6bcd5bbb80df9e594e9e "Awesome-san's Awesome article")[^10]
Elixirコミュニティは本当に優しくて温かい人たちばかり！
私が挫折せずにいられるのもこの恵まれた環境のおかげです。
まずは気軽にコミュニティを訪れてみてください。[^11]


https://speakerdeck.com/elijo/elixirkomiyunitei-falsebu-kifang-guo-nei-onrainbian




[^10]: @torifukukaiouさんのAwesomeな名言をお借りしました。Elixirコミュニティを一言で表すと、これに尽きます。


[^11]: @kn339264さんの素敵なスライドをお借りしました。Elixirコミュニティはいろんな形で活動中！
未経験で覚えといてよかったLinuxコマンド集

LPICは保有していないけど
LinuCレベル1は持っているので今日はいくつかやっといてよかったと思ったコマンドを紹介していこうと思います。




| コマンド名 | 説明 |
|:-:|:-:|
| cd  |  指定したディレクトリに移動します。cdコマンドのあとにディレクトリの指定がない場合はhomeディレクトリに移動します。 |
|  cc |  ソースファイルをコンパイルする(コンパイル＝機会でも読める言葉にコードを翻訳すること) |
|  cat |  テキスト・ファイルの内容を閲覧する＜使用例＞$cat file1 file2 > file3→file1とfile2の内容を連結してfile3に出力する |
|  chmod | ファイルやディレクトリへのアクセス権限を変更する→使用には注意が必要　  |
| cp  | 指定したファイルやディレクトリをコピーする  |
| grep (超重要) | 文字列を検索する ＜使用例＞$grep "Hello" file1→file1 ファイルから Hello という文字列を検索する。$grep -ci "Bye" file2→file2 ファイルから Bye がある行数を表示する。  |
|  ls(よく使う) | ファイルやディレクトリの情報を表示する ＜使用例＞$ls　dir1 dir2 dir3 file1.txt command.txt …→現在アクセスしているディレクトリ内のファイルがすべて表示される。|
|  mkdir | ディレクトリを作成する  |
| pwd  | 自分が今どのディレクトリにいるのかを教えてくれる  |
| rm  |   ファイルを削除する |
|  vi | テキストエディタを開く |
|  mv | ファイル移動や名前の変更を行う  |



この中でもvi ls grep cat mkdir rm はほんとによく出てきます
例えば一時的にインストールしたいソフトがあって一時的な保存場所としてディレクトリを作成します。
そこにファイルを入れてインストールし終わったらrmで削除


例えばRedhatの場合だとyumでインストールします
そしてこの時yumが見に行っている場所を変えたいときに
viコマンドを使ってここを見に行ってね！と指示を出します
yum君が持ってる宝の地図の内容をviコマンドで変えていくイメージです。
これがディストリビューションによってyum君じゃなくてapt君だったりします

::: note 
ディストリビューションについて簡単に認識だけ説明すると
OSが国だとしたらディストリビューションは地方です。
Linux国Redhat地方のyum君とLinux国Ubuntu地方のapt君みたいな感じで覚えといてください。
:::


viの書式などは手順書に書いてくれると思うので見て学びましょう

来週はViで使えるコマンドを書こうと思います。
AWSリソースをTerraformにImportする（SecretsManager関連）

# 前提
[全体の概略はこちらから](https://qiita.com/hrkkanda/items/1ef47fd6213547396c99)

# 構成図

👆の図のように、
- SecretsManagerで管理するのは、RDSProxyが使うDB認証とLambdaが使うDB認証。

# 環境構築用のmain.tf, variable.tf
## main.tf
```tf
# secret used by application
resource "aws_secretsmanager_secret" "dbstring" {
  name          = "${var.project}-${var.env}-db-connection-string"
  description   = "PGconnection string will be used for connecting to database"
  tags = {
    Env     = var.env
    Account = var.account
    Project = var.project
  }   
}
# secret used by rds proxy
resource "aws_secretsmanager_secret" "dbpw" {
  name          = "${var.project}-${var.env}-db-connection-pw"
  description   = "RDSProxy"
  tags = {
    Env     = var.env
    Account = var.account
    Project = var.project
  }   
}
```
## variable.tf
```tf
# common variable 
variable "project" {
    type        = string
    description = "project name"
}
variable "account" {
    type        = string
    description = "prod or no-prod"
}
variable "env" {
    type        = string
    description = "dev, test, stage or prod"
}
```
## outputs.tf
```tf
output "secretsmanager_dbstring_arn"{
  value       = aws_secretsmanager_secret.dbstring.arn
  description = "arn of secrets manager' secret used by application"
}
output "secretsmanager_dbpw_arn"{
  value       = aws_secretsmanager_secret.dbpw.arn
  description = "arn of secrets manager' secret used by rds proxy"
}
```

## 設計思想
- importする場合、secret情報そのものはtfファイルに記載しない。
    （outputs.tfで他リソースから利用できさえすればいい）
- **最初からterraform でインフラ構築する場合、注意が必要！**
cscの作法 その490

# 概要
cscの作法、調べてみた。
練習問題やってみた。

# 練習問題
closedxmlで、テンプレートに書き込め。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/febcfb6c-8b7b-a750-3187-d1c56f82c831.png)

# サンプルコード

```

using System;
using System.IO;
using ClosedXML.Excel;

namespace App
{
	class Program {
		static void Main(string[] args) {
			var filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Book3.xlsx");
			var wb = new XLWorkbook("red.xlsx");
			IXLWorksheet sheet1;
			if (wb.TryGetWorksheet("Sheet1", out sheet1))
			{
				Console.WriteLine(sheet1.Name);
			}
			else
			{
				Console.WriteLine("ワークシートを取得できませんでした。");
			}
			sheet1.Cell("b5").Value = "相田株式会社";
			sheet1.Cell("b7").Value = "開発部御中";
			sheet1.Cell("b18").Value = "サーベル";
			sheet1.Cell("e18").Value = "1";
			sheet1.Cell("f18").Value = "本";
			sheet1.Cell("g18").Value = "12500";
			wb.SaveAs(filePath);
			Console.WriteLine("ok");
		}
	}
}



```

以上。
yarn v4で立ち上げたnextプロジェクトでvscodeのtsエラーが出る

表題の通りの現象への対処メモです。
yarn v4で`yarn create next-app`したプロジェクトにおいて画像のような状態になっていました。

![スクリーンショット 2024-04-14 10.53.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2835473/b60ca6f3-c47a-58ae-2937-24399d7ab5b7.png)

## 問題の切り分け
ビルドは問題なくできるのでエディターの問題です。

調べてみるとVSCodeはデフォルトで`node_modules`を参照して型情報を取得するのですが、yarn v2以上はPnPという仕組みで`node_modules`フォルダを作らず依存関係の解決をするようになっているようで、ここが原因になっていそうです。

## 解決方法
yarnの公式ドキュメントに解決方法がありました。
https://yarnpkg.com/getting-started/editor-sdks#vscode

内容そのままですが、[案内されている拡張](https://marketplace.visualstudio.com/items?itemName=arcanis.vscode-zipfs)を入れて、次のコマンドを実行すれば良さそうです。
```sh
yarn dlx @yarnpkg/sdks vscode
```

設定ファイルが色々生成され、エディタ上のエラーがなくなっていることが確認できました。
AWS コミュニティAMIを使用してみた

## はじめに
初めて検証用にコミュニティAMIを使用したため、使用後の料金を記事に投稿します

## 手順
**EC2を作成する際に以下の画面からコミュニティAMIを選択する**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/a16a43de-c231-f0a4-2cdb-44dac56ccdb0.png)

**EC2を起動しましたが、特に料金の表示はありませんでした**
料金が気になります。

EC2起動後、選択したAMI名が表示されました。コミュニティAMIを選択しましたが、marketplaceになっていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/1ebb09f8-7828-007d-b00c-a81d4285a4aa.png)

**メールが届いていました**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/52d7a4f8-1eec-8eac-5a2e-e6eb08798ad1.png)

**サブスクリプションの管理を確認しました**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/13e3af21-fb32-9f26-e4af-b1d6ca39fe13.png)

**今回使用したAMIの料金を確認しました**

料金モデルをクリックしました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/094db9c0-2c01-f323-bfeb-eb59fb4cbd94.png)

**コスト見積もり**
1時間当たり0.03ドル(4.60 円)+EC20.012ドル(1.84円)=合計6.9円であることを確認しました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/fd90bef3-6329-74d8-7767-0ac9219279bf.png)

**料金の予想**
EC2を1台立てて1時間19分使用しています。
```
$ uptime
 10:59:48 up  1:19,  1 user,  load average: 0.00, 0.01, 0.05
```
おそらく5円程度の料金がかかると予想します。


**実際は0.06ドル(9.47円)料金がかかりました**
見積もりは6.9円ですが値段が3円ほど上がっていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/4749b113-23f2-b600-8d17-3248da85063a.png)


使った分だけ課金のため、翌月からコミュニティAMIの料金はかからなくなりました。



## まとめ
コミュニティAMIを購入したらAWSサービス AWS Marketplace＞サブスクリプションの管理のページに
契約したAMIが表示されることを知りました
上記のページで詳細の契約と料金を確認できます。
OpenAIの画像生成Dall-E3を使うPythonコード

# 環境
M1 Mac 13.4.1
Visual Studio Code 1.87.0
python 3.11.3

ライブラリ
openai 1.12.0

# Visual Studio Codeのインストール

https://code.visualstudio.com/

左端の「拡張メニュー」から、
日本語化のインストールと、
pythonのインストールを行った。

# pythonとpipのインストール
ターミナルからpythonが入っていることを確認する。
入っていなければ、[pythonのインストール](https://www.python.org/downloads/macos/)と、[pipのインストール](https://qiita.com/sho03/items/bafdf19592f6f9d71135)を行う。
```
python --version
```
```
python 3.11.8
```

# OpenAIライブラリのインストール
```
pip install openai
pip install --upgrade openai
pip show openai
```
Version: 1.12.0

# OPENAI_API_KEYの設定
OpenAIのトークンはチャージ（課金）しておく。
$5チャージした。
Visual Studio Codeの機能で、launch.jsonファイルを作成する。
openaiサイトで、OPENAI_API_KEYを発行し、
launch.jsonファイルを、下記のように編集する。
```json:launch.json
{
    "version": "0.2.0",
    "configurations": [
        
        {
            "name": "Python デバッガー: 現在のファイル",
            "type": "debugpy",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "env": {
                "OPENAI_API_KEY": "ここに自分のOPENAIのキーを入れる",
            },
        }
    ]
}
```

# 画像の生成pythonコード
```python:dalle.py
from openai import OpenAI
client = OpenAI()

response = client.images.generate(
  prompt="a white siamese cat",
  size="1024x1024",
  quality="standard",
  n=1,
)

image_url = response.data[0].url
print(image_url)
```
F5で実行して、５秒ほど待つと、URLらしきものが出る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/9f31d337-f34f-4568-9ddf-4ef94304a206.png)

アクセスすると、画像を確認することができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/b730ee00-a71c-bdb7-2559-5cf688f877f7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/7b0fb608-bc48-9efa-297c-6487c66449b3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/75d67909-8df5-4266-926d-2424c3552f9c.png)

# 日本語プロンプトでもOK
　一応できるけど、なんか思ってたのと違う気が。

「カフェで二人の女の子が、パフェを食べているイラスト」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/b6915942-03a7-641c-c82f-c7f2abec6287.png)
「おしゃれなカフェで友人とゆっくり過ごしているイラスト調の絵を描いて」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/bc4a739e-a345-3a7a-2fe0-e1640ecc6885.png)


# 費用
　1回の生成で0.02ドル使った。

# 参考サイト

https://platform.openai.com/docs/guides/images?context=python