OmniAICreator/Qiita-1.07M huggingface dataset:
【ローカルLLM】Windows11,WSL2上でのllama-cpp-python環境構築(CPU/GPU利用)

# 概要
ローカルLLMをPython環境で使ってみたかったので環境構築。

llama-cpp-pythonをWSL上の仮想環境で動かそうとしたら、GPU使用の部分でだいぶハマったので自分用にメモ。(2024/8/26)
URL:(https://github.com/abetlen/llama-cpp-python)
## 環境
OS:Windows11 64bit
CPU:Intel Corei9 13900k
GPU:RTX4090 24GB
WSL:2.2.4.0 (Ubuntu22.04)
CUDA Toolkit:12.2
NVIDIA Driver:560.94
Python:3.12.3
rye:0.39.0

## CPU版のインストール
CPUで使用する場合CUDA等は必要ありません。
WSLを立ち上げて、pip installするだけです。
```terminal:
$ wsl 
$ . .venv/bin/activate #仮想環境のアクティベート
$ Python3 -m pip install llama-cpp-python 
```
※pip installできない場合は、パッケージとPythonのバージョンが対応しているか確認してください。
#### モデルのダウンロード
[Hugging Face](https://huggingface.co/)からGGUF形式のものをダウンロードする
目当てのモデルのGGUF形式が無い場合は、[llama.cpp](https://github.com/ggerganov/llama.cpp)にGGUF変換の説明があります。
今回は[こちら](https://huggingface.co/meta-llama/Meta-Llama-3.1-8B-Instruct)をGGUFに変換したものを使用しました。

#### 動作確認 （モデルのロードに結構時間がかかります）
```python:demo_cpu.py
from llama_cpp import Llama
llm=Llama(model_path="/path/*.gguf")
```
無事に終了すればOKです。
## GPU版のインストール
#### NVIDIA Driverのバージョン確認
```terminal:
$ nvidia-smi
```
※表示されているCUDA Versionが対応しているか確認してください。表示されているCUDA Version以下であれば対応しています。
#### CUDA Toolkitのバージョン確認
※WSLではNVIDIA DriverはWindowsと共通ですが、CUDAやcuDNNは新たに別でインストールする必要があります。
```terminal
$ wsl
$ . .venv/bin/activate
$ nvcc -V
```
＜確認＞
cudaを新たにインストールした場合は再起動する。
versionが出ない場合、~/.bashrcにPATHが通っているか確認する。

念のため、torchでCUDAが使えるか確認 (飛ばしてもOK)
```python:cuda_test.py
from torch
print(torch.cuda.is_available())
```
```terminal
True 
```
Falseが出る場合
```terminal
$python3 -m pip show torch
```
でcuda対応versionか確認する。
#### llama_cpp_pythonのインストール
```terminal:
$ CMAKE_ARGS="-DGGML_CUDA=on -DLLAVA_BUILD=off" pip install --upgrade --force-reinstall llama_cpp_python
```
#### 動作確認
```python:demo_gpu.py
from llama_cpp import Llama
llm = Llama(model_path="/path/*.gguf", n_gpu_layers=10)
```
実行時にGPU名、CUDAの表記、BLAS=1等が出ていればOK
```terminal
---------
llama_new_context_with_model:  CUDA_Host  output buffer size =     0.49 MiB
llama_new_context_with_model:      CUDA0 compute buffer size =   669.48 MiB
llama_new_context_with_model:  CUDA_Host compute buffer size =     9.01 MiB
llama_new_context_with_model: graph nodes  = 1030
llama_new_context_with_model: graph splits = 356
AVX = 1 | AVX_VNNI = 1 | AVX2 = 1 | AVX512 = 0 | AVX512_VBMI = 0 | AVX512_VNNI = 0 | AVX512_BF16 = 0 | FMA = 1 | NEON = 0 | SVE = 0 | ARM_FMA = 0 | F16C = 1 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 1 | SSE3 = 1 | SSSE3 = 1 | VSX = 0 | MATMUL_INT8 = 0 | LLAMAFILE = 1 |
---------
```
#### （おまけ）なぞなぞを試してみた結果
```python:Riddle.py
from llama_cpp import Llama
llm = Llama(model_path="./path/*.gguf", n_gpu_layers=10)
out=llm("Q:朝は四本足、昼は二本足、夕は三本足。この生き物は何か？ A: ")
pritn(out)
```

```terminal:out
'choices': [{'text': ' これはイカ。イカは朝にtentacleを伸ばす', 
```
まさかのイカ、、、イカ？？？

<img width="200" src="https://tegakisozai.com/wp-content/uploads/2020/03/mizunoikimono_ika_ao.png">
【競技プログラミング】pypyjitが無い環境でも再帰のおまじないを書きたい

# 競プロで再帰処理をPyPyで提出する時
AtCoderにおいてPython言語で提出する時、ほぼ全ての処理はPythonよりPyPyで提出した方が処理時間が速い。
ただ、再帰処理においてはPythonの方が速い傾向にある。
そこでPyPyでも処理を速くするためのおまじないがある。
```python
import pypyjit
pypyjit.set_param('max_unroll_recursion=-1')
sys.setrecursionlimit(10**7)
```
この三行を書くとPyPyでも再帰を高速に実行することができる。
だがこれをマクロに含めてしまうと、PyPyではない環境でコンテストに出ている時にimport出来なくてデバッグがやりづらい。
そして、これを外してデバッグして提出する時に忘れることも多い。
これを解決したい。
# 解決策：このファイルをローカルに用意する
```python:pypyjit.py
def set_param(st): pass
```
pypyjitが無ければ作ってしまえば良いじゃない。
このファイルを用意することで、マクロにおまじないを含めて置くことが出来る。
以上で再帰処理の時に考えることを増やさないで済んだ。
快適な競プロライフを～
まとめ用のブランチの作り方

# 概要
- 複数人で開発してて共通のコードベース利用したいとか、リリースブランチ作成したいとか
- 今の今までぱっとやり方思いつかなかったが、色々探して試したところできたのでメモ

# 方法

1. 最新のコードからbranchを切る（mainとかdevelopとか）
1. 空コミットを用意する
1. GitHub上でPR作成
1. 他PRの向き先を3に変更する

## 空コミットの用意

```bash
$ git commit --allow-empty -m "Initialize integration branch"
```

最新のところから切るだけじゃ差分ができない = PRが作成できないため差分を作らなきゃとなり、一部だけ変更するのもよくわからんなーと思っていたが、こんな方法があるなんて知らなかった
VSCodeで複数のウィンドウを1つにまとめる機能

:::note warn
mac限定の機能です
:::

VSCode (というよりmacOS) には複数のウィンドウを1つにまとめる機能があります．普段VSCodeのウィンドウが迷子になるエンジニアには大変おすすめの機能です

設定は非常に簡単です．`settings.json`に次の項目を追加します
```jsonc
{
  "window.nativeTabs": true,
}
```

複数のウィンドウを開いた状態で，ツールバーの **Window > Merge All Windows** を実行すれば全てのウィンドウを統合できます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291419/bc7579fa-89aa-d720-ec3f-b2781db3b6e3.png)

統合するとウィンドウがタブとして画面上部に表示されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291419/214a08f2-8360-fd74-1f78-e016dd425e66.png)


ウィンドウ間の切り替えをショートカットに登録しておくと便利です．`keybindings.json`の次の項目で設定できます
```jsonc
[
    {
        "key": "alt+[",
        "command": "workbench.action.showPreviousWindowTab"
    },
    {
        "key": "alt+]",
        "command": "workbench.action.showNextWindowTab"
    }
]
```

追加で`settings.json`にこのへんも書いておくと便利です
```jsonc
{
    // 画面上部がごちゃごちゃになるのでタイトルバーを非表示にする
    "window.customTitleBarVisibility": "never",
    // 現在アクティブなウィンドウが上書きされてしまうので新しいウィンドウで開くようにする
    "window.openFoldersInNewWindow": "on",
    // ファイルであれば現在のウィンドウで開いて問題ない
    "window.openFilesInNewWindow": "off"
}
```

## おまけ

VSCodeのターミナル上であれば，`code`コマンドを実行した際に別のタブとしてディレクトリを開けます．たいへんに操作感が良いです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291419/766994ef-d655-2c42-8270-c1ff20cb74be.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291419/068bfeca-cfd9-c243-2363-354546a44130.png)

ちなみに`code`コマンドに`-a`オプションを指定すると，ディレクトリをワークスペースとして開くことができます．上手く使い分けましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291419/54faea3a-ad4b-edc5-e6d7-abd4792076f3.png)

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291419/ea45a8c2-1c84-40d2-b3ca-9d729256f5a8.png' width='350px' />
【PostgreSQL】ローカルだと問題ないのに本番環境になると接続できなくなる

こんにちは、laravelで開発中の初心者です。
PostgreSQLを本番環境にデプロイしたいです。

そんなかエラーになってしまいました。

![スクリーンショット 2024-08-27 1.52.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3797858/4c7b4965-69a3-a24d-a9c6-85c8ba2940f1.png)

- 使用言語
laravel
- 使用サーバー
Vercel
PostgreSQL


