OmniAICreator/Qiita-1.07M huggingface dataset:
メソッドとは？ 〜ロボットで例えると〜🤖

**「メソッドって何？」** と聞かれたら、一言で言うと **「オブジェクトが持っている機能や動作」** のことです。

例えば、あなたが 「家事を手伝ってくれるロボット」 を持っているとしましょう。
**ロボットそのもの（オブジェクト）が存在していても、それだけでは何もできません。**
でも、ロボットに **「掃除をして！」** や **「料理を作って！」** と命令すれば、ロボットは動きますよね？

:::note info
この 「掃除する」「料理を作る」 などの動作こそが メソッド です！

:::

プログラミングの世界では、**オブジェクトがデータ（状態）を持ち、メソッドを使ってそのデータを操作したり、特定の動作を実行したりします。**

**メソッドがあるおかげで、プログラムは 「オブジェクトに命令を出して処理をさせる」 ことができるようになります。**
逆に言うと、メソッドがなければオブジェクトは ただのデータの塊 に過ぎず、何もできません。

これを ロボットを例にして さらに詳しく見ていきましょう！ 🚀

## 1. オブジェクト（ロボット）とメソッド（機能）の関係  
あなたが **「家事を手伝ってくれるロボット」** を持っているとしましょう。このロボットにはいくつかの機能（メソッド）が備わっています。例えば：  

- **掃除をする (`clean`)**  
- **料理を作る (`cook`)**  
- **洗濯をする (`wash_clothes`)**  

:::note info
ロボット自体は「ただの機械（オブジェクト）」ですが、「メソッド（機能）」を呼び出すことで、動作を実行できます。  
:::


## 2. 実際のコードでロボットを作ってみよう！
このロボットを Python で表現すると、次のようになります。  

```python
class Robot:
    def __init__(self, name):  # ロボットの名前を設定
        self.name = name

    def clean(self):
        print(f"{self.name} が掃除を始めました！🧹✨")

    def cook(self):
        print(f"{self.name} が料理を作っています！🍳🔥")

    def wash_clothes(self):
        print(f"{self.name} が洗濯をしています！🧺💦")

# ロボットを作成
my_robot = Robot("ハウスメイト9000")

# ロボットに仕事をさせる（メソッドを実行）
my_robot.clean()
my_robot.cook()
my_robot.wash_clothes()
```


## 3. メソッドを呼び出すとは？
ロボットに「掃除をして！」と言えば、**`clean()`** というメソッドが実行されます。  
Python では `my_robot.clean()` と書くことで、その機能を呼び出せます。  

実行すると、こんな感じの結果が出ます：  

```
ハウスメイト9000 が掃除を始めました！🧹✨
ハウスメイト9000 が料理を作っています！🍳🔥
ハウスメイト9000 が洗濯をしています！🧺💦
```

## まとめ
メソッドは **オブジェクト（ロボット）の動作や機能を決めるもの** であり、プログラムの中で「オブジェクトに何をさせるか」を管理する重要な役割を果たします。 

:::note info
- メソッドは **「オブジェクトの機能」** であり、特定の動作を実行する。  
- `オブジェクト.メソッド名()` の形で呼び出す。  
- メソッドがあることで、オブジェクトに「できること」を追加できる。 
:::

 
つまり、ロボット（オブジェクト）だけがあっても **動けない** けど、メソッドを定義して呼び出せば **実際に動作できる！** ということですね。  

ロボットが **「機能（メソッド）」** を持っているからこそ、私たちは命令して動かすことができるわけです。
 
ロボットに「掃除して！」と指示するように、オブジェクトに「この動作をして！」とメソッドを使って命令できるわけですね！  

メソッドをうまく活用すると、よりスマートで再利用しやすいコードが書けるようになります。
個人的な備忘録：Route 53 のホストゾーン無料ルールを記事としてアウトプットしてみた

## はじめに

AWS を利用する中で、**日々の検証費用やデプロイ作業に伴うコスト管理** は、とても重要なスキルの一つだと考えています。

:::note info
**今回は、その中でも **Route 53 の無料利用枠** に焦点を当ててまとめました。**
:::

技術的な検証というよりも、**私自身が感動した内容を共有** する形になりますので、温かい目で見守っていただければ幸いです。

## 記事を書こうと思ったきっかけ

受講している **IT スクールのチーム開発（ハッカソン）** に参加した際、インフラ担当をメインで務めることになりました。

:::note warn
***AWS のサービスを利用する上で、**どこまでが無料で、どこから料金が発生するのか** は非常にシビアに考える必要があります。***
:::

その中で無料利用枠を調べていくうちに、**ドメイン管理サービスである Route 53 にお得な情報** を見つけたため、記事としてアウトプットすることにしました。

## そもそも Route 53 とは？

Route 53 の魅力を簡単にまとめると、以下のポイントがあります。

:::note note
- **信頼性**  
  AWSのインフラ上で動作し、高い可用性を提供。

- **スケーラビリティ**  
  大規模なトラフィックにも対応可能。

- **シンプルな操作性**  
  コンソールやCLIを使った簡単な設定。

- **コスト効率**  
  必要な分だけ課金される従量課金制。
:::

Route 53 については、過去の記事で体系的にまとめていますので、こちらも参考にしてみてください。

https://qiita.com/free-honda/items/74f88eb4a02f6dd768ec

## 作成したホストゾーンは 12 時間以内だと無料

これまで自宅での検証では、「Route 53 のホストゾーンは一度作成するとそこそこお金がかかる」と認識していました。  
しかし、**実は 12 時間以内に削除すれば無料** ということが分かりました。

**公式サイトから一部抜粋**

> **ホストゾーンとレコード**
> 
> - ホストゾーンあたり **0.50 USD/月**（最初の 25 個のホストゾーン）  
> - ホストゾーンあたり **0.10 USD/月**（それを超えるホストゾーン）  
> 
> 上記の **1 か月あたりのホストゾーンの料金は、1 か月に満たない分について按分計算されません**。  
> ホストゾーンは **作成した時点で課金され**、翌月からは各月の初日に請求されます。  
> 
> **テスト用として、作成後 12 時間以内に削除されたホストゾーンには料金がかかりません**。  
> ただし、パブリックホストゾーンでのクエリには以下の料金が適用されます。  
> **プライベートホストゾーンに対するクエリは、Route 53 のお客様に追加料金なしで提供** されます。

https://aws.amazon.com/jp/route53/pricing/

つまり、**テスト用として作成したホストゾーンは、12 時間以内に削除すれば料金がかからない** ということです。

以下の画像の通り、先月 Route 53 を使って **ホストゾーンを 10 回程度作成** しましたが、料金は発生していないことが確認できました。

![Screenshot 2025-02-01 at 20.19.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/1094a62a-f0b5-8be3-8b04-88eaff8fe67e.png)

## まとめ

最後までお読みいただきありがとうございました！  今回は **私自身が感動したこと** を記事としてアウトプットしてみましたが、**無料で使えるのは本当に凄い** と思いました。

今後も **お得な情報があれば積極的に記事にまとめていく** つもりですので、引き続きよろしくお願いいたします！

## おまけ：今後も積極的に Route 53 を使っていきたい

私自身、**お名前.com で独自ドメインを購入** していますが、今後は**Route 53 に 12 時間以内で登録し、テスト環境として活用** していきたいと考えています。

:::note warn
***ちょっとした技術検証のために、**独自ドメインを使ったテスト環境の構築などを試していきたい** と思いました！***
:::

## Route 53 に関する記事

Route 53 に関連する情報を、以下の記事で詳しくまとめています。ぜひ参考にしてください！

https://qiita.com/free-honda/items/7a1fa3336273c3b7cfab

https://qiita.com/free-honda/items/8fb5124ae36616d64dd1

https://qiita.com/free-honda/items/ee77d4ad7a0617470cb7

https://qiita.com/free-honda/items/1d8810054b556739afaf

https://qiita.com/free-honda/items/4a7fae20e72a939aa51b
ESP32でサーボ１０個を制御

# サーボ10個でバイバイ

ESP32とPCA9685の組み合わせ。
<iframe width="585" height="1040" src="https://www.youtube.com/embed/MJLfBgvB8BU" title="DCDCコンバーターの罠！？サーボモーター10個制御への道 #電子工作 #爆発事件 #コンデンサ破裂 #tanilab #エンジニアライフ #電子回路 #失敗談 #ものづくり" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>


