OmniAICreator/Qiita-1.07M huggingface dataset:
機器の設置場所不明な機器を、macaddressで追いかける。

# 概要
ネットワークの仕事をしていると、このIPアドレスを持っている機器がどこにいるのかわからない。。という場面に何回か出くわすことがある。そういった際に、ある程度絞り込むための方法をここに記載する。

# 手順

## 1. pingを飛ばし、ARPを確認

同一セグメントのIPアドレスを持つサーバから、pingを実行する。
```
ping x.x.x.x
```
その後、以下のコマンドで、MACアドレスを確認する。
```
ip n | grep x.x.x
```
すると、以下のような形でMACアドレスを確認することができる。
応答があるものは、REACHABLEかSTALEになっているはずである。
```
x.x.x.x dev eno1 lladdr f0:1c:2d:6e:9a:30 REACHABLE
x.x.x.y dev eno1 lladdr 00:0c:29:e5:47:93 STALE
```

## 2. pingの実行元のサーバが物理的につながっているL2スイッチのMACアドレステーブルを確認

上記の例だと、eno1が繋がっている先のL2スイッチで、MACアドレステーブルを確認する。コマンドは機器のベンダー毎に異なる可能性があるため、都度確認すること。
```
show mac-address
```

```:実行結果
test-envsw# show mac-address

 Status and Counters - Port Address Table

  MAC Address   Located on Port
  ------------- ---------------
  2129d31-c3xxxx Trk1
  345d991-yyyyyy Trk1
  4f5c291-zzzzzz Trk1
略
```

そして、pingを打った時の`ip n`のMACアドレスと同じ内容を、上記のコマンド結果から探し、どのポートに流れたかを確認する。
*ここではトランクポートを表す、Trk1に渡されているものとする。
Trk1が繋がっている先のL2スイッチを探し、再度同じようにMACアドレステーブルを確認する。

# 3. 2を繰り返し、最終的につながっているL2スイッチを探す。

2を繰り返していると、最終的にあるL2スイッチのポート番号にたどり着く。
そのポート番号の先に、該当のIPアドレスを持つ機器が存在する。
ポート番号のdescriptionなどを確認し、どういった機器なのかを判別させる。

# 4.仮想マシンの場合

中に入っている機器が、仮想マシンの場合は、仮想ホストからmacアドレスを割り当てる必要が出てくる。
Linux KVMであれば、
```
 ip link show master ブリッジ名
```
など、
VmwareEsxiであれば、
管理GUIの中の、vswitchに存在するMACアドレスなど。
から確認していく。

# 余談
MACアドレスは、ベンダ毎に識別子が決まっているため、MACアドレスをインターネットで検索すれば、捜索対象の機器のベンダー名が確認できる。
これがわかれば、捜索のための手がかりを増やすことも可能だ。


https://www.bing.com/search?q=macaddress+%E3%83%99%E3%83%B3%E3%83%80%E3%83%BC%E3%82%B3%E3%83%BC%E3%83%89&form=ANNH01&refig=c392077af7c44c2593d127753f183b72&pc=HCTS&pqlth=10&assgl=18&sgcn=macaddress+%E3%83%99%E3%83%B3%E3%83%80%E3%83%BC%E3%82%B3%E3%83%BC%E3%83%89&smvpcn=0&swbcn=6&sctcn=0&cvid=c392077af7c44c2593d127753f183b72&kpratsg=1&hsmssg=0
Nginx⑦静的キャッシュの設定

## はじめに
Nginxを使用した静的キャッシュの設定をローカル環境で手軽に体感することを目的としておりますので、Nginxに初めて触れる方向けの内容となっております。

## キャッシュとは
同じアクションを高速化するために、ソフトウェアなどで取り扱うデータを一時的に保存する仕組みのことです

## 静的キャッシュとは
サーバーやブラウザが静的コンテンツ（画像、CSS、JavaScriptなど）をキャッシュする手法です

## 環境
- Ubuntu 24.04
- nginx-1.26.3
- 推奨される設定状態
  - `sites-available`と`sites-enabled`ディレクトリが存在する
  - `/etc/nginx/sites-enabled/`内の設定ファイルがNginxの設定に組み込まれている
  - 静的ファイルが存在する

下記のサイトで上記のような環境にする方法が記載されております。

https://qiita.com/myaX/items/4212e8899a39e6800414

https://qiita.com/myaX/items/527ad2a7b02488aad454

## 手順1：プロキシキャッシュの設定
```conf:/etc/nginx/sites-available/normal
server {
    listen 80;
    server_name localhost;

    # リクエストされた際にドキュメントがある場所
    root /path/to/static/files;
    index index.html;

    location ~ .*\.(html|jpg|gif|png|css|js) {
            expires 30d;
    }

    location / {
        try_files $uri $uri/ =404;
    }
}
```
- `location ~ .*\.(html|jpg|gif|png|css|js)`
  - `html`、`jpg`、`gif`、`png`、`css`、`js`の拡張子を持つリクエストに対して適用される`location`ブロックを定義しています
- `expires 30d;`
  - キャッシュを 30日間 ブラウザに保持させます（パフォーマンス向上）

### 静的キャッシュにおける注意点
動的コンテンツには`Expires`を設定しないでください。理由は、アクセスのたびに内容が変わる性質があり、`Expires`を設定すると最新の情報が正しく表示されなくなってしまうからです。

## 手順2：sites-enabled/にシンボリックリンクを作成
```
sudo ln -s /etc/nginx/sites-available/normal /etc/nginx/sites-enabled/
```

## 手順3：設定の反映
```
sudo systemctl reload nginx
```

## 手順4：キャッシュの状態を確認する方法
1. `http://localhost:80`にアクセスし、開発者ツールを開きます。
2. ネットワークタブを選択します
3. キャッシュ対象のリクエストを選択して、`レスポンス ヘッダー`の`Expires`が表示されるので、キャッシュの状態(例:`Sun, 06 Apr 2025 06:21:12 GMT`)を確認します

## まとめ
以上で、静的キャッシュの設定ができました。
Nginx⑥プロキシキャッシュの設定

## はじめに
Nginxを使用したプロキシキャッシュの設定をローカル環境で手軽に体感することを目的としておりますので、Nginxに初めて触れる方向けの内容となっております。

## キャッシュとは
同じアクションを高速化するために、ソフトウェアなどで取り扱うデータを一時的に保存する仕組みのことです

## プロキシキャッシュとは
Nginxなどのプロキシサーバが動的コンテンツやバックエンドのレスポンスをキャッシュする手法です

## 環境
- Ubuntu 24.04
- nginx-1.26.3
- 推奨される設定状態
  - `sites-available`と`sites-enabled`ディレクトリが存在する
  - `/etc/nginx/sites-enabled/`内の設定ファイルがNginxの設定に組み込まれている
  - 静的ファイルが存在する

下記のサイトで上記のような環境にする方法が記載されております。

https://qiita.com/myaX/items/4212e8899a39e6800414

https://qiita.com/myaX/items/527ad2a7b02488aad454

## 手順1：プロキシキャッシュの設定
下記のコードを`nginx.conf`に追加します。
```conf:/etc/nginx/nginx.conf
http {
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m use_temp_path=off;
}
```
- `/var/cache/nginx`
  - キャッシュデータが保存されるディレクトリのパスです
- `levels=1:2`
  - キャッシュファイルをディレクトリツリー内で保存する方法です。1:2は、1階層目に1文字、2階層目に2文字のサブディレクトリを作ることを意味します。これによりファイルシステムのパフォーマンスが向上します
- `keys_zone=my_cache:10m`
  - キャッシュキーを格納するメモリ領域の名前を`my_cache`、サイズを10MBに設定しています
- `max_size=1g`
  - キャッシュの最大サイズを1GBに制限しています。1GBを超えると古いキャッシュから順に削除されます
- `inactive=60m`
  - キャッシュが60分間使用されなかった場合、キャッシュが削除されます。つまり、最後にアクセスされてから60分経過すると、そのキャッシュは無効化されます
- `use_temp_path=off`
  - 一時的なファイルの保存を無効化します。これにより、キャッシュデータは直接`/var/cache/nginx`に保存されます

```conf:/etc/nginx/sites-available/proxy_cache.conf
server {
        listen 8080;
        server_name localhost;

        location / {
                proxy_pass http://localhost:80;
                proxy_cache my_cache;
                proxy_cache_valid 200 302 10m;
                proxy_cache_valid 404 1m;
                add_header X-Cache $upstream_cache_status;
        }
}
```
- `proxy_cache my_cache;`
  - `my_cache`という名前のキャッシュゾーンを使用してバックエンドからのレスポンスをキャッシュします
- `proxy_cache_valid 200 302 10m;`
  - 200と302ステータスコードのレスポンスを10分間キャッシュします
- `proxy_cache_valid 404 1m;`
  - 404ステータスコードのレスポンスを1分間キャッシュします
- `add_header X-Cache $upstream_cache_status;`
  - キャッシュの状態をX-Cacheヘッダーに追加します

```conf:/etc/nginx/sites-available/normal
server {
    listen 80;
    server_name localhost;

    # リクエストされた際にドキュメントがある場所
    root /path/to/static/files;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}
```

## 手順2：sites-enabled/にシンボリックリンクを作成
```
sudo ln -s /etc/nginx/sites-available/normal /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/proxy_cache.conf /etc/nginx/sites-enabled/
```

## 手順3：設定の反映
```
sudo systemctl reload nginx
```

## 手順4：キャッシュの状態を確認する方法
1. `http://localhost:8080`にアクセスし、開発者ツールを開きます。
2. ネットワークタブを選択します
3. 再度ページをリロードします
4. キャッシュ対象のリクエストを選択して、`レスポンス ヘッダー`の`X-Cache`ヘッダーが表示されるので、キャッシュの状態(例:`HIT`)を確認します