**今回のエラー**
```
Could not run query. Error: SQLSTATE[HY000][2002]No such file or directory 
(Connection: mysql, SQL: select * from `users`)
```
アプリケーションがMySQLに接続しようとしているが、接続が失敗していることが分かります。

**問題**
ローカル環境だとDB接続されるのですが、本番環境はエラーが出てしまいます。
ローカルで動いているのでファイルは特に何も間違っていないと思います。



誰か助けてください😭


【解決】
vercel.jsonを変更したらデプロイできました。

```
"env": {
        "APP_NAME": "Laravel Vercel",
        "APP_DEBUG": "true",
        "DB_CONNECTION": "pgsql",
        "DB_HOST": "YOUR_HOST_NAME",
        "DB_PORT": "5432",
        "DB_DATABASE": "verceldb",
        "DB_USERNAME": "default",
        "DB_PASSWORD": "YOUR_PASSWORD",
        "APP_CONFIG_CACHE": "/tmp/config.php",
        "APP_EVENTS_CACHE": "/tmp/events.php",
        "APP_PACKAGES_CACHE": "/tmp/packages.php",
        "APP_ROUTES_CACHE": "/tmp/routes.php",
        "APP_SERVICES_CACHE": "/tmp/services.php",
        "CACHE_DRIVER": "array",
        "LOG_CHANNEL": "stderr",
        "SESSION_DRIVER": "cookie",
        "VIEW_COMPILED_PATH": "/tmp/views",
        "SSR_TEMP_PATH": "/tmp/ssr",
        "NODE_PATH": "node"
    }
```
Build Meetup in Tokyo on Sept 9, 2024

EngFlow is partnering with Google to host a Build Meetup in Tokyo. It's an event that focuses on build systems, CI/CD, DevOps, and more. We'd love to see you there!

🗓️ Date: September 9, 2024
🕓 Time: 16:00 - 19:00 JST
🗺️ Location: Google Japan - Shibuya
3 Chome-21-3 Shibuya, Shibuya City, Tokyo 150-0002, Japan

Register here: https://forms.gle/YQ4uhUnhGYC54m568
Go言語(Golang)のスライス、マップ　まとめ

### スライスの概要

スライスは、Go言語における動的な配列を扱うデータ構造です。スライスは固定長の配列と異なり、要素の追加や削除が可能で、サイズを動的に変更できます。スライスは配列への参照として実装されているため、配列の一部を取り扱うこともできます。

### スライスの宣言と初期化

スライスの宣言と初期化の方法は以下の通りです。

```go
package main

import "fmt"

func main() {
    // 空のスライスを宣言
    var s1 []int
    fmt.Println(s1) // []

    // リテラルでスライスを初期化
    s2 := []int{1, 2, 3}
    fmt.Println(s2) // [1, 2, 3]

    // make関数でスライスを作成
    s3 := make([]int, 5) // 長さ5のスライスを作成
    fmt.Println(s3) // [0 0 0 0 0]
}
```

### スライスの操作

スライスに対する基本的な操作を以下に示します。

```go
package main

import "fmt"

func main() {
    s := []int{1, 2, 3, 4, 5}

    // 要素のアクセス
    fmt.Println(s[0]) // 1

    // 要素の変更
    s[1] = 10
    fmt.Println(s) // [1 10 3 4 5]

    // スライスの一部を取得
    sub := s[1:4]
    fmt.Println(sub) // [10 3 4]

    // スライスの追加
    s = append(s, 6, 7)
    fmt.Println(s) // [1 10 3 4 5 6 7]
}
```

### スライスの内部構造

スライスは以下の3つのフィールドで構成されています。

1. **ポインタ**: 配列の先頭要素へのポインタ。
2. **長さ**: スライスの要素数。
3. **容量**: スライスが参照する配列の最大要素数。

この構造により、スライスは効率的にメモリを管理し、動的なサイズ変更が可能です。

---

## マップ (Maps)

### マップの概要

マップは、キーと値のペアを管理するデータ構造で、他の言語でいうところのハッシュテーブルや辞書に相当します。キーを使って迅速に値を検索、追加、削除することができます。

### マップの宣言と初期化

マップの宣言と初期化の方法は以下の通りです。

```go
package main

import "fmt"

func main() {
    // 空のマップを宣言
    var m1 map[string]int
    fmt.Println(m1) // map[]

    // make関数でマップを作成
    m2 := make(map[string]int)
    fmt.Println(m2) // map[]

    // リテラルでマップを初期化
    m3 := map[string]int{
        "apple":  5,
        "banana": 10,
    }
    fmt.Println(m3) // map[apple:5 banana:10]
}
```

### マップの操作

マップに対する基本的な操作を以下に示します。

```go
package main

import "fmt"

func main() {
    m := map[string]int{
        "apple":  5,
        "banana": 10,
    }

    // 値の取得
    fmt.Println(m["apple"]) // 5

    // 値の追加・更新
    m["orange"] = 8
    fmt.Println(m) // map[apple:5 banana:10 orange:8]

    // 値の削除
    delete(m, "banana")
    fmt.Println(m) // map[apple:5 orange:8]

    // 値の存在確認
    value, exists := m["apple"]
    if exists {
        fmt.Println("apple exists:", value) // apple exists: 5
    } else {
        fmt.Println("apple does not exist")
    }
}
```

### マップの内部構造

マップはハッシュテーブルを基に実装されており、キーを迅速に見つけるためにハッシュ関数を使用します。これにより、キーの検索、追加、削除が平均的にO(1)の時間で行われます。

### まとめ

- **スライス**: 動的な配列で、サイズの変更や部分配列の取得が可能。
- **マップ**: キーと値のペアを効率的に扱うデータ構造で、迅速な検索、追加、削除が可能。
インターネットG/W経由のEC2とS3間の通信がインターネットを経由するかどうか

特に設定を変更しない場合に EC2 インスタンスから S3 や DynamoDB などのパブリックなサービスエンドポイントを持つ AWS サービスとの通信は、VPC に紐づく Internet G/W 経由でおこなわれます。この時、通信はインターネットを経由するのかという質問をたまに受けます。

この質問の回答は、AWS の次のドキュメントを読むと分かります。

https://docs.aws.amazon.com/ja_jp/vpc/latest/privatelink/privatelink-access-aws-services.html

下図に示す通り、EC2 インスタンスから S3 への通信は Internet G/W を通過しますが、AWS グローバルネットワーク内で処理されます。この通信は、パブリック IP を使用しておこなわれますが、物理的にインターネットを経由しません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2210265/103e0492-4cf8-0cfa-46bc-3d74468507ca.png)

Amazon VPC の [FAQ](https://aws.amazon.com/jp/vpc/faqs/) にも次のように書かれています。

> **2 つのインスタンスがパブリック IP アドレスを使用して通信する場合、またはインスタンスがパブリックな AWS のサービスエンドポイントと通信する場合、トラフィックはインターネットを経由しますか?**
> 
> いいえ。パブリック IP アドレスを使用する場合、AWS でホストされているインスタンスとサービス間のすべての通信は AWS のプライベートネットワークを使用します。AWS ネットワークから発信され、AWS ネットワーク上の送信先を持つパケットは、AWS 中国リージョンとの間のトラフィックを除いて、AWS グローバルネットワークにとどまります。
> 
> さらに、データセンターとリージョンを相互接続する AWS グローバルネットワークを流れるすべてのデータは、安全性が保証された施設を離れる前に、物理レイヤーで自動的に暗号化されます。すべての VPC クロスリージョンピアリングトラフィックや、カスタマーまたはサービス間のトランスポート層セキュリティ (TLS) 接続などといった追加の暗号化レイヤーもあります。 

クロスアカウントのシナリオでも、同様に AWS グローバルネットワーク内で処理されるため、通信はインターネットを経由しません。

但し、このことがドキュメントへ記載されるようになったのは 2021 年頃からであり、それ以前の状況については具体的な情報が不足しています。

VPC　から S3　への通信はインターネットを経由しませんが、VPC　内からのみの接続が必要な場合はインターネットからの接続を防ぐために VPC エンドポイントを設定することをおすすめします。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/access-points-vpc.html

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/privatelink-interface-endpoints.html

クロスアカウントのシナリオでは、VPC Peering　と併用する必要があります。但し、ゲートウェイエンドポイントは利用できない点に注意が必要です。

https://docs.aws.amazon.com/ja_jp/vpc/latest/peering/vpc-peering-basics.html#vpc-peering-limitations
Firebase Cloud FunctionsでのPython環境セットアップとエミュレータ起動手順

## はじめに
FlutterアプリからPythonコードを呼び出して実行する手段として、Firebase Cloud Functionsを利用する機会がありました。しかし、FunctionsのPythonに関する記事は少なく、セットアップ方法も複雑であるため、苦労していました。インターン先でサポートしていただきながら、なんとかセットアップすることができたので、注意点も交えながら紹介したいと思います。また、Firebase Cloud Functionsを用いた開発においては、エミュレータの使用が不可欠であることも実感したのでエミュレータの起動手順も説明したいと思います。

## 1. Firebase Cloud FunctionsでのPython環境セットアップ方法

セットアップの主な流れは以下の通りです：

1. `firebase init` を実行する
2. `requirements.txt` と `main.py` を作成する（必要なライブラリは全て `requirements.txt` に記述）
3. `requirements.txt` に記載されたライブラリを `pip install` する（←※）

※`firebase init` 時に自動生成される仮想環境（venv）は、デプロイ時に自動更新されません。`requirements.txt` を変更した場合、以下のいずれかの対応が必要です。
方法１： `firebase init` を再実行する
方法２：　venvフォルダを削除して`pip install`を実行する

以下に2つの方法を詳しく説明します。
### 方法１（firebase initしなおす）
(1) `firebase init` を実行し、必要な設定を行います。
    (Functions, Storage, Emulators などの使用するサービスを選択します)
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/a492d487-9798-2282-c7fb-ac1e995b1930.png)
![b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/c2d0645a-7cac-0818-3429-449094757dde.png)