```c
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// PCA9685のアドレス（デフォルトは0x40）
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);

// サーボの最小値と最大値（パルス幅）
#define SERVOMIN  115 // 150 // 最小パルス幅
#define SERVOMAX  525 // 600 // 最大パルス幅

int angleToPulse(int angle) {
  return map(angle, 0, 180, SERVOMIN, SERVOMAX);
}

void setup() {
  Serial.begin(115200);
  Serial.println("PCA9685テスト開始");

  // I2C通信の初期化
  pwm.begin();
  // PWM周波数を50Hzに設定（サーボモーターに適した周波数）
  pwm.setPWMFreq(50);

  int pulselen = angleToPulse(0);
  Serial.print("0度: ");
  Serial.println(pulselen);
  
  for (uint8_t i = 0; i < 10; i++) {  
      pwm.setPWM(0, 0, pulselen);
      pwm.setPWM(1, 0, pulselen);
      pwm.setPWM(2, 0, pulselen);
      pwm.setPWM(3, 0, pulselen);
      pwm.setPWM(4, 0, pulselen);
      pwm.setPWM(5, 0, pulselen);
      pwm.setPWM(6, 0, pulselen);
      pwm.setPWM(7, 0, pulselen);
      pwm.setPWM(8, 0, pulselen);
      pwm.setPWM(9, 0, pulselen);
  }
  
  Serial.println("OK");
}

void loop() {
  // サーボを0度から180度まで動かす
  for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
      pwm.setPWM(0, 0, pulselen);
      pwm.setPWM(1, 0, pulselen);
      pwm.setPWM(2, 0, pulselen);
      pwm.setPWM(3, 0, pulselen);
      pwm.setPWM(4, 0, pulselen);
      pwm.setPWM(5, 0, pulselen);
      pwm.setPWM(6, 0, pulselen);
      pwm.setPWM(7, 0, pulselen);
      pwm.setPWM(8, 0, pulselen);
      pwm.setPWM(9, 0, pulselen);
      delay(2);
  }

  // サーボを180度から0度まで戻す
  for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
      pwm.setPWM(0, 0, pulselen);
      pwm.setPWM(1, 0, pulselen);
      pwm.setPWM(2, 0, pulselen);
      pwm.setPWM(3, 0, pulselen);
      pwm.setPWM(4, 0, pulselen);
      pwm.setPWM(5, 0, pulselen);
      pwm.setPWM(6, 0, pulselen);
      pwm.setPWM(7, 0, pulselen);
      pwm.setPWM(8, 0, pulselen);
      pwm.setPWM(9, 0, pulselen);
      delay(2);
  }
}
Ubuntu 24.04＋RTX3060(12GB)の環境でOllamaと日本語版DeepSeekを動かしたときのメモ

流行りの生成AIを使ってみたくて試してみました。  
おおよそは他の方の情報をコピペしただけですが、後に続く方の参考になるかと思ってメモしておきます。  
手順は覚えてる範囲で書いていますが、追試してないので間違ってたらごめんなさい。

# 環境
以下の環境で構築しました。CPUやメモリは少なくても大丈夫ですが、GPUに関してはVRAMが12GB以上かつNVIDIAのものではないとダメかと思います。使用する14Bモデルが11GBぐらいあるので。
- Ubuntu Linux 24.04 
- CPU:Ryzen 7 5700G、RAM:64GB
- nVidia RTX3060 12GB

# 構築手順
Ubuntu 24.04をクリーンインストールして、最新版にした状態からスタートしました。  
インストール時にnvidiaのGPU用ドライバーが自動的に組み込まれている想定です。（クリーンインストールだと指定できます）

1. dockerを入れる。  
    `sudo apt install docker.io`
1. ユーザーをdockerグループに入れる。
    ``id `whoami` ``で所属してるグループを確認
    `grep docker /etc/group`でdockerグループがあるか確認
    ``sudo usermod -aG docker @USERNAME@`` ←＠で囲んだ部分は自分のユーザー名
    再ログインかOS再起動すれば次回からdockerグループに入ってるはず
    ``id `whoami` ``で確認できる
1. (必須ではないけど)btopを入れる。
    `sudo apt install btop`
    なくても動きます。
    CPUやRAMやGPUなどの使用率をターミナルで一覧できるので便利です
1. nvidia-container-toolkitを入れる。  
    NVIDIAのサイト[Installing with Apt](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html#installing-with-apt)に従います。
    ただし、2番のsedを使う部分はsudoを頭につける必要ありです。
    ※元の手順書がrootユーザーの存在するDebian向けなのかも？
1. からあげさんのサイトを参考にOllamaを入れる
コピペすると行頭に`$`が入ってるので削除が必要。`--gpus=all`付きの方を使いました。
`docker run -d --gpus=all -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama`
1. 続けてOpenWebUIを入れる
`docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main`
1. モデルをpullする
モデル名はdevliveさんの記事を参考に、hf.coからggufまでをコピーしてます。9GBぐらいダウンロードします。
`docker exec ollama ollama pull hf.co/mmnga/cyberagent-DeepSeek-R1-Distill-Qwen-14B-Japanese-gguf`
    - pullするデータはホストの`/var/lib/docker/volumes/ollama/_data`に保存されます
1. ブラウザで`http://localhost:3000`を開く。Firefoxで大丈夫でした
1. OpenWebUIの初期設定をする。メールアドレスとパスワードは次回以降に使うので、どこかにメモしましょう

# 停止手順と2回目以降の起動手順
今までロクにDocker触ったことがなくて、ここで手こずりました。
## 停止手順
以下の手順で停止しました。
1. `docker ps`で稼働中のコンテナ名のリストを表示して一番右側のカラムの名前を確認。ここまでの手順通りなら`open-webui`と`ollama`がいるはず
1. `docker stop open-webui`でOpenWebUIを停止
1. `docker stop ollama`でOllamaを停止

## 2回目以降の起動手順
以下の手順で2回目以降は起動できました。
1. `docker start ollama`でOllamaを起動
1. `docker start open-webui`でOpenWebUIを起動
1. ブラウザで`http://localhost:3000/`を開く。エラーになる場合は1分ほど待ちます

