OmniAICreator/Qiita-1.07M huggingface dataset:
Laravelで依存性注入を使わずに毎回インスタンス化するデメリットを検証してみた

## はじめに
Laravelで開発していると、インスタンスを作成する場合は依存性注入（Dependency Injection DI）を使用することが推奨されていて、コントローラー内で同じクラスを何度もインスタンス化することは避けられています。
しかし、毎回インスタンス化するのは非効率だという話を聞くけど、具体的にどう非効率なのか気になったので検証してみました。
今回は、依存性注入（DI）を使う場合と使わない場合で、メモリ消費量と処理時間を比較してみます。

## 検証環境
Laravel 11系
PHP 8系
Docker環境上で実行

## テストコード
テスト対象となる MyService クラスを用意する。

```php MyService.php
namespace App\MyClasses;

class MyService
{
    public function someMethod()
    {
        return true;
    }
}
```
続いて、コントローラーにテストコードを書く。

```php PostController.php
namespace App\Http\Controllers;

use App\MyClasses\MyService;

class PostController extends Controller
{
    public function index(MyService $myservice)
    {
        // 依存性注入なし
        $startMemoryNonDI = memory_get_usage();
        $startTimeNonDI = microtime(true);

        for ($i = 0; $i < 1000; $i++) {
            $object = new MyService();
            $object->someMethod();
        }

        $endMemoryNonDI = memory_get_usage();
        $endTimeNonDI = microtime(true);

        $msgNonDI[] = 'Memory used: ' . ($endMemoryNonDI - $startMemoryNonDI) . ' bytes';
        $msgNonDI[] = 'Time taken: ' . ($endTimeNonDI - $startTimeNonDI) . ' seconds';


        // 依存性注入あり
        $startMemoryDI = memory_get_usage();
        $startTimeDI = microtime(true);

        for ($i = 0; $i < 1000; $i++) {
            $myservice->someMethod();
        }

        $endMemoryDI = memory_get_usage();
        $endTimeDI = microtime(true);

        $msgDI[] = 'Memory used: ' . ($endMemoryDI - $startMemoryDI) . ' bytes';
        $msgDI[] = 'Time taken: ' . ($endTimeDI - $startTimeDI) . ' seconds';

        $data = [
            'NonDI' => $msgNonDI,
            'DI' => $msgDI,
        ];

        return view('post.index', $data);
    }
}
```
## 検証結果
![スクリーンショット 2025-03-28 16.17.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762407/d2752404-b1b2-4383-b481-a4824d20e2a3.png)

| テスト  | メモリ使用量 (bytes) | 処理時間 (seconds) |
|--------|----------------------|---------------------|
| NonDI  | 80 bytes             | 0.0346479 seconds     |
| DI     | 0 bytes              | 0.0144579 seconds     |

## 結果分析
メモリ使用量の違い：NonDI では毎回インスタンス化するためメモリを消費するが、DI では同じインスタンスを使い回すため消費が 0 になる。

処理時間の違い：NonDI は 1000 回のインスタンス化処理が発生するため、処理時間が長くなる。

## まとめ
コントローラー内で同じクラスを 何度もインスタンス化するのは非効率 であることが確認できました。
特に、処理回数が多くなるとパフォーマンスに影響が出やすいようですね。
Laravelの 依存性注入（DI） を使うことで、効率的に同じインスタンスを再利用できます。
DI を使わない場合のデメリットを実際に検証することで理解が深まりましたので、継続して学んでいきたいです！
🧠 エンジニア面接は本当に効率的か？──面接プロセスを分解・再設計する構想

## はじめに

エンジニアとして何度も面接を受ける中で、ふとこんなことを思いました。

> 「今の“面接”って、本質的に効率のいい選抜手段なんだろうか？」

アルゴリズムテスト、カルチャーフィット、技術面談、最終面接…。これまで当然のように行われてきたこれらのプロセスですが、冷静に見ると再現性も納得感も欠けた“古びたUX”ではないでしょうか。

この記事では、現行の面接プロセスをいったん“コードのように分解”してから、 **目的ベースで最適化・再構築するリファクタリング案** を提案します。

---

## 📦 現在の一般的な面接プロセスを要素分解してみる

まずは、現状の「典型的なエンジニア採用フロー」を以下のように分解してみます。

| ステップ | 目的 | 手法 | ボトルネック |
|----------|------|------|---------------|
| 書類選考 | スキルのスクリーニング | レジュメ・GitHubなど | 実力が見えにくい／表現力に依存 |
| 一次面接 | 人柄・動機の確認 | オンライン通話 | 短時間／主観的な判断 |
| 技術面接 | 実務スキルの確認 | コーディングテスト・設計課題など | 再現性がない／業務と乖離 |
| 最終面接 | 組織視点での総合評価 | CEO・役員面談 | 志望動機に演技が出やすい |
| オファー | 条件交渉 | 人事面談 | 判断基準が不明瞭になりがち |

こうして分解してみると、**各ステップが“短時間・主観的・単発的”な評価に寄っている**ことが分かります。しかも「一緒に働く相手として本当にフィットするのか？」という一番重要な問いには、どのプロセスも十分に応えていないのではないでしょうか。

---

## 🔧 面接プロセスをリファクタリングするなら？

この構造を、**エンジニアリング的思考で再設計**してみましょう。  
考え方は「ソフトウェア設計と同じ」です。

### 🎯 リファクタリングの原則
- **目的に対して正しい責務分離がされているか？**
- **評価の入力（Input）と出力（Output）が明確か？**
- **ステップ間に文脈的なつながりがあるか？**
- **再現性と納得感が高いか？**

---

## ✨ 新プロセス案「共創型トライアル（CoTrial）」採用

ここで僕が考えたのが、**面接を“共創のプロセス”に変える**というアプローチです。

### 🧱 CoTrial採用の構成（ステップごと）

| ステップ | 内容 |
|----------|------|
| `PreSelect()` | 書類＋GitHub＋ポートフォリオからAIスクリーニング（評価の事前仮説） |
| `AsyncFitCheck()` | 非同期チャットで価値観や考え方をすり合わせ |
| `SkillSimulation()` | 実際の小課題 or リアルなIssueに取り組む（ペア設計・PR・レビュー含む） |
| `InteractionObservation()` | Slack・GitHub上での“共創ログ”からチーム適性を観察 |
| `MutualFeedbackSync()` | 双方向のフィードバックと感想の共有（納得感の構築） |
| `OfferSync()` | 条件提示と今後のビジョンの共有、選択の最終確認 |

---

## 📈 Before / After で比較してみる

| 項目 | 従来の面接 | CoTrial方式 |
|------|-------------|----------------|
| 技術力評価 | 試験中心・一発勝負 | 実務ベース・プロセス重視 |
| 人柄評価 | 面接での印象 | 実際のやりとり・レビューから観察 |
| コミュ力評価 | 話し方やトーン | 非同期＋チーム内議論での対応 |
| 熱意の確認 | 志望動機の言語化 | 課題への取り組み方・提案力で判断 |
| 候補者体験 | 評価される一方的体験 | 相互フィードバックの共創体験 |

---

## 🤔 本当に必要なのは「面接」じゃなくて「共創の検証」なのかもしれない

現代のエンジニア採用では、  
単にスキルを測ることよりも、

> 「この人と実際に一緒に仕事ができそうか？」  
> 「プロダクトに責任を持てるチームを組めるか？」

という問いが本質的です。

だからこそ、採用もまた、**コードと同じように設計し直せるはず**です。  
実装コストは多少かかっても、「入社後のミスマッチ」という最大のバグを減らせるなら、その価値は十分にあると思っています。

---

## 🔚 おわりに

この構想はあくまで一案ですが、  
「面接を当たり前と思わず、再設計してみる」という発想自体に価値があると感じています。

みなさんのチームでも「これって本当に最適な形か？」と問い直す機会があれば、ぜひ一度“面接リファクタリング”してみてください。

---

📣 ご意見・フィードバック・実践例などあれば、ぜひコメントで教えてください！
ubuntuにwireguardを構築

# Wireguardとは
wireguardはVPNです。
その他詳しいことは調べてください。

# 記事の目的と利用方法
この記事は筆者のMEMOです。
後述のスクリプトを利用することでwireguardを容易に設定できます。
利用方法は以下の通りです。
- 初期設定：`wg-setup.sh`を実行します。
- peerを追加：`wg-peer.sh 172.16.42.x`を実行してください。
 `172.16.42.x`の`x`にあたる部分は適宜変更してください。

# wg-setup.sh
`INTERFACE=`は適宜変更してください。
```bash
#!/bin/bash

PS4="[  \e[32mOK\e[m  ] "
set -xue

sudo apt-get update > /dev/null
sudo apt-get install iptables resolvconf wireguard qrencode jq -y > /dev/null

sudo rm -rf /etc/wireguard/keypairs
sudo mkdir /etc/wireguard/keypairs

PRIVATE_KEY=`wg genkey | sudo tee -a /etc/wireguard/keypairs/server.key`
PUBLIC_KEY=`sudo cat /etc/wireguard/keypairs/server.key | wg pubkey | sudo tee -a /etc/wireguard/keypairs/server.pub`

INTERFACE=eth0

cat <<EOF | sudo tee -i /etc/wireguard/wg0.conf > /dev/null
[Interface]
PrivateKey=$PRIVATE_KEY
Address=172.16.42.1
ListenPort=51820
PostUp=iptables -A FORWARD -i wg0 -j ACCEPT && iptables -t nat -A POSTROUTING -o $INTERFACE -j MASQUERADE
PostDown=iptables -D FORWARD -i wg0 -j ACCEPT && iptables -t nat -D POSTROUTING -o $INTERFACE -j MASQUERADE

EOF

sudo  cat /etc/sysctl.conf | sudo sed -i '/net.ipv4.ip_forward=1/c net.ipv4.ip_forward=1' /etc/sysctl.conf
sudo sysctl -p > /dev/null
sudo systemctl enable --now wg-quick@wg0
```