(2) 既存のファイルを上書きするかどうかを選択します。
```shell
? Would you like to initialize a new codebase, or overwrite an existing one? Overwrite

Overwriting codebase default...

? What language would you like to use to write Cloud Functions? Python
? File functions/requirements.txt already exists. Overwrite? No
i  Skipping write of functions/requirements.txt
? File functions/.gitignore already exists. Overwrite? No
i  Skipping write of functions/.gitignore
? File functions/main.py already exists. Overwrite? No
i  Skipping write of functions/main.py
? Do you want to install dependencies now? Yes
```
注意：requirements.txt は上書きしないでください。上書きすると、デフォルトの内容のみになってしまいます。

(3) エミュレータの設定を行います。

![c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/5a288bb6-984e-e5b2-23ad-99591422eb82.png)

```
? Would you like to download the emulators now? Yes
```

### 方法2：venvフォルダを削除してpip installを実行する
(1) 以下のコマンドを実行して、新しい仮想環境を作成し、必要なライブラリをインストールします。

```
cd functions
python3.12 -m venv venv
source venv/bin/activate
pip3 install --upgrade pip
python3.12 -m pip install -r requirements.txt
deactivate
```

## 2. エミュレータを起動する

エミュレータは以下のコマンドで起動できます
```
firebase emulators:start
```

エミュレータでは、Storageを使用したり、Logを確認したりできます。
![e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/a8749d6d-5cd3-60d5-4909-8256ceaf258c.png)
![d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/18f7b52c-c1d5-fdb4-5972-b9c93f6181be.png)

## 3. デプロイ
エミュレータでの動作確認ができたら、最後に以下のコマンドでデプロイします。
```
firebase deploy --only functions:関数名
```

## まとめ
Firebase Cloud FunctionsでPython環境をセットアップではデプロイ時にrequired.txtが更新されないのがキーでしたね。
また、エミュレータを使用することで、効率的な開発が可能になります。
本記事で紹介した手順がスムーズな開発環境の構築に役立てたら幸いです。
シングルクォート・ダブルクォートを含む文字列の出力あれこれ

## はじめに

xml データを以下コマンドによりファイルに出力した際、**データ中のダブルクォートが削除されていた**という意図せぬ挙動になったので、その原因と対応策についてメモしたいと思う。

コマンドは以下:

```sh
echo "ダブルクォートを含む xml データ" > file.xml
```

## TL;DR

- 内容にダブルクォートが含まれる場合は、シングルクォートで囲む
- 内容にシングルクォートが含まれる場合は、ダブルクォートで囲む
- 内容にシングルクォートとダブルクォート両方が含まれる場合は、ヒアドキュメントを利用する

## ダブルクォートが含まれる場合

ダブルクォートのみが含まれる内容の時は、シングルクォートで囲むことで、正常に出力される。

```sh
echo 'this is a "pen"' > file

cat file
# this is a "pen"
```

ダブルクォートをダブルクォートで囲むと、`"` がなくなってしまう。

```sh
echo "this is a "pen"" > file

cat file
# this is a pen
```

## シングルクォートが含まれる場合

シングルクォートのみが含まれる内容の時は、ダブルクォートで囲むことで、正常に出力される。

```sh
echo "this is a 'pen'" > file

cat file
# this is a 'pen'
```

シングルクォートをシングルクォートで囲むと、`'` がなくなってしまう。

```sh
echo 'this is a 'pen'' > file

cat file
# this is a pen
```

## シングル/ダブルクォーテーションが両方含まれる場合

### そのまま出力

この場合は少し特殊で、単純な echo や cat コマンドでは対応できなかったため、ヒアドキュメントを利用する。[^1]

[^1]: 中身のダブルクォートをエスケープすることで、このようなやり方をせずとも目的を達成できるのだが、ここでは元のデータをいじらないことに重きを置くことにする。


```sh
cat <<EOF  > file
this is a "pen" and that is an 'eraser'
EOF

cat file
# this is a "pen" and that is an 'eraser'
```

### ダブルクォートに寄せる

```sh
cat file
# this is a "pen" and that is an 'eraser'

cat file | sed "s/'/\"/g" > file

cat file
# this is a "pen" and that is an "eraser"
```

### シングルクォートに寄せる

```sh
cat file
# this is a "pen" and that is an 'eraser'

cat file | sed "s/\"/'/g" > file

cat file
# this is a 'pen' and that is an 'eraser'
```

### おまけ

#### エイリアスにしてみた

```~/.zshrc
alias tosq='sed "s/\"/'\''/g"' # to single quote
alias todq='sed "s/'\''/\"/g"' # to double quote
```

使用例:

```sh
# cat 経由
cat file | todq
# this is a "pen" and that is an "eraser"

# 文字列を直接渡しても良いが、その場合はダブルクォートを `\` でエスケープする
echo "this is a \"pen\" and that is an 'eraser'" | tosq
# this is a 'pen' and that is an 'eraser'
```

#### 関数にしてみた

```~/.zshrc
ftosq() {
 echo $1 | sed "s/\"/'/g"
}

ftodq() {
 echo $1 | sed "s/'/\"/g"
}
```

使用例:

```sh
# 文字列直接渡す
ftodq "$(echo this is a \"pen\" and that is an \'eraser\')"
# this is a "pen" and that is an "eraser"

# cat 経由
ftosq "$(cat file)"
# this is a 'pen' and that is an 'eraser'
```

今回は関数にしてもあまりメリットがないかもしれない。
git stash：変更を元の状態に戻す

# はじめに
git stash は、Git で作業中の変更を一時的に退避させるためのコマンドです。これにより、現在の作業内容を保存してワーキングディレクトリをクリーンな状態に戻し、別の作業やブランチへの切り替えをスムーズに行うことができます。

# 主な用途
1. **一時的な保存**: コードに変更がある状態で別のブランチに切り替える必要がある場合、変更をコミットせずに作業を中断したいことがあります。このとき、git stash を使うことで、変更を一時的に保存できます。
1. **クリーンな状態で他の作業を行う**: 現在の変更を一時的に退避させ、クリーンなワーキングディレクトリで新しい作業を始めることができます。

# 基本的な使い方
### 1. 変更を一時的に退避する
まず、現在の変更を stash に退避させます。
```
git stash
```
これにより、すべての未コミットの変更が一時的に保存され、ワーキングディレクトリが元の状態に戻ります。

### 2. 退避した変更を確認する
git stash list を使用して、退避した変更の一覧を確認できます。
```
git stash list
```
例として、以下のような出力が得られます：
```
$ git stash list
stash@{0}: WIP on feature-branch: 1234567 Add new feature
stash@{1}: WIP on master: 89abcde Fix bug in production code
stash@{2}: WIP on develop: 456defg Implement new logging system
```
解説
1. stash@{0}, stash@{1}, stash@{2}: これらは各スタッシュの識別子です。stash@{0}が最も新しいスタッシュで、数字が増えるにつれて古いスタッシュになります
1. WIP on feature-branch: これはスタッシュが作成されたときに作業していたブランチ名を示します。WIPは"Work In Progress"の略で、作業中の状態を示しています
1. 1234567 Add new feature: これは、その時点での最新コミットのハッシュと、そのコミットのメッセージの一部です

このような出力から、どのスタッシュにどの作業が保存されているかを確認することができます。

### 3. 退避した変更を適用する
退避した変更をワーキングディレクトリに戻すには、次のコマンドを使用します。
```
git stash apply
```
これにより、最新の stash が適用され、ワーキングディレクトリに変更が戻ります。

### 4. 特定の stash を適用する
特定の stash を適用したい場合は、stash ID を指定します。
```
git stash apply stash@{0}
```
これにより、stash@{0}（特定の stash ID）を適用できます。

### 5. 退避した変更を削除する
適用後に不要となった stash を削除するには、次のコマンドを使用します。
```
git stash drop
```
これにより、最新の stash を削除します。

### 6. 退避した変更を適用して削除する
git stash apply と git stash drop を組み合わせて、適用と削除を一度に行うこともできます。
```
git stash pop
```
これにより、最新の stash を適用した後、その stash を削除します。

:::note info
**git stash applyとの違い**
1. git stash apply は、stash を適用した後もその stash をリストに残しておく場合に使用します。リストに残るため、後で再適用することもできます
1. git stash pop は、stash を適用した後に自動的にリストから削除したい場合に使用します。通常、一度適用すればもう不要な stash を簡単に削除できるため、これが便利です
:::

