OmniAICreator/Qiita-1.07M huggingface dataset:
webアプリ my-favorite-list 詳細機能

# 一覧

したこと：ページネーションと詳細

# 流れ

views.py -> urls.py -> anime_list.html
フォームの基礎 -> 選択肢 -> 見た目 -> urlの設定 -> html(ユーザーの見た目)

# 役割

views.py(データをhtmlに渡すため)/ urls.py(urlの設定)/html(ユーザーに見せる)

# ポイント：urlの指定

`int:pk` を使う理由：pkは一意であるため

## views.py

- get_object_or_404で一致するものを受け取る
    - pkはプライマリーキー（一意）：idとか
- 受け取ったデータをhtmlに渡す

```python
def anime_detail(request, pk=None):
    anime = get_object_or_404(Anime.objects.prefetch_related('casts', 'staff'), pk=pk)  #related(リレーションについては別の機会)
    return render(request, 'myapp/anime_detail.html', {'anime' : anime})
```

## urls.py

- `int:pk` で個々のページを生成

```python
#int:pkでアニメの詳細を指定
path('anime/int:pk/', views.anime_detail, name='anime_detail'),
```

## html

- 受け取った各データを出力

```ht
<!DOCTYPE html>
<html lang="ja">
<head>
    {% load static %}
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Anime Detail</title>
    <link rel="stylesheet" href="{% static 'myapp/css/book_detail.css' %}">
</head>
<body>
    <h1>{{ anime.title }}</h1>
        <!-- 分類 -->
        <h3>分類: 
            {% with anime.status.all as status_list %}
                {% if status_list %}
                    {{ status_list|join:", " }} #カンマ区切りで出力
                {% else %}
                    分類はありません
                {% endif %}
            {% endwith %}
        </h3>
    
        <!-- ジャンル -->
        <h3>ジャンル: 
            {% with anime.genre.all as genre_list %}
                {% if genre_list %}
                    {{ genre_list|join:", " }}
                {% else %}
                    ジャンルはありません
                {% endif %}
            {% endwith %}
        </h3>
        <!-- 評価 -->
        <h3>評価: 
            {% with anime.value.all as value_list %}
                {% if value_list %}
                    {{ value_list|join:", " }}
                {% else %}
                    評価はありません
                {% endif %}
            {% endwith %}
        </h3>
    <p>メディア: {{ anime.media }}</p>
    <p>話数: {{ anime.episodes_count }}</p>
    <p>放送年度: {{ anime.season_year }}</p>
    <p>季節： {{ anime.season_name}}

    <h2>キャスト</h2>
    <ul>
        {% for cast in anime.casts.all %}
            <li>{{ cast.name }}</li>
        {% empty %}
            <li>キャストは登録していません</li>
        {% endfor %}
    </ul>

    <h2>スタッフ</h2>
    <ul>
        {% for staff_name_roletext in anime.staff.all %}
            <li>{{ staff_name_roletext.roletext }} : {{ staff_name_roletext.name }}</li>
        {% empty %}
            <li>キャストは登録していません</li>
        {% endfor %}
    </ul>

    <div class = 'group'>
        <!-- 削除ボタン -->
        <form action="{% url 'anime_delete' anime.id %}" method="post" style="display:inline;">
            {% csrf_token %}
            <button type="submit">削除</button>
        </form>    
        <!-- 編集ボタン -->
        <form action="../form/{{ anime.id }}/" method="get" style="display:inline;">
            <button type="submit">編集する</button>
        </form>
    
        <!-- 戻るボタン -->
        <form action="{% url 'home' %}" method="get" style="display:inline;">
            <button type="submit">戻る</button>
        </form>
    </div>
</body>
</html>
```
【 プログラミング】初学者の学習記録（2025年4月30日）

# 📝 プログラミング初学者の学習記録（2025年4月30日）

こんにちは！今日は、GitとGitHubの基本的な概念や操作について学習しました。以下に、学んだ内容を整理して記録します。

## 📁 リポジトリとは？

- **リポジトリ**: ソースコードや変更履歴を管理する場所。プロジェクトのすべてのファイルとその変更履歴が保存されます。
- **ローカルリポジトリ**: 自分のPC上にあるリポジトリ。開発者が個々に作業を行うためのものです。
- **リモートリポジトリ**: GitHubなどのサーバー上にあるリポジトリ。チームでの共有やバックアップのために使用されます。

---

## 💾 インデックスと `git add`

- **インデックス（ステージングエリア）**: コミットする前に変更を一時的に保存する場所。
- **`git add`**: 変更をインデックスに追加するコマンド。これにより、次のコミットに含める変更を選択できます。

---

## ✅ コミットとコミットメッセージ

- **コミット**: インデックスに追加された変更をリポジトリに記録する操作。
- **コミットメッセージ**: そのコミットで行った変更の内容を説明する短い文章。明確で具体的なメッセージを書くことが推奨されます。

---

## 📜 コミットログと粒度

- **コミットログ**: 過去のコミットの履歴。`git log`コマンドで確認できます。
- **コミットの粒度**: 一度のコミットでどれだけの変更を含めるかの程度。適切な粒度でコミットすることで、履歴が分かりやすくなり、レビューもしやすくなります。

---

## 🌿 ブランチとその運用

- **ブランチ**: 開発の流れを分岐させる機能。異なる機能や修正を並行して開発できます。
  - **メインブランチ（main/master）**: プロジェクトの主要なブランチ。常に安定した状態を保ちます。
  - **トピックブランチ**: 特定の機能追加やバグ修正のために作成される一時的なブランチ。

---

## 🔀 プルリクエストとコードレビュー

- **プルリクエスト（Pull Request）**: 他の開発者に自分の変更をレビューしてもらい、メインブランチへの統合を提案する機能。
- **コードレビュー**: 他の開発者が変更内容を確認し、問題がないかをチェックするプロセス。品質向上やバグの早期発見に役立ちます。

---

## 🧳 `git stash` とは？

- **`git stash`**: 作業中の変更を一時的に保存し、作業ディレクトリをクリーンな状態に戻すコマンド。急なタスク対応やブランチの切り替え時に便利です。

---

## ⚠️ コンフリクト（競合）の解消

- **コンフリクト**: 複数のブランチで同じファイルの同じ部分が異なる内容で変更された場合に発生します。
- **解消方法**: Gitが示すマークを確認し、どの変更を採用するかを手動で決定し、修正後に再度コミットします。

---

## 🧠 学んだことのまとめ

- GitとGitHubを活用することで、効率的なバージョン管理とチーム開発が可能になります。
- 適切なブランチ運用やコミットの粒度、明確なコミットメッセージは、プロジェクトの品質向上に寄与します。
- コンフリクトの解消や`git stash`の活用など、実践的な操作も理解することで、開発の柔軟性が高まります。

これらの知識を活かして、今後の開発に取り組んでいきたいと思います。

---

以上、今日の学習記録でした！引き続き、Railsの学習を進めていきます。🚀
Tips: GCE（Google Compute Engine）でFastAPIをDockerを使わずにホストする

## この記事は何
最近GPUリソースを利用する処理を行うAPIを実装する必要があり、FastAPIをGCE上に立てました。
あまり方法がまとまっている記事がなかったので記事としてまとめます。

## 前提
GCEはDockerでもホストすることができますが、Container-Optimized OSを用いるとGPUリソースの利用がとてもめんどくさく、また動かせたとしてもパフォーマンスはネイティブで実行した場合の方が高いことがわかったので今回はDockerを用いずにホストを行います。
また、今回は処理が非常にシンプルでオートスケーリングなども考える必要がないので、一つのサーバーでFastAPIを立ち上げることを想定しています。

## GCEのセットアップ
まずはGCEのセットアップを行います。
セットアップを行う上でのポイントは以下の通りです。

- OSはDebian系を利用
- ファイアウォールでhttpリクエストを許可する

ファイアウォールの設定については以下の記事をご覧ください。

https://dev.classmethod.jp/articles/gce-firewall/

## スクリプト
とりあえず以下のスクリプトとアプリケーションコードをSSHなどでサーバーに入り実行すればFastAPIのサーバーにHTTPアクセスできます。
コードはGitHubなどで管理し、cloneをしてくると簡単にセットアップができると思います。
Pythonのバージョンは利用するイメージによって変更してください。

