OmniAICreator/Qiita-1.07M huggingface dataset:
DockerでSpring Bootをコンテナ化しaws ECR・ECSを利用しデプロイ part 2

## 目次
1. AWS ECRにプッシュ
    - DockerイメージをAWSのコンテナレジストリにアップ。
2. AWS ECS + Fargateにデプロイ
    - クラウド上でコンテナを起動。
3. クラウド上でのアクセス
    - apiを確認
`この記事はDockerでSpring Bootをコンテナ化しaws ECR・ECSを利用しデプロイ part 1の続きになっております。もしよろしければpart1も見ていただけると幸いです。`
https://qiita.com/jugon_p_p/items/2233da5d31ffa6e50688

<div style="border: 2px solid #f44336; background-color: #ffebee; padding: 10px; border-radius: 5px;">
<strong>⚠️ 警告:</strong> ここに注意してください！
</div>

:::message alert
    本環境を実行すると、ECSの利用料金が発生する可能性があります。
    費用の発生を避けたい方は、十分ご注意ください。

:::

## AWS ECRにプッシュ

### DockerイメージのAWSのコンテナレジストリにアップロードする手順

### ECRとは?
* Amazon Elastic Container Registry (ECR) は、Dockerイメージを安全に保管し管理できるAWSのサービス。
* AWSの他サービス（例: ECS）と連携しやすい。

### 手順
1. ECRリポジトリ作成
    - AWSマネジメントコンソールのECRサービスから、リポジトリを作成。
2. AWS CLIでECRにログイン`各PCにAWS CLIをインストールする必要有`
```bash
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 522585361401.dkr.ecr.ap-northeast-1.amazonaws.com
```
* `522585361401.dkr.ecr.ap-northeast-1.amazonaws.com` はアカウントID + リージョンを含むECRリポジトリのURL
3. Dockerイメージにタグ付け
    - ローカルのイメージにECRリポジトリのURLをタグとしてつける
```bash
docker tag springboot-demo:latest 522585361401.dkr.ecr.ap-northeast-1.amazonaws.com/springboot-demo:latest
```
4. イメージをプッシュ
```bash
docker push 522585361401.dkr.ecr.ap-northeast-1.amazonaws.com/springboot-demo:latest
```
* これでイメージがECRにアップロードされ、クラウドで使える状態に。

## AWS ECS + Fargateにデプロイ
### ECRにあるDockerイメージを使ってコンテナを起動する設定をAWS ECSで行う

### ECSとは？
* Elastic Container Serviceの略で、コンテナの管理とオーケストレーションを担うサービス。
* Fargateはサーバーレスでコンテナ実行できる起動タイプ。EC2管理が不要。

### 手順
1. クラスターを作成
    * ECSの画面からクラスターを作成。
    * クラスタータイプは「Networking only (Fargate)」を選択。
2. タスク定義を作成
    * コンテナの設定を登録するためのテンプレート。
    * コンテナ名、イメージURL（ECRのURI）、CPU・メモリ、ポートマッピング（例: コンテナポート8080）を指定。
    * ネットワークモードは awsvpc（Fargateの場合必須）。
3. サービス作成
    * タスク定義を使ってサービスを作成
    * サービスはクラスター内でタスクを複数起動・管理。
    * 起動タイプは「Fargate」、タスク数を指定（例: 1）。
4. ネットワーク設定
    * VPCのサブネットを選択（パブリック or プライベート）。
    * セキュリティグループでコンテナに割り当てる通信ルールを設定（例: ポート8080を0.0.0.0/0に開放）。
    * `本番環境ではこのポート許容先を指定する必要有`
5. 起動
    * サービスを作成すると、Fargateが自動でコンテナを起動。
    * ECSのタスクが「RUNNING」状態になれば稼働中。

## クラウド上でのアクセス
### 起動したコンテナに外部からアクセスするためのポイント
1. 公開IPの確認
    * FargateタスクにパブリックIPを割り当てている場合、タスク詳細画面で「パブリックIP」を確認。
    * 例: 54.92.52.223
2. セキュリティグループの設定確認
    * ポート8080（コンテナで使っているポート）が、0.0.0.0/0に開放されていることを必ず確認。
3. URLにアクセス
    * ブラウザやcurlで http://<パブリックIP>:8080/ にアクセス。
    * Spring Bootアプリが起動していればAPIや画面が見れる。

# AWSにデプロイするためのまとめ
|ステップ|詳細|
|---|---|
|ECRリポジトリ作成|Dockerイメージ保存用リポジトリをAWSで作成|
|ECRログイン|aws ecr get-login-password でDockerをECRにログイン|
|Dockerイメージタグ付け|ローカルイメージにECRリポジトリURIのタグをつける|
|ECRへプッシュ|docker push コマンドでイメージをアップロード|
|ECSクラスター作成|Fargate用のクラスターを作成|
|タスク定義作成|コンテナの設定（イメージ、リソース、ポートなど）を登録|
|サービス作成 & 起動|タスクをFargateで実行するサービスを作成して起動|
|アクセス|パブリックIPとセキュリティグループの設定を確認し、APIにアクセス|
お昼休みですよ！決まった時間に自動で通知&チャイムが鳴るバックグラウンド風アプリ作成してみた！

## テレワークだと気づきません！
テレワークのとき、昼休憩の時間や終業時間に気づきますか？
社内にいるとチャイムが鳴るので気づきますが、テレワークだと気づかず仕事を続けてしまうことがあります。

今回はWindows起動時に自動実行されて、設定した時刻になると、画像のように通知されてチャイムが鳴るバックグラウンド風アプリを作成しました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682615/d50da1f8-bbe9-41e1-bd9b-8f29167bcad5.png)

また、チャイム音はリンク先にある「学校のチャイム」にしました。

https://soundeffect-lab.info/sound/anime/


## 実装

### コード
ALARM_TIMESにアラーム時刻、SOUND_PATHに好きな音声ファイルの絶対パスを設定すれば使用できます。

```time_announcement.py
import tkinter as tk
import threading
import time
import datetime
import pygame

ALARM_TIMES = ["12:00", "17:30"]  # 12:00と17:30にアラート
SOUND_PATH = r"SOUND_PATH"  # お好きなwav/mp3ファイルの絶対パス

def play_sound():
    try:
        pygame.mixer.init()
        pygame.mixer.music.load(SOUND_PATH)
        pygame.mixer.music.play()
    except Exception as e:
        print(f"音声再生エラー: {e}")

def show_time_and_play_sound(now):
    root = tk.Tk()
    root.attributes('-topmost', True)
    root.geometry("400x200+600+300")
    root.overrideredirect(True)
    label = tk.Label(root, text=now, font=("Arial", 60), fg="red")
    label.pack(expand=True)
    threading.Thread(target=play_sound, daemon=True).start()
    root.after(30000, root.destroy)
    root.mainloop()

def main():
    last_trigger_date = {t: "" for t in ALARM_TIMES}  # 各時刻ごとに管理
    while True:
        now = datetime.datetime.now()
        now_str = now.strftime("%H:%M")
        today_str = now.strftime("%Y-%m-%d")
        for alarm_time in ALARM_TIMES:
            if now_str == alarm_time and last_trigger_date[alarm_time] != today_str:
                show_time_and_play_sound(now_str)
                last_trigger_date[alarm_time] = today_str
        time.sleep(1)

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

### exe化
pythonファイルをexe化します。
ここでnoconsoleにすることで、バックグラウンド風になります。

```sh
pip install pyinstaller
pyinstaller --onefile time_announcement.py --noconsole
```

### スタートアップフォルダを開く
`` Windowsキー +  R ``を押した後、`` shell:startup ``を入力すると、スタートアップフォルダが開かれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682615/a33c69aa-d207-4f19-9d38-2d9920cf48fa.png)

### スタートアップに登録
スタートアップフォルダにexe本体かそのショートカットを入れる。
これでWindows起動時に自動でファイルが実行されるようになります。

### まとめ
私は基本的に出社していて、会社だとお昼や終業時間にチャイムが鳴るので、たまにテレワークすると時間に気づかないときがよくあります。そのため、今回はそこそこ実用的なものができたのではと思っています。

もし良ければ皆さんも実装してみてください！
[ShowDebug CAMERA] UnrealのPIE等でプレイヤー及びカメラ座標を表示する

コンソールにShowDebug CAMERAと入力すると、プレイヤーの座標と向き、カメラの基本的な情報（座標、回転、FOV、AspectRatio）などが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66160/1200a8f5-3093-4426-8d09-495a142166cc.png)

上の画面はUE5.6ですが、UE4.27でも使えることを確認しました。
【Dagster備忘録】Assetcheckと完了トリガの設定

# 初めに
DagsterのAssetCheckと、その完了をトリガにして後続処理を走らせるのに少し苦労したので備忘録に残します。

## やりたいこと
* AssetにAssetCheckを行い、自動でテストを行う
* Upstreamの実行完了時、Downstreamを自動実行する
* UpstreamのCheckに失敗した場合、Downstreamは実行しない

## うまくいかない例
```
import dagster as dg

@dg.asset(
    group_name="test",
)
def upstream(context: dg.AssetExecutionContext) -> dg.MaterializeResult:
    return dg.MaterializeResult(
        metadata={
            "partition_2":f"____v2"
            }
    )

@dg.asset_check(
    asset=upstream,
)
def upstream_check(duckdb: DuckDBResource) -> dg.AssetCheckResult:
    return dg.AssetCheckResult(
        passed=False,
        metadata={"check": 12}
    )