# まとめ
git stash は、作業を中断して別のタスクに移る際や、クリーンな状態で作業を続けたいときに非常に役立つツールです。これをうまく活用することで、作業効率を高め、柔軟に開発を進めることができます。
ResoniteでQuestProフェイシャル＆アイトラッキングする方法(VirtualDesktop)

ResoniteでQuestProフェイシャル＆アイトラッキングする方法(VirtualDesktop)


ResoniteでModを使える状態にします。
https://wiki.resonite.love/%E6%9C%AA%E5%88%86%E9%A1%9E%E3%83%9A%E3%83%BC%E3%82%B8/mod

こちらのModの最新版の.dllをrml_modsの中にいれます。
https://github.com/Zeitheron/VDFaceTracking/releases/
![スクリーンショット 2023-12-20 200747.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2626996/fc4d8186-c72e-a48b-d15f-e70eb63d84df.png)

こちらのVirtualDesktopの最新版をインストールします。（VDがインストール済みの方はスキップ）
https://github.com/guygodin/VirtualDesktop/releases/

QuestPro側でもストアからVirtualDesktopをインストール

VRCFaceTrackingをインストール。
https://github.com/benaclejames/VRCFaceTracking
VirtualDesktopをModuleRedistryからインストール。

PCでVirtualDesktopStreamerを起動、QuestProでVirtualDesktopを起動。

QuestPro本体の設定で、VDアプリの視線追従と表情の追加のアクセスの許可。
VirtualDesktopの設定StreamngでForward face/eye tracking to PCをON。

VRCFaceTrackingのHomeでトグルをON。

Resoniteを起動すると、目と口が動く！！！
Go言語（Golang）  ポインター  まとめ

### ポインターの役割

1. **メモリの効率的な操作**:
   ポインターを使用することで、大きなデータ構造をコピーする代わりに、そのデータ構造のメモリアドレスをコピーするだけで済みます。これにより、メモリ使用量と処理速度の面で効率が向上します。

2. **参照渡し**:
   関数に引数を渡す際に、値渡しではなく参照渡しを行うことができます。これにより、関数内で元の変数の値を直接変更することが可能になります。

3. **動的メモリアロケーション**:
   ポインターを使用することで、動的にメモリを割り当てたり解放したりすることができます。Goでは、`new`や`make`を使用して動的にメモリを割り当てることができます。

### ポインターの基本的な使い方

#### ポインターの宣言
ポインターは、`*`を使って宣言します。例えば、`*int`は`int`型のポインターです。
```go
var p *int
```

#### ポインターの初期化
変数のアドレスを取得するには、`&`演算子を使用します。
```go
var i int = 42
p = &i
```
これで、`p`は`i`のメモリアドレスを保持します。

#### ポインターのデリファレンス
ポインターが指す値を取得するには、`*`演算子を使用します。
```go
fmt.Println(*p) // 42
```
`*p`は`p`が指すアドレスの値を取得します。

#### ポインターを使用した関数呼び出し
ポインターを使って関数に変数を渡すことで、その変数の値を関数内で変更することができます。
```go
func increment(p *int) {
    *p++
}

func main() {
    var x int = 10
    increment(&x)
    fmt.Println(x) // 11
}
```
この例では、`increment`関数はポインターを受け取り、そのポインターが指す値をインクリメントしています。

### ポインターの詳細な例

以下に、ポインターの詳細な使用例を示します。

```go
package main

import (
	"fmt"
	"unsafe"
)

func main() {
	var i int = 10
	var p *int = &i

	fmt.Printf("i: %v\n", i)               // 10
	fmt.Printf("p: %p\n", p)               // メモリアドレス
	fmt.Printf("*p: %v\n", *p)             // 10

	// pを使ってiの値を変更
	*p = 20
	fmt.Printf("i after *p = 20: %v\n", i) // 20

	// ポインターサイズ
	fmt.Printf("size of p: %d bytes\n", unsafe.Sizeof(p)) // 8 (64ビット環境では一般的に8バイト)
	
	// 二重ポインター
	var pp **int = &p
	fmt.Printf("pp: %p\n", pp)             // ポインターpのアドレス
	fmt.Printf("*pp: %p\n", *pp)           // pの値（iのアドレス）
	fmt.Printf("**pp: %v\n", **pp)         // 20

	// 関数を使ったポインター操作
	changeValue(p)
	fmt.Printf("i after changeValue: %v\n", i) // 30
}

func changeValue(p *int) {
	*p = 30
}
```
オブジェクト指向について