### `X-Cache`の状態
- `HIT`
  - キャッシュからレスポンスを返した場合
- `MISS`
  - キャッシュが存在しなかった場合（初回リクエストなど）
- `BYPASS`
  - キャッシュがバイパスされた場合（例えば、キャッシュ無効化設定が適用された場合）
- `EXPIRED`
  - キャッシュが期限切れになり、バックエンドから新たにレスポンスを取得した場合

## まとめ
以上で、プロキシキャッシュの設定ができました。
SnowProのバッジをLinkedInに反映させる方法

完全に自分用メモです。
SnowPro Coreのバッジが反映されているのに、今回やり方わからなくなりました。
なんとかできましたが、次もわからなくなる自信があるので残しておきます。

# certmetrics
これはSnowProの試験を申し込むときに使うサイトですね。
![スクリーンショット 2025-03-07 191943.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487310/ea3401bb-9ac7-4a53-9ae4-b3202745ace1.png)
画面ショットのピンクで囲った部分です。
左のメニューの「ACCREDIBLE - DEGITAL BADGE」 ⇒ 「Accredible Sign In」
を選んでメイン画面の「CLICK TO GO TO ACCREDIBLE」をクリックします。

# ACCREDIBLE
![スクリーンショット 2025-03-07 192236.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487310/c9a4189e-59e7-4b29-9e74-2fac4acfa073.png)
WalletタブにSnowProバッジが表示されます。
ピンクで囲った「Share」をクリックします。

![スクリーンショット 2025-03-07 192325.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487310/f961151d-89e3-4bb2-b509-c126731a9be4.png)
こんな画面が上がってきます。
facebookとかXとかといっしょに並んでいるアイコンは無視しましょう。

その下にあるピンクで囲ったLinkedInのボタン「Add to my profile」をクリックします。

# LinkedIn
![スクリーンショット 2025-03-07 192447.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487310/556d93d1-b18f-4bff-903e-aa4be174915d.png)
するとLinkedInの画面に移ってきまして、「資格を追加」という画面になります。
右下の「保存」ボタンを押します。

これでSnowProのバッジをLinkedInに反映させることができました。

# 意気込み
ここで手順を残してもWeb画面なんてすぐ変わりそうですが、変わる前に次のAdvanced Data Engineer取りたいです。
シェルピンスキー曲線 Sierpinski Curve

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/b3b56c57-a899-4e5d-9b5c-417782e0e7aa.png)

# はじめに
シェルピンスキー曲線をLシステムを使って描きます。

# 環境
Processing 4

# 生成ルール

https://en.wikipedia.org/wiki/Sierpi%C5%84ski_curve

こちらに準拠しています。

# コード

wikiから取ってきた、ルールの文字列の「-」の文字コードが違っていて、この問題になかなか気がつくことができませんでした。chatGTPにバグ取りお願いしました。
SVGで出力していますが、depthを１段階上げると15倍にデータサイズが増えます。
5で246MB


```java
import processing.svg.*;

int depth = 4; // 再帰の深さ
float length = 200; // 初期の線の長さ
String axiom = "F--XF--F--XF";
String ruleA = "XF+G+XF--F--XF+G+X";
String current;
float angle = radians(45);

void setup() {
  size(500, 500);
  background(255);
  beginRecord(SVG, "filename.svg");

  stroke(0);
  current = axiom;
  for (int i = 0; i < depth; i++) {
    current = generate(current);
  }
  translate(20, 10);
  rotate(angle*3);
  drawLSystem(current, length / pow(2, depth));

  endRecord();
}

String generate(String str) {
  String result = "";
  for (char c : str.toCharArray()) {
    if (c == 'X') {
      result += ruleA;
    } else {
      result += c;
    }
  }
  return result;
}

void drawLSystem(String str, float len) {
  for (char c : str.toCharArray()) {
    if (c == 'F' || c == 'G') {
      line(0, 0, len, 0);
      translate(len, 0);
    } else if (c == '+') {
      rotate(angle);
    } else if (c == '-') {
      rotate(-angle);
    }
  }
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/985e8894-2d74-4136-927e-a9eee29cf607.png)

# 90度のルール

wikiにある以下のルールだと、このような図になります。
```java
axiom = "F+XF+F+XF";
ruleA = "XF-F+F-XF+F+XF-F+F-X";
angle = radians(90);
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/94c3729f-0010-4cbf-b091-71e2108d4115.png)

# Sierpinski Gasketになるルール
ルール文字が２種類
```java
axiom = "A";
ruleA = "B-A-B";
ruleB = "A+B+A";
angle = radians(60);
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/656f774c-c6f4-4423-9716-e1d71830ff58.png)


```java
int depth = 6; // 再帰の深さ
float length = 500; // 初期の線の長さ
String axiom = "A";
String ruleA = "B-A-B";
String ruleB = "A+B+A";
String current;
float angle = radians(60);

void setup() {
  size(550, 500);
  background(255);

  stroke(0);
  current = axiom;
  for (int i = 0; i < depth; i++) {
    current = generate(current);
  }
  translate(20, 10);
  drawLSystem(current, length / pow(2, depth));
}

String generate(String str) {
  String result = "";
  for (char c : str.toCharArray()) {
    if (c == 'A') {
      result += ruleA;
    } else if (c == 'B') {
      result += ruleB;      
    } else {
      result += c;
    }
  }
  return result;
}

void drawLSystem(String str, float len) {
  for (char c : str.toCharArray()) {
    if (c == 'A' || c == 'B') {
      line(0, 0, len, 0);
      translate(len, 0);
    } else if (c == '+') {
      rotate(angle);
    } else if (c == '-') {
      rotate(-angle);
    }
  }
}
```
『Akool』：世界最高峰のフェイススワップ機能が利用できる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4029999/14bead54-ae79-451d-8ba0-73f15c4ab1db.png)


引用：[https://akool.com/](https://akool.com/apps/faceswap?via=jpfswesley)


[AKOOL公式サイト](https://akool.com/apps/faceswap?via=jpfswesley)

[Akool](https://akool.com/apps/faceswap?via=jpfswesley)は、Webブラウザ上で利用できる世界で100万人以上が利用する画像生成AIツールです。





[Akool](https://akool.com/apps/faceswap?via=jpfswesley)の最大の特徴は、「フェイススワップ」機能の精度の高さです。

[Akool](https://akool.com/apps/faceswap?via=jpfswesley)のフェイススワップは、画像や動画に登場する人物の顔を別の人物の顔と入れ替えることができる機能ですが、その精度は他のツールと比べて抜きん出ています。

顔の角度や表情、照明条件などが異なる画像同士でも、違和感なく自然にフェイススワップが可能で、まるで最初からその人物が映っていたかのような仕上がりになります。

そして何より嬉しいのは、Akoolではアカウント登録するだけで、フェイススワップを含む様々な機能を無料で試せることです。

初回ログイン時には50クレジットが付与されるため、その範囲内ですぐにフェイススワップ機能を試すことができます。

フェイススワップ機能を無料で使ってみたい方は、ぜひAkoolを試してみてください。



[AKOOL公式サイト](https://akool.com/apps/faceswap?via=jpfswesley)
歴2ヶ月のエンジニアが個人開発でCI/CDに挑戦した話

## はじめに

初めまして、UX/UIデザイナーとして活動しているKikoといいます。
デザインエンジニアになることを目標に今年の1月からReactの勉強を始めました！

自分の簡単な自己紹介はこちら👇

https://qiita.com/kikotkk/items/b702b6c3a227690eeec6



## 2ヶ月（8週間）でやったこと

最初の3週間はReactで簡易的な学習アプリを作りました。正直ここまではそこまで辛くもなく、、、
ただ、後半の環境構築やCI/CDの構築に5週間もかかりました。これはターミナルコマンドって何？っていうところからのスタートだったので、かなり難しく感じました。

作業工程は以下になります。

1. 学習記録アプリ作成（CSSなしの簡素なもの）
2. Viteで環境構築
3. supabaseでDB設定
4. Firebaseでデプロイ
5. Jestとreact-testing-libraryでテスト作成
6. Github Actionsでパイプライン構築

![study-app (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3977506/05997361-4720-4195-a338-770e826e51e2.gif)


## 迷走の記録
デプロイもテストも大変でしたが、中でもテストに一番苦しみました。
本番環境ではsupabaseの認証がうまくいくのにテスト環境ではエラーになったり（結局はVite環境での環境変数の扱いが原因でした）
Gitの理解が怪しいせいでローカルではない変な場所に環境を作り、リポジトリから作り直したり....
最後のテストがPASSしたときは本当にホッとしました。

![スクリーンショット 2025-03-04 8.55.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3977506/3f19da9a-cdaa-43c4-b230-2715e6cdbebd.png)


## エラーと対策

この課題を進める中で、環境変数やテストの設定に関していくつかのエラーに直面しました。
これらのエラーについては、以下の記事に詳しくまとめています。

https://qiita.com/kikotkk/items/4644dc15c085473744ab

https://qiita.com/kikotkk/items/0691baf6d09e3e4460e3


## 取り組み方について
私は今回がっつりAI（chatGPT4o）を使いましたが、難易度的にAIがなければ難しかったと思います。
React専用のGPTsを作って、毎日キャンバスに学習内容をまとめていました。
![スクリーンショット 2025-03-06 8.30.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3977506/ec448a25-99e6-4749-a758-aba9a0e6c925.png)

しかし、技術的にもモチベーションの維持のためにもAIの補助はマストでしたが、やはり「頼りすぎは良くないから徐々に脱AIしなきゃ」という気持ちになりました。
そこで、console.logを状態変化のある場所に差し込むように習慣づけ、**最低でも仮説を自分の中でまとめてからAIへ尋ねるように**しました。

そうすると少しずつAIに丸投げではなく、「自分の仮説が妥当なのか」「進め方はこれであっているのか」という抽象的な質問へシフトしていき、最終的にAIとの付き合い方も変わっていきました。（皆目検討がつかないものは仮説の洗い出しからAIに投げてOKで進めましたが）
それでも無理な場合はJISOUのエンジニアさんに質問しました。

## Next Step
- JapvascriptからTypescriptに移行してリライトする
- 自分の作りたいアプリの像を詰めていく





## JISOUのメンバー募集中！
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？
興味のある方は、ぜひホームページをのぞいてみてください！

https://projisou.jp/
Windows環境で「python3」コマンドを使うには？バッチファイルでエイリアスを作成する方法

# はじめに
Windowsでは、公式インストーラを使ってPythonを導入しても、**「python3」** コマンドが標準で設定されていない場合が多いです。
そのため、ネット上の何らかの手順で見かける `python3 -m pip install <パッケージ>` が通らずに戸惑うこともあるでしょう。

本記事では、
- **「python3」コマンドが使えない理由**
- **代わりに推奨される呼び出し方 (`py -3` / `python`)**
- **どうしても「python3」で呼び出したい場合のバッチファイル活用術**

について紹介します。

## Windowsで「python3」がデフォルトでは存在しない理由
Windowsでは、Python公式インストーラを使用してPython 3をインストールしても、パスに登録されるのは多くの場合
- `python.exe`
- `py.exe`（Pythonランチャー）
だけです。

`python3.exe` が用意されることはあまりありません（Microsoft Store版をインストールした場合は設定次第で存在するケースもあります）。そのため、コマンドプロンプトやPowerShellで `python3` と入力しても「Python」としか言われず、「なんだこれは？」となってしまうわけです。

## 公式に推奨される呼び出し方
### 1. `py -3`
Pythonランチャー (`py.exe`) にバージョン指定を渡すことで、Python 3.x を確実に呼び出す方法です。
たとえば次のようにコマンドを実行できます。

```bash
py -3 --version
```

Python 2系が入っている環境でも、`py -3` ならPython 3系を明示的に起動できます。

### 2. `python`
もしPython 2系をインストールしていないのであれば、`python` と打つだけでもPython 3が呼び出される環境が大半です。

```bash
python --version
```

`python3` ではなく `python` ですが、特に問題がなければそのまま使ってもOKです。

## どうしても「python3」というコマンド名を使いたい場合
とはいえ、他のOS（LinuxやmacOS）に合わせて「python3」コマンドを使いたい場面もあります。そんなときは、**バッチファイル**を使ってエイリアスを作る方法が簡単でおすすめです。

### バッチファイルで「python3」エイリアスを作成する手順
1. **バッチファイルの作成**
   - 任意のテキストエディタで「`python3.bat`」という名前のファイルを作成します。
   - ファイルの中身を以下のように記述しましょう。

     ```bat
     @echo off
     py -3 %*
     ```

2. **環境変数が通ったフォルダに配置**
   - 作成した `python3.bat` を、環境変数の通ったフォルダへ移動します。
     例: `C:\Windows`（管理者権限が必要な場合あり）

3. **動作確認**
   - コマンドプロンプトやPowerShellで `python3 --version` を実行して、Pythonのバージョンが表示されれば成功です。

これでWindows環境でも気軽に `python3` コマンドを使えるようになります。

ぜひ試してみてくださいね。
M5StampS3、スタックチャンで時間を表示する。(SNTP)



注意、いろいろ
----

- 過去ログを見よ!!!
- 3.1.3
- 書き換えてください。


```c++