@dg.asset(
    group_name="test",
    automation_condition = dg.AutomationCondition.eager(), # Checkが失敗しても実行される
    deps=[upstream],
)
def downstream(context: dg.AssetExecutionContext):
    return ""
```

## 原因
2点あります。
1. AssetCheckに`bloaking`属性を付与していないこと
1. AutomationConditionに`all_deps_blocking_checks_passed`条件が付与されていないこと

## 改善例

```
import dagster as dg

# カスタムAutomationを設定
condition = (
    dg.AutomationCondition.eager()
    & dg.AutomationCondition.all_deps_blocking_checks_passed()
)

@dg.asset(
    group_name="test",
)
def upstream(context: dg.AssetExecutionContext) -> dg.MaterializeResult:
    return dg.MaterializeResult(
        metadata={
            "partition_2":f"____v2"
            }
    )

@dg.asset_check(
    asset=upstream,
    blocking=True, # ⇦追加
)
def upstream_check(duckdb: DuckDBResource) -> dg.AssetCheckResult:
    return dg.AssetCheckResult(
        passed=False,
        metadata={"check": 12}
    )

@dg.asset(
    group_name="test",
    automation_condition = condition # ⇦変更
    deps=[upstream],
)
def downstream(context: dg.AssetExecutionContext):
    return ""
```

以上です。
AssetCheckを導入したけれど、うまく動作しなかった場合ｈ参考になるかと思います。
MacにMAMPをインストールするときの注意（Windowsも）

# WordPress × MAMP に関するQ&Aまとめ

## Q1. MAMPのdatabaseのデフォルトのrootのパスワードは？

**ユーザー名：** root  
**パスワード：** root  

セキュリティ上、公開環境では使用しないでください。

## Q2. WordPressのデータベース名で使えないものはあるか？

基本ルール：英数字、アンダースコア（_）は使用可。  
**使用できない・避けるべき名前：**

- mysql, information_schema, performance_schema（MySQLの予約システム）
- 日本語、全角文字、スペース
- 記号（ドット、ハイフンなど）
- SQL予約語（select, user など）

## Q3. 「wordpress」というデータベース名は問題あるか？

他の名前にしたほうが無難です。

## Q4. wp-config.php は事前に作成する必要があるか？

通常は必要ありません。WordPressが初回起動時に自動生成します。  
ただし、ディレクトリの書き込み権限がない場合は手動で作成が必要です。

    
## Q5. 権限がない場合の対処方法（ターミナルコマンド)
```
cd /Applications/MAMP/htdocs/wordpress
cp wp-config-sample.php wp-config.php
sudo chown $(whoami):staff wp-config.php
chmod 644 wp-config.php
sudo chmod -R 755 /Applications/MAMP/htdocs/wordpress
sudo chown -R $(whoami):staff /Applications/MAMP/htdocs/wordpress
```

[参考になったサイト](https://webst8.com/blog/mamp-wordpress-install/)

# Windowsで `MAMP` を入れる方法
1. MAMPのサイトを検索してダウンロード[リンク](https://www.mamp.info/en/windows/)
2. WordPress インストール で検索してダウンロード[リンク](https://ja.wordpress.org/support/article/how-to-install-wordpress/)
3. MAMPをインストール「C:\MAMP」
4. WordPressのZipを解凍する「Wordpress xx.xx\ `wordpress\wp-config-sample.php `」WordPressフォルダを取り出す

5. インストール後に「C:\MAMP\htdocs\wordpress」という配置にする
6. MAMP を起動する
7. phpmyadmin からWordpress用データベースを作成する
8. 「localhost\wordpress」にアクセスするとWordPressの画面に移動する
9. データベースの情報を入力する「データベース名」、ユーザ名（root）、パスワード（root）
10. サイトの名前などを設定でインストール完了！

**Mac** と同じ手順で構築出来たので簡単でした。
Atcoder全探索入門問題

## 全探索入門問題
[ABC106 B](https://atcoder.jp/contests/abc106/tasks/abc106_b)
[ABC122 B](https://atcoder.jp/contests/abc122/tasks/abc122_b)
[パ研杯2019 C - カラオケ](https://atcoder.jp/contests/pakencamp-2019-day3/tasks/pakencamp_2019_day3_c)
### ABC106 B
制約
N ≤ 200（小さい）

方針（全探索できる！）
1〜N までの奇数について、正の約数の個数を求める
その個数が8個ちょうどならカウント
計算量は十分小さいので全探索でOK
### Ruby
```ruby
# frozen_string_literal: true
# 正の約数の個数を返す関数
def count_divisors(n)
  count = 0
  (1..n).each do |i|
    count += 1 if n % i == 0# i が n の約数かどうかを判定
  end
end
n = gets.to_i
ans = 0
(1..n).step(2) do |i| #奇数のみを走査（step(2)で2ずつ増加）
  ans += 1 if count_divisors(i) == 8# 約数が8個ならカウント
end
```
### Python
```python

N = int(input())

ans = 0


def count_divisors(n):
    count = 0
    for i in range(1,n+1):
        if n % i == 0:# i が n の約数ならカウント
            count += 1
    return count


for i in range(1,N+1,2):
    if count_divisors(i) == 8:# 約数がちょうど8個ならカウント
        ans += 1
print(ans)
```
### ABC122 B

#### 制約確認
S の長さ ≤ 10 -> 部分文字列の数は最大で 10C2 = 45 程度 -> 全探索OK

方針
S のすべての部分文字列を取り出す

その中で「すべての文字が A/C/G/T のいずれか」である文字列だけを対象とする

### パ研杯2019 C - カラオケ
#### 制約確認
N, M ともに最大 100

曲の組み合わせは M*(M-1)/2 通り（最大 4950 通り）
全探索でOK
全ての 2 曲の組み合わせ (j, k) を全探索（j < k）

各生徒について max(A[i][j], A[i][k]) を取る
生徒全員分の合計得点を求める
全体の中で最大のものを答えとして出力
計算量：O(M²×N) = 約 10⁴ 程度 
### Ruby
```ruby
# frozen_string_literal: true
n,m = gets.split.map(&:to_i)
# 生徒ごとの点数行列（2次元配列）
a = Array.new(n){gets.split.map(&:to_i)}

max_score = 0
# すべての2曲の組み合わせを全探索
(0...m).each do |i|
  (i+1...m).each do |j|
    total_score = 0
    (0...n).each do |k|
      total_score += [a[k][i],a[k][j]].max  # 各生徒の高得点を加算

    end
    max_score = [max_score, total_score].max
  end
end
puts max_score
```
### Python
```python
N,M = map(int,input().split())
# 点数行列 A[i][j]：生徒 i が曲 j を歌ったときの点数
A = [list(map(int,input().split())) for _ in range(N)]

max_score = 0
# すべての2曲の組み合わせを全探索
for i in range(M):
    for j in range(i+1,M):
        total_score = 0
        for k in range(N):# 各生徒ごとに
            total_score += max(A[k][j],A[k][i]) # 高得点の方を加算
        max_score = max(max_score, total_score) # 最大値を更新
