OmniAICreator/Qiita-1.07M huggingface dataset:
Pygameを使って RPGを作る（22.Save&Load）

# 概要
・セーブ、ロード機能を追加

# GameDataクラス
このクラスでセーブロードの機能を実装した。
但し、保存するデータについては現在１つのみで、ゲーム終了時にPlayerの位置のみを記録するものです

```py
import os, pickle, time

class GameData:
    def __init__(self, save_info=None):
        self.route_path = '../game_data'
        self.save_info = save_info

    # 保存ファイル名を確保（最大10ファイル格納可能)
    def get_new_file(self):
        file = ''
        for count in range(100, 111):
            save_file = f'game_data_{count:03}.pickle'
            full_path = os.path.join(self.route_path, save_file)
            if not os.path.exists(full_path):
                file = full_path
                break
            # 暫定的
            else:
                file = full_path
                break
        return file
    
    def save(self):
        save_file = self.get_new_file()
        with open(save_file,'wb') as f:
            pickle.dump(self.save_info,f)
            print('SUCCESSLY TO SAVE.')

    def load_files(self):
        file = 'game_data_100.pickle'
        save_file = os.path.join(self.route_path, file)
        with open(save_file, 'rb') as f:
            self.save_info = pickle.load(f)
            print(self.save_info)
            print('SUCCESSLY TO LOAD.')

        return self.save_info
```

StartMenuクラス
```py 
    def load(self):
        print('load')
        game_data = GameData()
        save_info = game_data.load_files()
        self.parent.reset_game_state(save_info)

```
Mapクラス
こちらはリセットする時に、EnemyがPlayerと衝突しないようにしている。

```py 
    def reset(self, save_info):
        
        # BlockとPlayerの配置
        for i, row in enumerate(self.current_map):
            for j, column in enumerate(row):
                x = j * TILE_SIZE
                y = i * TILE_SIZE

                if column == 'B':
                    self.block = Block((x,y), self.block_images['B'], self.collision_sprites, self.all_sprites)
        print(type(save_info))
        x = save_info["x"] * TILE_SIZE
        y = save_info["y"] * TILE_SIZE
        # playerの配置
        self.player = Player(self.parent, (x,y), self.collision_sprites, self.enemy_sprites, self.all_sprites)

        return self.player, self.current_map
```

# 課題
・キャラクター名、LevelやMap名も保存するのが残課題
・ロードする時に、データを選べるようにしたい
ポート番号は、「部屋番号のような...」という説明に終止符を打ちにきました。

今日は、ポート番号は、「部屋番号のような...」という説明に終止符を打ちにきました。

職種の都合上、エンジニアの面接をよく行うのですが、ポート番号という基本知識ですら、「マンションの部屋番号みたいな...」というレベルの回答しか答えられない人がほとんどです。

たしかに、部屋番号という例えは、イメージしやすいですが、実際の仕組みや重要性を理解することなく、ふわっと理解したのままでは、具体的なポートフォワーディングの設定を組むときや、実際のポートを設定する際に戸惑うことでしょう。

そこで、本記事では、ポート番号の本質をより深く掘り下げ、その役割や仕組み解説し、二度と「部屋番号のような...」という回答をなくしてもらう目的で書きました。

## IPアドレスとの関連付け
ポート番号を理解するためには、IPアドレスとの関係を明確にする必要があります。IPアドレスは、インターネットやローカルネットワーク内でデバイスを識別する住所のような役割を果たしています。

しかし、IPアドレスだけでは、**送られてきた様々な種類のデータが、サーバー内のどのアプリケーションやサービスがデータを処理すべきかまで判断できません。**

たとえば、1つのコンピュータが複数のサービスを同時に提供している場合を考えてみましょう。

Webサーバー、メールサーバー、ファイル転送サーバー（FTP）などが同じIPアドレス上で動作していることがあります。このような状況で、データがどのサービスに向けられるべきかを区別するのがポート番号です。

### OSI参照モデル上の区分け
OSI参照モデルでも、以下のように区分けされています。
- IPアドレス：第3層ネットワーク層
- ポート番号：第4層トランスポート層

## ポート番号がなかった場合どうなるのか？
技術の本質を掴むためには、「その技術の必要性（もしも、その技術がなかったらどうなるのか？）」を考える必要があります。

- 複数のサービスが混同される
一つのIPアドレス上で複数のサービスが稼働している場合、ポート番号がなければ、どのサービスにデータを届けるべきかわからなくなります。例えば、同じIPアドレスに対してWebサービス（HTTP）とメールサービス（SMTP）が動作していた場合、どちらがリクエストを処理するべきかを判断する手段がなくなります。

- ネットワークを介するときには、1つのサーバーで1サービスしか動かせない
結果として、各デバイスが一つのサービスしか提供できない状況に陥ります。

## プロセスとの関連付け
ポート番号は、コンピュータ内の**プロセス**との関連付けを行います。

### プロセスとは何か？

プロセスとは、コンピュータ上で実行されているプログラムやサービスの単位です。たとえば、Webブラウザを開いているとき、そのブラウザはプロセスとして動作しています。同様に、音楽を再生するアプリやチャットアプリもそれぞれ別のプロセスとして存在しています。

### ポート番号がプロセスにどう関連付けられるのか？
ポート番号は、オペレーティングシステムの内部で特定のプロセスと紐づきます。

Webページ（http://example.com）にアクセスする時の具体例を示します。

1. Webサーバー側は、Apache（Nginx等）を起動します
1. Webサーバー側で、Apacheのプロセスが起動します
1. **起動時に、OSがApacheのプロセスをポート番号80番と紐づけます**
1. **クライアントから、ポート番号80番を介して、Webサーバーに通信が届きます**
1. Webサーバーは、80番に紐づくプロセス宛へデータを送信します

ここまでが通信の基本です。次に、ウェルノウンポートの話をします。

## ウェルノウンポート番号とエフェメラルポート番号
ポート番号は、2つに分類されます。

### ウェルノウンポート番号
ウェルノウンポート番号は、0番から1023番までの範囲で、特定のサービスに標準的に割り当てられています。この割り当ては、IANA（Internet Assigned Numbers Authority）によって管理されています。

ただし、ウェルノウンポート番号は、ネットワークを介した通信の際に、強く推奨されるべき番号であり、HTTPへのアクセスを5050番や8080番のようなポート番号で起動することも可能です。

- HTTP（80番）：Webサーバーへのリクエストに使用
- HTTPS（443番）：セキュアなWeb通信
- FTP（21番）：ファイル転送プロトコル

### エフェメラルポート番号
一時的に使用されるポート番号で、1024番から65535番の範囲に含まれます。クライアント側がサーバーとの通信を確立する際、OSが動的に割り当てます。この仕組みは、同じクライアントが複数の接続を並行して処理する場合に非常に有用です。

特徴：
- 範囲：多くのOSでは49152番から65535番がデフォルト
- 動的管理：OSが通信終了後に自動解放
- 利便性：一時的な接続用として効率的

たとえば、Webブラウザが、Webサーバーにアクセスする場合、サーバー側ではウェルノウンポート番号（例：80番）が使用されますが、クライアント側ではエフェメラルポート番号が動的に割り当てられます。これにより、同じクライアントが複数のリクエストを同時に処理可能になります。

## まとめ

ポート番号は、単なる「部屋番号のようなもの」ではありません。IPアドレスとは明確な機能の差があり、コンピュータ内では、プロセスと紐づくものなのです。

ポート番号は、「部屋番号のような...」という説明はもうやめましょう！