```bash
#!/bin/bash

# エラーが発生した場合スクリプトを停止
set -e

# --- 仮想環境のセットアップ ---
echo "Creating Python 3.10 virtual environment..."
python3.10 -m venv .venv
echo "Activating virtual environment..."
source .venv/bin/activate

# --- Pythonライブラリのインストール ---
echo "Upgrading pip..."
pip install --upgrade pip

echo "Installing PyTorch for CUDA 12.x..."
# PyTorchのバージョンとCUDAバージョンの互換性を確認してください。
# 公式サイト (https://pytorch.org/) で適切なコマンドを確認することをお勧めします。
# ここではCUDA 12.1向けの一般的なコマンドを使用します。
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121

echo "Installing dependencies from requirements.txt..."
pip install -r requirements.txt

echo "Setup complete."

# --- iptables のインストール ---
echo "Checking and installing iptables if necessary (Debian/Ubuntu)..."
if ! command -v iptables &> /dev/null; then
  echo "iptables not found, attempting to install..."
  sudo apt-get update && sudo apt-get install -y iptables
else
  echo "iptables is already installed."
fi
# --- ここまで iptables インストール ---

# --- 既存のサーバープロセスを停止 ---
echo "Stopping existing Uvicorn server processes if any..."
# 'uvicorn app.main:app' を含むプロセスを検索して停止 (-f オプションでコマンドライン全体を検索)
# プロセスが存在しなくてもエラーにならないように || true を追加
pkill -f "uvicorn app.main:app" || true

# --- ポートフォワーディング設定 (iptables) ---
echo "Setting up port forwarding using iptables..."
# このコマンドは sudo 権限が必要です
echo "Forwarding HTTP (80) to 8000..." # HTTPルールを削除
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8000 # HTTPルールを削除
echo "Port forwarding rule added."

# --- サーバーの起動 ---
echo "Starting Uvicorn server in the background..."
# nohupでバックグラウンド実行し、出力を nohup.out にリダイレクト
nohup uvicorn app.main:app --host 0.0.0.0 --port 8000 > nohup.out 2>&1 &

# 仮想環境を無効化
deactivate

echo "Setup script finished. Uvicorn is running in the background."

```

必須になるrequirements.txtは以下の通りです。
```requirements.txt
fastapi
uvicorn[standard]
```

## ポイントの説明
この処理の中でのポイントを簡単に紹介します。

### iptablesの利用
基本的にGCEのOSは80番ポートを直接開けることはできません。
その代わりに、iptablesを用いて80番ポートのリクエストを8000番に流しています。
こうすることで権限などを特にいじらずにHTTPリクエストをFastAPIで受け取ることが可能です。

### nohupの利用
今回はプロセスをバックグラウンド化するのにnohupを用いており、スクリプトを実行するごとに既存のプロセスを殺し再起動するようにしています。
よりちゃんとしたい場合はsystemdなどを用いてデーモン化するのも良いと思います。
今日から使える便利なGitコマンド10選

## はじめに
Gitを使いこなすと、開発の効率が格段に向上します。リポジトリが大きくなるにつれて操作が遅くなったり、ブランチ切り替えで変更を上書きしてしまったり、巨大なモノレポで苦労したり...そんな経験はありませんか？

Gitは進化を続けており、便利な機能が追加されています。今回紹介する10のコマンドは、知っているだけでワークフローがスムーズになる「隠れた便利機能」です。さっそく見ていきましょう！

---

### 1. `git switch` — ブランチ切り替えを安全に

#### 〈従来の問題〉
以前は `git checkout` でブランチを切り替えていましたが、このコマンドは「ファイルの復元」「ブランチ作成」「特定コミットのチェックアウト」など多機能すぎて混乱の元でした。

#### 〈解決策〉
Git 2.23で導入された `git switch` は、**ブランチ操作に特化**したコマンドです。

```bash
# ブランチの切り替え
git switch feature-branch

# 新規ブランチを作成して切り替え
git switch -c new-branch
```
これで、誤ってファイルを上書きする心配がなくなります！

---

### 2. `git restore` — 変更を安全に元に戻す

#### 〈従来の問題〉
変更の取り消しには `git checkout` や `git reset` を使っていましたが、これらのコマンドはブランチの状態を意図せず変更するリスクがありました。

#### 〈解決策〉
`git restore` は ファイルの変更のみ を対象とします。

```bash
# 作業ディレクトリの変更を破棄  
git restore main.js  

# ステージングされた変更を解除  
git restore --staged main.js  
```
ブランチの状態を気にせず、安全に変更を元に戻せます。

---

### 3. `git maintenance` — リポジトリのメンテナンス自動化

#### 〈従来の問題〉
リポジトリが大きくなると `git gc` や `git repack` を手動で実行する必要がありました。

#### 〈解決策〉
Git 2.29で導入された `git maintenance` で自動化可能に：

```bash
# 自動メンテナンスを有効化  
git maintenance start  

# 即時実行  
git maintenance run  
```
#### 内部で実行される処理：
- 不要オブジェクトの削除（`git gc`）
- パックファイルの最適化（`git repack`）
- コミットグラフの更新（`git log` の高速化）

---

### 4. `git sparse-checkout` — 巨大リポジトリを効率的に扱う
モノレポで特定のディレクトリのみ必要な場合、全体をクローンするのは非効率です。

```bash
# スパースチェックアウトを有効化  
git sparse-checkout init  

# 必要なディレクトリのみ指定  
git sparse-checkout set services/ docs/  
```
これでディスクスペースと時間を節約できます！

---

### 5. `git log --remerge-diff` — マージの変更を詳細に確認

マージコミットでどの変更が加わったのかを明確に表示：

```bash
git log --remerge-diff  
```
コンフリクト解決後の変更をデバッグする際に便利です。

---

### 6. `git blame --ignore-rev` — フォーマット変更を無視

一括フォーマット変更で `git blame` が使いづらくなったとき：

```bash
# 特定コミットを無視  
git blame --ignore-rev commit-hash  

# 永続的に無視リストに追加  
echo "commit-hash" >> .git-blame-ignore-revs  
git config blame.ignoreRevsFile .git-blame-ignore-revs  
```

---

### 7. `git range-diff` — コミット範囲の差分を比較

リベース前後のコミットを比較：

```bash
git range-diff old-branch new-branch  
```
機能追加やバグ修正の履歴を追うのに最適です。

---

### 8. `git worktree` — 複数ブランチを同時に作業

別ディレクトリでブランチを並行作業：

```bash
# 追加作業ディレクトリを作成  
git worktree add ../feature-branch feature-branch  

# 削除  
git worktree remove ../feature-branch  
```
ブランチ切り替えのストレスから解放されます！

---

### 9. `git rebase --update-refs` — ブランチ参照を自動更新

リベース時に関連ブランチも自動で更新：

```bash
git rebase --update-refs  
```
手動でのポインタ修正が不要に。

---

### 10. `git commit --fixup + git rebase --autosquash` — コミット履歴をきれいに

過去のコミットに修正を加える場合：

```bash
# 修正用コミットを作成  
git commit --fixup=<target-commit>  

# 自動で統合  
git rebase -i --autosquash main  
```
手動で編集する必要がなくなります。

---

### まとめ
今回紹介したコマンドは、日常的なGit操作の悩みを解決してくれます。
今日から1つでも試してみてください！ 
次の記事まで、ハッピーコーディング！ 🚀
Chrome拡張機能で開発を始める


最近、Chrome拡張機能を触る機会があったので、基本的な概念から、開発で参考になったリソース、感じたことまでを軽くまとめてみました。

例として、Amazonの商品分析ツール「SellerSprite」という実例を参考にしています。

https://www.sellersprite.com/jp/sellersprite-extension

## なぜChrome拡張機能を始めたのか？

きっかけは業務ではあるんですが、
ある特定のWebサイト（たとえばAmazonなど）の情報を効率的に扱いたい場面が増えたことです。

拡張機能は、特定のドメインに対してピンポイントで強く作用できるのが大きな魅力です。
ページの構造がわかっていれば、カスタムDOMを差し込んだり、API連携したりと柔軟に拡張できるため、0からWebアプリを作るよりも効率的で、かつ機能性や拡張性にも優れていると感じました。

特にBtoBでPCを使う、かつ特定のドメインを使うニッチな業務にはすごく刺さると個人的には考えています。

## 拡張機能の構成要素

Chrome拡張機能は、以下の3つの主要コンポーネントで構成されています。

- Manifestファイル
- Content scripts
- Service Worker 

### Manifestファイル
拡張機能全体の定義を記述するファイル（manifest.json）。
Chromeはこのファイルを読み、どのファイルを読み込むか判断します。

```manifest.json
{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0",
  "permissions": ["activeTab"],
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [
    {
      "matches": ["https://www.amazon.co.jp/*"],
      "js": ["content.js"]
    }
  ],
  "action": {
    "default_popup": "popup.html",
    "default_icon": "icon.png"
  }
}


```



### Content scripts
拡張機能のフロントエンド部分。
既存のWebページのDOMに対して操作を行うJSがここです。

Amazonの商品ページなどでDOMに直接情報を差し込むことが可能です。

例：SellerSpriteのように、Amazonの商品詳細ページにカスタム情報を差し込む

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3621281/5a419799-08c3-449e-ab0e-7f1d937c7669.png)

また、画面右上の拡張機能アイコンを押すと、ポップアップ（UI）が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3621281/1fb681c7-371b-45e2-89e1-1cdc25e99231.png)

（Next.jsで言うところの pages/ や components/ のような役割）

https://developer.chrome.com/docs/extensions/develop/ui/add-popup?hl=ja

### Service Worker（旧 background.js）

拡張機能のバックエンド部分。
DOMにはアクセスできませんが、イベントハンドリングやAPI通信などが可能です。

主に以下のような用途で使われます：

APIとの通信

スケジュール処理

ユーザー操作のトラッキング

Chrome拡張のIDは固定され、以下のような形式で確認可能です：
```
chrome://extensions/?id=◯◯◯◯
```
（Next.jsでいう api/ ディレクトリ的な役割）

chrome://extensions/ は拡張機能の管理画面であり、実はこれ自体が1つの特殊なブラウザページです。

開発者ツール（DevTools）を開くと、Network や Application タブが使え、拡張機能専用の保存領域「Extension Storage（拡張機能ストレージ）」も確認できます。