# 目次
[1.はじめに](#1-はじめに)
[2.オブジェクト指向ってなんぞや](#2-オブジェクト指向ってなんぞや)
[3.オブジェクト指向の三大要素](#3-オブジェクト指向の三大要素)
[4.オブジェクト指向のメリット](#4-オブジェクト指向のメリット)
[5.おわりに](#5-おわりに)

# 1. はじめに
近年、主流の開発言語を使用する際によく耳にされる方も多いのかなと感じておりますが、オブジェクト指向とは一体なんなのか、簡潔にまとめてみました。

本記事では初学者である私がudemyで学習した、「これだけ知っていれば大丈夫！プログラミング入門以前の基礎知識」の内容をもとにしております。ご了承ください。

https://www.udemy.com/course/ilhxxtmo/?couponCode=KEEPLEARNING

# 2. オブジェクト指向ってなんぞや
オブジェクト指向とは`「全てをモノという単位で表現するプログラムの考え方」`のことです。
「モノ」の概念には生物・無生物も含まれます。


# 3. オブジェクト指向の三大要素とは
オブジェクト指向プログラミングの3大要素は`「カプセル化」、「継承」。「多態性（ポリモーフィズム）」`です。
それぞれもう少し具体的に説明いたします。

## カプセル化
カプセル化とは`オブジェクトの情報を隠蔽すること`です。
重要なデータを外から簡単に書き換えられないようにカプセル化を行い、安全性を高めます。また、操作可能な情報のみ専用のアクセスメソッドをつけます。

### 4種類の制御レベル
javaを例に出すと、データ・メソッドそれぞれに対して以下4種類からアクセス制御レベルを選択する仕組みになります。

①private...自身のクラスからのみアクセスを許可
②package private...自身と同じパッケージに属するクラスからのみアクセスを許可
③protected...自身と同じパッケージに属するか自身を継承した子クラスからのみアクセスを許可
④public...全てのクラスからのアクセスを許可

## 継承
継承とは`あるクラスのメンバを他のクラスに引き継ぐこと`です。

基になるクラスをスーパークラス、ベースクラスといいます。
継承したクラスをサブクラスといいます。
サブクラスはスーパークラスのメンバ＋独自のメンバを持てます。

### 単一継承
１つのクラスが1つのスーパークラスのみ持てます。
### 多重継承
1つのクラスが複数のスーパークラスを持てます。
・単一継承しか許されていない言語...Java,C#など
・多重継承が許されている言語...C++,Pythonなど

## 多様性（ポリモーフィズム)
ポリモーフィズム（多態性）とは、異なるクラスのオブジェクトを統一されたインターフェースを介して操作できる能力を指します。

日本語で 「多様性」「多態性」「多相性」 と訳され、多様な形や状態をとることができることを意味します。
# 4. オブジェクト指向のメリット
## メリット1
・現実世界をそのままクラスに落とし込める
・クラスの関係性を記述することによりアプリを開発できる
・プログラムの改良などが容易になる
## メリット２
・ソフトウェアメンテナンスが容易になる
・新しい機能を実装・・・クラスを入れ替える
・従来の機能をさらに拡張した新機能の実装・・・継承を利用する
# 5. おわりに
今回はオブジェクト指向についてまとめてみました。
非常に簡単な紹介でしたが参考になれば幸いです。
最後まで読んでいただきありがとうございます。
【Getting Over It】壺おじのレベルデザイン考察


## 本文

壺に入った男が山を登る苦行ゲームがあって、なんでこの苦行ゲームが流行ったのだろう、とぼんやり考えていたら、ふとあることに気づきました。

それは、先に進むほど（登るほど）背景が暗くなるということです。

これによってゴールが近づいていることをプレイヤーに無意識レベルで伝え、
「もうすぐゴールだ…」というモチベーションにつなげられるのではないかと考えます。

こういう苦行系ゲームは途中で諦められてしまうことが多いですが、
ゴールまでの長さと背景を比例させることでプレイヤーを勇気づけていたのかもしれません、

終わり。

## チラ裏

「プレイヤーを勇気づける」レベルデザインって面白いね。
VLC Media Player をTkinter の画面に埋め込む（Python-VLC + libvlc.dll）

Tkinter で簡易的なメディアプレイヤーを作ろうとしたとき、OpenCVが真っ先に登場しますが、残念ながら動画再生のみで、音声まで再生してくれません。
ほかにもっと簡単な手段は無いかと探したところ、VLC Media Player を使う方法を見つけました。 

Pythonから VLC の動画再生機能を使う場合、VLC Media Player のインストールが必要ですが、ポータブル向けにZip圧縮されたものが公開されているので、ここから必要なものを入手することができます。

## PythonでVLCを制御するためのDLLを入手する

### 1.VLC Media Player ポータブル版をダウンロードする
下記のリンクに飛んで、画面をスクロースすると、一番最後に "last/" のリンクが見つかるので、これをクリックします。 

[https://download.videolan.org/pub/videolan/vlc/](https://download.videolan.org/pub/videolan/vlc/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775985/5c487a59-f875-37c3-1bcb-0916beb1ef56.png)

次に、"Win64" のリンクをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775985/9d125f2f-aa92-018c-b32f-04824b3820a0.png)

最後に、"vlc-3.0.21-win64.zip" のリンクをクリックすると、Zip ファイルがダウンロードできます。     
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775985/fffdd9d0-970d-d3d0-4090-d44b372fcb80.png)

### 2.Zip ファイルを解凍し、必要なDLLを取り出す
Zip ファイルを解凍し、2つのDLLと1つのフォルダを取り出し、任意のフォルダにコピーします。
必要なDLL：libvlc.dll 、 libvlccore.dll
必要なフォルダ：plugins

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775985/b49a87e1-d747-ee63-4887-e61c7d963116.png)

## python-vlc を pip でインストールする
Pythonからvlc を扱うには、 python-vlc をインストールする必要があります。
```
pip install python-vlc
```

## TkinterにPythonを埋め込むコードのサンプル

下記がTkinterにVLCの動画再生機能を埋め込んだサンプルになります。
先ほど取り出した２つのDLLと１つのフォルダを、任意のフォルダにコピーしてもらいましたが、Pythonにその場所を教える必要があります。

```
os.add_dll_directory( DLLが置かれているフォルダのパス )
```

Pyファイル実行時のカレントディレクトリに DLL を入れても正しく参照してくれないので、上記の１行を記述して参照場所を明示的に指定します。

下記のサンプルは、カレントディレクトリに DLL を置いたという前提で、os.getcwd() でカレントディレクトリのパスを設定しています。

```python
import os
# Pythonから、カレントフォルダに置かれたDLLが参照できるようにする
os.add_dll_directory(os.getcwd())
import vlc  # VLCメディアプレーヤーライブラリをインポート
import tkinter as tk

# Tkinterウィンドウの作成
root = tk.Tk()
root.title("動画再生")

# 動画を表示するためのフレームを作成
frame = tk.Canvas(root)
frame.pack()

# VLCメディアプレーヤーの作成
instance = vlc.Instance("--no-xlib")
player = instance.media_player_new()
media = instance.media_new('O:\TestData\Movie/437_1280x720.mp4')
player.set_media(media)
player.set_hwnd(frame.winfo_id())

# 動画の再生／停止ボタン
start_button=tk.Button(text="再生/一時停止",width=30,command=lambda : player.pause())
start_button.pack()

# 動画再生を開始
player.play()

# Tkinterウィンドウを表示
root.mainloop()
```

実行すると下記の画面が表示されます。ちゃんとTkinterの画面で動画が表示されていますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775985/7b2e6086-5bab-5d64-9ba0-69636d3f66ab.png)


## まとめ

PythonのTkinterで音声と動画を再生させたい場合、VLC Media Player のDLLを使うのが一番手っ取り早いです。
VLC Media Player のポータブル版から、libvlc.dll 、 libvlccore.dll　plugins　の３つを任意のフォルダにコピーして、os.add_dll_directory() で DLL のパスを指定するところがポイントです。

参考記事：[【初心者歓迎】動画分割・結合ツールを作ろう（ffmpegで動画の切り出しと結合）](https://favorite-worlds.com/2024/08/25/%e3%80%90%e5%88%9d%e5%bf%83%e8%80%85%e6%ad%93%e8%bf%8e%e3%80%91%e5%8b%95%e7%94%bb%e5%88%86%e5%89%b2%e3%83%bb%e7%b5%90%e5%90%88%e3%83%84%e3%83%bc%e3%83%ab%e3%82%92%e4%bd%9c%e3%82%8d%e3%81%86%ef%bc%88ff/)
【Linux】絶対パスを取得する方法

絶対パスを取得するには以下のコマンドを実行します。

```zsh
ls ~/path/to/dir/*
```

```zsh
$ ls /home/user/sample/*
/home/user/sample/example.txt
/home/user/sample/sample.txt

/home/user/sample/example:

/home/user/sample/sample/sample:
```
supabaseへ登録処理を行うデータが一部表示できない件について

# やりたいこと
* 入力した学習内容と学習時間の両方を登録処理を行ったときに画面に表示すること

# 今回の状況
* 学習時間のみしか画面に表示されない

# 問題の原因
supabaseのカラム名と入力したデータを入れているオブジェクトのプロパティ名が違っていたから
* newRecordという変数に代入されているオブジェクトのtitleプロパティが正しくはcontentであるため

# supabaseのカラム名
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3789688/5e663bd8-1b31-06d9-7542-1f6bb0b196f8.png)

# 問題のコード
```App.jsx
else {
      //入力した学習内容、学習時間をオブジェクトの中に入れる
      //学習時間は数値型で10進数に変換
      newRecord = {
        title: inputs.content,
        time: parseInt(inputs.time, 10),
      };

      try {
        //supabaseのテーブルのcontent,timeというカラムに入力した学習内容、学習時間を登録する
        const { error } = await supabase
          .from("study-record")
          .insert({ content: newRecord.title, time: parseInt(newRecord.time, 10) })
          .select().single()
        //エラーがあれば例外を投げる
        if (error) {
          throw error;
        }
          //入力したデータをリストに追加する
    const newRecords = [...records, newRecord];
    setRecords(newRecords);
```
# 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3789688/81298826-b58b-c374-16eb-5cc787a05769.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3789688/956af927-21c3-6b2c-6f8c-3ffd614393b2.png)

# 解決方法
* カラム名がcontentの為newRecordのtitleプロパティをcontentに変更する
```App.jsx
else {
      //入力した学習内容、学習時間をオブジェクトの中に入れる
      //学習時間は数値型で10進数に変換
      newRecord = {
        content: inputs.content,
        time: parseInt(inputs.time, 10),
      };

      try {
        //supabaseのテーブルのcontent,timeというカラムに入力した学習内容、学習時間を登録する
        const { error } = await supabase
          .from("study-record")
          .insert({ content: newRecord.content, time: parseInt(newRecord.time, 10) })
          .select().single()
        //エラーがあれば例外を投げる
        if (error) {
          throw error;
        }
          //入力したデータをリストに追加する
    const newRecords = [...records, newRecord];
    setRecords(newRecords);
```
# 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3789688/6309c24c-fc92-4d26-371a-2bea0532414a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3789688/12def2bc-8d4c-27e6-54d3-3bc4e14ddd2d.png)

# さいごに
* supabaseの{data}を使用して登録処理を行うように変更した
※const [inputs, setInputs] = useState({ content: "", time: "" })
⇒入力した内容が保存されるStateです。
```App.jsx
else {

      try {
        //supabaseのテーブルのcontent,timeというカラムに入力した学習内容、学習時間を登録する
        //学習時間は数値型で10進数に変換
        const { data, error } = await supabase
          .from("study-record")
          .insert({ content: inputs.content, time: parseInt(inputs.time, 10) })
          .select().single()
        //エラーがあれば例外を投げる
        if (error) {
          throw error;
        }
          //入力したデータをリストに追加する
    const newRecords = [...records, data];
    setRecords(newRecords);
```
UnrealEngineでC++23を使いたい

# C++23

CEDEC2024にてC++17~C++23の講演がありました。
https://www.docswell.com/s/cpp/5XEY92-cedec2024

さっそくC++23を使いたくなったけど、UnrealEngineが公式サポートしているのはC++20まで。

VisualStudio2022の対応状況は進んでいてSTLはもう使えそう。
https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=msvc-170

エンジンビルドもC++23でするのは問題でるかもだけど、自プロジェクトならC++23ビルドしても動くでしょうということで設定方法を調べました。

# Build.csを開いて一行書く
Build.csに
```c#
CppStandard = CppStandardVersion.Latest;
```
の一行を足しましょう。
これだけだとインテリセンスがまだC++20です。
cprojファイルを開きNMAKEの追加のオプションにあるオプションを変更しましょう。

/std:c++20 -> /std:c++latest

変更後はslnを閉じて開き直すとインテリセンスもC++23として働いてくれます。

適当なC++23コードを書いてテストします。
join_withを試します。
https://cpprefjp.github.io/reference/ranges/join_with_view.html
```c++
void AMyClass::BeginPlay()
{
	Super::BeginPlay();
	std::vector<std::string> hoge = {"aaa", "bbb"};
	for(char h : hoge | std::views::join_with('-'))
	{
		std::cout << h << std::endl;
	}
}
```
コンソール出力に無事に出ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157391/605d2475-a6ea-0b82-af93-c56be05679fb.png)

rangeアダプタで面倒な配列操作が楽になるといいなぁ

# あくまで自己責任
UnrealEngineは公式にC++20なので、何かあっても自己責任の精神でいきましょう。
個人プロジェクトで使いなれていくのがいいですね。
Turbo Streamの主なアクション

## 初めに

疑問に思ったことや上手くいかなかったことのアウトプットをしています。
自分なりの理解でアウトプットしていきます。初学者なので誤りもあると思います。
その際はご指摘いただけると幸いです。

# Turbo Streamとは
HTMLの断片をリアルタイムで更新するツール。
Java Scriptの動的な更新を知識が無くとも可能にする。

# 代表的なアクション
・append
・prepend
・replace
・update
・remove
・before
・after
```
<%= turbo_stream.prepend "(IDの名称)" do %>
  <%= render @xxxxxx %>
<% end %> 
```
指定した要素をアクションに従って指定したIDを持つ要素の内部に反映する。
# Append
新しい要素を既存のコンテンツの後に追加

# Prepend
新しい要素を既存のコンテンツの後に追加

# Replace
既存の要素を新しい内容で置き換える

# Update
既存の要素の内容を部分的に更新する際に使用する。
※いいね数等

# Remove
不要になった要素をDOMから取り除く

# Before
特定の要素の前に新しい要素を追加する。

# After
特定の要素の後に新しい要素を追加する
動作環境調べるのは大事だよねっていう話

こんにちは

所で皆さんはサイトを立ち上げるためにサーバーを借りたりすると思うんですが
自分のサイトに人が集まるかどうかなんてわからないのだから出来れば
安く借りたいよねって考えている人も多くいると思います

自分も、出来れば安く立ち上げが出来るのが良いよねってさくらVPSの
一番安いサーバーを借りたのですが、nuxtが立ち上がらないんですよね
エラーが出たわけではなくて、リソース情報を見ると
CPUが頑張っている痕跡が出ていました

後からchatGPTに聞いたらこんな回答が出ました
## chatGPTの回答
```
Nuxt.jsの動作環境

Nuxt.jsは、一般的なモダンな開発環境でスムーズに動作します。具体的には、以下の要件が推奨されます。

Node.js: 推奨バージョンはLTS版（長期サポート版）。例えば、Node.js 18.x LTSなど。
npm または yarn: パッケージマネージャー。npmはNode.jsに同梱されていますが、yarnも使用可能です。
OS: Ubuntuや他のLinuxディストリビューション、macOS、Windowsなどで動作します。
CPU/RAM: 開発環境では、4コア以上のCPUと8GB以上のRAMを推奨。プロジェクトの規模によっては
これ以上のスペックが必要になることがあります。
CPU使用率が高い場合の対処

依存関係の確認: node_modulesフォルダが正しくインストールされているか確認してください。
rm -rf node_modulesしてから再インストール (yarn install または npm install) する
ことも有効です。
プロセスの監視: htopなどのツールを使用して、どのプロセスがCPUを消費しているかを確認します。
ビルドの最適化: nuxt.config.js内でbuildオプションを適切に設定し、開発ビルドとプロダクションビルドの
違いを確認してください。
Linuxの環境を調べる方法（Ubuntu）

CPU情報の確認:

bash
コードをコピーする
lscpu
CPUの詳細（コア数、アーキテクチャなど）が表示されます。

メモリの確認:

bash
コードをコピーする
free -h
RAMの使用状況と全体量が表示されます。

ディスク容量の確認:

bash
コードをコピーする
df -h
各ディスクの使用量と空き容量が表示されます。

LinuxカーネルとOSバージョンの確認:

bash
コードをコピーする
uname -a
OSの詳細バージョン情報が表示されます。

Ubuntuバージョンの確認:

bash
コードをコピーする
lsb_release -a
Ubuntuのバージョン情報が表示されます。

これらのコマンドを使って、システムの環境を確認し、Nuxt.jsの動作に問題がないかどうかを
チェックしてください。
```
ただ,nuxtのガイドには動作環境については書かれていなかったので本当かどうか分からなかったのですが

https://nuxt.com/docs/getting-started/installation

調べたらgithubのissueにそれらしい記述がありました

https://github.com/nuxt/nuxt/issues/8080

うわーサーバー代払った後じゃん
スケールアップするかなと考えたのですがその後試した所、
一応nuxtの立ち上げは出来ました

なのでnuxtの動作環境としては

:::note warn
OS:Ubuntu 24.04
CPU:仮想2Core
メモリ:1GB メモリ
:::

でも動作します
ただ、chatGPTが求める推奨環境は

:::note info
4コア以上のCPUと8GB以上のRAM
:::

が必要です
なのでもし、さくらVPSでnuxtを使ったサイトを立ち上げようと考える場合は
４Gか８Gのサーバーを借りないとサーバーがフリーズするかもしれません

https://vps.sakura.ad.jp/specification/

追記
２コア１GBのサーバーでは動作しません
サーバーがすぐにクラッシュしました
VRChat標準シェーダーの保存場所

# 概要
VRChat標準シェーダーが保存されている場所を紹介します。

QuestアバターでおなじみのStandard LiteやToonLit、MatCapLitなどのシェーダーの中でどんな処理がされているのか確認することができます。

# 環境
- Unity 2022.3.22f1
- VRChat SDK - Base 3.6.1
- VRChat SDK - Worlds 3.6.1
- VRChat SDK - Avatars 3.6.1

# 保存場所
試していないのでわかりませんが、ここに保存されているシェーダーはあくまでもUnity上での確認用で、中身を変更してもVRChat上では反映されないと思います。

- エクスプローラーから確認する場合
```
Packages\com.vrchat.base\Runtime\VRCSDK\Sample Assets\Shaders\
```
- Unity上から確認する場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3864812/becce09c-3d49-547c-9d98-723e3e13767c.png)
【アップデート】CloudFormationでIaC ジェネレーターでのリソース検出とテンプレートレビューの機能が強化されました