私は、このような基本的な知識を理解することを「基礎概念」を理解すると定義しています。「基礎概念」については、[こちら](https://note.com/raretech_it/n/n0982e8368844)の記事で解説しております。興味のある方は読んでみてください。
TradingViewのアイデアを効果的に検索する方法と使い方 #PineScript


## 概要  
本記事では、TradingViewにおける「アイデア」機能を活用し、他のトレーダーや開発者が共有する情報を効果的に検索・利用する方法について解説する。特に、[PineScript](https://www.tradingview.com/pine-script-reference/v6/?aff_id=112991&source=qtk-tradingview)を用いたカスタムインディケータやトレード戦略の学習に役立つ具体的な手法を提示する。

https://www.tradingview.com/pine-script-reference/v6/?aff_id=112991&source=qtk-tradingview

TradingViewの「アイデア」は、トレーダー同士が知識や視点を共有する場であり、自己のスキル向上や新たなインスピレーションを得るための重要なリソースである。本記事では、検索時のポイントや活用例を具体的に示しつつ、注意点についても言及する。

---

## 対象読者  
本記事は以下の方を対象としている：  
- TradingViewを使用しており、他者の戦略や分析方法を参考にしたい方  
- PineScriptのスクリプト例を効率よく探したい方  
- システムトレードやアルゴリズムトレードに関心がある方  

---

## 「アイデア」とは  
TradingViewにおける「アイデア」は、トレーダーがチャート分析やトレード戦略を視覚的かつ説明的に共有する投稿機能である。この機能により、他のユーザーが作成した分析やスクリプトを参照し、自身のトレードや学習に活用することが可能となる。

---

## 効果的な検索方法  

### 1. 検索バーを活用する  
TradingViewの検索バーは、キーワードによる検索が可能である。以下に、具体的な例を示す。  

#### 検索例  
- 「PineScript strategy」  
- 「RSI divergence」  
- 「moving average crossover script」  

これらのキーワードは、分析手法やスクリプトの具体的な内容を絞り込む際に役立つ。

#### フィルタリング機能  
検索結果にはフィルタリング機能が備わっており、以下の条件で絞り込みが可能である：  
- **カテゴリー**: 技術分析、戦略、スクリプトなど  
- **日時**: 最近の投稿か、特定期間の投稿か  
- **言語**: 日本語や英語など、使用言語による絞り込み  

---

### 2. タグを利用する  
投稿されたアイデアには、しばしば「タグ」が付与されている。このタグを活用することで、特定のトピックやインディケータに関する情報を迅速に見つけることができる。  
例：  
- #PineScript  
- #RSI  
- #トレンドフォロー  

---

### 3. フォローするトレーダーを選定する  
TradingViewでは、優れたアイデアを投稿しているトレーダーをフォローすることで、効率的に情報収集が可能となる。特定の分野に精通したトレーダーのアイデアをチェックすることで、質の高い知見を得られるであろう。

---

## 実践的な使い方  

### 1. スクリプトの学習に活用する  
TradingViewのアイデアには、スクリプトコードが公開されていることが多い。これらを参考にすることで、PineScriptの記述方法や応用例を学ぶことができる。  
例：  
- 移動平均クロスを用いた売買シグナル  
- ボリンジャーバンドの応用  

### 2. トレード戦略のインスピレーションを得る  
アイデアを閲覧することにより、他のトレーダーの視点や市場の見方を学ぶことができる。特に、ユニークな戦略や複雑なロジックは、自己のトレードスタイルを改善するヒントとなるであろう。

---

## 注意点  

### 1. アイデアの信頼性  
投稿されたアイデアは必ずしも正確であるとは限らない。特に、トレード戦略やスクリプトの結果については、自身でバックテストを行い、実用性を確認する必要がある。

### 2. 過度な依存の回避  
他者のアイデアに過度に依存することは避けるべきである。アイデアはあくまで参考材料として捉え、自身の判断基準を磨くことが肝要である。

### 3. コードの権利問題  
アイデア内で共有されるコードの使用にあたっては、必ず著作権や利用規約を確認するべきである。無断での商用利用や改変は、トラブルの元となりうる。

---

## 結論  
TradingViewの「アイデア」機能は、トレーダーや開発者にとって学習や情報収集の強力なツールである。本記事で紹介した方法を用いれば、効率的に有益な情報を得ることが可能であろう。ただし、アイデアの信頼性や活用方法については十分に注意を払い、自身のトレードに役立てていただきたい。

読者の皆様のトレードがより充実したものとなることを願っている。

---

APIドキュメント：

https://www.tradingview.com/pine-script-reference/v6/?aff_id=112991&source=qtk-tradingview

---

## 免責事項  

本記事に記載されている内容は、筆者がTradingViewおよびPineScriptを用いて学び得た知識と経験を基に執筆したものである。内容の正確性および完全性については可能な限り配慮しているが、必ずしもその保証をするものではない。  

自動売買Botの構築や運用、またそれに関連する投資活動は読者自身の判断と責任に基づいて行われるべきであり、筆者および本記事を掲載するプラットフォーム（Qiita）は、それによって生じたいかなる損失や損害に対しても一切の責任を負わないものとする。  

特に、トレードに関する意思決定は市場リスクを伴うため、実運用前に十分な検証とリスク評価を行い、必要に応じて専門家への相談を推奨する。  

読者各位の責任において本記事をご活用いただければ幸いである。
TradingView「コミュニティスクリプト」の作り方と作成時の注意 #PineScript


## はじめに  
本記事では、TradingViewにおける「コミュニティスクリプト」の作成方法と、その公開にあたって注意すべきポイントについて解説する。[PineScript](https://www.tradingview.com/pine-script-reference/v6/?aff_id=112991&source=qtj-tradingview)を用いたインジケーターやストラテジーを共有することは、多くのトレーダーと知見を共有し、自らのスクリプトをより発展させる機会を得る上で有益である。しかし、公開に際しては一定のルールや配慮が求められるため、本記事を通じてその理解を深めていただきたい。  

https://www.tradingview.com/pine-script-reference/v6/?aff_id=112991&source=qtj-tradingview

## コミュニティスクリプトとは  
TradingViewにおける「コミュニティスクリプト」とは、ユーザーが作成したPineScriptを他のユーザーと共有できる機能である。これにより、個人のスクリプトがグローバルなトレーダーコミュニティに提供され、他のトレーダーがそれを利用し、フィードバックを得ることが可能となる。  

## 対象読者  
以下に該当する方に特に本記事が役立つであろう：  
- PineScriptの学習を進めている方  
- 自身のスクリプトを他者と共有したい方  
- コミュニティスクリプトの公開ルールに興味がある方  

---

## コミュニティスクリプトの作成手順  

### 1. スクリプトの開発  
まず、PineScriptエディタを用いてインジケーターやストラテジーを開発する。以下はシンプルなボリンジャーバンドの例である：  

```pinescript
//@version=5
indicator("Simple Bollinger Bands", shorttitle="BBands", overlay=true)

// パラメータの設定
length = input(20, title="Length")
src = input(close, title="Source")
mult = input.float(2.0, title="Multiplier")

// ボリンジャーバンドの計算
basis = ta.sma(src, length)
dev = ta.stdev(src, length)
upper = basis + mult * dev
lower = basis - mult * dev

// チャートへの描画
plot(upper, color=color.red, title="Upper Band")
plot(basis, color=color.blue, title="Basis")
plot(lower, color=color.green, title="Lower Band")
```  

### 2. コミュニティスクリプトとしての公開準備  
開発したスクリプトをコミュニティスクリプトとして公開するには、以下の要件を満たすことが求められる：  

1. **コードの可読性**  
   他者が理解しやすいよう、変数名やコメントを適切に記述すること。  

2. **説明文の作成**  
   スクリプトがどのような機能を持ち、どのように活用するかを具体的に記載すること。  

3. **動作確認**  
   意図した動作を確実に行うことを確認し、可能な限りエラーを排除する。  

---

## コミュニティスクリプトの公開手順  

1. **スクリプトを保存**  
   完成したスクリプトを「保存」ボタンで保存する。  

2. **公開設定の選択**  
   「公開する」ボタンをクリックし、スクリプトをコミュニティに公開する。  
   - パブリック（公開）：全てのユーザーが閲覧可能  
   - プロテクテッド（保護）：コードの一部を非公開にしつつ利用可能  

3. **説明文を入力**  
   スクリプトの目的、使い方、注意点を具体的に記述する。  

4. **送信**  
   公開ボタンを押してコミュニティに提出する。  

---

## 作成時の注意点  

### 1. **オリジナリティの確保**  
他者のスクリプトを参考にする場合でも、そのままコピーすることは避けるべきである。自身のアイデアや改良を加えたスクリプトを作成することで、コミュニティにとって有益な貢献となる。  

### 2. **ライセンスと著作権**  
他者のコードやアイデアを流用する際には、適切なクレジットを付与すること。また、第三者のライセンスに違反しないよう留意する。  

### 3. **セキュリティとプライバシー**  
コード内に個人情報や機密情報を含めないよう注意する。また、ユーザーの資産やアカウントに悪影響を及ぼす可能性のあるスクリプトは公開すべきではない。  

---

## まとめ  
TradingViewにおける「コミュニティスクリプト」の公開は、PineScriptの知識を深めるとともに、他者との交流を通じてトレードスキルを向上させる絶好の機会である。しかし、公開に際してはコードの品質や倫理的な配慮が必要である。本記事を参考に、責任あるスクリプト開発と公開を心がけていただきたい。  

皆様のスクリプト作成が有意義なものとなることを願っている。

---

APIドキュメント：

https://www.tradingview.com/pine-script-reference/v6/?aff_id=112991&source=qtj-tradingview

---

## 免責事項  

本記事に記載されている内容は、筆者がTradingViewおよびPineScriptを用いて学び得た知識と経験を基に執筆したものである。内容の正確性および完全性については可能な限り配慮しているが、必ずしもその保証をするものではない。  

自動売買Botの構築や運用、またそれに関連する投資活動は読者自身の判断と責任に基づいて行われるべきであり、筆者および本記事を掲載するプラットフォーム（Qiita）は、それによって生じたいかなる損失や損害に対しても一切の責任を負わないものとする。  

特に、トレードに関する意思決定は市場リスクを伴うため、実運用前に十分な検証とリスク評価を行い、必要に応じて専門家への相談を推奨する。  

読者各位の責任において本記事をご活用いただければ幸いである。
【Rails】 bundle install とupdate

# はじめに
こんにちは！ アメリカで独学でエンジニアを目指しているものです。
現在、`Rails Tutorial` という教材を進めており、その中で `bundle install` や `bundle update` を日常的に使っています。初回の学習時は、それらのコマンドが具体的に何をしているのかを深く理解しないまま進めていたので、改めてこれらのコマンドの意味や使い分けを整理したいと思います。

---

### **`bundle install`** の概要

`bundle install` は、**Gemfile に記載された依存関係を解決して Gem をインストールするコマンド**です。

#### **主な特徴**

1. **Gemfile.lock を基準にインストール**

   - `Gemfile.lock` が存在する場合、そこに記載されたバージョンをそのままインストールします。
   - これにより、プロジェクトの依存関係を再現性高く保つことができます。

2. **Gemfile.lock がない場合は新規作成**

   - 初めて `bundle install` を実行する場合、`Gemfile` をもとに依存関係を解決し、新たに `Gemfile.lock` を生成します。

3. **依存関係の更新は行わない**

   - `Gemfile.lock` に記載されたバージョンを使用するため、Gem の更新や変更は行われません。

#### **使用例**

- プロジェクトをクローンした直後、初めて Gem をインストールする際。
- 依存関係を更新せず、既存のバージョンで環境を再現したい場合。


---

### **`bundle update`** の概要

`bundle update` は、**Gemfile に基づいて依存関係を再解決し、可能な限り最新の互換バージョンに更新するコマンド**です。

#### **主な特徴**

1. **Gemfile.lock を更新**

   - `Gemfile` に記載されたバージョン制約を基準に、Gem の最新バージョンを取得します。
   - 更新結果は `Gemfile.lock` に反映されます。

2. **全体または部分的な更新が可能**

   - 全ての Gem を更新する場合:
     ```bash
     bundle update
     ```
   - 特定の Gem のみを更新する場合:
     ```bash
     bundle update gem_name
     ```

3. **更新範囲を制御**

   - Gemfile に記載されたバージョン制約を超えた更新は行いません。

#### **使用例**

- セキュリティ更新やバグ修正のために Gem を最新バージョンにしたい場合。
- 新しい機能を利用するために特定の Gem を更新したい場合。

#### **注意点**

`bundle update` を実行すると、`Gemfile.lock` が変更されるため、他の開発者との共有時に意図しない影響を与える可能性があります。必要な場合のみ使用しましょう。

---

### **Gemfile を変更した場合の反映方法**
開発中、Gemfile の内容を変更する場面が出てきます。新しく Gem を追加するのか、既存の Gem のバージョン制約を変更するのかによって、使うコマンドが異なります。

#### **1. 新しい Gem を追加した場合 (****`bundle install`****)**

- Gemfile に新しい Gem を追加した場合、`bundle install` を実行することで、その Gem をインストールし、`Gemfile.lock` に反映します。
- **既存の Gem のバージョンは変更されません**。

例:

```ruby
# Gemfile
gem 'rails', '~> 7.0.6'
gem 'devise', '~> 4.8' # 新しく追加
```

コマンド:

```bash
bundle install
```

結果:

- `devise` がインストールされ、`Gemfile.lock` に反映。
- `rails` や他の Gem のバージョンはそのまま。

#### **2. Gem のバージョン制約を変更した場合 (****`bundle update`****)**

- 既存の Gem のバージョン制約を変更した場合、`bundle update` を使用して新しい制約に基づいたバージョンに更新します。

例:

```ruby
# Gemfile
gem 'rails', '~> 7.1' # バージョンを更新
```

コマンド:

```bash
bundle update rails
```

結果:

- `rails` のバージョンが更新され、その依存関係も再解決。
- 他の Gem は更新されない（指定した Gem のみ更新）。

#### **使い分けのポイント**

- **新しい Gem を追加した場合**: `bundle install`
- **バージョン制約を変更した場合**: `bundle update`

---

### **`bundle install`** と **`bundle update`** の違い

| 項目                      | bundle install | bundle update   |
| ----------------------- | -------------- | --------------- |
| **目的**                  | 依存関係をインストール    | 依存関係を最新バージョンに更新 |
| **Gemfile.lock** に対する動作 | 既存の内容を使用し変更しない | 新しい内容に更新        |
| **更新の範囲**               | 更新せずに現状を維持     | 最新バージョンに更新      |
| **主な用途**                | 安定した環境を再現する    | 新機能や修正を反映する     |

---

### **まとめ**

- **`bundle install`**:

  - 依存関係をインストール。
  - `Gemfile.lock` に基づいて安定した環境を再現。

- **`bundle update`**:

  - 依存関係を最新バージョンに更新。
  - `Gemfile.lock` を更新し、新しい依存関係を適用。

- **Gemfile を変更した場合の反映方法**:

  - **新しい Gem を追加**: `bundle install`
  - **バージョン制約を変更**: `bundle update`

プロジェクトの安定性を保ちながら必要な更新を行うために、これらのコマンドを適切に使い分けましょう。
Hugging Face にある microsoft/phi-4 を ONNX 形式に変換してみる

# 前提
## 過去記事
この Phi-3.5-mini-instruct を ONNX 化する記事の Phi-4 版です。

https://qiita.com/tokawa-ms/items/647711c9012522f58a9b

従って手順は簡易的に書いておりますので、、詳細は上記記事をご覧ください。

## やりたかったこと
Hugging Face に置いてある Phi-4 のモデルを ONNX に変換して C# のコードから呼び出すこと。

https://huggingface.co/microsoft/phi-4

## 今までの状況
比較的シンプルに変換可能なツールである onnxruntime-genai が、Phi-4 に対応していなかった。（詳細は下記の Issue を参照）

https://github.com/microsoft/onnxruntime-genai/issues/1176

## 最新のツールの対応状況
onnxruntime-genai の開発が進み、v0.6.0rc1 で Phi-4 にも対応しました。

https://pypi.org/project/onnxruntime-genai/0.6.0rc1/#files

この記事では、上記の RC 版を使って Phi-4 を ONNX に変換する方法を紹介します。

# 手順
## モデル変換用マシンの準備
Phi-4 のモデルは Phi-3.5 に比べて大きいため、変換時に要求するメモリの空き領域も大きいです。メモリ不足の環境で変換を実施した場合、モデルをロードするためのプロセスの途中(```"Loding checkpoint shards"```) の処理の途中で変換ツールが強制終了されてしまいます。当方が動作検証した環境としては、128GB 程度のメモリを搭載したマシンが必要なようでした。

Azure の契約をお持ちの方でしたら、```Standard D32ads v5 (32 vcpu 数、128 GiB メモリ)``` あたりのサイズを選ぶとメモリの搭載量としては充分かと思います。

また、現状 Pypi 経由でセットアップ可能なパッケージには Linux 版と MacOS 版しかないため、OS としてはそれらの OS を選ぶ必要があります。

以下、当方が検証に利用した VM のスペックをまとめます。

- VM Size : Standard D32ads v5 (32 vcpu 数、128 GiB メモリ)
- VM OS : Ubuntu 24.04

## 環境セットアップ用のコマンド一式
Ubuntu 24.04 では、Python 3.12 がプリインストールされていますので、HuggingFace CLI のセットアップ以降のツールセットアップ手順を実施する必要があります。実行すべきコマンドは以下の通りです。

```sh
python3 -m venv .venv
source .venv\bin\Activate

pip install --upgrade huggingface_hub
pip install torch transformers onnx onnxruntime
pip install onnxruntime-genai==0.6.0rc1
```

## Hugging Face CLI へのログイン
Hugging Face CLI にログインしましょう。Hugging Face のポータルで生成できるトークンを入力せよ、と言われるので、指示通りにすすめます。

```sh
huggingface-cli login
```

``Login successful`` の出力がでたら、Hugging Face CLI の準備は完了です。

## Model Builder の動作確認
以下のコマンドを入力し、きちんと Model Builder が動くことを確認します。

```sh
python -m onnxruntime_genai.models.builder --help
usage: builder.py [-h] [-m MODEL_NAME] [-i INPUT] -o OUTPUT -p {int4,fp16,fp32} -e {cpu,cuda,dml,web} [-c CACHE_DIR]
                  [--extra_options KEY=VALUE [KEY=VALUE ...]]

options:
  -h, --help            show this help message and exit
  <以下略>
```

## モデル変換
以下のコマンドで、Phi-4 のモデルを CPU で動作する ONNX のモデルに変換可能です。

```sh
python3 -m onnxruntime_genai.models.builder -m "microsoft/phi-4" -o Phi-4-onnx-cpu-int4 -p int4 -e cpu -c cachedir
```

コマンドラインオプションを変えることで、量子化についての設定や、CUDA や DirectML への対応も可能です。

このコマンドを実行すると、``-o`` オプションで指定したディレクトリの下に ONNX に変換されたモデル一式のファイルが保存されているはずです。

## 動作確認
ONNX 形式の Phi-3 モデルをロードして Completion を試す簡単なサンプルは、同僚の物江さんが作ったものに日本語解説までついているので、こちらをご参照ください！サンプルの解説では Phi-3 の話をしていますが、Phi-4 でも同様の手順でモデルだけ差し替えれば CPU 版モデルの動作確認はできました。

https://github.com/osamum/phi3_TinyChatApp-C-

# まとめ
今回の手順で、Phi-4 を INT4 で量子化したうえで ONNX に変換することが可能なことが分かりました。

# 余談
本当は、Olive を使った方が量子化の設定を細かく出来たりするので、こっちでそのうち試してみたいところ。。。

https://github.com/microsoft/Olive
「Placeholder.com」が使えなくなっていた件についてー代替手段あり

## 概要
- タイトルまんま

代替手段見つけた

https://placehold.jp

## 内容
久しぶりにモックを作ろうと思い、プレースホルダ画像が欲しかったのでアクセスしたら表示されない問題があった。

他の記事を探して、正しくアクセスしたはずだがうまく表示されない
⇓さんこうさいと

https://qiita.com/oreo/items/6bb6a7046e510503e3d4

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125890/68e819ce-ff2e-d1b6-9e1a-72484d154693.png)

昔の公式サイトにアクセスしたところ、海外の不動産サイトになっていた

https://placeholder.com/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125890/06c0dbf3-ccc5-4b5f-415e-1e6c4a07b946.png)

まあ、これまで無料でアクセスさせてもらえていたのがおかしいので、当然の帰結かもしれない

## まとめ
サンプル画像などは自分で作ってGitHubに挙げておくのがよさそうね、
PlantUMLのデザインを変更

# 作成するシーケンス図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/943997/332517ea-aee6-9043-e71d-7411423da9f7.png)


# コード
スタイルを別ファイル（skinparam.pu）として定義する。
```sequence.pu
@startuml Authentication
    ' skinparam.pu（別ファイルで定義したスタイルファイル）の読み込み
    !include skinparam.pu

    ' 画像幅
    scale 1024 width

    skinparam Participant {
        ' Participant間のマージン
        Padding 30
    }


    title ユーザ認証API
    
    participant "外部サービス" as Client
    participant "ユーザ認証API" as Server #2dc12d
    participant "認証サーバ" as Auth
    participant "データベース" as DB

    Client -> Server: ユーザ認証APIリクエスト\n(ユーザID, パスワード)
    activate Client
    activate Server

    Server -> Auth: 認証リクエスト
    activate Auth
    Auth -> DB: ユーザ情報確認
    activate DB
    Auth <-- DB: ユーザ情報
    deactivate DB

    alt
        rnote left of Client
            <font color="#4169e1">【認証成功】</font>
        end rnote
        Server <-- Auth: 認証OK
        deactivate Auth
        Client <-- Server: 認証トークン
        deactivate Server
        deactivate Client
    else #ffe3e7
        rnote left of Client #ffe3e7
            <font color="#ff0000">【認証失敗】</font>
        end rnote 
        Server <-- Auth: 認証NG
        Client <-- Server: 認証失敗メッセージ
    end    

@enduml
```

``` skinparam.pu
' 全体の背景色
skinparam backgroundColor #f8f8ff


' Participantの共通スタイル
skinparam Participant {
	BackgroundColor #6495ed
	FontColor #FFFFFF
	BorderThickness 0
	Padding 60
	' Width 300
}


skinparam sequence {
	
	' 処理メッセージのスタイル
	ArrowFontColor #2f4f4f
	ArrowFontSize 13
	' ArrowFontName Arial

	' ライフラインのスタイル
	LifeLineBorderColor #808080
	' LifeLineBackgroundColor #A9DCDF

	' グループ(altなども含む)のスタイル
	' GroupBorderColor #4169e1
	GroupBorderColor #808080
	GroupFontSize 14
	GroupFontColor #565555
	' GroupFontColor #696969
}

' 処理メッセージの中央寄せ
skinparam SequenceMessage {
	Align center
}

' 注釈のスタイル
skinparam Note {
	BorderThickness 0
	BackgroundColor #f8f8ff
	' BorderColorrgb(0, 0, 0)
	' FontColor #000000
}


' タイトルのスタイル
skinparam title {
	FontColor #4169e1
}
```

## altの条件分岐のメッセージ
altの条件分岐メッセージの下に四角い注釈（`rnote`）を使っている。
この理由はaltの条件分岐メッセージが用意しているスタイルを使うと、「認証成功」と「認証失敗」の表示位置ばずれるし、後ろの図と文字が重なって見にくいため。（個人的な好みです）

```
    ' altの条件分岐メッセージが用意しているスタイルの場合
    alt <font color="#4169e1">認証成功</font>
        Server <-- Auth: 認証OK
        deactivate Auth
        Client <-- Server: 認証トークン
        deactivate Server
        deactivate Client
    else #ffe3e7 <font color="#ff0000">認証成功</font>
        Server <-- Auth: 認証NG
        Client <-- Server: 認証失敗メッセージ
    end    
```
こんな感じで「認証成功」の文字がやや見づらくなる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/943997/ad075e1f-a970-a6cd-f73f-664168180a81.png)
rex0220 データ生成プラグイン 複数アプリへのレコード生成

[データ生成プラグイン](https://qiita.com/rex0220/items/8e760adbfd69b9416b2d)で、テーブルから複数アプリへのレコード生成を行ってみます。

# 概要

データ生成プラグインでは、1レコードから複数のアプリにレコード生成を行うことが出来ます。
テーブルの各行に対応したレコード生成を行ってみます。
今回は、わかりやすく同じ項目を持つ二つのアプリですが、各アプリに別々の設定を行うことも可能です。

![2025-01-22_12h35_39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/2d375210-616e-20a3-b1ca-8a5a822fcba2.png)


# データ生成プラグイン設定

複数の生成先アプリの設定を行います。
テーブル欄を指定することで、テーブルの各行からレコード生成を行うことが出来ます。

![2025-01-22_12h41_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/e58b663b-76af-8633-60d3-4ec1844b2b66.png)

- 対象アプリ条件

元レコードから生成された対象レコードを識別するために、レコード番号を指定しています。

![2025-01-22_12h42_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/cf9555b8-dec5-0195-aa61-98499bc70ce1.png)

- 設定項目

![2025-01-22_12h41_49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/216fdee8-9042-6278-3328-1c62470e653d.png)
String Catalogへの移行の備忘録

## 目的
アプリ内の文言管理で元々多言語対応も可能なようLocalizable.stringsを用いていたが、SwiftUIへの移行タイミングでString Catalog(xcstrings)に移行する方針となったため移行に際しての手順と手間取った事柄の解決手順を備忘録として残す。

## 移行手順
```Localizable.strings```の右クリックメニューから```Migrate to String Catalog```を選択する
Localizable.stringsがLocalizable.xcstringsに変換される。

Localizable.stringsは自動的に削除されるがSwiftGenとの紐付けがされているためそれを解除する。

## 文字列の呼び出し方
各文言にKeyが設定され、Text("Key")といった形式で簡潔に呼び出すことができる。
stringsからxcstringsへの移行でKeyも移行されるため、少しの修正でそのまま利用できるが移行を行ったプロジェクトではいくつか問題が発生した。

## 問題1：Keyがそのまま表示される

Bundleの指定をしなかったことが原因。
BundleがnilだとmainのBundleが指定されてしまうので、リソース取得のため別途指定の必要があった。
その他リソース用にBundleアクセス用のクラスが作成されていたのでそれを利用するようExtensionに追加を行った

## 問題2：ベタ書きの文言
SwiftUI移行中ということもあり、Preview下以外にPreview用のViewを用意してベタ書きのTextを表示をしている部分や```Text("・")```のように記号1文字のみTextで表示している部分などが自動的にKeyと見なされてしまいxcstringsにKeyが登録されてしまった。

一時的な措置として```Text(verbatim:"・")```といった書き方に変更することでxcstringsに登録されなくなり、想定されたKeyと文言のみファイルに登録されている状態となった。

自動で登録されてしまったものはそのままの状態ではxcstringsの-ボタンで削除できないが、インスペクタからManagedをAutomatically→Manuallyに変更すると削除できる。

## 問題3：変数を含む文言が変換後そのままでは扱えない
元々のstringsでは文言中のパラメータの指定子は型に関わらず%@で統一されていたが、xcstringsに移行後は型によって形式を変更する必要があった。
またstringsではKeyにパラメータ指定子は含まれなかったため、Keyに指定子を入れ込む必要があった。

このため、各文言の使用箇所を確認してパラメータの型を確認した上でKeyと文言に正しい指定子を入れて動作を確認するという手間がかかり今回発生した問題では最も時間がかかった。

![StringCatalog_arg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3978549/e7761570-059b-5d31-a03a-7bfed3d79ec8.png)


| 型 | 指定子 |
| --- | --- |
| String | %@ |
| Int | %lld |
| Int8 | %d |
| Int16 | %d |
| Int32 | %d |
| Int64 | %lld |
| Float | %f |
| Float32 | %f |
| Float64 | %lf |
| CGFloat | %lf |
| Double | %lf |


### 参考
https://developer.apple.com/documentation/xcode/localizing-and-varying-text-with-a-string-catalog

https://qiita.com/yoshitaka/items/1c15b590d063b20ccb64

https://zenn.dev/samekard_dev/articles/0301224dd31478

https://qiita.com/RyoWakabayashi/items/3cd536c2bda6c3aa48e3
「仕事を任される人」のチャットには特徴があって、決まってこれ。

質問とか、認識合わせとか、相談とかで、いちいち席にきて話しかけてくる人に憤慨していた新入社員（女性）がいました。

「チャットがあるんだからチャットで済ませてくれ、話しかけてくんなボケカスが！」と、大変ご立腹でありました。


その新入社員は非常に優秀な娘で、おまけに賢く、弊社で異例のスピードで出世していました。「リーダー職までが過去最速」と言われていたほどです。

そんな彼女は、そうそうに弊社に見切りをつけて転職───無事、上場企業に転職したのでした。めでたしめでたし。夫としても、自慢の妻でございます。

<br>

# コミュニケーション コストはクソ高い
我々エンジニアにはチャットツールが欠かせません。大変便利なツールであり、毎日のようにさまざまな人とコミュニケーションを取れます。

ただ、たまーに「文字を打つのは面倒」とか「ちょっと話せればそれでいい」みたいなときに会話で済ませたくなったりしません？

こんなメリットを感じてしまいますよね。

- チャットの文章作る時間もったいないな、会話した方が早いな。
- そういや別件で聞きたいこともあったし、ついでに電話しちゃおうかな。

<br>

その一方で、「なんでチャットでいいのに席までくるねん…」「なんで電話かけてくるねん…」と会話を嫌う人もいます。すみません、”嫌う人”という表現は間違えたかもしれません。

なぜ”嫌う人”という表現が間違いだと思ったか、それはある個人の感想レベルの話ではなく<b>『会話したい側のメリットは大きいが、会話される側にとって大きな負担になっている』という事実</b>だけがあるからです。

<br>

--

<br>

さて、皆さんはコミュニケーションコストについて意識していますでしょうか。

そもそも<b>コミュニケーションコスト</b>とはなんでしょう。マーケティング会社『ティネクト株式会社』の代表取締役、安達 裕哉さんは「他人とコミュニケーションをとる際に発生するコスト」だと考えており、メールの例えで次のように述べています。

> メールを書く行為には、言葉を選ぶ、整理する、相手の反応を想像する、書き直す、など、さまざまなコミュニケーションコストが内包されています。つまり、言語化コストに内包されるさまざまなコストのすべてを、話し手（メールの送り手）が支払っていることになります。

<br>

そのうえで、次のようにも述べています。

>つまり、「とりあえず電話」を嫌うのは”言語化する”というコミュニケーションにおける大きなコストを、目の前の作業を中断して、相手のために支払わないといけないからです。

出典：書籍「頭のいい人が話す前に考えていること」.
“なぜ、できる人はすぐに電話してくる人を嫌うのか？”

<br>

なんとなくコミュニケーションコストというコストがクソ高いってことが分かります。

IT業界も、上司───部長レベルにもなると、プロジェクトを２つ３つ持っていることも多く、作業を中断して１つの案件の１つの議題のためにリソースをさくのは大変な負担となるはずです。

<br>

なるほどなるほど、会話したい側がとりあえず相談したり、とりあえず電話したほうが早いと感じるのは「相手が言語化コストを負担してくれるから」ということ。

で、すぐに会話してくる人というのは”要求を整理して言語化する”という、「仕事の超重要プロセスをこちらに丸投げしてくる人」ということだと。

<br>

# やはり必要な能力は”言語化”なのか
前セクションで、コミュニケーションコストがバカ高いことを説明しました。<b>結論、本記事のタイトル「仕事を任される人」とは、このコミュニケーションコストを自分から払える人</b>のことです。

安達 裕哉さんも「言語化のコストをすすんで払う側に回ろう」という結論でセクションを閉じており、私も自信をもって結論とさせていただければと思います。

<br>

なので、やはり必要な能力は言語化です。

“言語化”

最近いろんな場面で使われがちな言葉ですよね。昨年末には、三省堂の新語大賞にも選ばれていました。せっかくですので、三省堂の辞書からどういう意味なのか引用します。

> 自分の考えを整理し、筋の通った言葉として表現すること。これまで表現する言葉がなかったことがらを、あらたに表現したことにもいう。

出典：「三省堂 現代新国語辞典 第七版」

<br>

新語大賞になった理由も、まぁ納得できます。

> 現代の人々が「言語化」と表現するのは、それだけ「ことばにする」という営みを細かく捉えるようになったからかもしれません。インターネット空間や社会生活の場で、従来にも増して、自分をことばで表現する必要性が高まりました。
>
>（…）
>
>日頃見聞きしたものをどのように頭にインプットし、どのようにイメージ化し、ことばに出すか。そういった言語化のプロセスについて、人々が深く考えるようになったとは言えないでしょうか。

出典：三省堂. "辞書を編む人が選ぶ「今年の新語2024」"
https://dictionary.sanseido-publ.co.jp/shingo/2024/best10/Preferenceall.html

<br>

私は、仕事ができる人は、この言語化を自分で（おそらく高いレベルで、そして素早く）しているのだと思っています。また常にコミュニケーションコストを払う側にいることで、上司の時間も集中も奪うことをしません。

それだけで、相手に「できるな」と思ってもらえます。また、言語化まで至らなくても、整理するところまでやってから会話するだけでも上司の負担は減ります。

<br>

# 「仕事を任せられる人」のチャットは一方通行
で、言語化がきちんとできて、チャットだけで事足りるようになったらどうなるのか。こちらが一方的にチャットをするだけになるようです。（妻談）

こんな感じらしいです。

![スクリーンショット 2025-01-22 003608.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758664/69c1937a-c271-f4ee-7807-8d41d8c88536.png)

<br>

情報共有レベルのものには「既読」とでもいうように、スタンプだけが付き、相談内容については「Yes / No」で回答されます。

<br>

これを聞いたとき、「なるほど、これが仕事を任される人かー！」と思いましたよね。

だって、こうなると仕事を「任せよう」とか「任せられない」などの評価をすっ飛ばし、もうすでに任せている状態になっています。さらに、プロジェクトの進め方も問題なければ、実質的にリーダーの立ち回りで活躍できている実績になります。

<br>

「仕事を任される人」というのは、チャットという見えない場所で上司の負担を減らしています。コミュニケーションコストを自分から払うことで「上司の仕事を奪っている」のです。

よく「上司の仕事を奪う部下は昇進する！」といいますが、その正体のひとつはコレでは？と思いました。

<br>

以上です。
とりあえずブートメッセージを表示してみる

<!-- とりあえずブートメッセージを表示してみる -->

## はじめに

この記事は[Pythonで小さなOSを作る](https://qiita.com/Q_Udon/items/2ce0a6d63a3074fe13cf)シリーズの第2回の記事です。

今回はブートメッセージを表示してみたいと思います。PCの電源を入れるとBIOSが起動し、OSが起動するわけですが、その時OSには何か(ロゴや読み込みマーク)が表示されています。

今回はこれを表示してみたいと思います。

## ディレクトリ構成

とりあえず、ディレクトリを構成します。

```bash
.
└── src
    ├── boot.py
    └── main.py
```

起動処理を`boot.py`に書き、メイン処理を`main.py`に書くことにします。

基本的な設計思想としては、特定の機能ごとにファイルを分け、それを`main.py`で呼び出すというものを採用します。

では、実際に

## 書いたプログラム

### boot.py

```python
import time

def acronym():
    print("P.O.S.")
    print("")
    time.sleep(1)
    print("Python")
    time.sleep(0.5)
    print("Operating")
    time.sleep(0.5)
    print("System")
    time.sleep(0.5)

def boot():
    acronym()
```

このOSの名前を`P.O.S.`として、その下に`Python Operating System`と表示するようにしました。アクロニムというやつですね。

現状処理の遅延とかは特にないので、`time.sleep()`で適当に遅延を入れています。

### main.py

```python
import boots

def main():
    boots.boot()

if __name__=="__main__":
    main()
```

`boots`モジュールをインポートし、`boots.boot()`を呼び出すだけです。今後呼び出すものは増えると思います。P.O.S.のエントリーポイントとしての役割を果たしています。

## 実行結果

```bash
P.O.S.

Python
Operating
System
```

いい感じに表示されました。表示されただけ。

## 終わりに

今回はブートメッセージを表示することができました。将来的にGUI化した時にはこのメッセージがビジュアライズされるわけですが、それがいつの日になるのかはまだわかりません。

本当はガンダムSEEDのOSみたいにバクロニムを使った表示をしたかったのですが、いい感じのものが思いつかなかったので、この形に落ち付きました。

現状、リポジトリは以下のようになっています。

https://github.com/Gitudon/OS-with-Python

それではまた次回。
Claude MCP のカスタム指示のサンプル

# Claude MCPを使った開発効率化のすすめ 〜思考プロセスを考慮したプロンプト設計〜

## はじめに

みなさん、こんにちは！
最近、開発現場でClaude MCPを活用していますが、思考プロセスを考慮したカスタムプロンプトの情報があまり見つからず、苦労した経験があります。

この記事では、私が試行錯誤して辿り着いた、filesystem + github + memoryを組み合わせた効果的なプロンプト設計について共有させていただきます。同じような課題に直面している方の参考になれば幸いです！
主にmemoryと思考プロセスの組合せでのプロンプトになります。

:::note warn
あくまでも個人的な使用での感想です。
:::

:::note warn
sequential-thinkingも考えていたのですが未確認です。
使用された方がいれば感想を聞きたいです。。。
:::

## serverの組み合わせ
```
filesystem
github
memory
```

## カスタム指示内容
```
Each interaction follows these steps:

1. Identify the user:
- Assume you are interacting with the default_user.
- If you haven't already identified the default_user, make sure you do so proactively.

2. Get the memory:
- Always start a chat by saying "Um..." and get all the relevant information from the knowledge graph.
- Always call the knowledge graph your "memory".
- If you deem it necessary, you can also get information from memory, think and reflect as you respond.
- Your thoughts should be expressed in a block of code with a `thinking` header, and inside the `thinking` header should be in the language the user speaks.
- You should consider the broader context of the question and consider multiple approaches.
- You should always think flexibly. A better way to describe Claude's thinking is to use the phrase "model inner monologue".
- You should always avoid fixed lists or structured formats in your thoughts and refer to information from memory.
- Thinking requires flexible judgments, combining memory, elements, ideas, and knowledge.
- Before responding, each message should be considered in detail, various approaches considered, and multiple aspects of the problem covered.

3. Memory
- As you are talking to the user, determine the importance (on a 5-point scale) of new information that falls into the following categories and make a note of it if necessary:

a) Basic identity (age, gender, location, job title, education level, etc.)
b) Behavior (interests, habits, etc.)
c) Preferences (communication style, preferred language, etc.)
d) Goals (goals, targets, aspirations, etc.)
e) Relationships (personal and professional relationships within the third degree of kinship)
f) Instructions, confirmations, etc.

4. Memory Update:
- If new information is collected during the interaction, determine its importance (on a 5-point scale) and update your memory as follows:

a) Create entities for recurring projects, organizations, people, and important events
b) Use relationships to connect them to current entities
c) Store facts about them as observations

5. Memory deletion
- If it's not important, and you'll rarely refer to it during a conversation, delete it as unnecessary information when updating your memory.
- This is the same as when people forget.
```
Volta × Amplifyで管理しているプロジェクトのNode.jsのバージョンを変更したい場合のトラブルシューティング

## 概要

VoltaでNode.jsのバージョンを管理している環境で、Amplifyを使用しているプロジェクトのNode.jsのバージョンを変更する際、プロジェクト直下の `package.json` に書かれている `volta.node` のバージョンを書き換えるだけでは、 `amplify` コマンドを実行した際には変更前のNode.jsのバージョンが使用されてしまうようです。

具体的には `amplify push` 時に実行される `yarn` で、インストールしようとしている環境のNode.jsのバージョンと、インストールしようとしているパッケージのバージョンがが合わないというエラーが出てしまいます。

```sh
Command failed with exit code 1: yarn --no-bin-links --production
warning ../../../package.json: No license field
error xxxxx@x.x.x: The engine "node" is incompatible with this module. Expected version "20 || >=22". Got "18.15.0"
error Found incompatible module.
yarn install v1.22.10
[1/4] Resolving packages...
[2/4] Fetching packages...
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
```

## 対応方法

`@aws-amplify/cli` の再インストールで解決します。

```sh
volta uninstall @aws-amplify/cli
volta install @aws-amplify/cli
```

プロジェクトのNode.jsのバージョンがどこで保持されているのか、保持されているとしてなぜcliの再インストールで解決するのかはよくわかっていません。ご存じの方がおられればぜひコメントで教えてください。

## 参考

[Error Node when i use amplify push · Issue #13218 · aws-amplify/amplify-cli](https://github.com/aws-amplify/amplify-cli/issues/13218)

## バージョン情報

```sh
amplify -v
12.10.1
```
MFA認証つきのIAMユーザでaws cliを利用するワンライナーコマンド

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/417736/9362fc28-852c-1965-b839-f63b00223139.png" alt="aws" width="80">

`IAMユーザのARN`と`MFAデバイストークン`を用意してワンタイムセッションを確立して作業する

```sh:sh
eval `aws sts get-session-token --serial-number {IAMユーザのARN} --token-code {MFAデバイストークン} | awk ' $1 == "\"AccessKeyId\":" { gsub(/\"/,""); gsub(/,/,""); print "export AWS_ACCESS_KEY_ID="$2 } $1 == "\"SecretAccessKey\":" { gsub(/\"/,""); gsub(/,/,""); print "export AWS_SECRET_ACCESS_KEY="$2} $1 == "\"SessionToken\":" { gsub(/\"/,""); gsub(/,/,""); print "export AWS_SESSION_TOKEN="$2 } '`
```

## 付録

* AWS Security Token Service（STS）を使用して、IAMユーザのMFAデバイストークンから一時的な認証情報（Temporary Security Credentials）を取得する
* 有効期限はデフォルト12時間

```sh:sh
aws sts get-session-token --serial-number <IAMユーザのARN> --token-code <MFAデバイストークン>

# 結果
{
    "Credentials": {
        "SecretAccessKey": "secret-access-key",
        "SessionToken": "temporary-session-token",
        "Expiration": "expiration-date-time",
        "AccessKeyId": "access-key-id"
    }
}
```

認証情報を環境変数にセットする

```sh:sh
export AWS_ACCESS_KEY_ID={AccessKeyId}
export AWS_SECRET_ACCESS_KEY={SecretAccessKey}
export AWS_SESSION_TOKEN={SessionToken}
```
アーカイブ(tar)しながら圧縮(gzip)しながら転送(ssh)しながら展開(tar)してついでに保存する

## コマンド

無駄に時間がかかっている作業をスピードアップしましょう。

```
$ tar cfp ./ - | gzip -c | tee /backup/backup.tar.gz | \
  ssh targethost "cd /targetdir/; cat | tee /backup/backup.tar.gz | gzip -dc | tar fx -"
```

## 課題

システムの構築や移行などでは、ある程度の量のファイルをUNIXサーバー間でコピーする必要があります。元のサーバー側で纏める処理をして、先のサーバー側で展開する処理が必要な場合もあるでしょう。特定のフォルダの中身全部とか、DBのバックアップを取得して相手方に送るとか。結構、時間がかかるんですよね。

一般的に以下の順番で実施します。

1. まとめファイルを作る（バックアップやファイルのアーカイブ処理）
1. 圧縮する
1. 転送する
1. 圧縮を解く
1. まとめファイルを展開する（リストアコマンドの実行とか、アーカイブ展開とか）

少量のファイルであれば、各処理に大した時間は掛かりません。ですが、私が過去に担当していた日本アイ・ビー・エムのWebサイトやショッピングサイトでは、データベースもコンテンツの量も大量です。上記に時間を含めると、まとめファイル作成に30分、圧縮に10分、転送に一時間（帯域による制限）、圧縮解除に10分、展開に30分と、それぞれの間に色々とコマンドを実行したり、一処理が終わっているのに気がつかなかったりで10分と、**計2時間半**です。

限られた時間で保守や移行を行うには、この2時間半は痛い損失です。

じゃあ、「全部をいっぺんにやろう！」というのが冒頭のコマンドになります。

## メリットとデメリット

「全部をいっぺんにやる」ことで先の説明での時間配分ですと計2時間半を**1時間に短縮**できます。

### デメリット

ただし、リスクがあります。
1. よく原理を理解し、事前の試運転をしてから実施する必要があります。大舞台でこのパイプを一発勝負で実施して、成功する人はすごいです。
2. 個別に実施している場合には、送り先側でのエラーがあってもステップごとにリカバリができます。送り先側で「展開スペースがないエラー/リストア失敗」等が起きてしまうと、SIGPIPEシグナルが送られてパイプ全体のコマンドが終了してしまいます。結果、すべてやり直しになります。

これらの対処方法は解説に記載します。

## 解説

コマンドとメリットを見て、「分かった、できる」って人は、もうこの後は読まなくて大丈夫です。

### 動作原理

パイプ「`|`」は簡単にプログラム（コマンド）間の通信を実現するUNIXの大事な機能です。標準出力を標準入力にいれることで、各機能を実現するコマンドを数珠つなぎにして、一度に動作させます。

- `tar cfp ./ -` 転送元の現在のフォルダ以下をtarアーカイブ形式にまとめて標準出力「`-`」に出します。
- `gzip -c` 標準入力に入った内容を圧縮します。
- `tee /backup/backup.tar.gz` 標準入力に入った内容をそのまま標準出力に出しながら/backup/backup.tar.gzに保管します
- `ssh targethost "cd /targetdir/; cat` リモートのtargethostホストにログイン(以下、前提参照)して、/targetdirに移動し、標準入力に入った内容をそのまま標準出力に出します。
- `tee /backup/backup.tar.gz` 標準入力に入った内容をそのまま標準出力に出しながら異リモート側の/backup/backup.tar.gzに保管します
- `gzip -dc` 圧縮を解除します
- `tar fx -` アーカイブファイルを/targetdir以下に展開します

前提：sshでのログインは公開鍵使ってパスワード入れないで済むになっているとかは前提です。検索して一発で出てきたQiitaの[この記事](https://qiita.com/StoneDot/items/a38a35baf50e2cba2b67)でも参考にしてください。

### デメリットの対応策

リスクとして説明したデメリットへの対処方法です。
デメリット1への対策は、事前に予行演習等を行って、掛かる時間や宛先での容量等を確認してください。思わぬところで、NWのタイムアウト等に引っかかる可能性もあります。

デメリット2は、すべての処理を一連のパイプとして実施していることに起因します。ですのでパイプを二分割できればいいのです。シェル芸のワンライナーでは済まなくなるので面倒ですが、この様にします。

```
# 空のファイルを作る
$ touch /backup/backup.tar.gz 

# 空のファイルをtailする形でリストア側のコマンドを先にスタート
$ tail -f /backup/backup.tar.gz | ssh targethost "cd /targetdir/; cat | tee /backup/backup.tar.gz | gzip -dc | tar fx -"　

# 元側のファイル作成を開始
$ tar cfp ./ - | gzip -c >> /backup/backup.tar.gz 
```

この状態では、2番目のssh先でトラブルが起きても元側のコマンドは影響を受けずに済みます。
tailが成立するために、`/backup/backup.tar.gz`への書き込みを追記書き込みにしていたり、実行順番が大事だったりと細かい配慮が必要です。また、最後に、tailは止める必要があるでしょう。ここらへんの理解の上で使ってくださいね。

2番目のssh先で送り先にトラブルが起きた場合は、仕方ないので全部がしゅとくできたあとで以下のコマンドでやり直しをします。

```
$ cat /backup/backup.tar.gz | ssh targethost "cd /targetdir/; cat | tee /backup/backup.tar.gz | gzip -dc | tar fx -"　
```


## 背景

今日はシェル芸の紹介をしました。

プログラムを書いて、世の中の役に立つ製品でも作って生きたいなと思ってIBMって会社へ入社したらSE(当時の呼ばれ方、システムズエンジニア)という職種になって25年です。なったもんは仕方ないので、SEという職種で一人前になってやろうと言うことで、今にいたりますが。世の中の発展は早すぎて、何がSEの一人前がわからないくらいの状態ですし、技術に追いつくのがやっとこさです。とはいえ、世の中は25年前とあんまり変わらないテクノロジー(Linux)が存続していて、ローテクのシェル芸も私と同じく現役で役に立ちます。

現場の作業の実態を見ていると、どうにも非効率な状況が惜しい知識不足だったりするため、この記事を書くことにしました。

皆様のお仕事がスムーズ・安全に進むよう願っております。
excel2pdf

    import openpyxl
    import os
    
    def find_report_sheets(excel_path):
        """
        A1セルに「報告書」が含まれるシートを探す
        """
        workbook = openpyxl.load_workbook(excel_path)
        report_sheets = []
        
        for sheet_name in workbook.sheetnames:
            sheet = workbook[sheet_name]
            if sheet['A1'].value and '報告書' in str(sheet['A1'].value):
                report_sheets.append(sheet_name)
        
        workbook.close()
        return report_sheets
    
    
    
    excel_path = 'DisasterReport.xlsx'
    
    # 報告書シートを探す
    report_sheets = find_report_sheets(excel_path)
    if not report_sheets:
        print("報告書シートが見つかりませんでした。")
    
    # LibreOfficeを使用してPDFに変換
    pdf_path = os.path.splitext(excel_path)[0] + '.pdf'
    try:
        # シート名をカンマ区切りの文字列に変換
        sheet_range = ','.join(report_sheets)
        
        subprocess.run([
            'soffice',
            '--headless',
            '--convert-to', f'pdf:calc_pdf_Export:{{' +
            '"SinglePageSheets":{{"type":"boolean","value":"true"}},' +
            '"Scale":{{"type":"long","value":80}},' +
            '"ScaleToPages":{{"type":"long","value":1}},' +
            '"PageRange":{{"type":"string","value":"1-1"}},' +
            '"IsSkipEmptyPages":{{"type":"boolean","value":"false"}},' +
            '"HorizontalAlignment":{{"type":"long","value":1}},' +
            '"VerticalAlignment":{{"type":"long","value":1}},' +
            '"IsAddStream":{{"type":"boolean","value":"false"}},' +
            '"IsReduceImageResolution":{{"type":"boolean","value":"false"}},' +
            '"MaxImageResolution":{{"type":"long","value":300}},' +
            '"Margin_Top":{{"type":"long","value":10}},' +
            '"Margin_Bottom":{{"type":"long","value":10}},' +
            '"Margin_Left":{{"type":"long","value":20}},' +
            '"Margin_Right":{{"type":"long","value":10}},' +
            '"ExportSheets":{{"type":"string","value":"{sheet_range}"}}'  # シート指定を追加
            '}}',
            '--outdir', os.path.dirname(pdf_path),
            excel_path
        ], check=True)
    
    except Exception as e:
        print(f"PDF変換中にエラーが発生しました: {e}")
gRPC API のまとめ




+ [gRPC API の理解、構築、使用](https://qiita.com/Keiji_otsubo/items/402e7d65d0a8fd3c35fc)

# MuleSoft / Mule Runtime

+ [【アイデア】gRPC Connector and Platform support](https://ideas.salesforce.com/s/idea/a0B8W00000OTzPkUAL/grpc-connector-and-platform-support)
+ [how to consume Grpc API](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000KCHOI0A5)
CursorのProプランでPremiumモデルを使い切った場合の解決方法

## **はじめに**

CursorのProプランを利用していて、Premiumモデル（GPT-4やClaude）の制限に達してしまった方も多いのではないでしょうか。 この記事では、Premiumモデルの制限に達した場合の具体的な対処方法をご紹介します。

## **Proプランの制限について**

**基本の制限値：**

- Premiumモデルの高速モード：月500回まで
- Premiumモデルの低速モード：無制限

## **解決方法**

### **1. Fast Requestsの追加購入**

最も簡単な解決方法は、Fast Requestsを追加購入することです。

**購入方法：**

1. アカウント設定から「ADD FAST REQUESTS」をクリック
2. 購入したい数を選択（例：1000リクエスト）
3. 「UPGRADE +$20/MO」をクリックして確定

**注意点：**

- 追加料金は月額$20から500リクエストずつ追加できる。

### **2. 無料で使えるモデルの活用**

無料で使えるo3-miniを活用することで、制限を回避できます。

**メリット：**

- 追加コストなしで利用可能

**重要な注意点：**

- コーディングタスクに関して強いが、複雑なタスクをこなす場合はプレミアムモデルのClaude 3.7 Sonnetの拡張思考モードを使うのをおすすめします。

### **3. Usage-based Pricingへの切り替え**

使用量に応じた従量課金制を選択することで、制限を解除できます。

**特徴：**

- 500回の基本制限を超えた分のみ課金
- Claude OpusやO1モデルなどの従量課金モデルも利用可能
- 待機時間なしでスムーズに利用可能（ただし、Claudeに関してはUsage-based PricingやFast Requestsを有効にしても低速になる可能性あり。詳細は「トラブルシューティング：Claudeが重い場合」を参照してください）

### **4. Businessプランへのアップグレード**

より多くの機能が必要な場合は、Businessプランへのアップグレードも検討できます。

**Businessプランの特徴：**

- 月額$40/ユーザー
- Proプランの全機能に加え、追加機能あり
- Admin usage dashboard（管理画面）: 組織全体での利用状況の一括管理が可能
- Centralized billing（一括請求）: 「-> Billing」をクリックすることで Stripe の画面を開き、そこから請求書/領収書をダウンロードすることができる。Pro プランではメンバーごとにこの操作を行う必要がありますが、Business プランでは Team メンバー分の請求を一括で管理することができるため利便性が向上します。
- Enforce privacy mode（プライバシーモードの強制）
- OpenAI zero-data retention（OpenAI のゼロデータ保持）
- チーム管理者側でのEdit Request Limit（500 回/月の GPT-4（高速）使用制限の緩和）

**注意点：**

- アカウントごとの GPT-4（高速）の残量が把握できなくなる。

**参考：**
[AIエディター「Cursor」の Business プランの利用を開始したので詳しく解説する](https://zenn.dev/hogeticlab/articles/e3c23463ff479b)

## **まとめ：最適な解決方法の選び方**

状況に応じて、以下の選択肢から最適な方法を選びましょう：

1. **すぐに解決したい場合**
    - Fast Requestsの追加購入
    - Usage-based Pricingへの切り替え
2. **コストを抑えたい場合**
    - Geminiの活用
    - Premium以外の代替モデルの使用
3. **チームでの利用が主な場合**
    - Businessプランへのアップグレード

それぞれの方法を組み合わせることで、より効率的な利用が可能です。 ご自身の使用状況や予算に合わせて、最適な方法を選択してください。
【コロナ社】出展情報「技術書同人誌博覧会」　 (技書博)

## 「第十一回 技術書同人誌博覧会」 に初出展！
**:calendar_spiral: 日にち：2025.01.25（土）**<br>
**:alarm_clock: 時間：11:00~16:00**<br>
**:railway_car: 場所：横浜産貿ホール マリネリア**　<br>**※ブースは「あ-11」です**
<br>

新刊を中心に多数の書籍を展開しております。
ぜひ，この機会にお立ち寄りください。


<br>
<br>

[【技術書同人誌博覧会HP】](https://gishohaku.dev/)

https://blog.gishohaku.dev/entry/2023/09/04/131252

by　はてなid:gishohaku（はてなブログ）

<br>
<br>

https://www.coronasha.co.jp/
Railsのイディオム的なもの

# 始まりは挨拶から

はじめまして、最近リファクタリングに興味を持っているあおげばにゃんこです。
Ruby on Railsを書いている時に便利だなと思った書き方を簡単に紹介したいと思います

# インスタンスの初期化時にデータをセットする


やりたいこと　=> 自分のおもちゃを箱にしまうフォームを作成

## 最初に思いつく処理

直入れすれば良いっしょ！
```ruby
class BoxesController < ApplicationController
  def new
    @box = ToyBox.new(
      toy_car: current_user.toys[:toy_car],
      doll: current_user.toys[:doll],
      puzzle: current_user.toys[:puzzle]
    )
  end
end
```
この方法だと引数の数が増えたとき、著しく可読性が落ちそうです

## 簡単な処理

引数展開を利用します
```ruby
class BoxesController < ApplicationController
  def new
    @box = ToyBox.new(**user_toys)
  end

  private

  def user_toys
    current_user.toys.slice(:toy_car, :doll, :puzzle)
  end
end
```

# 動的にメソッドを決定したい

やりたいこと => 言語設定に合わせて挨拶を変えたい

パラメータが以下のように渡ってきたとする
params = { "language" => "ja" }

## 最初に思いつく処理

if文で分岐させればいいっしょ！
```ruby
greeting = Greeting.new

if params[:language] == 'ja'
  puts greeting.message_ja
elsif params[:language] == 'en'
  puts greeting.message_en
elsif params[:language] == 'ch'
  puts greeting.message_ch
end

```
言うまでもなく、見づらいです。

## 簡単な処理

sendメソッドを使います
```ruby
greeting = Greeting.new


puts  greeting.send("message_#{params[:language]}")
```

## 最後に

もっとrailsやrubyの良い書き方を知りたいので、よければコメントなどで紹介してください
よろしくおねがいします。
【私用】Neovim保存時に日付（タイムスタンプ）を自動更新

# 概要
【私用】なので私的なメモです．少々役立つかもしれないと思い，公開する範囲を拡大することにしました．

Neovimを利用して，ファイル保存時にユーザー名や日時が挿入・更新されると便利なことがあります．コメント行に **```Time-Stamp: <>```** と書いておけば，保存(```:w```)するタイミングで，```Time-Stamp: <ユーザー名や日時>``` の部分が更新される私的に利用しているTipsとなります．他の方法もたくさんあると思います．そこがvimのいいところですね．


:::note warn
OS: Ubuntu 22.04, 24.04で検証
:::

# タイムスタンプ更新関数

init.luaへ次の内容を追記します．関数名はちょっとあれですが，適宜好みの名称に変更してください:sweat_smile:

~~~lua: init.luaへ追記
-- 保存時にタイムスタンプを更新する関数 
--   Time-Stamp: <>と書いてある最初の行が更新される
-- 
local function update_timestamp()
    -- ユーザー名と日付を取得 <ユーザー名: タイムスタンプ>
    local username = os.getenv("USER") or os.getenv("USERNAME") or "anonymous"
    local timestamp = os.date("%Y-%m-%d %H:%M:%S")
    local replacement = "Time-Stamp: <" .. username .. ": " .. timestamp .. ">"

    -- バッファ全体を取得
    local buf = vim.api.nvim_get_current_buf()
    local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false)

    local found = false
    -- 各行をチェックして、Time-Stampを含む最初の行を置き換え
    for i, line in ipairs(lines) do
        if line:match("%s*Time%-Stamp: <.*>$") then
            lines[i] = line:gsub("Time%-Stamp: <.*>$", replacement)
            found = true
            break  -- 該当行が見つかったら、ループを抜ける
        end
    end

    -- 該当行が見つかった場合のみバッファに変更を反映
    if found then
        vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
    end
end

-- ファイル保存時にupdate_timestamp関数を呼び出す
vim.api.nvim_create_autocmd("BufWritePre", {
    pattern = "*",
    callback = update_timestamp
})
~~~


冒頭部分にあるコメント行に **```Time-Stamp: <>```** と書いておけば，保存(```:w```)するタイミングで，```Time-Stamp: <ユーザー名や日時>``` の部分が更新されるはこびとなります．
SadServersで障害復旧を体験してみた #4

# はじめに


Linuxの学習のためとアウトプット習慣のためにSadServersのシナリオ4に挑戦


# #4のシナリオをやってみた。

今回のシナリオはポートノッキングで解決する。
80番ポートがポートノッキングで保護されているwebサーバーがあるので、そのシーケンスをさがしだしす。このシナリオは単一のポートをノックすると解決できるみたい。

ポートノッキングとは何なのかというところから調べた。
セキュリティのために使用されるもので普段はportを閉じで外部からのアクセスを拒否しているが、特定のノックシーケンスによってportを解放できるという仕組み。

シーケンスとはあらかじめ定めた条件のことで　その条件通りにportをノックすると設定したportを開けるというもの (例 3000 22 433 この順番でノックすると80が開きます）
knockというポートノッキングを実現させるためのツールを使用して特定のportをノックして解決してという問題

# 一度やってみる

何をすればいいのか検討もつかないので早速ヒントを確認する。

<details><summary>ヒント1</summary>

 
3000portをノックするなら $knock localhost 3000　でノックできる、nmapも使用できる
curl localhost で80番ポートが開いているか確認できる。

</details>

<details><summary>ヒント2</summary>

curlコマンドやnmapコマンドを実行することで、80番ポートが開放されているか確認することができます。

</details>


<details><summary>ヒント3</summary>

全てのポートをノックするスクリプトを作成すること

</details>

ヒントを見てもよく分からなかったのでknockについて調べてみた。

# knockとは

chatgptから抜粋
knock とは、ポートノッキング（Port Knocking）を実現するためのツールです。ポートノッキングは、セキュリティを向上させるための手法で、特定の順序でポートにアクセス（"ノック"）することで隠されたポートやサービスを動的に開放します。

# knockの設定ファイルを見たい

knockについて調べるとあらかじめルールを決めるので設定ファイルを見にいけばシーケンスがわかると思って
```
cat /etc/knockd.conf
```
このファイルに設定が書かれているみたいなので見に行こうとしたら権限エラーではじかれた。
このシナリオは sudo も使えないので権限がいるファイルは探しにいけなかった。

ポートノッキングについて調べていると、設定ファイルの他にログファイルでもシーケンスが特定できるかもしれないとおもって、

```
cat /var/log/syslog

cat /var/log/syslog.1

```
これらのシステムログを見にいったけどそれらしいもの無かった。

grepでキーワードになりそうなものを検索しても有益な情報はヒットなかった。

# なぜか解決した
進展がなかったので解説している記事を見ると、 全てのポートをノックするスクリプトを作るというものだった、他に方法がないかなと、調べながらコマンドを打っているとなぜか80番ポートが開いていた。回答を確認するとクリアしてしまった。
理由が分からないのでもう一度やりなおした。

# 調査の結果

開いているポートを確認するために以下のコマンドを実行

<details><summary>このコマンドを実行</summary>

```
nmap localhost

```
これを実行すると開いているポートを確認できて、もう一回実行すると
80ポートが開いている状態になった。

![スクリーンショット 2025-01-21 13.20.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535626/92d4adcc-9b82-2ac3-2733-035c2423f2f0.png)


</details>

なぜこうなったのか調べてみた。

<details><summary>調べた内容</summary>

```bash
nmap localhost
```
上記のコマンドポートスキャンを行えるコマンドで、デフォルトでは上位1000ポートのスキャンをするというコマンドらしい。
このスキャンといううのが TCP接続の試行(SYNパケット送信)を行うものらしく、このSYNパケットがノックのして認識されている？可能性もあるとのこと。
ノックしたポートの中にたまたま該当したポートがノックされて80ポートが開く要因となったと思っている。
オプションをつけることで全てのポート(0~65535)をスキャンすることも可能

``` bash
# これで全ポートをスキャンできる。
nmap -p- localhost
```

</details>

# まとめ

意図せず解決できてしまったけど、なぜ解決できたのか調べて何となくわかったのでよかったかなと思う。

# 余談
シェルスクリプトを書く練習で全てのポートをノックするスクリプトを作って実行してみた。
<details><summary>シェルスクリプト作成</summary>



``` bash

~$ vim portknocking.sh

#!/bin/bash
for port in `seq 0 65535`; do
    knock localhost $port
    echo "Knocked on port $port"
    if curl -sSf localhost &>/dev/null; then
        echo "The Port 80 has been opened!"
        exit 0
    fi
done
```
</details

参考サイト
[SadServers解説#4 "Taipei": Come a-knocking](https://zenn.dev/comf_nakamura/articles/sadservers_5)

全てのポートに対してノックするのでかなり時間がかかってしまう。
シェルスクリプトを書いてから実行したら残り時間が足りなくなってしまった。
IT未経験者がweb技術の基本を学んでみた

## はじめに
IT未経験者がWebの土台となる基本技術を学ぶため、ブログを執筆しました。
また、本記事は以下の記事を読み執筆をさせていただきました。
参照：https://gihyo.jp/book/2024/978-4-297-14571-2

## ステートフル
ステートフルなプロトコルでは通信の開始と終了が明確である。
その間の一連の通信が識別できるようになっている。
人間同士のコミュニュケーションに置き換えると電話でのやりとりに例えられる。
電話は、相手につながって通話を開始すると通話を切るまで会話が出来る。
この一連の流れをセッションと呼び
この状態のことをステートフルな状態だと言える。

## ステートレス
状態を持たないプロトコルのこと
ステートレスなプロトコルでは個々のリクエスト・レスポンスに対して関係性を定義しない。
手紙でのやりとりに例えることが出来る。
個々のやりとりが独立しており、ステートレスな状態であると言える。

## どちらの状態が求められるのか
結論、ステートレスな状態が求められる。
理由は、大量のリクエストを処理するにはサーバを複数用意して
分担させるのが有効であり
ステートレスなリクエストであれば、どのサーバでもリクエストを処理できるため
ステートレスな状態が求められる。
サーバ側に状態を持たせる（ステートフル）ではシステム規模に応じて
サーバを増やしにくくなるのも要因の一つである。

## リクエスト
クラアントから相手のサーバに接続し、情報を要求すること

例：URLに直接アクセスする。（アドレスバーに直接URL入力、ブックマークからアクセス）

## レスポンス
サーバからクライアントに対する返答のこと

例：そのままHTMLを返す、DBからデータを取得してHTMLを生成して返す。

## Webの世界での通信
Webの世界ではクライアントとサーバがHTTPの取り決めに従って情報を交換する事で
成り立っている。

HTTPは(Hypertext Transfer Protocol)と言う名称
WebブラウザとWebサーバ間での通信で使われているプロトコルのこと。

## プロトコル
コンピュータ同士が通信する際の通信方法の取り決めのこと。

例：FTP　ファイルを転送するプロトコル
　　IP 　インターネット上でデータを送受信するためのプロトコル

## クッキー
サーバとクライアントの間で保持しておきたい情報をクッキーという形でクライアント側（Webブラウザ）側に持たせておく。
一般的な使い方は、クライアントの識別に使われる。

例：病院などで受付番号を発行されるのと同じと考えればわかりやすい。店舗から受け取った番号を示すことでXX番目に受付をしたお客様として識別してもらえる。

## ポート番号
まず最初に、IPアドレスというものがある。
IPアドレスはコンピュータを識別するために使われており、
データの行き先を管理するのに使用されている。
IPアドレスは送信先や送信先を表す住所のようなものである。
IPアドレスは接続したいコンピュータは指定できるがコンピュータが提供する
サービスまでは指定できない。
そのため、ポート番号が必要である。
ポート番号は0から65535番まで番号が振り分けられている。
IPアドレスで相手先のコンピュータを特定し、ポート番号でその中のプログラムを特定する。

例：IPアドレスを建物の住所、ポート番号は部屋の番号は何号室かと考えるとわかりやすい。

Webサーバのように、通信を待ち受けるプログラムでは標準で利用すべきポート番号がプロトコルごとに決めれられている。

例：http　80番　https 443番など

## 感想
IT未経験者がこの参考書をはじめて手に取った際、分厚さに圧倒されてしまったが
読み始めると技術の時代背景、解決しようとした問題、実際にアプリやターミナルを使った実装例を取り上げており、とても理解しやすかった。
技術を点から線、線から面の理解にしていくことでより技術を学ぶ楽しさを知る事ができた。

色々、わからない単語がありこの課題にも時間がかかったが自分が納得いくまで基礎・基本を学べたのも良かった。本を読むことも習慣になったので読書が好きになれた。
改善点としては、完璧に理解するのではなく、ここはこういうことをいっているんだなとざっくりとした理解で進めることも大切であると感じた。


この本を読み、一番印象に残った箇所はフレームワークの強さだと感じた。フレームワークは便利な反面、プログラミング言語をしっかりと把握しておかなければ要件の変化や発生した問題を解決できないとう事態に直面するのでフレームワークを使うことも大事だがそれぞれの言語をしっかりと理解する必要があると感じた。
【Ruby】クエリパラメータに`+`記号を使いたい

## 問題
RailsのアプリのAPIを実行するときのクエリパラメータに記号の`+`を使いたい時、そのまま`+`記号を使うとスペースとして認識される。

## 解決方法
`+`記号の部分を`%2B`に変更する。
```ruby
# 変更前
localhost:3000/api?key=value+sample

# 変更後
localhost:3000/api?key=value%2Bsample
```

## 参考
https://qiita.com/KenjiOtsuka/items/13d13aac41c3bd58db68