# wg-peer.sh
`172.168.42.0/24`であることを想定して作っています。
```bash
#!/bin/bash

PS4="[  \e[32mOK\e[m  ] "
ERROR="[  \e[31mERROR\e[m  ]"
IP="$1"

if [ -z $IP ]; then
  echo -e "$ERROR Please set the "IP" environment variable and try again. It must be between 172.16.42.2 and 172.16.42.254" >&2
  exit -1
fi
if [ `sudo cat /etc/wireguard/wg0.conf | grep "$IP"` ]; then
  echo -e "$ERROR $IP is already configured." >&2
  exit -1
fi

set -xue

PRIVATE_KEY=`wg genkey | sudo tee -a /etc/wireguard/keypairs/client.$IP.key`
PUBLIC_KEY=`echo $PRIVATE_KEY | wg pubkey | sudo tee -a "/etc/wireguard/keypairs/client.$IP.pub"`

cat <<EOF | sudo tee -a /etc/wireguard/wg0.conf > /dev/null
[Peer]
PublicKey=$PUBLIC_KEY
AllowedIPs=$IP
PersistentKeepAlive=25

EOF

cat <<EOF | sudo tee -i /etc/wireguard/client.conf.$IP.sample > /dev/null
[Interface]
PrivateKey=$PRIVATE_KEY
Address=$IP/32
MTU=1365
DNS=1.1.1.1

[Peer]
PublicKey=`sudo cat /etc/wireguard/keypairs/server.pub`
AllowedIPs=0.0.0.0/0
Endpoint=`curl -sL 'https://api.ipify.org?format=json' | jq .ip | sed 's/"//g'`:51820
PersistentKeepAlive=25
EOF

sudo systemctl restart wg-quick@wg0

set +x
echo -e "\e[33m"
sudo cat /etc/wireguard/client.conf.$IP.sample
echo -e "\e[m"
sudo cat /etc/wireguard/client.conf.$IP.sample | qrencode -t ansiutf8
```
DIについて

【DI】
役割→オブジェクトの依存関係を外部から注入する仕組み
RepositoryとServiceクラスで、インターフェイスで定義すると、依存関係が低くなる。使わない場合は、依存関係が強くなる。


【どうやって注入するのか？】
→@Component と @Autowired を使用して、Springが依存関係を注入する。
もしくは、＠RequiredArgsConstructorを使用する。Lombokが依存関係を注入するためのコンストラクタを自動生成してくれる


【DIが成立する条件】
①依存元と依存先どちらもSpringの管理対象である
→＠Component、＠Service、＠Repository、＠Beanをつけている必要がある

②依存関係を注入するための仕組みが必要
→＠Autowiredか、Lombokの＠RequiredArgsConstructorを使用する

【＠Componentとは】
→Springの管理下として認識させるためのもの
＠Service、＠Repository、＠Beanでも代用できる


【＠Autowired】
→SpringのDIコンテナに依存関係を注入するためのもの


【＠RequiredArgsConstructorとは】
→フィールドにfinalか＠NotNullがついていれば、コンストラクタを自動生成してくれる
このコンストラクタの引数に、依存元のオブジェクトが元々入っているのでDIが成立している（依存先と依存元のクラスはSpringの管理対象であることが前提）


【＠NotNull】
→フィールドの変数にNullを代入できない。nullを防ぐもの
Laravel phpMyAdminとユーザ登録・ログイン機能の実装

今回はLaravelの最初の設定としてデータベースを見やすくする phpMyAdmin

![スクリーンショット 2025-03-28 141400.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4034432/f637e3f7-8843-4a63-88b9-1435a259939c.png)
（こんなやつ）

とユーザ登録・ログイン機能

![スクリーンショット 2025-03-28 073140.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4034432/30b8bf8f-d081-4ec2-9bff-73501afc8441.png)

を実装した。

## 1. phpMyAdmin 
phpMyAdminをつかえば専門的な知識がなくてもwebブラウザ上で視覚的にデータベース管理をすることができます。
**docker-compose.yml** ファイルを編集します。
具体的には以下のコードを追加します。（インデントに注意！）

```php
phpmyadmin:
        image: phpmyadmin/phpmyadmin
        links:
                - mysql:mysql
        ports:
                - 8080:80
        environment:
                MYSQL_USERNAME: '${DB_USERNAME}'
                MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
                PMA_HOST: mysql
        networks:
                - sail

```

その後　（http://localhost:8080/）
にアクセスすればブラウザ上でデータベースを可視化できます。

## 2. ユーザ登録・ログイン機能の実装

この機能の実装にはLaravelのユーザ認証機能パッケージを使うのが手っ取り早い。
パッケージはいくつかある。例えば、Laravel/ui, Jetstream, Breeze, Fortifyなどだ。
こんかいはBreezeを使用していく。

まず以下のコマンドを順番に実行する。

```
 ./vendor/bin/sail composer require laravel/breeze --dev
```

ここで実行するといくつか質問をされるが、以下のようになるように答える。

![スクリーンショット 2025-03-28 154003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4034432/6d2b710a-3b9e-4fa8-89b9-c882037f80b0.png)

続いて以下のコードを実行

```
./vendor/bin/sail artisan breeze:install
```

successfully とでたら次のコードを実行して完了です。

```
./vendor/bin/sail artisan migrate
```

![スクリーンショット 2025-03-28 071944.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4034432/73bc8b0e-acbd-4bfd-b2ae-2f9089a61495.png)

![スクリーンショット 2025-03-28 073140.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4034432/83ca850c-5451-4b0c-b0ca-b7584aa50430.png)
代表的なサーバの種類

## はじめに
代表的なサーバの種類についてまとめてみました。