こんばんは、Koderaです。
CloudFormationでIaCジェネレータに関するアップデートがありました。
https://aws.amazon.com/about-aws/whats-new/2024/08/cloudformation-resource-discovery-template-review-iac-generator/

## IaCジェネレータとは
CloudFormation IaC ジェネレーター（Infrastructure as Code ジェネレーター）は、AWS CloudFormation で既存のリソースからテンプレートを作成できる機能です。
CloudFormation で管理されていないアカウントにプロビジョニングされた AWS リソースを利用してテンプレートを生成できます。

AWSマネジメントコンソールからも利用でき、メニューの「IaCジェネレーター」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/c60fa9c0-19ec-9159-cdc9-19a226c932e1.png)



IaCジェネレーターからテンプレートを作成するにあたり、以下の3ステップに分かれています。
>1. リソースのスキャン
>最初のステップは、リソースのスキャンを開始することです。このスキャンは、リージョン全体で、30 日間続きます。この間、同じスキャンから複数のテンプレートを作成できます。
>
>2. テンプレートの作成
>テンプレートを作成するには、次の 2 つのオプションがあります。
>
>・新しいテンプレートを最初から作成し、スキャンしたリソースと関連リソースをそこに追加します。
>・既存の CloudFormation スタックを開始点として使用して、スキャンされたリソースと関連リソースをそのテンプレートに追加します。
>
>3.リソースのインポート – テンプレートを使用して、リソースを CloudFormation スタックとしてインポートするか、AWS CDK アプリに移行し詳細ます。
>> https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/generate-IaC.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/98e82372-aa57-c35f-2d42-13f6a0527578.png)


IaCジェネレータのメリットとしては、AWS Management ConsoleやCLIなど、IaC以外の方法で作成したリソースに IaC を採用するのに役立ちます。
選択したリソースのテンプレートを生成後、リソースを CloudFormation にインポートしたり、他のリージョンやアカウントにデプロイするため、テンプレートのダウンロードが可能です。
また、TypeScript や Python などの好みのプログラミング言語でテンプレートを CDK アプリに変換する CDK CLI コマンドの利用ができます。


## アップデート内容
#### スキャンの概要タブ
IaC ジェネレーターがアカウント内のリソースのスキャンを完了後、「スキャンされたリソース」の内訳が追加で表示されるようになりました。
本アップデートによりアップデート、テンプレートに含めるリソースをより迅速に見つけることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/e95901e3-f719-bc29-6dce-a8894dac1854.png)

スキャンされたリソースは製品別に表示されており、右の「スキャン概要の詳細」から詳細情報を確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/c4ccdf1e-c55d-b018-7776-017294102707.png)

#### Application Composerでの視覚化
リソースを選択した後、AWS Application Composer でテンプレートをプレビューすることができるようになりました。
スキャン後の「テンプレートの定義」から表示を「キャンバス」に変更すれば確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/9a57136e-58cf-7056-d4d8-5095932ca406.png)

また、リソースにカーソルを合わせると、他リソースの関係性もAppllication Composerの機能で視覚的に確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/6a54edd5-e2dc-a76f-8267-3c0bce181202.png)


## まとめ
CloudFormationでIaC ジェネレーターでのリソース検出とテンプレートレビューの機能のアップデートが発表されました。
これからIaCを活用されるという方にとっては、どのリソースが使われているのかより明確になって、IaCジェネレータが使いやすくなったのではないかと思います。
mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64e' or 'arm64') の対処法

## 概要

この記事では、macOS で Python 環境を使用している際に発生する `mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64e' or 'arm64')` エラーの原因と、その対処法について解説します。特に、Apple Silicon（M1/M2 チップ）を搭載した Mac での Python パッケージのインストールに関する問題に焦点を当てています。

## 原因