print(max_score)
```




#### e869120さんの記事を参照しました.
[レッドコーダーが教える、競プロ・AtCoder上達のガイドライン【中級編：目指せ水色コーダー！】](https://qiita.com/e869120/items/eb50fdaece12be418faa)
OACホームページの検索ボックスでAIアシスタントを使う

# はじめに
OAC（**Oracle Analytics Cloud**）では、事前設定したデータセットを読み込んだワークブックを開いて、AIアシスタントと対話しながらビジュアライゼーションを作成することができます。
また、ホームページの検索ボックスに質問することで、そもそもどのデータセットを使うべきかわからない、といった場合でもAIアシスタントがユーザーをサポートしてくれます。

![HomePage Ask.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/2ad780e7-029b-436c-bf85-3c8298e68fc5.gif)

# Oracle Analytics AIアシスタントとは
生成AIと連携し、対話形式でのデータ分析を実現するのがOracle Analytics AIアシスタントです。
デフォルトのLLMの他、外部のLLMの持ち込み（BYO-LLM）も可能です。

https://qiita.com/tyo38/items/dcd9cf8b636d885b9b10

# 事前準備
AIアシスタントの対象とするデータセットにインデックスを作成しておきます。
データセットの「検査」メニューを開き、「検索」タブに移動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/a7b0d84b-09a8-4cb9-b4bb-6b60a65d9b9d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/19745335-8fb6-4b6a-9840-f4e5b13fd8e6.png)

「アシスタントおよびホームページの質問」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/59ce9c62-2f63-409c-945b-0575540e30b2.png)

「アシスタント」を選択した場合は、ワークブックを開いてAIアシスタントを使用することはできますが、ホームページの検索からは使用できません。

LLMへの質問に含める可能性が低い列では、インデックスを作成しないようにすることができます。
列名とは別に、使用する可能性のある名前をシノニムとして列ごとに設定することも可能です。
設定し終わったら、「即時実行」をクリックしてインデックスを作成します（または実行をスケジュールします）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/0456ad75-db79-456f-a5f9-cd1097de9d16.png)

## インデックスのヒント

https://qiita.com/tyo38/items/a6add7da7a43728b920f

# ホームページから質問してみる
OACのホームページを開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/f6288030-0a82-4575-a88f-1e841bb2fbfe.png)

質問を入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/c311c8f0-7676-49ef-8abf-c3262ab16458.png)

## 利益率が低下している製品はどれですか？ それらの製品と利益率のワースト10を表示してください
「利益率が低下している製品はどれですか？ それらの製品と利益率のワースト10を表示してください。」と入力し、Shiftキーを押しながらEnterキーを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/fd9198a7-62c5-4dc5-8e38-f709e9826493.png)

質問に回答可能なデータセットが複数見つかった場合は、切り替えてそれぞれの結果を確認することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/ba31bebb-1d1f-4432-afb6-9441200a9f89.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/b78b61a5-a4b9-4c5f-87c2-0b0c9f968d86.png)

## 名古屋における製品カテゴリ別の売上と利益と配送方法の傾向を表示して
別の質問をしてみます。
「名古屋における製品カテゴリ別の売上と利益と配送方法の傾向を表示して」と入力し、Shiftキーを押しながらEnterキーを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/9e869396-8584-4715-a1aa-d218159b98b9.png)

様々な観点からビジュアライゼーションが作成されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/6a009fdb-5f3e-40a2-8c98-0efbb7caa0d2.png)

気になるビジュアライゼーションの「ワークブックとして探索」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/f9afdddb-9a3a-41a1-b270-0ec788de9a65.png)

新しいワークブックを作成し、選択したビジュアライゼーションを表示できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/ab1cb0bd-0e1f-4ef3-be18-be3e04413a2d.png)

ここから、さらに詳細な探索を実施することができます。

# 参考情報
https://qiita.com/tyo38/items/dcd9cf8b636d885b9b10
Streamline Self-Registration for Experience Cloud Sites

https://trailhead.salesforce.com/content/learn/trails/streamline-self-registration-for-experience-cloud-sites

-------------------

# We couldn't find the 'Privacy Settings' flow enabled on the 'Customer Account Portal' profile.

+ [Challenge not yet complete in PA Implementation Playground. We couldn't find the 'Privacy Settings' flow enabled on the 'Customer Account Portal' profile.](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000JfmaM)

:::note
 i missed a step, which i figured and could complete it.
:::

# REQUIRED_FIELD_MISSING: Required fields are missing: [LastName]. You can look up ExceptionCode values in the SOAP API Developer Guide

+ [Self registration for experience cloud site Privacy Settings flow not working](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000SXiz5)
ulimit -n が足りない！？〜「Too many open files」の世界にようこそ〜

こんにちは。tampopo256です。
普段は教育系のWebサービスを作ったりしています。

Linux系OSで大量ファイル生成アプリを運用してると、ある日突然こんなエラーに出会います。

```bash
Too many open files
```

え、何これ。ちゃんとcloseしてるんだけど？という気持ち、わかります。
でもこれ、**システムのせい**なんです。まさに「`ulimit -n`地獄」の始まり。

## `ulimit -n`って何者？

Linux系OSには「同時に開けるファイルディスクリプタの数」に制限があります。
それを管理しているのが `ulimit -n`。

試しに叩いてみましょう。

```bash
$ ulimit -n
1024
```

出た数字が「**1プロセスが同時に開ける最大ファイル数**」です。
ファイルだけでなく、ソケットやパイプもカウントされます。


## 実際の現場：PDF生成ツールが爆発した話

たとえば社内で使っている「clemyのアカウント初期設定PDF自動生成ツール」
生徒ごとに初期パスワードとアカウント設定をPDF化して渡す便利な仕組みですが…

* まとめて大量生成する
* しかも裏で並列処理してる

みたいな状況になると、ある日こうなります。

```
Too many open files
PDF生成に失敗しました
```

PDFが空になったり、初期パスワードが消えてたり、最悪の場合は**何も出てこない**という地獄絵図。
ファイルディスクリプタ（fd）が足りてない、ってわけですね。

## 対処法：`ulimit -n 65535` してみよう

とりあえず一時的に上げたいなら、こう。

```bash
ulimit -n 65535
```

## 終わりに

社内ツールでも、プロダクションでも、**「Too many open files」は他人事じゃない**です。

> ファイル大量作成や編集系のアプリが急に動かなくなった

**まずは`ulimit -n`を疑ってみる**のも一手です。
【パフォーマンス改善】画像の最適化 Tips まとめ

## はじめに

Webサイトの表示速度を改善したいとき、まず見直すべきポイントのひとつが「画像」です。

特に、**Core Web Vitals**（LCPなど）の指標でも画像の表示速度が重視され、画像を最適化することが求められています。

そのため、この記事では、実際にQiitaで取り入れている画像最適化のTipsをまとめてみました。

## 画像の最適化について

画像の最適化が特に重要になる理由のひとつが、**LCP（Largest Contentful Paint）** という指標です。
このLCPは、GoogleもCore Web Vitalsの一環として重視しており、スコアがSEOにも影響を与えます。

そのため、画像を最適化することで、表示順位を改善したり、UXも改善できます。

:::note
**LCPとは？**
LCPは、ページの中で最も大きなコンテンツ（画像やテキスト）が表示されるまでの時間を測る指標で、ユーザーが「ページが読み込まれた」と感じる速さに直結します。
:::

具体的に、画像の最適化とは、主に以下のような観点で画像の扱いを見直します。

+ ファイルサイズを小さくする
+ 必要な画像だけを表示する
+ 適切なフォーマットやサイズを選ぶ

このあたりの観点に、画像最適化のTipsを紹介します。

## 画像最適化Tips
### ◯ 画像のファイルのメタデータを削除する
FigmaやIllustratorなどから画像を書き出すと、メタデータも一緒に保存されています。
そのため、肥大化したメタデータを削除することで、ファイルサイズを小さくすることができます。

メタデータを削除するために使っているツールは、ImageOptimというツールです。

https://imageoptim.com/mac

### ◯ WebPやAVIFを使う
画像フォーマットをWebPやAVIFに変えるだけで、ファイルサイズを30〜70%削減できることがあります。
特にヒーロー画像や大きなバナー画像では、読み込み時間に大きな差が出ます。

:::note
**WebPとは？**
Googleが開発した　画像フォーマットで、JPEGと同じ画質で、ファイルサイズが小さくでき、αチャンネルやアニメーションにもサポートしているのが特徴です。
https://developers.google.com/speed/webp/faq?hl=ja
:::

:::note
**AVIFとは？**
WebPよりも高い圧縮率を実現でき、同じ画質でもよりファイルサイズを小さくできるのが特徴です。
また、HDR、10bitカラー、広色域に対応にも対応しています。
ただ、WebPと比べると、エンコード・デコードに時間がかかるらしいです。
:::

使うイメージとしては、こんな感じになるかと思います。

```sample.html
<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="説明文">
</picture>
```

### ◯ デバイスに応じた画像を出し分ける
デスクトップサイズで作られた画像をモバイルで表示させると、必要な画像サイズより大きいため、読み込み時間の無駄が発生します。
そのため、デバイスに応じた画像サイズで表示させてあげることで、パフォーマンスは改善します。

そのため、やり方いろいろあるとおもうので、プロダクトにあったやり方で対応しましょう！
1つの画像を複数書き出して、`<picture>` を使って、出し分けたり、
imgixなどのCDNとかを使って、最適かするのでもいいと思います。


### ◯ 遅延読み込みを取り入れる
初期表示に不要な画像は後で読み込む設定をすることで、読み込み時間を短縮させ、パフォーマンスが改善します。

遅延読み込みは、`<img>`タグに `loading="lazy"` を使うことで、簡単に設定することができます。

```sample.html
<img src="image.jpg" loading="lazy" alt="説明文">
```

## まとめ
画像の最適化は、手軽に始められて、効果も大きいパフォーマンス改善の手段です。
特に、LCPのようなユーザー体験に直結する指標において、画像の最適化はとても重要な役割を果たします。

今回紹介したように、

- メタデータの削除
- 軽量フォーマット（WebP / AVIF）の導入
- デバイスに応じたサイズの出し分け
- 遅延読み込み（Lazy Load）の活用

といった施策を一つずつ取り入れるだけでも、表示速度やUXは大きく改善できます。

まずはできそうなところから一つずつ、取り入れてみてください！
小さな積み重ねが、プロダクト全体の品質向上につながります。

---
最後まで読んでくださってありがとうございます！

普段はデザインやフロントエンドを中心にQiitaに記事を投稿しているので、ぜひQiitaのフォローとX(Twitter)のフォローをお願いします。

https://twitter.com/degudegu2510
Dify入門：生成AIアプリの使用状況ダッシュボードを見てみる（データ分析機能）

# はじめに

Difyは、ノーコードで生成AIアプリを構築できる便利なプラットフォームとして注目されていますが、運用面で役立つ「利用状況の可視化」機能も備えています。アクティブユーザー数やトークンの使用量、メッセージ数など、運用中のアプリの状態をひと目で確認できます。

この記事では、Difyの利用状況確認機能でどんなことが見えるのかをサクッと紹介します。


# 利用状況の確認

アプリケーションの左側のメニュバーから「**監視**」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3963468/be0b4dce-31a7-407b-acac-600fd85aec50.png)

## データ分析

「**分析**」では、トークン使用量やアクティブユーザー数、ユーザー満足度（いいねの数）などのデータを確認できます。
表示範囲を指定できます。
※この分析データはほぼ遅延なくすぐに情報が更新されるイメージでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3963468/8cefbd42-2618-45bc-8686-03e0e5e76f0a.png)



#### 総会話数
ユーザーとAIがやり取りしたメッセージの総数です（ユーザーとAI間の1往復で1カウント、プロンプトエンジニアリングやデバッグは含まれません）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3963468/07f77233-bc51-42de-9e72-58f9d672a831.png)

#### アクティブユーザー数
一定期間内にAIと少なくとも1問1答以上の会話をしたユニークユーザーの数です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3963468/46c1acab-62df-4c2a-b67b-2141b8f2135d.png)


#### 平均セッションインタラクション数
1ユーザーあたりの平均的な会話ラウンド数を示す指標で、どれだけ深く対話されているか（粘着性）を表します。ユーザーが AI と 10往復の質問と回答を行った場合、その数値は 10 になります。※対話型アプリでのみ確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3963468/bd796700-9003-49bd-aee2-e7bc1d1bc2a5.png)


#### トークン出力速度
AIが毎秒どのくらいのスピードで応答（トークン出力）しているかを示します。生成速度や処理負荷の目安になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3963468/06889a67-3451-4c01-ba42-a01c636f30e6.png)


#### ユーザー満足度率
Difyではチャットボットから応答に「いいね」で評価をすることができます。ここでは1000メッセージあたりの「いいね」数を示します。ユーザーの満足度の目安です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3963468/6a928352-2c1e-444e-b51e-bfbee0335b36.png)

#### トークン使用量
アプリが1日に消費したトークン数を示します。利用状況やコスト管理の参考になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3963468/72e3db4f-f310-47e8-a914-344db8b273be.png)


#### トータルメッセージ数
1日に発生した会話セッションの数です。ユーザーからの質問にチャットボットが応答すると１カウントされます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3963468/fdb8bb7a-dec5-4953-a61e-84156379adb5.png)


# 参考
[Dify - ドキュメント　モニタリング　データ分析](https://docs.dify.ai/ja-jp/guides/monitoring/analysis)
意外と知らない？地味だけど便利なMySQL関数たち


こんにちは。tampopo256です。
普段は教育系のWebサービスを作っています。

さて、MySQLって結構長い付き合いなんですが、使えば使うほど、

**「え、こんな関数あったの！？」**

ということが出てきます。
今回は、意外と知られていないけど、地味に便利なMySQLの関数たちを紹介します。

## 1. FIELD()：値の「順位」を返すやつ
たとえば、こういうやつ。

```sql
SELECT FIELD('banana', 'apple', 'banana', 'orange'); -- → 2
```
「banana」は2番目に出てきたので、結果は2。
見つからないと0になります。

```sql
SELECT FIELD('grape', 'apple', 'banana', 'orange'); -- → 0
```
これ、地味に便利で、手軽な並び順カスタムに使えます。

```sql
ORDER BY FIELD(status, 'pending', 'review', 'done')
```
これで、SQLだけでカスタムソートできます。
CASE WHENでゴリゴリ書いてた自分、さようなら👋

## 2. ELT()：インデックスから値を引く逆バージョン
これはFIELD()の逆みたいなやつです。

```sql
SELECT ELT(2, 'apple', 'banana', 'orange'); -- → banana
```
インデックス2を指定すると、2番目の'banana'を返します。
地味にENUMのラベル化とかに使えたりします。

## 3. FIND_IN_SET()：カンマ区切り文字列を検索できる
```sql
SELECT FIND_IN_SET('banana', 'apple,banana,orange'); -- → 2
```
「banana」は2番目に出てきた、という意味。
つまり、DB設計が微妙で、CSVで値が入ってるテーブルに出会ったときの救済関数。

```sql
SELECT * FROM fruits WHERE FIND_IN_SET('apple', tags);
```
※もちろん正規化したほうが良いです。

4. IFNULL()とNULLIF()：名前がややこしい双子関数
違い、ちゃんと覚えてますか？

```sql
SELECT IFNULL(NULL, 'default'); -- → 'default'
```
こっちはNULLだったら第2引数を返すやつ。

```sql
SELECT NULLIF(1, 1); -- → NULL
SELECT NULLIF(1, 2); -- → 1
```
こっちは「2つが等しければNULLを返す」。
0で割るなエラーを避けるときに役立ちます。

```sql
SELECT 10 / NULLIF(0, 0); -- → NULLになるからエラー回避
```
地味だけど、覚えておくと助けてくれます。

## 5. STR_TO_DATE() と DATE_FORMAT() の合わせ技
日付フォーマットを変換するとき、毎回ググってませんか？

```sql
SELECT STR_TO_DATE('2025/06/17', '%Y/%m/%d'); -- → '2025-06-17'
SELECT DATE_FORMAT(NOW(), '%Y年%m月%d日'); -- → '2025年06月17日'
```
人に読ませる用にもってこい。

# おわりに
MySQLって、なんかいつも COUNT(*) と GROUP BY しか使ってない気がしますよね。
でも、こういう地味な関数たちもちゃんと使ってあげると、

「SQL、ちょっと気が利くじゃん？」

って思えたりします。

今回紹介した関数たちは、運用でもちょこちょこ使っていて、「あ〜これあったんだ助かる〜」ってなった子たちばかりです。

もし他にも「これ使えるよ！」っていう関数があれば、コメントで教えてもらえると嬉しいです 🙌
【個人開発】AI学習の"次の一冊"が見つかる！教材ライブラリ「SAKAItechLibrary」を公開しました

皆さん、こんにちは！

この度、「未来を創るAI技術を、深く・体系的に学ぶ」をコンセプトにした電子書籍・教材のライブラリサイト **SAKAItechLibrary** を個人開発しました。

**Webサイトはこちら**
https://sakaitechlibrary.web.app/

「AIを学びたいけど、どの本から読めばいいかわからない…」
「自分のレベルに合った、実践的な教材が見つからない…」

そんな悩みを解決するための一助となればと思い、このサイトを開発しました。

## 「SAKAItechLibrary」とは？

AI・機械学習・深層学習の分野に特化した、書籍や教材を探せるライブラリサイトです。
世の中に数多ある優れた教材の中から、自分にピッタリの一冊を見つけるためのプラットフォームを目指しています。

**こんな方におすすめです！**
- AI・機械学習をこれから学びたい、学び始めた方
- 次に学ぶべきテーマや、より専門的な教材を探している中級者の方
- 知識を体系的に整理したい、学びを深めたいと考えている方

## サイトの主な特徴

学習者が本当に知りたい情報にすぐアクセスできるよう、以下の3つの特徴を持たせました。

#### 1. 目的から探せる詳細な情報
書籍ごとに、内容紹介はもちろん、「学習内容」「対象読者レベル」「得られるスキル」などを詳しく掲載しています。目次情報も確認できるので、購入前に内容をしっかり吟味できます。

#### 2. 強力な検索・絞り込み機能
「`Python`」「`画像認識`」「`初心者向け`」といった**タグ**や、キーワードで簡単に書籍を検索できます。膨大な情報の中から、あなたの目的に合った教材を素早く見つけ出します。

#### 3. 学習リソースのハブとなる外部連携
書籍情報だけでなく、関連するUdemy講座などの外部学習リソースへのリンクも掲載。本で学んだ知識を、動画教材などでさらに深めることができます。

## 技術スタック（開発者向け）

サイトの高速表示と快適なブラウジング体験を実現するため、以下の技術スタックを採用しました。

- **フレームワーク**: `Next.js` (App Router + 静的エクスポート)
- **言語**: `TypeScript`
- **スタイリング**: `Tailwind CSS`
- **UIコンポーネント**: `Radix UI`, `Lucide`
- **ホスティング**: `Firebase Hosting`

Next.jsの静的エクスポート機能とFirebase Hostingを組み合わせることで、表示速度が速く、かつセキュアなサイトを構築しています。

## さいごに

「SAKAItechLibrary」が、皆さんのAI学習の羅針盤のような存在になれれば幸いです。
ぜひ一度サイトを訪れて、あなたの学習を加速させる一冊を見つけてみてください。

「こんな機能が欲しい」「この本も載せてほしい」などのご意見・ご感想も大歓迎です。ぜひコメントで教えてください！
ChatGPTのコード、動いたけど“わかってない”あなたへ贈る記事【JavaScript初〜中級者向け】 Vol.4

## はじめに
前回の記事では、ChatGPTが当たり前のように使ってくる“関数まわり”の仕組みについて解説しました。

https://qiita.com/mukai3/items/7909df724da53c366e93

今回は、ChatGPTがよく出してくるけど「なんとなく書いてるだけ」になりがちな、**分割代入・スプレッド構文・restパラメータ**などの“構文理解”を深掘りしていきます。

「動くけど、カスタマイズは無理」という状態から脱出しよう！

---

## 1. 配列の分割代入

```js
const arr = [1, 2, 3];
const [a, b] = arr;
console.log(a); // 1
console.log(b); // 2
```

✅ **配列の順番で変数に代入される**

```js
const [first, , third] = [10, 20, 30];
console.log(third); // 30
```

👉 **スキップもできる**

---

## 2. オブジェクトの分割代入

```js
const user = { name: "ムカイ", age: 26 };
const { name, age } = user;
console.log(name); // ムカイ
```

✅ **キー名と変数名が一致するなら、簡略に書ける**

```js
const { name: username } = user;
console.log(username); // ムカイ
```

👉 **別名をつけたいときは `:` を使う**

---

## 3. スプレッド構文（展開）

```js
const arr1 = [1, 2];
const arr2 = [...arr1, 3, 4];
console.log(arr2); // [1, 2, 3, 4]
```

✅ **配列のコピーやマージに使える**

```js
const user = { name: "ムカイ" };
const extended = { ...user, age: 26 };
console.log(extended); // { name: "ムカイ", age: 26 }
```

👉 **オブジェクトも展開できる**

---

## 4. restパラメータ（残り全部受け取る）

```js
function sum(...numbers) {
  return numbers.reduce((acc, n) => acc + n, 0);
}
console.log(sum(1, 2, 3)); // 6
```

✅ **「不特定数の引数をまとめて扱う」関数で便利**

---

## 5. 分割代入 + デフォルト値 = 最強

```js
const user = { name: "ムカイ" };
const { name, age = 20 } = user;
console.log(age); // 20（userにageがなければ20になる）
```

👉 **APIレスポンス処理などでめちゃくちゃ便利**

---

## 6. よくある「ChatGPTが使ってくる構文」読解練習

```js
function greet({ name, age = 18 }) {
  console.log(`Hi ${name}, you are ${age}`);
}