const char *ssid = "ご自宅のSSID";
const char *password = "ご自宅のパスワード";


```

結果
----

![image_original (54).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/5fdb22a6-425d-4ffe-b95b-affb3f941c51.jpeg)


![image_original (55).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/e3348f05-9cd5-4266-8491-732c587a8c2b.jpeg)


プログラム
----

```c++



//balloon_sntp_1_M5StampS3_2


//インクルド
#include <M5UnitGLASS2.h>
#include <M5Unified.h>
#include <Avatar.h>
#include <WiFi.h>
#include <time.h>


//定義
using namespace m5avatar; //ネームスペース

Avatar avatar; //アバターの実体の定義
const char* lyrics[] = {"今何時","何時カナ","時間"};//ポインター配列
const int lyricsSize = sizeof(lyrics) / sizeof(char*);//配列の個数
int lyricsIdx = 0;//カウンター

#define JST  3600*9

const char *ssid = "ご自宅のSSID";
const char *password = "ご自宅のパスワード";


//初期化
void setup(){

  //WiFiの初期化
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  auto cfg=M5.config();
  cfg.unit_glass2.pin_sda=13;
  cfg.unit_glass2.pin_scl=15;
  M5.begin(cfg);//M5の初期化

  avatar.setScale(.45);
  avatar.setPosition(-88-17,-96);
  avatar.init();//アバターの初期化 (アバターは、バックグランドで動く)

  //avatar.setSpeechFont(&fonts::lgfxJapanGothic_12);//日本語フォント
  avatar.setSpeechFont(&fonts::lgfxJapanGothicP_16);//日本語フォント

  delay(3000);//決め打ちなので、おかしかったら調整してね! wifiの待ち0.5*6

  configTime( JST, 0, "ntp.nict.jp", "ntp.jst.mfeed.ad.jp");

}//setup


//メインループ
void loop(){

  time_t t;      //経過秒
  struct tm *tm; //時間の実体とポインター

  t = time(NULL);     //経過秒を取得する
  tm = localtime(&t); //経過秒を時間の構造体に変換する

  //M5.update(); 
  //if (M5.BtnA.wasPressed()){//ボタンが押された場合

    //lyricsIdx++は、後で1プラスする
    //余りを求める処理は、0から文字列のポインター配列サイズぶん繰り返す
    //「l」に文字列のポインターが入る
    const char* l = lyrics[lyricsIdx++ % lyricsSize];

    avatar.setSpeechText(l); //テキストの表示

    avatar.setExpression(Expression::Happy); //表情を変える

    avatar.setMouthOpenRatio(0.7); //口を動かす

    delay(200);//0.2秒待つ

    avatar.setMouthOpenRatio(0); //口を閉じる

    delay(2000);//1秒待つ

    //時間
    char hh[20];
    sprintf(hh,"%02d:%02d",tm->tm_hour, tm->tm_min);
  
    avatar.setSpeechText(hh); //テキストの表示

    avatar.setMouthOpenRatio(0.7); //口を動かす

    delay(200);//0.2秒待つ

    avatar.setMouthOpenRatio(0); //口を閉じる

  //}//if

  delay(4000);//3秒待つ

}//loop




```
PassitCertifyの学習教材でNetApp NS0-093試験を完全攻略！


NetApp NS0-093試験に一発合格する準備はできていますか？ 2025年の認定試験はこれまで以上に難易度が上がり、深い知識と実践的なスキルが求められます。合格を確実にするためには、信頼できる最新の学習教材が不可欠です。PassitCertifyは、リアルなNetApp NS0-093試験問題と専門家が検証した学習リソースを提供し、自信を持って試験に挑めるようサポートします。しかも、今なら全教材が35%オフ！

PassitCertifyがNS0-093試験対策に最適な理由

✅ 本番レベルの試験問題 – 最新傾向を完全網羅
PassitCertifyは、最新の試験フォーマットや出題範囲に基づいたリアルな問題を提供します。本番と同じ難易度・出題内容で練習することで、試験の流れを把握し、合格の可能性を高めることができます。

✅ 3つの学習スタイルに対応
PassitCertifyは、学習スタイルに合わせて3つの形式を提供：
📄 PDF版 – いつでもどこでも、どんなデバイスでも学習可能。
🖥️ デスクトップ模擬試験 – 本番試験と同じ環境でカスタマイズ可能な模擬テストを実施。
🌐 Webベース模擬試験 – インストール不要、ブラウザ上で簡単に学習可能。

✅ 最新＆専門家による検証済みコンテンツ
試験の内容は頻繁に更新されるため、PassitCertifyの学習教材も常に最新情報にアップデートされています。出題傾向を的確に反映した信頼できるリソースを提供します。

✅ 一発合格保証！
詳細な解説付きの問題、専門家が検証した正確な解答、リアルな模擬試験が合格への近道。多くの受験者が一発合格を達成しています！

✅ 90日間の無料アップデート＆24時間サポート
試験範囲の変更があっても安心！購入後90日間の無料更新付き。また、24時間365日対応のサポートで、質問や技術的な問題にも即対応します。

✅ 今だけ35%オフ – 期間限定キャンペーン！
2025年限定！今ならNetApp Accredited Hardware Support Engineer試験の全教材が35%割引。高品質な試験対策教材をお得に手に入れるチャンスをお見逃しなく！

📥 NetApp NS0-093試験問題を今すぐダウンロード：
🔗 https://www.passitcertify.com/netapp/ns0-093-questions.html

PassitCertifyを活用したNS0-093試験対策の進め方

✔ PDFをダウンロードまたはWebテストプラットフォームにアクセス。
✔ リアルな試験問題で練習し、出題傾向を把握。
✔ デスクトップまたはWeb模擬試験で試験形式に慣れる。
✔ 間違えた問題を分析し、弱点を克服。
✔ 90日間の無料アップデートで最新情報をチェック。

まとめ – NetApp NS0-093試験に自信を持って挑もう！

正しい学習教材があれば、2025年のNetApp NS0-093試験合格は確実！PassitCertifyの信頼性の高い試験対策リソースで、あなたも成功を掴みましょう。今すぐ35%割引を利用して、未来への第一歩を踏み出しましょう！

💡 今すぐ準備開始！ 🔗 https://www.passitcertify.com/netapp/ns0-093-questions.html
【Astro × Astro Icon】astro-iconの使い方について

# はじめに
`Astro`でアイコンを設定したいときに検索すると、最もよく出てくるのが`astro-icon`です。このライブラリを使うと、SVGアイコンやオープンソースのアイコンを簡単に利用できます。

この記事では、その導入方法と使い方を紹介します。

:::note warn
***この記事は<font color="Red">個人的なアウトプット</font>を目的として作成したものです。そのため、誤った情報や不足している内容が含まれている可能性があります。もし間違いや気になる点がございましたら、ぜひご指摘いただけますと幸いです***。
:::


# astro-iconの使い方
## インストール
まずは`astro-icon`をインストールします。
```
npx astro add astro-icon
```

インストールが完了すると、任意のページで`astro-icon`を使うことができます。
SVGを直接指定することも可能ですが、今回は オープンソースのアイコンライブラリ「Material Design Icons（MDI）」 を使用します。

## MDIアイコンのインストール
以下のコマンドで`MDI`アイコンを追加します
```
npm install @iconify-json/mdi
```
`mdi`の部分は、使用したいアイコンのセットに応じて変更できます。
（例：FontAwesomeなら @iconify-json/fa）

##  アイコンの表示方法
インストールが完了したら、`Icon`コンポーネントをインポートして、以下のように記述します。

```jsx
---
import { Icon } from "astro-icon/components";
---

