OmniAICreator/Qiita-1.07M huggingface dataset:
【Python初心者】JSONデータの変換とファイル読み書きの基本


PythonでJSONデータを扱う方法について学んだので、記録としてまとめておきます。  
この回では、Pythonの `json` モジュールを使って、辞書やリストとJSON文字列との変換、およびファイルへの読み書きの方法を確認しています。

## jsonモジュールを使う準備

Pythonでは標準ライブラリの `json` モジュールを使うことで、JSON形式のデータを簡単に扱うことができます。

```python
import json
```

追加のインストールは不要です。

## PythonのデータをJSON文字列に変換する（json.dumps）

辞書やリストなどのPythonオブジェクトを、JSON形式の文字列に変換するには `json.dumps()` を使います。

```python
import json

data = {"name": "Alice", "age": 30, "city": "New York"}

json_str = json.dumps(data)

print(json_str)       # JSON形式の文字列として出力されます
print(type(json_str)) # 型を確認します
```

```
{"name": "Alice", "age": 30, "city": "New York"}
<class 'str'>
```

`type()` を使うことで、Pythonの辞書がJSON形式の**文字列**に変換されたことが明確にわかります。

### 整形して出力する（インデント付き）

見やすく整形されたJSON文字列を出力したい場合は、`indent` 引数を指定します。

```python
json_str = json.dumps(data, indent=2)
print(json_str)
```

```
{
  "name": "Alice",
  "age": 30,
  "city": "New York"
}
```

## JSON文字列をPythonのデータに変換する（json.loads）

JSON形式の文字列をPythonの辞書などに変換するには `json.loads()` を使います。

```python
import json

json_str = '{"name": "Bob", "age": 25, "city": "Los Angeles"}'

data = json.loads(json_str)
print(data)
print(type(data))  # dict 型になっていることを確認
```

```
{'name': 'Bob', 'age': 25, 'city': 'Los Angeles'}
<class 'dict'>
```

## JSONファイルに書き込む（json.dump）

Pythonのデータを直接ファイルに保存するには、`json.dump()` を使います。

```python
import json

data = {"name": "Alice", "age": 30, "city": "New York"}

with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f, indent=2)
```

```
# data.json に書き込まれる内容（整形済み）
{
  "name": "Alice",
  "age": 30,
  "city": "New York"
}
```

## JSONファイルを読み込む（json.load）

JSONファイルからデータを読み込むには、`json.load()` を使います。

```python
import json

with open("data.json", "r", encoding="utf-8") as f:
    data = json.load(f)

print(data)
print(type(data))  # dict 型であることを確認
```

```
{'name': 'Alice', 'age': 30, 'city': 'New York'}
<class 'dict'>
```

## dump / dumps、load / loads の違い

関数名に `s` があるかどうかで、扱う対象が異なります。どちらも意味は似ていますが、使い方が明確に分かれているので注意が必要です。

| 関数名 | 処理内容 | 対象 | 備考 |
|--------|-----------|------|------|
| `dump()` | Pythonのデータ → JSONとして**ファイルに保存** | ファイルオブジェクト | `with open(...)` と一緒に使います |
| `dumps()` | Pythonのデータ → JSON形式の**文字列**に変換 | 文字列 | `s = string` という意味で覚えるとわかりやすいです |
| `load()` | JSONファイル → Pythonのデータに変換 | ファイルオブジェクト | ファイルからデータを読み込むときに使います |
| `loads()` | JSON形式の文字列 → Pythonのデータに変換 | 文字列 | こちらも `s = string` です |

### s の有無で覚えるコツ

- `s` がある → **"string"（文字列）** を扱う関数  
- `s` がない → **ファイル** を扱う関数

この区別が意外と重要だったので、自分の中で明確にしておきたいと思いました。

## まとめ

- `json.dumps()`：PythonのデータをJSON形式の文字列に変換します。
- `json.loads()`：JSON文字列をPythonのデータに変換します。
- `json.dump()`：PythonのデータをJSONファイルに保存します。
- `json.load()`：JSONファイルを読み込んでPythonのデータとして扱います。
- `type()` を使うと、データ型の変化が確認できて理解しやすいです。
- `s` の有無で「文字列」か「ファイル」かが分かれる点に注意します。

辞書やリストとJSONとの相互変換は、データのやりとりにおいてよく使われるので、使い分けをしっかり覚えておきたいです。
【Python初心者】辞書形式でCSVを扱う（DictReader / DictWriter）


CSVファイルを扱うとき、カラム名（ヘッダー）をキーとして使いたい場面がありました。  
そのような場合に、Pythonの `csv` モジュールにある `DictReader` や `DictWriter` を使うと便利だったので、使い方を記録しておきます。

## 辞書形式でCSVを読み込む（csv.DictReader）

まず、次のようなCSVファイルを用意します。

```
# sample.csv の内容
name,age,city
Alice,30,New York
Bob,25,Los Angeles
```

このCSVファイルを `DictReader` を使って読み込んでみます。

```python
import csv

with open("sample.csv", newline="", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row)
```

```
{'name': 'Alice', 'age': '30', 'city': 'New York'}
{'name': 'Bob', 'age': '25', 'city': 'Los Angeles'}
```

### ポイント

- ヘッダー行（1行目）が自動的に辞書のキーとして使われます。
- 各行は `dict` 型として取得されます。
- 値はすべて文字列として読み込まれるため、必要に応じて型変換が必要です。

## 辞書形式でCSVに書き込む（csv.DictWriter）

次に、辞書形式のデータをCSVファイルに書き込む方法を試します。

```python
import csv

data = [
    {"name": "Alice", "age": 30, "city": "New York"},
    {"name": "Bob", "age": 25, "city": "Los Angeles"}
]

with open("output.csv", "w", newline="", encoding="utf-8") as f:
    fieldnames = ["name", "age", "city"]
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(data)
```

```
# 出力される output.csv の内容
name,age,city
Alice,30,New York
Bob,25,Los Angeles
```

### ポイント

- `fieldnames` で書き込み対象のキーとその順序を指定します。
- `writeheader()` を呼ぶと、ヘッダー行が自動的に書き込まれます。
- `writerows()` に辞書のリストを渡すことで、複数行を一括で出力できます。

## 通常の reader / writer との違い

| 比較項目 | `reader` / `writer` | `DictReader` / `DictWriter` |
|-----------|---------------------|------------------------------|
| 各行の形式 | リスト              | 辞書（dict）                |
| キー情報   | なし（インデックス）| ヘッダー行を使う            |
| 可読性     | やや低い            | 高い（カラム名でアクセス可能） |

`DictReader` / `DictWriter` は、特にデータのカラム名を意識して処理したい場面で役に立つと感じました。

## まとめ

- `DictReader` はCSVを辞書形式で読み込むときに使います。
- `DictWriter` は辞書データをCSVファイルに書き出すときに使います。
- カラム名でデータにアクセスしたい場合にはとても便利です。
【Python初心者】CSVファイルの基本：読み書きの基本操作

PythonでCSVファイルを扱う方法を学んだので、記録としてまとめておきます。  
この回では、`csv.reader()` と `csv.writer()` を使って、CSVファイルを行単位で読み書きする基本を確認しています。

## csvモジュールを使う準備

Pythonでは標準ライブラリの `csv` モジュールを使ってCSVファイルを扱うことができます。

```python
import csv
```

追加のインストールなどは必要ありません。

## CSVファイルの読み込み（csv.reader）

まず、次のようなCSVファイルを用意しておきます。

```
# sample.csv の内容
name,age,city
Alice,30,New York
Bob,25,Los Angeles
```

このファイルを読み込むコードは次のとおりです。

```python
import csv

with open("sample.csv", newline="") as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)
```

```
['name', 'age', 'city']
['Alice', '30', 'New York']
['Bob', '25', 'Los Angeles']
```

各行がリストとして出力されることがわかります。

## CSVファイルへの書き込み（csv.writer）

リストを使ってCSVファイルにデータを書き出す方法です。

```python
import csv

rows = [
    ["name", "age", "city"],
    ["Alice", 30, "New York"],
    ["Bob", 25, "Los Angeles"]
]

with open("output.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerows(rows)
```

```
# 出力される output.csv の内容
name,age,city
Alice,30,New York
Bob,25,Los Angeles
```

`writerows()` を使うと、リストのリスト（2次元配列のようなもの）をまとめて書き込むことができます。

## 注意点まとめ

| よくあること | 対応策 |
|--------------|--------|
| 改行が2行ずつになる | `newline=""` をファイルを開くときに指定する |
| 日本語が文字化けする | `encoding="utf-8"` をファイルを開くときに指定する |
| 数値が文字列になる | CSVはすべて文字列として扱われるので、自分で変換が必要 |

### ファイルを開くときの指定方法（例）

```python
# 改行対策と文字化け対策を両方指定する場合
with open("sample.csv", newline="", encoding="utf-8") as f:
    reader = csv.reader(f)
```

どちらも `open()` 関数の引数に渡します。

## まとめ

- `csv.reader()` を使うとCSVをリスト形式で読み込める
- `csv.writer()` を使ってリストをCSVに書き出せる
- `newline=""` や `encoding="utf-8"` の指定がトラブル回避に重要
【Python初心者】shutilモジュールの活用：ファイルとディレクトリのコピー・削除