## Webサーバ
Webサイトの機能を提供するサーバ。HTMLファイルや画像ファイル、プログラムなどを置いておく。クライアントのブラウザがアクセスしてくると、それらのファイルを提供する。
代表的なソフトは、Apache(Apache HTTP Server)、Nginx（エンジンエックス）、IIS(Internet Information Services）。

## メールサーバ
メールの送受信を担当するSMTPサーバと、クライアントにメールを受信させるPOPサーバがある。これら2つを合わせてメールサーバと呼ぶことが多い。メールをダウンロードしてから読むのではなく、サーバに置いたまま読めるIMAP4サーバもある。
代表的なソフトは、Sendmail、Postfix、Dovecot。

## データベースサーバ
データを保存したり、検索したりするためのデータベースを置くサーバ。
代表的なソフトは、MySQL、PostgreSQL、MariaDB、SQL Server、Oracle Database。

## ファイルサーバ
ファイルを保存して、皆で共有するためのサーバ。
代表的なソフトは、Samba。

## DNSサーバ
IPアドレスと、ドメインを結びつけるDNS機能を持つサーバ。

## DHCPサーバ
IPアドレスを自動的に振る機能を持つサーバ。

## FTPサーバ
FTPプロトコルを使って、ファイルの送受信を行うサーバ。Webサーバと同居させることが多く、ファイルの設置に使う。

## プロキシサーバ
通信を中継する役割を持つサーバの総称。社内LANなどインターネットから隔離された場所からインターネット上のサーバに接続するときに使う。また、プロキシサーバを経由すると、接続先から自分のアクセス元を隠すことが出来るため、自分の身元を隠したいときにも使われることもある。

## 認証サーバ
ユーザー認証するためのサーバ。Windowsネットワークにログインするための「Active Directory」と呼ばれるサーバや、無線LANやリモート接続する際にユーザー認証する「Radiusサーバ」などがある。
代表的なソフトは、OpenLDAP、Active Directory。

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

## 参考文献
・仕組みと使い方がわかる Docker&Kubernetesのきほんのきほん 単行本（ソフトカバー） – 2021/2/1
小笠原種高 (著)
p.13
【スプレッドシート】☑つけると現在時刻が入力できるようにする方法

# はじめに

スプレッドシートでタスク管理をしていると、現在の日時を入力したいときってありますよね。

セルを選択した状態で以下のようにコマンドすると日時を入力できるんです。（Mac）

コマンド|入力内容
---|---
`Cmd + Shift + ;` | 時間が入力できる<br>例）`15:30:03`
`Cmd + Option + Shift + ;` | 日付と時間が入力できる<br>例）`2024/12/27 15:30:42`

でも…

**「チェックボックスに ✔ つけたら、その時の時刻が入力されてほしいな〜」**

と思うことがあったので、[Google Apps Script](https://developers.google.com/apps-script?hl=ja)（以下、GAS） を使用して実装してみました。

# 完成イメージ

以下のスクショが完成イメージです。

![スクリーンショット 2024-12-27 16.46.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204349/5a0428c0-8a86-3668-ad0f-cafa50140b3f.png)


C列にチェックボックスがあり、✔ をつけると同行のD列に時刻が入力されるようにします。

`D2` のセルには `=returnTimestamp(C2)` という値が入っています。

# 実装

## チェックボックスの出し方

[こちら](https://support.google.com/docs/answer/7684717?hl=ja&co=GENIE.Platform%3DDesktop) に記載の通りで簡単にチェックボックスを追加することができます。

以下、手順からの抜粋です。

> 2.　チェックボックスを挿入するセルを選択します。
> 3.　上部のメニューで [挿入] 次へ [チェックボックス] の順にクリックします。

## GASで関数を作成

D列で使用する `returnTimestamp` という関数はGASを使って作成しています。
次の手順で作成していきます。

1. 上部メニュー [拡張機能] で　[Apps Script] をクリックしてGAS画面を開く
2. 画面上部のファイル名を適当に変更しる
3. 以下のスクリプトをコピーし、エディタへ貼り付けて保存する

```
function returnTimestamp(value) {
  if (value === true) {
    return getFormattedTimestamp();
  }
  return "";
}

function getFormattedTimestamp() {
  var now = new Date();
  var year = now.getFullYear();
  var month = ("0" + (now.getMonth() + 1)).slice(-2); // 月は0から始まるので+1
  var day = ("0" + now.getDate()).slice(-2);
  var hours = ("0" + now.getHours()).slice(-2);
  var minutes = ("0" + now.getMinutes()).slice(-2);
  var seconds = ("0" + now.getSeconds()).slice(-2);
  
  return year + "/" + month + "/" + day + " " + hours + ":" + minutes + ":" + seconds;
}
```

![スクリーンショット 2024-12-27 16.49.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204349/d7a0c604-c3c4-6bcc-36fc-404d6c190c83.png)

## 作成したスクリプトを呼び出す

チェックボックスがあるセルが `C2` なので、
`D2` のセルには `=getFormattedTimestamp(C2)` を入力します。

あとは `C2` のチェックボックスに ✔ をつけてみてください。

`D2` セルに現在時刻が入力されます。

# さいごに

以前は `=if(C2=TRUE,NOW(),"")` で同様のことが出来ていたんですが、
いつからかこの式だと「別の行の ✔ に反応して全部の時刻が現在の時間に更新される」という挙動になってしまうようになりました。

というわけで、GASを使って実装する経緯となりました。

もっといいやり方あるよ〜って方は、ぜひ教えていただけると助かります！
Swiftでシンプルで使いやすいカスタムLogger（ロガー）を実装

# ■ 概要
Swiftでログを出力するとなれば標準の「print関数」を使うのが一番簡単で手っ取り早いと思います。何かしらの結果をすぐログで出力して確認する用途であれば十分なのですが、アプリ内の処理結果を追う目的などの意図的に残すログとしてはあまりにも不十分です。<font color="gray">（ショボすぎ）</font>

とは言いつつ、そのログで確認したい情報ってある程度限られてきますし、そのためにLoggerのライブラリを入れるのもなぁという気持ちしかないです。

そのため今回は、標準のライブラリとフレームワークのみを使ったカスタムLoggerを実装してみました。

# ■ 環境
開発動作環境：MacBook Pro 16インチ
OSバージョン：macOS Sequoia バージョン15.0.1

Xcodeバージョン：16.2

# ■ 実装
```Swift:Logger.swift
import Foundation

class Logger {
    
    private static let dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        return formatter
    }()
    
    static func puts(_ items: Any..., file: String = #file, function: String = #function, line: Int = #line) {
        let currentTime = Logger.dateFormatter.string(from: Date())
        let itemStrings = items.map { String(describing: $0) }.joined(separator: " ")
        let fileName = URL(fileURLWithPath: file).lastPathComponent
        print("[\(currentTime)] \(fileName) (Line: \(line)) \(function) \(itemStrings)")
    }
}
```
こんな感じで呼び出すと

```Swift
Logger.puts("テスト")
```
こんな感じで出力されます。
```
[2025-03-28 14:47:01] TransitionView.swift (Line: 78) updateAnimation() テスト
```



# ■ 解説

Loggerとして必要な最低限の情報を

`① 日付時間`
`② ファイル名`
`③ 行数`
`④ 関数名`
`⑤ 出力する任意の値`

として実装しました。

Swiftで「print関数」をラップする形で実装することで、軽量かつ、ライブラリ関連などの特定環境に依存しないというメリットがあります。また上記の項目以外にも必要な情報があれば追加して、自由に出力のフォーマットを変更できるのも良い点です。

実装自体は「解説」ってほど内容はないですが、要所だけ。

## 1. 可変長引数

第一引数はAny型の可変長引数<font color="gray">（任意の数だけ引数を渡せます）</font>にしており、標準の「print関数」とインターフェースを統一してみました。

## 2. リテラル（#file、 #function、 #line）

第二引数以降は`ファイルパス(#file)`、`関数名(#function)`、`行数(#line)`のリテラルを、引数のデフォルト値に設定しておくことで、この関数の「呼び出し元」の値を取得することができます。<font color="gray">（つまりこのputs関数の呼び出した側のクラスのファイルパス、関数名、行数を取得できます。）</font>

またデフォルト値が設定されていることにより、実際にコーディングする時にエディタの補完にも第二引数以降は出てこない<font color="gray">（省略可能である）</font>ため、第二引数以降を基本的には一切意識せずに使用できます。

## 3. 「DateFormatter」はstatic定数で定義

スレッドセーフ、パフォーマンスを考慮してDateFormatterオブジェクトは静的定数で定義しています。

# ■ 最後に （感想）

Loggerとして必要最低限の機能を、限りなくミニマムで実装できたので良かったです。使えそうだなと思ってもらえたり、何かの実装の参考になれば幸いです。

最後まで読んでいただきありがとうございました。
ExcelVBAで多言語対応をする

ExcelVBAで多言語化対応をすることになったので、備忘録としてまとめます。

ExcelVBAでフォームを使ったアプリを作ったところ、英語でも表示できるようにしたいと要望がありました。
当然、多言語に対応するための機能はありません。
そこでVisual Studioでの多言語対応の方法を参考に、同等の機能をExcelVBAでも再現してみました。

## 実装イメージ
1.使用する単語をシートにまとめる
2.クラスモジュールに単語を格納するプロパティを追加する
3.CallByName関数を使い、指定された言語の文字列をプロパティに格納する
4.クラスモジュールに格納された文字列を使用する

## 使用する単語をシートにまとめる
言語情報を記載するシートを用意します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945532/82d1f58d-168d-41e7-b2d1-ad68f665ca80.png)

ここで記載するのは識別用の名称と各言語ごとの内容です。
識別名称はこのあとクラスモジュールに文字列型パラメータの名称として使います。
言語については横方向に列挙します。
また、テーブル化しておくと以降のコーディングがしやすくなります。

## クラスモジュールに単語を格納するプロパティを追加する

~~~vba:textResCls
Public TXT_HELLO As String
~~~
新規にクラスモジュールを作成し、シートに記載した識別名称を使って文字列型プロパティを定義します。
このクラスモジュールではプロパティの定義のみ行います。

## CallByName関数を使い、指定された言語の文字列をプロパティに格納する

~~~vba:標準モジュール
'言語設定(読み出し列)
Const LANG_JA As Integer = 2
Const LANG_EN As Integer = 3

'テキストリソースオブジェクト
Public TXT_RES As New textResCls


Public Sub LoadTextResource()

    textValues = ThisWorkbook.Sheets("言語").Range("言語テーブル").Value

    For idx = LBound(textValues) To UBound(textValues)
        '指定された言語の文字列をテキストリソースオブジェクトに格納
        CallByName TXT_RES, textValues(idx, 1), VbLet, CStr(textValues(idx, LANG_JA))
    Next idx

End Sub
~~~
言語テーブルから対応した内容を取得します。
CallByName関数を使い、クラスオブジェクトの対応するプロパティに文字列を設定していきます。
言語を切り替える場合は読み出し列の定義を変えます。
上記では固定になっていますが、可変にしてリスト等から選べるようにすることもできます。


## クラスモジュールに格納された文字列を使用する

~~~vba:UserForm
Private Sub UserForm_Initialize()

    'テキスト読み出し
    LoadTextResource
    
    'コントロールに設定
    Label1.Caption = TXT_RES.TXT_HELLO

End Sub
~~~
フォームの初期化タイミングの先頭で文字列の読み出し処理を行います。
その後、ラベルに表示したい文字列を設定しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945532/addd0163-384f-4a44-b860-650de427545d.png)
今は日本語を指定しているので「こんにちは。」と標示されます。
読みだす言語を英語(LANG_EN)に切り替えると英語に登録した文字が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945532/45df7466-308d-491a-b3f1-df56939643ca.png)

単語の追加はシートとクラスモジュールのメンテナンスだけでできます。
プロパティの定義も、シート上でコードを自動的に作れるようにしておくと、定義もコピペですむようになります。（「Public [プロパティのセル番号] As String」で文字列を作成）

ExcelVBAで多言語対応というニッチな機能ですが、こういうやり方もあるということで覚えておいていただければと思います。
【Unity 初心者】SliderのValueがゲーム中に左右入力で動いてしまう。スクリプト上は問題ないのに！

どうもUnity初心者です。初投稿なので、お手柔らかにお願いします。