これにより、拡張機能がユーザー情報や設定をブラウザに保存・管理できる仕組みが提供されています。

Service Workerをクリックすると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3621281/2bd30883-3142-42de-9b74-6463cbd2fd2b.png)

DevToolが出てきます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3621281/0e911064-f679-4c56-af52-b7f2ac9e8793.png)

https://developer.chrome.com/docs/extensions/develop/concepts/service-workers?hl=ja

## フレームワーク選定

今回は以下の理由でReact + Viteのテンプレートを使いました。

- React・TS・Tailwindがつかえること
- ホットリロード対応（ビルド不要で即時反映）
- 初心者でも分かりやすい構造
- GitHubで高評価（スター数が多い）

使ったテンプレートはこちら：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3621281/306ff39c-ce10-4b61-888b-950c86ad3e16.png)

https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite

## Iframeからの脱却を目指して

以前はiframeを使って、外部ページにフレームを読み込んで機能を実装していました。

✅ メリット：ストアに出さなくてもすぐ修正できる
❌ デメリット：読み込みが重く、ユーザー体験が悪い

現在はContent Scriptを用いて直接DOMに差し込む方式に変更し、UXを改善しています。


## 感想

Chrome拡張機能は、通常のWeb開発とは少し違った概念があり、とても新鮮でした。
「ポップアップUI」「既存ページへのDOM差し込み」「バックグラウンド通信」など、SPAとは異なるアーキテクチャを楽しめるのが面白いところです。

## 参考資料
https://zenn.dev/alvinvin/books/chrome_extension
scheme(Gauche)のfold系手続きの比較

# 4月の振り返り

3 月に続いて scheme をやっていた。練習問題として Project Euler を 20 問まで解いた。今まで Python、 JavaScript などオブジェクト指向の動的型付け言語ばかりをやっていたので一つくらい関数型言語を覚えたいという目標をとりあえず達成した形だ。

この記事は、その時困惑したところなどをまとめる。

## プロジェクトオイラーとは？