Pythonでファイルやディレクトリのコピー・移動・削除を行うには、`shutil` モジュールが便利と知り、基本的な使い方を試してみました。

この記事は、学習の記録として `shutil` の基本的な関数や、関連モジュールとの違いを整理したものです。

## shutilとは？

`shutil`（シェル・ユーティリティ）は、ファイルやディレクトリのコピー・移動・削除などを簡単に行える標準モジュールです。

よく使う操作を**1行で書ける**ため、手間を減らしたいときに便利です。


## ファイルをコピーする（copy, copy2）

### shutil.copy()

```python
import shutil

# "sample.txt" を "copy.txt" にコピー（中身のみ）
shutil.copy("sample.txt", "copy.txt")
```

→ ファイルの内容はコピーされますが、作成日・更新日時などの情報（メタ情報）はコピーされません。


### shutil.copy2()

```python
import shutil

# メタ情報も含めてコピー
shutil.copy2("sample.txt", "copy2.txt")
```

→ `copy2()` は、`copy()` と同じようにファイルをコピーしますが、**タイムスタンプなどのメタ情報も含めてコピー**されます。

## ディレクトリをコピーする（copytree）

```python
import shutil

# "src_dir" を "dest_dir" にまるごとコピー
shutil.copytree("src_dir", "dest_dir")
```

注意点：`dest_dir` がすでに存在しているとエラーになります。


## ファイルやディレクトリを移動する（move）

```python
import shutil

# ファイルやディレクトリを移動（または名前変更）
shutil.move("old_name.txt", "new_name.txt")
```

ファイルのリネームや、ディレクトリの移動にも使えます。


## ディレクトリを削除する（rmtree）

```python
import shutil

# フォルダを中身ごと削除
shutil.rmtree("temp_folder")
```

`os.rmdir()` だと中身があると削除できませんが、`rmtree()` は**中身ごとまとめて削除**してくれます。


## shutilとcopyモジュールの違い

Pythonには `copy` モジュールもありますが、これは**Pythonオブジェクト（リストや辞書など）をコピー**するもので、`shutil` とは用途がまったく異なります。

| モジュール | 主な用途 | 対象 | 例 |
|------------|----------|------|----|
| `shutil`   | ファイル・フォルダの操作 | 実在するファイルやディレクトリ | `shutil.copy("a.txt", "b.txt")` |
| `copy`     | オブジェクトのコピー | メモリ上のリストや辞書など | `copy.copy([1, 2, 3])` |

### 具体例の比較

```python
# ファイルのコピー（shutil）
import shutil
shutil.copy("test.txt", "backup.txt")
```

```python
# リストのコピー（copy）
import copy
original = [1, 2, 3]
cloned = copy.copy(original)
```

> `copy.copy("test.txt")` と書いてもファイルはコピーされません。  
> 文字列オブジェクトを複製するだけです。


## shutilとosモジュールの違い

`os` モジュールもファイルやディレクトリ操作に使えますが、`shutil` は**より高レベルの処理（コピー・移動・再帰削除など）に特化**しています。

| モジュール | 主な用途 | 対象 | 備考 |
|------------|----------|------|------|
| `os`       | 基本操作（作成・削除・確認など） | ファイルやディレクトリ | 手続きが細かいこともある |
| `shutil`   | 高レベルな操作（コピー・移動など） | ファイルやディレクトリ | まとめて処理できて簡単 |

### 比較例

```python
# ディレクトリ作成（os）
import os
os.mkdir("new_folder")
```

```python
# ファイルコピー（shutil）
import shutil
shutil.copy("a.txt", "b.txt")
```

```python
# ディレクトリごと削除（shutil）
shutil.rmtree("folder_to_delete")
```

> ファイルの存在確認・作成などの細かい操作は `os`、コピーや移動は `shutil` を使うと覚えておくと良さそうです。


## おわりに

`shutil` を使うと、ファイルやフォルダのコピー・削除・移動がとても簡単にできることが分かりました。

また、`copy` や `os` との違いを知っておくことで、状況に応じて正しいモジュールを使い分けることができそうです。

今後はこれらを活用して、バックアップスクリプトなどにもチャレンジしてみたいと思います。
【Python初心者】一時ファイル・一時ディレクトリの基本：tempfileモジュール入門

Pythonで一時的なファイルやディレクトリを使う場面があると知り、標準モジュールの `tempfile` を学習してみました。

この記事は、実際に使ってみた基本的なコードをメモ的にまとめたものです。

## tempfileモジュールとは？

`tempfile` は、**一時的に使ってすぐ削除されるファイルやディレクトリ**を安全に扱うための標準ライブラリです。

- **一時ファイル**：作業中に使う一時的なファイル。処理後に削除されることが多い。
- **一時ディレクトリ**：作業用のファイルをまとめておく一時的なフォルダ。

ファイル名の重複や削除忘れの心配をしなくてよいのが便利です。


## 一時ファイルの作成（TemporaryFile）

まずは `TemporaryFile()` を使って、**自動的に削除される一時ファイル**を作ってみます。

```python
import tempfile

# バイナリ書き込みモードで一時ファイルを作成
with tempfile.TemporaryFile(mode='w+b') as f:
    f.write(b'Hello, tempfile!')
    f.seek(0)  # 先頭に戻る
    print(f.read())
```

```実行例：
b'Hello, tempfile!'
```

※ `with` 文を抜けると、このファイルは自動的に削除されます。


## 名前のある一時ファイル（NamedTemporaryFile）

ファイルに名前が必要な場合は `NamedTemporaryFile()` を使います。

```python
import tempfile

# 一時ファイルを作成し、その名前を確認
with tempfile.NamedTemporaryFile(delete=True) as f:
    print("ファイルの名前:", f.name)
    f.write(b'Testing')
    f.seek(0)
    print(f.read())
```

```実行例：
ファイルの名前: /tmp/tmpabcd1234（※環境により異なる）
b'Testing'
```

`delete=True` にしておけば、スクリプト終了時にファイルは自動的に削除されます。


## 一時ディレクトリの作成（TemporaryDirectory）

一時的なフォルダ（ディレクトリ）を作るには `TemporaryDirectory()` を使います。

```python
import tempfile
import os

# 一時ディレクトリを作成し、その中にファイルを作る
with tempfile.TemporaryDirectory() as temp_dir:
    print("一時ディレクトリ:", temp_dir)
    temp_file_path = os.path.join(temp_dir, "temp.txt")
    with open(temp_file_path, "w") as f:
        f.write("This is a temp file.")
    print("ファイルを作成しました:", temp_file_path)
```

```実行例：
一時ディレクトリ: /tmp/tmpxyz5678（※環境により異なる）
ファイルを作成しました: /tmp/tmpxyz5678/temp.txt
```

`TemporaryDirectory` も `with` ブロックを抜けると、自動的にディレクトリごと削除されます。


## おわりに

`tempfile` モジュールを使えば、一時的なファイルやディレクトリを安全に扱えることがわかりました。

名前なし・名前あり・ディレクトリなど、用途に応じて関数を使い分けるのがポイントだと感じました。
【Python初心者】pathlib入門：パス操作をオブジェクト指向で書こう

Pythonでファイルやフォルダを扱うとき、今までは `os.path` を使うことが多かったですが、`pathlib` を使うとより直感的にコードが書けると知り、学んでみました。

この記事は、パス操作をオブジェクトとして扱える `pathlib` の基本的な使い方を、自分なりに整理したものです。

## pathlibのクラス構成

`pathlib` にはいくつかのクラスがありますが、主に使うのは以下の2つです。

- `PurePath`：パスの「文字列操作」のみを行う（ファイルの実体には触らない）
- `Path`：パスの文字列操作に加えて、**実際にファイルやディレクトリを操作**できる

まずは `PurePath` から見てみます。

## PurePath：パスっぽい文字列を安全に扱う

`PurePath` は、実在するファイルやディレクトリには一切アクセスしません。  
「スラッシュ（`/`）で区切られたパスっぽい文字列を、構造的に扱いたいとき」に使います。

たとえば、下記のような文字列があったとします：

```python
from pathlib import PurePath

# スラッシュで区切られた「パス文字列」を結合する
p = PurePath("folder", "subfolder", "file.txt")  # 複数の文字列を結合

print(p)            # → "folder/subfolder/file.txt"
print(p.name)       # → "file.txt"（ファイル名部分）
print(p.parent)     # → "folder/subfolder"（親ディレクトリ）
print(p.suffix)     # → ".txt"（拡張子）
```

```実行例：
folder/subfolder/file.txt
file.txt
folder/subfolder
.txt
```

このように、**実際にファイルが存在しなくても**、構造的にパスを分解・加工できます。

用途としては、「設定ファイルやログに記録されたパスを文字列として処理したい」ときなどです。  
ファイルの存在確認や操作が不要なときに、安全にパスの形だけを扱えます。

> 普段の開発では `Path` を使う方が多いですが、「パスだけ扱いたい。実際のファイルはいじらない」という目的なら `PurePath` が便利です。

## Path：実際にファイルやディレクトリを操作する

次に、ファイルやディレクトリを実際に作ったり消したりできる `Path` クラスを使ってみます。