## 前提1
以下の条件を全て含む。
・アクションゲーム
・AttackやJumpなどをマウスクリック（Button含め）で行うゲーム。
・スクリプト上は問題ない場合。


## 前提2
・以下のゲームのような感じ![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4047458/28ac57d7-c380-4ce2-b317-68e2e10def57.png)

※
①ゲーム全体のCanvas( Screen Space - Overlay かScreen Space - Camera)
➁PlayerのHPバー専用のCanvas( World Space)
③HPバー（Sllider）


## 経緯と不具合
・２Dゲームで、PlayerとEnemyのHPバーを制作中に、以下の不具合が発生。
・Slider（HPバーとして使用）のValueが左右入力で勝手に動いていしまう。しかも、Plaeyrだけでなく、Enemyも。


## 解決
・インスペクター上でSliderコンポーネントのInteractableのチェックを外し、falseに。


## 説明（GPTに聞いた）
【Interactableとは】
・Button・Slider・Toggleなどの各UIパーツごとにあり、そのUIがタッチで反応するかを制御する。

【なぜ interactable = true だと Slider.value が勝手に動くのか】
・前提として、Slider は選択状態だとキーボード入力 or ゲームパッド入力で操作できる。
・interactable = true の場合、Sliderを一度クリックすると、クリックに反応しUIイベントシステムがSliderを選択状態にしてしまう。選択状態になったSliderは、キーボードの左右入力を受け入れ、それに応じて値を変化させてしまうから。

※Sliderをクリックしていない場合でもなる？
・スクリプトの処理やEventSystemの仕様で、クリックしていないアクティブなUI要素が選択状態になってしまう場合があるらしい。（ちなみに私はこのパターン）


【不具合の流れ】
・ゲーム中、Attackなどの動作で画面をクリック　or 意図せずスライダーの部分をクリック→Sliderが選択状態になり、左右のInput入力を受けいれる　→  左右のInput入力でSlider.Valueが動く。

## 余談：　CanvasのGraphic Raycasterについて
【Graphic Raycasterとは】
・Canvas に付いているコンポーネントで、「ユーザーのクリックやタップをUIに届かせるかどうか」を制御する。
・ Interactableは各UIパーツについている。

つまり、CanvasのGraphic Raycasterをインスペクター上でflaseにすれば、UIはクリックに反応しない。 SliderのInteractableよりCanvasのGraphic Raycasterをfalseにした方がいい？

では、上記:point_up:の前提2を例で考えてみる


▶①のCanvasのGraphic Raycasterをfalseにする場合
・これをfalseにすると、ゲーム全体のUIのクリック検出ができないので、私の場合、Buttonがあるから無理。

▶➁のCanvasのGraphic Raycasterをfalseにする場合
・これをfalseにしても、①のCanvasが全体を覆っているのでクリック検出はできる

以上から、今回の例の場合、Graphic Raycasterでは対応できないためSliderのInteractableをfalseにするのが正解。
Athena で Iceberg テーブルを使った基本操作：S3 Table Bucket

## 概要
本記事では、S3 Table Bucket の準備や名前空間の作成、Icebergテーブルの作成、操作について説明します。

1. S3 Table Bucket を作成
2. 名前空間と Iceberg テーブルを作成
3. Lake Formation の設定
4. INSERT クエリでデータを追加
5. テストクエリ 
6. テーブルと S3 Table Bucket の削除

この基本的な使い方を順を追って解説します。

## 1. S3 Table Bucket を作成

Iceberg テーブルで使用する S3 Table Bucket は、S3 側で事前に作成する必要があります。

### 作成方法：
- S3 コンソール（UI）から "S3 Table" バケットを作成する
![スクリーンショット 2025-03-27 17.05.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/cfc05fb3-d3ec-4a6f-ba0c-265a7e156fbb.png)




## 2. 名前空間を作成

- S3 Table Bucket を作成した直後に、Athena を使ってデータベースを作成します。
![スクリーンショット 2025-03-27 17.08.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/fa565613-0a9b-408c-b476-480064441e2e.png)
↓
![スクリーンショット 2025-03-27 17.16.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/881ca384-c9d4-4835-b7e8-8b8a6c5c0c86.png)

## 3. Lake Formation の設定

Athena で Iceberg テーブルを操作するには、最初に Lake Formation 側で必要な権限を設定しておく必要があります。これを設定しないと、データベースやテーブルの作成・操作時にエラーが発生します。ここではルートユーザーで設定せずに、IAMユーザーとして設定しましょう。

手順：

Lake Formation コンソール > Databases >に移動します。
![スクリーンショット 2025-03-27 17.17.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/deb452a4-b369-4f29-a1c5-6f71aa673a09.png)
データベースを開き、「Grant」を選択します。
![スクリーンショット 2025-03-27 17.18.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/6ee8a2a5-85ec-436d-b1c7-8aebb72ab161.png)
対象の IAM ユーザーまたはロールに任意の権限を付与します。
![スクリーンショット 2025-03-27 17.22.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/6b64aad3-e810-4a50-9b82-61cf963f5d9d.png)





## 3. Iceberg テーブルを作成

```sql
CREATE TABLE `my_iceberg_table`.daily_sales (
    sale_date date, 
    product_category string, 
    sales_amount double
)
PARTITIONED BY (month(sale_date))
TBLPROPERTIES ('table_type' = 'iceberg');
```
![スクリーンショット 2025-03-27 17.21.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/34517b17-6f54-4f9d-8cc0-d453244ab53b.png)

## 4. データの追加（INSERT）

```sql
INSERT INTO my_iceberg_table.daily_sales
VALUES
    (DATE '2024-12-01', '家電', 1000.50),
    (DATE '2024-12-02', '食料品', 300.00),
    (DATE '2025-01-05', '衣料品', 250.25);
```


## 5. お試しクエリ

```sql
SELECT
  DATE_TRUNC('month', sale_date) AS sale_month,
  SUM(sales_amount) AS total_sales
FROM my_iceberg_table.daily_sales
GROUP BY 1
ORDER BY 1;
```
![スクリーンショット 2025-03-27 17.20.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/c7a16e5c-0245-4b6d-aaa7-2211a618c8b9.png)

## 6. テーブルの削除

### Iceberg テーブルの削除

```sql
--IAMロールで
DROP TABLE IF EXISTS my_iceberg_table.daily_sales;
```


## おわりに

- Iceberg + Athena の基本的な流れを掴むには、まず S3 側の準備（S3 Table Bucket）と権限設定を理解することが重要
- 特に Lake Formation との連携は、想定外の権限制限によりエラーの原因となるため注意
- 小規模な検証から始めて、段階的に構築していくのがおすすめです!
#7 Next.jsのバージョンアップを14から15にアップデートしたら、serverActions.bodySizeLimitの設定が適用されなかった話

# はじめに

社内で開発中のWebシステムの大規模改修にあわせてNext.jsのバージョンアップを行いました。その際、SeverActionによるファイルのアップロードに1MBのサイズ制限がかかるようになり、その解決に少々時間を要しましたので対応内容を共有したいと思います。

# 発生した問題

Next.jsのバージョンを14から15にあげた時点から、ファイルのアップロード機能が1MBのサイズ制限にひっかかる現象が発生しました。以下エラー内容です。

