OmniAICreator/Qiita-1.07M huggingface dataset:
【AIエージェント】Hugging Faceのエージェントコースを学んでみる

# はじめに
最近膝がむずむずしてなかなか眠れない、ノベルワークスのりょうちん（[ryotech34](https://x.com/ryotech34)）です。
今回は、AI開発プラットフォームとして有名なHugging Faceで最近スタートしたAgent Courseについて簡単にまとめてみました。

https://huggingface.co/learn/agents-course/unit0/introduction

# Agent Courseとは
Agent Courseとは、その名の通りAIエージェントについて体系立てて学べるコースです。
ユニットごとに講座が公開され、ステップバイステップでAIエージェントを学ぶことが出来ます。

このコースを学ぶことで以下のことが出来るようになると記載されています。
> 📖 AIエージェントの理論、設計、実践が学べる。
🧑‍💻 smolagents、LangChain、LlamaIndexなどの確立されたAIエージェントライブラリの使い方の習得。
💾 Hugging Face Hubであなたのエージェントを共有し、コミュニティが作成したエージェントを探すことができる。
🏆 自分のエージェントを他の受講生のエージェントと比較評価するチャレンジに参加できる。
🎓 課題をクリアすると修了証がもらえる。


私自身、Hugging Faceの強化学習と深層強化学習についてのコースを受講していたのですが、事前に準備されたリソースを使用して体系立てて学べるのがとても気に入っており、今回も応募しました。

# ざっと感想
2/17現在、ユニット1を受講した感想になります。とにかくここまでやってくれるの？の連続でした。

最初は座学ということで、LLMについての基本的な知識やエージェントについての概念を学びました。
各ステップで小テストがあり、実際に学んだことをアウトプットして知識を習得することができます。
ここまでは、その他学習サービスとの差はあまり感じられませんでした。
<!-- ![](https://storage.googleapis.com/zenn-user-upload/f2c34c51b4b8-20250217.jpg) -->


## ここがすごい
Hugging Face内でトークンを発行し、コース内で指定されたアプリケーションを複製するだけで、チャットアプリケーションをビルドすることができます。これが本当にすごい。
自分の環境を用意することなく、Web上でコードを編集することでAIエージェントを実装することができます。
![](https://storage.googleapis.com/zenn-user-upload/12741dfd30b7-20250217.png)


## 実装してみる
今回は、お試しということで名前と数値を与えると、末尾に`007`を追加してコードネームを返すようなツールをAIエージェントに追加してみました。

```py:app.py
@tool
def get_codename(arg1:str, arg2:int)-> str:
    """A tool that add number to name as codename
    Args:
        arg1: name that is the first argument
        arg2: number that is the second argument
    """
    return arg1 + str(arg2) + "007"
```

:::note info
CI/CDも実装されているため、保存後に編集内容に不備があった場合でも、すぐに判別できます。
:::

そして、このAIエージェントに
- ハリーポッターの名前と誕生日からコードネームを取得してください

という指示をインプットしてみました。

![](https://storage.googleapis.com/zenn-user-upload/edb1d532f2d9-20250217.png)

画像の通り、出力結果は
- HarryPotter19800731:007

と少し雑ですが、きちんと名前と誕生日に`007`が追加され出力されていることが確認できました。

## ちょっと嬉しい
ユニットの最後にあるテストで一定以上のスコアを取得すると修了証が貰えます。これが地味に嬉しい。褒められると同時に学んだ証跡が形として残るのはとてもいい体験です。
![](https://storage.googleapis.com/zenn-user-upload/ec2fcbd40492-20250217.webp)

# おわりに
今回は始まったばかりのAIエージェントコースについてまとめてみました。
今後ファインチューニングや評価などさらに深い内容まで学べるとのことでとても楽しみです。
また、Discord上で他の受講者とコミュニケーションできるのもモチベーション高く勉強できてとても良いです。気になった方は是非受講してみてください！

# 参考
- https://huggingface.co/learn/agents-course/unit0/introduction
Markdownで書けるhtml形式の文書    

## SimppleHTML
 あなたは、どの形式（txt,html,md,docx,xlsx)で文書を作成しますか？
simplehtml を使えば、htmlフアイルをmd形式で直接編集できます。

[[About SimpleHTML]](https://dddp-gl.github.io/simplehtml/)
ngrokのCLIを使った基本的な使い方を抑える

## はじめに
簡単なWebアプリケーションを作成し、それをスマホから確認する場合、通常であればサーバーを立ててWeb上に公開する必要があります。
しかし、パッと確認したいときにはちょっとした手間も惜しいものです。

そんなときに使えるのがngrokというサービスです。

ローカル上で動かしているサービスを、ngrokが提供する一時的なURLを通じて、インターネット上に公開することができます。

## 事前準備
### アカウント作成
アカウントを持っていない場合には以下から作成してください。
Googleアカウント、もしくはGithubアカウントから作成することもできます。

https://dashboard.ngrok.com/signup

また、ログインする際にはMFA（多要素認証）の設定が求められるので、任意のAuthenticatorのアプリを使用します。

### ngrokのインストール
ログイン後に、それぞれの環境に適したインストール方法が提示されます。
私はMacを使用している、かつhomebrewを導入しているため、以下のコマンドでインストールしました。

```terminal
brew install ngrok
```

これで`ngrok`コマンドが使用できるようになりました。

### 設定ファイルに認証情報を書き込み

`ngrok config`で設定ファイルに認証情報を書き込みます。

```terminal
ngrok config add-authtoken [token]
```
`[token]`は自身のトークンに置き換えます。
トークンはngrokのページの「Your Authtoken」から確認できます。

<img width='80%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/58c79004-f9e0-4211-80e3-b7ee23a1a971.png'>

ここまでで準備は完了です。

## CLIを使ったngrokの基本的な使い方
### ローカルで起動しているアプリをWebに公開する
自分が作成したアプリをローカルで起動した後、`ngrok http`を使用します。
```terminal
ngrok http [address:port]
```

私はviteを使用して作った適当なアプリで試すことにします。
ローカルでのアプリの表示はこのようになっています。
<img width='80%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/e62152b6-9f08-494d-a2f2-050a47cb2641.png'>

コマンドを以下の通り実行しました。
```terminal:例
ngrok http http://localhost:5173
```

ターミナルの表示が変わります。
<img width='80%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/d9360ed8-f27f-4a24-9c45-8ea6663a8495.png'>

着目してほしいのは「Forwading」に表示されている「https」から始まるURLです。
これが、ローカルのアプリケーションに外部からアクセスするためのURLになります。

試しに、このURLでアクセスしてみましょう。
<img width='80%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/99beec15-79aa-4987-9cf0-1fd1a44fa42a.png'>
初回アクセス時は、このような警告画面が表示されます。
問題ないので、「Visit Site」をクリックします。

アクセスに成功しました。
先ほどローカルで確認したものと同じ画面が表示されています。
<img width='80%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/dbe3ef29-7ba9-457f-b56d-ef6afb201422.png'>
着目すべきはURLの部分で、`http://localhost~`ではなく、`https://...`となっています。
つまり、外部に対してローカルで立ち上げたアプリが公開できているということです。

ターミナルに戻ります。

<img width='80%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/abd7c295-4ac4-4c61-a80e-cc0c7dc76c09.png'>

「HTTP Requests」として、どのようなリクエストがあったのかが出力されているのがわかります。

コマンドを1つ叩くだけで、Web上に公開することができました。
注意点として、このURLはコマンド実行のたびに変わるので、静的なアドレスにしたい場合は別途設定が必要になります。
Meetsの小窓について調べてみた

## 概要
meetsで別のwindowなどに移動した場合に別のポップアップ画面のようなものが表示されるが、最前面に固定される。どのようにやっているのか気になったので調べてみた。

## ポップアップウィンドウを利用している？？
まず初めに、ポップアップウィンドウを利用していると考えた。

**根拠：**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125890/2831bfa8-dfff-4c84-b1d4-e24f552f542c.png)

当たり前のようにChrome DevToolsが利用できる。

**疑問点：**

ソースは見つからなかったが、標準機能ではできないっぽいし、自分もその認識であった。セキュリティリスクであるため利用できないイメージである。

https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q13290459733

https://developer.mozilla.org/ja/docs/Web/API/Window/open

## ピクチャinピクチャ機能？

AIに聞いたところピクチャinピクチャ機能の可能性があるとのことであったが、試しに作成してみたところ、DevToolsの表示や動画以外のものを表示することは不可能であった。

しかし、矢印を押すことで画面に戻れるなど、内部的にピクチャinピクチャを利用しているかもしれないとは感じた。

## どうやらピクチャinピクチャ！！
別のブラウザで試してみたところ、次のような表示が出た。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125890/63cf66fa-2f1a-4cd1-9437-eb6dc406a2f3.png)

実装の部分で違うと感じたが、実際にはピクチャinピクチャで実装しているとのこと。
とすると、ピクチャinピクチャでも同様のことが可能である。

いろいろ調べてみたところこのようなドキュメントを見つけることができた。

https://developer.chrome.com/docs/web-platform/document-picture-in-picture?hl=ja

## 動作検証
このような形で適当に作ってもMeetsのような動きが可能である。

![2025-02-17_22h48_47.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125890/d3976540-7288-46ef-a628-9ff7ba3b7a7e.gif)

## まとめ
Web会議等を自作する場合はめちゃくちゃ便利そうに感じた。
最初はポップアップウィンドウで実装だと思っていたためそちらメインで調べていたので、偶然ではあるがピクチャinピクチャと表示してくれたGoogleには感謝である
kotestでなんで引数にinit{}の中身にいれられるの？(豆知識)

Q: kotestを使ってテストを書く時、以下のように`init{}`を用いて書くことができますが、

```kotlin
class Test : DescribeSpec() {
    init {
        describe("test") {
            it("test") {
                println("test")
            }
        }
    }
}
```

以下のように引数にいれることでインデントを1段階浅くすることができます。

```kotlin
class Test : DescribeSpec({
    describe("test") {
        it("test") {
            println("test")
        }
    }
}) 
```

A: なぜこのようなことができるかというと、以下で引数にblockを渡すとinit内で実行できるという実装がkotest側で行われているからです。

https://github.com/kotest/kotest/blob/master/kotest-framework/kotest-framework-engine/src/commonMain/kotlin/io/kotest/core/spec/style/describeSpec.kt#L23-L27
寺尾裕昭のTips：優秀エンジニア採用の5つのステップ

寺尾裕昭です。

技術革新が加速する現代において、優秀なエンジニアの確保は企業の競争力を左右します。しかし、単に募集をかけるだけでは、優れた人材を引き寄せることは難しいものです。ここでは、優秀なエンジニアを採用するための5つのステップを解説します。

## 1. 求めるエンジニア像を明確にする

まずは、自社が求めるエンジニア像を具体的に定義しましょう。必要なスキルセットだけでなく、チームにフィットする性格や働き方も考慮することが重要です。

### 具体的なアクション
- **必要な技術スキルをリスト化**（例：Python、AWS、機械学習など）
- **必須スキルと歓迎スキルを区別**
- **求める人物像を明文化**し、チーム文化との適合性を確認

## 2. 魅力的な求人情報を作成する

優秀なエンジニアは多くのオファーを受けています。求人情報を他社との差別化を図り、魅力的に伝えることが大切です。

### 具体的なアクション
- **仕事内容を具体的に説明**（使う技術、プロジェクトの魅力を強調）
- **成長機会を明示**（スキルアップ支援、技術カンファレンス参加支援など）
- **働きやすさをアピール**（リモートワーク、フレックスタイム、ワークライフバランス）

## 3. 効果的な採用チャネルを活用する

ターゲットとなるエンジニアにリーチするために、最適な採用チャネルを選定しましょう。

### 具体的なアクション
- **専門性の高い採用プラットフォームを利用**（Green、Forkwell、LinkedInなど）
- **SNSを活用**し、エンジニア向けの情報発信を行う
- **エンジニアイベントに参加**し、直接交流を図る

## 4. 技術と人間性を見極める選考プロセス

優秀なエンジニアを見極めるには、技術力だけでなく、コミュニケーション能力や文化適応性も重要です。

### 具体的なアクション
- **技術テストやコーディング課題を実施**
- **ペアプログラミングで実践力を確認**
- **チームメンバーとの面談を設定**し、カルチャーフィットを評価

## 5. 入社後のフォローと定着支援

優秀なエンジニアを採用しても、定着しなければ意味がありません。入社後のフォローを強化しましょう。

### 具体的なアクション
- **オンボーディングプログラムを整備**
- **定期的な1on1を実施**し、悩みを早期解消
- **キャリア成長の機会を提供**し、長期的な関係構築

## まとめ

優秀なエンジニアを採用するためには、明確な採用方針と丁寧なプロセスが必要です。求める人物像を明確にし、魅力的な求人を作成し、適切なチャネルでアプローチを行い、選考とフォローに力を入れることで、優れた人材を確保し、組織の成長を加速させましょう。
SadServers No.1 解説 "Saint John": what is writing to this log file?

# SadServer #1 - 暴走ログ出力プロセスの特定と停止 〜デスクトップLinuxの経験を活かして〜

## はじめに
サーバー管理者として直面する一般的な問題の1つが、ディスク容量を圧迫するログファイルの処理です。今回は、不要なテストプログラムが継続的にログを出力し続けている状況に対処します。この問題は、デスクトップLinuxユーザーが日常的に経験する「暴走プロセスの特定と停止」と本質的に同じ問題です。

## 問題の概要
- 対象ログファイル: `/var/log/bad.log`
- 状況: 継続的な書き込みによるディスク容量の圧迫
- 制約: root権限なしでの解決が必要
- 目標: プロセスの特定と停止

## デスクトップLinuxユーザーの視点からの考察
CachyOSなどのArch系ディストリビューションを使用していると、開発環境やテストプログラムが暴走してログを大量に出力する経験は珍しくありません。特に、pacmanでのパッケージビルド時やAURヘルパーの使用時に類似の状況に遭遇することがあります。

このような状況での基本的なトラブルシューティングの流れは以下の通りです：
1. 問題のファイルを特定する
2. そのファイルに書き込みを行っているプロセスを見つける
3. プロセスの正体を確認する
4. 安全に停止する

## 解決手順の詳細

### 1. ログファイルの監視
まず、ログファイルの変更を確認します：

```bash
tail -f /var/log/bad.log
```

これは、デスクトップ環境で `journalctl -f` を使用してシステムログを監視するのと同じ考え方です。

### 2. 書き込み中のプロセスの特定
Linuxのプロセスとファイルディスクリプタの関係を利用して、書き込みプロセスを特定します：

```bash
lsof /var/log/bad.log
```

もしくは：

```bash
fuser /var/log/bad.log
```

これらのコマンドは、デスクトップ環境でファイルをロックしているプロセスを探す時にも使用する一般的なツールです。

### 3. プロセスの詳細確認
特定したプロセスIDについて、詳細情報を確認します：

```bash
ps -fp <PID>
```

これにより、プロセスの実行ユーザー、起動時刻、コマンドラインなどの情報が分かります。

### 4. プロセスの停止
特定したプロセスを安全に停止します：

```bash
kill <PID>
```

より穏やかな終了を試みる場合：

```bash
kill -15 <PID>
```

## システムの仕組みについての理解

### ファイルディスクリプタとプロセス
Linuxでは、開いているファイルの情報は各プロセスのファイルディスクリプタテーブルで管理されています。この仕組みは、デスクトップでもサーバーでも同じです。`lsof`や`fuser`は、このファイルディスクリプタの情報を読み取ることで、ファイルを使用しているプロセスを特定できます。

### プロセス管理
プロセスの停止には、通常以下のシグナルを使用します：
- SIGTERM (15): 正常終了を要求
- SIGKILL (9): 強制終了

デスクトップ環境のタスクマネージャーで「終了」を選択した場合も、内部的には同様のシグナルが送信されています。

## 学んだこと・重要なポイント

1. ファイルシステムの監視ツール
   - `tail -f`、`lsof`、`fuser` などの基本的なツールの重要性
   - これらのツールはデスクトップでもサーバーでも同じように使える

2. プロセス管理の基本
   - プロセスの特定から停止までの手順
   - シグナルの適切な使用方法

3. 権限管理の考え方
   - root権限がなくても実行できる操作の理解
   - ユーザーレベルでのトラブルシューティング

## おわりに
デスクトップLinuxの日常的な使用で得られる経験は、サーバー管理にも直接活かすことができます。基本的なLinuxの仕組みを理解していれば、環境が変わっても同じ考え方でトラブルシューティングを行うことができます。

## 参考情報
- man ページ: lsof(8), fuser(1), ps(1), kill(1)
- [Linux Process Management](https://www.kernel.org/doc/html/latest/admin-guide/pm/index.html)
- [File Descriptor Documentation](https://man7.org/linux/man-pages/man2/open.2.html)
atcoder_水色精進記録1

# Atcoder水色精進記録
ABC212
E - Chain Contestant
https://atcoder.jp/contests/abc215/tasks/abc215_e

# アルゴリズム・データ構造
bitDP

# 考察
各コンテストは出場する/出場しないの2択
1<N<=1000のため全探索は2*1000のため不可
→DPを検討
保持しておかないといけない情報は？
→現在までの選び方の総和、最後に選んだコンテスト、これまで選んだコンテスト
最後に選んだコンテスト=max(10)
これまで選んだコンテスト=2**10 (10種類のコンテストについて選んだ/選んでいないの2択)

計算量
N*最後に選んだコンテスト*これまで選んだコンテスト
1000\*10\*1000=10**7

# 提出
https://atcoder.jp/contests/abc212/submissions/62729683


# 感想
3次元DPとなるため実装がかなり複雑だった。
bitDPを解説なしで導出できたのは成長を感じる。
理解が深まるプロンプト：「対話物語形式」で説明して

## はじめに
Linuxを勉強しようと思い、Udemyの講座を購入したものの、
・内容が少し難しい...
・講師の話すスピードが速くてついていけない...
・説明が淡々としていて、集中力が続かない...

こんな悩みを抱えていました。

そんな時、Twitterで **「対話物語形式で説明して」** というプロンプトを使うと、分かりやすい解説が得られると知り、さっそく試してみました。

そこで、Linuxのブートプロセスを 対話形式 で説明させてみたところ…
これなら Linux初心者でも概要的な理解はできるのではと感じました。
小学校の図書室にあった「〇〇のひみつ」シリーズみたいな感じで読みやすいですね、、！

何かを新しく学ぶときは重宝しそう。。。
（モデルはおそらくo1 proが一番適していそうですね）

以下GPTの出力結果です。
-----


### **🌍 Linuxのブートプロセス：対話形式で理解しよう！**

---

🌞 **あなた**：「よし、パソコンの電源を入れるぞ！」  
🔌 **パソコン**：「ウィーーン！（ファンの音）」  

---

🧑‍🏫 **Linux博士**：「さあ、ここからパソコンの内部で何が起きているのか、わかりやすく説明しよう！」

---

## **📌 ステップ1：電源投入**
💡 **電源ボタンを押した瞬間、PCの内部で何が起こるの？**

🔌 **パソコン**：「おはよう！起動する準備を始めるよ！」  
🔋 **マザーボード**：「まずは、システムをチェックするために **BIOS/UEFI** を起動するぞ！」  

---

## **📌 ステップ2：BIOS/UEFIが動く**
💡 **BIOS/UEFIはPCの「目覚めチェック」をする司令官！**

🔍 **BIOS/UEFI**：「おっと、みんな揃ってるか？ **CPU！メモリ！HDD！SSD！USB！ちゃんとつながってる？**」  
🖥 **CPU**：「準備OK！」  
💾 **メモリ**：「データを保存する準備完了！」  
🖴 **HDD/SSD**：「オペレーティングシステム（OS）はここにあるよ！」  

🧑‍🏫 **Linux博士**：「つまり、BIOS/UEFIは **PCが正常に動くかチェック** して、OSを起動する準備をするんだ。」

---

## **📌 ステップ3：ブートデバイスを探す**
💡 **BIOS/UEFIは「どこからOSを読み込むか」決める！**

🔍 **BIOS/UEFI**：「さて、OSはどこにあるかな？ まずはSSDをチェック……あった！」  
📀 **HDD/SSD**：「オレの中に **GRUB（ブートローダー）** が入ってるよ！」  

---

## **📌 ステップ4：GRUB（ブートローダー）が起動**
💡 **GRUBは「OSを選んで起動するメニュー」**

🎛 **GRUB（ブートローダー）**：「こんにちは！どのOSを起動しますか？」  
🖥 **画面**：「1. Linux（Ubuntu）  2. Windows  3. 設定変更」  

🧑‍🏫 **Linux博士**：「GRUBは、複数のOSが入っていると、どれを起動するか選ばせてくれるんだ！」

---

## **📌 ステップ5：カーネルの起動**
💡 **カーネルは「Linuxの心臓部」**

🎛 **GRUB**：「OK！Linuxを選んだね！さっそく **カーネル（Kernel）** をメモリに読み込むよ！」  
⚙ **カーネル**：「やあ！Linuxのエンジン部分を起動するよ！」  
💾 **メモリ**：「カーネルを読み込んで、必要なデータを準備するよ！」  

🧑‍🏫 **Linux博士**：「カーネルは、CPU・メモリ・ストレージをコントロールする **Linuxの核** なんだ。」

---

## **📌 ステップ6：systemdの起動**
💡 **systemdは「Linuxのサービスを管理するボス」**

⚙ **カーネル**：「すべて準備OK！あとは **systemd** に任せるよ！」  
🛠 **systemd**：「よし！では、ネットワークやログイン画面を用意しよう！」  
🖥 **画面**：「ログインしてください」  

🧑‍🏫 **Linux博士**：「ここまできたら、あとはユーザーがログインするだけ！」

---

🌟 **最終ステップ：ログイン！**
🖥 **画面**：「ユーザー名を入力してください」  
👤 **あなた**：「ユーザー名を入力！ログイン！」  
🖥 **画面**：「ようこそ！」  

---

## **📌 まとめ**
💡 **パソコンの電源を入れると、内部ではこんな流れで起動している！**
1️⃣ **BIOS/UEFI** が起動して、ハードウェアチェック！  
2️⃣ **ブートデバイス（HDD/SSD）** を探す  
3️⃣ **GRUB（ブートローダー）** がOSを選択  
4️⃣ **Linuxカーネル** が動いて、メモリやCPUを準備  
5️⃣ **systemd** が各種サービスを起動  
6️⃣ **ログイン画面が表示され、ユーザーが操作可能に！**  

---

## **💡 確認クイズ！**
### **Q1. BIOS/UEFI の役割は？**
➡ （A）ハードウェアのチェックをして、OSを起動する準備をする  

### **Q2. GRUB（ブートローダー）の役割は？**
➡ （A）どのOSを起動するか選ぶ  

### **Q3. カーネル（Kernel）は何をする？**
➡ （A）CPU・メモリ・ストレージなどを管理する  

---

🧑‍🏫 **Linux博士**：「どうだい？Linuxの起動プロセスがイメージできたかな？」  
👤 **あなた**：「めちゃくちゃ分かりやすい！PCの中でみんなが働いてる感じがする！」  

---

✨ **これで、Linuxのブートプロセスをマスター！** ✨  
もし分からないところがあれば、何でも聞いてください！💡

# ここまでがGPTの出力
どうでしたか？？なかなか良いプロンプトですよね！！ぜひ試してみてください！！
私は今回のプロンプトでは指定してないですが、「場面解説するキャラクター」を登場させるようにプロンプトに入れてもさらに理解が楽になりそうで良いですよね👀
【失敗談】Python病との戦い：便利すぎるがゆえの落とし穴

# **1. はじめに**
Pythonは非常に便利で何でもできる言語ですが、その万能さゆえに「Python病」とも呼べる現象に陥りました。このPythonを過剰に活用してしまった失敗談や反省点、そして適材適所の重要性について記載します。

---

# **2. SQL関連の反省：環境構築と操作の分離**
- **問題点**: SQLAlchemyを使ってデータベースの環境構築から操作まで全てPythonで行おうとした結果、コードが複雑化しメンテ不能な状態に。
- **学び**: 環境構築はSQLコマンドで行い、Pythonはテーブル操作のみに専念することで、学習難易度やメンテナンス性が大幅に向上。
- **結論**: 適材適所を意識し、ツールごとの役割を明確にすることが重要。

---

# **3. AWS関連の反省：boto3とTerraform/CloudFormation**
- **問題点**: boto3を使ってAWSリソースを管理しようと試行錯誤したものの、コードが複雑化してメンテナンス不能に。
- **学び**: TerraformやCloudFormationなどの専用ツールを活用すれば、より簡単かつ効率的に環境構築が可能。
- **結論**: Pythonは便利だが、AWS管理には専用ツールの方が適している場合が多い。

---

# **4. Dockerfile生成での試み：テンプレート拡張の失敗**
- **問題点**: DockerfileをPythonでテンプレート化しようとしたが、結果的に時間と労力を浪費。
- **学び**: シンプルなDockerfileであれば直接記述する方が効率的でメンテナンス性も高い。
- **結論**: 自動化や効率化を追求しすぎると逆効果になる場合もある。

---

# **5. Excel操作：openpyxl vs VBA**
- **問題点**: Python（openpyxl）でExcel操作を自動化したものの、数万行程度の表計算であればVBAやExcel関数の方がメンテナンス性が高いと感じた。
- **学び**: 小規模な処理なら既存機能を活用した方が良い場合も多い。
- **結論**: 楽しい試行錯誤も大切だが、目的に応じた最適な手段を選ぶべき。

---

# **6. 低レイヤ作業：Cpython vs C/C++**
- **問題点**: 一時期低レイヤ作業をCpythonで試みたが、C/C++を使った方が簡単かつ効率的だった。
- **学び**: 適材適所で言語やツールを選ぶことの重要性を再認識。
- **結論**: Pythonだけに頼らず、他言語も柔軟に活用する姿勢が必要。

---

# **7. まとめ：Python病から脱却するために**
- Pythonは万能な言語ですが、その便利さゆえに全てをPythonで解決しようとしてしまう「Python病」に何度も陥りました。
- 適材適所でツールや言語を選ぶことが、効率的かつメンテナブルな開発につながります。
- 今後も再発しそうな「Python病」ですが、そのたびに冷静になり最適な手段を選ぶことを心掛けたいと思います。

---

# **8. おわりに**
生成AIなど技術の進化によって言語の壁はほぼなくなりつつあります。これからも楽しみながら試行錯誤しつつ、「適材適所」を意識して開発していきたいと思います。


# その他

AtCoderについては、現状ランク上昇ではなく、考え方やアルゴリズムを学んでいるため、仮にTLE頻発しようと使い慣れたpythonを続けて行きます。

解放さえ理解すれば、他言語にも生成AIで対応出来るし、言語変換については[AtCoderの規約]()でも禁じられてませんしね。
太田心のブログ：高単価エンジニアになる方法

太田心です。

エンジニアとして働くなら、できるだけ高単価で案件を獲得したいと考えるのは当然のことです。しかし、単に技術力を上げるだけでは、高単価エンジニアにはなれません。ここでは、実際に高単価を実現するために必要なスキルや考え方を具体的に解説します。

## 1. **専門性を磨き、希少価値を高める**

高単価エンジニアになるためには、他にはない専門性を持つことが重要です。特に以下の分野は需要が高く、報酬も上がりやすいです。

- **AI・機械学習**：最新の技術を扱える人材は不足しており、高単価を期待できます。
- **クラウドインフラ**：AWSやGCP、Azureのスキルは、クラウド移行の需要に伴い高く評価されています。
- **セキュリティ**：サイバーセキュリティの専門知識はニッチでありながら必要不可欠な分野です。

### ポイント
特定の技術領域に強みを持ち、「この分野なら任せられる」と言われるようになることを目指しましょう。

## 2. **ビジネス視点を持つ**

高単価を実現するためには、単なる技術者ではなく、ビジネスに貢献できるエンジニアになる必要があります。

- **顧客の課題を理解する**：技術だけでなく、クライアントが抱える課題を理解し、解決策を提示できることが重要です。
- **ROIを意識する**：技術の導入によって、いかにコスト削減や売上向上に貢献できるかを説明できると価値が高まります。

### ポイント
「技術で何を解決できるか」を説明できるエンジニアは、クライアントから重宝され、単価も上がりやすくなります。

## 3. **コミュニケーション能力を向上させる**

技術力だけではなく、円滑なコミュニケーション能力も重要です。

- **要件定義の精度を上げる**：クライアントの要望を正確に理解し、整理できる能力は特に評価されます。
- **非エンジニアにも分かりやすく説明**：技術的なことを専門外の人にわかりやすく伝える力が、信頼を獲得します。

### ポイント
高単価を目指すなら、「分かりやすく、丁寧に伝える力」を意識的に磨きましょう。

## 4. **実績を見える化する**

高単価を提示するには、自分の価値を相手に伝える必要があります。

- **ポートフォリオを作成**：過去の成果を具体的に示すポートフォリオを作成しましょう。
- **資格を取得**：AWS認定資格や情報処理技術者試験など、市場価値が高い資格を取得することも有効です。
- **ブログ・SNSを活用**：技術ブログやSNSで知見を共有し、専門家としてのブランドを築くとよいでしょう。

### ポイント
客観的な実績を示すことで、単価交渉がしやすくなります。

## 5. **単価交渉を恐れない**

高単価を得るためには、自ら積極的に単価交渉を行う姿勢も必要です。

- **市場価格を把握する**：同じスキルセットを持つエンジニアの市場価格を調査し、自分の単価が適切か確認しましょう。
- **自信を持って交渉**：自分の価値を理解し、自信を持って希望単価を提示することが大切です。

### ポイント
単価交渉は実力と同じくらい重要です。自分の価値を正しく評価し、適切な価格を提示しましょう。

## まとめ

高単価エンジニアになるためには、技術力だけでなく、ビジネス理解・コミュニケーション・実績の見える化・交渉力が求められます。これらを意識的に強化し、市場での価値を高めることで、より高い報酬を実現できるでしょう。
Tips: GitHub Actions で Array を複数行の文字列に変換する方法

# 忙しい人向け

GitHub Actions の式で以下のように `fromJSON('"\n"')` を join すると、 改行文字 `\n` で区切られた複数行の文字列に変換できます。

```js
join(array, fromJSON('"\n"'))
```

# 解説

以下のように定義した Array を例として説明します。

```yaml
env:
  ARRAY: '["candy", "cookie", "chocolate"]'
```

（env には直接 Array を渡せないので、string にしてあります。以降、[`fromJSON`](https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#fromjson) で Array に変換してから使用します。）

## 失敗するパターン

まずは、普通に [`join`](https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#join) で `'\n'` で連結してみます。

```yaml
      - run: echo "$OUTPUT1"
        env:
          OUTPUT1: ${{ join(fromJSON(env.ARRAY), '\n') }}
```

実行結果はこちら

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325392/546011b1-4050-4782-969d-ea4a014cae64.png)

`candy\ncookie\nchocolate` のようになってしまいました。
改行文字 (`LF`) ではなく、バックスラッシュ (`\`) と `n` が挟まれてしまい、1行の文字列になっています。

## 成功するパターン

ちょっとしたテクニックが必要です。
`fromJSON('"\n"')` のように書くと、ちゃんと改行文字を挟んでくれます。

```yaml
      - run: echo "$OUTPUT2"
        env:
          OUTPUT2: ${{ join(fromJSON(env.ARRAY), fromJSON('"\n"')) }}
```

実行結果はこちら

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325392/68906f42-022d-460e-a4b3-03563bc52d6e.png)

`fromJSON` は文字列をパースしてJSONデータ型に変換できます。
文字列も JSON として有効なので、`"\n"` を文字列化した `'"\n"'` を `fromJSON` でパースすると改行文字になります。
【メモ】オレオレ証明書

## 前書

いつもコマンドを忘れてしまうための備忘録。
（[mkcert](https://github.com/FiloSottile/mkcert)使うのが一番楽だが、勝手にインストできないとき用）

* Ubuntu 24.04.1 (wsl2)
* OpenSSL 3.0.13 30 Jan 2024 (Library: OpenSSL 3.0.13 30 Jan 2024)

コマンド中のCN（CommonName）など適宜変更すること。

## ルート認証局

認証局になる秘密鍵と証明書。

```
$ openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout rootCA.key -out rootCA.crt -subj "/C=JP/ST=Tokyo/L=Minato/CN=local Root CA"
```

## サーバ証明書と秘密鍵

まずは秘密鍵と著名要求（Certificate Signing Request）を作成。

```
$ openssl req -newkey rsa:2048 -nodes -keyout server.key -out server.csr -subj "/C=JP/ST=Tokyo/L=Minato/CN=localhost"
```

SAN（SubjectAltName）を設定するためのファイル用意。

```[ext.txt]
subjectAltName=DNS:localhost,IP:0.0.0.0
```

作成した著名要求にルート証明書で著名。

```
$ openssl x509 -req -days 365 -in server.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out server.crt -extfile ext.txt
```

## 末文

やっぱopensslはコマンドむずすぎる（多すぎる）、以上。
Tableau blueprint重要だな〜と思ったことまとめ

Tableau bleuprintで大事だなと思ったことまとめ
URL
https://help.tableau.com/current/offline/ja-jp/tableau_blueprint.pdf

SELECT 
    s.name AS site_name,
    COALESCE(SUM(w.size), 0) AS total_workbook_size,
    COALESCE(SUM(d.size), 0) AS total_datasource_size,
    COALESCE(SUM(w.size), 0) + COALESCE(SUM(d.size), 0) AS total_storage_size
FROM sites s
LEFT JOIN workbooks w ON s.id = w.site_id
LEFT JOIN datasources d ON s.id = d.site_id
GROUP BY s.name
ORDER BY total_storage_size DESC;
sizeof演算子



```C:sizeof演算子
#include <stdio.h>

int main(void)
{
    int n;
    printf("sizeof 1             = %zu\n", (sizeof  1));
    printf("sizeof-1             = %zu\n", (sizeof -1));
    printf("sizeof(unsigned)-1   = %zu\n", (sizeof(unsigned)-1));
    printf("sizeof(double)-1     = %zu\n", (sizeof(double)-1);
    printf("sizeof((double)-1)   = %zu\n", (sizeof((double)-1)));
}

```

実行結果
```
sizeof 1             = 4
sizeof-1             = 4
sizeof(unsigned)-1   = 3
sizeof(double)-1     = 7
sizeof((double)-1)   = 8
```

sizeof演算子は、引数で与えられた式・型のメモリサイズを返す。単位はbyte。
- `sizeof1`, `sizeof-1:`
1はint型なので4。-1も同じ
- `sizeof(unsigned)-1` : 
まずsizeof(unsigned)が評価され、unsigned int型なので4。そこから-1するので3
- `sizeof(double)-1`:
上に同じ。double型なので8。そこから-1するので7
- `sizeof((double)-1)`:
こちらはまず()内の(double)-1が評価される。()の中では-1をdoubleに型キャストしている。引き算っぽい見た目してるけど、引き算ではない。
また、`sizeof(double-1)`はエラーとなる。型名そのものを式にぶち込む（=オペランドとして使う）ことはできないから。
最近流行のmiseで環境構築してみた

# はじめに
　以前までasdfというツールを用いて環境構築をしていたのですが、最近miseというものが流行っているようなので備忘録もかねて環境構築してみました。

# 環境構築の手順

- WSL2を[公式サイト](https://docs.microsoft.com/ja-jp/windows/wsl/install-win10)の手順に基づきインストールする。

- ディストリビューション（[Ubuntu](https://www.microsoft.com/ja-jp/p/ubuntu/9nblggh4msv6?activetab=pivot:overviewtab)）をMicrosoftStoreからインストール

- ubuntuを起動し、アカウント名とパスワードを入力してアカウントを作成する、

- 以下のコマンドを実行してパッケージを更新する。
```bash
sudo apt update
sudo apt -y upgrade
sudo apt -y dist-upgrade
```
    
- 以下のコマンドを実行してmiseを適用する。
```bash
sudo apt install -y curl git
curl https://mise.run | sh
echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc
exec $SHELL -l
```

- 各言語で必要なパッケージ（特にphp）をインストールしておく。
```bash
sudo apt install g++ make autoconf bison re2c libxml2-dev libssl-dev libsqlite3-dev zlib1g-dev libcurl4-openssl-dev libgd-dev libonig-dev libpq-dev libreadline-dev libzip-dev libbz2-dev libyaml-dev gfortran xorg-dev
```

- 各言語をmiseを用いてインストールする（phpの場合は以下の通り）
```bash
mise ls-remote php # phpのインストールバージョンを確認
mise use php@(インストールバージョン) # すべてのフォルダでインストールバージョンのphpが利用できる
mise ls # phpがインストールできたかを確認
```
- これを別の言語でも実施すれば、使える言語が広がります。詳細はmiseの[HP](https://mise.jdx.dev/getting-started.html)をご確認ください。私の場合は、以下の通りインストールできました。
```bash
Tool     Version                Source                      Requested
crystal  1.15.0                 ~/.config/mise/config.toml  latest
go       1.23.5                 ~/.config/mise/config.toml  latest
java     adoptopenjdk-23.0.2+7  ~/.config/mise/config.toml  adoptopenjdk-23.0.2+7
mint     0.22.0                 ~/.config/mise/config.toml  latest
node     22.13.1                ~/.config/mise/config.toml  22.13.1
php      8.4.3                  ~/.config/mise/config.toml  8.4.3
python   anaconda3-2024.10-1    ~/.config/mise/config.toml  anaconda3-2024.10-1
r        4.4.2                  ~/.config/mise/config.toml  latest
ruby     3.4.0                  ~/.config/mise/config.toml  3.4.0
rust     1.84.1 (symlink)       ~/.config/mise/config.toml  latest
```
# asdfとの比較

　コマンドの違いについては既に別の方が投稿されている（ [asdf/mise コマンド比較](https://qiita.com/Lamaglama39/items/70a359b4f4c613eb2ee6)）ので、そちらをご確認いただければと思います。個人的には

 - rustのcargoコマンドやphpのlaravelコマンドなどを利用するときにパスを通さなくてもいい
 - javaのjava_homeをmise useした時点で自動で変更してくれる

といったところで便利だと感じてます。

# 補足

言語によってはインストールが困難な場合があるため、エラーが発生した際には参照していただければと思います。

- php

```bash
例：Could not open input file: composer.phar
```
このエラーはあまり起こらないかもしれないですが、opensslがバージョン3以上だと起こるので一時的にダウングレードすると発生しないと思います（macだとよく起こるのでたちが悪い…）。

- R言語
```
例：libicuuc.so.73: cannot open shared object file: No such file or directory
    undefined reference to `uloc_setDefault_73'
```

1. icuの[github](https://github.com/unicode-org/icu/releases)にアクセスする。
1. 例では73.Xのバージョンになるため、icu4c-XX-X-src.tgzをダウンロードする。
1. 以下のコマンドを実行する。
```bash
sudo ln -s /usr/include/locale.h /usr/include/xlocale.h
wget (icu4c-XX-X-src.tgzのURL)
tar xvfz icu4c-XX-X-src.tgz
cd icu/source
./configure
make
sudo make install
```

```
例：libiconv関連のエラー
```
1. 以下のコマンドを実行する。
```bash
wget https://ftp.gnu.org/gnu/libiconv/libiconv-1.17.tar.gz
tar xvfz libiconv-1.17.tar.gz
cd libiconv-1.17
./configure --prefix=/usr/local
make
sudo make install
```
【Python3】【電脳少女プログラミング2088 ─壊レタ君を再構築─】「自然の残る公園」をchatGPTにコードレビューしてもらった。

Qiita公式で投稿のネタを提供してくださったので...

paizaの新作プログラミングゲーム【電脳少女プログラミング2088 ─壊レタ君を再構築─】[自然の残る公園（paizaランク：C相当）](https://ppg.paiza.jp/denno2088/areas/10)をPython3で実装しました。

- - -
###### 問題
https://ppg.paiza.jp/denno2088/challenges/denno2088_c_c_03

- - -
###### 内容
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517078/7f416a2e-b3ba-44bf-afbe-9946d5b3bd29.png)

現在地の座標から最短の座標の距離(ユークリッド距離)を求める問題だったので、
実装後、chatGPTにコードレビューしてもらって、その後に改良したコードもレビューしてもらいました。

:::note warn
注意
情報漏洩の危険性があるため、
コードに個人情報、認証情報、顧客情報が含まれる場合は注意してください。

:::

## 最初のコード
``` python3
import numpy #平方を求めたい

#ビーコンの数、現在地x座標、現在地y座標
beacon_num, now_x, now_y = list(map(int, input().split()))
dict_distance = {} #キー:ビーコン番号 バリュー:距離

#ビーコンの回数分ループ
for i in range(beacon_num):
    #まずはビーコン番号:[x座標, y座標]の形で辞書を作る
    dict_distance[i+1] = list(map(int, input().split()))
    #現在の座標との距離を計算する
    distance = ((now_x - dict_distance[i+1][0]) **2  + (now_y - dict_distance[i+1][1]) **2) 
    #平方根を計算して結果をビーコン番号:距離の形で格納
    dict_distance[i+1] = int(numpy.sqrt(distance))

#最終的な答えを入れる変数を作成して0で初期化
answer = 0
#辞書のバリューを比較するためのダミーのデータを入れておく(後述のif文で必ずTrueが返る値)
test_case = 10000000

#距離の比較をして一番小さい値のビーコン番号がanswerに格納されるようにループ処理
for key, value in dict_distance.items():
    if value <= test_case:
        answer = key
        test_case = value
        
#結果を表示
print(answer)
```

という感じで作りました。

## 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517078/0ba3ab43-90f3-40f5-97a1-aae20c72a076.png)

・数の比較ができればいいから平方根の計算がいらない
・結果欲しいのは最短距離を示すビーコンの番号だけだから他のビーコンの番号を記憶しておく必要ない

冷たい。
ということなので修正してみました。

## 2回目のコード
``` python3
#ビーコンの数、現在地x座標、現在地y座標
beacon_num, now_x, now_y = list(map(int, input().split()))

#最終的な答えを入れる変数を作成して0で初期化
answer = 0
#辞書のバリューを比較するためのダミーのデータを入れておく(後述のif文で必ずTrueが返る値)
test_case = 10000000

#ビーコンの数分ループ(iはビーコンの番号として使う)
for i in range(beacon_num):
    #ビーコンのx座標、y座標を取得
    x, y = list(map(int, input().split()))
    #距離計算してresultへ格納
    result = (now_x - x) ** 2 + (now_y - y) ** 2
    #resultとtest_caseを比較する
    if result <= test_case:
        answer = i + 1 #indexは0からスタートするためビーコンの番号として機能するように+1をする
        test_case = result

print(answer)
```
numpyと辞書を使わなければこうなりました。

## 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517078/534fd1ae-caed-4b9c-9480-42853a3a13d7.png)
褒めてくれました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517078/abd243cc-eede-481d-8420-4e4aca68e848.png)
最初のレビューでは冷たかったのに今ではすっかりと仲良しになりました。

## まとめ
問題の判定としては両コード間違いではないですが、ふと自分のコードってどうなの？って客観視したいときには
AIを有効活用して更なるスキルアップを目指したいですね！
Spring Boot トランザクション

## はじめに
spring bootのトランザクションの貼り方について
[@Transactional アノテーションでトランザクション管理](@Transactionalアノテーションでトランザクション管理)で学習したのでまとめます。

## 貼り方

コードを一部抜粋
```java
package com.example.managingtransactions;

import java.util.List;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

// Transactionを利用したいファイルでインポートを行う
import org.springframework.transaction.annotation.Transactional; 


@Component
public class BookingService {

    private final JdbcTemplate jdbcTemplate;

    public BookingService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    
   // Transactionを貼りたい場所でアノテーションを設定する
    @Transactional

    // Stringの配列を引数で受け取り一件ずつInsert
    public void book(String... persons) {
        for(String person : persons) {
            jdbcTemplate.update("insert into BOOKINGS(FIRST_NAME) values (?)", person);
        }
    }
}
```

配列の要素が全てInsert成功時のみCommitされる。
失敗したらRollbackされる
【LADMEハッカソン】茶太郎アイランド：「中中の麻雀トレーニング」

## アプリの一言紹介

### 課題
麻雀の役を覚えることが難しく、数を計算することが難しい

### 解決案
ユーザーの手牌をもとに点数や翻数を計算する

### こんなアプリを作りました！
手牌とさまざまな条件を入力することで役を判定し、点数を表示する

### アプリの一押しポイント！
手牌を画像で表示することでユーザーが理解しやすいようにした
オリジナルキャラクターの中中を作った

## リンク集
https://github.com/LEADME-Okinawa/mahjong_1

## アプリの背景
近年の日本では麻雀ブームがきている。2018年から始まった「Mリーグ」や麻雀アプリなど、日常生活において麻雀に触れる機会は多くなっています。しかし、麻雀はルールが複雑で計算が難しく、始めるハードルは高いです。

そこで、私たちは「役や翻数を判定し、点数を表示するアプリ」を開発しました。このアプリは、ユーザーが和了したときの手牌や自風、場風、状況役などを入力することで、役の種類や翻数、点数を表示することができる機能を提供します。これにより、初心者でも役の種類や翻数、点数を簡単に知ることができるような仕組みになっています。
## アプリの紹介
### 機能
・ユーザーが和了したときの手牌、自風、場風、親・子、状況役、ドラの数を入力することで翻や点数計算、役の検出を行い、結果を出力することができるようになりました

## 画面
### トップページ
![main.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4013530/7c8e040d-ba59-4b5c-bcf0-78243fa673c4.png)

・手牌選択から和了時の手牌を入力することができます。
・スコア表示ボタンを押すことで点数と翻数の履歴を閲覧することができます。


### 条件選択画面
![jyouken1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4013530/af472e22-ef6d-4eec-a97e-35ecb24f66a5.png)

![jyouken2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4013530/c52c3736-3723-460b-93d1-fb3b55878b4d.png)

・場風、自風、親・子、条件役、ドラの数を入力し、点数表示を押すことで点数表示画面に役や点数、翻数のデータを送信できます。

###点数表示画面
![result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4013530/10b7049d-ae95-47fb-87e2-31d7f599f8bb.png)


・条件選択画面から送信されたデータが画面上に表示されます。

## 技術紹介
フロントエンドではDart/Flutter、バックエンドでは役や翻数、点数の結果をクラウド上に保存するためデータベースとしてFirebaseを使用しています。

## こだわり
手牌選択ボタンから手牌を選択を行うと画像で手牌が表示されるようにしました。これにより、ユーザーが選択した牌が分かりやすくなりました。
オリジナリティを出すために中中というキャラクターを作成しました。

## 今後の意気込みについて
　私たちのチームは約１ヵ月前にアプリ開発について学び、今回のハッカソンに参加したので不安もあったのですが、無事にチームで大枠のアプリを開発することができてよかったです。ハッカソンではマージする際のコンフリクトや意見の相違など、チームで作業する難しさやチームで協力してひとつのアプリを完成させたときの楽しさを体験することができました。アプリ開発に関しては、現状符計算の実装ができていないので今後も継続して今回の麻雀計算アプリの開発を進めていきたいです。
typstでpdf形式の図を入れる

## はじめに
LaTeXではjpg画像やpng画像と同じ記法でpdf形式の図も挿入することが可能ですが，現在のところTypstではそのようなことはできません．そこで，Typstでpdf形式の図を埋め込む方法を説明します．

## 方法
muchpdf というライブラリを用いることでpdf形式の図を挿入することが可能です．muchpdf を使用する際には，`#import "@preview/muchpdf:0.1.0": muchpdf` でインポートします．以下のコードをコンパイルします．

```typst
#import "@preview/muchpdf:0.1.0": muchpdf

画像を挿入するよ．
#figure(
  muchpdf(
    read("figure/sine_wave.pdf", encoding: none),
  width: 10cm,
  ),
  caption: [
    sine wave．
  ]
)
画像を挿入したよ．
```

出力結果は以下の通りです．
`#figure()`を使うことで中央揃えやキャプションの設定などを用いることができます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642842/22dc0761-8b6e-4148-93db-d5a835df468a.png)

## 参考文献
- muchpdf https://typst.app/universe/package/muchpdf/
- Image Function - Typst Documentation https://typst.app/docs/reference/visualize/image/
<Python>1GB以上のファイルを探す

# 前提
自分でPythonを学習するために自分が使いたいスクリプトを書いてみました。
記録のために投稿します。

# コード
```python
import os
import datetime
import math

#file_unitはファイルサイズ単位を適切に判断するための処理です。
#少数点第二位までを表示させます。
#人間が読みやすいようにファイルサイズによって単位を変更します。
def file_unit(size_bytes):
	units=["B", "KB", "MB", "GB", "TB"]
	i = math.floor(math.log(size_bytes, 1024)) if size_bytes > 0 else 0
	size = round(size_bytes /1024 ** i, 2)
	return f"{size}{units[i]}"


#list_filesはファイルサイズが1GB以上のファイルを出力する処理です。
#file_size >= 1 * 1024 * 1024 * 1024 によってファイルサイズを計算しています。1024を1回掛けるごとにファイルサイズが1KB,1MB,1GBというように変化します。
#表示はファイルフルパス、タイムスタンプ、ファイルサイズを表示します。
def list_files(base_dir):
	file_info_list=[]
	for root, dirs, files in os.walk(base_dir):
		for file_name in files:
			file_path = os.path.join(root, file_name)
			if os.path.isfile(file_path):
				file_size = os.path.getsize(file_path)
				if file_size >= 1 * 1024 * 1024 * 1024:
					mtime = os.path.getmtime(file_path)
					timestamp = datetime.datetime.fromtimestamp(mtime).strftime('%Y/%m/%d')
					file_info_list.append({
						"path": file_path,
						"timestamp": timestamp,
						"size": file_size
					})
	if file_info_list==[]:
		print("file over 1GB was not found")
	for info in file_info_list:
		size_str = file_unit(info["size"])
		print(info["path"])
		print(info["timestamp"])
		print(size_str)
		print()

if __name__ == "__main__":
	TARGET_DIR = "."             #任意のフォルダを指定してください。
	list_files(TARGET_DIR)
```
（模索中）LaravelでグローバルIPアドレス取るのってどうすんだっけという記事

# 環境
- laravel 11
- react-router
- docker
- nginx

# 起こった事
要件でログイン画面にアクセス元のグローバルIPアドレスを表示する実装で躓いた。
やりたいこととしてはそのIPアドレスをログイン時に送信してuserテーブルが持っているipadressカラムの値じゃなかったらNGみたいなものを作ろうとしていた。

# 実装
以下のようにBE側でIPアドレス取得のメソッドを作ってFEでloaderから呼べばいいんじゃないかと思って実装

### BE側

```php
        $forwardedFor = request()->headers->get('X-Forwarded-For');
        $realIp = request()->headers->get('X-Real-IP');
        $clientIp = null;
        $isClientIpReliable = true;

        if ($forwardedFor) {
            $ipAddresses = explode(',', $forwardedFor);
            $clientIp = trim($ipAddresses[0]);
        } elseif ($realIp) {
            $clientIp = $realIp;
        } elseif (request()->ip()) {
            // ローカルホストのIPは除外
            $clientIp = request()->ip();
            $isClientIpReliable = false;
        }

        return ['clientIp' => $clientIp, 'isClientIpReliable' => $isClientIpReliable];
```

FE側
```react
export const loader = async () => {
  const { data, error } = await apiClient.GET('/get-ip（みたいなURL）')

  if (error) {
    return { error: error.message }
  }

  return { data }
}
```

# とれてるっちゃ取れてるけど
Swaggerから行った値が以下
`192.168.xx.x`
FEに表示されてる値は
`172.18.x.x`
だった。
ちなみにpostmanでも同じ結果だった

まだデプロイしていない状態だから自身のプライベートアドレスが返ってくるかなと思ったらどうやら違う。
ちなみにプライベートIPは
`10.x.x.x`
全部違う値や。。。

# NGINXではどうなのか
ログは見た感じ以下のようなことがわかった
`192.168.xx.x`と`172.18.x.x`はnginx側のログに残っているのでおそらく`192`側はBE、`172`はFEなのかなという感じ。

# dockerの方ではどうなのか
`docker network inspect bridge | grep Gateway`
で見てみると
`Gateway: 172.17.x.x`

# どうしようか
多分Docker内のネットワークを参照してIPアドレスを取得してる感じがするのでdockerが外部IPを取れるような感じにするんかなぁdockerを雰囲気でやってきたので少し勉強しよ。
PHP学習メモ⑤

# 論理リテラル（bool）
ture/false　大文字、小文字の区別はない
PHPでは「falseキーワードだけがfalseを表すわけではない」
以下が自動でfalseとみなし
・空文字列、または文字列の0
・整数リテラル0、-0
・浮動小数点数リテラル0.0、-0.0
・要素数が0である（空の）配列
・null（未定義数）


# 整数リテラル（int）
よくわからないのでスキップｗ

# 浮動小数点数リテラル（float）
よくわからないのでスキップｗ

```ruby:桁数が大きい時に、以下のように区切る
$price = 10_214_00 ;
$value = 12.3_124_14;
```
└一般的には3桁単位区切る
└数値セパレーターを挿入できるのは数値の間だけ！

# 文字列リテラル
文字列リテラルを表すには、文字列全体をシングルクォート、またがダブルクォートでくくる必要がある

```ruby:OKな例①
print " you are so 'CUTE' ! " ;
```

```ruby:OKな例②
print ' you are so " CUTE " ! ' ;
```

```ruby:NGな例
print ' you are so ' CUTE ' ! ' ;
```
もし文字列にシングルクォート/ダブルクォート双方が含まれる場合

```ruby:He's " GREAT " teacher !
print ' He\'s " GREAE " tache ! " ; 
```
ここではエスケープ処理をしている
└**エスケープ処理**とは、
ある文脈の中で意味を持つ文字を、あるルールに基づいて無効化する

# シングルクォート文字列とダブルクォート文字列の違い

```ruby:例文
<?php
$title = 'あいうえお';
$date1 = 'ようこそ \ t [{$title}]へ , br /> ';
$date2 = 'ようこそ \ t [{$title}]へ , br /> ";
print $data1 ;
print $date2 ;
```
実行結果
```ruby:例文
ようこそ  [あいうえお]  へ
ようこそ¥t[{title}]  へ
```
（１）変数を展開するか
**変数展開**または**変数のパース
└**ダブルクォート文字列リテラルでは、文字列に含まれる変数を解釈し、その値で変数の箇所を置き換える

変数全体を｛　｝で囲んでいるのは、変数の範囲を明確にするため

```ruby:範囲が明確でない例
" I am $snowman_da!! "
```

```ruby:範囲が明確な例
" I am {$snowman}_da!! "
           or
" I am ${snowman}_da!! "
```

#エスケープシーケンスを認識するか
phpでは、タブや改行など特殊な意味を持つ文字を「\文字」の形式で表現する

<table>
  <caption>主なエスケープシーケンス</caption>
  <thead>
    <tr>
      <th>エスケープシーケンス</th> <th>概要</th>
    </tr>
  </thead>
  <tr>
    <td> \r </td> <td>復帰</td>
  </tr>
  <tr>
    <td> \n </td> <td>改行</td>
  </tr>
    <tr>
    <td> \t </td> <td>垂直タブ</td>
  </tr>
</table>
　　　　　　　　　　　　　　　　　など

**これらを認識できるのはダブルクォート文字列だけ**

# ヒアドキュメント

# ヌル（null）
ヌル型は、ある変数が値を持たないことを表す
以下の条件で変数はヌルであるとみなされる
・変数に値を代入されていない場合
・変数に明示的にnullが代入された場合
・unset関数で変数の内容が放棄された場合
怠惰なのでQiitaを今さら始める

## やる気のない記事を書いていきます
初めましてMakiです。Webエンジニアとして働き始め1年と少しが経ったへっぽこエンジニアです。
何か自分がしてきたことやしていることをまとめ始めようと言いながら大学時代から含めると4年近く経ちました。
いい加減やろうと決意しここに残しています。

基本ネガティブな言葉ややる気のない記事だけが残されていくと思いますがよろしくお願いします。

## 技術について
書いていくであろう技術だけ残します。
基本的にWeb技術の関することを残すつもりです。

* HTML/CSS
* Javascript/Typescript
* React/Vue その他フレームワーク

## 更新ペース
2~3日に１回くらいのペースで残せればと思ってますがどうなることやら



### では皆さんどうぞよろしくお願いします。
AWS TranscribeのJSON出力を整理しつつテキスト化

AWS TranscribeのJSON出力を整理しつつテキスト化するPowerShellスクリプトを書いてみた。

https://gist.github.com/mtsukamoto/0055e1dd0aae28e5fa732617684eeb8c

# 動作仕様というかプロンプト

書いてみたというけど、実際にはChatGPT 4oとの共作で、最初のうちは生成されたスクリプトを手作業でエラー解決したり動作改善させたりしていって、最後はプロンプト一発でこのスクリプトを生成させるところまでいった。

動作仕様の説明にもなると思われる、最終的なプロンプトは以下。

## 概要

AWS TranscribeのJSON出力を、読みやすいテキストに整理するPowerShellスクリプトを必要としています。

## 処理方法

1. 入力JSONファイルを出力テキストファイル名を引数で受け取ります。
2. 入力JSONファイルを読み込みます。 `ConvertFrom-Json` を使い、変数 `$data` に格納します。
3. `$data.result.items` を `$items` に格納します。
4. `$items` に格納されたアイテムを順に処理します。以下では個々のアイテムを `$item` とします。 `$item` は以下の情報を持ちます。
   1. `$item.alternatives[0].content` が発話テキストです。
   2. `$item.speaker_label` は発話者名です。
   3. `$item.start_time` は開始時刻、 `$item.end_time` は終了時刻が、秒で格納されています。ただしこれらを持たないアイテムもあります。
5. 以下のいずれかを満たすとき、そのアイテムを新しい発言の開始位置とみなします。
   1. 前のアイテムと発話者が違う
   2. 前のアイテムの終了時刻と、いまのアイテムの開始時刻が、3秒以上空いている
   3. 前のアイテムが `。` または `.` で終わっている。
6. ひとまとまりの発言を、以下の情報を持つアイテムにまとめてください。
   1. `content` に、この発言の全部の発話テキストが連結されて格納されている。連結時、前のアイテムの発話テキストが英数字で終わっており、このアイテムの発話テキストが英数字で始まっているときは、半角空白を挟む。
   2. `start_time` に、一つの発言にまとめられた全アイテムのうち、最初に開始時刻を持っていたアイテムの開始時刻が格納されている。
   3. `end_time` に、一つの発言にまとめられた全アイテムのうち、最後に終了時刻を持っていたアイテムの終了時刻が格納されている。
   4. `speaker_label` に、この発言の最初に出てきた発話者名が格納されている。
7. 全アイテムの処理が終わったら、結果を出力テキストファイルに出力します。
   1. 前の発言の終了時刻と、この発言の開始時刻が3秒以上空いている場合、または前の発言とこの発言の発言者が違う場合、空行を挟みます。
   2. 出力時に、開始時刻と終了時刻は `h:mm:ss` の形式に変換します。
   3. 発言の末尾には改行を一つ入れます。

## 指示

上記を行うPowerShellスクリプトを出力してください。
Ruby: HTMLパーサGammoでルート以外の要素を起点にcssメソッドを使いたい

<!-- ruby-gammo-html-parser-element-css -->

Gammo は pure Ruby な HTML パーサです。

- [gammo | RubyGems.org](https://rubygems.org/gems/gammo)
- [namusyaka/gammo: A pure Ruby HTML5-compliant parser with CSS selector and XPath 1.0 traversal](https://github.com/namusyaka/gammo)

参考: [WHATWG Living StandardとHTMLパーサ - Qiita](https://qiita.com/namusyaka/items/f10ce88e6f8bf322b0ff)

> 本記事は、WHATWG Living Standardに準拠することを目的としたHTMLパーサである「gammo」の紹介を目的としている。

---

タイトルの通りです。以下の方法でできました、というメモです。

```ruby
require "gammo"

def my_css(node, expr)
  # ほぼ Gammo::CSSSelector#query_selector_all の実装を流用しただけ
  Gammo::CSSSelector::Traverser.new(expr)
    .evaluate(Gammo::CSSSelector::Context.new(node: node))
end

html = <<~HTML
  <!DOCTYPE html>
  <html>
    <body>
      <div id="div1">
        <span>span 1</span>
      </div>
      <div id="div2">
        <span>span 2</span>
      </div>
    </body>
  </html>
HTML

doc = Gammo.new(html).parse

div2 = doc.css("#div2")[0]
p div2.class #=> Gammo::Node::Element

spans = my_css(div2, "span")
p spans.size #=> 1
p spans[0].inner_text #=> "span 2"
```

`Gammo::Node::Element` をオープンクラスして `include Gammo::CSSSelector` を追加する方法でも動きますが、モンキーパッチを避ける意味では上記の方法が無難かなと思いました。


# バージョン

```
ruby 3.4.1
gammo 0.3.0
```




# この記事を読んだ人は（ひょっとしたら）こちらも読んでいます

<!-- Raccでかんたんな自作言語のパーサを書いた  -->
https://qiita.com/sonota88/items/97ba1f0c377fbe86d5b1

<!-- Ruby/StringScanner: scan_full, search_full 系メソッドの整理   -->
https://qiita.com/sonota88/items/a7da299b84f17459967c

<!-- 『RubyでつくるRuby』のMinRubyのパーサを書いた（手書きの再帰下降パーサ）  --> 
https://qiita.com/sonota88/items/84e4c16e5602b9771e92

<!-- Lramaで簡単な自作言語のパーサを書いた   -->
https://qiita.com/sonota88/items/372da20581c16cbd4eea
Agentblazerになろう！

　本橋孝昭です

 今回はSalesforceのAgentblazerについて解説します


 サイトはこちらです

 https://trailhead.salesforce.com/ja/agentblazer

 こちらでモジュールを完了させると、Agentblazerステータスに加算されます

 AgentforceはLevelが3個あります


Level1　Champion
Level2　Innovator
Level3　Legend

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/20cfc205-acc0-41fc-9e47-ed9f2c9732f1.png)


 現状はChampionのみが解放されているのでChampionになれます


 もしもChampionが完了するとこのようにステータスが更新sれるようです

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/a95beb21-c779-48b1-a20b-98d44e32f07e.png)

今はChampoinのみ解放されてますが、
Level2　Innovator
Level3　Legend
がどういう内容なのか楽しみですね。
【超実践】Spring Boot × React でリアルタイム通信！SSE を完全理解

## 🎯 本記事のゴール

この記事では、Spring Boot と React を用いて **Server-Sent Events (SSE)** を実装し、サーバーからクライアントへのリアルタイム通知を行う方法を解説します！

- **SSE の仕組みを図解で理解する**
- **Spring Boot で SSE を実装する**
- **React 側で SSE を受信し、UI を更新する**

---

## 🔥 SSE とは？WebSocket との違いは？

SSE（Server-Sent Events）は、**サーバーからクライアントへ一方向のリアルタイム通信を行う技術**です。主に以下のような用途に適しています。

✅ **通知機能**（例：システムの更新情報）  
✅ **チャットアプリ**（ユーザーの新しいメッセージ受信）  
✅ **データストリーミング**（リアルタイムのデータ更新）  

### 📌 WebSocket との比較

| 特徴 | SSE | WebSocket |
|---|---|---|
| **通信方向** | 一方向（サーバー→クライアント） | 双方向（サーバー⇄クライアント） |
| **プロトコル** | HTTP | 独自の WebSocket プロトコル |
| **コネクション管理** | HTTP の keep-alive を利用 | WebSocket 専用の接続管理 |
| **適用例** | 通知、データストリーミング | チャット、インタラクティブなアプリ |

### 🎨 SSE の仕組み（図解）

```plaintext
+-------------+            +-------------+
|  クライアント  |<--HTTPリクエスト--> |   サーバー   |
| (React)     |            | (Spring Boot) |
|-------------|            |-------------|
| EventSource |  ←SSEイベント  | SseEmitter  |
| で接続       |            | で送信       |
+-------------+            +-------------+
```

---

## 🚀 Spring Boot で SSE を実装

まずは **Spring Boot 側で SSE のエンドポイント** を作成します。

### 📝 SSE のエンドポイントを作成

```java
@RestController
@RequestMapping("/sse")
public class SseController {

    @GetMapping("/stream")
    public SseEmitter streamSse() {
        SseEmitter emitter = new SseEmitter();
        new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    emitter.send(SseEmitter.event()
                        .name("message")
                        .data("リアルタイム通知 " + i));
                    Thread.sleep(1000);
                }
                emitter.complete();
            } catch (Exception e) {
                emitter.completeWithError(e);
            }
        }).start();
        return emitter;
    }
}
```

**ポイント**
- `SseEmitter` を使用し、非同期でイベントを送信
- 1秒ごとにメッセージを送信（10回繰り返し）
- エラー発生時は `completeWithError` を呼び出し

---

## ⚡ React で SSE を受信する

React 側で **SSE を受信して UI を更新** します。

### 📝 SSE クライアントの実装

```javascript
import React, { useEffect, useState } from 'react';

const SseComponent = () => {
    const [messages, setMessages] = useState([]);

    useEffect(() => {
        const eventSource = new EventSource('http://localhost:8080/sse/stream');

        eventSource.onmessage = (event) => {
            setMessages(prevMessages => [...prevMessages, event.data]);
        };

        eventSource.onerror = () => {
            console.error('SSEエラーが発生しました');
            eventSource.close();
        };

        return () => {
            eventSource.close();
        };
    }, []);

    return (
        <div>
            <h1>リアルタイム通知</h1>
            <ul>
                {messages.map((msg, index) => (
                    <li key={index}>{msg}</li>
                ))}
            </ul>
        </div>
    );
};

export default SseComponent;
```

**ポイント**
- `EventSource` を使用して SSE 接続
- `onmessage` で受信したメッセージを `messages` に追加
- エラー発生時は SSE 接続を閉じる

---

## ✅ まとめ & 実践

🚀 **Spring Boot × React で SSE を実装することで、リアルタイム通知が簡単に実現できる！**  
📌 **SSE は WebSocket に比べて実装がシンプルで、通知システムに最適！**  
💡 **サーバー側は `SseEmitter`、フロントエンドは `EventSource` を活用！**  

ぜひ、この記事を参考にしてリアルタイム通知機能を実装してみてください！🙌
複数リンク jsonファイルで開く

<h3>jsonファイルを使い、jsonファイルを読み込んで開くやり方が楽</h3>
<p>一個しか開けないwebbrowser.openは、大量リンクがあるとき使えない</p>

<br>
<h3>使うjsonファイル　注意点</h3>
<p>ファイルを囲うとき、必ずダブルクオテーション → ”</p>

```ruby:url.json
{
  "urls": [
"https://prtimes.jp/main/html/rd/p/000000080.000005698.html",

"https://news.mynavi.jp/techplus/article/security_ransomware02-pPbsjdDk/"
          ]
}
```
<br>

<h3>pythonファイルの中身</h3>
<p>たくさんURLがあるから、配列 forで必ずループさせる</p>
<p>たくさんURLがあるから、timeで時間をあけて開くよう設定</p>
<p>jsonファイルを使うときは、必ず import json</p>

```ruby:sample.py
import json
import webbrowser
import time

with open('url.json', 'r') as file:
    data = json.load(file)

# URLのリストを取得
urls = data['urls']

# 各URLを自動で開く
for url in urls:
    webbrowser.open(url)
```

<br>

<h4>感想</h4>
<p>pythonのコード、わかりやすいぃ</p>
scpコマンドについて


scp（Secure Copy Protocol）とはファイルをリモートサーバーにコピーするためのものです。

今回は例として、AWSのEC2でダウンロードしてきたローカルファイル(api-check-key.pem)をリモートサーバー(EC2のinstance) に移行します。

### 実行コマンド
```shell
$ scp -i ~/Downloads/api-check-key.pem ~/Downloads/api-check-key.pem ec2-user@11.111.11.111:~
```
scpコマンドは、5つのコードから成り立ちます。
```shell
$ scp -i '①SSH認証に使用するPEMファイル' '②コピー元ファイル' '③ユーザー名@IPアドレス'
```
### コマンドの詳細な解説:
- `scp`: 安全な通信を使ってファイルをリモートシステムにコピーするコマンド
- `-i ~/Downloads/api-check-key.pem`: scpで接続する際に使用する秘密鍵を指定する。ここでは`~/Downloads/api-check-key.pem`というファイルがSSH認証に使用される
- `~/Downloads/api-check-key.pem`: コピー元のローカルファイル（自身のPC上にある`api-check-key.pem`）
- `ec2-user@18.183.36.136:~`: コピー先のリモートサーバーの指定。`ec2-user`はサーバーのユーザー名、`11.111.11.111`はサーバーのIPアドレス、`~`はユーザーのホームディレクトリを意味する

### ポイント
`api-check-key.pem`を移行するためにscpコマンドを使用しておりますが、そのコマンドを使用する際の認証として`api-check-key.pem`を使用しています。
「なんで同じコード記述してるの〜」って最初は混乱していましたが、理解できてスッキリしました。

#### 以上です。
python path (自分用メモ)

<h3>pythonインスト　基本</h3>
<p>homebrewからインストールしたら、インストしてる時必ずミスる！</p>
<p>インストしたら、globalで設定するのを忘れない<p>

<h3>python path</h3>

```ruby:zshrc
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv init -)"
```
mattermost docker

https://docs.mattermost.com/about/version-archive.html

ESRバージョンを探す

```
sudo /usr/local/bin/docker-compose -f docker-compose.yml -f docker-compose.nginx.yml down
sudo systemctl stop nginx.service
sudo /usr/local/bin/docker-compose -f docker-compose.yml -f docker-compose.nginx.yml up -d
```
.env.localと.zshrcに同じ変数名を書いたら混乱した話(macOS)

# はじめに
[こちら](https://qiita.com/portfoliokns3/questions/087ffa8cf88397cf46e7#answer-0aa87e797e29b4497e22)の質問に対する解決法になります🤮

# 何があった？
.env.localへ環境変数を設定しても、全く違う値が取得されてしまう事象⚠️

具体的にはRECAPTCHA_SECRET_KEYに末尾3n7を設定したつもりが、コードを実行すると末尾cD5という意図しない値が取得されるという事象⚠️

# 原因
.zshrcの方に同じ変数名を記述していたことが原因💦

# 対処法
```:envの環境変数
vim ~/.zshrc
```
ここに同じ変数名がexportで記述されていたので、削除した🆑もう使わない古いものだったので削除したけど削除する際は注意が必要ですよ🚨

```:適応
source ~/.zshrc 
```
念の為に適応👀

```:Shellから削除
unset RECAPTCHA_SECRET_KEY 
```
環境変数を削除🆑

# .env.localって何なの❓
どうやらアプリケーション（プロジェクト）ごとに設定できる環境変数ファイルらしく、.zshrcと.env.localの違いを全然理解していなかった😅今回の事象を見るに同じ変数名だと環境変数（.zshrcの方）が優先されるみたい🧐ただ厳密にはどうなっているのか自分はわからないのでどっちが優先されるかは環境によるのかも❓
FlutterアプリのApp Storeリリースで躓いた点と解決方法


## はじめに
FlutterアプリをApp Storeにリリースする過程で、いくつかの躓きポイントがありました。この記事では、それらの問題と解決方法を共有し、同じ課題に直面している方々の助けになればと思います。

## 参考にしたサイト
- https://cat-prog.com/799/


## 主な躓きポイント

### 1. Bundle IDの変更に関する注意点
iOSディレクトリ内で、Bundle IDの変更が必要な箇所が2つあります。これを見落としやすく、後々の問題の原因となることがあります。

変更が必要なファイル：
1. `ios/Runner.xcodeproj/project.pbxproj`
2. `ios/Runner/Info.plist`

両方のファイルで Bundle ID が一致していることを確認してください。不一致があると、ビルドエラーの原因となります。

### 2. Xcodeが開けない問題
Flutterプロジェクトのディレクトリを選択してXcodeで開こうとしても、正しく開けないことがあります。これは、Xcodeで開く対象のディレクトリを間違えているためです。

#### 解決方法
- Flutterプロジェクトのルートディレクトリではなく、`ios/Runner.xcworkspace` を直接開いてください
- `ios/Runner.xcodeproj` ではなく、必ず `.xcworkspace` を使用してください

この違いは重要で、`.xcworkspace` にはCocoaPodsの依存関係情報が含まれているため、これを使用する必要があります。

### 3. Archive作成時のビルド失敗
Xcodeでアーカイブを作成する際（Product > Archive）に失敗するケースがあります。

#### 主な原因
Archive作成時に、正しいプロジェクトファイルが選択されていないことが主な原因です。

#### 解決手順
1. Xcodeの画面左上で必ず `Runner.xcworkspace` を選択していることを確認
2. Product > Archive を実行
3. 必要に応じて、Signing & Capabilities の設定を確認
   - TARGETS > Runner を選択
   - Building Settings タブを開く
   - 証明書が正しく選択されているか確認

## まとめ
App Storeへのリリースプロセスでは、以下の点に特に注意が必要です：
- Bundle IDの設定は複数箇所で確認
- 正しいXcodeワークスペースファイルを使用
- ビルド設定での証明書の確認
テストケースの考え方

# はじめに
私は株式会社GENEROSITYのエンジニアです。
開発において重要な工程である**テスト**の重要性について普及したいと思いこの記事を書きます。

はじめに　**有用なテストケースかけていますか？**

ソフトウェア開発において、テストは品質を確保するために欠かせない要素です。しかし、テストが十分に実施されていない、または効果的でない場合、バグや予期しない不具合が発生する可能性が高まります。
この記事では、テストの必要性から良いテストケースの作成方法、そしてテストケースの考え方について解説します。

合わせて以下記事もご参照ください
- [テストが書きやすいコードを書く](https://qiita.com/kentosity/private/d8654dad4fbf216f6843)
- [良いテストとは？なぜテストをするのか？](https://qiita.com/generoKoki/private/7c06f3df54766528a32b)

# こんな人に読んでほしい
- テスト作成者
- テスト実行者
- テストの重要性について理解したい

# テストの必要性
テストは単にバグを見つけるための手段だけでなく、ソフトウェアが要件通りに機能するかを検証する重要な手段です。テストを実施することで、以下のようなメリットが得られます。

- 品質の向上/仕様確認: ソフトウェアが想定通りに動作していることを確認できる
- バグの早期発見: 実際の運用に入る前に問題を見つけ、修正できる
- メンテナンス性の向上: 新たな機能追加や修正を行った際に影響範囲を簡単に特定できる
- リファクタリングの安心感: コードの変更やリファクタリングが安全であることを確認できる
- ドキュメントの代替: テストコード自体が、コードが何をするのかを示すドキュメントの役割を果たす

# 良いテストとは
良いテストケースは、シンプルかつ明確で、特定の機能やユースケースに対して確実に結果を検証できるものです。良いテストの特徴は以下の通りです。

- 明確で正確な表現(冪等性): 誰でも理解できるようなシンプルで直感的な表現を使用する
- 包括的なカバレッジ(網羅性): 正常系・異常系、そして境界条件を含めたテストを作成し、要件や仕様の抜け漏れがない
- 再利用可能(汎用性): 使い回しが可能なテストケースを作成する
- 独立性を保つ(独立性): 他のテストケースに依存しない設計を行う

# テストケースの考え方
今まで、そもそもテストって何？について記載しましたが、ここからは本題であるテストケースについて記載します。

テストケースを作成する際には、以下の要素を考慮して作成することが重要です。

## (1) テストケースの基本構成
まず、効果的なテストケースを作成するためには以下の項目を明記します

- 目的: 何を検証するのか。テスト範囲を明確にする
- 前提条件: 実行前に必要な設定や状態
- テスト手順: 実行する具体的なステップ
- 期待結果: どのような結果を期待するか
- テストデータ: 使用するデータや入力値

## (2) どこまでテストすべきか
テスト範囲や優先度を設定し、必要なテストを実施することが重要です。

- 高優先度のテスト: ユーザーに大きな影響を与える機能、クリティカルな処理を優先
- 低優先度のテスト: 安定している外部ライブラリや小さな機能に対して低優先度のテストを実施

## (3) 正常系と異常系
- 正常系: ユーザーが期待する標準的な入力や動作に対するテストを行います。例えば、入力フォームに正しい値を入力した場合の動作を確認します
- 異常系: ユーザーが誤った値や範囲外の入力をした場合の動作を確認します。異常系のテストは、エラー処理が正しく行われるかを確認するために重要です

## (4) カバレッジを意識する
テストケースを作成する際には、条件網羅や分岐網羅を意識して、異常系やエッジケースも含めたテストケースを作成しましょう。例えば、数値入力であれば、最小値・最大値だけでなく、その前後の値も確認します。

## (5) 大きなケースから詳細なケースに向かって考える
大きなシナリオから細かいケースに分けていくと効率的です。まずは全体のフローを理解し、その後に詳細なケースを分けていきます。

## (6) チェックリスト
(1)~(5)を検討したら、テストを書き始める前にチェックリストを作成し、これを満たすケースを考える方法が有用です。

# まとめ
本記事ではテストケースの考え方について紹介しました。
みなさんのテストが少しでも意義のあるものになれば幸いです。

再度になりますが、ぜひこちらも併せてご覧ください。
- [テストが書きやすいコードを書く](https://qiita.com/kentosity/private/d8654dad4fbf216f6843)
- [良いテストとは？なぜテストをするのか？](https://qiita.com/generoKoki/private/7c06f3df54766528a32b)

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