OmniAICreator/Qiita-1.07M huggingface dataset:
【コマンド】Homebrew

## 目次
- [コマンド](#コマンド)
    - [バージョンを確認する](#バージョンを確認する)
    - [Homebrewを更新する](#homebrewを更新する)
    - [Homebrewを診断する](#homebrewを診断する)
    - [パッケージをインストールする](#パッケージをインストールする)
    - [パッケージをアンインストールする](#パッケージをアンインストールする)
    - [パッケージを更新する](#パッケージを更新する)
    - [パッケージを検索する](#パッケージを検索する)
    - [インストールパッケージを確認する](#インストールパッケージを確認する)
    - [古いパッケージを削除する](#古いパッケージを削除する)

## コマンド

### バージョンを確認する

```zsh
brew --version
```

### Homebrewを更新する

```zsh
brew update
```

### Homebrewを診断する

```zsh
brew doctor
```

以下のコードが表示されたら正常です。
```zsh
Your system is ready to brew.
```

### パッケージをインストールする

```zsh
brew install "パッケージ名"
```

### パッケージをアンインストールする

```zsh
brew uninstall "パッケージ名"
```

### パッケージを更新する

指定したパッケージを更新する。
```zsh
brew upgrade "パッケージ名"
```

全てのパッケージを更新する。
```zsh
brew upgrade
```

### パッケージを検索する

```zsh
brew search "パッケージ名"
```

### インストールパッケージを確認する
```zsh
brew list
```

### 古いパッケージを削除する

削除する古いパッケージを事前確認する。
```zsh
brew cleanup --dry-run
```

古いパッケージを削除する。
```zsh
brew cleanup
```
【Rails】テストではfollow_direct!が必要


# はじめに
こんにちは。アメリカに住みながら独学でエンジニアを目指している taira です。
本日はテストでリダイレクトをする際には明示的に`follow_redirect!`を書く必要があると知り、とても勉強になったので、実例を交えてまとめてみようと思いました。

## テストコードの意図

Railsチュートリアルで出てきた課題で、以下のような意図を持った統合テストコードを書こうと思いました。

1. ログイン処理
2. `user_path(@user)` へリダイレクト
3. 画面にあるリンクをそれぞれ確認

ちなみにログイン処理(`log_in_as`)を呼び出すと、次のメソッドが実行されます。

```ruby
def create
  @user = User.find_by(email: params[:session][:email].downcase)
  if @user&.authenticate(params[:session][:password])
    forwarding_url = session[:forwarding_url]
    reset_session
    params[:session][:remember_me] == '1' ? remember(@user) : forget(@user)
    log_in @user
    redirect_to forwarding_url || @user # ここでリダイレクトしている
  else
    flash.now[:danger] = 'Invalid email/password combination'
    render 'new', status: :unprocessable_entity
  end
end
```

上記のコードでは、条件を満たしていれば `forwarding_url` もしくは `@user` にリダイレクトします。

## 私が書いたテストコード

```ruby
require "test_helper"

class SiteLayoutTest < ActionDispatch::IntegrationTest
  def setup
    @user = users(:michael)
  end

  test 'logged in user layout' do
    log_in_as(@user)
    assert_redirected_to @user # リダイレクトしている？
    assert_select "a[href=?]", root_path, count: 2
    assert_select "a[href=?]", help_path
    assert_select "a[href=?]", users_path
    assert_select "a[href=?]", edit_user_path(@user)
    assert_select "a[href=?]", logout_path
  end
end
```

上記は統合テストですが、当初、私は `assert_redirected_to` でリダイレクト処理が完了していると思っていました。そのためテストを実行するとエラーが発生。
実は `assert_redirected_to` はリダイレクトを実行するのではなく、**コントローラーのアクションがリダイレクトレスポンスを返したかどうかと、リダイレクト先が想定のURLかどうかをチェックするメソッド** です。

つまり、`assert_redirected_to` だけではリダイレクトは実際に行われないので、以下のように `follow_redirect!` を書く必要があります。

```ruby
log_in_as(@user)
assert_redirected_to @user
follow_redirect!  # ← この一行が必須
assert_template 'users/show'
```

## なぜcreateメソッドには `follow_redirect!` がないのか

テストで `follow_redirect!` が必要なことは理解できましたが、では `create` メソッドにも `redirect_to forwarding_url || @user` の後に `follow_redirect!` が必要なのでは？ と思うかもしれません。

ここでは、次の2つの違いを理解しておくことが重要です。

1. ブラウザ（開発環境・本番環境）
2. 統合テスト

### ブラウザ（開発・本番）の場合

ブラウザがRailsアプリと通信する際、処理の流れは以下のようになっています。

1. ブラウザでフォーム送信（POST）
2. Railsからレスポンスが返ってくる（ステータスコード302、リダイレクト先URL）
3. ブラウザはRailsからのレスポンスを解釈し、自動的にリダイレクト先に対して新たにGETリクエストを送信
4. リダイレクト先ページのHTMLを取得・表示

つまり、ブラウザはRailsからのリダイレクト指示を受け取ると**自動的に転送先URLへリクエストを送る**仕組みを持っています。これが、開発や本番環境で `follow_redirect!` が不要な理由です。

### 統合テストの場合

一方、統合テストではブラウザのような自動リダイレクト処理を行う仕組みがありません。

- テスト側からPOSTリクエストを送信 → Railsがリダイレクト指示を返す（ここで処理が止まる）
- テストコード側で明示的に「リダイレクト先URLを取得してほしい」と指示する必要がある

このため、Railsの統合テストでは `follow_redirect!` が用意されており、
「リダイレクト先へ移動する」という操作をテストコード側で書く必要があります。

## まとめ

テストコードでリダイレクト先を確認したい場合、`assert_redirected_to` は「リダイレクトレスポンスを返したかどうか」を確認するためのメソッドであり、実際にリダイレクト先に移動するわけではありません。そのため、リダイレクト後のページ内容まで確認する際には `follow_redirect!` が必要です。

- **ブラウザ（開発・本番環境）** では、リダイレクト指示（302）を受け取ったとき、ブラウザが自動で転送先にアクセスしてくれる。
- **統合テスト** では、自動リダイレクトが行われないので、自分で `follow_redirect!` を書いて明示的に次のページを取得しに行く必要がある。
Pythonのエスケープシーケンス(escape sequence)について

## はじめに
Pythonのエスケープシーケンス(escape sequence)についてまとめてみました。

## エスケープシーケンス(escape sequence)とは
　単一引用符（シングルクォーテーション）「'」は、文字列リテラルの最初と最後を表すための特別な文字です。そのため、例えば「**'This isn't a pen.'**」といった表記は行えません。
　文字「'」は、２個の文字「\'」で表記します（見かけは「\」と「'」の２個の文字ですが、「'」という１個の文字を表します）。すなわち、「**'This isn「\」't a pen.'**」が正しい表記です。

 ✖　「**'This isn't a pen.'**」
 〇　「**'This isn「\」't a pen.'**」

　このような、逆斜線記号（バックスラッシュ）「\」を先頭にした、２個、あるいは、それ以上の個数の文字で、（通常の文字としては表記不能あるいは困難である）単一の文字を表す表記法が、**エスケープシーケンス**(**escape sequence**)です。

## エスケープシーケンスの一覧
### \a
**警報**(alert)
聴覚的または視覚的な警報を発する。

### \b
**後退**(backspace)
表示位置を直前の位置へ移動する。

### \f
**書式送り**(form feed)
改ページして、次のページの先頭へ移動する。

### \n
**改行**(new line)
改行して、次の行の先頭へ移動する。

### \r
**復帰**(carriage return)
現在の行の先頭位置へ移動する。

### \t
**水平タブ**(horizontal tab)
次の水平タブ位置へ移動する。

### \v
**垂直タブ**(vertical tab)
次の垂直タブ位置へ移動する。

### \ \
**逆斜線文字（バックスラッシュ）** **「\」**

### \ ?
**疑問符** **「?」**

### \ '
**単一引用符（シングルクォーテーション）** **「'」**

### \ "
**二重引用符（ダブルクォーテーション）** **「"」**

### \newline
バックスラッシュと改行文字を無視する。

### \ooo
oooは１～３桁の８進数
８進数でoooの値をもつ文字。

### \xhh
hhは２桁の１６進数
１６進数でhhの値をもつ文字。

### 注意：日本語版のMS-Windowsでは、逆斜線\の代わりに円記号￥を使います。

## おわりに
ここまで読んでいただきありがとうございます！

## 参考文献
・新・明解Python入門 (新・明解シリーズ) 単行本 – 2019/5/23
柴田 望洋 (著)
p.13
PowerQueryでURLをデコードする方法まとめ

# はじめのはじめに
本文はすべて我が配下、ChatGPTに出力させたものです。検証も面倒でメモ程度に出力したものですので眉唾で見てください。

## はじめに
Power BI（Power Query）を使っていると、URLエンコードされている文字列を「元の人が読める文字列」に戻したくなることがあります。例えば `redirect_to=https%3A%2F%2Fexample.com%2F` のようなパラメータがクエリ内に混在している場合などです。

通常、.NET系なら `Uri.UnescapeDataString()` を使ってデコードできますが、PowerQuery（M言語）環境だと **`Uri.UnescapeDataString` が使えない** 場合があります。そこで活躍するのが、**`Uri.Parts`** を使った「ダミーURLへ埋め込み → クエリ部分を引っこ抜く」テクニックです。

## やりたいこと
```text
"https%3A%2F%2Fexample.com%2F?utm_source%3Dxxx"
↓
"https://example.com/?utm_source=xxx"
```
のように、URLエンコード文字列を元に戻します。

## 使うもの：Uri.Parts
Power Queryには、`Uri.Parts()` という「URLを構成要素に分解する関数」が用意されています。  
この関数で返される結果はレコード型で、以下のようなキーを持っています。

- `Scheme`  (例: "https")
- `Host`    (例: "example.com")
- `Port`    (例: null)
- `Path`    (例: "/path/to/something")
- `Query`   (例: [ q = "実際のクエリ文字列" ])
- `Fragment`(例: null)
- ...など

たとえば「クエリパラメータの中に文字列を埋め込んで `Uri.Parts` に食わせる」ことで、**半自動的にエンコードを解除**してくれます。

## サンプルMコード
```m
let
    // 例）エンコード済みの文字列をDataというテーブルで持っているとする
    Source = Table.FromRecords({
        [ id = 1, EncodedUrl = "https%3A%2F%2Fexample.com%2F?utm_source%3Dxxx" ],
        [ id = 2, EncodedUrl = "https%3A%2F%2Fexample.org%2Fpath%3Fparam%3Dtest" ]
    }),

    // 1) ダミーURLへ埋め込み
    //    ※ "https://dummy.com/?q=" + [EncodedUrl] の形式
    // 2) Uri.Parts で分解
    // 3) 取得した Query の "q" を取り出す
    Decoded = Table.AddColumn(
        Source,
        "DecodedUrl",
        each Uri.Parts("https://dummy.com/?q=" & [EncodedUrl])[Query][q]
    )
in
    Decoded
```

このようにすれば、`DecodedUrl` 列には
```
https://example.com/?utm_source=xxx
```
のように**URLデコードされた結果**が入ります。あとは `Text.BetweenDelimiters` や `Text.Split` などを使って、パラメータ解析を進めるだけです。

## 仕組み
ダミーURLにパラメータをくっつけて `Uri.Parts` に丸投げすると、`Uri.Parts` が内部的に**URLデコードをしながら構造を分析**してくれます。その結果、`Query` に含まれるデータが**デコード後の文字列**として取得できるというわけです。

Power BIの環境で直接 `Uri.UnescapeDataString` が使えない場合は、**この「ダミーURLにエンコード文字列を埋め込んで `Uri.Parts`」** というやり方をぜひ活用してみてください。

## まとめ
- PowerQuery/M言語では `Uri.UnescapeDataString` が機能せず困る場合がある
- 代わりに `Uri.Parts("https://dummy.com/?q=" & [EncodedUrl])[Query][q]` でデコードできる
- これでエンコードされたURLを簡単にデコードし、解析や加工が可能になる

Power BI での ETL 処理を効率よく進めるうえで、覚えておくときっと役に立つはずです。
【Pyxel】マップ内の移動を簡単に実装する！

![pyxel-20250320-110200.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3922095/f4766c96-82b9-4fc7-814b-cd22d374eb7e.gif)

## はじめに
　Pyxelでは、マップ移動を実装するにあたって便利なメソッドが用意されています。しかし、その解説記事があまりなく、あっても古い情報だったりするので、現在使える方法をご紹介いたします。

:::note
この記事の情報はversion 2.3.16のものです。
:::

## テンプレ
　マップ移動をするにあたり、任意のタイルマップの特定の座標が、何のタイルか取得するメソッドを使用します。
```python
tile = pyxel.tilemaps[n].pget(x, y)
print(tile)    #(1, 3)など
```
pyxelのエディタを起動すれば確認できますが、タイルマップは0～7まで登録できます。このタイルマップの任意の番号と座標を指定することで、そのマスがどのタイルかを取得してくれます。

　取得したタイルの情報は、イメージバンクの左上を0, 0としたときの座標で返してくれるので、以下のように移動可能なタイルをリストにしておくことで、簡単に移動判定ができます。

```python
dest_x = 10    #移動先のx座標
dest_y = 10    #移動先のy座標
movable_tiles = [(0, 0), (0, 1), (2, 3)]    #移動可能なタイルの一覧
if pyxel.tilemaps[0].pget(dest_x, dest_y) in movable_tiles:
    #任意の移動処理
else:
    #任意の衝突処理
```
移動不可能なタイルを一覧にしてもいいですが、移動可能なタイルのときのみ移動可にすることで、画面外の判定をする必要がなくなります。

:::note warn
　このメソッドを使う場合、タイルには一つの機能しか持たせられません。したがって、違う機能を持たせたい時は、同じ模様のタイルをもう一つ用意する必要があります。
 例）エンカウントするマスとエンカウントしないマス
:::

### おまけ
　もしこのメソッドが使えない場合は、どのように実装する必要があるのか紹介します。pygameで作る場合は、必然的にこの処理をすることになりますね。

```python
tilemap = [
    [0, 0, 0, 0, 0, 0, 0], 
    [0, 1, 1, 1, 1, 1, 0],
    [0, 2, 2, 2, 1, 1, 0],
    [0, 1, 1, 2, 1, 1, 0], 
    [0, 1, 1, 2, 1, 1, 0],
    [0, 1, 1, 2, 2, 2, 0],
    [0, 1, 1, 1, 1, 1, 0], 
    [0, 0, 0, 0, 0, 0, 0]
]
dest_x = 2
dest_y = 3
movable_tiles = [1, 2]
if tilemap[dest_y][dest_x] in movable_tiles:
    #任意の移動処理
else:
    #任意の衝突処理
```

このくらいの規模なら二次元リストを用意するのも可能ですが、マップのサイズが大きくなればなるほど現実的ではなくなっていきます。また、複数マップを用意することが多いはずなので、やはり強力なメソッドである事がご理解いただけたと思います。

## まとめ
マップ移動を実装するなら、`pyxel.tilemaps[n].pget(x, y)`は必須級！

## 最後に
　ここまで読んで下さりありがとうございました。今回は移動の判定にフォーカスしてメソッドの紹介をしました。他にも、`camera`など便利な機能が用意されているので、一度公式ドキュメントに目を通してみると良いのではないでしょうか。

https://github.com/kitao/pyxel
7.リアルタイムで顔検出を行ってみよう

# **シリーズ記事一覧**
| | タイトル  リンク |
|:---:|:---:|
| **第1回**  | [環境構築](https://qiita.com/yuta3003/items/302ae91e6f4ab7164d9b) |
| **第2回**  | [Python 概要](https://qiita.com/yuta3003/items/a51dbfea2c942ffdbec2) |
| **第3回**  | [Python 基礎](https://qiita.com/yuta3003/items/178c238c387faecc8d13) |
| **第4回**  | [Pythonで学ぶWebの基本と実践](https://qiita.com/yuta3003/items/902dc18c6618456c7010) |
| **第5回**  | [Streamlitを使ってみよう](https://qiita.com/yuta3003/items/c269f889b4d1a87efacb)|
| **第6回**  | [Streamlitでリアルタイム画像処理](https://qiita.com/yuta3003/items/cabbdced44bcf1e84a1b) |
| **第7回**  | [リアルタイムで顔検出を行ってみよう](https://qiita.com/yuta3003/items/ec7411748997b7a2d05d) |

# **リアルタイムで顔検出を行うアプリを作成してみよう**

## **概要**
YOLOを用いて物体検出を行い、StreamlitでWebアプリケーションとして実装してみよう。

## **YOLOとは**
YOLO（You Only Look Once）は、ディープラーニングに基づいた物体検出アルゴリズムであり、高速かつ効率的な検出を実現する。


### **メリット**
- **高速**: リアルタイム処理が可能
- **検出精度が高い**: 最新のモデルでは高精度な検出が可能
- **導入が簡単**: 事前学習済みモデルを利用可能

### **デメリット**
- **小さな物体や遠くの物体の検出精度が低い**
- **重なり合った物体の検出精度が低い**
- **複数の物体が検出された場合、精度が低下することがある**

## **Webアプリケーション作成**
### **ライブラリをインストール**
```
pip install ultralytics streamlit opencv-python numpy
```
- `ultralytics`: YOLOを提供するライブラリ
- `streamlit`: Web UIを作成するライブラリ
- `opencv-python`: カメラ映像の取得・処理に必要なライブラリ
- `numpy`: 画像データ処理に必要なライブラリ

### **プログラムファイル作成**
以下内容を`st-yolo.py`として作成し、保存する
```Python
import streamlit as st
import cv2
import numpy as np
from ultralytics import YOLO

# Load YOLO model
model = YOLO("yolov8n.pt")

# Streamlit app setup
st.title("Real-time Object Detection (YOLOv8 + Web Camera)")
start_button = st.button("Start Camera")
stop_button = st.button("Stop Camera")
FRAME_WINDOW = st.image([])

# Camera setup
camera = cv2.VideoCapture(0)

# App state
if 'running' not in st.session_state:
    st.session_state['running'] = False

# Button actions
if start_button:
    st.session_state['running'] = True
if stop_button:
    st.session_state['running'] = False

# Real-time object detection
if st.session_state['running']:
    while True:
        _, frame = camera.read()
        if frame is None:
            st.write("Camera disconnected or unavailable.")
            st.session_state['running'] = False
            break
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        results = model(frame)
        annotated_frame = results[0].plot()
        FRAME_WINDOW.image(annotated_frame, channels="RGB")
        if not st.session_state['running']:
            break
else:
    st.write("Camera stopped.")

camera.release()
```

### **プログラムを起動**
```
streamlit run st-yolo.py
```
6.Streamlitでリアルタイム画像処理

# **シリーズ記事一覧**
| | タイトル  リンク |
|:---:|:---:|
| **第1回**  | [環境構築](https://qiita.com/yuta3003/items/302ae91e6f4ab7164d9b) |
| **第2回**  | [Python 概要](https://qiita.com/yuta3003/items/a51dbfea2c942ffdbec2) |
| **第3回**  | [Python 基礎](https://qiita.com/yuta3003/items/178c238c387faecc8d13) |
| **第4回**  | [Pythonで学ぶWebの基本と実践](https://qiita.com/yuta3003/items/902dc18c6618456c7010) |
| **第5回**  | [Streamlitを使ってみよう](https://qiita.com/yuta3003/items/c269f889b4d1a87efacb)|
| **第6回**  | [Streamlitでリアルタイム画像処理](https://qiita.com/yuta3003/items/cabbdced44bcf1e84a1b) |
| **第7回**  | [リアルタイムで顔検出を行ってみよう](https://qiita.com/yuta3003/items/ec7411748997b7a2d05d) |

# **リアルタイム画像処理アプリを作成してみよう**
## **リアルタイム画像処理Webアプリを作成**
### **ライブラリをインストールする**
```
pip install -U streamlit streamlit-webrtc opencv-python-headless
```
- `streamlit`: Streamlit本体
- `streamlit-webrtc`: Streamlitでリアルタイム映像・音声を扱うコンポーネント
- `opencv-python-headless`: OpenCV(UIはStreamlitで作成するのでHeadless版を使用)

### **カメラの映像を表示するWebアプリを作成**

- 以下の内容を`camera.py`として作成し、保存する
  ```python
  import streamlit as st
  from streamlit_webrtc import webrtc_streamer

  st.title("My first Streamlit app")
  st.write("Hello, world")

  webrtc_streamer(key="example")
  ```

- プログラムを実行する
  ```sh
  streamlit run camera.py
  ```

- プログラムを停止する
  `Ctrl + c`


### **リアルタイム画像処理を行うWebアプリの作成**

- 以下の内容を`webrtc.py`として作成し、保存する
  ```python
  import streamlit as st
  from streamlit_webrtc import webrtc_streamer
  import av
  import cv2

  st.title("My first Streamlit app")
  st.write("Hello, world")

  def callback(frame):
      img = frame.to_ndarray(format="bgr24")
      img = cv2.cvtColor(cv2.Canny(img, 100, 200), cv2.COLOR_GRAY2BGR)

      return av.VideoFrame.from_ndarray(img, format="bgr24")

  webrtc_streamer(key="example", video_frame_callback=callback)
  ```

- プログラムを実行する
  ```sh
  streamlit run webrtc.py
  ```

- プログラムを停止する
  `Ctrl + c`
5.Streamlitを使ってみよう

# **シリーズ記事一覧**
| | タイトル  リンク |
|:---:|:---:|
| **第1回**  | [環境構築](https://qiita.com/yuta3003/items/302ae91e6f4ab7164d9b) |
| **第2回**  | [Python 概要](https://qiita.com/yuta3003/items/a51dbfea2c942ffdbec2) |
| **第3回**  | [Python 基礎](https://qiita.com/yuta3003/items/178c238c387faecc8d13) |
| **第4回**  | [Pythonで学ぶWebの基本と実践](https://qiita.com/yuta3003/items/902dc18c6618456c7010) |
| **第5回**  | [Streamlitを使ってみよう](https://qiita.com/yuta3003/items/c269f889b4d1a87efacb)|
| **第6回**  | [Streamlitでリアルタイム画像処理](https://qiita.com/yuta3003/items/cabbdced44bcf1e84a1b) |
| **第7回**  | [リアルタイムで顔検出を行ってみよう](https://qiita.com/yuta3003/items/ec7411748997b7a2d05d) |

# **Streamlitを使ってみよう**
## **Streamlitとは？**
Streamlitは、Pythonのみで実装可能なWebアプリケーションのフレームワークです。
シンプルなコードでインタラクティブなUIを作成でき、データ可視化や機械学習のデモなどに適しています。

### **Streamlitの特徴**
- シンプルなコード
  通常のWebフレームワーク(Flask, Django)とは異なり、HTMLやCSSを必要とせずPythonだけでWebアプリを作成することができます。
- 高速な開発
  ホットリロードに対応しているため、ファイルを編集すると自動的にWebアプリも更新されます。
- データサイエンス向け
  PandasやTemsorFlowなどのライブラリと簡単に統合できるため、データ分析や機械学習の可視化に用いられることが多いです。

## **Streamlitを使ってWebアプリを作成**
### **ライブラリをインストールする**
まず、Streamlitをインストールします。
```
pip install streamlit
```

### **ファイルを作成する**
次に、アプリのスクリプトファイルを作成します。
```
notepad streamlit_app.py
```
以下内容を保存し、メモ帳を閉じる

```python
import streamlit as st

# タイトル
st.title("簡単な Streamlit アプリ")

# テキスト入力
name = st.text_input("名前を入力してください")

# ボタン
if st.button("送信"):
    st.write(f"こんにちは、{name} さん！")

# スライダー
age = st.slider("年齢", 0, 100, 25)
st.write(f"あなたの年齢は {age} 歳です。")

# チェックボックス
if st.checkbox("詳細を表示"):
    st.write("これは詳細情報です！")

# セレクトボックス
option = st.selectbox("好きな色を選んでください", ["赤", "青", "緑"])
st.write(f"あなたの好きな色は {option} ですね！")

```

#### コード解説
- `st.title("タイトル")`：アプリのタイトルを設定します。
- `st.text_input("ラベル")`：ユーザーからのテキスト入力を受け取ります。
- `st.button("ボタン名")`：ボタンがクリックされたら特定の処理を実行します。
- `st.slider("スライダー名", 最小値, 最大値, 初期値)`：数値をスライダーで選択できます。
- `st.checkbox("チェックボックス名")`：チェックが入った場合に表示される内容を制御できます。
- `st.selectbox("セレクトボックス名", [選択肢リスト])`：ドロップダウンメニューを作成します。

### **Streamlitを実行する**
作成したアプリを起動するには、次のコマンドを実行します。
```
streamlit run streamlit_app.py
```
![screenshot_streamlit_app.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356851/752324ce-7df3-4a66-971b-f353f6ec0bc2.png)

**補足**
実行時にEmailの入力を求められることがありますが、空欄のままエンターキーを押せば問題ありません。

### **Webにアクセスする**
アプリが起動すると、ブラウザで以下のURLにアクセスできます。
http://localhost:8501/

### **プログラムを止める**
アプリを終了するには、ターミナルに戻り、`Ctrl + c`を押下してください。

## **Streamlitの活用例**
### **データの可視化**
PandasやMatplotlibを使い、グラフや表を動的に表示できます。
![screenshot_visual.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356851/8b2b6c29-993e-40c9-9848-bd8fee839e22.png)

### **ダッシュボードの作成**
業務データをリアルタイムで分析し、視覚的にわかりやすく表示できます。
![screenshto_dashboard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356851/fc225396-20dd-42cc-b43e-60c66c215ac7.png)
簡単な決定木を実行してみる

機械学習の学びのため簡単な決定木を実行してみる。

# 使うもの
matplotlib(グラフ描画のためのライブラリ)
scikit-learn(データ分析や機械学習のためのライブラリ)
Iris Dataset(アイリスデータセット)
→150件のあやめ(花)のデータ。
中身は以下である。
・「花びら（petal）／がく片（sepal）の長さと幅（cm）」という4つの特徴や属性。
・あやめの種類である「setosa(セトサ)／versicolor(バージカラー)／virginica(バージニカ)」という3つのラベル。

# データ処理のざっくりとした流れ
①必要なライブラリのインポート:データ操作、可視化、機械学習などに必要なライブラリをインポート。
②Irisデータセットのロード:Scikit-learnのデータセットからIrisデータセットをロードし、特徴量データ X とターゲットデータ y に分ける。
③データの分割:データをトレーニングセットとテストセットに分割する。トレーニングセットが70%、テストセットが30%。
※訓練データとテストデータが分かれている理由は、まずは訓練データだけで学習を行い、データの特徴を理解する。その後、テストデータを使って、未知のデータに対しても正しく判断できるかをチェックする。
④モデルのトレーニング:トレーニングデータを使用してモデルを訓練する。
⑤テストデータに対する予測:テストデータに対して予測を行う。
⑥正確度の評価:予測結果と実際のラベルを比較してモデルの正確度を算出し、表示する。
⑦決定木の可視化:訓練された決定木モデルを視覚化する。特徴量名とクラス名を表示し、ツリーの各ノードを色付けする。

```
# 必要なライブラリをインポート
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.tree import plot_tree

# Irisデータセットをロード
iris = datasets.load_iris()
X = iris.data
y = iris.target

# データをトレーニングセットとテストセットに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 決定木分類器のインスタンス化
clf = DecisionTreeClassifier(random_state=42)

# モデルのトレーニング
clf.fit(X_train, y_train)

# テストデータに対する予測
y_pred = clf.predict(X_test)

# 正確度の評価
accuracy = accuracy_score(y_test, y_pred)
print(f'モデルの正確度: {accuracy * 100:.2f}%')

# 決定木の可視化
plt.figure(figsize=(20, 10))
plot_tree(clf, filled=True, feature_names=iris.feature_names, class_names=iris.target_names, rounded=True)
plt.show()
```


![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4041530/39fee780-4761-435e-8993-bb1a284e03a6.png)



# 決定木の見え方
条件分岐:条件が満たされている場合は左へ、満たされない場合は右へ分岐。
gini:データが異なるクラスに属する程度を示す指標。(数値を最小化するように分割することで、より精度の高いモデルを構築できる)
samples:データに含まれるサンプルがそのノードに何個行き着いたか。
value:そのノードに行き着いた学習サンプルがどのクラスに属しているか。
Snippetsで簡単にテンプレートを呼び出す方法(Vue, React)

# なぜこの記事を書こうと思ったのか
Vueの学習を始めたのですが、Reactと比べて script, template, style の3つのタグを書くのが少し面倒だなと感じました。
拡張機能を導入すれば「vueinit」の入力で自動生成できるのですが、タグの順番やインデントなど、細かい部分が自分の好みに合わず…。(reactではtsxを表示する際に「rafceやrafc」をよく使っていました。)

何度か手動で直しながら書いてみたものの、3回目あたりで「やっぱり毎回これは面倒だな」と感じ、
「じゃあもうスニペット作ってみるか」と初めて手を出してみました。

いざ作ってみると、思ったよりずっと簡単で、もっと早くやっておけばよかった…と。
こう言った経緯で今回記事にまとめてみました。

## 実例とやりたいこと、結果。

``` javascript
<template lang="">
  <div>

  </div>
</template>
<script>
export default {

}
</script>
<style lang="">

</style>

```
これはvueでの拡張機能インストール後に「vueinit」を用いて出力されるテンプレートになります。これに対して以下の問題がありましたので改善していきます。

### どういった構成にしたいのか？
- 表示される順番についてはscript -> template -> styleとしたい
- scriptには setup と lang="ts"をあらかじめに持たせたい
- templateにはindex.htmlでデフォルトのlangを設定するため何も持たせたくない
- styleについてもlangは特に指定しない

ということを実際にスニペットで書いてみたいと思います。

## スニペットファイルの置き場所と構成について
今回は「チームでも共有できるようにしたい」という前提があったため、
プロジェクトディレクトリ内の .vscode にスニペットファイルを設置し、Git管理することにしました。

なお、.vscode/snippets/ のようなディレクトリ分けはできないため、
prefix に s- を付けてソートしやすいように分類しています。
（ファイル名は .code-snippets 拡張子、命名はケバブケースが主流とのことなのでそれに倣いました）
```
.vscode
├── extensions.json
├── s-function-snipets.code-snippets ✅
├── s-vue-snipets.code-snippets ✅
└── settings.json
```

### スニペットファイルの中身
.vscode/s-vue-snippets.code-snippets に記載している内容は以下のとおりです：

```
{
  "Vue Script Setup": {             //スニペットのタイトル
    "prefix": "vvv",                //呼び出し時に使われる文字列
    "body": [                       //出力される内容(文字列配列で管理する)
      "<script lang=\"ts\" setup>",
      "",                           //改行時は空文字を入れる
      "</script>",
      "<template>",
      " <div>",
      "",
      " </div>",
      "</template>",
      "",
      "<style></style>",
    ],
    "description": "このプロジェクト独自のvueファイル構成",   //説明欄
  },
}
```

基本的に以下の４段階構成でした。全然難しくなかったですね。
- タイトル
- 呼び出し用の文字列(prefix)
- 出力される内容(body)
- 補足の説明(description(任意))

### 実際に作成したスニペットを使ってみる
App.vueファイル内で prefixとして設定した「 vvv 」を入力すると以下のように選択候補が出力されました。
![スクリーン ショット 2025-03-24 に 11.25.41 午前.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624085/4387d067-58a0-443e-b4dd-7091c764d2ce.png)

入力補完に出力された内容を出力してみると以下のようになります。ばっちり狙ったものができました。
![スクリーン ショット 2025-03-24 に 11.28.14 午前.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624085/0085e699-d6dc-41f2-acec-ad9a542307d4.png)

### 小技について
```
$1 → 展開直後にカーソルが当たる  
$2 → Tabキーで次の場所へ移動
```
さらに、文字列変換にも対応しています
- Capitalize ${1:/capitalize} ->先頭だけ大文字に
- Lowercase	${1:/downcase} -> 全部小文字に
- Uppercase	${1:/upcase} -> 全部大文字に
- Regex Replace	${1/(.*)/prefix$1/}	-> 正規表現で置換

ReactのuseState用snipets(setの後の最初の文字列を大文字に)

```
{
  "useState": {
    "prefix": "usc",
    "body": [
      "const [$1, set${1/(.*)/${1:/capitalize}/}] = useState<$2>($3)"
    ],
    "description": "useState with auto-cap setter"
  }
}
```

## 最後に
Reactで毎回 :FC を書いていた頃から、
「スニペットでもっと早くできたんじゃ？」と思っていた部分が、
今回のVue学習を通してようやく解消できました。

今後もこうした小ネタを活用して、少しでも開発効率を上げていければと思います。
【環境構築】Homebrew

## 環境構築

### Homebrewをセットアップする

以下のコマンドでHomebrewをインストールします。
```zsh
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
```

以下のコードが表示されたらログインユーザーのパスワードを入力します。
```zsh
Password:
```

以下のコードが表示されたらEnterキーを入力します。
```zsh
Press RETURN/ENTER to continue or any other key to abort:
```

以下のコマンドでパスを通します。
`username`：Macのユーザー名
```zsh
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/username/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
```

以下のコマンドでHomebrewのインストール確認をします。
```zsh
brew --version
```
以下のコードが表示されたらインストール完了です。
X.X.X：Homebrewのバージョン
```zsh
Homebrew X.X.X
```
ローカル環境でのGit初期設定ガイド

## はじめに
MacOSでGit初期設定をする方法についてのメモとなります。
(何回やっても忘れてるので...😭)

## 環境
■ MacOS
14.0
■ チップ
Apple M2

## 1.Homebrewをインストール
HomebrewはmacOS上で動作するパッケージ管理ツールのひとつとなります。
Homebrewを用いて様々なパッケージをインストールすることができます。

■ Homebrew
https://brew.sh

以下のコマンドでインストールできます。
コマンドが変わる可能性があるので、ホームページで確認するのをお勧めします！
```Terminal
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

Homebrewをインストールしたものの、まだHomebrewが使えないようです、、、
以下のエラーが発生していました。
```Terminal
$ brew -v
zsh: command not found: brew
```

パスが通ってないことが原因となるため、Homebrewのパスを通すことにより、解決できます。
```Terminal
# 出力
Warning: /opt/homebrew/bin is not in your PATH.
  Instructions on how to configure your shell for Homebrew
  can be found in the 'Next steps' section below.
==> Installation successful!

中略

==> Next steps:
- Run these commands in your terminal to add Homebrew to your PATH:
    echo >> /Users/{UserName}/.zprofile
    echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/{UserName}/.zprofile
    eval "$(/opt/homebrew/bin/brew shellenv)"
- Run brew help to get started
- Further documentation:
    https://docs.brew.sh
```

下記のコマンドを実行します。
```Terminal
$ echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/{UserName}/.zprofile
$ eval "$(/opt/homebrew/bin/brew shellenv)"
```

これで、Homebrewのバージョンを確認します！
```Terminal
$ brew -v
# 出力
Homebrew 4.4.16
```

## 2.HomebrewでGitをインストール
brewでGitをインストールするため、以下のコマンドを実行します。
```Terminal
$ brew install git
```

インストールが完了したら、Gitのバージョンを確認してみましょう！
```Terminal
$ git --version
# 出力
git version 2.39.5 (Apple Git-154)
```
## 3.Gitアカウントの設定（git config）
これを設定していないと、ローカルリポジトリからリモートリポジトリにpushする度に、
アカウントの情報を入力する必要があります。

最初に設定しておくと便利です！

gitのユーザー名、メールアドレスを以下のコマンドで設定します。
```Terminal
$ git config --global user.name "{GitUserName}"
$ git config --global user.email {GitUserEmail}
```

登録内容を確認したい場合は、以下のコマンドを実行してください。
```Terminal
$ git config --list
```

≈4.GitのSSH接続を設定
自分のパソコンからサーバーに接続しているよー！と安全に通信をおこなう一つの手段として、
SSH公開鍵による認証をする必要があります。

まず、SSHキーが存在するのかを確認します。
```Terminal
$ cat ~/.ssh/id_rsa.pub
# 出力
cat: /Users/xxxx/.ssh/id_rsa.pub: No such file or directory
```

ディレクトリが存在しない場合、SSH公開鍵を作成します。
```Terminal
$ ssh-keygen
or
$ ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
```

SSHキーをSSHエージェントに追加します。
GitHubなどのリモートサーバーとの安全な接続を確立するために使用されるそうです！
```Terminal
$ eval "$(ssh-agent -s)"
$ ssh-add ~/.ssh/id_rsa
```

生成されたSSH公開鍵をコピーします。
以下のコマンドを実行すると、SSH公開鍵をクリップボードにコピーしてくれるので便利です。
```Terminal
$ cat ~/.ssh/id_rsa.pub | pbcopy
```

コピーした公開鍵をGithubに登録します。
登録方法は以下となります。
1.「自分のGithubプロフィール」>「Settings」>「SSH and GPG keys」で「New SSH key」に移動
2.コピーした公開鍵を登録

## 最後に
ここまですれば、Git初期設定は一通り完了です！
ftdiのusb-uart変換チップでUSB送信内容をキャプチャ

キャプチャフィルタは以下
```ruby
usb.src == host and ftdi-ft
```

表示フィルタだけなら以下
```ruby
usb.src == host && ftdi-ft
```

pythonでの送信内容取得は以下

```shell
python3 -m pip install pyshark
```

```python

import pyshark
...
    cap = pyshark.FileCapture(fpath, display_filter='usb.src==host && ftdi-ft')
    for packet in cap:
        if not hasattr(packet, 'ftdi-ft'):
            continue
        ftdi = getattr(packet, 'ftdi-ft')

        if not hasattr(ftdi, 'if_a_tx_payload'):
            continue
        tx_payload = getattr(ftdi, 'if_a_tx_payload')
```
ABC398の記録

# はじめに
最近またちょくちょく参加しているので記録を残しておく。

https://atcoder.jp/contests/abc398

成績：ABC3完（650, unrated）

# A
nが奇数なら1つ、偶数なら2つの=が中央に来る。文字列を掛け算で扱えるのはpythonならではなのだろうか。
```python:A
n = int(input())
if n%2 == 0:
    print("-"*((n-2)//2) + "==" + "-"*((n-2)//2))
else:
    print("-"*((n-1)//2) + "=" + "-"*((n-1)//2))
```

# B
ちょっと難しい。5枚のカードがフルハウスになる時、カードがソートされていれば[1,1,1,2,2]のように前3枚が同じパターンか、[1,1,2,2,2]のように後ろ3枚が同じパターンかしかないため、それを判定する関数を定義してカードの選び方を全探索した。

```python:B
A = list(map(int,input().split()))

#5枚のカードがフルハウスになるか判定する関数を定義
def check(cards):  #cardsはソートされている必要がある
    if cards[0] == cards[1] and cards[1] == cards[2] and cards[2] != cards[3] and cards[3] == cards[4]:
        return True
    elif cards[0] == cards[1] and cards[1] != cards[2] and cards[2] == cards[3] and cards[3] == cards[4]:
        return True
    else:
        return False


#選ばない2つを選択
flag = False
for i in range(7):
    for j in range(i+1,7):
        choose = []
        for k in range(7):
            if k != i and k != j:
                choose.append(A[k])
        #choose内でフルハウスになるか判定
        choose.sort()
        if check(choose):
            flag = True
if flag == True:
    print("Yes")
else:
    print("No")
```
5枚の選び方は選ばない2つを指定することで実装し、時間に余裕があるので途中で答えが見つかったとしても最後まで探索するようにした。5枚の選び方はitertools.combinationsを使った方が楽な気がする。
==Trueも書かなくていいのだがどうも何もないのが気持ち悪くて書いてしまう。

# C
要は配列の中で一度しか登場しない数の中で最も大きいものの位置を出力すればOK。dictで登場回数を管理し、keyで降順にソートして登場回数が1の数字のindex+1を出力した。


```python:C
n = int(input())
A = list(map(int,input().split()))

cnt = {} #登場回数をカウント
chk = set() #登場したかチェック
for i in range(n):
    if A[i] in chk:
        cnt[A[i]] += 1
    else:
        chk.add(A[i])
        cnt[A[i]] = 1
cnt_sort = sorted(cnt.items(), key = lambda x:x[0],  reverse=True)
for x, times in cnt_sort:
    if times == 1:
        print(A.index(x) + 1)
        break
else:
    print(-1)
```
なぜかdict中のkeyの有無をわざわざsetで管理している。dictのinも$O(1)$なのでdictを検索すればよいのだが、よく忘れる。index()は$O(n)$なので避けがちだがここでは1回きりの使用なので問題ないのが面白い。

# D
時間内には方針が立たず、諦めて風呂に入っていたら解法を思いついた。
煙は全体が移動するため、最初に発生した煙を基準とするとそれ以降に発生した煙の相対的な位置は常に変わらない。ということで、最初に発生した煙の座標と、この煙に対する原点と高橋君の位置は毎秒計算する。「最初に発生した煙に対する後続の煙の座標」をsetで持っておき、先ほど計算した原点の位置がこのset中になければ煙が発生するので原点の位置をsetに加え、高橋君の位置がこのset中になければ0、あれば1を答えの配列に加算する。
```python:D
n,r,c = map(int,input().split())
s = input()

ans = []
rows = set() #最初の煙から見た後続の位置関係をメモする
rows.add((0,0))
smk = [0,0] #最初の煙の位置

for i in range(n):
    if s[i] == "N":
        smk[0] -= 1
    if s[i] == "W":
        smk[1] -= 1
    if s[i] == "S":
        smk[0] += 1
    if s[i] == "E":
        smk[1] += 1
    
    if (-smk[0], -smk[1]) not in rows: #原点に煙がなければ追加
        rows.add((-smk[0], -smk[1]))
    
    if (r - smk[0], c - smk[1]) in rows:
        ans.append("1")
    else:
        ans.append("0")
print(''.join(ans))
```
公式解説では座標平面の方を動かすというアプローチが取られていたが、たぶんイメージの問題でやっていることはそんなに変わらないと思う。方針が経ってから5分くらいで書けたのでもう少し早く気づきたかったところだった。

Cまで解いて1時間くらい残せているのはよい傾向。Dを時間内に通したいところ。
AWS Gen AI Loftが変える生成AIの学び方と、今後の展望

# はじめに
生成AIが急速に普及する中、技術キャッチアップと実践スキルの習得が求められている。しかし、個人やスタートアップが最新のAIトレンドを独力で追い続けるには限界がある。こうした課題に対するAWSのアプローチが「AWS Gen AI Loft」である。世界10都市以上で展開され、生成AIをテーマにした学びとネットワーキングを実現するリアルな空間として注目を集めている。

参考URL: https://lnkd.in/gWAxNF5q?trk=public_post_reshare-text

# 最新の技術をリアルタイムで学ぶ

Gen AI Loftは、LLM（大規模言語モデル）、Amazon Bedrock、AIエージェントなど、生成AIの最新技術に関するハンズオンセッションが中心。専門家による解説と実機での体験を通じて、トレンド技術をいち早く実装ベースで習得できる。特に「ワークフローとエージェントの統合」は、今後のAIサービス構築における重要テーマの一つになっている。
# デモとフィードバックの循環が成長を加速させる

ロフトではスタートアップや個人開発者がプロダクトのデモを披露できる環境が整っており、他の開発者やAWS関係者からの直接フィードバックが得られる。こうした即時性の高いインプットにより、製品改善やアイデアの進化が促進され、開発のサイクルが加速する。
# 実践知を得られる場所としての価値

AWSの技術者と直接対話しながら課題解決できる点も、ロフトならではの特徴。クラウド移行、AI導入、セキュリティ設計など、個別課題に対する実践的な知識が得られる。経験が浅い開発者にとっても、コミュニティとの関わりを通じて安心して技術を身につけられる。
# ネットワーキングによるビジネス機会の創出

Gen AI Loftでは、同じ志を持つ開発者や投資家、起業家が集い、信頼関係を築くことで協業や出資といった次のステージに進むチャンスもある。特にシード段階のスタートアップにとっては、貴重なビジネスマッチングの場とも言える。
# 参加者主体のコミュニティ形成

ロフトの特徴は「AWSが提供する場」ではなく、「参加者が主体的に学びを形成できる場」である点。各拠点でコミュニティリーダーが育成され、勉強会やディスカッションが継続的に行われており、参加者自身がロフトの成長を牽引する存在になっている。
# 今後の展望と考察
## 1. 生成AIの学びは「個人学習」から「共同探求」へ

これまで生成AIに関する知識習得はオンラインコースやドキュメント中心だったが、Gen AI Loftの登場によって「リアルな対話」「実装体験」「コミュニティ支援」が融合した学習スタイルが広がっていく。今後、他のクラウドベンダーやエンタープライズ企業も、類似の学習空間を提供し始める可能性が高い。
## 2. 生成AIエコシステムの拡張

AWSがロフトを拡大し続けている背景には、生成AIを中核にしたSaaSやアプリケーションの市場拡大がある。ロフトで育ったプロジェクトがAWS上でスケールすることで、BedrockやSageMakerのエコシステムも強化され、AWSにとっての戦略的価値が高まる。
## 3. 地域ごとの生成AI特化型人材の育成拠点へ

ロフトは単なる学習の場ではなく、地域に根差したAI人材のハブにもなっている。今後は都市単位でのAIアクセラレータや起業支援と連携し、スタートアップ育成・人材育成の拠点化が進む可能性がある。教育機関や自治体との連携も視野に入る。

## 4. ジェネレーティブAIの民主化

Loftのような開かれたスペースを通じて、生成AI技術が一部のエキスパートだけでなく一般開発者へも浸透、技術格差の縮小と、AIによるイノベーションの民主化が進む
# まとめ

AWS Gen AI Loftは、生成AI技術を「学ぶ」「試す」「つながる」という3要素を統合した共創空間。参加者はここで実用的なスキルを獲得し、コミュニティとともに成長する。AI技術の習得にとどまらず、ビジネスや社会への波及効果をも生み出すエンジンとなっていく。今後、より多くの都市・業界でLoftが展開され、生成AIを軸とした技術革新と人的ネットワーク形成がますます活性化していくと考えられる。
GoでFTP操作を実現！「github.com/jlaffaye/ftp」を使ったサンプルコード解説

この記事では、Go言語でFTPサーバーに接続し、基本的な操作（接続・ログイン、ディレクトリ一覧の取得、ファイルのアップロード・ダウンロード）を行う方法を解説します。シンプルなサンプルコードを通して、主要な処理の実装方法を見ていきましょう。

## 1. 事前準備

まず、以下のコマンドでパッケージをインストールしてください。

```bash
go get github.com/jlaffaye/ftp
```

## 2. サンプルコード

以下のコードは、FTPサーバーへの接続からファイルのアップロード、ダウンロードまでを実装したサンプルです。

```go
package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"time"

	"github.com/jlaffaye/ftp"
)

func main() {
	// FTPサーバーに接続
	ftpServer := "ftp.example.com:21" // サーバーアドレスとポート
	c, err := ftp.Dial(ftpServer, ftp.DialWithTimeout(5*time.Second))
	if err != nil {
		log.Fatal("接続エラー:", err)
	}
	defer c.Quit() // プログラム終了時に切断

	// ログイン
	username := "your_username"
	password := "your_password"
	if err := c.Login(username, password); err != nil {
		log.Fatal("ログインエラー:", err)
	}

	// ディレクトリの一覧を取得
	entries, err := c.List("/")
	if err != nil {
		log.Fatal("ディレクトリ一覧取得エラー:", err)
	}
	fmt.Println("ディレクトリ一覧:")
	for _, entry := range entries {
		fmt.Printf("Name: %s, Type: %s, Size: %d\n", entry.Name, entry.Type, entry.Size)
	}

	// ファイルのアップロード
	localFile := "local_file.txt"    // ローカルに存在するファイル
	remoteFile := "remote_file.txt"  // アップロード先のファイル名
	file, err := os.Open(localFile)
	if err != nil {
		log.Fatal("ローカルファイルオープンエラー:", err)
	}
	defer file.Close()

	if err := c.Stor(remoteFile, file); err != nil {
		log.Fatal("ファイルアップロードエラー:", err)
	}
	fmt.Println("ファイルのアップロードに成功しました。")

	// ファイルのダウンロード
	r, err := c.Retr(remoteFile)
	if err != nil {
		log.Fatal("ファイルダウンロード開始エラー:", err)
	}
	defer r.Close()

	downloadedFile := "downloaded_file.txt" // ダウンロード先のファイル名
	out, err := os.Create(downloadedFile)
	if err != nil {
		log.Fatal("ローカルファイル作成エラー:", err)
	}
	defer out.Close()

	if _, err := io.Copy(out, r); err != nil {
		log.Fatal("ファイルダウンロードエラー:", err)
	}
	fmt.Println("ファイルのダウンロードに成功しました。")
}
```

## 3. 各処理の解説

### 3.1 FTPサーバーへの接続

- **Dial関数**  
  `ftp.Dial`を使ってFTPサーバーに接続します。`DialWithTimeout`オプションを使うことで、接続タイムアウトを設定できます。  
  ```go
  c, err := ftp.Dial(ftpServer, ftp.DialWithTimeout(5*time.Second))
  ```

### 3.2 ログイン処理

- **Login関数**  
  接続後は、`c.Login(username, password)`で認証を行います。エラーが発生した場合はログを出力してプログラムを終了します。

### 3.3 ディレクトリ一覧の取得

- **List関数**  
  `c.List("/")`を使用してルートディレクトリの内容を取得しています。返されるスライスには、ファイルやディレクトリの情報が含まれており、名前や種類、サイズを出力できます。

### 3.4 ファイルのアップロード

- **Stor関数**  
  ローカルファイルを`os.Open`で読み込み、`c.Stor(remoteFile, file)`を使ってFTPサーバーへアップロードします。アップロード前にファイルの存在チェックやエラーハンドリングを行うことが重要です。

### 3.5 ファイルのダウンロード

- **Retr関数とio.Copy**  
  `c.Retr(remoteFile)`でFTPサーバー上のファイルを取得し、`io.Copy`を使用してローカルファイルに書き込みます。この方法により、ファイルの内容をストリームとして効率的に転送できます。

## 4. まとめ

今回紹介したサンプルコードは、GoでFTP操作を行うための基本的な流れを示しています。実際の開発では、エラーハンドリングの強化や、接続の再試行、セキュリティ面の考慮など、用途に合わせた工夫が必要になるでしょう。  
このサンプルを参考に、あなたのプロジェクトでFTP操作を実装してみてください！
C#.NETでライセンス認証機能を作る

## はじめに
こんにちは。開発部のMです。
今回はC#.NETでライセンス認証機能を作成する方法の一例を紹介したいと思います。

## 前提
- オフラインにてユーザーからリクエストを受けライセンスを許可する。
- １度許可した端末では次回から認証を求めない。
- Visual Studioの”Windows フォーム アプリケーション(.NET Framework)”での開発を想定。

## 仕様
1. ユーザーがアプリケーションを使用したい端末でリクエストファイルを作成する。
1. リクエストファイルを受け取り、その内容を元にライセンスファイルを作成する。
1. ユーザーがライセンスファイルを受け取りリクエストファイルの内容と一致すれば認証成功。

## リクエストファイルの作成
#### １）リクエストファイルを出力する画面を作成する。
画面内容
- リクエストファイルの出力先、出力ファイル名を指定する項目(フォルダ選択ボタンやファイル名を入力するテキストボックスなど)
- リクエストファイルを出力するトリガーとなるボタン(以下、「リクエストファイル出力」ボタン)

#### ２）リクエストファイル出力処理
①　「リクエストファイル出力」ボタン押下時の処理を作成する
```c#:端末情報取得
string plainText = "";
ManagementClass mc = new ManagementClass("Win32_OperatingSystem");
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
    plainText = mo["SerialNumber"].ToString();
    mo.Dispose();
}
moc.Dispose();
mc.Dispose();
```
下記はWindowsオペレーティングシステムの情報にアクセスする処理です。
```c#:
ManagementClass mc = new ManagementClass("Win32_OperatingSystem");
```
Win32_OperatingSystem クラスのインスタンスを取得した場合、以下のような情報にアクセスできます。

##### システム情報
- Caption - OSの名前（例: "Microsoft Windows 11 Pro"）
- Version - OSのバージョン（例: "10.0.22000"）
- BuildNumber - ビルド番号
- CSDVersion - サービスパックのバージョン
- Manufacturer - 製造元（"Microsoft Corporation"）
- OSArchitecture - アーキテクチャ（"64-bit" や "32-bit"）
##### インストール・ライセンス情報
- InstallDate - OSのインストール日時
- SerialNumber - ライセンスキー
- RegisteredUser - 登録ユーザー名
##### システムパス
- SystemDirectory - システムディレクトリのパス
- WindowsDirectory - Windowsディレクトリのパス
- BootDevice - 起動デバイス
##### メモリ情報
- TotalVisibleMemorySize - 合計物理メモリ (KB)
- FreePhysicalMemory - 利用可能な物理メモリ (KB)
- TotalVirtualMemorySize - 合計仮想メモリ (KB)
- FreeVirtualMemory - 利用可能な仮想メモリ (KB)
##### パフォーマンス・状態情報
- LastBootUpTime - 最終起動時間
- LocalDateTime - 現在のローカル時間
- NumberOfProcesses - 実行中のプロセス数
- NumberOfUsers - ログイン中のユーザー数
- Status - 現在の状態
##### ページファイル情報
- SizeStoredInPagingFiles - ページファイルのサイズ
- FreeSpaceInPagingFiles - ページファイルの空き容量

今回は端末を特定したいので「SerialNumber」を使用しました。

②　共通鍵Aで「SerialNumber」を暗号化
③　②の内容をレジストリに書き込み
```c#:レジストリ書込
try
{
    //キー（HKEY_CURRENT_USER\Software\xxx）を開く
    Microsoft.Win32.RegistryKey regkey =
        Microsoft.Win32.Registry.CurrentUser.CreateSubKey(@"Software\xxx");
    //バイト配列を書き込む（REG_BINARYで書き込まれる）
    byte[] arrBytes = Encoding.Unicode.GetBytes(cipher);
    regkey.SetValue("request", arrBytes);
    //閉じる
    regkey.Close();
} catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}
```
④　②の内容をリクエストファイルに出力
#### ３）ライセンスファイルを出力する画面を作成する
画面内容
- リクエストファイルを取り込む項目(ファイル選択ダイアログなど)
- ライセンスファイルの出力先、出力ファイル名を指定する項目(フォルダ選択ボタンやファイル名を入力するテキストボックスなど)
- ライセンスファイルを出力するトリガーとなるボタン(以下、「ライセンスファイル出力」ボタン)
#### ４）ライセンスファイル出力処理
①　リクエストファイルの内容を共通鍵Aで複合化
②　複合化した内容を共通鍵Bで暗号化
③　②の内容をライセンスファイルに出力
#### ５）ライセンス認証処理
①　ライセンスファイルの内容を共通鍵Bで複合化
②　２）-③で書き込んだレジストリの内容と一致するか確認する。一致すれば認証成功！
③　①の内容をレジストリに書き込み
１度許可した端末では次回から認証を求めないという仕様のため、リクエスト内容をレジストリに書き込みます。次回起動時にはレジストリにライセンス内容があるかどうかチェックし、あった場合ライセンス認証処理をスキップします。

## さいごに
簡単ですがC#.NETでライセンス認証機能を作成する方法の一例をご紹介しました。
- Windowsオペレーティングシステムの情報にアクセス
- 暗号化、複合化
- レジストリへの書き込み

と複雑な機能が複数あり、詳しく書ききれなかった部分もありますが認証機能を作成したいという方の参考になれば幸いです。

はつかぜ株式会社では、IT学習や業務に役立つ情報を定期的にお届けしていきたいと思っています。
システム開発のお問い合わせ・ご相談はこちら
https://www.hatsukaze.co.jp/inquire/
WPF の DataTemplate を活用した MVVM パターンの実践

# WPF の DataTemplate を活用した MVVM パターンの実践

## はじめに
業務でたまたま見ていて気になったので・・・
WPF (Windows Presentation Foundation) では、**DataTemplate** を活用することで、ViewModel のデータに応じて柔軟な UI を作成できます。本記事では、MVVM (Model-View-ViewModel) パターンを用いて、DataTemplate を使い分ける方法を解説します。

## DataTemplate の基礎
**DataTemplate** とは、データをどのように表示するかを定義するテンプレートです。例えば、`ListBox` のアイテムにカスタム UI を適用することができます。

```xml
<ListBox ItemsSource="{Binding Items}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Name}" FontWeight="Bold" />
                <TextBlock Text="{Binding Description}" FontStyle="Italic" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
```

## DataTemplateSelector を使った UI の切り替え

### DataTemplateSelector とは？
`DataTemplateSelector` を使用すると、データの種類に応じて異なる `DataTemplate` を動的に適用できます。たとえば、アイテムの種類によって表示を変えたい場合に便利です。

### 実装手順

#### 1. ViewModel の定義
まず、異なる種類のデータを表す ViewModel を定義します。

```csharp
public abstract class ItemViewModel {}

public class TextItemViewModel : ItemViewModel
{
    public string Text { get; set; }
}

public class ImageItemViewModel : ItemViewModel
{
    public string ImagePath { get; set; }
}
```

#### 2. DataTemplateSelector の実装

次に、DataTemplateSelector を作成します。

```csharp
public class ItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate TextTemplate { get; set; }
    public DataTemplate ImageTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        return item switch
        {
            TextItemViewModel => TextTemplate,
            ImageItemViewModel => ImageTemplate,
            _ => base.SelectTemplate(item, container)
        };
    }
}
```

#### 3. XAML で DataTemplateSelector を適用

XAML で DataTemplate を定義し、`ItemTemplateSelector` を適用します。

```xml
<Window.Resources>
    <DataTemplate x:Key="TextItemTemplate">
        <TextBlock Text="{Binding Text}" Foreground="Blue" />
    </DataTemplate>

    <DataTemplate x:Key="ImageItemTemplate">
        <Image Source="{Binding ImagePath}" Width="100" Height="100" />
    </DataTemplate>

    <local:ItemTemplateSelector x:Key="ItemSelector"
        TextTemplate="{StaticResource TextItemTemplate}"
        ImageTemplate="{StaticResource ImageItemTemplate}" />
</Window.Resources>

<ListBox ItemsSource="{Binding Items}" ItemTemplateSelector="{StaticResource ItemSelector}" />
```

## まとめ
WPF の DataTemplate と DataTemplateSelector を組み合わせることで、MVVM パターンに沿った柔軟な UI の実装が可能になります。本記事では、異なる種類の ViewModel に基づいて UI を切り替える方法を解説しました。

これを応用すれば、リッチな UI を持つ WPF アプリケーションを効率的に開発できます！
Pythonの哲学、The Zen of Python

## はじめに
The Zen of Pythonについてまとめてみました。

## The Zen of Python

import thisを実行します。
```Python
import this
```

英語の文書が表示されます。これは、Tim Peters氏によってまとめられた"**The Zen of Python**"です。
Zenは、日本語の「**禅**」に由来します。
```Python:出力結果
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
```

### Beautiful is better than ugly.
醜いよりも美しいほうがよい。

### Explicit is better than implicit.
暗示するより明示するほうがよい。

### Simple is better than complex.
複雑であるよりも単純なほうがよい。

### Complex is better than complicated.
複雑すぎるよりも、ただ複雑なほうがよい。

### Flat is better than nested.
ネストしているよりも、しないほうがよい。

### Sparse is better than dense.
密よりも疎のほうがよい。

### Readability counts.
可読性（読みやすさ）が大切だ。

### Special cases aren't special enough to break the rules.
特殊だからといって規則を破る理由にならない。

### Although practicality beats purity.
とはいえ、実用性は、純粋さに勝る。

### Errors should never pass silently.
エラーを黙って渡してはならない。

### Unless explicitly silenced.
とはいえ、わざと隠されているのならば見逃せばよい。

### In the face of ambiguity, refuse the temptation to guess.
曖昧なものに出会ったときに、その意味を推測してはならない。

### There should be one-- and preferably only one --obvious way to do it.
何かよい方法があるはずだ。誰にとっても明らかな、唯一の方法が。

### Although that way may not be obvious at first unless you're Dutch.
オランダ人でない限り、そのような方法が明らかとは思えないだろうけど。
※"オランダ人"は、Python開発者のGuido van Rossum氏がオランダ人であることに由来する。

### Now is better than never.
いつまでもやらないのではなく、やるのは今でしょ。

### Although never is oftern better than *right* now.
とはいえ、今《すぐ》にやるより、やらないほうがよいことも多い。

### If the implementation is hard to explain, it's a bad idea.
実装を説明するのが難しければ、アイディアが悪い。

### If the implementation is easy to explain, it may be a good idea.
実装が説明しやすければ、アイディアがよいはずだ。

### Namespaces are one honking great idea -- let's do more of those!4
複数の名前空間の使い分けは、とても優れたアイディアだ。他にもたくさんアイディアを使おう。

## おわりに
ここまで読んでいただきありがとうございます！

## 参考文献
・新・明解Python入門 (新・明解シリーズ) 単行本 – 2019/5/23
柴田 望洋 (著)
p.22-23
IAMロールへのスイッチロールをタグで許可する方法

## これは何？
IAMロールに対してスイッチロールする際にIMAユーザーのタグの有無で切り替え許可を与えられるかを検証したため、その結果をまとめたものです。
## 対応方法
1. IAMユーザーに対し任意のタグを設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510307/75d819e0-e0c8-4921-bd00-ab238ff1d047.png)
※例としてキーに「CodeApproval」、値に「true」を設定<br><br>
2. IAMロールに対し、以下信頼関係(信頼されたエンティティ)を設定する
```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<AWSアカウントID>:root"
            },
            "Action": "sts:AssumeRole",
            "Condition": {
                "StringEquals": {
                    "aws:PrincipalTag/CodeApproval": "true"
                }
            }
        }
    ]
}
```
※aws:PrincipalTagの部分に対し、1にて設定したタグを設定する<br>
3. 実際にスイッチロールを行い、結果を確認する
#### 指定したタグが付与されている場合(成功)
→「現在アクティブです」の部分に対象のIAMロール名が表示されていればOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510307/80d069e8-b0bf-40b3-bde8-f79c91e5d7c2.png)

#### 指定したタグが付与されていない場合(失敗)
→「Invalid information in one or more fields」というエラーメッセージが表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510307/d83b2aa1-187e-4f6f-bc81-418cff051557.png)

## 最後に
IAMユーザーに対しタグを設定することで、特定のIAMロールに対してのスイッチロールの許可を与えるかどうかを制御できることが確認できました。

使用例として、IAMロールで許可する類のリソース(CodeCommitの承認ルールとか)を制御する際に、タグを使うことで柔軟に設定できるので、有効活用してもらえると幸いです。
Xcode [option + shift + command + R] (文字列置換より賢い) Rename

# 文字列置換

変数名、クラス名やプロパティ名を一度に変更する場合、`option + command + F`で文字列置換することがあると思います。

<i>例えば、Replace に `text`、With に `message` をセットして `All` をクリック</i>
 
![scr-f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/f0b39f52-1803-4639-ba31-3829a7681fdc.png)

ところが、`text`であっても、置換対象で無い「text」が有る場合は、`All`（全置換）できず、確認しながら一つずつ`Replace`する必要があります。
これは、単なる文字列置換であるために起きる不都合です。
（正規表現等を駆使すれば、真に置換対象だけを全置換できる可能性はありますが）

これに対して、`option + shift + command + R`は文脈を解釈して「リネーム」してくれる便利な名称変更機能です。同じ文字列があっても、文脈を解釈するため対象外と判断されると置換されません。


# リネーム

ショートカットは`option + shift + command + R`ですが、メニューから実行する場合は、Xcodeメニュー → Editor → Refactor → Rename です。

![menu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/f546c667-8a31-452d-8d38-c147ca593d16.png)


変更したい「名称」を選択した状態で、「リネーム」を実行します。すると、定義（宣言）の箇所がテキストフィールドに代わり（かつ、変更対象の箇所がファイルをまたいで一覧で表示され）、変更後の「名称」をタイプし enter すると、該当箇所が一度に変更されます。

![scr2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/8023a91e-de1b-405a-8a45-c22c6ef443a7.png)

![scr3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/27d37bb8-9c4b-401f-a1cc-4d61f4c80588.png)

取りやめる場合は、escape を押します。

必要により、ファイル名も自動的にリネームします。これはありがたい機能です。

![scr4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/ff09e762-8a5c-465a-8a82-7114efe52815.png)

_ビルドエラー（コンパイルエラー）がある状態では、正しく機能しない場合があります。ビルドエラーがない状態で使用しましょう。_

<br><br>
<hr>
Xcode初心者向けにまとめました。<b>以上</b>
Angular コンポーネントとは

# はじめに
Angularには**コンポーネント**という概念がある。
自分が初めてAngularに触れたとき

**コンポーネントってなんぞ?**

っとなった覚えがあるので、コンポーネントについて簡単に解説したい。

# コンポーネントって
コンポーネントは**ビュー**(View)を定義し、制御するものである。←**重要**

**ビュー**て何?

アプリケーションのユーザーインターフェース（UI）を構成するHTMLテンプレートのことを指す。

簡単に言うと、ビューは**画面を表示する役割**を担っているということ。

このビューの表示内容を更新したり、イベントバインディングを設定するといった制御する役割を担うのが**コンポーネント**である。

言葉だけではわかりづらいと思うので以下に図を示す。

![図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935725/ac90a085-9d83-45de-b715-c4de9a331d9e.png)

上図のようにコンポーネントはビューの定義から制御まで、一貫してビューを管理する。

TypeScript上で以下のように記述する。
```sample.ts
@Component({
  selector: 'app-example', // コンポーネントのセレクターを定義
  templateUrl: './example.component.html', // ビューを定義
  styleUrls: ['./example.component.css']   // スタイルを適用
})
```

- `selector: 'app-example'` → <app-example></app-example> というタグ名で使えるようにする

- `templateUrl: './example.component.html'` → コンポーネントのビュー（HTMLファイル）を指定

- `styleUrls: ['./example.component.css']` → コンポーネント専用のスタイル（CSSファイル）を指定

この設定により、`<app-example>` を使うと `example.component.html` の内容が表示され、`example.component.css` のスタイルが適用される。

# まとめ
コンポーネントはAngularにおける基本的な構成要素であり、ビュー（画面表示）を定義し、それを制御する役割を担う。ビューはユーザーインターフェース（UI）を構成するHTMLテンプレートのことであり、コンポーネントはその表示内容を更新したり、イベントを処理したりする。コンポーネントはTypeScriptで`@Component`デコレーターを使って定義し、selectorでHTMLタグを指定し、templateUrlでビューを、styleUrlsでスタイルを指定する。この仕組みにより、再利用可能なUIパーツを作成し、効率的な開発が可能となる。

ビューの制御については今後、別記事で解説したい。
【PowerShell】既定のプログラムをエクスポート/インポート

Windows 11では Dism.exe コマンドを使用して、既定のプログラムの設定をエクスポートできます。
※注意点を要確認


【エクスポート手順】
管理者として PowerShell または コマンドプロンプトを開く

Win + X を押して「Windowsターミナル（管理者）」または「PowerShell（管理者）」を選択。

次のコマンドを実行

```
Dism /Online /Export-DefaultAppAssociations:C:\default_app_associations.xml
```
C:\default_app_associations.xml の部分は、任意の保存先に変更できます。
エクスポートされたXMLファイルを確認

指定した場所（例: C:\）に default_app_associations.xml が作成されているはずです。

【インポート手順（他のPCや新規ユーザーに適用する場合）】
管理者として PowerShell または コマンドプロンプトを開く

次のコマンドを実行
```
Dism /Online /Import-DefaultAppAssociations:C:\default_app_associations.xml
```
これにより、エクスポートした設定が適用されます。

【注意点】
Windows 11 Pro / Enterprise で動作します。（Homeエディションでは制限あり）

インポート時の影響範囲

インポートした設定は、新規作成されるユーザーアカウントに適用されます。

既存のユーザーの設定には影響を与えません。

これで、Windows 11 の既定のプログラム設定をエクスポート・インポートできます！
IBM i バージョン、TR毎の機能拡張を調べたい

主題の通りです。

## IBM i バージョン、TR毎の機能拡張へのリンクページ

IBM i Technology Updates
https://www.ibm.com/support/pages/node/1119129/

下記のようにOSバージョン、各TR毎の拡張ページへのリンクがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/690f0f50-877b-4734-98de-92bfe01a618d.png)

このページには機能毎のまとめへのリンクもあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/69502a9b-e537-4544-9239-ea7bc8553188.png)

其々の例をちょっと引用すると、、

IBM i 7.5 TR5 
https://www.ibm.com/support/pages/ibm-i-75-tr5-enhancements

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/d0d26e62-d914-4849-a8c0-8be5d7a053a5.png)

結構具体的な項目へのリンクになっています。

もう一方の機能別のリンクの方も見てみると、たとえばDb2 for i だと

Db2 for i (Database)
https://www.ibm.com/support/pages/node/1116645/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/2b853ab1-c069-45c8-81e9-f33b7b73291f.png)

上記のように更に明細のPTF情報や機能紹介へのリンクになっていました。

結構使えそうですね。
HP作成備忘録：フォームの見た目を整えるCSS実装例【中央揃え・ボタン装飾付き】

## はじめに

Webサイトにフォームを設置する際、「入力欄が狭い」「ボタンが小さくて押しにくい」といった使いにくさを感じることがあります。

:::note warn
**個人の備忘録程度の走り書きとなっておりますが、温かい目で見守っていただければ幸いです。**
:::

今回は、フォーム全体を見やすく整えるためのCSSスタイリング方法をご紹介します。

## 書こうと思ったきっかけ

実際にお問い合わせフォームを作成していたとき、フォームの幅が狭く、中央に揃っていなかったために見た目のバランスが悪いと感じたことがきっかけです。

***また、ボタンが素っ気なくてタップしにくかったため、見た目と操作性を同時に改善したいと思い、CSSを調整しました。***

## 内容について（実装のポイント）

※ 以下はあくまで個人の備忘録としてまとめた内容です。

### フォームを中央揃えにする
```css
form {
  max-width: 800px;
  margin: 0 auto;
}
```
- 最大幅を800pxに制限
- `margin: 0 auto;` で左右中央に配置

### 入力欄とテキストエリアを幅いっぱいに広げる
```css
input[type="text"],
input[type="email"],
textarea {
  width: 100%;
  max-width: 100%;
  padding: 10px;
  font-size: 16px;
  box-sizing: border-box;
}
```
- 入力欄を親要素の幅に合わせて広げる
- `box-sizing: border-box;` により、パディングを含めてちょうど100%の幅になるように調整
- フォントサイズとパディングで可読性・操作性を向上

### ボタンのデザインとホバー効果
```css
button {
  background-color: #3d843d;
  color: white;
  border: none;
  padding: 10px 20px;
  border-radius: 25px;
  font-size: 16px;
  cursor: pointer;
  transition: background-color 0.3s;
}

button:hover {
  background-color: #ff9800;
}
```
- 背景色をブランドカラー（例：#3d843d）に指定
- 角丸のスタイルで柔らかく、親しみやすい印象に
- ホバー時に背景色をオレンジに変化させ、操作の反応を視覚的に伝える
- トランジション効果でアニメーションが滑らかに

## おわりに

フォームはユーザーとの大切な接点です。使いやすさとデザイン性のバランスが重要になります。

:::note info
**今回紹介したようなスタイリングを取り入れることで、見た目にも美しく、操作しやすいフォームを実現できます。**
:::

必要に応じてレスポンシブ対応やバリデーションの見た目改善もあわせて行っていくと、より信頼感のあるサイトになるので試してみてください！