> uncaughtException: [Error: Body exceeded 1 MB limit.
> To configure the body size limit for Server Actions, see: https://nextjs.org/docs/app/api-reference/next-config-js/serverActions#bodysizelimit] {
> statusCode: 413

上記エラー内容に出力されているURLには、next.config.jsに以下の設定を追加すればサイズ制限を拡張できると記載されていました。

``` next.config.js
const nextConfig = {
  experimental: {
    serverActions: {
      bodySizeLimit: "5mb",
    },
  },
}

module.exports = nextConfig;
```

https://nextjs.org/docs/app/api-reference/config/next-config-js/serverActions#bodysizelimit

ローカル環境で動作確認した際は問題なく動作したのですが、dockerコンテナとしてAWSのECSにデプロイすると設定が効いていないのか1MBの制限にかかってしまいました。

# 対応

結論、Next.jsのStandaloneモードでビルドすることで、問題が解消されました。

https://nextjs.org/docs/pages/api-reference/config/next-config-js/output#automatically-copying-traced-files

以下のページをみて、アプリが動作するためのファイルが.next/standaloneにすべて含まれるようになるということだったので、bodySizeLimitの設定そこに含まれるのではないかと考え、試してみたところうまく動作しました。

https://zenn.dev/team_zenn/articles/nextjs-standalone-mode-cloudrun

また副次的な効果として、Dockerイメージのサイズが1G強から100MB程度まで減りました。画面の動作も軽くなったような気がします。

Dockerfileは以下のように修正しています。

## 修正前のDockerfile

``` Dockerfile
# 依存パッケージインストールのレイヤー
FROM public.ecr.aws/docker/library/node:22.14.0-alpine AS deps
WORKDIR /app
COPY package*.json ./
COPY prisma ./prisma/
RUN npm ci --omit=dev

# Build環境のレイヤー
FROM public.ecr.aws/docker/library/node:22.14.0-alpine as builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npx prisma generate
ENV GENERATE_SOURCEMAP false
RUN NODE_OPTIONS=--max-old-space-size=4096 npm run build

# 実行環境のレイヤー
FROM public.ecr.aws/docker/library/node:22.14.0-alpine as runner
WORKDIR /app
ENV NODE_ENV production
ENV DATABASE_URL xxxxx
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
EXPOSE 3000
CMD [ "node_modules/.bin/next", "start" ]
```

## 修正後のDockerfile

``` Dockerfile

# Build環境のレイヤー
FROM public.ecr.aws/docker/library/node:22.14.0-alpine as builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npx prisma generate
ENV GENERATE_SOURCEMAP false
RUN NODE_OPTIONS=--max-old-space-size=4096 npm run build

# 実行環境のレイヤー
FROM public.ecr.aws/docker/library/node:22.14.0-alpine as runner
WORKDIR /app
ENV NODE_ENV production
ENV DATABASE_URL xxxxx
COPY --from=builder /app/public ./public
COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/.next/standalone ./
EXPOSE 3000
CMD [ "node", "server.js" ]
```

そもそもなぜserverActions.bodySizeLimitの設定が効かなかったのか、など理解が追いついていないところがありますが、取り急ぎ記事にします。
CloudRunデプロイ時にterminated: Application failed to start: failed to load /usr/local/bin/docker-entrypoint.sh: exec format errorが発生する

## 背景

Next.jsとSupabaseを使用したウェブアプリケーションをCloud Runにデプロイする際に遭遇した課題について共有します。

**端末：MacBook Pro M2 Max**

## 課題

手元で`docker build`・`docker push`・`gcloud run deploy`コマンドを実行しCloudRun上でリビジョンの作成まで完了するがトラフィックのルーティングが失敗してしました。

logを確認すると下記のエラーが表示されました。
```
ERROR 2025-22-33T04:43:28.073035984Z terminated: Application failed to start: failed to load /usr/local/bin/docker-entrypoint.sh: exec format error
```

## 解決策
`docker build`コマンドに`--platform linux/amd64`でプラットフォームを指定

実際のコマンド
```sh
$ docker build --platform linux/amd64 -t asia-northeast1-docker.pkg.dev/hoge/bar/foo-app:latest .
```

## 学び/ポイント

### アーキテクチャの違い
mac側でARM、CloudRunではLinuxでアーキテクチャに差分があったことが原因でした。
Dockerはデフォルトで実行された環境のアーキテクチャに応じてイメージを作成するため、アーキテクチャが異なるCloudRunにあげるとうまく動かなかったです。

そのため、**Apple SiliconのMacBook**を使用している場合は明示的に`platform linux/amd64`を指定することで、Dockerに対してLinuxのamd64でビルドする必要があります。

### 改善の余地
`platform linux/amd64`を加えることで`docker build`コマンドの時間が8分以上かかるようになってしまいました。（加える前は5分未満で完了した）。



## 参考情報

[Deploy Next.js Supabase App to Cloud Run using Artifact Registry and Secrets Manager](https://dev.to/jamescroissant/deploy-nextjs-supabase-app-to-cloud-run-using-artifact-registry-and-secrets-manager-cm9)
[CloudRunのデプロイに失敗した時のメモ（failed to load /bin/sh: exec format error）](https://zenn.dev/yutan/articles/bc0ef89b15d2ba)
[docker build --platform=linux/amd64 fails: ERROR: failed to solve: no match for platform in manifest](https://stackoverflow.com/questions/76355896/docker-build-platform-linux-amd64-fails-error-failed-to-solve-no-match-for)
【List】要素を結合をスマートに行おう

# 目次
この記事は2分ほどで読めます。
[1. 要素の結合](#1-要素の結合)
[2. 解決方法](#2-解決方法)
[3. 要素を変換してから結合](#3-要素を変換してから結合)

# 1. 要素の結合

- 要素を結合する際に「最後の要素の後にコンマがついてしまうな～」と思ったことはないでしょうか。
```
		List<String> persons = List.of("satoshi", "takeshi", "haruka", "masato");

		for (String person : persons) {
			System.out.print(person + ","); // satoshi,takeshi,haruka,masato, となってしまう！！
		}
```
- これをforループを用いて解決しようとすると少しややこしいコードを書かなければなりません。
```
		for (int i = 0; i < persons.size() - 1; i++) {
			System.out.print(persons.get(i) + ","); // satoshi,takeshi,haruka,
		}

		// 最後の要素を取得
		if (persons.size() > 0) {
			System.out.println(persons.get(persons.size() - 1)); // masato
		}
```
# 2. 解決方法

- 以下のようにするとシンプルに問題解決できます。
```
		System.out.println(String.join(",", persons)); // satoshi,takeshi,haruka,masato
```
- Java8で加わったStringJoinerクラスと、Stringクラスに実装されたjoin()メソッドを使用しましょう。
- join()は裏でStringJoinerクラスを呼び出し、1つ目の引数を区切り値として、2つ目以降の引数として渡された値を統合します。

# 3. 要素を変換してから結合

- さて、単に要素を結合するだけではなく「結合前に何らかの処理をしたい」「要素の絞り込みをした後に結合をしたい」というケースもあると思われます。
- その場合はstreamAPIを使用しましょう。
- 例えば`要素を大文字に変換して結合する`という処理を書いてみましょう。
```
		System.out.println(
			persons.stream()
				   .map(String::toUpperCase)
				   .collect(Collectors.joining(","))); // SATOSHI,TAKESHI,HARUKA,MASATO
```
- map()で変換をし、変換されたリストでcollect()という集約処理を行うメソッドを呼び出しています。
- collect()内でCollectersクラスのjoin()を呼び出します。
<br/>
「ラムダ式やStreamAPI使うの難しそうだし嫌だな～」と思われている方もいらっしゃるかと思います（私もプログラミング初心者の頃は避けてきました笑）<br/>
では従来の方法で、同じ処理を書いて比較してみましょう。

```
		StringBuilder resultBuilder = new StringBuilder();
		for (int i = 0; i < persons.size(); i++) {
			String person = persons.get(i).toUpperCase();
			resultBuilder.append(person);

			if (i < persons.size() - 1) {
				resultBuilder.append(",");
			}
		}

		System.out.println(resultBuilder.toString());
```
- 2つの処理方法をぱっと見比べたときにどちらが可読性が高いでしょうか？
- 大半の人はStreamAPIを使用した方法と答えると思われます。
- またコーディング量も削減できるので良いですね。
(ラムダ式・StreamAPIの解説については今後発信予定です。ぜひ「いいね＆フォロー」してお待ちください！)

- ちなみにcollect()ではなくreduce()を使って今回の処理を記述することも可能です。
```
		System.out.println(
			persons.stream()
				   .map(String::toUpperCase)
				   .reduce((x, y) -> x + "," + y)
				   .orElse(null));
```
- 個人的にはコーディング量的にもcollect()を使う方をおすすめします
<br/>

いかがでしたでしょうか。
ご好評であれば、他にも詰まりそうな点も記事にしていこうと思います。
VSCodeでJavaのフォーマッタを設定する

# はじめに
- VSCodeでJavaのフォーマッタを設定する方法を調べたので、その備忘録。

# 前提
- 以下の拡張機能をインストールしておく。

https://marketplace.visualstudio.com/items?itemName=redhat.java

# VSCodeの設定変更
- ctrl + shit + p で「Preferences: Open User Settings (JSON)」を開く。
- 以下の内容を追記。
```
// ファイル保存時に自動でフォーマットする
"editor.formatOnSave": true,
// ペースト時に自動でフォーマットする
"editor.formatOnPaste": true,
// Javaのファイルのフォーマッタを指定
"[java]": {
  "editor.defaultFormatter": "redhat.java"
},
```
【用語解説】ランタイムという言葉の文脈について

### 実行環境としてのランタイム
・プログラムが実行される際に必要なプログラムやライブラリ群のこと。

### 実行時（ランタイム）とコンパイル時（ビルドタイム）の区別を指したい時
・実際にコード（コンパイルされた後の機械語）を実行するときと、単純にソースコードをコンパイルするときと分けて使う。

主にこのくらいかな....。

### 参考文献（参照日2025年3月28ｎ）

https://mond.how/ja/topics/4c8d22twq65bg9r/ty0ryvw38y5voes

https://www.jstage.jst.go.jp/article/jsaisigtwo/2017/AGI-007/2017_07/_article/-char/ja/
[備忘録]useEffectについて理解する②

以下の記事の続きです。
[\[備忘録\]UseEffectについて理解する①](https://qiita.com/minoura_a/items/11672e54b4424faf1527)

## UseEffectとは

前回の記事で、なんで`useEffect`が必要なのか理解できてきました。
また、レンダリング後にやりたい副作用処理を記述できることを理解しました。
本題の`useEffect`について、もう少し詳しく見ていきます。

基本的な実装は以下です。

```js
import { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    // 副作用処理

    return () => {
      // クリーンアップ処理
    };
  }, []); // 依存配列
}
```

### 依存配列について

依存配列に、副作用処理の中で使用している状態(`state`)やプロパティ(`props`)を指定することで、指定した値が変更されたタイミングで、副作用処理を実行できるようになります。（`state`や`props`と副作用処理を同期できます。）
空の配列を指定した場合は、特に依存する値がないということで、初回レンダリング以降副作用処理が実行されません。

### クリーンアップ関数について

コンポーネントが削除されるタイミングで実行され、副作用で行った処理の後始末を行います。

## コンポーネントのライフサイクルとEffectの関係

Reactのコンポーネントのライフサイクルには以下の3つのフェーズがあります。
- マウント（Mount） → コンポーネントが初めて画面に表示される（コンポーネントが DOMに追加される瞬間にマウントされます。）
- 更新（Update）→ 状態やプロパティが変更される
- アンマウント（Unmount） → コンポーネントが画面から削除される

それに対して、`Effect`は、`props`、`state`などのリアクティブな変数と、副作用との同期の開始と終了のさせ方を決める仕組みを提供しています。

この2つの関係をまとめると、以下のようなよく見る説明になります。
|コンポーネントのライフサイクル|useEffectの書き方|説明(利用例)|
|:-----------|:------------|:------------|
|マウント	|`useEffect(() => {...}, [])`|初回レンダリング後のみ実行（API取得、イベントリスナー追加などに使う）|
|更新|`useEffect(() => {...}, [変数])`|変数が変わるたびに実行(状態が更新されたときの処理)|
|アンマウント|`useEffect(() => { return () => {...}; }, [])`|コンポーネントが削除される前に実行（イベントリスナー削除、タイマー停止などに使う）|

## useEffectが無かったら

関数コンポーネントで`useEffect`を使った場合と使わなかった場合で何がどう変わるかを見てみます。

以下の例では、`Increment`ボタンをクリックして`count`の`state`が更新されるたびに、`Counter`コンポーネントの再レンダリングが走ります。
また、そのレンダリングの度に`user`を取得するためのフェッチが、無駄に走ります。
このように副作用処理をレンダリング中に記載すると、容易に意図しない挙動になります。

```jsx
import { useState } from "react";

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [count, setCount] = useState(0); // user とは関係ない state

  // count が変わるたびに user取得の API リクエストが走ってしまう
  fetch(`https://xxxxxxxxx/users/${userId}`)
    .then((res) => res.json())
    .then((data) => setUser(data));

  return (
    <div>
      <p>{user ? user.name : "Loading..."}</p>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
}
```

今回の場合、`user`の取得のためのフェッチを初回レンダリング後、または、`UserId`が変わったときだけにしたいです。
そのような場合、`useEffect`を利用することで、こういった副作用処理の問題を解決できます。
以下が修正したコードです。

```jsx
import { useState, useEffect } from "react";

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [count, setCount] = useState(0); // user に関係ない state

  useEffect(() => {
    fetch(`https://xxxxxxxxx/users/${userId}`)
      .then((res) => res.json())
      .then((data) => setUser(data));
  }, [userId]); // 初回のレンダリングおよび userId が変わったときだけ実行

  return (
    <div>
      <p>{user ? user.name : "Loading..."}</p>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
```

# さいごに

`useEffect`の超基本でした。
公式ドキュメントには、useEffectの利用方法のアンチパターンも載っていたので、さらにそれも読んで理解を深めたいと思います。

# 参考

https://ja.react.dev/learn/synchronizing-with-effects
https://ja.react.dev/learn/lifecycle-of-reactive-effects#the-lifecycle-of-an-effect
OWASP ZAP webswing / Docker

# 概要
(自分用メモ) OWASP ZAPを使用し接続先サーバの脆弱性診断

# 環境
- Ubuntu 24.04

# 実行
```shell
docker run --rm -v `pwd`:/zap/wrk/:rw -p 8080:8080 -p 8090:8090 -i ghcr.io/zaproxy/zaproxy:stable zap-webswing.sh
```

# GUI起動
`http://localhost:8080/zap/`
明示的に設定しなけれが認証不要。

# Browserのproxy設定
`http://localhost:8090`
※GUI起動後、`./zap_root_ca.cer`が(なければ)生成される。それを信頼できるRootCAとして登録



# 参考文献

https://qiita.com/Shcb8Qyoj021/items/8da1a7663b77c7f5dad4
１１１

Option Explicit

Sub ProcessExcelFiles()
    Dim objExcel As Variant
    Dim objWorkbook9 As Variant
    Dim objWorkbook As Variant
    Dim objSheet As Variant
    Dim objFSO As Variant
    Dim objFolder As Variant
    Dim objFile As Variant
    Dim lastRow As Integer
    Dim sourceRange As Variant
    Dim targetSheet As Variant
    Dim targetRow As Integer
    
    ' Excelを起動
    Set objExcel = CreateObject("Excel.Application")
    objExcel.Visible = True ' Excelを表示
    
    ' Excelファイル9を作成
    Set objWorkbook9 = objExcel.Workbooks.Add
    Set targetSheet = objWorkbook9.Sheets(1)
    targetRow = 1 ' 初期行設定
    
    ' フォルダZ内のファイルを処理
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set objFolder = objFSO.GetFolder("C:\Path\To\FolderZ")
    
    For Each objFile In objFolder.Files
        If LCase(Right(objFile.Name, 5)) = ".xlsx" Or LCase(Right(objFile.Name, 4)) = ".xls" Then
            ' Excelファイルを開く
            Set objWorkbook = objExcel.Workbooks.Open(objFile.Path)
            Set objSheet = objWorkbook.Sheets("A")
            
            ' "総計"が含まれる行を特定
            lastRow = FindTotalRow(objSheet)
            
            If lastRow > 2 Then
                ' データをコピー
                Set sourceRange = objSheet.Range(objSheet.Cells(3, 1), objSheet.Cells(lastRow, 20))
                sourceRange.Copy
                targetSheet.Cells(targetRow, 1).PasteSpecial -4163 ' xlPasteValues の代用
                targetRow = targetRow + sourceRange.Rows.Count
            End If
            
            ' ファイルを閉じる
            objWorkbook.Close False
        End If
    Next objFile
    
    ' Excelを保存（必要に応じて変更）
    objWorkbook9.SaveAs "C:\Path\To\FolderZ\Excel9.xlsx"
    objWorkbook9.Close
    objExcel.Quit
    
    ' 後片付け
    Set objWorkbook9 = Nothing
    Set objWorkbook = Nothing
    Set objSheet = Nothing
    Set objFSO = Nothing
    Set objFolder = Nothing
    Set objExcel = Nothing
    
    MsgBox "処理が完了しました。"
End Sub

Function FindTotalRow(objSheet As Variant) As Integer
    Dim i As Integer
    Dim lastRow As Integer
    lastRow = objSheet.Cells(objSheet.Rows.Count, 1).End(-4162).Row ' xlUp の代用
    
    For i = 1 To lastRow
        If objSheet.Cells(i, 1).Value = "総計" Then
            FindTotalRow = i
            Exit Function
        End If
    Next i
    
    FindTotalRow = 0
End Function
よく間違えられる「インタプリタとコンパイラ」

　コンピュータ用語において、インタプリタとコンパイラは以下のように定義されます。

### インタプリタ
ソースコードを読み込み、解釈して実行するもの。  

処理の流れ：  
**コード読み込み → 解釈 → 実行**

### コンパイラ
ソースコードを読み込み、解釈して別の形式（通常は機械語）に変換するもの。  

処理の流れ：  
**コード読み込み → 解釈 → 変換 → 出力ファイル**

インタプリタとコンパイラの分類は、「実行主体の違い」に基づいています。 

- **インタプリタ**: インタプリタが実行を担当します。  
- **コンパイラ**: 出力された実行ファイルが実行を担当します。

|             | インタプリタ | コンパイラ |
|-------------|--------------|------------|
| 出力ファイル | なし         | あり       |
| 実行         | あり         | なし       |

---

## 誤解1: 「インタプリタは機械語で実行される」

　コンピュータは機械語で動くので、コンピュータを動かすには機械語にする必要があるという誤解からきています。
 
　インタプリタは必ずしも機械語に変換して実行するわけではありません。ソースコードをそのまま解釈して実行するインタプリタも存在します。  

**例: bashシェル**  

シェルはインタプリタです。
シェルスクリプトを機械語に変換せず、解釈して実行します。

 

---

## 誤解2: 「Javaはコンパイル言語である」

　インタプリタの一般的な仕組みを説明します。  
 以下の流れで処理が進んでいきます。
 
処理の流れ：  
**コード読み込み → 構文解釈 → 構文木作成 → 中間コード変換 → インタプリタで実行**

Javaの場合：  
- 上記の処理の流れの中間コード変換まで**Javaコンパイラ**はソースコードを中間コード（バイトコード）に変換し、`.jar`ファイルとして出力します。  
- 中間コードの`.jar`ファイルを **Javaランタイム(中間コードインタプリタ)** が実行します。  

インタプリタの処理を中間コード変換部で分離したのがJavaです。
実行はJavaランタイム（インタプリタ）が実行します。
なのでJavaは「インタプリタ言語」に分類されます。


通常のインタプリタ実行時の
**コード読み込み → 構文解釈 → 構文木作成 → 中間コード変換**
が事前に完了していますので通常のインタプリタよりは
処理速度が速くなります。

さらに、実行時にはバイトコードを**JITコンパイル**して機械語に変換し実行することもあります。機械語で実行されますので高速に動作します。
しかし、実行の制御はあくまでインタプリタ（Javaランタイム）です。
なのでJITコンパイルしたとしてもjavaはインタプリタ言語です。



---

## 誤解3:　「Typescriptはインタプリタ言語である」

 　TypescriptはTypescriptからJavascriptへのコンパイル言語です。
 Typescriptが直接は実行されません。
 Typescriptを実行できる処理系(Node.js)もありますが、基本的はコンパイル言語です。
 
高級言語から機械語への変換ではなく、
高級言語から高級言語の変換なのでコンパイルでなくトランスパイルと言われます。

---

## 誤解4: 　「Javascriptは実行速度が速い。だからインタプリタは遅くない」

　JavascriptインタプリタであるV8エンジンは実行直前に総てを機械語に変換してから実行します。機械語ですので実行速度はコンパイル言語に匹敵します。
V8エンジンでの実行速度が速いのです。インタプリタ方式が速いわけではありません。


---

## 誤解5: 　「JITコンパイルしているからインタプリタは遅くない」

　JITコンパイルすることで機械語に変換されて実行されるので
実行時間はコンパイル言語と同じになります。
 
 しかし、コード読み込み、解釈、中間コード変換の処理時間がかかります。
 この時間は０にはならないので、総実行時間を比較するとコンパイル言語よりはトータル時間は遅くなります。
 実行速度の比較ではインタプリタ言語はコンパイル言語よりも原理的に遅くなります。
 
 ---

## 誤解6: 　「インタプリタ言語とコンパイル言語の区別は意味がない」

　インタプリタ言語とコンパイル言語は実行主体の違いでの分類です。
 区別に意味はあります。
 
 　JITコンパイルが導入されたことでインタプリタ言語とコンパイル言語の処理系における技術はほぼ同じものが使われます。
 現代ではインタプリタとコンパイラの技術的差異はありません。

 ---

## 誤解7: 　「インタプリタは一行毎、コンパイラは事前に一括」

というような意味ではありません。

---
  
  
  
以上　よく間違えられるインタプリタとコンパイラでした。  



### 参考資料

https://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%97%E3%83%AA%E3%82%BF
 
https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9
【JS】MutationObserverで監視設定する

**背景**
編集画面で変えたものを確認画面で反映するには、よくイベントリスナーを使っているが、実はリソースの消費がより抑えられる効率的なもう一つの方法がある。

**説明**
``MutationObserver``はDOMの変更をリアルタイムで監視するAPIである。
DOM変更が発生すると、自動的にコールバック関数（下記の例では``observer``）が呼び出され、変更の詳細は``mutationsList``に渡される。詳細によって処理が分かれる。

``observe()``はリアルタイム監視を可能にする鍵で、どの要素のどの変更を監視するかを設定できる。
第1引数は監視対象、
第2引数は監視する変更の種類。
【変更の種類】
``childList: true``
子要素の追加/削除を監視
``subtree: true``
全ての子孫要素の変更を監視
``attributes: true``
属性の変更を監視
など…
```javascript
    //#editor内のdivの変更を監視する
    const editor = document.getElementById('editor');
    const observer = new MutationObserver(function(mutationsList) {
        mutationsList.forEach(function(mutation) {
        //変更の種類によって処理するなど
        if (mutation.type === 'childList') {
            console.log('子要素が追加/削除されました');
        }
        if (mutation.type === 'attributes') {
            console.log('属性が変更されました');
        }
        });
    });

    //observerの監視設定
    observer.observe(editor, { childList: true, subtree: true, attributes: true });

    //必要に応じて監視を停止
    //observer.disconnect();

```
AWS Terraform - WAF で基本はアクセスをブロック、指定のIPアドレスだけを許可する例

# 例

```tf
resource "aws_wafv2_web_acl" "example" {
  name  = "example-waf-acl-name"
  scope = "REGIONAL"

  default_action {
    block {}
  }

  # 設定はてきとう
  visibility_config {
    cloudwatch_metrics_enabled = false
    metric_name                = "example-waf-metric"
    sampled_requests_enabled   = false
  }

  rule {
    name     = "allow-ips-list"
    priority = 1

    action {
      allow {
      }
    }

    statement {
      or_statement {
        statement {
          ip_set_reference_statement {
            arn = <WAFのIPセットのARN>
          }
        }
        statement {
          ip_set_reference_statement {
            arn = <WAFのIPセットのARN>
          }
        }
      }
    }

    # 設定はてきとう
    visibility_config {
      cloudwatch_metrics_enabled = false
      metric_name                = "example-waf-rule-metric"
      sampled_requests_enabled   = false
    }
  }
}
```

# 参考

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# プロフィール・経歴

https://github.com/YumaInaura/YumaInaura
Uithub をヒントにローカルで使えるコード表示ツールを Go で作った


## はじめに

最近、勤務先の支援もあり AI を活用した開発を日常的に行っています。

https://qiita.com/torifukukaiou/items/9ac6c7258c8a1549674a

一方で、テキストエディタはなるべくシンプルに保ちたい気持ちもあり、AI に直接コード補完を任せるのではなく、自分でコードを書いて考える時間も大切にしています。

https://qiita.com/mnishiguchi/items/d67ef4e363e472411b70

そんな中、同僚に教えてもらった [Uithub](https://uithub.com/) という Web サービスがとても便利でした。Git リポジトリ内のディレクトリ構造とファイル内容を AI に扱いやすい形式で表示してくれます。

https://qiita.com/haw_ohnuma/items/3c4f0a764b1cf66bae7b

Uithub のようなツールをローカル環境でも使いたいと思い、自分なりに作ってみました。

https://uithub.com/



---

## シェルスクリプトでの試作

まずはBash スクリプトで Uithub 的な出力を再現してみました。

- Git 管理されているファイルだけを対象にする
- ディレクトリ構造をツリー形式で表示する
- 各ファイルの内容を見やすく出力する（行番号付き）

といったことを実現しています。

詳細は以下の Qiita 記事にまとめています：

https://qiita.com/mnishiguchi/items/af13b34ac636c03d97c5

ある程度満足のいくものができましたが、スクリプトが少し複雑になってきて、保守しにくさを感じるようになりました。テストも書きづらく、ちょっとした変更にも不安が残ります。

---

## Go言語での書き直し

そこで、改めて Go 言語で CLI ツールとして作り直すことにしました。

ちょうどその頃、日頃から愛用しているバージョン管理ツール[asdf](https://github.com/asdf-vm/asdf) が シェルスクリプトから Go に書き直されたことを知りました。たまたま Go を学習中だったこともあり、言語としてGoを選択しました。

CLI フレームワークには、`asdf` でも使われている [urfave/cli/v2](https://github.com/urfave/cli) を採用しました。軽量で直感的な API が特徴で、今回のようなシンプルなツールにはちょうど良い選択肢だと感じています。

ツール名は `uit`としました。  
後付ですが、「Uithub-Inspired Tool」とも読めます。

以下のような機能を備えています：

- Git 管理下のファイルのみを対象に、ディレクトリツリーとファイル内容を表示  
- 各ファイルの内容には行番号を付与  
- バイナリファイルはデフォルトで非表示
- `--max-lines` オプションで、ファイルごとの表示行数を制限  
- `--no-tree` や `--no-content` オプションで、ツリーや内容の表示を省略可能  

GitHub リポジトリはこちら： [mnishiguchi/uit](https://github.com/mnishiguchi/uit)

自分で言うのもなんですが、めっちゃ便利です。

---

## おわりに

自分のために作ったツールですが、もし誰かの役に立つことがあれば嬉しいです。

ツール自体も Go の勉強にもなりましたし、「既存の便利なツールの仕組みをローカルで再現してみる」というのは楽しい学びのあるプロジェクトだと感じました。

好奇心を忘れず、AIを超えていきましょう。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82804/dc1ddba7-ab4c-5e20-1331-143c842be143.jpeg)
![DSC_0082.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82804/f9f1b977-5bc1-4443-9fc1-8351176ee71d.jpeg)

https://www.haw.co.jp/blog/2025/02/10/qiita_advent2024/
レーザー測距センサモジュール VL53L0XをArduinoで使う

STマイクロ社モジュールの使い方備忘録

測定範囲：3～200cm
レーザー：940nm　Class 1

商品情報はこちらから [秋月電子通商のページ](https://akizukidenshi.com/catalog/g/g112590/)
マニュアル(PDF)はこちら [秋月電子通商のマニュアル](https://akizukidenshi.com/goodsaffix/AE-VL53L0X_20180112_01.pdf)

配線は以下の通りです。
No |sensor|arduino
---|---|---
1 赤 |電源3.3～5V| 5V
2 黒 |GND        | GND
3 黄 |SDA I2C data| SDA
4 緑 |SCL I2c clock| SCL
5 青 |Shutdown signal| -
6 紫 |GPIO output| -

![laser_sensor.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2583728/f6bff0a6-5362-4c72-b66e-91e892fddcb4.jpeg)
![Arduino_uno.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2583728/e92e9095-5f14-4274-baff-e0d3b7e20fc3.jpeg)
![Arduino_uno_5V_GND.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2583728/2cb3ad19-ee7d-4c9d-b2df-cc09a7af340d.jpeg)

Arduino IDEを起動する
「ツール」「ボード」でArduino Uno を選択
「ポート」で COM#  (#は数字）を確認

ソフトはpolulu のGithubを利用
[pololu/vl53l0x-arduino](https://github.com/pololu/vl53l0x-arduino)
(*) Arduino IDE versions 1.6 以上

ソフトの準備
1. Githubの上記のサイトで、<> Code を右クリックして Download ZIP で zipファイルを保存
2. Arduino IDEで「スケッチ」「ライブラリを使用」「ライブラリをインストール」でzipファイルを登録
これは、最初の１回目だけでOK
3. 「ファイル」「スケッチの例」「VL53L0X」で「Continuous」を選択
4. 以下のスケッチが表示される
5. startContinuous(100) の100を測定間隔に応じてセットする(100 ms)
6. 必要に応じて、名前をつけてスケッチを保存

``` : VL53L0X sketch example
#include <Wire.h>  / I2C library
#include <VL53L0X.h> / VL53L0X library

VL53L0X sensor;

void setup()
{
  Serial.begin(9600); / connection rate 9600 bps
  Wire.begin(); / I2C start

  sensor.setTimeout(500); 500ms time-out
  if (!sensor.init())
  {
    Serial.println("Failed to detect and initialize sensor!");
    while (1) {}
  }

  // set time interval in millisecond
  sensor.startContinuous(100);
}

void loop()
{
  Serial.print(sensor.readRangeContinuousMillimeters());
  if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }

  Serial.println();
}
```
「ㇾ」をクリックで検証（コンパイル）
「⇒」をクリックで検証＋マイコンボード書き込み

「ツール」「シリアルモニタ」で出力表示(単位：mm)

シリアルモニタではなく、Tera Term で読み込む場合
1. Tera Term を起動
2. 「TCP/IP」　ではなく　「シリアル」を選択
3.  ポート番号を確認して、「OK]をクリック
4. 出力表示（単位：mm）を確認

以上
Ruby Rails 時間を操れるgem Timecopの導入と活用法

ECサイトの開発では、「購入時刻の処理が正しく動いているか？」をテストする場面が多くあります。  
たとえば、以下のようなケースです。  

- 予約販売の商品が、指定の時間より前に購入できてしまわないか？  
- タイムセールの終了時刻を過ぎても割引が適用されていないか？  
- 一定期間内の購入回数をカウントするロジックが正しく機能しているか？  

こうしたテストを行う際、いちいちシステム時刻を変更するのは現実的ではありません。  
そこで便利なのが **Timecop** というgemです。  

## **Timecopの導入方法**  

まず、`Gemfile` に以下を追加し、`bundle install` を実行します。  

```ruby
group :test do
  gem 'timecop'
end
```

## **Timecopの基本的な使い方**  

### **時刻を固定する (`Timecop.freeze`)**  

```ruby
require 'timecop'

Timecop.freeze(Time.local(2025, 1, 1, 12, 0, 0)) do
  puts Time.now  # => 2025-01-01 12:00:00
end

puts Time.now  # 実際の現在時刻が表示される
```

### **過去や未来にジャンプする (`Timecop.travel`)**  

```ruby
Timecop.travel(Time.local(2025, 12, 31)) do
  puts Time.now  # => 2025-12-31 00:00:00
end
```

### **時の流れを遅くする (`Timecop.scale`)**  

```ruby
Timecop.scale(3600)  # 1秒が1時間に相当するスピードで時間が進む
```

## **ECの購入時刻のテストにTimecopを活用する**  

例えば、**「午前10時～11時限定のタイムセール」** のロジックが正しく動作するかテストしたい場合、以下のように実装できます。  

```ruby
describe 'タイムセールの価格適用' do
  it '10:00〜10:59の間は割引価格になる' do
    Timecop.freeze(Time.local(2025, 1, 1, 10, 30)) do
      product = Product.find(1)
      expect(product.discounted_price).to eq(500) # 割引価格
    end
  end

  it '11:00以降は通常価格に戻る' do
    Timecop.freeze(Time.local(2025, 1, 1, 11, 0)) do
      product = Product.find(1)
      expect(product.discounted_price).to eq(1000) # 通常価格
    end
  end
end
```

## **Timecopを使う際の注意点**  

- `Timecop.freeze` を使ったら、`ensure` ブロックで `Timecop.return` を呼ぶか、ブロック内で使う  
- `Time.now` を直接参照するコードでのみ有効（外部APIのタイムスタンプには影響なし）  

## **まとめ**  

EC開発では、購入時刻に関するテストが重要になります。  
**Timecopを使えば、自由に時間を操りながら簡単にテストを実装できる** ので、ぜひ活用してみてください！
Google Cloudのプロジェクト間でPubSubトピックを送信するときにハマったこと

今回は、Google Cloudのプロジェクト間でPubSubトピックを送信できるかを検証した際、別プロジェクトのPubSubトピックが表示されない問題に直面しました。  

結論として、ログシンク作成時に同一組織内であっても別プロジェクトのPubSubトピックは自動表示されず、手動で設定する必要があることが分かりました。

## 概要

前回の実装（[Cloud Buildのデプロイ失敗をDiscordに通知する仕組みを構築する](https://qiita.com/hrfm1623/items/784799905edb35dfec19)）では、通知用のコンテナを各環境ごとに用意していました。  
しかし、dev、stg、prdと分ける必要性を感じなかったため、今回は**あるプロジェクト（prd）から別のプロジェクト（dev）へ、PubSubトピックを介して特定のログを送信する仕組み**を試してみました。

## 実装手順

1. **ロギング** → **ログルーター** → **シンクを作成**
2. シンク作成画面で、**Pub/Subトピック**を選択し、`"トピックを手動で入力"`を選びます。  
   ![スクリーンショット 2025-03-28 12.19.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939741/d7bdf165-4640-49f2-808e-1d4fd22b3b5f.png)
3. 手動入力欄に、通知を担当するCloud Run関数にトリガーしてあるPub/Subトピックから**トピック名**（**完全なリソースID**)をコピーして貼り付け、保存します。  
   ![スクリーンショット 2025-03-28 12.21.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939741/c78d4264-26b1-4691-a668-1fa9084b7648.png)  
   ![スクリーンショット 2025-03-28 12.52.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939741/8bd80840-5289-4e48-8fea-d7deacfe8ddb.png)

以上で設定は完了です。

## まとめ

今回の実験により、Google Cloudのプロジェクト間でもPubSubトピックを介して通知連携が可能であることが確認できました。  
この検証結果を活かし、今後は組織内のデプロイ通知のグループ化など、さらなるシステム運用の効率化を目指していきたいと考えています。  

フィードバックやご意見がありましたら、ぜひコメントでお知らせください！
【ChatGPT＋4o Image Generation】による画像内に、別の画像をはめ込む方法です。


　どうも、カーブミラーです。

　今回は、4o Image Generationによる画像内に、別の画像をはめ込む方法です。

:::note info
本記事は、ChatGPT（Plus版）
で行なっております。
画像はあります。　あしからず。
:::
　ChatGPT等の動作状況を知らせる
　　OpenAIのステータスページ。
　　　[OpenAIステータス](https://status.openai.com/)
***
　こちらも載せますね。
　　[ChatGPTが使えない？ログインできない・反応しない原因やエラー時の対処法を解説](https://aismiley.co.jp/ai_news/chatgpt-error-resolution-explanation/)
***
　まずは、ニュースです。

　サムから悲鳴😅
　　[サム・アルトマンポスト](https://x.com/sama/status/1905296867145154688?t=fn1fJyK01GFSdvA1isdZmQ&s=19)
***（ChatGPT翻訳）***
ChatGPTで画像を楽しんでくれている人たちを見るのは、本当に楽しいです。

でも、GPUが溶けそうです。

そのため、効率を上げるための対応をしている間、一時的に利用制限を導入する予定です。長くはかからない見込みです！

ChatGPTの無料プランでは、まもなく1日あたり3回まで画像生成が可能になります。

（それと、許可されるべき画像生成が拒否されてしまうケースもあり、それについても急いで修正中です）
***
　次に
　　OpenAIからポストが
　　　ありました。

　[OpenAI公式ポスト](https://x.com/OpenAI/status/1905331956856050135?t=hS7YO61PIpDSvZq2U0ieyw&s=19)
***（ChatGPT翻訳）***
ChatGPTのGPT-4oに新たなアップデートが登場！

何が変わったの？

複雑で複数のリクエストが含まれるプロンプトへの対応力が向上

高度な技術的・プログラミング関連の問題への対応力が強化

直感力と創造性がより優れたものに

絵文字の使用が控えめに（たとえば、こういうの 🙃 が減少）


この最新版のGPT-4oは有料ユーザー全員がすぐに利用可能で、無料ユーザーにも今後数週間かけて順次提供される予定です。
***
　では、【本題】です。

　今回は、
　　4o Image Generationによる
　　　画像内に、別の画像を
　　　　はめ込む方法です。

　新しい画像生成である
　　4o Image Generationの反響は
　　　とても多く、そのすべてを
　　　　チェックはできません。

　昨日（2025/03/27）は
　　そこまでに知り得た使い方を
　　　取り上げただけでした。

　あれからも
　　使い道が出てきています。
***
　今日は、
　　DALL-E3とCode Interpreterを
　　　使わねば、難しかった
　　　　画像内に、画像をはめ込む
　　　　　ことをしてみようと思います｡

　こんなふうになります。
![ChatGPT Image 2025年3月27日 10_05_18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/d0829c62-9d6f-4169-8888-fc50ba5af7e0.png)


　手順は次のとおり
　❶GPT-4oモデルであることを確認
　❷これまで通りに、Promptを入力
　　　まだ送信しない。
　❸下記Promptを追記入力
```Text:追記Prompt
スマホ画面には画像をはめ込んで。
```
　❹はめ込む画像をアップロード
　❺送信する

　これで描画されます。

　なお、はめ込む場所が
　　スマホ以外であれば、
　　　そう記述してください。

　　テレビ画面とか
　　　ホワイトボードとかですね。

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。