[About - Project Euler](https://projecteuler.net/)

プログラミングを使って解く数学の問題集。回答者だけが読めるフォーラムでいろいろな人がいろいろな言語を使って解いていて参考になる。

## fold 適用順

gauche(scheme の処理系の一つ) には fold 系の手続き fold、 fold-left、 fold-right の三種類がある。
要するに Python, JavaScript に存在する `reduce` の一種と理解した。

例を挙げると次のように違う。

```scheme
gosh> (fold cons '() '(1 2 3))
;; (3 2 1)
gosh> (fold-left cons '() '(1 2 3))
;; (((() . 1) . 2) . 3)
gosh> (fold-right cons '() '(1 2 3))
;; (1 2 3)
```

結果の差異は確認したので、次にその理由を見ていく。

:::note info
調べて 1 週間もすればどれがどれか絶対にごっちゃなるだろうとか、他の言語ともズレている部分もありそうと思って調べてみるととっくにまとめた記事があった。

この章の記述はリンク先を読んで理解できれば、実のところ読む必要はない。

- 他言語との比較
    - [畳み込み関数の比較 (fold / accumulate / inject / reduce) - blanket log](https://blanketsky.hatenadiary.org/entry/20071129/1196329379)

- fold 系手続きの比較
    - [fold, fold-left, fold-right](https://blog.practical-scheme.net/shiro/20120314-fold)
:::

fold 系手続きは結果が適用順に依存しない計算ならばすべて同じ結果を返す。ここでは総和を例に適用順を説明する。
総和は fold で `(fold + 0 '(1 2 3 4 5))` のように書ける。
適用順を調べるために `+` の代わりに次のような手続き `addxy` を作る。
見ての通り引数を表示して足し算するだけの手続きだ。

```scheme
(define (addxy x y)
  (print (format "X:~a Y:~a" x y))
    (+ x y))
```

この手続きを使い 1 から 5 の総和の過程を確認していこう。

```scheme
(define lst (iota 5 1 1)); '(1 2 3 4 5)

(print "list: " lst)
(newline)
(print "fold")
(print (fold addxy 0 lst))
(newline)
(print "fold-left")
(print (fold-left addxy 0 lst))
(newline)
(print "fold-right")
(print (fold-right addxy 0 lst))

```
このコードを実行するこのような結果を返す。
```text 
fold
X:1 Y:0
X:2 Y:1
X:3 Y:3
X:4 Y:6
X:5 Y:10
15

fold-left
X:0 Y:1
X:1 Y:2
X:3 Y:3
X:6 Y:4
X:10 Y:5
15

fold-right
X:5 Y:0
X:4 Y:5
X:3 Y:9
X:2 Y:12
X:1 Y:14
15
```

この結果をまとめるとつぎのようになる。

| 関数名       | 結果を蓄積する変数 | リストの読取方向 |
|--------------|----------------|------------------|
| `fold`       | 右             | 頭から           |
| `fold-right` | 右             | 逆から           |
| `fold-left`  | 左             | 頭から           |



<!--
## 長さが違う複数のリストをmap に渡したときの挙動

長さが違う複数のリストを map に渡したとき短い方に合わせて適用を止めてくれる。エラーなどは発生しない。
優しいけど、エラーを吐いてほしい気もする。

多言語の比較がしたいところだが、どうやらとっくにまとめられている模様。

- [Map (higher-order function) - Wikipedia](https://en.wikipedia.org/wiki/Map_(higher-order_function))

あと処理系ごとに map の挙動がちがうようだ。

> lists must all have same length (SRFI-1 extends to take lists of different length)

書くなら Python(たぶん gauche と同様?)、 JavaScript(たぶん既定値で拡張?) のテキストも読んでおきたい。
-->

## 終わりに

プロジェクトオイラーを解きながら書くべきでした。いろいろ気になっていたのにほとんど忘れてしまいました。
この感覚が抜けないうちに、静的型付け言語に挑戦するつもりです。候補は Java, Rust, Haskell のどれかです。

## Link

- fold
    - [fold (Gauche ユーザリファレンス)](http://practical-scheme.net/gauche/man/?l=ja&p=fold)
    - 他言語との比較
        - [畳み込み関数の比較 (fold / accumulate / inject / reduce) - blanket log](https://blanketsky.hatenadiary.org/entry/20071129/1196329379)
    
    - fold 系手続きの比較
        - [fold, fold-left, fold-right](https://blog.practical-scheme.net/shiro/20120314-fold)
- [左再帰 - Wikipedia](https://ja.wikipedia.org/wiki/%E5%B7%A6%E5%86%8D%E5%B8%B0)
- [map (Gauche ユーザリファレンス)](http://practical-scheme.net/gauche/man/?l=ja&p=map)
脱衣所でTerraform Associate(003)を受験した

# はじめに
:::note info
本記事の内容は2025年4月30日時点のものです。
:::
2025年4月30日に[Terraform Associate(003)](https://developer.hashicorp.com/certifications/infrastructure-automation)を受験し、無事合格しました。私はTerraformを触った経験がなかったのですが、自身の業務でこれからTerraformを触っていくことになるため知識習得のために受験しました。
これから受験する方々へ少しでもお役に立てればと思い、受験体験談を書くことにしました。
# 受験準備
- 受験予約について
  - 他の方のブログでご紹介されている内容とほとんど変わっていないと思いますのでここでは割愛します。受験時に政府発行のIDを見せる必要があります。私はパスポートを所有していますので、試験予約時の氏名はローマ字で登録しました。
  - また、母国語が英語ではないため試験時間30分追加の申請もしました。
- 受験会場
  - 自宅の脱衣所
    - 恥ずかしながら自室が散らかっていたのと、デジタル機器を置いていないスペースが脱衣所くらいしか思いつかなかったので、そこにテーブルを置いて受験しました。試験官から指摘を受けることはなかったです。　
- 勉強した内容
  - Udemy
    - 座学：[HashiCorp Certified: Terraform Associate 2025](https://www.udemy.com/course/terraform-beginner-to-advanced/?srsltid=AfmBOoqa8lA_NHKa1X99hEmujVy8s_q028-337hi9q1pbfd6Xuhxq0iW)
    - 模擬試験：[HashiCorp Certified: Terraform Associate Practice Exam 2025](https://www.udemy.com/course/terraform-associate-practice-exam/?kw=HashiCorp+Certified%3A+Terraform+Associate+Practice+Exam+2025&src=sac&couponCode=ST7MT290425G2)
  - また、集中研修を受ける機会がありました。そこでTerraform実行環境の導入から、実際にAWS上にTerraformを用いてリソースを構築、設定変更したりなど手を動かしてました。ディレクトリの構成とかコマンドの意味はここで身に着けていた感じです。
# 受験中の様子
- 開始直前
  - 30分前くらいに試験予約サイトへアクセスしました。私の場合、30分前では試験をスタートできませんでした。
  -  **受験時に追加のアプリをインストールすることはなかったです。** 私はChromeブラウザ上で完結しました。
  - 試験が始められるようになると試験官とチャットでのやり取りが開始されます。チャット欄で入力する言語を選択できるようで、日本語に設定したら日本語でチャットのやり取りができました。(おそらく自動翻訳) 英語でのチャットに不安があったので、これはかなり助かりました。
  - IDを見せてと言われるのでパスポートをPCのカメラに提示。
  - 部屋の周りを見せてと言われるのでゆっくりPCを回して部屋の様子を見せる。
  - テーブルの下を見せてと言われるので言われた通りに見せる。
  - だいたいここまでできれば、試験開始となります。
- 受験最中
  - ネットワークの調子が悪く接続が途切れてしまうことがありました。ですがネットワーク復旧後、画面上にページをリロードするボタン(？)が現れ、それを押して1~2分ほど待つと試験官と再接続。その後、試験を再開する旨がチャットで連絡されて試験再開となります。途中までの回答状況、試験の残り時間も保存されていました。ネットワークの接続切れが起きてしまっても焦らずに対応しましょう。
- 受験終了後
  - 試験に対するアンケートに答えて次の画面へ遷移すると合格か不合格かすぐに表示されます。詳細なスコアレポートは48時間以内にメール通知されるとのこと。(私の場合は約24時間後に届きました。)
# 最後に
ここまでご覧いただきましてありがとうございます。簡単な内容になりますが、TerraformAssociate受験の際の参考になれば幸いです。
【TypeScript】コンストラクタ内で、非同期処理で取得した値をインスタンス変数に設定する方法

# はじめに
こんにちは！
タイトルのケースを実装する際に若干迷ったので記事にします。
同じようなことをしたい方の参考になればと思います！

# 問題
以下のケースの場合を考えます。

### <font color="red">例.NGパターン</font>
```diff_tsx:index.ts
// クラス
class SampleClass {
  private asyncVar: number | undefined;

  // 初期化
  constructor() {
    const _this = this;
    setTimeout(() => {
      _this.asyncVar = 1; // 非同期関数（setTimeout）内でインスタンス変数を初期化
    }, 1);
  }

  // 出力
  print() {
    console.log(this.asyncVar);
  }
}

// インスタンス化
const instance = new SampleClass();
// 出力
instance.print(); // undefined
```
やりたいこととしては、SampleClassのコンストラクタ内で初期化した`asyncVar`の値（`1`）を、`print`関数でコンソールに出力したいとします。
が、コメントにある通りこのソースでは`print`関数にて`1`が出力されず、`undefined`が出力されてしまいます。
これは、<font color="red">`まず同期処理が全て実行されてから非同期の処理が実行される`</font>というJavaScriptの仕様のためです（詳細は↓の記事が分かりやすかった）。つまり、`SampleClassのインスタンス化が実行されてからprint関数が実行され、最後にコンストラクタ内のsetTimeoutで指定したコールバック関数が実行される`という流れで処理が進むため、print関数が実行される時点では変数が初期化されておらず、`undefined`が表示されてしまうということですね。

https://qiita.com/UTDoi/items/d49ea919818d9b519f93

ちなみに、コンストラクタ関数で`async constructor() {`のような記述はできず、処理を待つようにすることはできません。
ではどのように`asyncVar`を初期化するか、↓に記載します。

# 解決方法

答えは、`インスタンス化を行うstaticメソッドを定義し、その中でインスタンス変数を初期化する`です。
具体的には以下のソースの通りです。

### <font color="red">OKパターン</font>
```diff_tsx:index.ts
// クラス
class SampleClass {
  private asyncVar: number | undefined;

  // 初期化
+  private constructor() {}

+  // 生成
+  static async create() {
+    const instance = new SampleClass();
+    await instance._initialize();
+    return instance;
+  }
+
+  // インスタンス変数の初期化
+  private async _initialize() {
+    const _this = this;
+    await new Promise((resolve) => {
+      setTimeout(() => {
+        _this.asyncVar = 1; // 非同期関数（setTimeout）内でインスタンス変数を初期化
+        resolve(true);
+      }, 1);
+    });
+  }

  // 出力
  print() {
    console.log(this.asyncVar);
  }
}

// インスタンス化
+ const instance = await SampleClass.create();
// 出力
instance.print(); // 1
```
ポイントは **`constructor`をprivate化していること** と、 **`create`関数内で、生成したインスタンスを返却していること** です。まず、`constructor`をprivate化することで通常のnewを禁止し、インスタンスを生成する場合には必ず`create`関数を経由することを強制しています。
こうすることで、`create`関数内で呼び出している`_initialize`関数の中で変数の初期化を待ってから生成したインスタンスを返却させることができます（`_initialize`関数の中では、awaitを使ってasyncVarの初期化を待たせています）。

上述の通り、インスタンス化は`new SampleClass()`ではなく、`await SampleClass.create()`で行います。こうすることで、インスタンス変数の初期化を待つことができるので、`print`関数の出力結果が`1`となり想定通りに出力されることになります。

# おわりに
JavaScriptは非同期とthisの扱いが鬼門ですが、ここを乗り越えたら使いこなしたと言えると思います（個人的意見）。

## JISOUのメンバー募集中🔥
プログラミングコーチングJISOUではメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？
気になる方はぜひHPからライン登録お願いします！👇

https://projisou.jp/
【Rails】application_controller.rbについて

# 記事概要
Ruby on Railsのapplication_controller.rbについて、まとめる

# 前提
- Ruby on Railsでアプリケーションを作成している

# 基本情報
## ファイルパス
app/controllers/application_controller.rb

## 記載方法
[[コントローラー名]_controller.rb](https://qiita.com/likapantrip/items/b82ea9f7ef4942afabd8)を、参照

## 処理概要
すべてのコントローラーが継承しているファイル
ここに処理を記述しておくことで、すべてのコントローラーで共通となる処理を作ることができる

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

# まとめ
## authenticate_or_request_with_http_basicメソッド
Basic認証を実装するために使用する
使用方法は、[こちら](https://qiita.com/likapantrip/items/0fb66fc2f171e393c6c1)を参照

```ruby
# 'admin'というユーザー名と、'password'というパスワードでBasic認証できるように設定
authenticate_or_request_with_http_basic do |username, password|
  username == 'admin' && password == 'password'
end
```

# Ruby on Railsまとめ
https://qiita.com/likapantrip/items/46b43c9d1309b6633f0a

# コントローラー
https://qiita.com/likapantrip/items/66a30e887ffe20ad08a4
【Salesforce】Chatterにてメンションをしても通知メールが届かない

〇事象
・Chatterにてメンションを行った際、メール通知が届かない
→以下の記事を参考に、組織内にてメール通知の設定を事前に行う必要あり

☆Chatter メール通知を送信するときの送信者名とメールアドレスの必須化 (リリース更新)
https://help.salesforce.com/s/articleView?id=release-notes.rn_experiences_chatter_email_update.htm&release=244&type=5
ABC403バーチャル参加

## はじめに

AtCoder Beginner Contest 403にバーチャル参加しました。

## 概略

- ABC403にバーチャル参加した
- 時間が無くて(Daily Trainingも参加している)2問のみ
- B問題が250点問題で難度アップ

## A - Odd Position Sum

奇数番目の数値を足し合わせるだけの簡単なお仕事です。
ただし、ループの添字を0からにしている方は注意が必要な、AtCoderのA問題にふさわしい罠が仕掛けられています。

```cpp:A.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  int N, ans = 0;
  cin >> N;
  for (int i = 0; i < N; i++) {
    int a;
    cin >> a;
    if (i % 2 == 0) ans += a;
  }
  cout << ans << endl;
  return 0;
}
```

## B - Four Hidden

文字列$T$の中に文字列$U$が含まれているかを1文字ずつずらして愚直に検索すればOKです。
なお`?`はいわゆるワイルドカードなのでその点には注意が必要です。

`ans = false;`の後に`break;`を入れれば良かったかなーと反省。
まあいいか、結果は1msだし。

```cpp:B.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  string T, U;
  cin >> T >> U;
  for (int i = 0; i <= (int)(T.size() - U.size()); i++) {
    bool ans = true;
    for (int j = 0; j < (int)(U.size()); j++) {
      if (T[i + j] != '?' && T[i + j] != U[j]) ans = false;
    }
    if (ans) {
      cout << "Yes" << endl;
      return 0;
    }
  }
  cout << "No" << endl;
  return 0;
}
```

## 最後に

今回は疲れていて(流石に私用で3日間空けた後帰宅したその日は年齢的に無理)不参加でした。
今もまだ疲れが完全に取れていません。うーん、これが50歳というやつかあ……。

なお次回(5月3日)は是非参加したい所存です。

### 課題

- まだ読み終えてない『問題解決のための「アルゴリズム×数学」が基礎からしっかり身につく本』(アルゴ数学本)を読み進める
- アルゴ数学本の問題を解く(AtCoderでこの本専用のコンテストがあって問題を解くことができる)
- 高校数学の書籍(数冊所持)を読む
- [アルゴ式](https://algo-method.com/ "アルゴ式")を進める。まずはPython入門・基礎編を全クリアーする

## その他

『競技プログラミングの鉄則』購入しました。アルゴ数学本は電子書籍だったのですが、こちらは固定レイアウト方式とのことだったので、紙書籍で購入しました。
なおアルゴ数学本を読み終えていないので、まだ読んでいません。
TIL: Podfile.lockのSPEC CHECKSUMSに差分がでる

# 概要

Flutterを使ったprojectで「Podfile.lockのCHECKSUMSに差分が出るんだけど」と言われた。
最初はキャッシュかな~~と思いながら対応するも一向に解決しない。チームメンバー全員が最新のcodeで `pod install` すると差分が出る。自分は出ない。

## Podfile.lock とは

文字通りlock fileなので、package-lock.json のような認識で概ね問題ない。
Podfile に対しての lock fileである。
つまり、実際に入れた Pods(ライブリ) に関する情報がまとめられている。

## SPEC CHECKSUMS とは

これなんぞや??
と思った人も多いと思います。自分も今回の件があるまではちゃんと調べてなかった。
同じような機構は他のpackage managerにもあるような気がする。多分。

### SPEC CHECKSUMS が生成される仕組み

すごく雑な理解だと、
- pod install を実行する
- `ios/Pods/Local Podspecs/<lib_name>.podspec.json` をhashにして変更があれば書き換える

という理解。なので、
`shasum ios/Pods/Local\ Podspecs/<lib_name>.podspec.json` とすると SPEC CHECKSUMSに書かれている値と同じ値が出力されるはず。
(ちなみにですが sha256ではなく、sha1らしい。意外だ)

## 原因

半日ほど費やして cocoapods のcodeを覗いて理解しました。
https://github.com/CocoaPods/Core/blob/a53e235aa4d1eec8a21042e022ba7bcaca14ae56/lib/cocoapods-core/specification/json.rb#L11-L16

```ruby
      # @return [String] the pretty json representation of the specification.
      #
      def to_pretty_json(*a)
        require 'json'
        JSON.pretty_generate(to_hash, *a) << "\n"
      end
```

gem `json` を使ってるわけですね。でこのjsonのversionはlocal環境に左右されます。
チームメイトと自身のversionを確認したところversionに差分があり、updateすることで解決しました。

## 余談

- https://github.com/ruby/json/blob/master/CHANGES.md#2024-11-06-280 version 2.8.0 で変わったみたい
- Gemfileを入れて管理するか考え中。個人的にはcocoapods側でどうにかしてくれと思うので、[issue](https://github.com/CocoaPods/CocoaPods/issues/12807)を投げてみた
- おかげさまでpodのキャッシュについての理解が深まりました
Mac mini で ローカルLLM： Qwen3（MLX版）を MLX LM ＋ Python で試した時のメモ

## はじめに

以下で試した内容の続きみたいな内容の記事です。以下ではコマンドラインからローカルLLM を試していましたが、今回は Python のコードで処理を実行します。

●Mac mini で ローカルLLM： Qwen3（MLX版）を MLX LM で試した時のメモ - Qiita
　https://qiita.com/youtoy/items/18a105e3925fc34cc624


## 実際に試していく

### 試す環境

今回、[上記の 1つ前の記事](https://qiita.com/youtoy/items/18a105e3925fc34cc624)にも書いている環境を使っています。

具体的には、以下のとおりです。

- PC
   - M4 の Mac mini（メモリ 24GB、うち 16GB をローカルLLM用で利用可能）
- モデル
   - MLX版の Qwen3 で量子化されているもの
      - [Qwen3-14B-8bit（MLX版）](https://huggingface.co/mlx-community/Qwen3-14B-8bit)
- 実行環境
   - Python の仮想環境で MLX LM を利用、Python のコードで処理を実行


### コード・処理の実行

#### 参考にしたコード

今回用いた Python のコードは、[Qwen3-14B-8bit（MLX版）](https://huggingface.co/mlx-community/Qwen3-14B-8bit)のページ冒頭に書かれたものを、少し変えただけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/52b420e6-57f6-4f60-9cbe-5120a554aa23.png)

#### 仮想環境での処理の実行

前回の記事で用いた Python の仮想環境（myenv という名前で作成したもの）を使います。
Python のコードを実行する前に、以下のコマンドで仮想環境のアクティベートなどを行っておきます（念のため、mlx-lm の最新版へのアップデートを行うコマンドも含めています）。

```zsh
source myenv/bin/activate
pip install -U mlx-lm
```

#### コードと処理の実行1

とりあえず、以下のコードで処理を試しました。

```python
# source myenv/bin/activate
from mlx_lm import load, generate

model, tokenizer = load("mlx-community/Qwen3-14B-8bit")

prompt = "生成AIを8歳に分かるように短い言葉で日本語で説明して"

if tokenizer.chat_template is not None:
    messages = [{"role": "user", "content": prompt}]
    prompt = tokenizer.apply_chat_template(
        messages, add_generation_prompt=True
    )

response = generate(model, tokenizer, prompt=prompt, verbose=True)
```

実行結果は以下のとおりで、出力が途中で途切れました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/3e02a47f-ebaa-47de-96b1-dd2c40a68bf3.png)

おそらくデフォルト設定だと、今回の内容を出力しきれずに終わるパラメータになっていると思われます（「Generation: 512 tokens」となっているので、ここを増やしてやれば良さそうです）。


#### コードと処理の実行2

コード内の `generate()` で `max_tokens=512` という指定を加えた、以下のような内容にしてみました。

```python
# source myenv/bin/activate
from mlx_lm import load, generate

model, tokenizer = load("mlx-community/Qwen3-14B-8bit")

prompt = "生成AIを8歳に分かるように短い言葉で日本語で説明して"

if tokenizer.chat_template is not None:
    messages = [{"role": "user", "content": prompt}]
    prompt = tokenizer.apply_chat_template(messages, add_generation_prompt=True)

response = generate(model, tokenizer, prompt=prompt, max_tokens=512, verbose=True)
```

再度、処理を実行してみると、以下のように最後まで内容が途切れることなく出力されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/265aff3a-548d-4c34-a0a3-21f86284b471.png)


#### コードと処理の実行3

2つ目のお試しのプロンプトの部分だけ「 `prompt = "東京について3段落くらいで、日本語で説明して"` 」という内容に変えて、処理を実行してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/ae7b145f-3aba-43db-8075-1b22878c7259.png)

この場合は、 `max_tokens=512` だと出力が途中で途切れました。これを `max_tokens=1024` にして試したところ、以下のように出力が途切れることはありませんでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/6383ec4a-8a39-47a1-a66b-998e4c16f2a2.png)
DNSサーバーの移行について無知すぎて手も足も出なかったので前提理解を深めた

# 対象読者
- DNSサーバーが何かは分かる
- クラウドのDNSサービスを使用している
- DNSサーバーの設定は触ったことも、見たこともない

# 今回の想定
- ドメインのレジストラはお名前ドットコム
- GCPのクラウドDNSからAWSのRoute53へ移行する
- サービスを止めずに移行する

あくまでもこれは今回の例であり、ドメインもGCPで管理しているパターンもあるでしょう。
本記事の内容は、クラウドサービスであれば何でも当てはまると思います、多分。

# 結論

「DNSを移行する」＝「ドメインに紐づけるDNSのネームサーバーを変更する」
です。
DNSのネームサーバーはNSレコードの値になります。

作業としてはこちらのAWS公式サイトの手順が全てです。
考慮しておくべきは、準備作業をしたあと大体数日待ってから移行作業を行う必要があることです。

https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/migrate-dns-domain-in-use.html

作業自体は簡単です。
ただし、サービスを停止しないために順番を守る必要があります。

# 準備作業

## 移行元(GCPクラウドDNS)のDNSレコードを確認

__NSレコードとSOAレコード以外の__ レコードをそのままAWSにも同じように作成するので、後からレコードの内容をコピペするために画面を確認します。
NSレコードとSOAレコードは、DNSサーバー固有の値になるので自動付与されたものを使います。

:::note info
メモ
- NSレコード
  - そのドメインの権威DNSサーバーを指定するレコード
  各DNSサービスプロバイダー（GCPのCloud DNSやAWSのRoute53など）は、自社のDNSサーバーを指すNSレコードを自動的に設定
- SOAレコード
  - そのDNSゾーンの管理情報を含むレコードで、プライマリネームサーバー、管理者のメールアドレス、シリアル番号、更新間隔などの情報を持つ
:::

![スクリーンショット 2025-03-10 15.52.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388259/4ac16321-448e-48fb-bc33-14c6c086f816.png)


## ドメインのレジストラで紐づけているネームサーバーを確認

ドメインのレジストラ(お名前ドットコム)では、「本ドメインはこのDNSサーバーを使いまーす」という設定があります。
移行前はGCP側のネームサーバーが入ってます。ネームサーバーは先程確認したNSレコードの4つの値です。
後でネームサーバーを変更するために設定画面を確認します。

![スクリーンショット 2025-04-18 22.24.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388259/58cdf126-33f8-468a-b7d4-87df40cd6108.png)

## 移行先(AWS Route53)のDNSレコードを作成

Route53にて、使用しているドメインと同じ名前でホストゾーンを作成し、そこに先程GCPで確認したレコードを真似して作成します。
ホストゾーンを作成した時点で勝手に用意されているレコード(おそらくNSレコードとSOAレコード)はそのままにしておきます。

この勝手に用意されたNSレコードの4つの値をネームサーバーとして移行先の指定に使うので、メモしておきます。

![スクリーンショット 2025-04-21 16.40.52のコピー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388259/0399e84b-ffd4-4262-8f58-233a877213df.jpeg)


## 移行元と移行先の両方のNSレコードのTTLを下げる

個人的にはこれが一番のポイントかなと思ってます。
DNSレコードのTTLとは、DNSリゾルバーがレコードをキャッシュし、キャッシュされた情報を使用する期間のことです。
TTLが期限切れになると、リゾルバーはドメインのDNSサービスプロバイダに別のクエリを送信し、最新の情報を取得する、とのことです。

![スクリーンショット 2025-03-10 15.52.11のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388259/6dc28da9-a32d-4dd0-ae74-23166800b3fd.png)

![スクリーンショット 2025-04-21 16.40.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388259/663f22af-6dfe-4834-b89b-2000ef0b08d2.png)

で、このTTLは1日以上(24時間以上)であることが多いようです。

つまり、NSレコードのTTLが例えば24時間のままDNSサーバーを移行すると、新しいDNSサーバーがWebサイト利用者側に反映されるのは最大24時間になるということです。

問題なく移行できた場合はこれでもいいのですが、
24時間後になって、もし何かしらの問題があって新しいDNSが動作せずWebサービスにアクセス出来なくなった場合、急いで元に戻したり修正したりしても、最大24時間は動作しない状況が続きます。
そうなるともう指をくわえて見てるしかありません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388259/09f74dae-a795-4836-b1d6-d3b6f4ee4bf0.png)


そのため、TTLは60秒とかにしておきましょう。
設定方法は簡単で、GCPとAWSそれぞれのNSレコードの編集画面で、TTLを60秒に設定します。

## 古いTTLの期限切れを待つ

TTLを60秒に戻したらすぐにキャッシュの期限が60秒になるわけではありません。
それ以前にすでにキャッシュされたレコードは元々のTTLの期間だけ保持されるので、この期限が切れるのを待つ必要があります。

# 移行作業

ドメインのレジストラ(お名前ドットコム)で設定しているネームサーバーを変更します。
具体的には、前項で新たに作成したRoute53側のNSレコードの4つの値をコピペします。

# 動作確認

60秒以上経ってWebサービスが問題なく利用出来れば、移行成功です。
念の為、複数のDNSリゾルバーを使って動作確認しておくと安心です。

移行先のDNSのTTLを24時間などの元の値に戻します。

# 補足

今回、TTLを下げてキャッシュの期限切れを待つということを解説しましたが、体感ではもっと早く反映されてるように思います。設定変更を検知して自動でキャッシュをクリアする技術がありそうです。
その場合、実際はそういった「待つ」というのは必要ないかもしれません。
proconioを使ったRust標準入力

# Rustの標準入力
以前、Rustの標準入力についての記事を投稿しました。
「Rustの標準入力めっちゃ理解したかもしらん」なんて先輩に報告したら、**proconio**というものを教えてもらいました。

# 準備
```terminal
$ cargo new prac
$ cd prac
```
`cargo new prac`で新しい prac というフォルダを作ります。
`cd prac`で先ほど作られた prac というフォルダに移動しておきましょう。
`cargo`というのはビルドシステム兼パッケージマネージャーです。とても便利です。
`cargo`を使うことでライブラリのダウンロードからビルドまで扱ってくれます。

# proconioのインポート
`Cargo.toml`というファイルがあると思います。
```toml
[package]
name = "prac"
version = "0.1.0"
edition = "2024"

[dependencies]
```
そのファイルを開くとこんな感じになっています。
>最後の行の[dependencies]は、プロジェクトの依存を列挙するためのセクションの始まりです。 Rustではコードのパッケージのことをクレートと呼びます。
[Rust Programing Language 日本語版](https://doc.rust-jp.rs/book-ja/ch01-03-hello-cargo.html)

とのことなので、`[dependencies]`の後にproconioを使うよーという内容のものを書き足してあげます。
```terminal
[package]
name = "a"
version = "0.1.0"
edition = "2024"

[dependencies]
proconio = "0.4.3"
```
これでProconioを使用できます。

# スクリプト
`main.rs`にスクリプトを書いていきます。srcフォルダの中に入っています。
`mian.rs`を開けると
```rust
fn main() {
     println!("Hello World");
}
```
とすでに書いてあります。今回は`Hello World`は使わないので消しておいてください。
```rust
use proconio::input;

fn main() {
    input! {
        n: String,
        m: f32,
        l: i32,
    }
    println!("{} {} {}", n, m, l);
}
```
`n`でString型（文字列）を受け取ります。
同じように`m`でf32型（浮動小数点型）、`n`でi32型を（整数型）を受け取ります
そして受け取った値を`println!`で出力します。

# 実行
```terminal
$ cargo run
```
このコマンドで実行すると標準入力が可能です。

楽ですね。標準入力をつらつらと書いているのに比べたらすごく楽な気がします。

# 参考

https://docs.rs/proconio/latest/proconio/

もとは競プロ用に作られたクレートらしいです。競プロをRustでやる人はぜひ。
【初心者OK】GW中にChatGPTでできること📋×実践まで

みなさん、こんばんは！　韓国在住のsanaです:relaxed:

最近、私たちの生活に欠かせない存在になりつつあるchatGPT
単に調べものをしたり、画像生成だけでなくプログラミングもchatGPTで可能だということはIT学習をしている皆さんならもうご存じですよね！

今日はchatGPTを活用方法を学べる講座を３つ紹介いたします。


🌟 講座①
📚 ChatGPTって何？🤖という方にピッタリの入門講座✨
💬 日常での使い方から、ちょっとした自動化までサクッと解説！
🎓 はじめてAIに触れる人でも、やさしく・わかりやすく学べます！
📌「とりあえず使ってみたい！」人はここからスタート🏁

https://u.inf.run/4lOJEZn


🚀 講座②
🧑‍💻 仕事にAIを活かしたい人向けの超実用講座💥
🗂️ メール作成📨、議事録まとめ📝、企画のアイデア出し💡など、
⏰ 毎日の業務を「爆速」にするワザを伝授！
👀 明日から即効使えるテクニック満載✨

https://u.inf.run/4jx4mLt

🐍 講座③
👨‍💻 Pythonでネットワークツールを作ってみたい人におすすめ🎯
🤖 ChatGPTを使ってコードを自動生成→実装まで体験できる✨
🌱 コーディング経験がある人は、AI×開発の楽しさを味わえます！
💪 ひと味違う実践型チャレンジ～🔥

https://u.inf.run/4jWMLMZ



複雑な作業こそChatGPTの力を借りたいですよね!! 

ChatGPTを使いこなす役に立てば嬉しいです！

アンニョン:girl_tone1:
ネストされたオブジェクトの分割代入(react-hook-formでの利用例も紹介)

## 基本：オブジェクトの分割代入

オブジェクトは**キー名で指定して取り出す**必要があります。順番は関係ありません。

```js
const obj = { foo: 100, bar: 200 };
const { foo, bar } = obj;

console.log(foo); // 100
console.log(bar); // 200
```

存在しないキーを指定した場合も、値は `undefined` になります。

```js
const { baz } = obj;
console.log(baz); // undefined
```

## 本題：ネストされたオブジェクトの分割代入

オブジェクトの中にオブジェクトがある場合、**ネストして取り出す**ことができます。

```js
const user = {
  name: "太郎",
  contact: {
    email: "taro@example.com",
    phone: "090-1234-5678"
  }
};

const {
  contact: { email, phone }
} = user;

console.log(email); // "taro@example.com"
console.log(phone); // "090-1234-5678"
```

このとき、`contact` という変数自体は定義されません。

```js
console.log(contact); // ReferenceError: contact is not defined
```

## エラーになるケース

ネストされたプロパティを取り出そうとした際、途中のオブジェクトが `undefined` の場合にはエラーになります。

```js
const obj = {};
const { nested: { value } } = obj; // エラー
```

このような場合は、デフォルト値を指定して防ぐことができます。

```js
const { nested: { value } = {} } = obj;
```

または、事前に空オブジェクトで安全に展開する方法もあります。

```js
const { nested = {} } = obj;
const { value } = nested;
```

## react-hook-formでの利用例

Reactでは、ライブラリの内部から提供されるオブジェクトを「分割代入」で効率よく扱うことがよくあります。

以下は、`react-hook-form` の `useForm` フックを使った例です。

```js
import { useForm } from "react-hook-form";

export default function App() {
  const {
    register,
    handleSubmit,
    watch,
    formState: { errors },
  } = useForm();

  const onSubmit = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input defaultValue="test" {...register("example")} />
      <input {...register("exampleRequired", { required: true })} />
      {errors.exampleRequired && <span>This field is required</span>}
      <input type="submit" />
    </form>
  );
}
```

この中の以下のコードに注目します。

```js
const {
  formState: { errors },
} = useForm();
```

ここでは、`useForm()` が返すオブジェクトの中にある `formState` というプロパティから、さらに `errors` を取り出しています。

このことから、`useForm()` の戻り値はおおよそ以下のような構造になっていることが連想できますよね。

```js
{
  register: ...,
  handleSubmit: ...,
  watch: ...,
  formState: {
    errors: { // ←注目、formStateプロパティのバリューさらにerrorsオブジェクトがあるはず
       ...,
      }
    },
    isDirty: true,
    isValid: false,
    // 他にもいろいろ
  },
  // 他にもいろいろ
}
```

このように、`formState` というオブジェクトの中にある `errors` を直接使いたい場合、ネストされた分割代入を使うことで次のように書けます。

```js
const { formState: { errors } } = useForm();
```

こうしておくと、以降 `errors.exampleRequired` のように直接アクセスできるため、コードがすっきりします。

この構文は一見複雑に見えますが、前述のネストされたオブジェクトの分割代入とまったく同じ考え方です。

## まとめ

- オブジェクトは**プロパティ名**で対応付けられる
- 存在しないキーを指定しても `undefined` になる（基本的にはエラーにはならない）
- **ネストされたオブジェクトの中身を取り出す場合、途中のオブジェクトが存在しないとエラーになる**
Airflow の DAG で、start_date を明示的に設定して dag trigger したい話

# ユースケース

以下のような DAG 設定だったとする

```
args = {
    "owner": "shase428",
    "start_date": airflow.utils.dates.days_ago(2),
}

parent_name = "foobar_dag"

dag = DAG(
    parent_name,
    default_args=args,
    schedule_interval="0 10 * * *",

)
```

通常の運用では問題ないのだが、古い日付でdag triggerしたい場合、dag trigger の日付指定は、start_date より以前は指定できないため、詰む（以下のようなエラーが出る）


```
ValueError: The execution_date [2025-02-28T00:00:00+00:00] should be >= start_date [2025-04-28T00:00:00+00:00] from DAG's default_args
```

そのため、必要に応じて以下のように修正する

```
args = {
    "owner": "shase428,
    'start_date': datetime.datetime(2025, 2, 1),

}

parent_name = "foobar_dag"

dag = DAG(
    parent_name,
    default_args=args,
    schedule_interval="0 10 * * *",
    catchup=False,
)
```

# ポイント

- start_date は、`airflow.utils.dates.days_ago` ではなく、絶対的な日付を渡す `datetime.datetime(2025, 2, 1)`
- `catchup=False` をつけて、勝手にbackfill実行されないようにする

# 参考
- https://future-architect.github.io/articles/20200131/
OAC：AGO関数を使った際のエラー　"[nQSError: 59001] Add操作は、TIMESTAMP, INTEGERオペランドでは許可されていません。"

はじめに
---
AGO関数を使った際にエラーが発生しました。エラーの詳細に、、"[nQSError: 59001] Add操作は、TIMESTAMP, INTEGERオペランドでは許可されていません。"というメッセージが含まれています。そんなときの対処についての１つについて記載します。

![g5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/6fa28eb3-4548-4446-9a57-016e8065c79b.jpeg)

記事記載時のOAC ver：May 2025 Update

前提
---
データセットを利用してワークブックを作ったことがある
マイ計算で関数を使ったことがある

データセットの作成
---
以下のExcelファイルをアップロードして、データセットを作成します。
![g1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/ec433a6b-bcb9-4176-8b3a-c052cf2dbd2b.jpeg)

ワークブックの作成
---
以下のワークブックを作成します
![g2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/938074e8-b45b-437e-a414-bf43b1a03f94.jpeg)

マイ計算で、AGO関数を利用したマイ計算列を作成します
![g3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/d27d33f6-c97a-49d8-bc64-afa396f007b3.jpeg)

作成したマイ計算列を配置します
![g4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/e2c67766-5c96-4da3-92d5-e6d5ce8097bb.jpeg)

問合せエラーで、詳細をクリックします。
メッセージに、以下が含まれています。
"[nQSError: 59001] Add操作は、TIMESTAMP, INTEGERオペランドでは許可されていません。"というメッセージが含まれています。
![g5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/ebd54887-7f3d-41c3-beed-166f5db0cc41.jpeg)


対処
---
マイ計算で、メジャー列の数値型をかえてみます。たとえば1.0をかけると、DOUBLEの数値型をもつ列になります。
![g6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/6f20f9f2-b277-4957-be68-cb3f05bc0156.jpeg)

AGO関数で、作成したマイ計算列をつかいます
![g7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/3fdd8907-5c38-4718-b1f8-fb79f4ae2bb9.jpeg)

列を配置します。
![g8.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516153/1c990617-e6c1-4f9b-8988-7fce9993aaad.jpeg)

まとめ
---
AGO関数を使った際にエラーが発生し、エラーの詳細に、、"[nQSError: 59001] Add操作は、TIMESTAMP, INTEGERオペランドでは許可されていません。"というメッセージが含まれている場合の対処について、試してみました。
AGO関数にセットする列で、INTEGERの数値型のデータが返される場合に発生するメッセージです

以上
【Claude 3.7sonnet】予算管理アプリ開発レポート!

## はじめに
現在、Claude 3.7 sonnet を色々と試してみようということで
Claude 3.7 sonnet を使ってアプリ開発を行っております

今回は第3弾！予算管理アプリです！理由は特にありません！

これまでの記事はこちら

https://qiita.com/shimizu_432/items/0c8a8e91365b79164e33

https://qiita.com/shimizu_432/items/b5bf6de705056b9a19d4

## 予算管理アプリを作っていく！

少し難しそうな機能までお願いしてみようと思います！
どこまで生成してくれるか！

プロンプトはこちら
```ruby:プロンプト
以下のアプリを作って
 予算管理アプリ
   * 基本機能: 収入と支出の記録、カテゴリ分け、予算の設定。
   * 難しい機能: 自動予算計算、レポート表示、予算の共有機能。
```
【TOP（取引履歴）】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3954326/5b827fb3-b7dc-47a9-ba17-d446ff55d890.png)
【取引追加】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3954326/8ee426a5-25d4-45f0-9058-4d7d6d877b41.png)
【予算共有】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3954326/74719c4a-65ed-4977-913e-33092125ac99.png)
【TOP（レポート 円グラフ）】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3954326/fbeb6cb3-5b7c-43e8-9d43-e478b0c30bd1.png)
【TOP（レポート 棒グラフ）】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3954326/716cb7fb-e64f-4172-b082-af7c3f10761d.png)
【予算を設定】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3954326/66a325fb-ef43-4f05-b759-d58e27e6282e.png)

なんだこれ、、、スゴスギル！！！
2回程エラーと字数制限がありましたが、そんなことよりもすごい

収支も見やすいし、取引明細まである
レポートも棒グラフと円グラフどちらにも対応している

画像では分かりにくいかもしれませんが、
棒グラフ円グラフ共に、0からグワーッと広がる動的なもの！
さらにカーソルを合わせると詳細まで表示してくれます！！！

レポートの共有は動きませんでしたが、ここまで進めてくれるのなら個人的には満足です

では、カスタムしていきます！
これまでの経験から、ここから大きな変更をするとエラーが頻発する気がするので
少しずつ機能追加していきます！

あまり負荷が無さそうな機能を追加してみます

```ruby:プロンプト
収入支出残高をドルでも表示して
```

字数制限とエラーが続きアプリが生成されませんでした、、
一番上の収支支出残高だけ変えてもらおうと思ったのですが、
グラフとかもドルverにしようとしてたみたいです

そりゃ、負荷がありすぎましたね。プロンプトも良く考えなければなりませんね

今度こそ、本当に負荷が少ないものにしたいと思います

```ruby:プロンプト
やっぱり、別の変更をしたい
色を青ペースにして
```

こちらも字数制限とエラーが頻発し、生成されませんでした

最初に生成したものが最大の機能だったのでしょうかね

## 今回の気づき
・グラフも作れる
・動的なものも作れる
・マウスオーバーも作れる
・Claudeの良さを引き出せる適切なプロンプトがありそう
・勘違いされないプロンプトを書く
・今回生成したアプリが現状できる最大の機能量っぽい
アジャイル開発と長期的なUI/UX設計は両立すべきもの



##  結論：  
> アジャイルだからといって「行き当たりばったり」でよいわけではなく、  
> **「MVPで素早く試す」×「将来を見据えたUI/UXの設計思想」**　を両輪で回す必要があります。

---

##  両立させるためのポイント

### ① UI/UXにも「プロダクトの北極星（North Star）」を持つ
- どんな価値を誰に届けたいのか、サービスの「理想体験」を定義しておく
- MVPではそのごく一部しか実装しなくても、「どこに向かっているか」が明確なら後で再利用・拡張がしやすい

### ② アーキテクチャと同様に、UI構造も「疎結合」を意識する
- 「とりあえず画面作る」ではなく、UIコンポーネントや情報設計に再利用性や柔軟性をもたせる
- 例：共通のボタン設計、状態管理、ナビゲーションルールなどを最初に軽く整えておく

### ③ ユーザーテストや分析を前提にした「変化に強い設計」
- アジャイルは変更を前提とするが、**「なんでも作り直し前提」ではコストが爆増**
- 初期から「検証して変える部分」と「変わりにくい基盤」を切り分ける

---

##  例：MVP設計と将来の両立のイメージ

| 項目 | MVPでは | 長期設計では |
|------|----------|----------------|
| 画面構成 | 最小限（2〜3画面） | 全体構成はFigmaでマップを描いておく |
| UIデザイン | 手早く作れる範囲で | コンポーネント指向にして再利用性を持たせる |
| UX導線 | 1つの基本フロー | ペルソナやシナリオマップを設計しておく |
| 情報設計 | 必要最低限のデータ表示 | 情報階層を見据えて設計しておく |

---

## 👨‍💻 まとめ：  
アジャイル = 短期思考ではなく、  
**「将来を見据えて、今できることから順に価値を出していく開発」**　です。

「今はMVP、でも設計思想は10年先も見ている」  
そういうチームは、結果的に早く成長できますでしょう。
steinburg UR22Cのfirmwareが古くてpipewire上でALSA UCM errorになった話

# はじめに
個人的な理由からメインで使用するPCをwindowsからarchlinuxに移行中。  
Yamahaのsteinburg UR22Cを接続した際、ALSA UCM errorが発生しました。  

入出力へ大きな問題はありませんでしたが、気持ち悪かったので対処しました。  
調べても日本語の記事がなかったので念の為qiitaに記事を投稿しておきます。

# 原因と対策

## 原因
UR22Cのfirmwareのバージョンが1.2.14〜3.0だとUCMエラーが発生します。
この間のバージョンではUR22CのHWChannelが2となっているようです。
一方、alsa-ucm-confはUR22C用のHWChannelsが2-->4へ変更されています。
この不一致がエラーの原因のようです。

## 対策
windowsもしくはmacを使用して、UR22C側のファームウェアのバージョンを上げます。
2025-04-30現在、3.2.0が最新でした。
`TOOLS for UR-C`であれば、UR22CとPCを接続してソフトウェアを起動するだけで、ファームウェアのバージョンの確認を行い、ユーザーへバージョンアップを提案してくれるのでお手軽かなと思います。

# おわりに
steinbergのフォーラムなどでは、archlinuxで本体は使えるけどdspMixFxが使えない、のような投稿が多く、UCM errorに関する投稿は見かけませんでした。
周辺機器のファームウェアのチェックを怠っていた私の落ち度でした。反省です。

# 参考
- alsa-project/alsa-ucm-conf　コミット`2f0c858`
https://github.com/alsa-project/alsa-ucm-conf/commit/2f0c858ed799b53864f9e0da53d125419fce8ee9
- TOOLS for UR-C ダウンロードサイト
https://japan.steinberg.net/jp/support/downloads/ur-c.html
半加算器

Paizaの問題解いてたら、足し算をゴリ押しするより論理演算使ったほうがカッコいいじゃんって気づきました。

## <br>📝 問題概要

`0` か `1` の整数 `A` , `B` が与えられる。

`A + B` の2進表記で

下から2桁目 → `C`（Carry：繰り上げ）

下から1桁目 → `S`（Sum：和）

を出力せよ！

例:
```
入力: 
1 1

出力: 
1 0
```
<br>

https://paiza.jp/works/mondai/logical_operation/logical_operation__basic_step8



## <br>例１:普通に足し算
```js
const sum = A + B;
const S = sum % 2;
const C = Math.floor(sum / 2);
console.log(C, S);
```
- `sum = A + B` として普通に足し算する
- `S`は 1の位 を `sum % 2` で求める
- `C`は 繰り上がりを `Math.floor(sum / 2)` で求める

たしかに動くけど、なんか...スマートさに欠ける！

## <br>✅例２：論理演算
```js
const C = A & B; // AND: 両方1なら1
const S = A ^ B; // XOR: 違うときだけ1
console.log(C, S);
```
- `&`（AND） は 「両方が1なら1」 → 繰り上がり（Carry）が発生する条件
- `^`（XOR） は 「どちらか一方が1なら1」 → その桁の合計（Sum）の値





## <br>✍️メモ　まとめ

- `&`（AND）は両方1なら1 → Cにぴったり。
- `^`（XOR）はどちらか一方だけ1なら1 → Sにぴったり。


これが噂の「半加算器」か…!

<br>[失敗談(´;ω;｀)と解決法🐈](https://paizabeginner.wordpress.com/2025/04/30/paiza%e3%81%a7%e5%9f%ba%e6%9c%ac%e3%83%9e%e3%82%b9%e3%82%bf%e3%83%bc%ef%bc%9a%e5%8d%8a%e5%8a%a0%e7%ae%97%e5%99%a8/)
AtCoder Beginner Contest 403 振り返り

ABC403の振り返りです。久しぶりの参加です

## 結果

ABCの3完でした。

![スクリーンショット 2025-04-30 17.14.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167729/7b194aee-e690-4b7f-a1d5-03a38769e7e8.png)

![スクリーンショット 2025-04-30 17.13.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167729/d22c558b-8f78-46ad-aae1-98a4375c3ede.png)

## ふりかえり

### A問題

- 問題
  - https://atcoder.jp/contests/abc403/tasks/abc403_a
- 回答
  - https://atcoder.jp/contests/abc403/submissions/65242354

範囲内の奇数を取得し、配列からアクセスして合計します

```haskell
main :: IO ()
main = do
  n <- readLn @Int
  as <- getInts

  print $ sum [as !! (i - 1) | i <- [1 .. n], odd i]
```

### B問題

- 問題
  - https://atcoder.jp/contests/abc403/tasks/abc403_b
- 回答
  - https://atcoder.jp/contests/abc403/submissions/65254094

部分配列をすべて取得して`zipWith`で比較します。
計算量は`O(T^2)`ですが、`T は長さ 4 以上 10 以下の英小文字と ? からなる文字列`とあるので、問題なしと判断しました。

```haskell
main :: IO ()
main = do
  t <- getLine
  u <- getLine

  let tLen = length t
      uLen = length u
      ts = [take uLen $ drop i t | i <- [0 .. (tLen - uLen)]]
      f = zipWith (\uc tc -> tc == '?' || tc == uc)
  printYn $ any (and . f u) ts
```

### C問題

- 問題
  - https://atcoder.jp/contests/abc403/tasks/abc403_c
- 回答
  - https://atcoder.jp/contests/abc403/submissions/65276761

```
1 X Y: ユーザ X にコンテストページ Y の閲覧権限を付与する。
2 X: ユーザ X にすべてのコンテストページの閲覧権限を付与する。
```

とあるので、ユーザ毎にに各コンテストページの管理テーブルを用意します

ただし、これだけだと2のパターンでユーザごとにコンテストページの閲覧権限をすべて付与することになってしまうため、TLEになることが目に見えています。
そのため、①サイト個別の権限管理テーブルと②サイト全体の権限管理テーブルの2つを用意します。

もう一点注意することとして、空間計算量の問題があります。
権限の管理テーブルをArrayで実装した場合、①のサイト個別の権限管理テーブルだと、

N人のユーザ x M個のサイト

の数だけ要素数を持っておく必要があります。

これだと、制約
```
1≤N≤2×10^5 
1≤M≤2×10^5
```

から、Intが4バイト(32bit環境)だとして、最悪空間計算量が

`(2*10^5)^2 * 4 = 1.6 * 10^11 = 160GB`

となってしまい、制約条件の`1024 MB`を軽く超えてREになってしまいます。

参考までに、実装は以下のようになります。
```haskell
main :: IO ()
main = do
  [n, m, q] <- getInts
  qs <- replicateM q getInts

  auth <- newArray @IOUArray ((1, 1), (n, m)) False
  allAuth <- newArray @IOUArray (1, n) False

  forM_ qs $ \case
    [1, x, y] -> do
      writeArray auth (x, y) True
    [2, x] -> do
      writeArray allAuth x True
    [3, x, y] -> do
      all <- readArray allAuth x
      indiv <- readArray auth (x, y)

      printYn $ all || indiv
```

REを防ぐためには、Setを使って管理するようにします。
これだとREが出ず、ACできます。

```haskell
main :: IO ()
main = do
  [n, m, q] <- getInts
  qs <- replicateM q getInts

  let indivAuth = S.empty
      allAuth = IS.empty

  f indivAuth allAuth qs

f :: S.Set (Int, Int) -> IS.IntSet -> [[Int]] -> IO ()
f _ _ [] = return ()
f indivAuth allAuth (q : qs') = case q of
  [1, x, y] -> do
    f ((x, y) `S.insert` indivAuth) allAuth qs'
  [2, x] -> do
    f indivAuth (x `IS.insert` allAuth) qs'
  [3, x, y] -> do
    let indiv = (x, y) `S.member` indivAuth
        al = x `IS.member` allAuth

    printYn $ al || indiv
    f indivAuth allAuth qs'
  _ -> error "invalid pattern"
```

## 全体を振り返って

早く茶色になりたい！
PhpStorm 2025.1 で消えた Local Changes タブを復活させる方法

最近PhpStormをアップデートすると度々 `Local Changes` タブが無くなるのですが、今回はプラグインの導入が必要だったためメモを残します。

📌 バージョン: PhpStorm 2025.1

## プラグインの導入

まず 「Settings > Plugins」 の Marketplace で「Git Modal Commit Interface」を検索しインストール後プラグインを有効にします。

![スクリーンショット 2025-04-30 17.01.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42028/afb5d7fd-6e5f-4a90-bdfb-c490a1bdd3e6.png)

## プラグイン有効化後の設定

プラグイン導入後、以下の設定を行います。
「Settings > Advanced Settings > Version Control. Git > Use modal commit interface」にチェックを入れます。

![スクリーンショット 2025-04-30 17.04.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42028/a2d494ae-0f7c-4180-b936-c48fd007b970.png)

## 結果

無事に Local Changes タブが復活しました 🎉

![スクリーンショット 2025-04-30 17.25.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42028/a2e216a1-4a94-4465-8148-2dba67b805c5.png)

## 参考
- [Local Changes Tab missing in PHPSorm 2025.1](https://intellij-support.jetbrains.com/hc/en-us/community/posts/26088498064786-Local-Changes-Tab-missing-in-PHPSorm-2025-1)