このエラーは、macOS 上で Python のパッケージをインストールした際に、システムのアーキテクチャ（`x86_64 と arm64`）が不一致である場合に発生します。具体的には、インストールされている Python やパッケージが `Intel（x86_64）` 用にビルドされている場合、`Apple Silicon（arm64）` 環境でこれを実行しようとすると、互換性の問題が生じます。その結果、特定のC拡張モジュールがロードできず、エラーが発生します。

## 対処法

この問題を解決するためには、`arm64` アーキテクチャに対応した形で Python パッケージをインストールする必要があります。そのためには、`arch` コマンドを使用して、`pip install` を `arm64` アーキテクチャ上で実行するように指定します。

```sh
# Python の仮想環境を作成し、アクティベートしたあと
arch -arm64 pip install -r requirements.txt
```

`requirements.txt` は、プロジェクトで必要な Python ライブラリの一覧を指定したファイルです。このコマンドを使うことで、`Apple Silicon` に適したパッケージがインストールされ、アーキテクチャの不一致によるエラーが解消されます。

## 参照

https://stackoverflow.com/questions/71745890/incompatible-architecture-have-arm64-need-x86-64-error-while-installing
OMC222B(1125,幾何)

https://onlinemathcontest.com/contests/omc222/tasks/4772

文章だけだと難しいので、図を描くと以下のようになります。
$∠BAQ=∠BPA$となるので、$△BAQ∽△BPA$であることがわかります。

![OMC222B2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543462/68c66e7e-d872-71ec-59af-8e9c5cd39f45.jpeg)

以下の方針で解いていきます。
$1.$ $x$を求める ($x=BP$とします)
　三角形の相似比を使います。
$2.$ $cosθ$を求める ($θ=∠B$とします)
　余弦定理を使います。
$3.$ $AC$を求める
　$tanθ$を使います。
$4.$ 面積の$2$乗を求める
　底辺$×$高さ$×\frac{1}{2}$です。


$1.$ $x$を求める
$BP:BA=BA:BQ$となるので、
$x:6=6:x+5$
$x(x+5)=36$
$x^2+5x-36=0$
$(x+9)(x-4)=0$
$B,P,Q,C$の順に並ぶことから$x>0$なので、$x=4$。


$2.$ $cosθ$を求める
$AB,BP,PA,cosθ$を使って、余弦定理の式を作ります。
$AB^2+BP^2-2・AB・BPcosθ=AP^2$

$AB=6,AP=5,BP=4$を代入し、$cosθ$を求めます。
$6^2+4^2-2・6・4cosθ=5^2$
$48cosθ=27$
$cosθ=\frac{9}{16}$


$3.$ $AC$を求める
$AC=ABtanθ$
$=AB\frac{sinθ}{cosθ}$
$=AB\frac{\sqrt{1-cos^2θ}}{cosθ}$

$AB=6,cosθ=\frac{9}{16}$を代入します。
$AC=6×\frac{\sqrt{1-(9/16)^2}}{9/16}$

分母、分子にそれぞれ$16$をかけます。
$AC=6×\frac{\sqrt{16^2-9^2}}{9}$
$=\frac{2\sqrt{175}}{3}$
$=\frac{10\sqrt{7}}{3}$


$4.$ 面積の$2$乗を求める
直角三角形なので、面積は$AB×AC×\frac{1}{2}$です。
$AB=6,AC=\frac{10\sqrt{7}}{3}$を代入して、
$(6×\frac{10\sqrt{7}}{3}×\frac{1}{2})^2$
$=(10\sqrt{7})^2$
$=700$
【Flutter】Checkboxの形を変える

こんにちは。
今回は、Checkboxの形を変える方法を紹介します。

# 方法
![スクリーンショット 2023-08-13 20.18.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524120/ce57fee2-1687-ea40-8538-b4c8b9db94e0.png)

Checkboxを丸くするには、引数「shape」を使います。
Checkboxの引数「shape」にCircleBorderを指定します。



# 使用例
```dart
Checkbox(
  value: true,
  shape: CircleBorder(),
  onChanged: (value) {},
),

```

# 実行例
![スクリーンショット 2024-08-26 22.55.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524120/c5652b45-3671-1414-9b4a-d5632074affe.png)


# 最後に
ここまで読んでいただき、ありがとうございました！
いいねしてくれたら、スキップして喜びます:heartpulse:
読書のすゝめ ～月 2 冊読書を初めて半年がたったので振り返る～

# はじめに

### きっかけ

以下の経緯があり、これを機に計画的に本を読もうと決めました。

- 最近、インプットの量が減り、知識やスキルの習得が滞っていると感じていた
- 気になる本は購入しても積ん読状態になっていた
- やはり、多くの成功者や優れたエンジニアが「本を読め」と言っている

### 読書ルール

以下のルールを定めて、日々の読書に取り組むことにしました。

1. 月に平均2冊以上読む
2. **読んだ本については感想や学びをメモに残す**
2. **読んだ本の中で今後実践していきたいことを積極的に試していく**
3. 技術書や自己啓発書など、ジャンルは問わない。ただし、なるべく自己成長につながる本を選ぶ
4. 小説や漫画は対象外とする

# 良かったこと