<Icon name="mdi:youtube" />
```
`name="mdi:youtube"`の部分を変更することで、異なるアイコンを表示できます。

## アイコンの探し方
アイコンは[iconify](https://icon-sets.iconify.design/)から探すことが可能です。
1. 検索欄にキーワードを入力し、使用したいアイコンを探す![スクリーンショット 2025-03-07 14.49.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3835217/f67095e8-0bcd-482e-be17-f9cec3c0335a.png)

2. アイコンをクリックし、「`Icon name`」をコピーする![スクリーンショット 2025-03-07 14.47.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3835217/9b968ebf-7a0a-45f6-8861-6ef36dbf0885.png)

コピーした名前を`<Icon name="xxx" />`の`name`に指定すれば、簡単にアイコンを表示できます。

# 終わりに
`astro-icon`を使うと、手軽にアイコンを導入できます。
今後、カスタマイズ方法や他のアイコンセットについても調べてみたいと思います。

# 参考
『astro-iconで手軽にいい感じのアイコンを使わせてもらおう』

https://alpacat.com/posts/introduction-of-astro-icon

https://www.astroicon.dev/getting-started/
Top 5 Concepts You Must Master for Salesforce CPQ Certification

Salesforce CPQスペシャリスト認定資格の評価範囲は、Salesforce CPQアプリケーションを基に査定されます。その試験に通過したり実務が出来るようになるには、基本の重大な要点とそれに伴う概念をしっかりと把握することが必要です。大半の受験者がこれらの概念を正しく理解することが、合格へと繋がります。
Salesforce CPQ認定資格の準備をしている方には、これが役立ちます https://www.certboosters.com/salesforce/path/cpq-specialist

1.製品構成

製品構成はSalesforce CPQの到達目標のひとつです。製品バンドルの作成、オプションや機能の定義、構成ルールの適用について十分に理解することが重要です。これらの考えに対した試験問題が大半であるため、必ずしも構成ルールの全てを網羅する必要はありません。

2.価格設定方法

価格設定は二次的要素よりも重要なポイントの1つとして正確に把握しなければなりません。価格付けには、リスト価格 または 原価想定 価格 の他にも プロペース 想定、低に直接的な れる 価格ソート、多様な方式に熟罰を撒まわる ことが必要になる それぞれの手法に適切に割り当てるためのフレームワーク、それぞれの社内営業部から出された崎の特定状況下で 様々な適応ができるからこそ、精密で俊敏な対応が可能になります。

3.価格ルール

あらかじめ設定された条件に従い、特定の製品やサービスの貸与交換価に対して自動的に変動させたりすることができるにも関わらず、使用側での実際に活用しか sap します。価格変更の自動化は選択を指令した製品やRON同 ARFYに原則させていけばできますが、そのためにはルール設定のクエリ化設定の定義ができ必要 選択式のぞい l方法が自動適用できるようになります。

4. 見積もりテンプレート

正確でプロフェッショナルな見積もりを作成する能力は重要です。見積もりテンプレートを設計または編集し、詳細ラインを管理し、適切なコンテンツを配置することで、ビジネスと顧客のニーズに合った見積もりを作成できます。

5. 高度な承認プロセス

これは、特別価格または割引承認を管理する上での重要な要素でもあります。承認チェーンを作成し、入力条件を定義し、承認ステップを構築することで、販売サイクルを遅らせることなく承認管理を制御できます。

これらの5つの基本概念を用いることで、Salesforce CPQスペシャリスト試験の問題に自信を持って取り組み、実際のプロジェクトで活用することが可能です。効果的に準備するためには、Salesforceサンドボックス環境内での作業、公式ドキュメントの確認、および実践的な演習を通じて自信と経験を得ることが重要です。
プリザンターの管理画面をちょっと使いやすくしてみる

## はじめに
今回はプリザンターの管理画面をちょっと使いやすくするTipsを紹介します。

## 項目設定欄の高さを拡げる
複数の項目がある場合に、エディタや一覧画面などの項目設定欄の高さが狭いと思ったことはありませんか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3555395/7ac4f3af-e372-4818-a1be-caa5e4159c5a.png)
この赤色の部分です。ここの高さを拡げてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3555395/3b496c12-5755-4e59-b934-ed4fb79d656f.png)
要素を見てみると、`.h250`というクラスで250pxに設定されていることが分かります。

```css
.h250 {
    height: 250px;
}
```
https://github.com/Implem/Implem.Pleasanter/blob/24fb71aa12d54ce04dd1fbf2fc49b0862031904d/Implem.Pleasanter/wwwroot/styles/site.css#L3224-3226

ソースだとこれですね。このリンクを見てもらうと分かるのですが、高さ指定用のクラスは`.h100`から`.h600`まで50px刻みで用意されています。ということはこのクラスをもっと大きいサイズが指定されているものに書き換えれば良いのでは？と思うのですが、この部分、サーバ側のプログラムでハードコードされているので書き換えが出来ません。そのため、設定されているCSSを上書きする形で拡張スタイルを作成します。

```css:AdminColumnsWrapperHeight.css
[id$="ColumnsWrapper"] {
    height: 500px !important;
}
```

タブごとにそれぞれ別のIDが設定されているのですが、命名規則的には`ColumnsWrapper`で終わるので、後方一致セレクタを使用します。ひとまずは標準の倍の500pxにしていますが、任意で調整してみてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3555395/19a033d0-fd75-4e45-b7da-7928b5aa5f0a.png)
適用例です。視認性がかなり向上しました。

## 項目に項目名(物理名)を表示する
分類Aや分類Bなどの項目名をデフォルトから変更して使うことがほとんどだと思います。この時に選択肢には変更された後の名前しか表示されず、変更前の項目名が分かりません。詳細画面を開けば分かるのですが、変更前の項目名はリンクやスクリプトなどちょっとしたことを行う時にぱっと分かりたい項目なので、いちいち開いて確認するというのはちょっと面倒です。これをちょっと改善してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3555395/736d6ba5-3b48-4c6f-b0f2-556a0928cd79.png)

```html
<li
    class="ui-widget-content ui-selectee"
    title="タイトル"
    data-order="2"
    data-value="Title">
        [記録テーブル(子テーブル)] 子タイトル
</li>
<li
    class="ui-widget-content ui-selectee"
    title="分類A"
    data-order="8"
    data-value="ClassA">
        [記録テーブル(子テーブル)] 親テーブル
</li>
<!--読みやすさを優先して改行をくわえています-->
```
要素を見てみると、`data-value`属性に物理名が格納されていることが分かります。これを表示させてみます。
こんな時にはCSSの`attr()`関数が便利なので、これと疑似要素を組み合わせて拡張スタイルを作成します。

```css:AdminColumnItemPhysicalName.css
[id$="ColumnsWrapper"] ol li::after {
    content: " (" attr(data-value) ")";
    color: gray;
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3555395/1637bc58-dbfd-45a9-82b3-6b05825265ef.png)
適用してみました。物理名がわかりやすく表示されることで、どの項目がどれを示すかを簡単に識別することができるようになりました。

## まとめ
今回は管理画面をちょっと使いやすくする方法を2つ紹介しました。プリザンターのHTMLの構造や、CSSのスタイルを当たり方を観察してみると、このような感じでちょっとしたCSSで改善出来るところを多く見つけることが出来ます。
皆さん是非挑戦してみてください。
daemon.jsonでDockerコンテナに割り当てるIPアドレスをコントロールする方法

`fixed-cidr`と`default-address-pools`の意味を把握しておらず、コンテナ作成時に振られるIPアドレスが狙い通りにならなかったため、これらについてまとめました。

`--ip`オプションやDocker Composeの`networks`で明示的にIPアドレスを指定するのではなく、コンテナ作成時にデフォルトで割り当てられるIPアドレスの範囲を`daemon.json`で設定する方法です。

## `fixed-cidr`と`default-address-pools`の意味

### fixed-cidr

`fixed-cidr`は、デフォルトブリッジネットワーク（`docker0`）のサブネット内でコンテナに割り当てるIPアドレスの範囲を制限する設定です。

例えば、`bip`で`172.20.0.0/24`を指定した際に、`fixed-cidr`で`172.20.0.128/25`のような範囲を指定することで、コンテナがその範囲内からIPを取得するように制御します。`bip`で指定したサブネット範囲全体を使っても構わない場合、`fixed-cidr`を指定する必要はありません。

ちなみに`bip`は、`docker0`のIPアドレスとネットワークアドレス範囲を指定する設定値です。

### default-address-pools

`default-address-pools`は、新規作成したDockerネットワーク内でコンテナに割り当てられるIPアドレスの範囲を指定するための設定です。