greet({ name: "ムカイ" }); // → Hi ムカイ, you are 18
```

✅ 何が起きてる？

* `greet`の引数で直接オブジェクトのプロパティを受け取ってる
* ageにデフォルト値が指定されてる

→ **ChatGPTはこういう記述をナチュラルに返す。読めないとカスタマイズできない。**

---

## まとめ：構文の「意図」がわかれば怖くない

| 構文        | 使う意味          |
| --------- | ------------- |
| 配列分割      | 順番で値を取り出す     |
| オブジェクト分割  | キー名でピンポイント抽出  |
| スプレッド     | 値をコピー・合体・展開する |
| restパラメータ | 可変引数を配列で受け取る  |
| デフォルト値    | 未定義でも安全に処理する  |

---

## おわりに

分割代入やスプレッド構文は、**今どきのJSでは「読めないと詰む」くらい頻出な構文**です。

ChatGPTを“ただの自動コーディングマシン”にせず、**“相棒”として使いこなすには、こうした構文の理解が不可欠。**
5250, CLコマンドの代わりにSQL(IBM iサービス）でシステム構成情報を取得する

システムを新規構築した際などシステム構成情報をドキュメント化すると思います。その際調査が必要となる項目の多くは現在SQL(IBM i サービス）で取得できるようになっています。とりあえず目についたものをまとめてみます。

***※ もし、これは取得できる？というのを見つけましたらコメント頂けますと幸いです‥。***

色々な取り方が出来そうと分かりましたので、一例としてご覧ください。

## IBM i で管理すべきシステム構成情報

まずは基本的なものだけです。ほかにハードウェア構成や導入ソフトウェアで別途必要な場合があります。

**全体像 ver.1** 随時更新予定です・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/b2473180-37c8-4716-9a80-ec9fc3d34096.png)

## それぞれのシステム構成情報取得方法

### ハードウェア構成情報
WRKHDRRSCコマンド　→　[QSYS2.Hardware_Resource_Info テーブル関数](https://qiita.com/gomAnomalocaris/items/3280890ec7f291e939e2)

### CPU,メモリ構成
WRKHDRRSCコマンド　→　[SYSIBMADM.Env_Sys_Infoビュー
](https://qiita.com/gomAnomalocaris/items/ee8c1c96536f34056038)

### ストレージ
WRKDSKSTSコマンド　→　[QSYS2.SysDiskStat ビュー](https://qiita.com/gomAnomalocaris/items/4006cffb7acdd07781ca)

### ソフトウェア情報
DSPSFWRSCコマンド　→　[QSYS2.LICENSE_INFO ビュー](Https://www.ibm.com/docs/ja/i/7.6.0?topic=services-license-info-view)

### PTF情報
DSPPTFコマンド　→　[QSYS2.PTF_INFO ビュー](https://www.ibm.com/docs/ja/i/7.6.0?topic=services-ptf-info-view)

### グループPTF情報
DSPPTFGRPコマンド　→　[QSYS2.GROUP_PTF_INFO ビュー](https://www.ibm.com/docs/ja/i/7.6.0?topic=services-group-ptf-info-view)

### システム値
DSPSYSVALコマンド　→ [QSYS2.SYSTEM_VALUE_INFO ビュー](https://qiita.com/gomAnomalocaris/items/a106f5a0790556e161ff)

### ユーザー・プロファイル情報
DSPUSRPRFコマンド　→ [QSYS2.User_Info ビュー](https://qiita.com/gomAnomalocaris/items/360e2ba6697640fc5601)

### システム応答リスト
WRKRPYLEコマンド　→　[QSYS2.REPLY_LIST_INFO ビュー](https://www.ibm.com/docs/ja/i/7.6.0?topic=services-reply-list-info-view)

### ライブラリー一覧
DSPLIBコマンド　→　[QSYS2.SYSTEM_OBJECT_TYPES テーブル](https://www.ibm.com/docs/ja/i/7.6.0?topic=services-system-object-types-table)

### IFS一覧・容量
GO DISKTASKSコマンド　→　[IBM iのIFS（統合ファイルシステム）のファイルサイズを調べたい](https://qiita.com/gomAnomalocaris/items/239abd057214ff9203d4)
【個人開発】AI・プログラミング初学者のための学習サイト「SAKAItech」を公開しました！

皆さん、こんにちは！

この度、AIやプログラミングを学ぶためのUdemy講座紹介サイト「**SAKAItech**」を個人開発し、リリースしました！

**Webサイトはこちら**
[https://udemy-c1f90.web.app/](https://udemy-c1f90.web.app/)

この記事では、サイトを作った想いや特徴、そして使用した技術についてご紹介します。

## 背景：なぜこのサイトを作ったのか

私自身、AIやプログラミングを学習する中で、「何から学べばいいかわからない」「環境構築で挫折してしまった」という声をよく耳にしてきました。

そこで、**初心者でも、実践的かつ視覚的に楽しく学べるコンテンツを届けたい**という想いから、学習の入り口となるようなプラットフォームとして「SAKAItech」を開発しました。

## 「SAKAItech」で学べること

「SAKAItech」では、私がUdemyで公開しているAI・プログラミング講座を紹介・販売しています。
特に、これからAIを学びたいという方に向けた、以下のような実践的な講座を揃えています。

- **Pythonを使った画像認識入門**
- **CNN（畳み込みニューラルネットワーク）の基礎から実践**
- **データ拡張（Data Augmentation）の実践講座**
- **強化学習（Q学習・DQN）の実装**
- **Raspberry Piの入門講座**

## 学習体験の3つの特徴

学習のハードルを少しでも下げるため、コンテンツには以下の3つの特徴を持たせています。

1.  **図解やアニメーションを多用した、とにかく分かりやすい説明**
    専門用語も、初学者の方がイメージしやすいように丁寧に解説しています。

2.  **手を動かしながら学ぶ「ハンズオン形式」**
    知識をインプットするだけでなく、実際にコードを書きながら学ぶことで、スキルが定着しやすいカリキュラムです。

3.  **環境構築が不要（Google Colabを使用）**
    多くの初学者がつまずきがちな環境構築。本講座ではGoogle Colabを使用するため、ブラウザさえあればすぐに学習を始められます。

## こだわりのデザインと技術スタック

開発者の方々に向けて、サイトのデザインや使用技術についても少しご紹介します。

#### デザイン
学習のモチベーションが上がるような、モダンで少し未来感のあるデザインを目指しました。
- **ネオンカラー**を基調とした配色
- 心地よい**アニメーション背景**とUIのカスタムアニメーション
- PC・スマホ両方で快適に閲覧できる**レスポンシブデザイン**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921163/883e50c9-b46d-4f33-8471-c2cd387ab199.png)

#### 技術スタック
フロントエンドは、モダンな開発環境で構築しました。
- **フロントエンド**: `React` + `TypeScript`
- **スタイリング**: `Tailwind CSS`
- **アニメーション**: `カスタムアニメーション効果`

## さいごに

「SAKAItech」が、これからAIやプログラミングを学ぼうとしている方々にとって、その一助となれば大変嬉しく思います。

ぜひ一度サイトに訪れてみてください！

**SAKAItech**
[https://udemy-c1f90.web.app/](https://udemy-c1f90.web.app/)

記事を最後まで読んでいただき、ありがとうございました。
「もっとこうしたら使いやすい」「こんな講座が欲しい」といったご意見・ご感想があれば、ぜひコメントで教えてください！
彼女に暗号化メッセージで愛を伝えよう

:::note warn
彼女がエンジニア以外の場合は喧嘩に発展する場合があります
:::

こんにちは。tampopo256です。
「Qiita Tech Festa 2025」記念すべき1記事目です。

皆様、彼女に愛を伝えたい時ってどういう伝え方をしますか？

##  「大好き」と伝える
これはどストレートの平文ですね
何も隠せていませんのでワクワク感に欠けています。


## 「e6849be38197e381a6e3828b」と伝える
一気に意味わかんなくなりましたが、パッと見で16進数(未圧縮)とわかりますので、簡単に変換するだけです。

## 「101001111010010110111101110001111000000110110001」と伝える
流石にこれが送られてくると、あれですね。
でもパッと見で2進数(未圧縮)であることはわかりますので、変換するだけです。

## こんな暗号なんてワクワクしない
ここまで3つの簡単な暗号化方式を紹介しましたが、こんな暗号化で愛を伝えられてもあなたのエンジニア愛までは伝わりませんよね？

ということで適切な暗号化方式をお伝えしたいと思います。

# 最適な愛の暗号化方式とは？
## 1. Base64エンコード（+甘めのコメント）
彼女がエンジニアでない場合でも、「ちょっとだけ変わったラブレター」として受け入れてもらいやすい暗号です。
```
5aSn5aW944GN44Gn44GZ
```
「ヒントは“Base64”だよ」と伝えると、意外に楽しんでもらえると思います。

例文：

`5aSn5aW944GN44Gn44GZ`
→ Base64デコードしてもらうと → 「大好きです」

## 2. AES暗号 + 口頭で鍵を渡す（ドキドキ共有）
もし、エンジニアでなくても**宝探し感覚**が好きな彼女であれば、
暗号本文はAESで暗号化し、復号鍵を“デート中に耳打ち”なんて演出も素敵です。

```bash
echo "大好きだよ" | openssl enc -aes-256-cbc -a -salt -pass pass:orange
```
出てきた暗号文を送信しておいて、

「あのときのパスワード、覚えてる？」

と問いかけると、記憶と愛の両方を試せます。

## 3. ステガノグラフィー（画像に忍ばせる）
これはエンジニア度が高い彼女向けですが、「普通の画像に秘密の愛のメッセージが隠れている」なんて、映画のような展開。

画像に「大好きだよ.txt」を埋め込み

steghideなどのツールを使って秘密の共有

```
steghide embed -cf lovely.jpg -ef daisuki.txt -p mysecret
```
これは彼女の勘が良くないと気づいてもらえませんが...

## まとめ：適切な暗号方式とは？
| 技術レベル | 暗号化方式 | 備考 |
|:-:|:-:|:-:|
| 非エンジニア |  Base64 | ヒント付きでワクワク感を  |
| 中級エンジニア |  AES + 鍵渡し |  宝探し的な演出で楽しく |
| 上級エンジニア |  ステガノグラフィー |  解読できたら運命を感じる |


次の記事では「別れ話をハッシュ関数で表現する」なんてのも良いかもしれませんね（？）

いいねとコメントをお待ちしております！
【個人開発】Claude Code Maxで“静けさ”を作る──6つの窓と12時間の開発ログ「Quiet View」

> **「広告もレコメンドもない“静けさ”を、Webで眺めたくなった」**  
> そんな違和感から生まれたのがこの「Quiet View」というプロダクトです。  
> Claude Code Max を使って、**環境構築からわずか 12 時間で完成しました。**

---

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2731307/52540246-9704-4adf-bf41-787e5186aa9c.png)

> **本業はフルタイムで手一杯。アイデアは山ほどあるのに、実装時間を思うと腰が重い
> そんな停滞を、Claude Code Max が一瞬で動かしてくれました。**

> **「ライブ映像を眺めたい。でも YouTube では広告とおすすめがうるさすぎる」**  
> その違和感を、Claude Code Max と 12 時間でプロダクトにしました。

- 🌐 Quiet View : [https://quietview.app](https://quietview.app)  
- 👤 作った人 : [gomatofu](https://github.com/gomatofu)  
- 💻 リポジトリ : [github.com/gomatofu/quiet-view](github.com/gomatofu/quiet-view)
- ⚙️ Stack   : Next.js + Tailwind


## なぜ作ったか

### 1. “静けさ” がどこにもない

SNS、動画、ニュース――すべてが  
> 「もっと見て」「もっと滞在して」「もっと消費して」  
と叫んでくる。  
それに疲れたとき、**本当に欲しかったのは「動かない UI」** でした。

### 2. YouTube のライブカメラは最高なのに、周辺がノイズ

各都市のライブカメラは美しい。  
でもページを開いた瞬間に**広告・コメント・レコメンドの嵐**。  
> コンテンツそのものは静かなのに、器がうるさい。  
この“静と騒”のギャップを埋めたかった。

### 3. 「体験」だけを先に決める開発を試したい

- **機能は最小**、コンセプトは最大  
- AI（Claude Code Max）と *会話だけ* で設計を固める  
- 実装は AI に寄せ、**人間は体験のディレクション** に集中

## Claude Code Max との 12 時間

| 時間帯 | 会話ログ (要約) | 出来たもの |
|:--|:--|:--|
| 0 – 4h  | “静けさを Web 上に置きたい”<br>→ UI モック案 | コンセプト定義 + モック |
| 4 – 6h  | 技術選定（Next.js / Tailwind）| スタック決定 |
| 6 – 12h | Claude に実装指示 → コード生成 | MVP 完成＆デプロイ

> 🧠 **補足**：この記事も Claude による自動生成です。人間は方向を決めただけ。

## Quiet View が守った 3 つのルール

1. **UI は動かさない**  
   - ボタンは Lo-Fi 切替だけ。タイムラプスもオフ  
2. **文字は都市名と時刻だけ**  
   - 情報を足すより、そぎ落とす  
3. **音はデフォルト無音**  
   - “静けさ” が主役。Lo-Fi はあくまでオプション  
   - 必要なときだけ、そっと流せるようにしています

## 使ってみてほしい 3 つのシーン

| 🕰️ シーン | 体験 |
|------------|------|
| **朝のコーヒー** | 他都市の夜明けを BGM 代わりに |
| **作業 BGM** | タブを横に置くだけで集中空間 |
| **就寝前** | 世界の静けさでスクロール欲をリセット |

## 実際のところ、ほとんどコードを書いていません

書いたのは背景色のクラス名を変えたくらい。あとは Claude に「こういう体験がいい」と伝えただけです。

**MCP (Model Context Protocol)** で複数のツールを連携：

```json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "your_token",
        "GITHUB_OWNER": "your_username", 
        "GITHUB_REPOSITORY": "your_repo"
      }
    },
    "Framelink Figma MCP": {
      "command": "npx",
      "args": ["-y", "figma-developer-mcp", "--figma-api-key=your_key", "--stdio"]
    }
  }
}
```

**結果**: 「Figmaのこのデザインを実装して」→30秒で完成

### すぐ試せる設定

1. **プロジェクトルートに `.claude/mcp.json` 作成**
2. **GitHub Token**: Settings > Developer settings > Personal access tokens
3. **Figma API Key**: Figma Settings > Personal access tokens  
4. **Claude Code Max再起動** → 自動連携開始


## まとめ

これまで、アイデアは浮かんでも「実装の壁」で諦めてきたものがたくさんありました。
でも今回、Claude Code Max のおかげで、“やりたいこと”がそのまま形になる感覚を初めて味わいました。

思いついた瞬間に手を動かせる。
エディターと自分の意思が直結したような体験でした。

**体験を作る → AI が実装 → すぐ試す → また体験を磨く**  
このループこそが、最速のものづくりだと確信しました。

---

🌍 **Quiet View**  
**Six windows. One quiet world.**  
[https://quietview.app](https://quietview.app)

---

👋 読んでくれてありがとうございます！  
もし Quiet View が気に入ったら、SNS で `#QuietView` をそっと付けてシェアしてもらえると嬉しいです。
🧡 記事が役に立ったら「いいね」「ストック」してもらえると励みになります！
【本当に何も知らない状態から知ってみよう①】HTMLとは、なんなのさ??