# 参考にしたサイト
以下のサイトを参考にしました
- [Installing the NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html)
DockerからGPUを参照する際に必要らしいツールを入れる手順を参考にしました
- [Ollama + Open WebUI でローカルLLMを手軽に楽しむ](https://zenn.dev/karaage0703/articles/c271ca65b91bdb) 
Docker導入後のコマンドを参考にしています（というかほぼコピペしました
- [Ollama で 「DeepSeek-R1 」の日本語追加学習モデルを動かす](https://note.com/devlive/n/n91bfe991fef4) 
pullするモデルの名前はこちらを参考にしました
シングルクォーテーション、ダブルクォーテーション、バッククォーテーションの違いをまとめた

## はじめに

Linuxにおいてシングルクォーテーション、ダブルクォーテーション、バッククォーテーションとあるけど結局どれを使えばいいか悩んでしまいませんか？

:::note info
ここでは、それぞれの違いを解説していきます。
:::

## シングルクォーテーション

- 囲んだ文字を`文字`としてそのまま解釈します
  - 変数だろうと、何だろうと関係ありません

```bash
name="Alice"
echo 'Hello $name'    # 出力: Hello $name
echo 'Current path: $PATH'    # 出力: Current path: $PATH
```

## ダブルクォーテーション

- 基本は**文字列**として解釈します
- 変数があれば**変数**として解釈します
- エスケープは解釈してくれます
- コマンド置換($())は機能します
- その他の特殊文字（*、?など）は文字列として扱われます

```bash
name="Bob"
echo "Hello $name"    # 出力: Hello Bob
echo "Current directory: $(pwd)"    # 出力: Current directory: /home/user
echo "Price: \$100"    # 出力: Price: $100
```

## バッククォーテーション

- **コマンド**の実行結果を取得したい時に使用します
- $(command)と同じ機能を持つ
- ネストすると可読性が悪くなるので$(command)の使用が推奨されています


```bash
current_date=`date`
echo "Today is: $current_date"    # 出力: Today is: Wed Feb 1 10:30:45 JST 2025

# 同じことを$(command)で書く場合：
current_date=$(date)
echo "Today is: $current_date"    # 出力: Today is: Wed Feb 1 10:30:45 JST 2025

# ネストの例
echo "Files in current directory: `ls \`pwd\``"    # バッククォーテーションでは読みにくい
echo "Files in current directory: $(ls $(pwd))"    # $()の方が読みやすい
```

## 変数だけで比べてみる

```bash
# nameに名前を入れる
name = "Alice"

# シングルクォーテーション
echo 'hello $name'
# そのまま出力される
hello $name

# ダブルクォーテーション
echo "hello $name"
# nameの中身を出力する
hello Alice

# バッククォーテーション
echo `hello $name`
# コマンドじゃないから怒られる
-bash: hello: command not found
```

## まとめ

- 文字列として扱いたいときは`シングルクォーテーション`
- 変数を扱うときは`ダブルクォーテーション`
- コマンドを扱うときは`バッククォーテーション`
    - $(command)を推奨
金のフレーズ機械学習

家電製品 (Home Appliances)
Refrigerator = 冷蔵庫
"In the experiment, the refrigerator's energy consumption was measured to study its efficiency in various temperature settings." （実験では、冷蔵庫のエネルギー消費量を測定し、異なる温度設定での効率を調べました。）

Washing machine = 洗濯機
"A machine learning model was trained to predict the optimal washing machine cycle based on load size and fabric type." （機械学習モデルは、荷物のサイズと生地の種類に基づいて最適な洗濯機サイクルを予測するために訓練されました。）

日用品 (Daily Goods)
Plastic bag = ビニール袋
"The dataset includes information about the use of plastic bags, which was used to predict environmental impact." （データセットにはビニール袋の使用に関する情報が含まれており、それを使用して環境への影響を予測しました。）

Scissors = はさみ
"In a robotics project, the system was trained to use scissors to cut different materials with precision." （ロボティクスのプロジェクトでは、システムがさまざまな素材を正確に切るためにハサミを使うように訓練されました。）

職業 (Occupations)
Mechanic = 機械工
"The machine learning algorithm is designed to help the mechanic predict the maintenance needs of a vehicle based on usage patterns." （機械学習アルゴリズムは、使用パターンに基づいて車両のメンテナンスニーズを予測するのに役立ちます。）

Surgeon = 外科医
"A deep learning model was developed to assist surgeons in diagnosing diseases from medical imaging data." （深層学習モデルは、外科医が医療画像データから病気を診断するのを支援するために開発されました。）

学問分野 (Fields of Study)
Robotics = ロボット工学
"Robotics research often utilizes machine learning to improve the autonomy and decision-making capabilities of robots." （ロボット工学の研究では、ロボットの自律性と意思決定能力を向上させるために機械学習がよく利用されます。）

Economics = 経済学
"Machine learning models have been used to predict economic trends based on historical data and various economic indicators." （機械学習モデルは、過去のデータとさまざまな経済指標に基づいて経済の動向を予測するために使用されています。）

接続詞・前置詞 (Prepositions & Conjunctions)
Due to = ~が理由で
"The model's performance decreased due to the lack of sufficient training data." （十分な訓練データが不足していたため、モデルのパフォーマンスが低下しました。）

Although/Though = ~にもかかわらず
"Although the model had high accuracy, it still struggled with certain types of input data." （モデルは高い精度を持っていたにもかかわらず、特定のタイプの入力データには苦労しました。）

接続副詞 (Conjunctive Adverbs)
Therefore = したがって
"The dataset was not large enough, therefore, the model's prediction accuracy was lower than expected." （データセットは十分に大きくなかったため、したがって、モデルの予測精度は予想よりも低かった。）

However = しかし
"The model performed well on small datasets; however, it struggled when the data size increased." （モデルは小さなデータセットではうまく機能しましたが、データサイズが増えると苦労しました。）
伝える相手を考える

# この記事の目的
４つの配慮ができるようになる
- 知識への配慮
- 価値観や意識への配慮
- 感情への配慮
- 共通原則への配慮

# 目次
▼[伝える相手の「知識」への配慮](#伝える相手の知識への配慮)
▼[伝える相手の「価値観や意識」への配慮](#伝える相手の価値観や意識への配慮)
▼[伝える相手の「感情」への配慮](#伝える相手の感情への配慮)
▼[人間のもつ「共通原則」への配慮](#人間のもつ共通原則への配慮)


# ▼伝える相手の「知識」への配慮
## 最初は読み手の知っていることから始める
階段を一歩一歩登らせていくイメージで説明する。
## 具体例を使う
読み手の知っている具体例を使わないと、混乱をさせるので注意する。
## 専門用語は説明してから使う
説明の流れの中で専門用語を知ってもらう方法がよい。しかし、いきなり専門用語を使う必要がある場合は、注釈を利用するとよい。
略式を利用する場合は、「正式名称（以降、略語）示す。

# ▼伝える相手の「価値観や意識」への配慮
## 自分の認識をそのまま前提にしない
伝える相手の認識はどうなのかを考える
## 自分の視点で書かない
例えば、案内用の地図を作成するとき、伝える相手がどこにいるのか、どんな行動をするのかを考えて作成する
## 強調表現を使用する
- 内容ごとに小見出しを作る
- 「つまり」などで繰り返す
- 括弧で囲む

# ▼伝える相手の「感情」への配慮
## 肯定的な表現を使う
>:x: サーバースペックを上げるとシステム速度は３倍に向上しますが、コストは２倍になります
>:o: サーバースペックを上げるとコストは２倍になりますが、システム速度は３倍向上します

# 人間の持つ「共通原則」への配慮
## 認知心理学によって明らかになっている心理を利用する
- 第一印象をよくする
- 意味のまとまりを作る
- 例を用いて知識と紐づける
- 読む気にさせる工夫をする

# 参考文献
[日本語スタイルガイド（第3版）](https://jtca.org/learn-tc/publication/guide_jsg/)
Bunで実行バイナリを作る際のバイナリの場所の取得

# やりたいこと

**バイナリの場所を実行時に取得したい!!!**

# 解決策

## 要約
```typescript
process.execPath
```
を使おう！

## 説明

```sh
$ bun build --compile ./index.js
```

みたいに実行可能バイナリを作るとき、そのバイナリの場所を取得するには `process.execPath` を使えば取得できる。
これは本来`Node`本体のパスを取得するものだが、バイナリには bun のランタイムが含まれるため、これで取得出来るらしい。

てっきり `__dirname` 使うのかと思っていた。

ちなみに `__dirname` とかは~~何と驚き~~ **コンパイル時にハードコーディング**なため、意味がなく(まあ定数と言えば定数なので。あとそもそも非推奨らしいが)、
[解決策として提示されている](https://github.com/oven-sh/bun/issues/4216) `import.meta` 系も `B:\~BUN\root` というよくわからない値を返す。
(たぶんこれはモジュールに対する解決策で、なおかつ `__dirname` を Node.js 互換にしてほしいという要望なのであまり関係がなさそう。
ちなみに`B:\~BUN\` は多分[ここ](https://github.com/oven-sh/bun/blob/26d3688e53369513d2df55d2c20b55a5b29d6fb5/src/StandaloneModuleGraph.zig#L33)から来てる)


# 検証


```powershell
> pwd
D:\tmp\bun-dirname\hoge

> bun init 
```

```typescript
// index.js
console.log("process.execPath:\t",process.execPath)     // これでやりたいことができる
console.log("import.meta.dir:\t",import.meta.dir)       // 変な値になる(B:\~BUN\root)
console.log("__dirname:\t\t", __dirname)                // 場所はハードコーディング
```

- 普通に実行
    ```powershell
    > pwd
    D:\tmp\bun-dirname\hoge # 同じディレクトリで
    
    > bun .\index.ts  # 普通に実行
    process.execPath:        D:\Scoop\apps\bun\1.1.42\bun.exe   # Bun 本体のパスが来る(僕はscoopから入れた)
    import.meta.dir:         D:\tmp\bun-dirname\hoge            # ちゃんと正解
    __dirname:               D:\tmp\bun-dirname\hoge            # ちゃんと正解
    ```


- コンパイルしてみる
    ```powershell
    > pwd 
    D:\tmp\bun-dirname\hoge # ディレクトリ戻って

    > bun build --compile .\index.ts    # コンパイル
    [107ms]  bundle  1 modules
    [9.688s] compile  index.exe

    > .\index.exe           # 実行
    process.execPath:        D:\tmp\bun-dirname\hoge\index.exe      # あってる(basename やれば同じになる)
    import.meta.dir:         B:\~BUN\root                           # ???
    __dirname:               D:\tmp\bun-dirname\hoge                # あっているように見える
    ```
    
- 場所を移してみる
    ```powershell
    > cp .\index.exe ..\index.exe   # ひとつ親にコピー

    > cd ..; pwd
    D:\tmp\bun-dirname

    > ls
    hoge
    index.exe

    > .\index.exe   # 親の方のものを実行
    process.execPath:        D:\tmp\bun-dirname\index.exe       # 追従した
    import.meta.dir:         B:\~BUN\root
    __dirname:               D:\tmp\bun-dirname\hoge　          # かわらない
    ```

# おわりに

誰かもっといい方法があれば教えてください。

あと自分の検索力が落ちてきていると感じた。
自分では調べても出てこなかったのに、GPT に聞いたら出てきた...(ﾄﾎﾎ...)
(もちろんそれから調べて検証もしているので内容は自分が保証します。何かあったら教えてください。)
【Rails】Tom Selectでテキストボックスに複数のテキストを入力させる

どうもこんにちは。

今回は`Tom Select`というライブラリを使用して、テキストボックスに複数のテキストを入力できるように実装したので、その備忘録として残しておきます。

https://tom-select.js.org/examples/

# 経緯

元々、`Select2`というライブラリを使用して、テキストボックスに複数のテキストを入力できるように実装していましたが、IMEがONになっている状態で入力すると、以下のように正常に入力できない現象が発生していました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/651da4a8-b0fa-0f03-4e0e-4bb538d78fe4.png)

一見テキストボックスに見えますが、コード上ではセレクトボックスとして実装しています。これが気に食わなかった...

# Tom Select

`Tom Select`の場合は、テキストボックスはテキストボックスとしてコーディングすることができるので楽でした。

導入方法は以下です。

## 1. importmap.rb

CDN経由でライブラリをインストールするようにしました。

```rb:config/importmap.rb
pin "tom-select", to: "https://cdn.jsdelivr.net/npm/tom-select@2.4.2/dist/js/tom-select.complete.min.js"
```

## 2. application.js

```js:app/javascript/application.js
import "tom-select";
```

## 3. tom-select.css

以下のURLから、CSSのスタイル定義をコピーして、`app/assets/stylesheets`ディレクトリ配下におきます。（ファイル名は`tom-select.css`とします。）

https://cdn.jsdelivr.net/npm/tom-select@2.4.2/dist/css/tom-select.css

## 4. application.css.scss

```scss:app/assets/stylesheets/application.css.scss
*= require tom-select
```

## 5. （必要があれば）rails assets:precompile

```sh
$ rails assets:precompile
```

プリコンパイルしたらrailsサーバを再起動

## 6. 要素を指定してtom-selectを適用

```js
function initializeTomSelect(selector) {
    const el = document.querySelectorAll(selector);
    el.forEach(function(e) {
        new window.TomSelect(e, {
            persist: false,
            createOnBlur: true,
            create: true,
            maxItems: null,
            placeholder: '選択肢を入力',
            delimiter: ','
        });
    });
}
```

このままだとイメージ通りの動作をしなかったので、CSSスタイルを上書きしました。

```css
#field_options_text.field-options .field-options-text {
  width: 100%;
  flex: 1;
  min-width: 500px;
}

.ts-control input {
  width: 100%;
}

.ts-hidden-accessible {
  display: none !important;
}
```

これで以下のように動作しました。

![スクリーンショット 2025-02-01 19.19.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/439fd019-978e-f4d5-bfa8-0aaa7e800215.png)

以上
Web Cripto API(SHA256)がHTTP環境で使えない時の対処方法

## 素直にライブラリを使いましょう:relaxed:
https://github.com/Caligatio/jsSHA

```powershell
npm install jssha
```

```utils.mjs
import jsSHA from "jssha";

/**
 * パスワードをSHA-256でハッシュ化する
 * @param {string} password - ハッシュ化するパスワード
 * @return {string} - ハッシュ値
 */
export function toHash(password) {
    const shaObj = new jsSHA("SHA-256", "TEXT");
    shaObj.update(password);
    const result = shaObj.getHash("HEX")
    return result;
}

console.log(toHash("たかし"));
// 出力 → 4db72cb639c9c8f8aa4e8fbdfd6228f5e4025a1260781d3499310a576cf75cbb
```

## そもそもSHA256ってなに？
SHA256(Secure Hash Algorithm 256-bit)はハッシュ関数の一つで、ハッシュ関数とは何かしらの値を入れると、固定長のハッシュ値が出力されるものです。

ハッシュドポテトおいしいよね。ハッシュってめちゃくちゃって意味らしい。めちゃくちゃポテト。

## ハッシュ関数の性質
最近ハッシュ関数について知ってちょっと勉強してるのですがその性質がとても興味深いんです！

入力が少しでも違うと全く違う値が出力される、そしてハッシュ値から元の値には戻せないという不可逆性。
アルゴリズムを紹介している記事を見ましたが全く理解できませんね:head_bandage:

2の256乗「115,792,089,237,316,195,423,570,985,008,687,907,853,
269,984,665,640,564,039,457,584,007,913,129,639,936」という想像もつかない巨大な空間の中に入力された値を1点の座標にマッピングするイメージ...？

https://qiita.com/takaminmin/items/698dad16a0d3a654b7e5#3-sha-256%E3%81%AE%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0

## ハッシュ関数の使い道
主にパスワードを平文で保存しないためにハッシュ値に変換して保存する。
あとは、入力の違いを検出できるという性質を利用して元データに変更が加えられたかどうかも判別できますね！
20250201

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3814426/5ecd322e-fa09-cf98-c048-3b83b80b478d.png)
変換	win+/
一括選択：	Ctrl + A +クリック
半角スペース： 	Ctrl + スペース
複数選択：	 Ctrl + クリック
エクスプローラーNEW	win + e
ファイル戻る：	Alt + ←　：進む：→
下のピン止めを開く　：　	win + 指定の数字
画面切り替え　：　	Alt + tab tabだけ離す
全ての画面を閉じる：　	win + D
タブを開く：	Ctrl + 数字
間違えてタブを閉じたのを復活：	Shift ＋Ctrl ＋T
仮想デスクトップを作成	Win ＋ Ctrl + D
仮想デスクトップを切り替える	Win + Ctrl + 矢印
仮想デスクトップを削除	Win + Ctrl + F4
画面分割を指定	win + z
右クリック	Shift ＋F10
カタカナに変換	F7 or FN+ F7
アルファベット	F10
タスクマネージャー	ctrl + shift + esc
GitHub Pages からFirebase に移行するまで

## 前置き
もともとGitHub Pages にAngular サイトを公開していた。  
正直不満はないが、なんとなくBaaS を使ってみたかった。  
なので、Firebase に移行し、ついでにAnalytics を設定した時のメモがこちら。  


## 本編
### firebase cli でHosting の設定
firebase cli の指示に従えばOK  
あとはメインのブランチにマージしたらGitHub Actions が動きデプロイされる。  

個人的に詰まったポイント
- デプロイしたけどアイコンしか表示されない。
  - 原因1:firebase.json のhosting.public がデフォルトのpublicだった。
    - ここで指定したフォルダ配下のファイルがHosting にアップロードされる。
    - firebase init で適当にデフォルトで進めていたからこうなった。
  - 原因2:ビルドオプションで`--base-href /project-name/`を指定していた
    - GitHub Pages とFirebase のURL の違いを考えていなかった。
- (ちょっと違うけど)プルリクを再開できなかった。
  - 原因:スカッシュマージしたから。
- Firebase のHosting の画面がダッシュボードにならない。
  - 単純に初回だから？時間がかかっただけ。

メモ
- Hosting ではAngular 等のSPA ようにrewrites が設定できる。
  - URL に対応しないやつはdestination に設定したファイルが得られる。
- GitHub Actions 生成時にサービスアカウント(機械用のアカウント)とtoken も生成される。
  - token はGitHub のsecrets に自動で登録されるので何もしなくてOK。
  - このtoken は秘密にする必要がある。
- プルリク時に実行されるGitHub Actions でプレビューが見れる。
  - 本番と別のドメインでアクセスでき、動作確認ができる。しかもプルリクごとに別！

### @Angular/fire の設定
やったことを箇条書きにすると以下の通り
- Firebase にアプリを登録する。  
- 登録したアプリの設定画面からfirebaseConfig を確認。
- `ng add @angular/fire`を実行。
- 例の通りapp.config.ts 等を修正。
- dotenv をインストール& 環境変数からfirebaseConfig を取得するts を作成。
- Secrets にfirebaseConfig を登録。
- GitHub Actions で環境変数にSecrets を設定。

個人的に詰まったポイント
- Firebase のコンソール画面からAnalytics を使おうとしたけど使えなかった。
  - 原因:アプリを登録していなかった。
    - Project があって、その中にアプリがあって、そのアプリからの情報をもとにAnalytics が動く流れ。
    - なので、アプリがないとAnalytics も何もない。
- Analytics が反応しなかった。
  - 原因1:Secrets を設定し忘れていた。
    - いくつも設定する必要があり...
  - 原因2:Analytics を正しく記載できていなかった。
    - 結局よくわかっていないのであとで勉強する予定。
- Analytics のcookie がサードパーティーだった。
  - chrome でも警告が出たし、firefox だとエラーが出ていた。
  - だけど、どちらも閲覧ページの情報等は取得できていた。
  - ちょっとよくわからないのであとで勉強する予定。

メモ
- firebaseConfig のAPI key は公開しちゃっても大丈夫？
  - 公式のドキュメントにも問題ないと記載がある。
  - 理由はバックエンドリソースへのアクセス制御には使用されないから、とのこと。
  - それよりも使えるAPI を制限して余計な穴は開けない方がよいよ、とのこと。
  - 使えるAPI の制限はAPI key でどういう操作ができるかは他のルールでやるという役割分担に見える。
  - どのアプリからかwebならどのURLからかと、使えるAPIを制限できる。

https://firebase.google.com/docs/projects/api-keys?hl=ja#general-info

- Analytics にはストリームという概念がある。
  - firebaseConfig のmeasurementId で一意に特定している。


## 感想
大分難しかった。  
そして、分からないことがものすごくあった。  


今回の記事は以上です。  

前回記事はこちら  

https://qiita.com/magurouhiru/items/e074248fabfe485b5a79

詳細見たい人はこちら  

https://mysite-with-firebase.firebaseapp.com/
【これを読めば分かる】AWS Wavelengthを使ってエッジにサーバーを構築してみた！

## 1. はじめに

最近では、IoTや自動運転、メタバースなどで「5G」が注目を集めていますね。
その中でも「MEC (Multi-access Edge Computing)」は、5Gネットワークの分散処理技術として重要な役割を持っています。
本記事では、AWS Wavelengthを利用して、エッジサーバーを構築し、実際の構築手順を紹介します！
[5Gの基礎やMECの概念については、こちら](https://qiita.com/shun8747/items/65f32ab98c8c3abf937d)

## 2. AWS Wavelengthによる5Gエッジコンピューティング
AWS Wavelengthは、5Gネットワーク内でAWSサービスを利用できる技術で、2020年にKDDIがサービスを開始しました。

### AWS Wavelengthの特徴
#### AWSクラウドを、5Gネットワークのエッジで利用可能にするサービス
- インターネットを経由せず、5Gネットワーク内でAWSを利用可能
- AWS Wavelengthでは、従来のAWSと同様の操作が可能
- マネジメントコンソールで全て管理でき、東京リージョンのクラウドと簡単に連携可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3998881/350d1832-72d9-9404-bf21-2631ea8b0d21.png)


## 3.構築手順
東京のWavelength ZoneのInstanceにアクセスできるのは、キャリアネットワークのユーザーからのみ
VPC内においては通信制限はない
1. **VPC・Subnetを作成**：AWSコンソールでVPC/Subnetなどを作成
2. **Wavelength Zoneを指定してSubnetを作成**：Wavelength Zoneに対応したエリアを選択
3. **Carrier Gatewayを作成**：Carrier Gatewayをデフォルトルートに指定したRoute Tableを作成し、Subnetに紐づける
4. **Instanceを起動しCarrier IPを割り当て**：Carrier IP(Elastic IPのようなもの)を取得し、Instance に割り当てる
5. **外部通信確認**：Carrier IPを利用し、対象ネットワークからのアクセスをテスト

✔ 東京のWavelength ZoneのInstanceにアクセスできるのは、***キャリアネットワーク***のユーザーからのみ
✔ VPC内においては***通信制限***はない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3998881/a7410dad-a079-b633-87b1-2318cfd2e291.png)


## 4.構築手順
**はじめに. オプトイン方式でWavelengthを有効化**
![構築1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3998881/d0f18619-8220-cd33-846e-0f56273822e5.png)

1. **VPC・Subnetを作成**
2. **Wavelength Zoneを指定してSubnetを作成**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3998881/ed96900a-9a77-b83c-48c4-7983aa76cbca.png)
3. **Carrier Gatewayを作成**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3998881/d665f92c-73c8-cd88-c587-6b6d781f0404.png)
4. **Instanceを起動しCarrier IPを割り当て**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3998881/2a13870f-d2f8-30be-5158-865821325f94.png)
5. **外部通信確認**
![構築5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3998881/59b40627-e070-1744-1b69-ff3dbf15eca6.png)
Android上でTinySwallow-1.5Bを動作させる！

# はじめに
私は、GPT-3などの大規模LLMが出始めたぐらいのころ、[rinna/japanese-gpt-1b](https://huggingface.co/rinna/japanese-gpt-1b)でローカル動作するチャットボットを作ろうとして挫折したことがあります。
当時試した1b級のモデルは、どれも全然会話になりませんでした。
独自のデータセットを作成し、ファインチューニングとか色々試したんですが、どうしてもダメ。
「1b台のモデルじゃどうやったって無理だな」とあきらめていました。

↓当時ファインチューニングしたAIモデルとの会話（なぜか何を言っても会話を打ち切ろうとしてくる）
![F6IqyrabUAA8HD5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/90b0c1bb-82e7-63cb-a310-bb87b3daf846.png)

ところが、最近Sakana.AIが公開した TinySwallow-1.5B を試したとき、衝撃が走りました。これはすごい。どうやら新しい手法を使った知識蒸留をしているようで、ローカル上でまともに会話できています。まさかこのサイズでそんなことができるなんて......
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/def5b6f4-789b-b6e0-5711-cb79485751ab.png)

ということで、技術の進歩に感動した勢いでこのモデルをAndroid上で動かす記事を書くことにしたわけです。

# できるだけ簡単に動かしたい
Termuxを利用してLlama.cppを動作させるなどあるようですが、私はコマンド使いたくない。できるだけ簡単に、できるだけ既にある物を利用して動作させたいと思いました。
そこで調べたところ、「PocketPal」というアプリがよさそうだなーと思ったので使ってみます。

https://play.google.com/store/apps/details?id=com.pocketpalai&hl=jp_JP

:::note
環境：
HUAWEI Matepad 11
Qualcomm Snapdragon 865
RAM 6GB
HarmonyOS 2 (Android10~11相当らしい)
:::

アプリを起動したら「Go to Models」を押す。
![Screenshot_20250201_180944_com.pocketpalai.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/c992d8b7-4ce3-cfba-d194-6021cab84529.jpeg)

右下の＋マークから、「Add from Hugging Face」を押す。
![Screenshot_20250201_181001_com.pocketpalai.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/10d7091a-7f5b-37de-b84d-4e09ad1e1d2a.jpeg)

Tinyswallowを検索してダウンロード。
![Screenshot_20250201_181258_com.pocketpalai.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/cd936216-3164-e2da-3e44-cd85ce3cd200.jpeg)

Modelsを開いて「Load」を押す。
![Screenshot_20250201_181512_com.pocketpalai.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/44a564b4-1ee1-b6ac-9133-74c86466cc0c.jpeg)

ロードが完了したら自動でチャット画面に移行し、AIとチャットできるようになります。
(TinySwallowはQwenが元になっていますが、Gemmaのデータも使ってるらしく、自分のことをGemmaと自称してきた。)
![Screenshot_20250201_181603_com.pocketpalai.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/371efefc-846c-0ddc-a972-a9356c14b8ca.jpeg)

# おわりに
思ったより簡単すぎてビビりました。ダウンロードまでやってくれるアプリがあるとは......
今までスマホでローカルAI動作なんて無理だろって思ってましたが、実現してしまったことに驚き。
技術の進歩ってすごいなぁ......
os.environ.get() vs os.environ[] の使い分けと違いを解説

Pythonで環境変数を取得する際、os.environ.get() と os.environ[] の2つの方法があります。

### os.environ.get() の特徴

- キーが存在しない場合にNoneを返す（エラーにならない）
- デフォルト値を指定できる（例: `os.environ.get("API_KEY", "default_value")`）

    ```python
    import os
    
    api_key = os.environ.get("API_KEY")
    if api_key:
        print("APIキーが設定されています:", api_key)
    else:
        print("APIキーが設定されていません")
    ```

    使うべき場面:

    - 環境変数が未設定でも処理を継続したいとき
    - デフォルト値を設定したいとき

### os.environ[] の特徴

- キーが存在しない場合にKeyErrorが発生する
- 値が必須であることを保証できる

    ```python
    import os
    
    try:
        api_key = os.environ["API_KEY"]
        print("APIキー:", api_key)
    except KeyError:
        print("環境変数 'API_KEY' が設定されていません")
    ```
    
    使うべき場面:
    
    - 環境変数が設定されていない場合、エラーを出して処理を止めたいとき
    - クリティカルな設定値（APIキーやデータベース接続情報など）を必須にしたいとき


### まとめ

- os.environ.get() は環境変数がなくても動作するため、柔軟なコードを書きたいときに適している。
- os.environ[] は環境変数が必須の場面で適しており、未設定ならエラーを発生させることで問題を早期に発見できる。

環境変数をどのように扱うかを考慮し、適切な方法を選びましょう！
Oracle VM VirtualBox経由でLinux Mintをインストール

## 概要
docker-composeで作成したwordpressを同じネットワーク上のユーザが使用できることを目標に環境を構築しています。。。
メモ程度に記載していますのでご了承ください。


## 参考記事
Vimのインストール

https://ja.linux-console.net/?p=14543

Linux Mintのインストール

https://dezanari.com/virtualbox-linuxmint/

Docker-ComposeでWordPressとMySQLとphpMyAdminのローカル環境の構築

https://qiita.com/tomokei5634/items/75d2501cfb968d0cfab5

## 苦戦したところ
１）日本語の入力ができなかった
解決策：
・インプットメソッドフレームワークで言語サポートのパッケージをインストール
・再起動

https://www.gwtcenter.com/linux-mint-211-japanese-input

２）ローカルPCとVM間での通信がVMからローカルPCへの通信はできず(ping)
  ★調査するところ
　・ホスト側のipアドレス、サブネットマスク、ゲートウェイ
　・VM側のネットワーク設定のIPv4のアドレス、サブネットマスク、ゲートウェイ、DNS
 　・WindowsDefenderの「詳細設定」-「受信の規則」で、「仮想マシンの監視（エコー要求ICMpv４受信）」を有効化
　・VMのネットワーク設定
　・Linux Mintのファイアウォール
　　　sudo ufw status
　　　sudo ufw enable
　　　sudo ufw allow 8080/tcp

　　　

## docker,docker-composeのインストール
★Linux Mint 22 に Docker をインストールする方法
下記を実行した

https://ja.linux-console.net/?p=34465

★dockerの起動
docker infoでdockerデーモンが起動していなかったので
以下のコマンドを入力
・sudo usermod -aG docker $USER
・sudo reboot
・sudo systemctl start docker

★docker-composeのインストール
・sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
・sudo chmod +x /usr/local/bin/docker-compose
・docker-compose --version

## Docker-ComposeでWordPressを起動する
下記のURLを参考にした

https://qiita.com/tomokei5634/items/75d2501cfb968d0cfab5
Qwenを触ってみた感想

# 概要

Qwen趣味の創作やコーディングなどで使ってみた感想。
プロンプトの良し悪しは考えず、使い勝手目線で評価する。

## できること
- 創作アイデアの提案
- コードの生成
- 検索
- 画像生成
- 動画生成
これがデフォルトであるのは注目に値する。

## できないこと
- HTMLのプレビュー

- 上記以外のフォーマットでのファイル生成

コードのtextファイルを作成するなど。

## 良い点
- モデルの数が多い。
モデル全体の評価はしてない。
- 課金なしでそれなりに使える。
現時点ではサブスクリプションはまだない。肌感覚でそれなりの回数は使っているがリミットはない？


## 悪い点
- 速度に難あり。

無料だからなのか使っていると明らかに速度が落ちて止まることがある。


- 機能の切り替えができない。

検索したらそこからずっと検索し始まる。
「～して。」というとこれを調べた答えが返ってきた。そうじゃない…

- 文脈の理解度が弱い

検索のときが一番顕著。上記の通り、常に調べた結果が返ってくるので「なんで？」と聞いても一般的な回答が返ってきて質問の内容を理解していない。
※時折、関係のない単語を結びつけることもあった。

## 実現できなかったこと

- 短文で動きのある動画を作る。
エフェクトだけ動いてキャラは静止画だった。

- ストーリーを書く
文章が欲しかったがストーリーのプロットが出てきた。
Java初心者の環境構築

### 背景
Javaの勉強も兼ねて、Javaで作成したTODOアプリをECSデプロイしようと思い、備忘録的に環境構築の手順を残すことにしました。

### 環境構築

#### 前提条件
OS:MacOS M1チップ


参考：https://qiita.com/yamashi_takeru/items/fabf52d73703dbe9ed7a


#### インストーラーのダウンロード

https://www.oracle.com/jp/java/technologies/downloads/#jdk23-mac

ここに**Apple Silicon (ARM64) 向けのJava Development Kit (JDK)** またはインストーラがあるのでインストーラ（ARM64 DMG Installer）をダウンロードする。

インストールできたかは

```jsx
which java
/usr/bin/java
```
または
```
java --version
java 23.0.2 2025-01-21
Java(TM) SE Runtime Environment (build 23.0.2+7-58)
Java HotSpot(TM) 64-Bit Server VM (build 23.0.2+7-58, mixed mode, sharing)
```

で確認する。

**IDEについて**

https://zenn.dev/hiro345/articles/20240926_java_ide

を参照

VScodeの場合は以下2つの拡張をインストール

- [Extension Pack for Java (vscjava.vscode-java-pack)](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack)
- [Language Support for Java(TM) by Red Hat (redhat.java)](https://marketplace.visualstudio.com/items?itemName=redhat.java)

インストールできたら、パスの設定

以下の2つを設定する

#### 1.`JAVA_JOME`について

```jsx
export JAVA_HOME=$(/usr/libexec/java_home)
```

Java関連のツールが Java のインストール先ディレクトリを参照するために使われる環境変数

**JDKがインストールされているディレクトリのパス** を設定

**`/usr/libexec/java_home`** は **macOS** に組み込まれている **Javaの管理ツール** 

#### 2.`export PATH=$JAVA_HOME/bin:$PATH` について

```jsx
export PATH=$JAVA_HOME/bin:$PATH
```

シェルでコマンドを入力すると、`$PATH` に設定されたディレクトリを上から順に検索してコマンドを見つける。

`export PATH=$JAVA_HOME/bin:$PATH` で、`$JAVA_HOME/bin` を検索パスの最初に追加することで、シェルがJava関連コマンドを優先的に探すことができる。

`source ~/.zshrc` で反映

`echo $JAVA_HOME`でパスが出力されるか確認

---
最後に、Javaプロジェクトの作成

今回は、初めてなのでno build toolを選択

VScode上で`Shift+command+p`でシェルを開き、**create java project** を選択

**no build tool**を選択後、プロジェクト名とプロジェクトの設置場所を決めると自動で作られる

とりあえず、これで構築は終わりです。
【ChatGPT に聞いてみた】go mod を理解せず package を動かす

# 概要
github の golang ライブラリやら手元の自分で作ったライブラリやらをどうすれば使えるのか ChatGPT に聞いて動かしてみた結果をまとめる

# REF （昔話）
https://qiita.com/Soleiyu/items/a799ac3d0da5e75f7b57

# 環境
PC：M1 Macbook Sonoma

```
> go version
go version go1.23.5 darwin/arm64
```
作業ディレクトリは `gomod_exam`
`>` はプロンプト


# ディレクトリ階層
``` shell
gomod_exam > tree .
.
├── main.go
└── mylib
    └── sample.go

2 directories, 2 files
```

# サンプルコード
``` main.go
package main

import "github.com/howeyc/crc16"
import "gomod_exam/mylib"

func main() {
	str := mylib.RetHoge()
	println(str)
	println(crc16.ChecksumCCITTFalse([]byte(str)))
}
```
```mylib/sample.go
package mylib

var (RetHoge = func() string {
	return "hoge"
})
```

# 簡単な説明
プログラム自体は特定の文字列に対してCRC計算を行う
この際、CRC計算ライブラリ（package）が github 上にある
また、 github 上の公開 package だけでなく、自作の package も同じプログラム内に存在する（状態を考える）

# 結論

## 公開 package + 自作 package の場合

1　go mod init
``` shell
gomod_exam > go mod init gomod_exam
go: creating new go.mod: module gomod_exam
go: to add module requirements and sums:
	go mod tidy
```

2　go mod tidy
``` shell
gomod_exam > go mod tidy
go: finding module for package github.com/howeyc/crc16
go: found github.com/howeyc/crc16 in github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6
```

3　go run
``` shell
gomod_exam > go run main.go
hoge
16693
```

4 
```
gomod_exam > tree
.
├── go.mod
├── go.sum
├── main.go
└── mylib
    └── sample.go

2 directories, 4 files
```
```
gomod_exam > cat go.mod
module gomod_exam

go 1.23.5

require github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6
```
```
gomod_exam > cat go.sum
github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6 h1:IIVxLyDUYErC950b8kecjoqDet8P5S4lcVRUOM6rdkU=
github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6/go.mod h1:JslaLRrzGsOKJgFEPBP65Whn+rdwDQSk0I0MCRFe2Zw=
```

## 自作 package のみの場合
``` main.go
package main

//import "github.com/howeyc/crc16"
import "gomod_exam/mylib"

func main() {
	str := mylib.RetHoge()
	println(str)
//	println(crc16.ChecksumCCITTFalse([]byte(str)))
}
```

1　go mod init
```
gomod_exam > go mod init gomod_exam
go: creating new go.mod: module gomod_exam
go: to add module requirements and sums:
	go mod tidy
```
2　go run
```
gomod_exam > go run main.go
hoge
```

3
```
gomod_exam > tree
.
├── go.mod
├── main.go
└── mylib
    └── sample.go

2 directories, 3 files
```
```
gomod_exam > cat go.mod
module gomod_exam

go 1.23.5
```
tidy は不要
シグモイド関数【データ分析】

## はじめに
シグモイド関数は、特に 0から1の間で値が変化する関数です。
簡単に言うと、シグモイド関数は 小さい入力に対しては値がほとんど変わらず、大きな入力になると急激に変化して最終的に1に近づく、という性質を持っています。

**f(x) = 1 / (1 + e^(-x))**

ここで、e は約2.718のことです。
これが底となる指数関数が使われています。

## シグモイド関数の特徴
**入力が0のとき：**
f(0) = 0.5 です。
つまり、シグモイド関数のグラフは、x = 0 のときにちょうど 0.5 になります。

**xが大きくなると1に近づく：**
xが大きくなる（たとえば、xが10, 100, 1000になる）と、関数の値は1に近づきます。
例えば、xが1000だとほぼ1に近くなります。

**xが小さくなると0に近づく：**
xが小さくなる（例えばxが-1000, -100、-10など）と、関数の値は0に近づきます。
xが-1000だとほぼ0に近くなります。

## 滑らかな変化
シグモイド関数は非常に滑らかに、急激な変化をせず、徐々に変化します。

## グラフの特徴
シグモイド関数をグラフにすると、S字型（S-curve）になります。
これが「シグモイド」という名前の由来です。
横軸がx、縦軸が関数の値**f(x)**です。

xが大きくなるとグラフは 1 に近づきます。
xが小さくなるとグラフは 0 に近づきます。
シグモイド関数の使い道
シグモイド関数は、主に以下のような場面で使われます：

## ニューラルネットワーク（人工知能の一部）
シグモイド関数は、人工ニューラルネットワークでよく使われます。
ニューロンの出力を0と1の間に収めるためです。

## 確率的な判断
シグモイド関数は、ある事象が起こる確率を表現するのに使われます。
0に近い値は確率が低いことを示し、1に近い値は確率が高いことを示します。

## ロジスティック回帰
シグモイド関数は、ある結果が起こる確率を予測するロジスティック回帰でもよく使われます。
例えば、メールがスパムかどうかを判定する場合などです。

## 最後に
シグモイド関数は、0から1の間で滑らかに変化する便利な関数で、特に確率や判断を表すときに非常に役立ちます。数学的にもとても簡単に表せるので、いろいろな場面でよく使われる関数です。
指数関数【データ分析】

## はじめに
指数関数は、数字がどんどん大きくなったり小さくなったりする関数です。
具体的には、「数を何回掛けるか」に関係しているんです。

例えば、2を何回掛けるかを考えてみましょう。
2^1 = 2 （2を1回掛ける）
2^2 = 4 （2を2回掛ける）
2^3 = 8 （2を3回掛ける）
こうやって、指数（べき）という数字を変えることで、答えがどんどん変わります。

## 指数関数の形

**f(x) = a^x**

a は数字（たとえば 2 や 10 など）
x は掛ける回数（これが変わる）
たとえば、aが2で、xが3の場合、2^3（2を3回掛ける）となり、答えは 8 です。

## 指数関数の特徴
**①増え方が早い**
a > 1 だと、xが大きくなると急に値が大きくなります（例：2^x）。
a < 1 だと、xが大きくなるとどんどん小さくなります（例：0.5^x）。
xが0のとき： どんな数でも、a^0 = 1 になります。
たとえば、2^0も1になります。

**②自然界でよく見かける**
自然の中で成長が速いものや減っていくもの（たとえば細胞の増え方、放射線の減衰など）では、
この指数関数がよく使われます。

**例を挙げると…**
もしお金を銀行に預けて、年利が5%だとします。
1年後は、元のお金に5%を足した額になります。
2年後は、それにさらに5%を足した額になります。 
こうやってお金がどんどん増えていくときにも、指数関数が使われます。

## 最後に
指数関数は、いろんな場面で「何かが増えたり減ったりする速さ」を表すときに使います。
最初は小さかったものが、次第に大きくなる様子や、小さくなる様子を表すのに便利です。
Googleスプレッドシートでシートを移動するGAS


Google SpreadSheetでシートが多いとマウス操作で移動するのが大変だ。
Apps Scriptでやる方が楽。

```
// シートを先頭(いちb)に移動
function moveSheetToFirst() {
  var sheetName = "シート名";  // 移動したいシートの名前に変更
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName(sheetName);
  
  if (sheet) {
    ss.setActiveSheet(sheet);
    ss.moveActiveSheet(1); // 1番左に移動
  } else {
    Logger.log("指定されたシートが見つかりません。");
  }
}

// シートを末尾(一番右)に移動
function moveSheetToLast() {
  var sheetName = "シート名";  // 移動したいシートの名前に変更
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName(sheetName);
  
  if (sheet) {
    var totalSheets = ss.getSheets().length; // シートの総数を取得
    ss.setActiveSheet(sheet);
    ss.moveActiveSheet(totalSheets); // 一番右に移動
  } else {
    Logger.log("指定されたシートが見つかりません。");
  }
}
```
ExcelのグラフをEPSファイルに変換する方法

　はじめまして、[りょーつ](https://twitter.com/Gomachan_2021)といいます。高専出身の大学院1年生です。最近TeXで書類を書くときに、ExcelのグラフをEPSファイルに変換する操作を行ったのですが、ネット上にあまり情報がなかったので書き留めておこうと思いました。

# 1. はじめに
　ExcelのグラフをEPSファイルに変換する方法をいろいろ試した中で、直観的に分かりやすかった方法を紹介します。今回紹介する方法には以下のツールを使用しました。
 
 **・Excel 2019** 
 **・Adobe Acrobat 2024**

 大まかな手順は以下のとおりになります。
 
**①Excelで新しいファイルを開き、作ったグラフをコピペする。**
**②新しいファイルをpdf形式で保存し、Adobe Acrobatで開く。**
**③pdfをトリミングし、EPS形式で保存する。**

 細かい手順については画像付きで後述します。

 # 2. 詳細手順
　ここではExcelのグラフをEPS形式にする手順を画像を用いて詳しく説明します。
　まずはExcelで適当にグラフを作り、ファイルを保存します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3031572/ccd9870b-f4a3-be60-ffa9-ceec5b0786e4.png)

　エクセルで新規ファイルを開き、先ほど作ったグラフを新規ファイルの左上にコピペします。ペーストの際の書式は「元の書式を保持」or「貼り付け先のテーマを使用」を選んでください。「Ctrl + V」で貼り付けてもよいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3031572/d8f29a85-cb3b-9f87-0a76-a8d2196b79cf.png)

　グラフを貼り付けた新規ファイルをpdf形式で保存します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3031572/842f05f5-382d-89a6-5c91-c7041e68a6d9.png)

　Adobe Acrobatを起動し、先ほど保存したpdfファイルを開きます。その後画面左側のツール一覧から「PDFを編集」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3031572/9c534a14-f389-350d-74ab-e463e77bbe51.png)

　編集ツールの中から「ページをトリミング」ボタンを選択し、グラフの部分を範囲選択します。範囲選択は頂点をドラッグすることで微調整できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3031572/029de19d-4f8c-c50f-8f5b-7882c11a9c56.png)

　範囲選択できたら、範囲選択の内側でダブルクリックします。すると、以下のようなウィンドウが表示されるので、特に何もいじらず「OK」ボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3031572/effdaabd-2f18-c2fa-11dd-d30873688da2.png)

　おそらく上記の操作により余分な余白が消えたと思います。
　最後に、「メニュー」→「別名で保存」からEPS形式(.eps)を選択し、保存します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3031572/f3b2fbcf-b961-fe88-b45a-38450982cbd5.png)

これでEPS形式のファイルが出力できました！

# 3. おわりに
　この記事が卒論や修論の執筆の手助けになれば幸いです。最後まで読んでいただき、ありがとうございました(^^)
Wordpress環境を進化させたい（構成編）



## はじめに
以前作成したマルチAZのWordpress環境を拡張したいと思い、本記事を投稿することにしました。
[CloudFormationを使ってWordPress環境を構築](https://qiita.com/Ryuta_Uchimura/items/ee9847e900cc10811408)
やることとしてはALBをオリジンとしたCloudFrontからWordpressを配信してコンテンツのキャッシュと最適化です。

### システム構成
#### 使用するAWSサービス
- CloudFront: ALBをオリジンとし、コンテンツのキャッシュと最適化
- ALB: EC2の負荷分散
- EC2 (WordPress Webサーバー): マルチAZ構成で配置
- RDS: マルチAZで配置
- S3 (メディアストレージ): WordPressのアップロードファイル保存
- Route 53: DNS管理、CloudFrontとの統合
- IAM: 必要な権限の管理

## 構成図
![構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812406/6a9d3707-6c8c-311b-8eac-bc9b48d34088.png)



### 更なる拡張計画
上のシステムはCloudFront を活用した ALB 経由の WordPress 配信を行い、RDS をマルチ AZ 構成で運用であるが、
より高い可用性と耐障害性を確保するため、リージョンを東京（ap-northeast-1）と大阪（ap-northeast-3）で分散し、DR対策を強化する拡張計画も検討してみる。
【計画】
##### Aurora Global Databaseの導入
マルチAZ構成のRDSをAurora Global Databaseにしてリージョン間でのレプリケーション

##### EFSによるデータの一貫性確保
マルチリージョン構成にした際に一貫性を保ちたいのでEFSを活用
- EC2 インスタンス間でのリアルタイムなファイル共有
- マルチリージョンレプリケーションによる可用性向上
- ストレージのスケーラビリティと管理コストの削減

##### 自動フェイルオーバー
Route 53のヘルスチェック機能でリージョン障害時には正常なリージョンへ自動でトラフィックを切り替える
CloudFrontのオリジングループを活用し、ALB（東京・大阪）の両方をオリジンとして自動フェイルオーバーを実施
##### 構成図
![構成図_2region.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812406/72c3fb20-c440-052f-77b7-55397c2811cf.png)


## 最後に
次回は上の構成図をもとに東京リージョンで実際に構築してみる
RTX 4060搭載ノートPCでDeepSeek-R1を動かす最短手順(Windows 11 Home/WSL2/Ubuntu-24.04/Python仮想環境/Ollama)

## 環境
- Windows 11 Home + WSL2 (Ubuntu 24.04)
- NVIDIA RTX 4060 Laptop GPU (VRAM 8GB)
- CUDA 12.4対応 / PyTorch 2.6.0+cu124
- Python仮想環境 (jupyter_env)

## セットアップ手順

### 1. WSL2/CUDA環境の確認

```bash
# PyTorch/CUDA検証
python3 -c "import torch; print(f'PyTorch: {torch.__version__}\nCUDA: {torch.cuda.is_available()}')"

# GPUドライバ確認
nvidia-smi
```

### 2. Git LFSのインストール

```bash
sudo apt install git-lfs
git lfs install --system
```

### 3. モデルのダウンロード

```bash
# 安定したクローン方法
GIT_LFS_SKIP_SMUDGE=1 git clone https://huggingface.co/deepseek-ai/DeepSeek-R1-Distill-Qwen-14B
cd DeepSeek-R1-Distill-Qwen-14B
git lfs pull
```

### 4. Ollamaのセットアップ

```bash
# インストール
curl -fsSL https://ollama.com/install.sh | sh

# サービス設定
sudo tee /etc/systemd/system/ollama.service <<EOF
[Unit]
Description=Ollama Service
After=network-online.target

[Service]
ExecStart=/usr/local/bin/ollama serve
User=ollama
Group=ollama
Restart=always
RestartSec=3
Environment="OLLAMA_MODELS=/usr/share/ollama/models"

[Install]
WantedBy=default.target
EOF

# サービス起動
sudo useradd -r -s /bin/false -m -d /usr/share/ollama ollama
sudo systemctl daemon-reload
sudo systemctl enable ollama
sudo systemctl start ollama
```

### 5. モデルの登録と実行

```bash
# Modelfile作成
cat > Modelfile <<EOL
FROM ./DeepSeek-R1-Distill-Qwen-14B-Q4_K_M.gguf
PARAMETER num_gpu 35
PARAMETER num_thread 6
SYSTEM "あなたは日本語専門のAIアシスタントです"
EOL

# モデル登録
ollama create deepseek-ja -f Modelfile

# 動作確認
ollama run deepseek-ja "こんにちは"
```

### 6. Jupyter Notebook連携

```python
import requests

def ask_deepseek(prompt, system_prompt=""):
    full_prompt = f"{system_prompt}\n\n{prompt}" if system_prompt else prompt
    response = requests.post(
        'http://localhost:11434/api/generate',
        json={
            'model': 'deepseek-ja',
            'prompt': full_prompt,
            'stream': False
        }
    )
    return response.json()['response']

# 使用例
result = ask_deepseek("Pythonについて説明してください")
print(result)
```

## パフォーマンス特性
- VRAM使用量: 約5.8GB
- 推論速度: 12-15 tokens/sec
- レイテンシ: 初回3-5秒、以降1-2秒

## トラブルシューティング
- CUDA Out of Memory → num_gpu値を25-30に調整
- 文字化け → `LANG=ja_JP.UTF-8`を設定
- WSL2 GPU認識エラー → `wsl --shutdown`後に再起動

この手順で、RTX 4060搭載ノートPCでDeepSeek-R1の日本語モデルが利用可能になります。8GB VRAMの制約内で安定した推論が可能です。
Bandit問題で見かけるsuboptimality gapに関して

強化学習のいくつかの文献で、suboptimality gapという言葉が出てくる。Google検索しても、それ自体にフォーカスした記事が出てこないため、そもそもなぜこの概念が重要なのかがわからない。

TLDR: 最適な腕の平均報酬からの各腕の報酬の差$\Delta_i$を考えたり、最適な腕の平均報酬からの２番目にベストな腕の報酬の差$\Delta$を考えることでRegretを捉えるのに役立つ。表記の揺れは文献により異なるが、多様なBanditの設定で、$\Delta$が既知の場合（比較的簡単な問題設定）や未知の場合（ややこしい場合）などで、研究者たちはさまざまな手法を用いてregretを$\Delta$以外で不等式で漸近的にとらえようと頑張っていることがわかった。

#### 最適な腕の平均報酬からの各腕の報酬の差

Multi-armed banditの文脈では、ある腕$i$における報酬の平均を$\mu_i$としたとき、さまざまな腕に関して$\mu_i$が最大であるもの、すなわち平均報酬が最大となるような腕の報酬を$\mu_*$とする。

このような設定下である腕$i$のsuboptimality parameterは以下となる。

```math
\Delta_i=\mu_*-\mu_i
```

https://arxiv.org/pdf/1204.5721

このsuboptimality parameter$\Delta_i$を儲けることによって何がいいのかというと、psudo-regretが簡潔にかけるということだ。上記のサーベイ論文のSection 2では色々変形をすると以下に要約される:

```math
\overline{R}_n=...=\sum_{n=1}^K\Delta_i\mathbb{E}T_i(n)
```

Multi-armed banditの文献のいくつかでは、いつもregretがどうなるかを捉えようとすることが多い。Regret boundsやRegret analysisというセクションのついた論文が多い。

例えば、Multi-armed banditの文献でよく見る以下の不等式（上記のサーベイ論文のTheorem 2.2）も、$\Delta_i$で表せる。また、$\Delta$をCtrl+Fで論文内で検索しても、さまざまなBandit問題の設定で多数ヒットするため、重要な概念であることは間違いない。

```math
\liminf_{n \to +\infty} \frac{R_n}{\ln n} \geq \sum_{i: \Delta_i > 0} \frac{\Delta_i}{\mathrm{kl}(\mu_i, \mu^*)}
```



#### 最適な腕の平均報酬からの２番目にベストな腕の報酬の差

 (Minimal) sub-optimality gapといって、最適な$\mu_*$の次に最適な腕の報酬を$\mu
'$とした時、次のように最適な腕の平均報酬から、２番目に最適な腕の平均報酬との差を考えることがある。これは前のセクションの$\Delta_i$の２番目に最適な腕を$i$に当てはめた時の値だ。

 ```math
\Delta=\mu_*-\mu'
```

https://proceedings.mlr.press/v202/zhang23n/zhang23n.pdf

#### 所感

表記や言葉のゆれはさておき、regretの数式を捉える上で、最適な腕の報酬から別の腕の差を考えることで、regretの数式が表現できることがわかった。Multi-armed banditではregretの最小化をすることにより報酬の最大化をするので、regretを理論的に考える上で$\Delta_i$, $\Delta$は便利だ。

もちろん、実際のところ、そもそも最適な腕$\mu_*$がわかっていたら、regretの最小化、すなわち、報酬の最大化をする必要はない。実際のところ、結局何がしたいのか？

上記のsub-optimality gap$\Delta$が既知の場合（次の論文のセクション4）と、既知でない場合の議論（次の論文のセクション5）がよく見られる。この広い宇宙の中で、既知である問題設定は多くないような気がする。それもあって、次の論文では、$\Delta$が未知の場合でもregretを捉えられるような理論的な工夫をしている。

https://proceedings.mlr.press/v202/zhang23n/zhang23n.pdf 


### まとめ


最適な腕の平均報酬からの各腕の報酬の差$\Delta_i$を考えたり、最適な腕の平均報酬からの２番目にベストな腕の報酬の差$\Delta$を考えることでRegretを捉えるのに役立つ。表記の揺れは文献により異なるが、多様なBanditの設定で、$\Delta$が既知の場合（比較的簡単な問題設定）や未知の場合（ややこしい場合）などで、研究者たちはさまざまな手法を用いてregretを$\Delta$以外で不等式で漸近的にとらえようと頑張っていることがわかった。
Go言語(プログラミング)入門メモ㉑

## selectでチャネルに応じた処理を行う。
複数のチャネルを使って複数のゴルーチンとやり取りをするとき、受信したチャネルによって処理を分岐させたい場合がある。その場合、selectを使うことでチャネルごとの処理を書くことができる。
イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579705/773e9003-5cd9-cf48-b3a0-83e8460dd54f.png)

コードとして表現する。string型のチャネルを2つ作成し、goroutine1関数とgorutine2関数に渡してゴルーチンで実行する。

~~~
func main() {
 c1 := make(chan string)
 c2 := make(chan string)
 go goroutine1(c1)
 go goroutine2(c2)
~~~

goroutine1関数の中では、for文で無限ループを作り「ch <- "packet from 1"」と書いて、チャネルに文字列「packet from 1」を送信する。これは、ネットワークから来るパケットを取り続けてチャネルに送り続けるイメージ。また、次に来るパケットまで時間がかかるという想定で、Sleepで1秒待つ処理も書いておく。

~~~
func goroutine1(ch chan string) {
    for {
        ch <- "packet from 1"
        time.Sleep(1 * time.Second)
    }
}
~~~

goroutine2関数も同様に書く。送信する文字列は「packet from 2」と変えておく。
~~~
func goroutine2(ch chan string) {
    for {
        ch <- "packet from 2"
        time.Sleep(1 * time.Second)
    }
}
~~~

main関数で受信するには、for文で次のようにselectを使う。selectの中にcaseでc1が来た場合とc2が来た場合で分ける。
~~~
for {
    select {
    case msg1 := <- c1:
        fmt.Println(msg1)
    case nsg2 := <- c2:
        fmt.Println(msg2)
        }
}
~~~

全体のコードをつなげると以下のようになる。
~~~
func goroutine1(ch chan string) {
    for {
        ch <- "packet from 1"
        time.Sleep(1 * time.Second)
    }
}

func goroutine2(ch chan string) {
    for {
        ch <- "packet from 2"
        time.Sleep(1 * time.Second)
    }
}

func main() {
 c1 := make(chan string)
 c2 := make(chan string)
 go goroutine1(c1)
 go goroutine2(c2)

for {
    select {
    case msg1 := <- c1:
        fmt.Println(msg1)
    case msg2 := <- c2:
        fmt.Println(msg2)
        }
}

//以下のように出力される
packet from 1
packet from 2
packet from 2
packet from 1
packet from 1
packet from 2
以下略
~~~

goroutine1 と goroutine2 が並行して動作し、それぞれのチャネルを介してメッセージを main 関数に送信し、main 関数はそれを受信して表示するという流れが成立する。

具体的なイメージとしては、goroutine1 が「パケット1」を1秒ごとに生成してパイプに流し込み、main 関数がそのパイプからデータを受け取って表示し、goroutine2 も同様に「パケット2」を生成し、別のパイプに流し込むイメージ。

## 学習に使用した教材
・『入門】Golang基礎入門 + 各種ライブラリ + 簡単なTodoWebアプリケーション開発(Go言語)』M.A EduTech
https://www.udemy.com/course/golang-webgosql/?utm_medium=udemyads&utm_source=bene-msa&utm_campaign=responsive&utm_content=top-1&utm_term=general&msclkid=81e2f24a32cc185d275d953d60760226&couponCode=NEWYEARCAREERJP

・『シリコンバレー一流プログラマーが教える Goプロフェッショナル大全』酒井 潤 (著)
https://www.amazon.co.jp/%E3%82%B7%E3%83%AA%E3%82%B3%E3%83%B3%E3%83%90%E3%83%AC%E3%83%BC%E4%B8%80%E6%B5%81%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%83%BC%E3%81%8C%E6%95%99%E3%81%88%E3%82%8B-Go%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E5%A4%A7%E5%85%A8-%E9%85%92%E4%BA%95-%E6%BD%A4/dp/4046070897
PHP勉強メモ20250201（foreachのindex, !==と!=)

## 概要
仕事でたまにPHPを書く機会が生じているが、頻繁に書くわけでないし、Copilotで自動補完してもらってしまっていることもありなかなか身につかない。本当に今さら？というような基礎的な内容になるが、調べた内容を備忘のためにメモする。

## foreachでindexもとる

```php
foreach($nums as $index => $value){
    //処理
}
```

この場合、`$nums` が配列、 `$value` が取り出される要素、 `$index` がindexになる。これ何回も見ているのだけど、いつも自分で書くとなると調べてしまう。

## 配列にその要素が存在するか確認して、存在したらindexを返す
存在しなかったらfalseを返す

```php
$key = array_search($target,$array);
```

## != と !==
`===` はデータ型まで含めて一致しているかみる、というところまではわかるのだが、
`==`だと0とnullとfalseと一致扱いになるそう。（つまり、`0` == `false` はtrueになる。）`empty` も 0はtrue扱いだし本当に0の扱いがよくわからない...。
つまり、上記の `array_search` でindex=0の要素が当てはまった場合、 != で比較してしまうと、一致する要素がない扱いになってしまう。（そもそも存在しなかったらfalseじゃなくて-1とかを返してほしいと思ってしまうのは私だけ？）

```php
// 誤り
$key = array_search($target,$array);
if($key != false){
    // これだと$key=0の時、ifの中に入らない
}

// 正しい
$key = array_search($target,$array);
if($key !== false){
    // これだと$key=0の時、ifの中に入る
}

```

この記事がわかりやすい。
https://blog.katty.in/51