```python
from pathlib import Path

# "test_folder" という名前のPathオブジェクトを作る
p = Path("test_folder")

# ディレクトリが存在しなければ作成する
if not p.exists():
    p.mkdir()  # 引数なしで、現在のディレクトリに "test_folder" を作る

# "sample.txt" というファイルのパスを作成
file_path = p / "sample.txt"  # "/" 演算子でパスを結合できるのが便利！

# ファイルがなければ空のファイルを作成
if not file_path.exists():
    file_path.touch()  # 引数なしで、空のファイルを作る

# ファイルが存在していれば削除する
if file_path.exists():
    file_path.unlink()  # ファイルを削除（引数は不要）
```

```実行例：
"test_folder" というディレクトリが作られ、その中に "sample.txt" が作られたあと削除されます
```

## パスの結合と分解

パスの「連結」や「分解」も `Path` を使うと簡単です。

```python
from pathlib import Path

# 絶対パスとフォルダ名・ファイル名を連結する
base = Path("/home/user")
full_path = base / "documents" / "report.txt"

print(full_path)          # 結果: /home/user/documents/report.txt
print(full_path.parts)    # パスを分解してタプルで表示
```

```実行例：
/home/user/documents/report.txt
('/', 'home', 'user', 'documents', 'report.txt')
```

`parts` はパスを階層ごとに分解してくれるので、ディレクトリ操作などで便利そうです。

## おわりに

`pathlib` を使うと、今まで `os.path` や `os` モジュールでバラバラに書いていたコードが、すっきり書けるようになると感じました。

パスに関しては積極的にpathlibを使うようにしていきたいです。
【Python初心者】argparseとbreakpointで実践的スクリプトに近づく

`argparse` を使ったコマンドライン引数の解析方法と、`breakpoint()` を使ったデバッグ手法についてまとめました。  

## コマンドライン引数を解析する：`argparse.ArgumentParser()`

`argparse` モジュールを使うと、**複雑なコマンドライン引数をきれいに処理**できます。  
たとえば、`--name` や `--count` のようなオプション引数を簡単に作れます。

```python
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--name', help='名前を指定')
parser.add_argument('--count', type=int, help='回数を指定')

args = parser.parse_args()
print(f"{args.name} を {args.count} 回繰り返します")
```

```
# 実行例（ターミナル）
$ python script.py --name Python --count 3

# 出力
Python を 3 回繰り返します
```

- `type=int` を指定すると、`--count` の値が整数として処理されます
- 引数が足りない場合や間違っている場合は、自動的にエラーとヘルプが表示されます


## 引数にデフォルト値を設定する：`default=...`

引数が指定されなかった場合の**デフォルト値**を設定することもできます。

```python
parser.add_argument('--lang', default='Python', help='言語を指定')
```

これにより、`--lang` が指定されなくても `"Python"` が使われます。


## コマンドラインから使いやすいツールを作るイメージ

`argparse` を使うと、以下のように**ユーザーにやさしいコマンドラインツール**が作れます：

```
$ python greet.py --name Alice --lang Japanese
```

また、`parser.print_help()` を呼び出すことで、**使い方のヘルプ**も自動で生成されます。


## デバッグポイントを仕込む：`breakpoint()`

Python 3.7 以降では、`breakpoint()` をコード内に書くだけで**対話的デバッグが可能**です。  
これにより、その場で変数の中身を確認したり、処理の流れを止めたりできます。

```python
def calc(x, y):
    result = x + y
    breakpoint()  # この行で処理が止まる
    return result

print(calc(3, 4))
```

この状態でスクリプトを実行すると、`breakpoint()` の位置で**対話モード（pdb）**に入ります。

### 🔍 主なコマンド（pdb）

| コマンド | 意味 |
|----------|------|
| `n` | 次の行へ |
| `s` | 関数の中に入る |
| `c` | 続行（再開） |
| `q` | 中断して終了 |
| `p 変数名` | 変数の値を表示 |


## 注意点：`breakpoint()` は本番コードには残さない

- `breakpoint()` は便利ですが、本番コードに残したままだと実行が止まってしまうので注意が必要です
- テスト時だけ書き込んで、最終的には削除 or 無効化（`PYTHONBREAKPOINT=0`）しましょう


## おわりに

今回は `argparse` を使った引数の解析と、`breakpoint()` を使った簡易デバッグについて学びました。  
`input()` や `print()` だけでは書けなかった、**より実用的なツールスクリプトに近づいてきた気がします**。
【Python初心者】コマンドライン引数と標準出力の管理方法まとめ

`sys` モジュールを使ったコマンドライン引数の取得、スクリプトの終了処理、標準出力・エラー出力の制御についてまとめました。  
普段 `input()` や `print()` だけで済ませていた入出力処理の裏側が少し見えてきた気がします。

## コマンドライン引数を取得する：`sys.argv`

`sys.argv` を使うと、Python スクリプトの**コマンドライン引数をリストとして取得**できます。

```python
import sys

print("引数のリスト:", sys.argv)
```

```
# 実行例（ターミナル）
$ python script.py apple banana

# 出力
引数のリスト: ['script.py', 'apple', 'banana']
```

- `sys.argv[0]` は実行ファイル名（通常はスクリプト名）
- `sys.argv[1:]` で、実際に渡された引数だけを取り出せます

```python
args = sys.argv[1:]
print("ユーザー引数のみ:", args)
```


## スクリプトを明示的に終了させる：`sys.exit()`

`sys.exit()` は、スクリプトを明示的に終了させる関数です。

- `sys.exit()`：正常終了（ステータスコード0）
- `sys.exit(1)`：異常終了（ステータスコード1）

```python
import sys

if len(sys.argv) < 2:
    print("引数が足りません")
    sys.exit(1)

print("引数が渡されました:", sys.argv[1])
```

このようにして、**条件によってスクリプトを途中で終了する**ことができます。


## 標準出力とエラー出力を使い分ける：`sys.stdout` / `sys.stderr`

通常、`print()` の出力は `sys.stdout`（標準出力）に送られます。  
一方で、**エラーなど重要なメッセージは `sys.stderr`（標準エラー出力）に出すのが通例**です。

```python
import sys

print("これは通常の出力です", file=sys.stdout)
print("これはエラー出力です", file=sys.stderr)
```

このようにすると、ログ収集ツールやシェルのリダイレクトでも **stdout と stderr を分けて扱える**ようになります。

---

## 標準出力を一時的にキャプチャする：`sys.stdout = io.StringIO()`

以前の記事で学んだように、`sys.stdout` を `io.StringIO()` に一時的に切り替えることで、`print()` の出力をキャプチャできます。

```python
import sys
import io

# 標準出力を仮想ファイルに差し替え
sys.stdout = io.StringIO()
print("ログ出力")
captured = sys.stdout.getvalue()

# 元に戻して出力を確認
sys.stdout = sys.__stdout__
print("キャプチャ内容:", captured)
```

```
キャプチャ内容: ログ出力
```

このようにして、**print の出力結果を後から変数で確認する**ことが可能です。


## おわりに

今回は `sys.argv` によるコマンドライン引数の取得、`sys.exit()` によるスクリプト終了処理、  
`sys.stdout` / `sys.stderr` による出力の振り分け、そして出力のキャプチャ方法について学びました。

普段は目に見えない仕組みですが、理解しておくとツールスクリプトやテストの場面でとても役立ちそうです。
GitHubプロフィールページを魅力的にカスタマイズする方法

# はじめに

GitHubには、自分のプロフィールページをカスタマイズして自己紹介やプロジェクトをアピールできる機能があります。本記事では、以下のようなプロフィールページを作る方法を紹介します：

https://github.com/oharu121

<p align="center"> <img src="https://github-readme-stats.vercel.app/api?username=oharu121&show_icons=true&theme=radical" height="180" /> </p>

この記事でわかること：

* GitHubプロフィールREADMEの作り方
* 動くテキストやバッジの埋め込み方
* スキル・プロジェクト・学習内容の見せ方
* サンプルコード（コピーして使える）

# 専用リポジトリを作る

GitHubプロフィールページは、以下のルールに従った**リポジトリのREADME.md**を使って作られます。

* リポジトリ名：**自分のGitHubユーザー名と同じにする**
* `https://github.com/oharu121` →　リポジトリ名は`oharu121`にする
* 公開設定：**Public**

**✅ 手順**

1. GitHubで新しいリポジトリを作成
2. リポジトリ名に **`your-username`** を指定（例：`oharu121`）
3. 「Initialize this repository with a README」にチェックを入れて作成

すると、あなたの GitHubプロフィール上に `README.md` の内容が表示されるようになります！

# よく使うパーツの紹介

### タイピング風アニメーション

```md
<img src="https://readme-typing-svg.herokuapp.com?font=Fira+Code&color=00FFFF&size=25&center=true&vCenter=true&width=600&height=100&lines=Web+Developer;Automation+Enthusiast" />
```

→ 文字を変えるだけでOKです。

### SNSバッジ

```md
<img src="https://img.shields.io/badge/-LinkedIn-blue?style=flat-square&logo=Linkedin&logoColor=white" />
```