`docker`コマンドでコンテナを作成する場合は、明示的にネットワークを指定しなければ`docker0`ネットワークに属するため`default-address-pools`の設定値は関係ありませんが、Docker Composeの場合は、`network_mode: bridge`と設定しなければ自動的に新たなネットワークが作成されるため、`default-address-pools`で設定したネットワークアドレス範囲からIPアドレスが割り当てられます。

## `daemon.json`の例

`daemon.json`の例を書いておきます。

以下の設定では、`docker0`ブリッジのIPアドレスを`192.168.0.1/24`に設定し、`docker0`に接続するコンテナのIPアドレスを`192.168.0.128/25`の範囲内から割り当てます。その他のネットワークには、`172.16.0.0/12`の範囲をベースとして、`172.16.0.0/20`、`172.16.16.0/20`、`172.16.32.0/20`、...、`172.31.240.0/20`といったサブネットが払い出されることになり、コンテナにはこれらのサブネットからIPアドレスが割り当てられます。

```daemon.json
{
    "bip": "192.168.0.1/24",
    "fixed-cidr": "192.168.0.128/25",
    "default-address-pools": [
        {
          "base": "172.16.0.0/12",
          "size": 20
        }
    ]
}
```

##  まとめ

デフォルトブリッジネットワークを適用する場合は`fixed-cidr`、Docker Composeで特に設定せず起動するなどして別途作成されたネットワークを適用する場合は`default-address-pools`を使うことでコンテナに割り当てるIPアドレスをコントロールすることができます。

## 参考