# はじめに

- この記事は5分あれば読めます

# どんな人に向けた記事?
- HTMLという言葉は聞いたことあるが、何なのかよく分からない人

# この記事で分かること
- HTMLが何なのか、ざっくりと理解できる

# 以下から本編!!
## HTMLって、そもそも何？
- Webサイトに表示する文章・画像・リンクなどを構成する言語
- Webサイトは、主に3つの要素で構成されている
    1. **HTML: Webサイトの「骨格」を作る。（本記事はココ!）**
    1. CSS: Webサイトの「見た目」を整える。（色、大きさ、配置など）
    1. JavaScript: Webサイトに「動き」をつける。（アニメーション、クリックすると動くなど）


## 実際にHTMLを見てみよう!

- HTMLは、「タグ」という`<p>`のような「`<`（開始記号）」と「`>`（終了記号）」で囲まれた特別な記号のこと
- 実際のタグはこのような感じ↓

```
<!DOCTYPE html>
<html>
<head>
    <title>初めてのWebサイト</title>
</head>
<body>

    <h1>はじめてのHTML！</h1>
    <p>初めて作ったウェブページ！</p>

</body>
</html>
```

## Webサイトを作ってみよう!
- 実際にサイトを作ると分かった感じになると思うので、やってみましょう!
### 1分でWebサイトを作る!
1. 上記の`<!DOCTYPE html>`から`</html`>をコピーする
1. パソコンに入っている「メモ帳」アプリを開く
1. １でコピーしたものを貼り付ける
1. 「ファイル」→「名前を付けて保存」で保存
    - ファイル名は「index.html」にする
    - ファイルの種類を「すべてのファイル」に設定し、文字コードを「UTF-8（下記画像の黄色部分）」にする
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578844/4cc07847-6ee2-4a7b-b41c-53fe60359dbe.png)