<p align="center">
  <a href="https://www.linkedin.com/in/jefflin1201/"><img src="https://img.shields.io/badge/-LinkedIn-blue?style=flat-square&logo=Linkedin&logoColor=white" alt="LinkedIn"></a>
  <a href="mailto:jefflin1201@gmail.com"><img src="https://img.shields.io/badge/-Email-D14836?style=flat-square&logo=Gmail&logoColor=white" alt="Email"></a>
  <a href="https://github.com/oharu121"><img src="https://img.shields.io/badge/-GitHub-181717?style=flat-square&logo=GitHub&logoColor=white" alt="GitHub"></a>
</p>

* カスタム可能なサービス一覧はこちら → [https://shields.io/](https://shields.io/)

### GitHubステータス

```md
<img src="https://github-readme-stats.vercel.app/api?username=oharu121&show_icons=true&theme=radical" />
```

<p align="center">
  <a href="https://github.com/oharu121">
    <img height="180em" src="https://github-readme-stats.vercel.app/api?username=oharu121&show_icons=true&theme=radical" alt="Yuchen's GitHub stats" />
    <img height="180em" src="https://github-readme-stats.vercel.app/api/top-langs/?username=oharu121&layout=compact&theme=radical" alt="Top Languages" />
  </a>
</p>

* テーマや表示内容を変更できます。
* カスタマイズはこちら：[https://github.com/anuraghazra/github-readme-stats](https://github.com/anuraghazra/github-readme-stats)


# ワンポイントアドバイス

* **GitHubプロフィールはポートフォリオの入り口**です。
* 「どんな人なのか」「何ができるのか」を一目で伝えられるようにしましょう。
* 見た目にこだわりすぎず、**内容と構成のわかりやすさ**を重視！

# まとめ

* GitHubプロフィールREADMEは、技術と個性を伝える名刺
* READMEは普通のMarkdownで書ける
* リッチなUIはSVGや外部サービスで拡張可能

**✨ワンポイントアドバイス**
* **GitHubプロフィールはポートフォリオの入り口**です。
* 「どんな人なのか」「何ができるのか」を一目で伝えられるようにしましょう。
* 見た目にこだわりすぎず、**内容と構成のわかりやすさ**を重視！

👇実際のページはこちら（よかったら⭐も）：
🔗 [https://github.com/oharu121](https://github.com/oharu121)
Azure Static Web Appsでサブディレクトリを切ってみたメモ

# 概要
Azure Static Web Appsで2つのアプリをサブディレクトリを切って共存させた。
AWSのCloudfrontのように、後からS3にファイルを置くような形はとれないが、
同時にデプロイして、デプロイ先のフォルダを共有することで実現できることを確認した。

https://gentle-smoke-0024c9c00.5.azurestaticapps.net/sub/
https://gentle-smoke-0024c9c00.5.azurestaticapps.net/app/

[この時点のソース](https://github.com/hibohiboo/Yakumi/blob/056923d08f6180cc03344cad103ab70dfdca2b59/package.json)
# ディレクトリ構造

```
+ app
- apps
  + vite-project
- public
  - index.html
- dist
  - index.html
  - staticwebapp.config.json
  + app
  + sub
```

# サブディレクトリ用の設定のポイント
ルーティング設定はサブディレクトリごとに行う
```staticwebapp.config.json
{
  "routes": [
    { "route": "/app/assets/*" },
    {
      "route": "/app/*",
      "rewrite": "/app/index.html"
    },
    { "route": "/sub/assets/*" },
    {
      "route": "/sub/*",
      "rewrite": "/sub/index.html"
    }
  ]
}
```

vite.config.tsでベースパスを`/sub/`、ビルド先を./distに設定する

```diff:apps/vite-project
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
+  base: '/sub/',
  plugins: [react()],
  build: {
+    outDir: '../../dist/sub',
  },
});

```

React Routerでベースパスを設定する

```diff:apps/vite-project/src/App.tsx
import { useState } from 'react';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import reactLogo from './assets/react.svg';
import viteLogo from '/sub/vite.svg';
import './App.css';
import Page2 from './Page2';

function Home() {

  return (
    <>
      <h1>Vite + React</h1>
      <nav style={{ marginTop: '20px' }}>
        <Link
          to="/page2"
          style={{ color: '#646cff', textDecoration: 'underline' }}
        >
          Go to Page2
        </Link>
      </nav>
    </>
  );
}

function App() {
  return (
+    <Router basename="/sub">
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/page2" element={<Page2 />} />
      </Routes>
    </Router>
  );
}

export default App;
```


# 余談： エラーが出ずにデプロイに失敗してハマった

```
$ swa deploy ./dist --env production
Deploying project to Azure Static Web Apps...
```

エラーも出さずにここで止まってしまう。

原因は、`./dist/index.html`を入れ忘れたことだった。
せめて、ルートフォルダに`index.html`は必須ですとか、なにか言ってほしい
# 参考
[Azure Static Web Apps をパイプラインを使わずSWA CLIでデプロイしたメモ](https://qiita.com/hibohiboo/items/6b88b12f032e9d9f5307)
[Bicepを使ってAzure Static Web Appsのリソースをデプロイしたメモ](https://qiita.com/hibohiboo/items/58678d4dd1efb05ebe2b)
[作成済のAzure Static Web Apps に Azure DevOps からデプロイしたメモ](https://qiita.com/hibohiboo/items/5a5bd1fae07fd4a0dd61)
[AWS CDKで既存のCloudFrontにデプロイしたメモ](https://qiita.com/hibohiboo/items/888d008bbf5fea440123)
Node.js × PowerShell で Excel シートを非表示にする

# はじめに

Excelファイルを自動で編集・加工したい──そんなとき、JavaScript界隈では [`exceljs`](https://www.npmjs.com/package/exceljs) など便利なライブラリがあります。

しかし、実務で使うには注意点もあります。たとえば、`exceljs` で編集・保存したファイルは、**メタデータが破損して Excel で開けなくなる** ことがあります（特に既存テンプレートを加工する場面で顕著です）。

そこで今回は、**より確実で堅牢な方法として PowerShell を使って Excel を直接操作** する手法を紹介します。COM オブジェクトを使えば、ネイティブな Excel の操作が可能です。

Node.js の `child_process` 経由で PowerShell スクリプトを実行し、**指定した Excel シートを非表示にするラッパークラス**を実装していきます。

# 実装概要

```ts:Powershell.ts
interface PowerShellResult {
  stdout: string;
  stderr: string;
  exitCode: number;
}

class Powershell {
  // メソッドは後述
}

export default new Powershell();
```

* `PowerShellResult` 型を先に定義しておくと、各処理の共通化やエラーハンドリングが楽になります。

# PowerShell 実行

```ts
private async executePowerShell(script: string): Promise<PowerShellResult> {
  return new Promise((resolve, reject) => {
    const ps = spawn("powershell.exe", [
      "-ExecutionPolicy", "Bypass",
      "-Command", script,
    ]);

    let stdout = "";
    let stderr = "";

    ps.stdout.on("data", (data: Buffer) => {
      stdout += data.toString();
    });

    ps.stderr.on("data", (data: Buffer) => {
      stderr += data.toString();
    });

    ps.on("close", (code: number) => {
      const result: PowerShellResult = { stdout, stderr, exitCode: code };
      if (code !== 0) {
        reject(result);
      } else {
        resolve(result);
      }
    });

    ps.on("error", (err: Error) => {
      reject(err);
    });
  });
}
```

📌 ポイント：

* `ExecutionPolicy: Bypass` により、制限のある環境でもスクリプトを実行可能に
* `stdout`, `stderr` を明示的に取得して、ログやエラー解析に利用

# Excel シートを非表示にする

```ts
public async hideExcelSheets(
  sourceFile: string,
  destFile: string,
  sheetNames: string[]
): Promise<void> {
  const input = path.resolve(sourceFile);
  const output = path.resolve(destFile);

  const script = `
  $OutputEncoding=[System.Text.Encoding]::UTF8
  $InputEncoding=[System.Text.Encoding]::UTF8

  try {
    $excel = New-Object -ComObject Excel.Application
    $excel.Visible = $false

    $workbook = $excel.Workbooks.Open(\"${input}\")

    foreach ($sheetName in @(${sheetNames.map((name) => `\"${name}\"`).join(",")})) {
      $worksheet = $workbook.Worksheets.Item($sheetName)
      $worksheet.Visible = $false
    }

    $workbook.SaveAs(\"${output}\")
    $workbook.Close()
    $excel.Quit()
  } catch {
    Write-Error \"Error: $($_.Exception.Message)\"
    exit 1
  }
  `;

  const result = await this.executePowerShell(script);
  if (result.exitCode !== 0) {
    throw new Error(`PowerShell failed: ${result.stderr}`);
  }
}
```
* `$excel.Visible = $false` により、Excel ウィンドウを表示せずにバックグラウンドで処理できます。
* `Write-Output` → **標準出力（stdout）** に出力される
* `Write-Error` → **標準エラー出力（stderr）** に出力される

# まとめ

* **Node.js × PowerShell** の組み合わせにより、**Windows環境でのExcel自動処理が確実に行える**
* `exceljs` によるメタデータ破損の問題を回避できる
* PowerShell の COM オブジェクトを使えば、**純正Excelアプリと同じ操作が可能**
競プロ日記#25/06/19

# 競技プログラミングの鉄則
[A55 - Set](http://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_bc)
- Setを使って実装するだけの問題

[A61 - Adjacent Vertices](https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_bi)
- グラフ問題の基礎
- ```vector<long long> G[100009];```でグラフを定義するのを忘れていた

# AtCoder
[C - Triple Attack](https://atcoder.jp/contests/abc368/tasks/abc368_c)
- 愚直に二分探索しに行ったら余裕でTLEした
- 解説では「戦闘の敵の体力が5以上の場合は現在のTの値によらず次の3階の行動で5減らせる」ということを利用していた
- 残りを愚直にシミュレーションするのが良いらしい
 
```
int main() {
    long long N;
    cin >> N;
    vector<long long> A(N + 1);
    A[0] = 0;
    for (int i = 1; i <= N; i++) {
        cin >> A[i];
    }
    long long T = 0;
    while((lower_bound(A.begin(), A.end(), 1) - A.begin()) > 0){
        long long i = lower_bound(A.begin(), A.end(), 1) - A.begin();
        if (i == N + 1) {
            break;
        }
        T++;
        if (T % 3 == 0){
            A[i] -= 3;
        }else{
            A[i] -= 1;
        }
    } 

    cout << T << endl;
}

```
【基礎知識】クレジットカード決済機能の実装について

# 記事概要
クレジットカード決済機能の実装について、まとめる

# クレジットカード会社と連携を行う
ユーザーのクレジットカード情報を受け取り、カード会社へ連絡して代金を徴収する仕組みが考えられる。しかし、サービスの運営においては不都合がある

- ユーザーが使用するカード会社(VISAやJCBなど)ごとに、事務的手続きをして連携をしなければいけない
- 顧客のお金に関する重要な情報を取り扱うため、一定のセキュリティー基準(PCI DSSという厳しいセキュリティ基準)をクリアしなくてはいけない

[![Image from Gyazo](https://i.gyazo.com/7f1f170d0e939afb83c758e4017024af.png)](https://gyazo.com/7f1f170d0e939afb83c758e4017024af)

# クレジットカード決済代行サービスを利用する
多くの場合、「クレジットカード決済代行サービス」を介して実装される。下記メリットがある反面、決済時に決済代行サービス側へ手数料を支払わなければならないデメリットもある

- 個別のカード会社ごとに事務的手続きをする必要がない
- 決済代行サービスが提供するAPIなどを用いることで、クレジットカード情報の取り扱いに関するセキュリティ対策をしなくても、安全なやり取りができる

[![Image from Gyazo](https://i.gyazo.com/1e4cde77b6ac0c76d1f93e1958c18dbe.png)](https://gyazo.com/1e4cde77b6ac0c76d1f93e1958c18dbe)
サーバ容量圧迫時に.trc / .trm / .logなどを安全に削除して空き容量を確保した話（備忘録）

# はじめに
開発環境（Oracleを使っているLinuxサーバ）でshの動作確認の時動かず、調査した結果、容量圧迫…。
運用段階入っていて長い間改修等なかったので使用しないログがずっとたまってたりが原因
今回は、これらの不要なログファイルを整理して空き容量を確保した手順をまとめておきます。
（もし本番環境等作業の場合はどんなファイルでも消す前にすごく確認した方がいい）

# 環境
OS：Linux（RedHat系）
Oracle：Oracle 11~12c（構成によっては11~12c以外でも参考になります）

# 背景
df-hとかでさがすと/ディレクトリが使用率100%
他のディレクトリ見ると
/var/logやoracle/diag/rdbms/traceフォルダに使用してなさそうな古いログファイルがたくさんある
今回は動作確認できるくらいで空けばいいのでこの二つを対象に作業する

| 拡張子              | 意味            | 安全に削除できるか          |
| ---------------- | ------------- | ------------------ |
| `.trc`           | トレースファイル（診断用） | ✅ 実行中セッション以外は基本削除可 |
| `.trm`           | トレースメタ情報      | ✅ 基本削除可            |
| `.1`             | ログの1世代前のバックアップ    | ✅ 安全　`logrotate`で次回上書きされる   |
| `.gz`            | さらに古い圧縮ログ         | ✅ 安全　見返す必要がなければ削除OK   |


# ログ削除方法
traceフォルダには.trcや.trmファイルがあるので古いのは削除
```
# 直近1日以内のファイル以外を削除（安全）
find /u01/app/oracle/diag/ -name "*.trc" -mtime +1 -exec rm -f {} \;
find /u01/app/oracle/diag/ -name "*.trm" -mtime +1 -exec rm -f {} \;
```

/var/logには以下のようなファイルがありそちらを削除
```
/var/log/syslog.1
/var/log/syslog.2.gz
/var/log/auth.log.1
/var/log/kern.log.3.gz
/var/log/messages.1
 ```

log削除コマンド
```
# ローテート済みの圧縮ログをすべて削除
sudo find /var/log -type f -name "*.gz" -delete

# 数字付きのバックアップログ（.1, .2, .3, etc.）
sudo find /var/log -type f -regex '.*\.[1-9]$' -delete
```

削除した後はもう一度df -hでディスク使用率を確認
自分はこれで1Gほど開けることに成功し、shの動作確認ができるようになった

# まとめ
そのサーバの運用方法によるが比較的消しても問題ない場所を探したので
似たような人がいれば参考までに
【PostgreSQL】備忘録_異なるテーブルの数値カラムを基に最小値・最大値のデータセットを作成したい

## やりたいこと
異なるテーブルの数値カラムを基に最小値・最大値のデータセットを作成したい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194659/7ea9c60c-c323-46b7-bd38-4df5c1b00a59.png)

上記でいうと、Table_A,Bの同じ番号で枝番が一番小さい値の名字と
枝番が一番大きい名前を1セットにしたデータがほしい感じです。

期待値
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194659/e75181bd-e818-409e-9ae6-21454d48a9ff.png)

## 解決策
ウィンドウ関数を利用するといい感じにできました。
```
SELECT DISTINCT
    b.番号,
    FIRST_VALUE(a.名字) OVER (PARTITION BY b.番号 ORDER BY b.枝番 ASC) as 名字,
    FIRST_VALUE(a.名前) OVER (PARTITION BY b.番号 ORDER BY b.枝番 DESC) as 名前
FROM テーブルB b
JOIN テーブルA a ON b.番号 = a.番号
ORDER BY b.番号;
```
ウィンドウ関数を利用しなくても実装できそうですが、
可読性を考えるとウィンドウ関数を使ったほうが個人的に頭に入りやすかったです。
ITガチ初心者なので同志向けにPythonを練習する会 part1（環境構築編）

# 自己紹介
初Qiitaなので簡単に自己紹介します。
今年IT専門学校2年制を卒業した**20歳**です。
AIに頼りすぎてコードが全く書けなくなったので、自分で書けるように勉強していきたいと思います。（ChatGPTいつもありがとう）

**資格**
・Python基礎エンジニア認定資格

# 今回すること
まず、私もガチ初心者なので**ガチ初心者向け**です。

今回は**環境構築**のみしていきます。
Pyhonを使用します。
次回は、実際にコードを書いていきたいと思います。

## Pythonとは？

Python（パイソン）は、世界中で使われているプログラミング言語のひとつです。  
特徴は以下のような点があります：

- **文法がシンプルで読みやすい** → 初心者でも書きやすい
- **用途が広い** → Webアプリ、AI・機械学習、データ分析、自動化 など
- **ライブラリが豊富** → 便利なツールがあらかじめたくさん用意されている

最近では、AIやデータ分析の分野で特に注目されていて、  
「最初に学ぶ言語」としてもよくおすすめされます。

私も、AI関連のツールを使うためにPythonを選びました。

## 使用環境

- OS：Windows 10（または11）
- エディタ：Visual Studio Code（VSCode）
- Python：3.11.9
## 必要な準備

### 1. Pythonのインストール

Python公式サイトから最新版のインストーラーをダウンロードして、インストールします。  
https://www.python.org/

ダウンロードから、windows用のexeをダウンロードしてください（私はPython3.11.9を使用しています）。

※「Add Python to PATH」に必ずチェックを入れてください（忘れるとpipが使えません）。

### 2. pipの確認

インストール後、コマンドプロンプト等で以下をコピーしてバージョンが表示されればOK。
複数貼り付けの警告文は無視してもいいです。

```bash
python --version
pip --version
```

↓ （見本）

```bash
C:\Users\UserName>python --version
Python 3.11.9

C:\Users\UserName>pip --version
pip 25.1.1 from C:\Users\UserName\AppData\Local\Programs\Python\Python311\Lib\site-packages\pip (python 3.11)
```

### 3. VSCodeのインストール
https://code.visualstudio.com/

Python開発用に「Python拡張機能」を入れておくと便利です。

以下拡張機能の入れ方
↓

# おすすめ拡張機能（初心者向け）

VSCodeでPythonを書くときに、入れておくと便利だった拡張機能を紹介します。  
全部「Marketplace」からワンクリックでインストールできます。

VSCodeの左のメニューの上から5番目、４つのブロックがまとまってるようなアイコンです。
（ctrl+shift+x）でも可能。

## （必須）Japanese Language Pack for Visual Studio Code

 - VSCodeを日本語にしてくれます。
 - 私は英語ができないのでこれが必須


次がPython関係

## 1. Python（Microsoft）

- 一番最初に入れるべき拡張機能
- `.py`ファイルの構文チェック、補完、Lint対応

## 2. Pylance

- 型チェックが強力で、ミスにすぐ気づける
- エラーが出る場所がわかりやすい

## 3. Black Formatter

- コード整形ツール。書き方を自動で揃えてくれる
- 見た目が統一されて気持ちいい

## 4. indent-rainbow

- インデントのレベルごとに色がつく
- Pythonはインデントでバグるので、めっちゃ便利

## 5. GitHub Copilot（Chatも）

- AIによるコード補完
- 使いすぎ注意。でも参考になるヒントがもらえる

---

## ちょっと注意点

- Copilotに頼りすぎると“自分の力で理解する”のが遅れることもある  
　→ **あくまで補助ツールとして使うのが大事**
 私の二の舞にならないように...；；
- Lint（構文チェック）とFormatter（整形ツール）は**同時に入れると競合することもある**ので、設定で調整しよう。

# おわりに

今回はPythonの環境構築をメインに紹介しました。

ここまで読んでくれた方、本当にありがとうございます。  
この記事が、私と同じように「これからPython始めたい！」という初心者の方の参考になれば嬉しいです。

**プロの初心者向けではなく、私も実際に初心者なので詰まりやすいところを同じ目線に立って進められるよう頑張りたいです。**

---

次回は、実際にコードを書きながら、

- `print()`や`input()`などの基本文法

を書きます。

需要がなければ、現在の自分の状況に合わせて
- ライブラリ等自分で書く力を身に着ける記事

を書きます...

どちらも、**ゆるく、でも少しずつ身につける感じ**でやっていこうと思っています。

私自身も勉強中なので、一緒に学んでいけたら嬉しいです！

---

※ もし「ここわかりにくいかも」みたいなところがあれば、コメントで教えてもらえるとめちゃくちゃ助かります。
ComposeでStateに振り回されないLayout

Compose for Desktopを用いてWindowsアプリ開発をしているのですが、一向に手が進まないので記事を書きながらモチベーションを維持しつつ作業を進めたいと思います。

---
# メインテーマ
- Composeにおける関数型UIの理解を深める
- Stateやインタラクティブな要素(ButtonやTextField)でごちゃつくCompose関数を解決する。



# layout用の関数を作ろう

レイアウト関数といえば言わずと知れたBox,Row,Columnがあります。
新たに画面固有のレイアウト関数を作り、そこに後から必要な要素を埋め込むことを目指します。

ComposeでのUIの作成方法は色々あると思いますが、いっぺんにすべてを書くとStateが多い画面ではごちゃ付き、レイアウトとそうでない要素を分けたくなるでしょう。
レイアウト用の関数を作るために以下のルールに従うといいのではないかと思っています。
(1)コンポーザブル関数のみを引数に取る
(2)階層を考えてはならない 
特に2は関数型において非常に重要な概念だと思います。
早速、SQL Clientアプリ風の画面をWindowsを対象に作ってみました。

取り急ぎのためろくなレイアウトではないですが、
申し訳程度にポート番号の入力幅は小さく、次へボタンを右寄せ位はしています。
引数名は雑に命名しています。問題があれば具体的な名前を考えればいいでしょう。
```Kotlin
@Composable
fun ConnectionLayout(
    slot1: @Composable () -> Unit,
    slot2: @Composable () -> Unit,
    slot3: @Composable () -> Unit,
    slot4: @Composable () -> Unit,
    slot5: @Composable () -> Unit,
    slot6: @Composable () -> Unit,
){
    Column (
        verticalArrangement = Arrangement.spacedBy(16.dp),
        modifier = Modifier.fillMaxSize(),
    ){
        // sqlクライアント
        slot1()
        // URL
        slot2()
        Box(
            modifier = Modifier
                .size(100.dp,  40.dp)
        ){
            // port
            slot3()
        }
        // ユーザー名
        slot4()
        // パスワード
        slot5()
        Row (
            modifier = Modifier.fillMaxWidth()
        ){
            Spacer(modifier = Modifier.weight(1f))
            // 次へボタンなど
            slot6()
        }
    }
}
```
また、コンポーザーブル関数ではよくViewModelなどのデフォルト引数を渡しているサンプルがあります。
Previewしたいのであれば別の関数で引数を解決したものを用意すればいいでしょうし、デフォルトでViewModelを渡すと意図が分からない、引数の渡し忘れが起きるなどのミスが起こるためデフォルト引数を渡す関数は別で定義したほうがよいでしょう。

```kotlin
@Composable
fun TestConnectionLayout(){
    PreviewConnectionLayout()
}


@Composable
fun PreviewConnectionLayout() {
    ConnectionLayout(
        {
            Button(
                onClick = {}
            ){
                Text("使用しているSQLクライアントを選択してください")
            }
        },
        {
            TextField(
                value = "",
                onValueChange = {}
            )
        },
        {
            TextField(
                value = "",
                onValueChange = {}
            )
        },
        {
            TextField(
                value = "",
                onValueChange = {}
            )
        },
        {
            TextField(
                value = "",
                onValueChange = {}
            )
        },
        {
            Button(
                onClick = {}
            ){
                Text(text = "次へ")
            }
        },
    )
}

```

コード全体でみると思ったよりも完成系としてはかなり見づらくも思えましたが、Stateの管理やもっと複雑なレイアウトになったときこれ以上の地獄が待っていることを考えるとこのように分けてみることはかなり有利ではないかと思います。

もっとうまくレイアウトすることができれば、グレーで塗りつぶした要素を引数に渡すだけでどの領域がどのスロットに与えられているのかを視覚的にさらにわかりやすくなるのではないでしょうか。

以上、レイアウトと入力要素を分けてみようという提案でした。



---
近日中に書きたい
- ComoseでLayout,ViewModel,Navigationに振り回されないScreen
- ComposeでNavhostを軸にしない構造
- ComposeでStateの数に振り回されないViewModelの状態管理メソッド定義
取得した値が空の時は、空の配列を返すようにする

## 修正前のコード
今日は開発中に、以下のようなコードを書きました。

```javascript
let oldArr = $p.getControl("項目名").val();
```
`$p.getControl`は、現在開発で使っているPleasanter（プリザンター）というWeb OSS独自のスクリプトです。

指定した項目に入力された値（配列型）を取得し、`oldArr`という変数に格納するといった内容です。

## 問題点
ただ、取得した値が空だった場合（何も入力されていない場合）、`oldArr` は null になります。
この状態では push や concat、map、filter、forEach など、配列のメソッドが使えずエラーになります。


## 修正後のコード
取得した値が空の場合には、空配列 [] で初期化してあげる必要があります。
```javascript
// 初期値のガード
// `oldArr` が `null` だった場合に `.concat()` でエラーになる可能性があります。
// **改善例**:
let oldArr = $p.getControl("階層分類").val() || [];
```
このコードでは、`$p.getControl("階層分類").val()` の返り値が falsy 値（null, undefined, '', 0, false など）の場合は[]（空配列）が使われます。
逆に、truthy 値（つまり実際に値が存在する場合）は`oldArr`に代入されます。



## 感想
実務で「値を取得して配列に代入する」というケースは結構あると感じたので、「取得した値が存在しない可能性がある」ことを常に意識し、空配列での初期化を忘れないようにしたいと思いました！
animation-delay と var() に起因する不具合

以下の条件が揃うと、Chrome において意図しないアニメーション挙動が発生することを確認しました。

- `animation-delay` を使用している
- keyframes 内で `var()` を使用している
- CSS 変数の値を非同期に変更している (例: React の `useEffect` で DOM 要素を取得後に変数を設定する)

# 実例
以下の CodePen を Firefox と Chrome で開き、挙動を比較してみてください。
本来は Firefox のように、赤い正方形が静止している状態が期待される動作ですが、Chrome では正方形が動いてしまっています。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="azORORJ" data-pen-title="animation-delay-var-bug" data-user="inonote" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/inonote/pen/azORORJ">
  animation-delay-var-bug</a> by inonote (<a href="https://codepen.io/inonote">@inonote</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://public.codepenassets.com/embed/index.js"></script>


# 回避策
CSS だけでトリッキーなことをせずに Web Animations API を使いましょう。

https://developer.mozilla.org/ja/docs/Web/API/Web_Animations_API

# おまけ
興味深いことに、Chrome の開発者ツールで要素を調査すると、描画上は (意図せず) 動いているのにもかかわらず本来あるべき場所にハイライトが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233982/6623db90-e66c-4223-acde-b4f721916b6b.png)
【CSS】clamp()の使い方

`clamp()` は CSS で値を **最小値**・**推奨値**・**最大値** の範囲内に収めるための関数です。

## `clamp()` の基本構文

```css
clamp(minimum, recommended, maximum)
```

- `minimum`：最小値。これより小さくはならない。  
- `recommended`：推奨値。通常はこちらが適用される。  
- `maximum`：最大値。これより大きくはならない。

## 例

```css
.card {
  width: clamp(200px, 50vw, 400px);
  padding: 1rem;
  background: #f5f5f5;
  border-radius: 8px;
}
```

- ビューポート幅が狭いときは最低幅 200px  
- 推奨は画面幅の 50%  
- 広大な画面では最大幅 400px
IT未経験がLPIC-3取得

# はじめに
LPIC-3 300を受けました。
勉強開始から2か月で合格しました。

# 学習目的
資格を取りつつLinuxの知識を身に付けること。

# 試験結果
LPIC-3 300
LPIC-2までとは異なり、LPIC-3は1つ受かると認定が受けられます。
今回の得点：680/800点
合格ライン：500/800点
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3771776/ab6246e5-5600-4f58-a814-c40f4fe80613.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3771776/40e306b2-cb84-4b9c-8bdf-0d8bb348867e.png)

# 試験受験時の資格
LPIC-1
LPIC-2
AWS SAA

# 学習時間
日数 : 60日
時間 : 約100時間

全体の勉強時間を日数で割ると、1日あたり平均で約100分勉強したことになります。ただし、試験直前の1週間で約30時間勉強しているため、それ以外の期間では、1日平均1時間ほどでした。

# 学習教材
* [学易](https://gakuyasu.byaku.jp/)
* [ChatGPT](https://openai.com/ja-JP/chatgpt/overview/)
* [Ping-t](https://mondai.ping-t.com/g/question_subjects)
* Linux仮想サーバー

## 選んだ理由

### [学易](https://gakuyasu.byaku.jp/)

合格者の振り返り動画（2本）と体験記事（3本）で強くおすすめされていたため、この教材を選びました。
特に他の教材と比べて信頼性が高いと評価されていたことから、メイン教材として活用しました。

### [ChatGPT](https://openai.com/ja-JP/chatgpt/overview/)
こちらに関しては選ぶ理由も何もなく日常生活のあらゆることを聞いているので、当然のように試験勉強にも活用していました。

### [Ping-t](https://mondai.ping-t.com/g/question_subjects)

これまでのLPIC試験でお世話になった教材なので今回も使用しました。
ただ、合格者の感想を見ていると的中率はそこまで高くないようでしたので今回は補助的に使用しました。
また、最新verの試験に対応していないので範囲外の問題もあります。具体的にはOpenLDAP（主題390）は全く出ません。他にもWindowsNT関連の問題がありますが、最新verの試験にはほぼ出ません。WindowsNTは古いOS(Active Directoryが導入される前の世代のOS)です。

# 学習方法
### 学易を全問解けるようにする。

1. 解説を読まずに、とにかく答えを覚えるまで何度も問題を解きました。
2. 答えを覚えた問題の解説を読み、納得できるまでChatGPTに質問しました。
3. 選択肢を見なくても自力で答えられるようにしました。

---

#### 1. 解説を読まずに暗記する
このやり方（最初は解説を読まずに答えだけを覚える方法）は、あまり一般的ではないかもしれませんが、これまで何度も資格試験の勉強をしてきた経験から、「一度に多くのことを理解しながら覚えるのは難しい」と実感していました。そこで、あえて解説を読まずに、まずは暗記に集中する方法を取りました。

この方法には大きなメリットがあり、短期間で大量の問題をこなすことができ、正答率も早い段階で高めることができました。

ただし、この学習法で対応できるのは「まったく同じ問題で、かつ選択肢が表示されている場合」に限られます。そのため、この段階では本番には通用しないと感じました。

#### 2. 問題の解説を理解する
1.の学習方法の弱点を補うべく問題の解説を読み漁りました。事前に答えを覚えていたことで、解説を読んだときに理解しやすくなり、学習効率が大きく上がりました。これまでの勉強では、知らない単語ばかりの長い解説を読むのが苦痛で、調べながら進めるのにかなり時間がかかっていたのですが、今回はそういったストレスが少なく、非常に自分に合った方法だったと感じています。

#### 3. 選択肢を見ずに答える
選択肢を見ないで答えられるようにするというのは、私が資格試験のたびに行っている方法です。選択肢があるとつい頼って「なんとなく」で正解してしまうことがありますが、本番では選択肢が同じように出るとは限らないため、自力で答えられるようにします。

---
### Ping-t
学易での学習を終えた後に、Ping-tの問題も解きました。問題数が400問以上あり、すべて解くにはかなりの時間がかかった印象があります。
ただ、全問解く必要はないです。自分が不安に感じる分野や苦手な部分だけ50問ほどを重点的に解けば、十分です。また、OpenLDAP（主題390）やWindowsNT,NTドメイン関連の問題は試験範囲外なのでやらないでください。

---

### 仮想サーバーで実践

試験勉強と並行して、Linuxの仮想サーバー構築にも取り組みました。
これは試験対策というよりも、学習した知識を実際に使ってみたいという思いから行ったもので、試験の得点にはほとんど影響はありませんでした。資格取得優先の方はやらなくてもまったく問題ありません。

具体的には以下のような構築を行いました：

Sambaサーバーの構築
　Windowsサーバーとファイル共有ができることを確認し、Linuxサーバーとの連携を体験しました。

SambaサーバーをADドメインのメンバーとして参加
　ドメインに参加することで名前解決ができるようになるなど、ネットワーク上での動作を確認しました。

FreeIPAサーバーの構築
　Linux環境での認証基盤構築の理解を深めました。

問題集だけでは文章上の理解にとどまりがちですが、実際に構築することで「何ができるようになるのか」を具体的にイメージすることができました。

# 試験
初見の問題は無く数問解いた段階でこの試験に受かると感じました。
終わった後に言うものあれですが、もう1か月早く受けてもよかったと感じました。

# まとめ
とある記事にも書いてあったのですが、LPIC-3 300は勉強すれば必ず合格できます。
Lpic-2に合格した方はすぐにでも受けましょう。勉強方法を間違えなければ絶対に受かります。そしてその勉強方法はこの記事に書いてあります。ぜひ合格してLpic-3という武器を手に入れましょう。
【Python初心者】ioモジュールでテキストとバイナリをメモリ上で操作してみた

`io` モジュールの使い方についてまとめました。  
ファイルのように扱える「仮想ファイルオブジェクト」を使って、テキストやバイナリの操作を試しました。

## テキストデータを仮想ファイルとして扱う：`io.StringIO`

`io.StringIO` を使うと、文字列をファイルのように扱えます。  
たとえばテスト時にダミーのファイルを用意したいときに便利です。

```python
import io

text_data = "これはテスト用の文字列です。\n2行目のテキストです。"
f = io.StringIO(text_data)

# 1行ずつ読み込む
for line in f:
    print("読み込み:", line.strip())
```

```
読み込み: これはテスト用の文字列です。
読み込み: 2行目のテキストです。
```

`write()` を使って書き込みも可能です。

```python
f = io.StringIO()  # 空の仮想ファイルを用意
f.write("Hello, ")
f.write("World!")
print("内容:", f.getvalue())  # getvalue() で全体を取得
```

```
内容: Hello, World!
```

## バイナリデータを仮想ファイルとして扱う：`io.BytesIO`

バイナリデータを扱うときは `io.BytesIO` を使います。  
画像データや音声データ、バイト列を一時的に扱いたいときに便利です。

```python
import io

binary_data = b'\x00\x01\x02hello\xff'
f = io.BytesIO(binary_data)

# バイナリを読み込んで表示
read = f.read()
print("読み込んだバイト列:", read)
```

```
読み込んだバイト列: b'\x00\x01\x02hello\xff'
```

書き込みも可能です。

```python
f = io.BytesIO()
f.write(b"abc")
f.write(b"123")
print("内容:", f.getvalue())
```

```
内容: b'abc123'
```

## 標準入力の模擬：`sys.stdin = io.StringIO(...)`

Pythonでは通常、`input()` を使うとユーザーのキーボード入力を読み取ります。  
その入力元は `sys.stdin` という「標準入力オブジェクト」です。

この `sys.stdin` を `io.StringIO()` に差し替えると、**キーボードからではなく、指定した文字列から `input()` を読み取ることができる**ようになります。

```python
import io
import sys

sys.stdin = io.StringIO("Hello\nWorld\n")
print(input())  # → Hello
print(input())  # → World
```

```
Hello
World
```

このようにして、**テストや自動化の場面でユーザー入力を再現することができます。**

---

## 標準出力のキャプチャ：`sys.stdout = io.StringIO()`

通常、`print()` した内容は画面（標準出力）に表示されます。  
この出力先は `sys.stdout` というオブジェクトで管理されています。

`sys.stdout` を `io.StringIO()` に差し替えると、**`print()` の内容が画面に出ず、仮想ファイルに書き込まれるようになります。**

```python
import sys
import io

sys.stdout = io.StringIO()  # 出力先を仮想ファイルに変更
print("テスト")             # 画面ではなく、StringIOに書き込まれる
result = sys.stdout.getvalue()  # 書き込まれた内容を取得
```

```
result に入る値: "テスト\n"
```

このようにして、**`print()` の出力内容を文字列としてプログラム内で扱えるようになります。**

### 📌 元に戻す方法

標準出力を変更したままだと、後続の `print()` もすべて `StringIO` に出力されてしまいます。  
以下のように、元に戻すことが推奨されます。

```python
sys.stdout = sys.__stdout__  # 標準出力を元に戻す
print("キャプチャ:", result)
```

```
キャプチャ: テスト
```

---

## おわりに

今回は `io.StringIO` と `io.BytesIO` を使って、メモリ上でテキストやバイナリをファイルのように扱う方法を学びました。  
特に `sys.stdin` や `sys.stdout` を差し替えて、テスト用に仮想的な入出力を操作できる仕組みはとても便利だと感じました。
バージョン違い

# spring bootとmysqlのバージョン違い
全然解決していなかったことが、ちょっと光明が見えてきた。
mysqlの最新バージョン8.4系にSpringが対応していない状況っぽい

今週土日で、再度dockerのmysqlの環境構築からやり直してみよう。
「Goツアー日本語版」をMacで手軽に試す方法

## はじめに

Go言語の学習をはじめようと思い、公式チュートリアルである「[A Tour of Go](https://go.dev/tour/)」に挑戦する方は多いと思います。 

実はこのチュートリアルには有志の方が作成してくださっている日本語版が存在し、ローカル環境で動かすことができます。

この記事では、HomebrewでGo言語をインストール済みのMac環境を前提として、「A Tour of Go」日本語版を最も手軽に起動する手順をまとめます。

## 前提条件

- macOS
- [Homebrew](https://brew.sh/index_ja) がインストール済み
- `brew install go` などでGo言語がインストール済み
- `git` コマンドが利用可能

## 結論：この3行で起動できる

ターミナルで以下のコマンドを順に実行すればOKです。

```bash
git clone https://github.com/atotto/go-tour-jp.git
cd go-tour-jp
go run .
```

実行後、自動でブラウザが立ち上がり http://localhost:3999 が開かれれば成功です。


## よくある失敗例：go install

なぜ上記の `git clone` からの手順が必要なのでしょうか。  
Goのパッケージをインストールする際によく使われる `go install` コマンドを試すと、私の環境ではエラーになってしまいました。

#### 試したコマンド

```bash
go install github.com/atotto/go-tour-jp/gotour@latest
```

#### 表示されるエラー

```
go: github.com/atotto/go-tour-jp/gotour@latest (in github.com/atotto/go-tour-jp@v0.0.0-20201205034358-913c5eae8455):
    The go.mod file for the module providing named packages contains one or
    more replace directives. It must not contain directives that would cause
    it to be interpreted differently than if it were the main module.
```

これは、Go 1.16以降のセキュリティ強化が理由です。  
インストールしようとしているパッケージの設定ファイル (go.mod) に `replace` という記述が含まれている場合、安全のため `go install` が許可されなくなりました。

この問題を回避し、かつ最もシンプルに日本語版ツアーを起動する方法が、ソースコードを直接ダウンロードして `go run` で実行する方法です。

## 正しい手順（詳細）

改めて、手順を詳しく見ていきましょう。

### 1. ソースコードをダウンロードする

まず、ターミナルでお好きな作業ディレクトリに移動し、`git clone` コマンドで日本語版ツアーのソースコード一式をダウンロードします。

```bash
git clone https://github.com/atotto/go-tour-jp.git
```

### 2. ディレクトリを移動する

ダウンロードして作成された `go-tour-jp` ディレクトリに `cd` コマンドで移動します。

```bash
cd go-tour-jp
```

### 3. Goプログラムを実行する

`go run .` コマンドを実行します。  
これは、カレントディレクトリにあるソースコードをコンパイルし、直接実行するコマンドです。

```bash
go run .
```

コマンドを実行すると、ターミナルには `Serving at http://127.0.0.1:3999` のようなメッセージが表示され、自動的にブラウザが起動します。

もしブラウザが起動しない場合は、手動で http://localhost:3999 にアクセスしてください。

ツアーを終了したい場合は、ターミナルで `Ctrl + C` を押してください。

## まとめ

`go install` が使えない場合でも、`git clone` して `go run .` を実行することで、簡単にローカルでプログラムを動かすことができます。  

## 参考

- A Tour of Go 日本語版リポジトリ  
  https://github.com/atotto/go-tour-jp
運用保守 × マルチタスク：現場で実践している10の習慣

#  はじめに
マルチタスクで運用保守するときに大切な事についてまとめました。

運用保守で気を付ける事と似ていますが大事な部分を抜き出しました。

https://qiita.com/gama1234/items/d6b0192ed4b7c2715f75

## 1 認識違いがないか確認する習慣をつける
思い込みや認識違いを疑いながら作業した方が防げたりします。

## 2 感覚ではなく実際の作業時間を見積もりスケジュールを立てる
保守作業のスケジュールは感覚で回答するのではなく、
実際どれぐらいかかるか頭の中でシミュレーションしてみて工数を見積もっています。

## 3 朝はtodoリストを作成して業務を全体把握する
まずは自分の全体の業務を把握してから、その中から本日のtodoリストを作成しています。
どの作業から着手するかをスケジュールします。
また作業漏れがないかを確認する。

## 4 作業内容を2日前までに理解すること
作業内容を事前に目を通して理解すること
本番では確認者から見られるため、気持ちに余裕がなく誤った作業になる可能性があります。

## 5 疲れをためないように休憩を取る習慣
疲れていると間違えた選択をしてしまいます。
疲れていると思ったら思い切って、仕事中でも30分ぐらい休むことが大切です。


## 6 作業の30分前は振り返りの時間を作る
作業手順のシミュレーションを頭の中でして、作業できるように事前準備をしています。
本日作業を行う旨を確認者に事前に伝えます。
他の仕事はしない方が良いです。

## 7 翌営業日の予定を確認する習慣
翌営業日は必ず確認するようにしています。
実は早朝に作業があったが忘れていたなど。

## 8 依頼が来たらすぐにカレンダー登録とタスクに登録する。
後回しにしたら作業自体を忘れてしまうことがありました。

依頼が来たらすぐに登録する。確認者も確保する。

## 9 手順と確認は必ずセットです
たまに手順のみが記載されていて確認する点が抜けている手順が見受けられます。
手順とその後の確認は必ずセットです。

## 10 作業前のエビデンスに残す習慣をつける
作業後によく作業前のエビデンスを取り忘れたということはあります。
個人的には作業前の状態は必ずエビデンスとして残した方が良いです。
**作業手順と切り戻しもセットです。例：「問題が発生した場合に迅速に対応できるようにするためです」）**


# まとめ
###  何よりも大切なことは落ち着いて対応することが一番大切です
【AWS】CDKで「AccessLogFormat.json_with_standard_fields() got an unexpected keyword」エラーが出た場合

# 概要
ApiGatewayを作成するCDKを実行したら以下のエラーに。

> TypeError: AccessLogFormat.json_with_standard_fields() got an unexpected keyword argument 'extended_request_id'

なぜ`extended_request_id`が指定できない...？

# 原因と解決方法
CDKv2では`extended_request_id`という引数はサポートされていないらしい。

そもそも`extended_request_id`を入れていたのは、以下の公式ドキュメントで書かれている「CloudWatch によるログの形式」の例に含まれていたため。

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/set-up-logging.html

```json
{ "requestId":"$context.requestId", "extendedRequestId":"$context.extendedRequestId","ip": "$context.identity.sourceIp", "caller":"$context.identity.caller", "user":"$context.identity.user", "requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod", "resourcePath":"$context.resourcePath", "status":"$context.status", "protocol":"$context.protocol", "responseLength":"$context.responseLength" }
```

公式にあるものをログに出した方がいいかな、と思いそのままCDKで入れたら先述のエラーになった。
その時の指定方法は以下の通り。

```py
        stage = apigateway.Stage(self, "Sample-ApiStage",
            deployment=deployment,
            stage_name="prod",
            logging_level=apigateway.MethodLoggingLevel.INFO,
            data_trace_enabled=True,
            access_log_destination=apigateway.LogGroupLogDestination(api_gateway_log_group),
            access_log_format=apigateway.AccessLogFormat.json_with_standard_fields(
                caller=True,
                extended_request_id=True,
                http_method=True,
                ip=True,
                protocol=True,
                request_time=True,
                resource_path=True,
                response_length=True,
                status=True,
                user=True
            )
        )
```

しかしこれではダメでした。
正確にいうと、`extended_request_id`以外は上記の指定方法で問題ないのですが、`extended_request_id`はサポートされていなかった、のです。


ということで手法を変えて、`AccessLogFormat.custom()`で明示的に指定してあげるとエラーがなくなります。

```py
stage = apigateway.Stage(self, "Sample-ApiStage",
    deployment=deployment,
    stage_name="prod",
    logging_level=apigateway.MethodLoggingLevel.INFO,
    data_trace_enabled=False,
    access_log_destination=apigateway.LogGroupLogDestination(api_gateway_log_group),
    access_log_format=apigateway.AccessLogFormat.custom(
        '{"requestId":"$context.requestId",'
        '"extendedRequestId":"$context.extendedRequestId",'
        '"ip":"$context.identity.sourceIp",'
        '"user":"$context.identity.user",'
        '"caller":"$context.identity.caller",'
        '"requestTime":"$context.requestTime",'
        '"httpMethod":"$context.httpMethod",'
        '"resourcePath":"$context.resourcePath",'
        '"status":"$context.status",'
        '"protocol":"$context.protocol",'
        '"responseLength":"$context.responseLength",'
        '"responseLatency":"$context.responseLatency",'
        '"integrationLatency":"$context.integrationLatency"}'
    )
)
```

AWS管理コンソールからも確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710373/1dd6863f-4202-4bbc-aa7d-a7cee0769e19.png)

何を指定した方がいいかについては、
「具体的にどんなログを出したいのか？」
によって固めていく必要がありますね。