- [Bridge network driver](https://docs.docker.com/engine/network/drivers/bridge/)
- [dockerd](https://docs.docker.com/reference/cli/dockerd/)
- [Compose の ネットワーク機能](https://docs.docker.jp/compose/networking.html)
forEachよりfor-of！フラグ管理でループを最適化

「フラグ管理」問題に挑戦した高2の僕。最初は7の個数をカウントしてたけど、実はもっとシンプルな方法があった！

<br>**問題概要**
与えられた数列に「7」が含まれているか判定し、1つでもあれば"YES"、なければ"NO" を出力する。

<br>**NG例**（非効率）
```js
rl.on('close', () => {
    let seven = 0;
    lines.slice(1).map(Number).forEach(num => {
        if (num === 7) seven++;
    });
    console.log(seven > 0 ? "YES" : "NO");
});
```
❌ 問題点:
・7 を数える必要はなく、1つ見つかった時点で確定できる
・forEach は途中で止められず、無駄なループが発生


<br>**OK例**（最適化）
```js
rl.on('close', () => {
    let foundSeven = false;

    for (let num of lines.slice(1).map(Number)) {
        if (num === 7) {
            foundSeven = true;
            break;
        }
    }

    console.log(foundSeven ? "YES" : "NO");
});
```
✅ 改善点:
✔ フラグ (foundSeven) で 存在確認のみに 絞る
✔ break を使い、最短で処理終了
✔ for-of は forEach と違い、途中でループを抜けられる

<br>まとめ
「カウント」ではなく「存在確認」ならフラグ管理が最適！

[僕の失敗談と解決話！](https://paizabeginner.wordpress.com/2025/03/07/paiza%e3%81%a7%e5%9f%ba%e6%9c%ac%e3%83%9e%e3%82%b9%e3%82%bf%e3%83%bc%e3%83%95%e3%83%a9%e3%82%b0%e7%ae%a1%e7%90%86%e3%81%a7%e3%83%ab%e3%83%bc%e3%83%97%e3%82%92%e6%9c%80%e9%81%a9%e5%8c%96%e3%81%97/)
ECサイト作成で学んだこと④

今回はECサイトを作成で学んだことを4つに分けて記事にしていきます。

:::note warn
以下の箇条書きの記事をそれぞれ作成します。
記事が出来次第、リンクへ変更になりますのでお待ちください。
:::

- エンジニアリングについて
- Djangoについて
- Pythonの文法
- 汎用ビューについて

# 汎用ビューについて
:::note
基礎的な部分の説明は省きます。
:::
- post()メソッド
- get_context_data()メソッド
- get_queryset()メソッド

## `post()`メソッド
`post()`は、フォームの`POST`リクエストを処理するために使用します。

### 実装例（カートへの商品追加）
```python
from django.views import View
from django.shortcuts import redirect, get_object_or_404
from django.contrib import messages

class AddToCartView(View):
    def post(self, request, product_id):
        form = AddToCartForm(request.POST)
        if not form.is_valid():
            messages.error(request, form.errors["num"][0])
            return redirect("cart:cart_page")
        
        cart = Cart.get_or_create_cart(request)
        product = get_object_or_404(Product, id=product_id)
        cart.add_product(product, form.cleaned_data["num"])
        messages.success(request, f'{product.name}をカートに追加しました')
        return redirect(request.META.get("HTTP_REFERER", "cart:cart_page"))
```
- `request.POST`からデータを取得し、フォームバリデーションを行う
- 処理後に`redirect()`を使って適切なページへリダイレクトする（RPGパターン）
- エラーメッセージを`messages`に保存し、リダイレクト後に出力可能にする


## `get_context_data()` メソッド
`get_context_data()`は、テンプレートに渡すデータをカスタマイズしたい時に使用します。

### 実装例（カートの情報を取得）
```python
class CartPageView(ListView):
    template_name = 'cart/cart_page.html'
    model = CartProduct

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        cart = Cart.get_or_create_cart(self.request)
        cart_products = cart.cart_products.select_related("product")
        
        context["cart_products"] = cart_products
        context["total_cart_price"] = sum(p.sub_total_price() for p in cart_products)
        context["total_quantity"] = sum(p.quantity for p in cart_products)
        return context
```
- `super().get_context_data(**kwargs)`で親クラスのデフォルトコンテキストを取得
- 追加のデータ（`cart_products`, `total_cart_price`など）を`context`に格納
- テンプレート内でデータを簡単に参照できるようにする


## `get_queryset()` メソッド
`get_queryset()`は、ビューで取得するデータのクエリセットをカスタマイズしたい時に使用します。

### 実装例（登録済みの商品一覧の取得）
```python
class ProductListView(ListView):
    model = Product

    def get_queryset(self):
        return Product.objects.filter(is_published=True)  # 公開済みの商品だけ取得
```
- デフォルトの`model.objects.all()`を`filter()`で絞り込むことができる
- 条件付きのデータ取得（例えば`is_published=True`のみ）を簡単に設定可能
- `select_related()`を追加してパフォーマンス向上も可能

## どのクラスを継承するか問題
よし、`model`や`template_name`はわかったけどどのクラスを継承したらいいのかわからないという状況になったので、表を用いて説明します。
| 目的 | 適切なCBV | 説明 |
|:-|:-|:-|
| 単純なページ表示 | `TemplateView`  | ただの静的ページ（HP, 利用規約)  |
|データ一覧の表示  | `ListView`  | モデルのリストを取得し、テンプレートに渡す<br>(商品一覧、注文履歴など）|
| 詳細ページの表示  | `DetailView`  | 特定のオブジェクトの詳細を表示<br>（商品詳細、注文詳細  |
| フォームを含むページ  | `FormView`  | フォームのバリデーションや処理が必要<br>（と言わせフォーム、注文フォーム）  |
| データの作成  | `CreateView`  | モデルの新規作成<br>（商品登録、ユーザー登録）  |
|  データの更新 |  `UpdateView` | モデルのデータを編集<br>（プロフィール編集、商品情報編集）  |
| データの削除  |  `DeleteView` | モデルのデータを削除<br>（アカウント削除、注文キャンセル）  |
|  特殊な処理<br>（GET/POST) |  `View` |  複数のフォーム処理やカスタムロジックが必要な場合 |


## 最後に
今回はECサイト作成で学んだこと④ということで
汎用ビューについて記載しました。

説明不足やもっと必要なことがあるかもしれませんが
その都度書き足していきます！
chromeで拡張機能を作るその1(特定のページを開いたら通知が出る拡張機能の作成)

# はじめに
業務の中で拡張機能を触ることが多いのですが、一から作ったことが無かったことと、V2とV3の違いがしっかり分かっていなかったため、復習がてら記事にまとめようと思います。

## 今回のゴール
特定のページを開いたら通知が出る拡張機能の作成
バックグラウンドでタブを検知してタブのURLが "https://sciencepark.co.jp" だったら通知を出す拡張機能を作成します。

## 目次
1. 必須ファイル
1. manifest.json
1. background.js
1. 結果
1. 参考文献

## 作成環境
OS: Windows 11 Pro 23H2
chrome: 133.0.6943.142
VSCode: 1.97.2


## 1. 必要なファイル
　必要なファイルは以下の2つです。今回はバックグラウンドで処理を行いたいので、background.jsを使用します。
 
 ・manifest.json
 ・background.js

## 2. manifest.Json 
 
manifest.Jsonは拡張機能に必須のファイルで、拡張機能の構造と動作に関する重要な情報が記載されています。

```javascript
{
    "name": "sampleExtension",
    "version": "1.0",
    "manifest_version": 3,
    "description": "拡張機能のテスト",
    "background": {
        "service_worker" : "background.js"
    },
    "permissions": [
        "tabs",
        "notifications"
    ]
}
```
nameは拡張機能の名前で、75文字以内で好きな名前を付けることができます。
varsionは拡張機能のバージョン番号です。
manifest_versionは使用するマニフェスト ファイル形式のバージョンで現在の標準はManifest Version 3 のため、3を指定します。
descriptionは拡張機能の説明で、最大132文字まで入力できます。
backgroundは拡張機能がバックグラウンドで動作するために必要な権限です。これにより、Chromeが起動していない時でも拡張機能を事項し続けることができます。
permissionsでは特定の拡張機能のAPIを有効にします。今回はブラウザのタブを検知して特定のURLの場合通知を表示させたいので、tabsとnotificationsの権限を追加します。


## 2. background.js

```javascript
var path = "https://sciencepark.co.jp";
var opt = {
    type: "basic",
    title: "notification",
    iconUrl: "icon.png",
    message: "サイエンスパークのHPです",
};

chrome.tabs.onActivated.addListener(function (activeInfo) {
    chrome.tabs.get(activeInfo.tabId, tab => {
        var url = tab.url;
        if(url.indexOf(path) === 0){
            chrome.notifications.create(opt);
        }
    });
});


chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
    var url = tab.url;
    if(url.indexOf(path) === 0){
        chrome.notifications.create(opt);
    }
});
```

### chrome.tabs.onActivated

タブがアクティブになったとき発生するイベントです。
引数はactiveInfoでtabIdとwindowIdの情報しか取得できないため、tabIdからタブのURL情報を取得しています。

### chrome.tabs.onUpdated

タブが更新されたときに発生するイベントです。
引数はtabId, changeInfo, tabの３つあります。

### chrome.notifications.create

テンプレートを使って通知を作成し、画面の右下に表示させることができるAPIです。
テンプレートのtype, title, iconUrl, messageは必須で、無いとコンソールログ上に以下のようなエラーが出力されます。
```
Unchecked runtime.lastError: Some of the required properties are missing: type, iconUrl, title and message.
````

## 結果
サイエンスパークのHPを開いたら右下に以下のような通知が来ます。
![スクリーンショット 2025-03-07 112824.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2871987/159fe03c-2953-42e3-b632-df2f04df2c10.png)

## 参考文献
https://developer.chrome.com/docs/extensions/reference/manifest?hl=ja
https://developer.chrome.com/docs/extensions/reference/api/tabs?hl=ja
https://developer.chrome.com/docs/extensions/how-to/ui/notifications?hl=ja
ポケポケの5連勝イベントはいうほど運ゲーではないという話


## 結論

```
勝率0.5で90試合以内に5連勝できる確率 → 0.774777
勝率0.55で90試合以内に5連勝できる確率 → 0.897051
勝率0.6で90試合以内に5連勝できる確率 → 0.964484
勝率0.65で90試合以内に5連勝できる確率 → 0.991669
勝率0.7で90試合以内に5連勝できる確率 → 0.998832
```

## ソース

```js
const 試行回数 = 100_0000;
const 試合数 = 90; // 勝率0.5で45勝するまでの試合数の期待値

function 試合結果(勝率) {
    if (Math.random() < 勝率) {
        return "勝ち";
    }
    else {
        return "負け";
    }
}

function シミュレーション(勝率) {
    let 達成数 = 0;
    for (let i = 0; i < 試行回数; i++) {
        let 連勝数 = 0;
        for (let j = 0; j < 試合数; j++) {
            if (試合結果(勝率) === "勝ち") {
                連勝数 += 1;
                if (連勝数 >= 5) {
                    達成数 += 1;
                    break;
                }
            }
            else {
                連勝数 = 0;
            }
        }
    }
    console.log(`勝率${勝率}で${試合数}試合以内に5連勝できる確率 → ${達成数 / 試行回数}`);
}

for (const 勝率 of [0.5, 0.55, 0.6, 0.65, 0.7]) {
    シミュレーション(勝率);
}
```
iPhoneでimage-compare-viewerの挙動が悪い時の対処法

# iPhoneでimage-compare-viewerの挙動が悪い時の対処法

`image-compare-viewer` は、2つの画像を比較するための便利なライブラリですが、iPhoneのSafariなどでは期待通りに動作しないことがあります。本記事では、その原因と具体的な対策を紹介します。

## iPhoneでの問題点
- **スライダーが動かない**
- **タッチ操作が効かない**
- **スクロールと干渉する**
- **ズームが勝手に発生する**

## 対策方法

### 1. `image-compare-viewer` の最新バージョンを確認

まず、ライブラリの最新版を使用しているか確認しましょう。バグ修正が行われている可能性があります。

```sh
npm update image-compare-viewer
```

### 2. `pointer-events` を適切に設定

iPhoneのSafariでは、`pointer-events: none;` の影響でタッチが効かないことがあります。CSSで適切に設定しましょう。

```css
.image-compare-wrapper {
  touch-action: pan-y; /* 縦スクロールを有効にする */
  pointer-events: auto; /* タッチイベントを有効化 */
}
```

### 3. `touch-action` を修正

`touch-action: none;` が設定されていると、スライダーの動作が制限されることがあります。JavaScriptで修正できます。

```javascript
document.querySelectorAll('.image-compare-wrapper').forEach(el => {
  el.style.touchAction = 'pan-y';
});
```

### 4. iPhoneの `gesturestart` を防ぐ

iPhoneでは、`gesturestart` イベントが発生すると意図しないズームが起こります。これを防ぐには以下のコードを追加します。

```javascript
document.addEventListener('gesturestart', function(event) {
  event.preventDefault();
});
```

### 5. `passive: false` を設定して `touchmove` を適切に処理

`touchmove` イベントを `passive: false` にすることで、iPhoneのタッチ操作が改善されることがあります。

```javascript
document.addEventListener('touchmove', function(event) {
  event.preventDefault();
}, { passive: false });
```

### 6. `mousemove` の代わりに `touchmove` を使用

iPhoneのSafariでは、`mousemove` が `touchmove` と競合することがあります。以下のコードで `touchmove` を適切に処理します。

```javascript
document.querySelectorAll('.image-compare-wrapper').forEach(wrapper => {
  let slider = wrapper.querySelector('.slider');

  function moveSlider(e) {
    let rect = wrapper.getBoundingClientRect();
    let x = e.touches ? e.touches[0].clientX - rect.left : e.clientX - rect.left;
    let percent = (x / rect.width) * 100;
    percent = Math.max(0, Math.min(100, percent));
    slider.style.left = percent + '%';
  }

  wrapper.addEventListener('mousemove', moveSlider);
  wrapper.addEventListener('touchmove', moveSlider, { passive: false });
});
```

## まとめ

iPhoneで `image-compare-viewer` をスムーズに動作させるには、以下の対策を試してください。

✅ **最新版にアップデート**  
✅ **CSSの `pointer-events` を修正**  
✅ **`touch-action` を適切に設定**  
✅ **iPhoneの `gesturestart` を防ぐ**  
✅ **`passive: false` を設定して `touchmove` を適切に処理**  
✅ **`mousemove` の代わりに `touchmove` を使う**
ECS,Nginxを利用した際にポート枯渇にハマった話

以前Amazon ECS,Nginxを利用したプロキシサーバを構築した際、ポート枯渇にハマった時の話を共有したいと思います。
下記の構成でオンプレの機器からインターネット接続するためのプロキシサーバをAWSに構築していたいました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990360/11b04e67-dfcd-4228-a62d-8a1000bd7a21.png)



元々下記のAWS公式サイトを参考にNAT gatewayで宛先IPアドレス一つにつき、同時接続数55000の制限があることを認識していたのですが、
https://repost.aws/ja/knowledge-center/vpc-resolve-port-allocation-errors
システム全体で処理できる同時接続数(Network Load  BalancerのActiveflowcount)が元々の想定よりも大幅少ない約14000程で通信エラーが多発するという問題が発生しました。


調査の中で、VPCフローログを確認したところ、Amazon ECSとNAT gateway間の通信で使用してるsrcポートが想定よりも少ないことが分かりました。
Amazon ECSのTask一つ当たりで利用するsrcポートが元々1-65535を想定していたのですが、32768-60998の偶数ポートのみ約14000程度しか使用されてないことを確認しました。

VPCフローログの確認結果
|interface-id  |srcaddr  |dstaddr  |srcport  |dstport |
|:-------------|---------|---------|---------|--------|
|eni-XXX |Amazon ECSTaskのIPアドレス  |NAT gatewayのIPアドレス  |32768  |443 |
|eni-XXX |Amazon ECSTaskのIPアドレス  |NAT gatewayのIPアドレス  |32768  |443 |
|～      |～                    |～                |～     |～  |
|eni-XXX |Amazon ECSTaskのIPアドレス  |NAT gatewayのIPアドレス  |60998  |443 |

調査をしたところ、IPv4のTCP通信の仕様で、srcIPとdetIPの組み合わせ一つにつき使用できるポート数が限られており、
今回dstportが443で固定だったため、srcportを使い切ってポート枯渇が発生してしまったことが原因でした。
XXX.XXX.XXX.XXX:srcprt1 ⇒ YYY.YYY.YYY.YYY:443
XXX.XXX.XXX.XXX:srcprt2 ⇒ YYY.YYY.YYY.YYY:443
~

こちらの問題の解決策として、Amazon ECSのTaskの数を増やしてsrcIPを増やすことでポート枯渇を防ぐことにしました。
AAA.AAA.AAA.AAA:srcprt1 ⇒ YYY.YYY.YYY.YYY:443
AAA.AAA.AAA.AAA:srcprt2 ⇒ YYY.YYY.YYY.YYY:443
BBB.BBB.BBB.BBB:srcprt1 ⇒ YYY.YYY.YYY.YYY:443
BBB.BBB.BBB.BBB:srcprt2 ⇒ YYY.YYY.YYY.YYY:443
~
システム全体のAWSコストはなるべく抑えるようにTask一つあたりのCPU/メモリは元々よりも減らしてます。
※NAT gatewayを増やす方法でも実装できますが、NAT gatewayは費用が高く、
　コストパフォーマンスが悪すぎるので、Amazon ECSのTask数を増やす方針にしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990360/a4f2f8d8-2e65-4557-aebb-64f5f4cdb8f8.png)


構成変更をした後、再度動作確認をしたところ、Amazon ECSのTaskの数増加に伴って、
システム全体で処理できる同時接続数を拡張していくことができることを確認できました。

※3/14追記
Amazon ECSのオートスケーリングについても検討しましたが、AWSの監視運用機能をAWSサービスではなく、別の製品で実装していたため、
Amazon ECSのTask数が変わる度に、監視製品側のconfig修正もやらないといけない仕様になっていたため、オートスケーリングの実装は断念しました。
(頑張れば実装できたかもしれませんでしたが、スケジュール優先で断念しました）
また、システム全体で処理できる同時接続数については、CloudWatchでNetwork Load BalancerメトリクスのActiveFlowCountを確認しています。
CloudWatchアラームで、Network Load BalancerのActiveFlowCountの値を超えると通知が来る設定を入れておき、
通知が来たらAmazon ECSのTask数増設を実施するという運用にしています。

■まとめ
srcIP,destIPの組み合わせ一つにつき利用できるポート数に上限がある。
ポート枯渇が発生しないようにシステム内のIPアドレスの数を増やす設計検討が必要
Amazon ECSのTask数を増やして、IPアドレスを増やすことでシステム全体の同時接続数上限を増やすことができます。
みんな大好きJavaScriptのimport.metaにどんなプロパティがあるか調べてみた

Node.jsで動くJavaScriptとか書いていると`import.meta.url`とか書きますよね？
最近のNode.jsだと`import.meta.dirname`も使えたりするわけですけど、ちょっと古い環境では動かなかったりで困ったりしていて、そういえばどの環境だとどの`import.meta`が使えるかよくわからないな、と思ったのでざっと調べてまとめようと思いました。

調べたドキュメントは、この辺りです。

- Living Standard:
    - <https://html.spec.whatwg.org/multipage/webappapis.html#integration-with-the-javascript-module-system>
- Node:
    - <https://nodejs.org/api/esm.html#importmeta>
- Deno:
    - <https://docs.deno.com/examples/module_metadata_tutorial/>
- Bun:
    - <https://bun.sh/docs/api/import-meta>
- Webpack:
    - <https://webpack.js.org/api/module-variables/#importmeta>
- Vite:
    - <https://vite.dev/guide/env-and-mode.html>
    - <https://vite.dev/guide/features.html#glob-import>
    - <https://vite.dev/guide/api-hmr.html>

ちなみにMDNで書いてあるのは、`import.meta.url`と`import.meta.resolve`だけです。
これは Living Standard のやつと一致しますね。

参考: [MDN - import.meta](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta#value)

ご存知かと思いますが、ECMAScriptにはどのプロパティも書いてありません。

追記2025-04-25：
もしNode.js向けのライブラリを書いている場合は、`eslint-plugin-n`を使えば、Node.jsのサポートバージョンごとに使えない`import.meta`を報告してくれるようになりました :tada:
<https://github.com/eslint-community/eslint-plugin-n/releases/tag/v17.17.0>
<https://github.com/eslint-community/eslint-plugin-n/pull/420>

# `import.meta.url`

そのスクリプトのURL文字列が取れる。大体どこの環境でも使えると思う。
Living Standard にも書いてあるのでブラウザでも使えそう。

# `import.meta.resolve()`

そのスクリプトから`import(specifier)`した場合に取れるスクリプトのパスのURL文字列が取れるはずだけど、環境によってはPromiseを返すらしい。怖い。
あと第2引数を受け入れるかどうかはその環境次第だと思う。
動きは違うけど、大体どこの環境でも存在はすると思う。
Living Standard にも書いてあるのでブラウザでも使えそう。

# `import.meta.filename`、`import.meta.dirname`

そのスクリプトのパスやディレクトリパスが取れる。
Node.js v20.11以降で使える。あとDenoとBunも大丈夫（バージョンは調べてない）。

# `import.meta.main`

そのファイルがエントリーポイントかどうかがわかる。
DenoとBunで使える。

# `import.meta.path`、`import.meta.dir`、`import.meta.file`


`import.meta.path`は`import.meta.filename`、`import.meta.dir`は`import.meta.dirname`と同じ。
`import.meta.file`はそのファイル名が取れる。
Bunで使える。

# `import.meta.env`

環境変数が取れる。
Bunで使える。あとViteではバンドル時に解決してくれる。

# `import.meta.glob()`

Viteで使える。globを使って一括importできる。
ドキュメントはこちら→ <https://vite.dev/guide/features.html#glob-import>

# `import.meta.hot`

Viteで使える。HMRのあれこれをするためのプロパティ。
ドキュメントはこちら→ <https://vite.dev/guide/api-hmr.html>

# `import.meta.webpack`

Webpackで使える。Webpackのバージョンが取れる。

# `import.meta.webpackHot`

Webpackで使える。HMRのやつ（かな？）
ドキュメントはこちら→ <https://webpack.js.org/api/module-variables/#importmetawebpackhot>

# `import.meta.webpackContext()`

Webpackで使える。何かのコンテキストが取れる。 
ドキュメントはこちら→ <https://webpack.js.org/api/module-variables/#importmetawebpackcontext>

# あとがき

まだあるかもしれませんが、どうやって調べればいいかわからないのでこの辺で終わります。
vscodeでjupyter notebookファイル上でカーネル選択に仮想環境先を指定しようとしたがちょっと詰まった。

## 仮想環境を構築したが、vscodeのjupyter notebookで構築した仮想環境を選択しようとして、少し詰まったので備忘録。
### やったこと
1. 選択先を指定する。
1. 仮想環境にjpykernelをインストール

一つずつみましょう

### 1.選択先を指定する。
1. コマンドパレットを開く
    Ctrl + Shift + P（Windows/Linux）または Cmd + Shift + P（macOS）を押します。
    コマンドパレットが表示されます。

2. Pythonインタプリタを選択
    コマンドパレットに「Python: Select Interpreter」と入力し、選択します。

3. 仮想環境のPythonを選択
    表示されたリストから、仮想環境のPythonインタプリタを選択します
例: your_venv_name/bin/python（macOS/Linux）または your_venv_name\Scripts\python.exe（Windows）
__＊この時のパスは開いているファイルの基準にした相対パス、もしくは絶対パスを入力。
＊ここでカーネル選択がされていなくても慌てず、カーネル選択→python環境を探せば出てくるはず__

### 2.仮想環境にjpykernelをインストール
- セルを実行しようとすると、仮想環境にjpykernelがないと怒られました。
```zsh
#仮想環境を有効化
sorce your_venv_name/bin/python
#ライブラリをインストール
pip install ipykernel 
```
これでOK
流行りの統合ID基板についての備忘

# 初めに
転職先の企業で参画する案件がID基盤のシステムのための事前学習を備忘として残す

# 統合ID基盤とは

- 複数システムにアクセスするためのユーザー情報を統合的に管理する仕組み
- 統合認証は以下の2パターン
  - ID管理
  - シングルサインオン

## ID管理

- 複数システムでアカウント情報の一元化
- アカウント情報にはID/PASSのほかに所属や役職の属性情報も含まれる

## シングルサインオン

- １度のユーザー認証で複数システムにアクセスできるようにする仕組み
- メリット
  - ユーザーの利便性が向上する
    - 一つのパスワードで複数のWebサービスにログインできる
  - ID管理者の負担が軽減する
    - ログイン認証の一元化によって、ユーザーがパスワードを忘れるリスクが低減する
  - セキュリティを強化できる
    - FIDO認証や生体認証などの多要素認証と連携する
- 以下の5つの認証方式がある
  - エージェント方式
  - リバースプロキシ方式
  - 代理認証方式
  - フェデレーション方式
  - 透過型方式

## 多要素認証
「多要素認証（MFA）」とは、ログイン時に複数の認証要素を組み合わせてセキュリティ強化を行い、なりすましや不正アクセスを防止する仕組み

- 知識情報	ユーザー本人にしか分からない情報	
  - ID、パスワード
  - PINコード
  - 秘密の質問（好きな食べ物、母親の旧姓など）と回答
- 所持情報	ユーザーが所持する物品に関する情報	
  - スマホ、携帯電話（SMS認証、着信電話認証など）
  - ハードウェアトークン
  - ICカード
- 生体情報	ユーザーの身体的特徴に関する情報	
  - 指紋
  - 声紋
  - 静脈
GitHub ActionsでCloudFrontのキャッシュ削除に失敗した原因と解決策

# はじめに

こんにちは、Gakken LEAPのバックエンドエンジニアのmizunoです。
サイトのリリース時、GitHub ActionsからCloudFrontのキャッシュ削除を行っていたのですが、ファイルが古いまま表示される問題が発生しました。
原因を調査したところ、AWS CLIのコマンド実行時にワイルドカードの扱いが正しくなかったことが判明しました。

## 問題の詳細

GitHub Actionsのワークフローで、以下のコマンドを実行していました。

```yaml
env:
  CLOUDFRONT_DISTRIBUTION_ID: "CLOUDFRONT_DISTRIBUTION_ID"
  CLOUDFRONT_TARGET_PATH: "/*"

jobs:
  upload:
    runs-on: ubuntu-latest
    steps:
      # ... (他の処理) ...
      - name: Delete Cloudfront Cache
        run: aws cloudfront create-invalidation --distribution-id $CLOUDFRONT_DISTRIBUTION_ID --paths $CLOUDFRONT_TARGET_PATH
```

しかし、この設定ではキャッシュが正しく削除されず、リリース後も古いコンテンツが表示されることがありました。

## 原因

原因は、AWS CLIのドキュメントに記載されている通り、ワイルドカードを含むパスを引用符で囲む必要があったためです。
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/Invalidation_Requests.html

> ファイルの無効化にAWS Command Line Interface (AWS CLI) を使用し、* ワイルドカードが含まれるパスを指定する場合は、以下の例のようにパスを引用符 (") で囲む必要があります。
> `aws cloudfront create-invalidation --distribution-id distribution_ID --paths "/*"`

環境変数を展開した結果、コマンドが以下のようになっていました。

```bash
aws cloudfront create-invalidation --distribution-id distribution_ID --paths /*
```

シェルがワイルドカードを解釈してしまい、CloudFrontに意図したパスが渡らなかったため、キャッシュ削除が失敗していました。

## 修正方法

環境変数の使用を止め、直接コマンド内に引用符で囲んだパスを指定するように修正しました。

```yaml
env:
  CLOUDFRONT_DISTRIBUTION_ID: "CLOUDFRONT_DISTRIBUTION_ID"

jobs:
  upload:
    runs-on: ubuntu-latest
    steps:
      # ... (他の処理) ...
      - name: Delete Cloudfront Cache
        run: aws cloudfront create-invalidation --distribution-id $CLOUDFRONT_DISTRIBUTION_ID --paths "/*"
```

これにより、シェルがワイルドカードを解釈する前に、CloudFrontに正しいパスが渡されるようになり、キャッシュ削除が成功しました。

## まとめ

今回の問題から、以下の教訓が得られました。

- 環境変数を扱う際は、展開される値を確認する
- AWS CLIのドキュメントをよく読む

これらの教訓を活かし、今後の開発に役立てていきたいと思います。

## エンジニア募集

Gakken LEAP では教育をアップデートしていきたいエンジニアを絶賛大募集しています！！
ぜひお気軽にカジュアル面談へお越しください！！

https://gakken-leap.co.jp/recruit/
2025年覇権を握る技術 3選


# 2025年トレンドIT技術

## 概要

2025年にトレンドになるであろうIT技術について、その理由、活用例、今後の展望を解説します。

## トレンド技術

### AI (人工知能)

#### なぜトレンド？

AIは、機械学習や深層学習の進化により、画像認識、自然言語処理など様々な分野で目覚ましい成果を上げています。2025年には、その応用範囲がさらに広がり、ビジネスや社会の様々な場面でAIが活用されることが予想されます。

#### どう役立っている？

- **業務効率化**:  AIによる自動化で、 repetitive なタスクを削減し、人間の生産性を向上させます。
- **意思決定支援**: データ分析に基づいたAIの予測や提案が、より良い意思決定をサポートします。
- **顧客体験向上**:  AIチャットボットやパーソナライズされたレコメンデーションが、顧客満足度を高めます。

#### 今後の展望

今後は、AIの倫理的な問題や、AIと人間の共存などが重要なテーマとなるでしょう。より人間らしいAI、説明可能なAI（XAI）への期待も高まっています。

### Web3

#### なぜトレンド？

ブロックチェーン技術を基盤とするWeb3は、分散型社会の実現に向けた新しいインターネットの形として注目されています。NFTやDAOなど、新しい概念が次々と生まれており、大きな可能性を秘めています。

#### どう役立っている？

- **データ所有権のユーザーへの移行**:  ユーザー自身がデータ所有権を持ち、プラットフォームへの依存から脱却できます。
- **透明性とセキュリティ**: ブロックチェーンの高い透明性とセキュリティにより、安全で信頼性の高い取引が可能です。
- **新しい経済圏の創出**:  暗号資産やNFTを活用した新しい経済圏が生まれ、クリエイターエコノミーの発展に貢献します。

#### 今後の展望

Web3はまだ発展途上の技術であり、スケーラビリティ問題や法規制など、解決すべき課題も多く存在します。しかし、これらの課題を克服することで、Web3は社会に大きな変革をもたらす可能性を秘めています。

### Metaverse (メタバース)

#### なぜトレンド？

VR/AR技術の進化、高速通信環境の普及、そしてコロナ禍におけるリモートワークの普及などが背景となり、メタバースへの関心が急速に高まっています。

#### どう役立っている？

- **新しいコミュニケーションとコラボレーション**:  物理的な制約を超え、 virtual な空間で人々が集まり、コミュニケーションやコラボレーションを行うことができます。
- **没入型体験**:  ゲーム、エンターテイメント、教育、ビジネスなど、様々な分野で没入型体験を提供し、新たな価値を創造します。
- **新しい経済活動**:  メタバース内でのアイテム売買やイベント開催など、新しい経済活動の場が生まれています。

#### 今後の展望

メタバースは、まだ黎明期であり、技術的な課題やプライバシーの問題など、克服すべき課題も多く存在します。しかし、これらの課題を克服し、より多くの人々がメタバースに参加することで、私たちの生活や社会を大きく変える可能性を秘めています。

## まとめ

2025年には、AI、Web3、メタバースといった技術が、私たちの社会に浸透し、大きな影響を与えるでしょう。これらの技術の動向を注視し、積極的に活用していくことが重要です。
「(前略)している話」をした話

「おぉっ！？ ガッツリ伸びてんじゃん！ カットだカット！！」

2025年の2月26日テレワーク出社前の朝、夜に[LT初陣](https://rakus.connpass.com/event/343101/ "QA Tips LT会 - vol.3")が開催される日。

僕がこのLT会で人生初の登壇をすることになっている日でもあります。
朝、洗面所の鏡でめっちゃゴツい鼻毛を発見して伐採完了。
オンラインのWEBカメラの前で醜態を見せる放送事故という名のインシデントをなんとか回避できました。
いやぁ手強い障害だった。 あぶないあぶない。



....こんにちは、紹介遅くなりました。 このブログではk-kikuっていいます。
こんな緩々なこと書いていますが、一応自社ではQAチームのマネージャーだったりします。

さて掲題の話、人がやってるLTはちょいちょい聴いてきたものの、見ず知らずの人前で初めて登壇することになったわけですが、結局どうだったんや、という話を記念に？ひと通り回顧しておこうかと思います。

# 1.登壇の背景
もともと[現職](https://toggle.co.jp/ "holding")では、
「エンジニアたる者、積極的に執筆・登壇していこうぜ」
的な風の流れがあり、僕もその対象だった。（一応、職はQAエンジニア）
そんな中、開催2週間くらい前に弊社HRから上述のイベントへの登壇はどうか、と声掛けを受けてどうしよう（←頼りない）、ってなる。

# 2.なぜ初登壇に踏み切ったのか
正直な話、上述「どうしよう」の理由は
「ちゃんと人前で『ほー』とか『へー』とか何らかのインパクトを残せそうなネタが手持ちになかった」から。
勿論、日々誇れる仕事を何もしていないのか、と言われるとそんなことはないのでそれを語ればいいんだけれど、何というか道半ば感が臭う話ばっかりで、話していても面白くない（∴聴いていても面白くないだろう）という疑念がどうしても消えない。
本番前日になって「出ます」って手を挙げたのは、後述で語るお題を選んだから、が理由になる。

# 3.なぜお題をそのテーマにしたのか
とはいえ道半ば道半ばっていうけれど、そもそもQAって何から何まで上手く回っているチームなんてそう多くない。
上手く回り出したからそのノウハウを開発エンジニアに譲渡してQAエンジニアのいない開発集団を！
みたいなビジョンを掲げてプロジェクト運営に勤しんでいる会社をいくつか聞いたことはあるけれど、未だに実現出来ていそうな感じには見えない。（外から見ている感じ）

開発の活動が強くて品質が上がらない、QAの主張が強過ぎて開発が弱る。
バランスって難しいんよ、はい。

で、何なら逆手にとって「途上上等！上手くいってない道半ばの話」を語るか、と腹を決める。

# 4.話したいことはどう決めたのか
じゃあ今やってる道半ば、何を選ぶか。
本当はエモいネタで「おお、マジで！？」みたいなものがいいんだろうけれど、どうせ「まだまだっすよ」っていうオチを最後に話すわけだから、聴いてくれるみんなも知ってそうなQAあるあるの材を選ぶことにした。
それが↓これ。

[アジャイルQAを定点観測している話](https://speakerdeck.com/kkikuno100083/20250226-presentation "アジャイルQAを定点観測している話")

# 5.結局一番言いたいことは何だったのか
自社の開発プロジェクトの品質向上を目指してゾーン分析してますよ、なかなか難しいすね。
端的に書くとそういう話なんだけれど、1点だけ聴衆が抱きそうな嫌な伝わり方がどうしても気になっていた。

「うわぁ、お前の会社その品質状態立て直すこと、出来んのかい！」

これ。
聴いてはもらえたけれど、持って帰って貰うイメージって大事だ。
僕はLTで言いたいこと言ってめでたしめでたしだけれど「うちってこんなに酷いのよ....」という生々しく苦戦していることを伝えたいのが本望ではない。
それを最後の最後にLTっぽく語って締めることした。

# 6.初登壇はどうだったのか

スライドは一応間に合った。
話すこともまあまあ出来ている。
あとは緊張でネタが飛ばないかどうか。

幸いオンライン参加だったので、ノートのカメラの延長線上にがっつり文面化したカンペを用意し、最悪丸読みしちゃおうぜ大作戦を決行。
結局7割ぐらいはカンペに頼り、何とか5〜6分のLTを終える。
ファシリの方にちょっとだけ笑って貰えたのは、何に笑っていたのか若干気になったが、終わればこっちのもんだ。

# 7.登壇を終えて何を得たのか
概ね言いたいことは言えたので無念も後悔もなかったけれど、自社の内情をまとめてスライドに綴りそれを語ることで「あぁ、我々そういやそういう状況だったんだな....」と改めて振り返るいい機会にはなった。
普段書いて社内に共有して留めるを粛々と継続してきたけれど、新しい刺激を受けて
「もうちょい何かせんといかんのでは....？」という気にはなったような。

# 8.で、LTとは
とりあえず言いたいこと言おう。 すっきりしよう。
その中で聴いてくれる人達に何か響くものがあれば、それでよし。
それが多ければ多いほどいいLTなんだろうけれど、1人でも現れれば成功でいいんじゃなかろうか。


さあ初LTも終わったことだし、(前略）しながらどうやって立て直すか、考えるか。