1. 保存した「index.html」ファイルをダブルクリックでひらいてみる
1. 下記の画像のように、ブラウザでWebページが表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578844/481a060a-d7f6-40ae-bf69-d354dae6b033.png)
1. Webページ完成🎉

## 最後に
- 超簡単なWebサイトですが、実際にサイトを作ることで、HTMLを少し身近に感じてもらえるのではないでしょうか??
- 僕も知らない事の方が圧倒的に多いので、ここから勉強していきます!!
【Laravel】マルチログインのセッションについて

## はじめに
個人開発でマルチログインを実装した後に挙動を確認してみるとsessionが上手く制御できていなかったので解決策を5ステップにまとめて忘備録として残します。
拡張性についても意識して調整を行ったので似たような実装を行なっている方達に参考にしていただけますと幸いです。

## 前提条件
①ローカル環境上でdocker-composeにて以下の構成になるようにコンテナを作成しています。

言語 php
RDBMS mysql
webサーバーソフトウェア nginx
メールサーバーあり
redisあり

※今回の投稿にて、各ソフトウェアのバージョンは無関係と認識しているので割愛します。

②認証機能についてはLaravel/Breezeを使用しており、Laravel/permissionも導入済みです。
③マルチログイン機能についても実装済みの状態です。

## 発生した現象と仮説
以前、こちらの記事でマルチログイン機能を実装した際にAdminとCustomerでアカウントテーブルを分離してログイン機能を実装したがsessionの情報を確認した所.....