読書で得た知識がインプットされ、**今後実践していきたいことをに対して行動に起こす**ことで、エンジニアとしても人としても成長を感じることができました！
ざっくり良くなったことは以下です（詳細は [2024年前半が終わったので、読んで良かった本を紹介する](https://qiita.com/bmjuggler/items/26c87a1ae8a92e55e884) の記事にも書いています！）

- コーディングスキルが向上した
- モーニングメソッドを実践し、生活習慣や人としても成長した
- 目標達成のコツを学び、達成率が上がった
- デザインの知識が深まり、より良い UI/UX を意識するようになった
- エッセンシャル思考を取り入れることで、仕事の優先順位をうまく調整できるようになり、不要なタスクを減らすことができた
- 効果的なコミュニケーション方法を学び、会話のスキルが向上した
- 一流エンジニアの思考法を取り入れ、自分自身の技術力向上につながった

**読書が習慣化したことで、日々少しずつ成長を実感**できるようになった

個人的に、インプットだけで終わりがちな読書に対して、**しっかり学んだ内容をアウトプットしていったのはよかったと思います！**
**日々成長しているのを感じることができました！**

# 反省点

ただし、反省点もいくつかあります。
最初のうちは「月に2冊読む」という目標に固執しすぎて、読むこと自体が目的化してしまった部分がありました。また、難解な本や文字数が多い本では、途中で読むのがしんどくなり、読書が重荷になることもありました。

さらに、読書メモを書く際にハードルを高く設定しすぎてしまい、次第に感想を書くペースが落ちてしまいました。。。

# 今後の方針

これらの反省点を踏まえ、今後は次のように取り組んでいこうと思います！

1. 「月に2冊」という目標にこだわらず、忙しい時や難しい本の場合は柔軟に対応する
    - 例えば、簡単な本と難しい本を並行して読む、あるいは翌月に調整するなど、無理なく続けられる方法を探す
2. **難しい本は概要をざっと読み、再度読みたいと思ったものにフォーカスして後日じっくり取り組む**
    - これにより、月に2冊の目標も無理なく達成できるはず
3. 感想を書く際は、内容を細かくまとめるのではなく、読**んで得た気づきや今後取り組みたいことをメモ程度に簡潔にまとめる。**
    - こうすることで、書くハードルを下げ、継続的にアウトプットできるようにする

# おわりに

みなさん、本を読む習慣をぜひ取り入れて、得られたインプットから実践してみてください！
恩恵は計り知れないものがあります！！
Gemini Nanoを利用した翻訳Extensionをリリースしました

Translate with Gemini Nano（Gemini Nanoによる翻訳）というChrome Extensionをリリースしました。[Chrome Web Store](https://chromewebstore.google.com/detail/nffemijelmgmjapkgomeahmmpbcjjpnn)からインストールできます。また[GitHub](https://github.com/sh2/extension-translate-gemini-nano)でソースコードを公開しています。

https://chromewebstore.google.com/detail/nffemijelmgmjapkgomeahmmpbcjjpnn

https://github.com/sh2/extension-translate-gemini-nano

このように選択範囲の翻訳ができます。
![スライド3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216196/f597b249-66a7-e971-da42-ae2f4f9b99ef.png)

Chrome 128から導入されたビルトインAIモデルGemini Nanoを利用しているところが特長です。現在のところGemini Nanoの利用には事前準備が必要である点に注意して下さい。
![スライド2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216196/112866e7-3af6-6848-c3a9-6f3690636905.png)

[Gemini版](https://chromewebstore.google.com/detail/hmdcbbbdmfapkpdaganadiihfmdnpngi)、[Claude版](https://chromewebstore.google.com/detail/ciikfihmdpcbmehhggahlgljimikipbm)と比較したGemini Nano版のメリットとデメリットを以下に示します。

- メリット
  - 無料で利用できる
  - 情報をインターネットに送信しない
- デメリット
  - 翻訳品質はGemini版、Claude版に劣る
  - PCの演算能力、メモリーを大量に消費する

正直なところ翻訳品質はまだ実用レベルには達していません。長い目で見ていただければと思います。またGemini版、Claude版には要約機能があるのですが、Gemini Nanoには荷が重すぎたためGemini Nano版での要約機能の実装は見送りました。

当面Gemini版、Claude版も合わせてご利用ください。

https://chromewebstore.google.com/detail/hmdcbbbdmfapkpdaganadiihfmdnpngi

https://chromewebstore.google.com/detail/ciikfihmdpcbmehhggahlgljimikipbm
matlabのドキュメンテーション作成ツール

Matlabで研究をする際、ドキュメンテーションツールとして何があるのか気になったのでメモ。

## [Using Doxygen with Matlab](https://jp.mathworks.com/matlabcentral/fileexchange/25925-using-doxygen-with-matlab)
matlabのコメントアウト形式をほぼ維持したままdoxygenに落とし込めるツール。
githubには[バージョンアップ版](https://github.com/simgunz/doxymatlab)もある。
ただどちらも10年近く前なのでメンテナンス性には難あり。
一応動いたけれど、完全とはいい難い感じ。最終的にC++への移植を考えるなら参考にして作り直すのもありか?

## [sphinx](https://github.com/sphinx-contrib/matlabdomain)
python等で使われているSphinxを使う手法。現在でも定期的にメンテナンスされているようなので最新版でも使えそう。現在はこちらを使用できないか検討中。

他にも[こちら](https://jp.mathworks.com/matlabcentral/answers/2074416-are-there-any-tools-for-generating-developer-documentation-of-simulink-model)ではsimulinkを使う方法なども提案されているため、他にもいい方法はあるかもしれない。当面はSphinx思い出そう。
【JavaGold】アノテーション

# アノテーション

<table>
  <thead>
    <tr>
      <th>主なアノテーション</th>
      <th>説明</th>
    </tr>
  </thead>
  <tr>
    <td>@￰Override</td>
    <td>スーパークラスのメソッドをオーバーライドすることを示す</td>
  </tr>
  <tr>
    <td>@￰FunctionalInterface</td>
    <td>関数型インターフェースであることを示す</td>
  </tr>
  <tr>
    <td>@￰Deprecated</td>
    <td>非推奨の要素であることを示す</td>
  </tr>
  <tr>
    <td>@￰SuppressWarnings</td>
    <td>コンパイラの警告を無効にする</td>
  </tr>
  <tr>
    <td>@￰SafeVarargs</td>
    <td>安全でない可変長引数に対する警告を無視する</td>
  </tr>
</table>



<table>
  <caption>警告のオン/オフ</caption>
  <thead>
    <tr>
      <th>非推奨のメソッドの宣言側</th>
      <th>非推奨のメソッドの呼び出し側</th>
      <th>警告のオン/オフ</th>
    </tr>
  </thead>
  <tr>
    <td>@Deprecated</td>
    <td>@￰SuppressWarningsなし</td>
    <td>オン</td>
  </tr>
  <tr>
    <td>@Deprecated</td>
    <td>@￰SuppressWarnings("deprecation")</td>
    <td>オフ</td>
  </tr>
  <tr>
    <td>@Deprecated(forRemoval = "true")</td>
    <td>@￰SuppressWarnings("deprecation")</td>
    <td>オン</td>
  </tr>
  <tr>
    <td>@Deprecated(forRemoval = "true")</td>
    <td>@￰SuppressWarnings("removal")</td>
    <td>オフ</td>
  </tr>
</table>

# メタアノテーション

<table>
  <thead>
    <tr>
      <th>主なアノテーション</th>
      <th>説明</th>
    </tr>
  </thead>
  <tr>
    <td>@￰Documented</td>
    <td>Javadoc API ドキュメントの出力にも反映するようにする</td>
  </tr>
  <tr>
    <td>@￰Target</td>
    <td>アノテーションを付与する要素を限定する</td>
  </tr>
  <tr>
    <td>@￰Retention</td>
    <td>
    アノテーションをソースコードもしくはクラスファイルまで保持するかなどを制御する
    </td>
  </tr>
  <tr>
    <td>@￰Inherited</td>
    <td>サブクラスにアノテーションを引き継ぐことを示す</td>
  </tr>
  <tr>
    <td>@￰Repeatable</td>
    <td>同じ場所に複数回適用する</td>
  </tr>
</table>

<table>
  <caption>RetentionPolicyの列挙子</caption>
  <thead>
    <tr>
      <th>種類</th>
      <th>内容</th>
    </tr>
  </thead>
  <tr>
    <td>CLASS</td>
    <td>
    アノテーションに関する情報はクラスファイルには残っているものの、実行時に破棄される。クラスファイルに事前処理するようなプログラムを作るときに使用する
    </td>
  </tr>
  <tr>
    <td>RUNTIME</td>
    <td>
    実行時までアノテーションに関する情報を保持する。実行時にアノテーションを処理をするために使用する
    </td>
  </tr>
  <tr>
    <td>SOURCE</td>
    <td>
    コンパイル時にアノテーションに関する情報は破棄される。コンパイラにアノテーションを処理させたいときに使用する。
    </td>
  </tr>
</table>

```java:実装例
public @interface Sample {}
```

@Targetアノテーションを指定しなかった場合は下記がアノテーションの対象になる。
* クラス
* メソッド
* フィールド
* コンストラクタ
決済サービスのAPIの同時接続数について

リファクタしてる時が一番興奮する泉（[@izumin_0401](https://twitter.com/izumin_0401)）です。

普段決済システムを触っているのですが、色々と調査するタイミングがあったのでメモしておきます。

# ブログ記事はこちら

https://traveler0401.com/api-payment-simultaneous-connections/

# 決済サービスのAPIについて
まず、決済サービスで有名なのは以下の二つかなと思います。
* [GMOペイメントサービス](https://www.gmo-ps.com/)
* [SBPS（ソフトバンクペイメントサービス）](https://www.sbpayment.jp/)

# 決済サービスのAPIの同時接続数について
決済サービスのAPIを使用する際、当然ですがリクエスト数や同時接続数は（外部APIなので）注意する必要があります。

同時接続数についてはサービスによって値が異なるので以下に記載しておきます。

## GMOの同時接続数
GMOは契約に応じて値が異なります。

契約によっては同時接続数の上限を上げることも可能みたいです。

https://mp-faq.gmo-pg.com/s/article/F00504

## SBPSの同時接続数
SBPSは最大5つまで同時接続できます。

5つ以上接続したい場合は問い合わせる必要があります。

https://developer.sbpayment.jp/system-specifications/api-type/3746/#:~:text=%E5%8A%A0%E7%9B%9F%E5%BA%97%E3%81%8B%E3%82%89%E5%BD%93%E7%A4%BE%E3%81%B8,%E5%96%B6%E6%A5%AD%E3%81%BE%E3%81%A7%E3%81%8A%E5%95%8F%E3%81%84%E5%90%88%E3%82%8F%E3%81%9B%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%E3%80%82

# 同時接続数を超えないために
同時接続数を超えないためには、バコバコAPIを実行しないように待機処理を入れたり、バッチ処理にしたりと工夫が必要です。

僕は普段Laravelを使っています（サーバ処理）が、PHPであれば「usleep」などを使って待機させるとより安全かと思います。

:::note info
アホみたいに実行しなければ問題ないと思います。
:::

# まとめ
決済サービスの開発ドキュメント、分かりにくいんですよね...

目がチカチカする

ではまた（例の如く、まとめになっていない）。

# 最後に
暇つぶしに[Twitter](https://twitter.com/izumin_0401)と[ブログ](https://traveler0401.com/)もやってるので見てね。
Dockerを用いたPython環境をクラウドに移行した際のNo module named 'fugashi.fugashi'

解決に結構沼ったので書き残しておきます。
## 問題
Docker imageを持ち込んでクラウドで動作させる際に、Docker内のpython環境でfugashiがインストールされているにもかかわらず以下のようなエラーが発生するようになった。

~~~
Traceback (most recent call last):
  File "/home/users/xxxx/.py", line 1, in <module>
    from fugashi import Tagger
  File "/home/users/xxxx/.local/lib/python3.11/site-packages/fugashi/__init__.py", line 1, in <module>
    from .fugashi import *
ModuleNotFoundError: No module named 'fugashi.fugashi
~~~

## 解決法
Docker内のPython環境で--no-warn-script-locationと--force-reinstallオプションを付けてpip installする。

私の場合はローカルで動作させる必要があったので
https://pypi.org/project/fugashi/
上記のサイトよりバージョンに合ったfugashiのwhlファイルをダウンロードして以下のように実行した。
> pip install ./\*.whl --no-warn-script-location --force-reinstall --no-index --find-links=./\*.whl

## 経緯
Docker imageをクラウドに持ち込んでdocker load -iしていたが、何らかの原因でfugashiのみPATHが通らなくなっていた。

whlからfugashiをreinstallすると
>  WARNING: The scripts fugashi, fugashi-build-dict and fugashi-info are installed in '/home/users/xxx/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.

上記の警告が出されて--no-warn-script-locationオプションを付けることで解決に至った。

ローカルでDocker imageからコンテナを起動させた際には問題なくfugashiが動作していたため、詳しい原因はわからないが、クラウド側のdockerがオプション等を勝手に付けられるといった制限の付いたものだったので、そこが原因だと思われる。