①ID1のAdminでログインを実施し、sessionsテーブルにレコードが生成されている事を確認
②ID1のAdminでログアウトを実施し、①によって生成されたレコードの内容が更新
③ID1のCustomerでログインを実施し、sessionsテーブルにレコードが生成されるかと思いきや、①によって生成されたレコードの内容が更新

→IDが同一の & 同一のsessionsテーブルで管理している関係で正しいsessionsレコードの発行~更新がされていないと推測

## 対応内容
各guard用のsessionsテーブルを作成してmiddlewareの処理で制御されるように調整

## 具体的な対応内容
### 1.以下のMigrationファイルの作成を行なって、テーブルの作成を実施する

admin_sessions
customer_sessions

```
// create()の第一引数は上記の項目の通りに書き換えてください
Schema::create('xxxxxxxxx_sessions', function (Blueprint $table) {
            $table->string('id')->primary();
            $table->foreignId('user_id')->nullable()->index();
            $table->string('ip_address', 45)->nullable();
            $table->text('user_agent')->nullable();
            $table->longText('payload');
            $table->integer('last_activity')->index();
        });

public function down(): void
    {
        Schema::dropIfExists('xxxxxxxxx_sessions');
    }
```

### 2.以下のコマンドを実行して①のtableの作成を実施する
```
 php artisan migrate
 ```

 ### 3.以下のコマンドでmiddlewareファイルの作成を行う
 ```
php artisan make:middleware SetSessionTablePerGuard
 ```
 ※Class名については一目で分かるような任意の名前であれば問題ないです。

 ### 4.作成したMiddlewareのhandleを以下の通りに編集

```
if ($request->is('admin/*')) {
            Config::set('session.table', 'admin_sessions');
        } 
        
        if ($request->is('customer/*')) {
            Config::set('session.table', 'customer_sessions');
        }

        return $next($request);
}
```
→内容としてはシンプルでurlがadmin関連の場合はadmin_sessionsテーブルを参照して、customer関連の場合はcustomer_sessionsテーブルを参照するといったロジック

### 5.app.phpへの設定
bootstrap/app.phpの中に作成したクラスを記載します
```
$middleware->alias([
            'set.session.table' => \App\Http\Middleware\SetSessionTablePerGuard::class,
        ]);
```
→StartSession が先に動くと、config('session.table') はすでに読み込まれておりそちらを優先してtableに情報が書き込まれるので、web.phpではなくprepend()を使用して先行して動作するように制御します。


## まとめ
上記の通りに実装する事でsessionを対象のテーブルで制御できるようになるかと思います。
マルチログインの実装方法については是非以下の記事を参考にしてみて下さい。

https://qiita.com/haragoo/items/52ada2b2fea8bd80df15
paizaラーニングレベルアップ問題集の「要素の種類数」をやってみた。

paizaラーニングレベルアップ問題集の[要素の種類数](https://paiza.jp/works/mondai/array_utilization_primer/array_utilization_primer__kind)をやってみました。
- - -
###### 問題
https://paiza.jp/works/mondai/array_utilization_primer/array_utilization_primer__kind
- - -
###### 方針
1. カウンタ変数$c$を$c=0$で初期化します
1. 要素数101の整数配列$B=(b_j)_{j=0,\dots,100}$を宣言し、各要素$b_i$（$i=0,1,\dots,100$）を$b_i=0$で初期化します
1. 入力配列$A=\(a_i\)_{i=1,\dots,N}$の各要素$a_i$について
	- $B_{a_i}=0$ならば
		- カウンタ変数$c$に$1$を足します
		- $B_{a_i}=1$（$0$や偽と評価されない任意の値）とします
1. カウンタ変数$c$を出力します

と書いたものの、結局「集合」を使ってます。
- - -
###### C
```c
#include <stdio.h>

int main() {
	int n;
	scanf("%d", &n);
	int m[101] = {};
	int cnt = 0;
	for (int i = 0; i < n; i++) {
		int a;
		scanf("%d", &a);
		if (!m[a]++) cnt++;
	}
	printf("%d\n", cnt);
	return 0;
}
```
- - -
###### C++
```cpp
#include <iostream>
#include <set>
using namespace std;

int main() {
	int n;
	cin >> n;
	set<int> s;
	for (int i = 0; i < n; i++) {
		int a;
		cin >> a;
		s.insert(a);
	}
	cout << s.size() << endl;
	return 0;
}
```
- - -
###### C#
```cs
using System;
using System.Collections.Generic;

class Program {
	static void Main() {
		int n = int.Parse(Console.ReadLine());
		HashSet<int> s = new HashSet<int>();
		for (int i = 0; i < n; i++) {
			s.Add(int.Parse(Console.ReadLine()));
		}
		Console.WriteLine(s.Count);
	}
}
```
- - -
###### Go
```go
package main
import "fmt"

func main() {
	var n int
	fmt.Scan(&n)
	m := make(map[int]bool)
	var a int
	for i := 0; i < n; i++ {
		fmt.Scan(&a)
		m[a] = true
	}
	fmt.Println(len(m))
}
```
- - -
###### Java
```java
import java.util.*;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		Set<Integer> s = new HashSet<>();
		for (int i = 0; i < n; i++) s.add(sc.nextInt());
		sc.close();
		System.out.println(s.size());
	}
}
```
- - -
###### JavaScript
```js
const [n, ...A] = require("fs").readFileSync("/dev/stdin", "utf8").trim().split('\n').map(Number);
console.log(new Set(A).size);
```
- - -
###### Kotlin
```kotlin
fun main() {
	val s = mutableSetOf<Int>()
	repeat(readLine()!!.toInt()) {
		s.add(readLine()!!.toInt())
	}
	println(s.size)
}
```
- - -
###### PHP
```php
<?php
	$n = intval(trim(fgets(STDIN)));
	$m = [];
	for ($i = 0; $i < $n; $i++) {
		$a = intval(trim(fgets(STDIN)));
		$m[$a] = true;
	}
	echo count($m), PHP_EOL;
?>
```
- - -
###### Perl
```pl
my $n = int(<STDIN>);
my %m;
for (1..$n) {
	my $a = int(<STDIN>);
	$m{$a} = 1;
}
print scalar keys %m, $/;
```
- - -
###### Python3
```py
print(len({int(input()) for _ in range(int(input()))}))
```
- - -
###### Ruby
```rb
puts gets.to_i.times.map { gets.to_i }.uniq.size
```
- - -
###### Scala
```scala
import scala.io.StdIn._

object Main extends App {
	println((0 until readInt()).map(_ => readInt()).toSet.size)
}
```
- - -
###### Swift
```swift
var s = Set<Int>()
for _ in 0..<Int(readLine()!)! {
	s.insert(Int(readLine()!)!)
}
print(s.count)
```
ASP.NETアプリケーションのモダナイゼーションについて

# モダナイゼーションとは？
老朽化した既存システムを現在のニーズに合うように刷新すること
ここでは、.NET Frameworkで構築されたシステムを.NETベースに刷新し必要に応じてUIを刷新します。

# .NET Frameworkベースのアプリケーション
移行が比較的容易なグループ(.NETにも同様のフレームワークがある)
WindowsForm, コンソール, MVC...

移行が難しいグループ(.NETに同様のフレームワークがない)
WebForms....

でも、WebFormsのシステムって意外と多いよね。。。

# なんで、モダナイしなければならないか？

コストメリットがないとモダナイなんてできないけども。

- コストの明瞭化（主にクラウドに移行する場合）
- 最新の機能を使用したい
- セキュリティの問題
- パフォーマンスの問題

だいたい以上のような理由に集約される

## .NET Frameworkにとどまる選択

- メリットを十分に感じられない場合は.NET Frameworkのまま塩漬けにする選択も

- .NETにモダナイズするにはそれなりに開発費用がかかる

- メリットによって得られる利益と開発費用によってかかるコストとのバランスによって選択

- とはいえ、そのシステムが未来永劫続くとしたらどこかの時点で.NETにモダナイゼーションすることにはなるかも
   →やるかやらないかではなく何時やるかの選択

   
## クラウドアプリケーションの場合

- .NET Frameworkのままの場合例えば、コンテナー化するとしてWindowsコンテナーですか？？
App Serviceの場合今はよい。だが、いつまでホストできるのか？？

- セキュリティ面での不安はないか？？

- 様々な自動化を推進する上で障害にならないか？


## 最新の機能を実装したい場合

AIに関する機能を実装したい場合一応、Microsoft.Extensions.AIは.NET Framework4.6.1以降で対応だが言語機能的にいろいろ難しいところも。。。
サンプルなどはたいていC#12以降を念頭に書かれたものが多く読み替えが必要
たとえば、ストリーミングするのにawait foreachしたいけどもC#8.0など。

### .NET Aspireとか使いたいですよね
- ローカルの開発段階でダッシュボードがあるだけでもデバッグやテレメトリー情報を使った性能分析ができて便利。

- 開発初期で遅いところを潰しておける効率的な開発ができる。


## パフォーマンス改善
- .NETは毎年多くのパフォーマンス改善がされています。

- 特に大規模システムの場合はサーバーのサイジングを小さくできることによって得られるコストメリットが大きい


## .NETのサポート期間について

- .NET FrameworkはOSのサポート期間に準じる

- .NETはLST(.NET 8など)はリリースより36ヶ月、STSは(.NET 9など)は18ヶ月

# モダナイズにあたってやりたいこと

- 既存機能の断捨離
業務プロセスの変化によって必ずしも全機能が使用されているとは限りません。
費用圧縮のためにも機能の見直しは必ず行いましょう。

- 新規機能のフリーズモダナイズにあたって機能追加などは一旦フリーズしましょう。
モダナイズと設計変更を同時に行うと既存機能を完璧に満たしながら機能追加かつモダナイゼーションしなければならなくなり難易度が上昇します。

# モダナイの方法について
## .NET Upgrade Assistant tool

- 自動で.NET Framework→.NETや.NETのバージョンアップ、診断などをしてくれるツール
- MVC、API、Windows Forms、WPFが対象

- 独自のコンポーネント・商用コンポーネントを使用しているとまあまあ手作業が増える


## 手動で頑張る
主に、Web Formsで構築されたシステムはこっちで頑張らなければ！

とはいえ、最近はGitHub Copilotもあるのでうまく立ち回れば省力化くらいはできるかも・・・
とはいえ、クラス設計とかその辺は人間駆動設計で頑張らないとぐだぐだに・・・

## WebFormsのモダナイゼーションについて

このパターン多い！

推奨はBlazor Web Appsとはいえ事実上フルスクラッチ
Entra IDのテンプレもまだないつらみ・・・

既存の設計書 or ソースコードをインプットに内部仕様を参考にしてフルスクラッチで設計し直すしか

既存設計に引っ張られる and 基本設計はある程度Passできるので工数的にほぼ新規開発とかわらないレベル感

画面設計は再設計を考えた方がいい

AIを活用して頑張るのもひとつ

# クラウドアプリケーションの考慮事項
ここは言語問わず共通事項かと思います。

多くのリソースはUTCで動作しています。JSTを前提にして動作してるアプリケーションは時刻について混乱します。

ノンカルチャーで動作します。
日本語カルチャーに依存するメソッドは動作しない・動作が変化する可能性があります。

# タイムゾーンについての設計
内部的には日時をUTCで扱う→あらゆるシステムからUTCで日時が取得できるので自然
日時を表現する型はDateTimeOffsetを使用する
→時差を考慮した表現をしなければいけないので必然また、TimeProviderから返される型もDateTimeOffsetになっているので事実上標準
表示する時にViewまたはViewに近いところでJSTに変換する

# カルチャーについて
stringクラスについては特に要注意
ローカルの単体テストを単純に実行しただけでは実行結果が変わることがある
→カルチャーを意識した単体テストの実施が必要


# まとめ

費用対効果を考えて.NETにモダナイゼーションしていこう

とはいえ、そのシステムが続く限り（おそらく）いつかは通る道。やるかやらないかではなく何時やるかの問題
Pythonの権限昇格調査ツール

# 主な機能
- Linux環境で権限昇格に必要な情報を簡単に収集します。  
- 現在のユーザー情報と所属グループを表示します。  
- 実行可能なSUIDファイルを探索し、所有者情報とともに一覧表示します。  
- パスワードなしで実行可能なsudoコマンドを確認します。  
- ユーザーおよびシステム全体のcronジョブを調査します。  
- 実行中のプロセスを見やすく整形して表示します。  
- 開いているネットワークポートと対応するサービスを表示します。  
- `.bak`、`.swp`、`.kdbx`、`.txt`などの拡張子を持つ怪しいファイルを検索します。  
- 指定したディレクトリ内でパスワードやデータベースに関連するキーワードを含むファイルを探します。  
- 各処理の実行後にEnterキーで次のステップに進めるインタラクティブな操作が可能です。  
- CTFや権限昇格演習に適したシンプルで見やすい設計になっています。

# 前提条件
- Python 3.5+
- Linux（Unix系OS）環境

# 使用例
```bash
python3 linprivesc.py

=====================================================================================

.__  .__      __________        .__
|  | |__| ____\______   \_______|__|__  __ ____   ______ ____
|  | |  |/    \|     ___/\_  __ \  \  \/ // __ \ /  ___// ___\
|  |_|  |   |  \    |     |  | \/  |\   /\  ___/ \___ \\  \___
|____/__|___|  /____|     |__|  |__| \_/  \___  >____  >\___  >
             \/                               \/     \/     \/

=====================================================================================
[*] Current User Info:
  - User: sup0gari
  - Groups: adm, dialout, cdrom, floppy, sudo, audio, dip, video, plugdev, netdev, test-ubuntu
=====================================================================================
```

# 補足
- 本ツールはCTFや演習環境での権限昇格調査を想定して作成されています。
- 実際の大規模サーバーや本番環境で実行すると、ファイル数の多さやアクセス権限により処理が遅くなったりエラーが発生することがあります。
- 大規模環境で使用する場合は、検索対象ディレクトリを絞るなどの調整を推奨します。
- 各処理はEnterキーで次に進みます。処理中にEnterを押すことで長い処理をスキップできます。
- 操作性や視認性を重視し、完全自動化や高速化よりもシンプルさを優先しています。

# GitHub
https://github.com/sup0gari/CTF_TOOLS/blob/main/linprivesc.py
学習13日目

# 今日学んだこと
① tableの行や列を結合する
② link_toでdeleteを指定する
③ 数値のバリデーション

## ① tableの行や列を結合する
下記の場合、3列(横に3つ)結合する。
```
<td colspan = "3"></td>
```

下記の場合、3行(縦に3つ)結合する。
```
<td rowspan = "3"></td>
```

## ②link_toでdeleteを指定する
以前学習していた時は、下記で削除の実装ができた。
```
<%= link_to "delete", hoge_path(@hoge), method: :delete %>
```
しかし、これはRails7から使えなくなったため、下記のように記述する。
```
<%= link_to "delete", hoge_path(@hoge), data: {turbo_method: :delete} %>
```

ちなみに、下記のように記述し、削除の確認メッセージを出すこともできる。
```
<%= link_to "delete", hoge_path(@hoge), data: {turbo_method: :delete, turbo_confirm: "Are you sure?"} %>
```

## ③ 数値のバリデーション
numericalityを用いる。
(例)
```
validates :price, presence: true, numericality:{only_integer: true, greater_than_or_equal_to: 0}
```
※上記では「0以上の整数」でないデータは、バリデーションに引っかかる。

# 感想
最初、バリデーションは「greater_than_or_equal_to」のみの指定で問題無いと考えていた。
しかし、金額に小数等も入力され得ることを考慮すると、必須の記述だと感じた。
Claude Codeで気づいた実装コストと思考制約の話

普通に開発してると、「こうしたらいいんだけど、めんどいからこうでいいや」みたいなのがある。特に少人数のPoC案件だとそういう思考になりがち。

でもClaude Codeに丸投げできるなら話は別。今まで思いついてたけど面倒で作らなかった処理も実装しようという気になる。

## コスパの分母が変わると判断基準も変わる

コスパ的に実装しなかったものが、分母であるコストがめっちゃ小さくなったから、判断基準も大きく変わった。これまでもできる限り良いものを作ろうとはもちろん思っていたけれど、どこかでストッパーがかかっていたんだなと気がついた。

具体的には：
- エラーハンドリングもう少し丁寧にしたい → でも面倒 → やらない
- ログ出力もっと充実させたい → でも面倒 → 最低限で
- 設定ファイル分離したい → でも面倒 → べた書きで

みたいなのが、全部「やろう」に変わる。

## 車を買ったときと似てる

車なくても自転車もあるしカーシェアもあるし、わざわざ車買う必要ないと思ってた。でもいざ買ってみたらめっちゃ快適で、行動範囲が劇的に広くなった。

車なし生活に不便を感じていなかったはずなのに、どこかで思考に制限がかかっていた。「ちょっと遠いからやめとこう」みたいな判断を無意識にしてたんだと思う。

Claude Codeもこれと似たものを感じる。

## 無意識の制約

開発者って長年やってると、実装コストを無意識に見積もって「これは割に合わない」って判断するフィルタが働くようになる。それ自体は悪いことじゃないんだけど、同時に「最初から考えない」という思考パターンも身についてしまう。

で、そのフィルタが外れると、これまで諦めてたアイデアが一気に現実的になる。技術的には可能だったし、やった方が良いのも分かってたけど、工数がネックで諦めてたやつら。

## 開発に対する姿勢の変化

結果的に、より良いものを作ることに対する心理的なハードルが下がって、開発に対する姿勢も変わってくる気がする。

「まあこれでいいか」から「せっかくだからもう少し良くしよう」へのシフト。実装コストが下がったことで、品質に対する意識も変わってきた。