OmniAICreator/Qiita-1.07M huggingface dataset:
【自己紹介】はじめまして、鈴木俊吾です。教育と開発、両方から世界をちょっと良くしたい！

![a.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4067506/b0c2908a-8932-47c4-96d9-e605adfb13f4.jpeg)

こんにちは、はじめまして。
鈴木俊吾（すずしん）と申します。

Qiitaにて、2025年4月から本格的にアウトプットを始めていこうと思います。

この記事では、

- 簡単な自己紹介
- 今までやってきたこと
- これから発信していく内容
- Qiitaにかける想い

についてまとめてみます。
ぜひ最後までお付き合いください！

## 簡単な自己紹介

- 名前：鈴木俊吾（すずしん）
- 居住地：日本（リモート好き）
- 興味：アプリ・ゲーム開発／教育／自己成長／挑戦
- 性格：マイペース・やる時は一気にやるタイプ

X（旧Twitter）でも日々の挑戦記録を発信中です。
https://x.com/suzushin7

## これまでの挑戦と、ちょっとの苦労話

「何かをつくること」と「人に教えること」。
昔からこの2つが好きでした。

最初はまったくの未経験から独学でプログラミングを始め、エラーに苦しみながらも、小さなアプリやツールを作れるようになっていきました。
ただ、会社での実務経験はゼロ。
完全な独学です。
現在は、フリーランスのコンテンツクリエイターとして活動しています。

「このまま自分のスキルってどこまで通用するんだろう？」と不安になる時期もありました。
でも、そんな中でも日々アウトプットし続けることで、少しずつ「形」になる実感が持てるようになってきました。

## これからQiitaに書いていくこと

Qiitaでは、主に以下のような内容を発信していきます👇

- アプリやゲーム開発の学習記録
- プログラミング初心者がつまづいたポイントとその解決法
- 独学のノウハウやヒント
- プログラミング教育
- 「教える人」目線での技術の伝え方・噛み砕き方

「自分が苦労して学んだことは、誰かの近道になる」
そう信じて、できるだけ読みやすく・再現性ある形で発信していきます。

## オンライン家庭教師にも挑戦予定

実は今、「オンライン家庭教師」にもチャレンジしようとしています。
最初は中学生の学習サポートが中心ですが、将来的には「アプリやゲーム開発をマンツーマンで教える家庭教師」という新しい形も目指しています。

理由はシンプルで、自分が「こういう人に教えてほしかったな」と思う存在になりたいから。
Qiitaでの発信も、家庭教師の仕事も、すべて「人の学びをサポートすること」に繋がっていると感じています。

## 発信すること＝自分を育てること

アウトプットは、誰かのためになると同時に、自分にとっても最高の「学びの定着ツール」だと思っています。

Qiitaに記事を書くことで、

- 自分の成長が見える
- 思考の整理になる
- 振り返りができる
- 仲間と繋がれる

この「良いサイクル」を回していきたいです。

## 最後に一言

最後まで読んでいただき、ありがとうございました！

もし「教育系エンジニア」「アプリ開発に挑戦中」「家庭教師に興味ある」など、少しでも共通点があれば、ぜひ繋がってくださいね。
フォローやコメント大歓迎です！
SNSでも気軽に絡んでいただけると嬉しいです。

これから、よろしくお願いします！

この記事が、誰かの「挑戦する勇気」になれば嬉しいです。

## ブログ紹介

私は、Kotlinで自作した静的サイトジェネレーターを使って作成したブログを運営しています。
そちらでは、私が様々なことに挑戦してきたことの過程や結果を残しています。
もし興味があれば、ブログも覗いてもらえたら嬉しいです！

- [スズシンラボ](https://suzushinlab.com/)
日付と時刻の列からタイムスタンプの列を作成する(SPSS Modeler データ加工逆引き1-24)

# 日付と時刻の列からタイムスタンプの列を作成する

![スクリーンショット 2025-04-14 10.42.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/45564b12-35a3-420f-944c-88ecafb540e5.png)

## 1.想定される利用目的

・日付をまたいだ時刻と実績の可視化

## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/raw/refs/heads/main/timestamp.str

## 3.サンプルストリームの説明

![スクリーンショット 2025-04-14 10.42.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/8166d6f8-0b1a-43d8-8879-1126d9916741.png)

a.入力するデータは以下の通りです。

![スクリーンショット 2025-04-14 10.45.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/d94cad5b-9d5e-44a0-b1db-4b2dc48d5128.png)

b.[フィールド作成]ノードを編集します。日付と時刻を文字列として接続させてタイムスタンプ化しています。

![スクリーンショット 2025-04-14 10.45.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/08d3b799-87a6-410c-b51d-53fd43703893.png)

[式ビルダー]ボタンを起動して日付関数から探すと便利に設定できます。

![スクリーンショット 2025-04-14 11.11.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/2654f442-a740-47e1-88cd-56065b8d9289.png)

[テーブル]を実行します。

![スクリーンショット 2025-04-14 10.46.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/4b1dbe2a-18fe-4dcf-98a1-cd849c324b46.png)

c.[時系列グラフ]ノードを編集します。

![スクリーンショット 2025-04-14 10.46.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/25fe45e7-3b32-4467-bb56-fbfa88bd8201.png)

実行します。不定期な記録でも線形補間して表示ができています。

![スクリーンショット 2025-04-14 10.46.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/792c6ad5-94fc-47a2-aee2-88413b4b2598.png)


#### 注意事項

日付と時刻との間のスペースを意図的に設けます。

![スクリーンショット 2025-04-14 10.45.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/08d3b799-87a6-410c-b51d-53fd43703893.png)

## 4.参考情報

#### タイムスタンプの差の計算

https://qiita.com/kawada2017/items/8e1291801aacf5427e7d

#### よく使う「日付と時間」関数

https://qiita.com/Makimaki2020/items/72e3b774039327fa4ac4

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/private/4bf813e6cba84b2a1008
画面フローにレコードのIdを渡す


+ [recordIdで取得ができません](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000KAaes)

:::note
画面フローですがURLを指定して起動させていますか？

そうであれば、変数としてrecordIdを指定してレコードのIdをパラメータとして記述していますか？

```
/flow/Create_Case_for_Contact?recordId={!Account.Id}
```

変数値を設定するようにフロー URL をカスタマイズ 
https://help.salesforce.com/s/articleView?id=sf.flow_distribute_internal_url_variable.htm&type=5
:::

この方法しかないと思っていたけど

recordIdという入力可能な変数だったら、アクションでそのまま使えるみたい

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/ce6669e8-48c7-4892-8eb1-bfd79ef77186.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/843096f5-35aa-4134-9906-5ca94def42cf.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/efeb8b7f-963b-4634-91e3-01c4daea12fc.png)
QNAP NASにOpenVPNで接続でちょっとハマった

「VPN経由で自宅と同じような感覚でNASにアクセスしたい」けどできないと相談を受けて調査した結果をメモ
技術的にハマった、ではなくって現状把握にはまった、という話

---
## ヒアリング内容

- **目的**：自宅のNAS（QNAP TS-231K）に、VPN経由で外部からアクセスできるようにしたい  
- **使用回線**：SoftBank光（ルーター一体型ONU）  
- **NASの状態**：QNAP公式アプリからはVPN接続できている  
- **要望**：OpenVPNでの接続（エクスプローラ風にアクセスしたい）  


---

## 環境の整理と対応方針

### 自宅ネットワーク構成（調査実施前にヒアリング）

- ONU一体型ルーター（SoftBank光。型番不明）  
- NAS（QNAP TS-231K）がLAN内に固定IPで接続  
- ポート開放設定は不明。してないと予想し、ここを重点的に調べようと。

### 方針
- **VPN方式**：OpenVPN（QNAPで.ovpn生成）  
- ソフトバンクルータを生かす(試行錯誤の中でTP-Link AX80も買ったけど、できればこっちで)

### 手順概要（想定していた手順）

1. QNAPでVPN Serverアプリを有効化  
2. ルータのポート1194を開放してNATてんそ  
3. OpenVPN設定をエクスポート（.ovpnファイル）し、OpenVPNクライアントにインポートして接続  
4. 接続後、`net use * \\[NASのローカルIP]\Public`でアクセス。  
5. エクスプローラからNASがネットワークドライブ（Zドライブ）として認識されることを確認  

---

## Windowsからの接続（確認用）

### 使ったツール

- OpenVPN GUI（Windows版）  
  https://openvpn.net/community-downloads/

- ポート開放確認サイト
  https://www.cman.jp/network/support/port.html
---

## トラブル内容と対応整理

- **Q：VPN接続できてもNASが見えない？**  
  → **A**： 蓋を開けてみれば、ソフトバンクではなくTP-Linkルータをつなげた状態だった。そしてQNAPとTP-Linkルータの両方でOpenVPN設定を有効にしていたため、切り分けに時間がかかっただけで、設定自体はほぼできていた状態。全体のVPNの構成の確認をいまいちど整理してクリアに（基本を忘れていた自分の愚かさ再認識）。
✅ 「ルータがOpenVPNサーバ」→ ルータのポート1194を開放
✅ 「QNAPがOpenVPNサーバ」→ NAT転送で UDP 1194 → QNAPのローカルIP へ転送する
どちらがいいか相談して今回はルータをOpenVPNサーバすることにした。

:::note info
TP-Link AX80のOpenVPNはユーザ指定なし。
QNAP TS-231KのOpenVPNはユーザ指定あり。NASユーザ追加して、そのユーザにOpenVPNの権限を与える方式。
:::


---

## 結果と今後

- WindowsエクスプローラからNAS共有フォルダへ接続成功でめでたし
- 今後はMacの音楽制作ソフトからNAS上の音声ファイルに直接アクセス可能になれば。
- DDNSも設定したほうがよいかも。


---

## おまけ：今回使ったWindowsコマンドメモ

```bash
# NASの疎通確認
ping [NASのIPか、名前]

# ネットワークドライブのマウント
net use * \\[NASのIPか、名前]\[設定した共有フォルダ名]

# ネットワークドライブのマウント（ドライブ指定したいなら）
net use Z: \\[NASのIPか、名前]\[設定した共有フォルダ名]
Golang学習記録1日目　TodoCLIアプリの作成

## 学んだこと

Golangの標準ライブラリflagを使って、コマンドライン引数を受け取る方法



### flagの使いかた
flag.Boolの使い方に少し戸惑った。ブール型のフラグを定義する。コマンドラインでは、変数名だけの時はtrueになり、別途明示的に、=false,=trueと記述できる。文字列や数値はパースエラーとなった。

```
func main(){
 hoge := flag.Bool("hoge", false, "hoge argument")
 fuga := flag.Bool("fuga", false, "fuga argument")
 flag.Parse()
 fmt.Println("hoge3",*add)
 fmt.Println("hoge4",*list)
}

go run . -hoge=true -fuga
hoge true
fuga true
```
また、flag.Parse()は一度だけ呼び出す必要がある（自分は２回呼び出そうとして、エラーになりました）


### deferの使いかた
deferはGoの制御構文の一つで、関数の実行を遅延するために使う。deferを使って指定した関数は、現在の関数が終了する直前に実行される。


### jsonタグの使いかた
jsonタグは、Goの構造体フィールドに付けるタグで、JSONのエンコードやデコード時に使用されるキー名を指定するために使う。

json:`"-"`と指定すると、そのフィールドがJSONエンコード・デコードから除外される。
json:`hoge,omitemmpty`と指定すると、そのフィールドの値がゼロ値（空文字列、0,false,nilなど）の場合、そのフィールドをJSONに含めない。

### エラーの中身を判定する方法
GOを勉強していると、以下のような記述をよく目にする。
```
if err != nil{
// 具体的な処理
}
```
もっと詳細にエラーハンドリングをしたいとき、osパッケージに以下のようなものがある。
```
// エラーが「ファイルやディレクトリが存在しない」ことを示すかどうか
os.IsNotExist(err)
// エラーが「許可されていない操作」や「アクセス権限がない」ことを示すかどうか
os.IsPermission(err)
```
必要に応じて、適切にエラーハンドリングをしていきたい。
また、fmt.Errorfでエラーメッセージを出力しようとしたときに、メッセージの末尾にピリオドを入れたら、警告が表示された。どうやら、Goのスタイルガイドでは、エラーメッセージの文字列は句読点で終わらないようにすることが推奨されているらしい。

### スライスから要素を削除する方法
追加するときはappend()メソッドを使えばいいが、削除するときはremove()のようなメソッドはないらしい。


今回作成したコード
https://codesandbox.io/p/sandbox/github/codesandbox/sandbox-templates/tree/main/go
ディスプレイについて

## ディスプレイについて
### 有機ELディスプレイ
電圧をかけて発光素子を発光させて表示する。

### ブラウン管ディスプレイ
電子ビームが発光体に衝突して生じる発光で表示する。

### 液晶ディスプレイ
透過する光の量を制御することで表示する。

### プラズマディスプレイ
放電によって発生した紫外線で、蛍光体を発光させて表示する。
[EKS] ASGにEC2はいるのにkubectl get nodesで出てこない問題と、その原因がまさかのNATだった件

はじめに

本番運用しているEKSクラスタで、ある日突然次のような状態になりました。
	•	kubectl get nodes に何も表示されない
	•	kubectl get pods の結果では、Podがずっと Pending
	•	でも、Auto Scaling Group（ASG）にはEC2インスタンスが正常に存在している

…え、なにこれ？

⸻

原因を探る

まず疑ったのは以下のような基本的なチェックポイントです：
	•	kubelet がちゃんと起動しているか（journalctl -u kubelet）
	•	EC2のIAM RoleにEKS関連のポリシーが付いているか
	•	TLS証明書が期限切れになっていないか
	•	古いノードが再登録されていないか

しかし、どれも該当せず。

⸻

犯人はNATだった

最終的に辿り着いた結論は…

NATインスタンスが死んでいた

EKSのノード（EC2）はプライベートサブネットにいて、外部インターネットへはNATインスタンス経由で通信する構成。
そのNATが落ちていたため、ノードがEKS APIサーバー（外部）にアクセスできず、クラスタに登録されていなかったわけです。

⸻

NAT障害で起きることまとめ
	•	kubelet がクラスタ登録に失敗
	•	Podネットワーク（CNI）の初期化が失敗
	•	ECRからコンテナイメージをpullできない
	•	yumやcurlなど外部アクセスもすべて死ぬ

結果、見た目上はEC2が正常に起動してるのに、EKSではノードとして認識されないという現象になる。

⸻

一時的な対応

問題のEC2をASGからデタッチ → 新しいノードを立て直すことで回復。
が、根本はNATだったので再発防止が必須。

⸻

監視対策：Slack通知スクリプト

監視スクリプトで異常検知 & Slack通知するようにして、次回からはすぐ気づけるようにしました。

1. サイトの疎通確認

``` 
#!/bin/bash
URL="https://your-service.example.com"
SLACK_WEBHOOK="https://hooks.slack.com/services/xxx/yyy/zzz"

STATUS=$(curl -s -o /dev/null -w "%{http_code}" $URL)

if [ "$STATUS" -ne 200 ]; then
  MESSAGE="🚨 サイトが応答していません！HTTPステータス: $STATUS ($URL)"
  echo "$(date): $MESSAGE" >> /var/log/eks-site-health.log
  curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$MESSAGE\"}" "$SLACK_WEBHOOK"
fi
``` 


2. ノードのReady状態確認

``` 
#!/bin/bash
SLACK_WEBHOOK="https://hooks.slack.com/services/xxx/yyy/zzz"

READY_NODES=$(kubectl get nodes --no-headers | grep -c " Ready")

if [ "$READY_NODES" -eq 0 ]; then
  MESSAGE="❗️EKSクラスタにReadyノードが存在しません！"
  echo "$(date): $MESSAGE" >> /var/log/eks-nodes.log
  curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$MESSAGE\"}" "$SLACK_WEBHOOK"
fi
``` 



⸻

再発防止のポイント
	•	NATインスタンスではなくNAT Gatewayを使う（マネージド＋高可用性）
	•	サブネットのルートテーブルを定期的に確認
	•	NATの死活監視も追加（例：外部のECR 
まとめ
	•	「ASGにはEC2あるのに、EKSのノードが見えない」問題の原因は意外とNAT障害かも
	•	kubeletやIAMだけじゃなく、ネットワークの出口（NAT）も要チェック
	•	監視スクリプト＋Slack通知で素早く気付ける体制を
個人的備忘録：CloudFormationでCloudFrontのHostedZoneIdを設定ミスしてハマった話を整理してみた

## はじめに
本記事では、CloudFormationでS3 + CloudFront + Route53を組み合わせて構成する際に、CloudFrontのHostedZoneIdに関する設定ミスによって発生したエラーとその解決方法について解説します。

***個人の備忘録程度の走り書きとなっておりますが、温かい目で見守っていただければ幸いです。***

## 書こうと思ったきっかけ
CloudFrontをAlias設定付きでRoute53に紐付ける際、誤ってRoute53のホストゾーンIDを指定してしまい、CloudFormationのスタック作成に失敗するエラーに遭遇しました。同じミスを防ぐためにも、原因と正しい設定方法をまとめておこうと思い、この記事を書くことにしました。

---

## 問題の原因まとめ
CloudFormationでCloudFront + Route53を組み合わせる際に、`AliasTarget.HostedZoneId` に **誤ってRoute53のホストゾーンID** を指定していたことが原因で、エラーが発生していました。

```yaml
# 誤りの例
AliasTarget:
  HostedZoneId: xxx  # ← Route53のHostedZoneIdを指定してしまっている
  DNSName: !GetAtt CloudFrontDistribution.DomainName
```

### 発生するエラー例
```
Resource handler returned message: "Invalid request provided: Cannot use Route53 HostedZoneId as AliasTarget for CloudFront distribution. Use CloudFront HostedZoneId instead." (RequestToken: ...)
```

正しくは、**CloudFront固有のHostedZoneIdを指定**する必要があります。

---

## 正しい設定（CloudFront用のHostedZoneId）
CloudFrontでは、全リージョン共通で次の固定値を使用すると思っています

```yaml
AliasTarget:
  HostedZoneId: Z2FDTNDATAQYW2  # CloudFront用の固定値
  DNSName: !GetAtt CloudFrontDistribution.DomainName
```

- `Z2FDTNDATAQYW2` は CloudFront 全体に共通の HostedZoneId です。
- この値は固定されており、AWSドキュメントにも明記されています。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/quickref-route53.html

---

## CloudFrontのHostedZoneIdはどこで確認する？
CloudFront の HostedZoneId は、
- **すべてのディストリビューションで共通の固定値**であり、
- 自分で調べたり変更したりする必要はありません。

### CloudFrontの固定 HostedZoneId
| リソースタイプ | HostedZoneId       | 備考                     |
|----------------|--------------------|--------------------------|
| CloudFront     | `Z2FDTNDATAQYW2`   | 全リージョン共通、固定値 |

https://qiita.com/kobanyan/items/2e8001ce393a6c426861

---

## まとめ
CloudFrontのAlias設定時には、Route53のホストゾーンIDではなく、CloudFront用の固定HostedZoneId（`Z2FDTNDATAQYW2`）を使用する必要があります。

この設定ミスは初心者が陥りやすいポイントのひとつですが、あらかじめ理解しておくことでスムーズに構築作業を進めることができるかと思います...！
競技プログラミングで使えそうなクラス

**基本的な使い方**
```python
from collections import Counter

# 文字列やリストを渡すだけで、要素ごとの出現回数をカウント
c1 = Counter("abracadabra")
print(c1)
# Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})

c2 = Counter([1,2,2,3,3,3])
print(c2)
# Counter({3: 3, 2: 2, 1: 1})
```

**主要メソッド**
* ```elements()```
    各要素をカウント分だけ列挙するイテレータを返す。
```pytohn
list(c2.elements())  # [1, 2, 2, 3, 3, 3]
```
* ```most_common()```
```python
c1.most_common(2)  # [('a', 5), ('b', 2)]
```
* ```update(iterable_or_counter)```
追加で要素をカウント。引数にイテラブルか他の Counter。
```python
c = Counter()
c.update("abc")
c.update(["a","b","b"])
print(c)  # Counter({'b': 3, 'a': 2, 'c': 1})
```
* ```subtract(iterable_or_counter)```
他と同様に要素の出現数を減算。マイナスの値も保持される点に注意。
```python
c = Counter(a=3, b=1)
c.subtract(Counter(a=1, b=2))
print(c)  # Counter({'a': 2, 'b': -1})
```

**四則演算・集合演算**
* 足算・引き算・掛け算・割り算でほかの```Counter```と組み合わせ可能
```python
c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2, c=4)

print(c1 + c2)  # 足し算: Counter({'c': 4, 'a': 4, 'b': 3})
print(c2 - c1)  # 差: 出力は正の部分のみ Counter({'c': 4, 'b': 1})
print(c1 | c2)  # 同一キーの最大値を取る: Counter({'c': 4, 'a': 3, 'b': 2})
print(c1 & c2)  # 同一キーの最小値を取る: Counter({'a': 1, 'b': 1})
```

**典型的なユースケース**
```python
words = "this is a test this is only a test".split()
freq = Counter(words)
```
【Kotlin × Minecraft】開発中のプラグインをワンクリックで楽にリロードする

# はじめに
開発中のプラグインを、**サーバーを再起動せずにワンクリックでリロードできる環境**を構築したので、メモを兼ねて記事にします。  
これはあくまで「自分なりの方法」です。もっと良い方法や最適解があるかもしれませんが、同じような悩みを持つ方の参考になれば嬉しいです。

# やりたかったこと
- プラグインをビルドしたら、自動でテスト用サーバーにコピーされる
- サーバーを再起動せずにプラグインをリロードできるようにする

# やったこと

## 1. PluginManager の導入
まずは [PluginManager](https://www.spigotmc.org/resources/pluginmanager.69061/) をサーバーに導入します。  
私の技術力では、**プラグインを完全に再読み込みする処理を自前で作るのは難しかった**ため、この便利なプラグインに頼ることにしました。

この PluginManager を使えば、**サーバーを再起動せずに対象のプラグインをリロードすることができます**！

## 2. 更新通知プラグインの開発・導入
[AutomaticCreatingPluginUpdate](https://github.com/ringoame196-s-mcPlugin/AutomaticCreatingPluginUpdate) というプラグインを自作し、サーバーに導入しました。

### このプラグインの機能：
- HTTPリクエストを受け取ると、対象のプラグイン名を取得
- 該当プラグインのリロードコマンドを組み立て
- チャットに「クリック可能なリロードコマンド」を送信

つまり、「チャットからワンクリックでプラグインをリロードできる」仕組みを作っています！

### 裏話（失敗談）
本当は「リクエストを受け取った瞬間にリロード処理まで自動でやりたかった」のですが、技術不足により断念しました。今後の課題です。

## 3. build.gradle.kts でコピー & リクエスト送信

ビルド時に自動で
- JARファイルをテストサーバーにコピー
- HTTPリクエストを送信して、チャットにリロードコマンドを表示

という処理を追加しました。

ポート番号は、AutomaticCreatingPluginUpdateで指定したものと同じにしてください

（自分の環境では、開発端末とテストサーバーが別端末なので、Samba 経由でコピーしています）

<details>
<summary>build.gradle.kts の例</summary>

```kotlin
tasks.named("build") {
    // プラグインを特定のパスへ自動コピー
    val copyFilePath = "" // コピー先のフォルダーパス
    val copyFile = File(copyFilePath)
    if (copyFile.exists() && copyFile.isDirectory) {
        doFirst {
            copy {
                from(buildDir.resolve("libs/${project.name}.jar"))
                into(copyFile)
            }
        }
        doLast { // AutomaticCreatingPluginUpdate連携
            // APIリクエストを行う
            val port = // テスト鯖のポート
            val ip = "" // テスト鯖のIPアドレス
            val apiUrl = "http://$ip:$port/plugin?name=${project.name}"
            val url = URL(apiUrl)
            val connection = url.openConnection() as HttpURLConnection

            try {
                connection.requestMethod = "GET"
                connection.connect()

                // レスポンスコードを確認
                if (connection.responseCode == HttpURLConnection.HTTP_OK) {
                    val response = connection.inputStream.bufferedReader().use { it.readText() }
                    println("API Response: $response")
                } else {
                    println("Failed to get response: ${connection.responseCode}")
                }
            } catch (e: Exception) {
                e.printStackTrace()
                println("Error during API request: ${e.message}")
            } finally {
                connection.disconnect()
            }
        }
    }
}
```
</details>

# さいごに
このように、PluginManager + 自作通知プラグイン + Gradle連携という形で、かなり快適な開発環境を整えることができました。

最終目標は、「1つのプラグインだけで JAR コピーからリロードまで完結する」ことです！
今後も引き続き改善していきたいと思います。
PowerPointの「ファイル内のイメージを圧縮しない」に既定でチェックを入れるレジストリの編集をPowerShellで実装

ファイル＞オプションの「ファイル内のイメージを圧縮しない」に常にチェックを入れる設定  

手動でレジストリキーの編集するときの手順は以下：  
https://answers.microsoft.com/en-us/msoffice/forum/all/how-to-disable-image-compression-permanently-and/8916e64d-f515-4345-98f6-6cffcc4d9883  

これはPowerShellでも以下の手順で実行できる
```powershell
$regPathEditcom = "HKCU:\Software\Microsoft\Office\16.0\PowerPoint\Options"

# 現状の設定確認（"AutomaticPictureCompressionDefault"がないことを確認）
Get-ItemProperty -Path $regPathEditcom

# 設定の更新
Set-ItemProperty -Path $regPathEditcom -Name "AutomaticPictureCompressionDefault" -Value 0 -Type DWord
```
参考にしたページ：
https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.management/set-itemproperty?view=powershell-7.5
sqが便利だったので軽くメモ

## これは何
DB版jqみたいなツール[sq](https://sq.io/)が便利だったので紹介する記事

コードは以下のリポジトリにて公開されている

https://github.com/neilotoole/sq

## 何ができる
データベースに対してinspect, query, join, import, exportができる

## どういう時に使う
- 手元にあるCSVファイルに対して検索をかけたいとき
  - これは単一のファイルに対してもできるし、複数ファイルまたいでjoinして検索とかもできる
- DBから取り出したデータをファイル出力してチームで共有したいとき

## その他
- [mikefarah/yq: yq is a portable command-line YAML, JSON, XML, CSV, TOML and properties processor](https://github.com/mikefarah/yq)
- [yq | yq](https://mikefarah.gitbook.io/yq)
- [jqのyaml版コマンド yq は2種類ある - つばくろぐ @takamii228](https://takamii.hatenablog.com/entry/2020/04/05/163748)
【OracleDB】PLSQLの%TYPE属性を指定していたらADBのアプデでエラーになった

# はじめに
本日、システムを利用するとシステム処理が【ORA-06552: PL/SQL: Compilation unit analysis terminated】とコンパイルエラーを吐いて実行できない状態となっていました。

原因としては、【ADBS-25.4.3.2】のアップデートがAutonomousDBに先週末行われているのですが、それによってプログラムのどこかに問題が発生し、コンパイルエラーが発生している状況でした。

何が問題なのかを洗い出していったところ、思わぬところでエラーとなっていました。

# PLSQLの%TYPE属性でエラー

エラーとなっていたのは、以下の2か所でした。
l_chid conversation_history.CHID%TYPE;
l_answer conversation_history.ANSWER%TYPE;

どちらも、テーブルの文字列項目を参照するように指定していただけでそれ単体では問題とはいえない箇所でネットやChatGPTで調べてもシステムのエラーからこの2つは洗い出せませんでした。

ただし、エラーの内容にVector型の項目をコンパイルする際にエラーとなっていると表記されており、テーブルにかかわる部分に問題があるとわかりました。

その為、今回の問題として先週のアップデートにより該当のテーブルにVector型が存在する状態で%TYPE属性を指定するとVector型の判断ができずにエラーとなっていたようです。

以下のように文字列として変数を書き換えて、処理を実行することでコンパイルが通るようになりました。

**l_answer  VARCHAR2(32767);**
**l_chid   VARCHAR2(32767);**


# 先週までは何も問題なかった
今回の事象で何が最も恐怖だったのかといえば、先週末までは動作しており突如としてコンパイルエラーとなっていた点です。

ADBのメンテナンスは、1週間前に実行することが可能であり、そこで検証することが大切であることを知りました。

# まとめ
ADBは、自動でアップデートを行ってくれる為、助かる反面こうしたアップデートによる問題も考慮した対応が必要です。

また、こうした%TYPE型で影響が出るなどの問題はこうして共有して情報を早く得られるようにしていきたいと思います。
4年間のデータ基盤スタートアップ創業記録：データベースPhDからの教訓

今月（2025年4月）で、私が[RisingWave](https://risingwave.com/)の開発を始めてから4年と1か月が経ちました。

![RisingWaveを中心としたエンドツーエンドのリアルタイムデータスタックの概念図](https://miro.medium.com/v2/resize:fit:1400/0*SeQK72xgkZYYGu5I.png)

信じられないことですが、私たちは生き残っただけでなく、実際には繁栄するまでになりました。毎月、私たちの予想を上回るスピードで成長し続けているのです。高い成長を維持することはデータインフラ企業にとって決して容易ではありません。特にAIブームの最盛期にはなおさらです。私はそのことを決して当たり前だと思ったことはありません。振り返ってみると、時間が私に教えてくれた教訓がいくつかあります。

## **時間を味方につける**
データインフラを構築するのは過酷です。どんなに頑張っても、最初の数年間は虚空に向かって叫んでいるように感じられるものです。人々はあなたを信頼してくれません。それは、あなたが間違っているからではなく、単に「早すぎる」のだと思われているからです。しかし、時間があなたの味方で、自分が構築しているものを信じているのであれば、そのまま進み続けてください。

私たちがRisingWaveの開発を始めた当初から、基本原則は明確でした。それは、Postgres互換性を備え、主要ストレージとしてS3を用いることで、ストリーム処理を民主化することです。4年が経過した今でも、この設計は時の試練に耐えうるものだと信じています。

そして何よりも、まだそれが明白になる前にあなたを信頼してくれたすべての顧客を大切にしてください。

## **Be water**

適応せよ。

AIブームが到来したとき、私たちはすべてを見直しました。「データインフラは市場にまだ必要とされているのか？」「AIに方向転換すべきか？チャットボット、エージェント、その他もろもろに？」

私たちの答えはこうでした：私たちはデータインフラ企業であることを誇りに思っています。でも、それは現状維持を意味するものではありません。

私たちはGo-To-Market（GTM）戦略をゼロから完全に作り直しました。Google広告はやめました。その代わりに、AIをマーケティングおよび営業ワークフローに組み込みました。私たちは高品質なコンテンツとGitHubでの存在感に賭けたのです。もし従来のやり方で成長を追い続けていたら、投資対効果（ROI）は崩壊していたことでしょう。

## **Ride the wave**

数か月ごとに、私は自分自身に問いかけます。「次に来るのは何だろう？3か月後、6か月後、1年後には？」

2年前、その答えは明確でした。「最高のストリーム処理エンジンになること」。そして、私たちはそれを成し遂げたと思います。

しかし、ゲームは変わりました。Iceberg がデフォルトのテーブルフォーマットとなったのです。誰もが Iceberg ベースのレイクハウスを構築したがっています──だから、私たちは全力でそこに舵を切りました。

私たちはモノリシックなオールインワンのレイクハウスを構築しているわけではありません。私たちが賭けたのは「オープンネス（開放性）」です。私たちの役割は、ユーザーが自分たちのレイクハウスを構築するハードルを下げる手助けをすることです。データの取り込み、変換、ストレージ最適化を私たちが担い、ユーザーは好きなクエリエンジンを持ち込めばいいのです。

今や、Iceberg は RisingWave における最重要のデータ出力先となりました。そして、それによって私たちの可視性は急速に高まっています。


## **Conclusion**

振り返ってみると、私は幸運だったと感じます。しかし、幸運はただ待っていても現れません。居続けること、一貫性を保つこと、そして変化に対して開かれていること──それがあって初めて、幸運はやってくるのです。

だから、もしあなたがデータインフラを構築しているのなら──あるいは、2025年のAI不安スパイラルに巻き込まれているのなら──慌てないでください。

長期目線でいきましょう。柔軟であり続けましょう。そして、波に乗るのです。
個人的備忘録：Git commitでエラー！index.lockファイルを削除して解決してみた

## はじめに

Gitでコミットしようとした際に、以下のようなエラーに遭遇することがあります。

```
fatal: Unable to create '/Users/ユーザー名/Desktop/プロジェクト名/.git/index.lock': File exists.

Another git process seems to be running in this repository, e.g.
an editor opened by 'git commit'. Please make sure all processes
are terminated then try again. If it still fails, a git process
may have crashed in this repository earlier:
remove the file manually to continue.
```

これは、Gitが一時的に使用するロックファイル `index.lock` が残ってしまっていることで発生するエラーです。本記事では、その原因と対処法について解説します。

## 書こうと思ったきっかけ

ローカルで作業中に、普段通り `git commit` を使おうとしたところ、このエラーに遭遇しました。

:::note warn
***原因がわからず戸惑ったため、備忘録として整理しておこうと思い、この記事を書きました。***
:::

同じようにGitのロックファイルで困っている方の参考になれば幸いです。

## 解決方法

エラーメッセージにもあるように、まず確認すべきは「他のGitプロセスが動いていないか」です。以下の手順で対応できます。

### ステップ1：Gitプロセスが動いていないか確認
```bash
ps aux | grep git
```
他にGit関連プロセスが動いていないことを確認します。

### ステップ2：ロックファイルを削除
```bash
rm -f .git/index.lock
```
Gitリポジトリのルートディレクトリに移動し、上記コマンドでロックファイルを削除します。

### ステップ3：再度コミットを実行
```bash
git commit -m "変更"
```
これでエラーが解消され、正常にコミットできるはずです。

## まとめ

- `index.lock` はGitの排他制御に使われる一時ファイルです。
- Gitプロセスが途中でクラッシュした場合などに残ることがあります。

このエラーは初見だと驚きますが、原因と対処法がわかれば難しいものではありません。トラブルに直面したときは、冷静に一つずつ確認してみてください...！
macOSのpyenvでTkinterが正しく使えるようにビルドする方法

macOSのpyenvを使うと、Tkinterが正しく動かないことが多いのです。

正しくインストールするポイントは、次の通り：

- `tcl-tk@8`をインストールすること
- ビルド時の変数に`tcl-tk@8`へのパスを追加すること

2025/04/21の時点で、下記のようにインストールするとうまくいきました。

### 1. 依存パッケージをインストール

```sh
brew install openssl readline sqlite3 xz zlib
brew install tcl-tk@8  # バージョン9.0に問題があるので @8 を明示
```

なお、コマンド「`brew pin tcl-tk@8`」を実行しておくと、tcl-tkのアップグレードを抑止できます。​

### 2. シェルに追記（例: ~/.zshrc）

```sh
export PATH="$(brew --prefix tcl-tk@8)/bin:$PATH"
export CPPFLAGS="-I$(brew --prefix tcl-tk@8)/include"
export LDFLAGS="-L$(brew --prefix tcl-tk@8)/lib"
export PKG_CONFIG_PATH="$(brew --prefix tcl-tk@8)/lib/pkgconfig"
```

### 3. Python をビルド

```sh
env PYTHON_CONFIGURE_OPTS="--enable-framework" \
    pyenv install 3.9.22
```

### 4. 動作確認

```sh
pyenv global 3.9.22
python -m tkinter
```

### オプション

Pythonで最も簡単にGUIが作成できるパッケージ[TkEasyGUI](https://note.com/kujirahand/n/n33a2df3aa3e5)をインストール！

```sh
pip install -U TkEasyGUI
python -c "import TkEasyGUI as eg; eg.popup('hi')"
```

というのも、Python3.9で、TkEasyGUIが動かないと報告があったので、試行錯誤してインストールしました。
「【初心者向け】JavaScriptの変数宣言（const / let / var）の違いまとめ」

## はじめに
初心者の勉強用の備忘録として、
JavaScriptの変数宣言 `const`、`let`、`var` の違いについてまとめました


## 結論

- **基本は `const` を使う**
- **再代入が必要なときだけ `let`**
- **`var` は使わない**

## 詳細
## 用語

| 用語     | 意味                                                                 |
|----------|----------------------------------------------------------------------|
| **宣言** | 新しく変数を作ること。例：`let x = 1;`                                   |
| **代入** | 宣言で作成した変数（箱）に値を入れること例：`let x = 1;x = 2;`    |                     
| **再代入** | 一度宣言した変数を更新すること。例：`x = 3;`（初回の代入後に行う） |
| **再定義** |同じ名前の変数を、再び `let` や `const` で宣言し直すこと。例：`let x = 1; let x = 2;`（←これはエラーとなる） ||

---
#### const
- 再代入できない
- 再定義もできない
- 値を固定したいときに使う
- ブロックスコープ
ブロック({})内で定義した変数はブロックスコープ内でのみ参照可能。
⇒関数スコープ同様にスコープの外側から参照すると例外が発生する。

【再代入】
```js
const test = "代入1回目";
test = "代入2回目"; //エラーになる
```
【関数スコープ】
```js
function test() {
  if (true) {
    const x = 1;
  }

  console.log(x); // エラー：x is not defined
}

test();
```

#### let
- 再代入は可能
- 再定義は不可
- 初期値なしで宣言できる
- constと同じくブロックスコープ

【再代入】
```js
let test = "代入1回目";
test = "代入2回目"; //実行可能
```
```js
function test() {
  if (true) {
    let x = 1;
  }

  console.log(x); // エラー：x is not defined
}
test();
```
 ＞初期値なしで宣言できる
```js
let x; // 初期値なし
x = 1; // 後で代入
```
#### var
- 再代入可能
- 再定義可能
- 関数スコープ（関数内で有効、ブロックスコープなし）
- 現代のJavaScriptでは基本的に非推奨
⇒const や let が導入される以前は var しかなく、
そのため古いコードでは使用されているが、新しいコードでは非推奨

【再代入】
```js
var test = "宣言1回目";
test = "宣言2回目";//実行可能
```
【関数スコープ】
```js
function test() {
  if (true) {
    var x = 1;
  }

  console.log(x); // 1（関数スコープなのでここでも見える）
}

test();
```

#### 参考文献
https://qiita.com/andota05/items/1233b147f4f96bd53646
https://magazine.techacademy.jp/magazine/14872
https://www.youtube.com/watch?v=4NPrR_szrUM&t=345s
https://typescriptbook.jp/reference/values-types-variables/let-and-const
https://tech-dream.school/archives/467
https://qiita.com/takuo_maeda/items/90d5152cc31e26d9d17b
新人エンジニアの備忘録

プログラムに書く際には１～１０まで丁寧に書くのではなく１～１０の１を１０に細分化して書くということを意識する。
自分のイメージとしてはプログラムを人間の身体で例えてまずは手から作る。
手を作るためにはじゃあまずは手の骨を作り、爪を作り指を作り、関節を作り、という風に各部位をさらに細かい部位に分けていく。
本当にもう分けることが不可能になるまで細分化したらそれをコードとして書くというのがいい。
各部位を組み合わせて最終的に身体にする。
個人的備忘録：CloudFrontのキャッシュを無効化する方法まとめ（手動・CLI対応）

## はじめに

CloudFrontは、ウェブサイトやアプリケーションのコンテンツをエッジロケーションにキャッシュして高速配信を実現するCDNサービスです。

:::note warn
***しかし、S3などのオリジン側でファイルを更新した際、CloudFrontのキャッシュが残っていると古いファイルが配信されてしまいます。***
:::

そこで重要なのが、キャッシュの"無効化"操作です。

## 書こうと思ったきっかけ

CloudFrontにキャッシュされた古いデータが、S3上での修正を反映せずに表示されて困った経験がありました。その際にAWS CLIを用いたキャッシュ無効化（Invalidation）の方法を調べ、実際に試してみて無事に解決できたため、手順を記録しておこうと思い記事化しました。

## CloudFrontキャッシュの削除方法

CloudFrontのキャッシュは、以下の方法で削除（無効化）できます。

### 方法1：AWSマネジメントコンソールから無効化

1. AWSマネジメントコンソールにログイン
2. CloudFrontサービスを開く
3. 対象のディストリビューションIDをクリック
4. 左メニューの「Invalidations（無効化）」を選択
5. 「Create Invalidation」をクリック
6. パスを入力（例：`/*` で全削除）
7. 「Invalidate」ボタンで作成

数分以内に無効化が完了します。

![Screenshot 2025-04-21 at 16.24.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/f31e593c-0d58-41e8-87f4-6703862cfe71.png)

### 方法2：AWS CLIから無効化（自動化向き）

```bash
aws cloudfront create-invalidation \
  --distribution-id xxx \
  --paths "/*"
```

出力例：
```json
{
  "Location": "https://cloudfront.amazonaws.com/...",
  "Invalidation": {
    "Id": "xxx",
    "Status": "InProgress",
    "CreateTime": "2025-04-21T01:38:14.503000+00:00",
    "InvalidationBatch": {
      "Paths": {
        "Quantity": 1,
        "Items": ["/*"]
      },
      "CallerReference": "cli-..."
    }
  }
}
```

### ステータスの確認

```bash
aws cloudfront get-invalidation \
  --distribution-id xxx \
  --id xxx
```

`Status`が `Completed` になっていればキャッシュ削除完了です。

## まとめ

CloudFrontは強力なCDNですが、キャッシュが原因で最新データが反映されないケースもあります。

:::note alert
***そうした場合は、CLIやコンソールからのキャッシュ無効化操作が非常に有効です。***
:::

特に頻繁にコンテンツが更新されるサイトでは、S3側のファイル名にバージョンを持たせる運用（例: `style-v2.css`）や、TTL設定の見直しも検討してみてください...！
令和7年応用技術者試験シラバス変更点

## シラバス変更点まとめ(chat gptによると)
​応用情報技術者試験のシラバスは、令和6年（2024年）秋期試験からVer.7.0に更新され、さらに令和7年（2025年）4月17日にはVer.5.4が公開されました。​これらの改訂により、出題範囲や用語の見直しが行われています。


主な変更点

<strong>1. セキュリティ分野の強化</strong>
セキュアバイデザイン：​従来の「セキュリティバイデザイン」に加え、「セキュアバイデザイン」という同義語が追加され、システムの企画・設計段階からセキュリティを確保する考え方が強調されました。

プライバシーバイデザイン：​プライバシー保護をシステム設計段階で組み込む概念が明示されました。​


<strong>2. AI・機械学習関連の追加</strong>
機械学習やAIに関する項目が新たに追加され、これらの技術の基本的な理解が求められるようになりました。​

point
令和7年春でもAIとか機械学習に関連する問題が散見されました。


<strong>3. 法令・用語の見直し</strong>
<strong>「プロバイダ責任制限法」</strong>が削除され、新たに<strong>「情報流通プラットフォーム対処法</strong>」が追加されました。




今後の学習のポイント
セキュリティ分野：​「セキュアバイデザイン」や「プライバシーバイデザイン」など、設計段階でのセキュリティ確保の考え方を理解し、関連する用語や概念を押さえましょう。

AI・機械学習：​基本的なアルゴリズムや応用例を学び、これらの技術がどのように活用されているかを把握することが重要です。

法令・用語の確認：​最新の法令や用語の変更点を確認し、試験で問われる可能性のある新しい内容に対応できるようにしましょう。​


これらの変更点を踏まえて、最新のシラバスに基づいた学習を進めることが、次回の試験合格への近道となります。


後自分が学習したりするうえで、追加するべき部分がありましたら、追記していきｍ
Git更新手順（コマンドver）

## Git更新手順（コマンドver）

ローカルブランチを最新の状態に更新する手順です。

### 1. 作業ブランチを確認する。

現在どのブランチで作業しているかを確認します。

```bash
git branch
```

（\*が付いているブランチが現在の作業ブランチです）

### 2. 更新元のブランチに移動する。

通常は `main` (旧 `master`) ブランチや `develop` ブランチなど、最新の状態を取り込みたいブランチに移動します。

```bash
git checkout <更新元branch名>
```

例：`main` ブランチに移動する場合

```bash
git checkout main
```

例：`develop` ブランチに移動する場合

```bash
git checkout develop
```

### 3. 移動できたか確認する。

移動が成功したか再度確認します。

```bash
git branch
```

（\*が付いているブランチが更新元のブランチになっていることを確認します）

### 4. 更新内容を確認する。

リモートリポジトリの最新の変更を取得しますが、ローカルブランチにはまだ反映しません。

```bash
git fetch
```

### 5. 問題がなければorigin/\<branch名\> (リモート追跡ブランチ) と \<branch名\> (ローカルブランチ) を一致させる。

リモートの変更をローカルブランチに取り込みます。

```bash
git pull
```

例：`origin/main` の変更をローカルの `main` ブランチに取り込む場合

```bash
git pull origin main
```

例：`origin/develop` の変更をローカルの `develop` ブランチに取り込む場合

```bash
git pull origin develop
```

### 6. 作業ブランチに移動する。

ご自身の作業ブランチに戻ります。

```bash
git checkout <作業branch名>
```

例：`feature/new-login` ブランチで作業していた場合

```bash
git checkout feature/new-login
```

### 7. 移動できたか確認する。

作業ブランチに戻れたか再度確認します。

```bash
git branch
```

（\*が付いているブランチがご自身の作業ブランチになっていることを確認します）

### 8. 更新内容をmergeする。

更新元のブランチ（最新の状態にした `main` や `develop` など）の変更を現在の作業ブランチに取り込みます。

```bash
git merge <更新元branch名>
```

例：`main` ブランチの変更を現在の作業ブランチにマージする場合

```bash
git merge main
```

例：`develop` ブランチの変更を現在の作業ブランチにマージする場合

```bash
git merge develop
```

これで、作業ブランチに最新の変更が反映されました。必要に応じてコンフリクトの解消などを行ってください。
個人的備忘録：ドメインに紐づくネームサーバーを調べるには？ nslookup -type=ns の基本を整理してみた

## はじめに
本記事では、ドメイン名のDNS情報を確認するためのコマンド「nslookup -type=ns」について解説します。

:::note info
**個人の備忘録程度の走り書きとなっておりますが、温かい目で見守っていただければ幸いです。**
:::

DNSの名前解決において、ネームサーバー（NSレコード）の情報を取得する場面で役立ちます。

## 書こうと思ったきっかけ
インフラ学習の一環としてDNS構成や名前解決の仕組みを学んでいた際に、「どのネームサーバーがこのドメインを管理しているのか」を確認したくなったことがきっかけです。その際に使用したのが `nslookup -type=ns` でした。

## nslookup とは
`nslookup` は、DNS（ドメインネームシステム）の名前解決情報を取得するためのCLIツールです。Windows、macOS、Linux いずれの環境でも使用できます。

**参考文献**

https://www.winserver.ne.jp/column/about_nslookup/

## NSレコードとは？
NSレコード（Name Serverレコード）は、ドメインの名前解決を行うネームサーバーの情報を格納しているDNSレコードです。あるドメインにアクセスしようとする際、どのネームサーバーに問い合わせるかを示す情報です。

**参考文献**

https://www.cloudflare.com/ja-jp/learning/dns/dns-records/dns-ns-record/

## コマンド構文
```bash
nslookup -type=ns <ドメイン名>
```

## 使用例
```bash
nslookup -type=ns example.com
```
このコマンドを実行すると、`example.com` を管理しているネームサーバーの一覧が表示されます。

### 出力例：
```
Server:  8.8.8.8
Address: 8.8.8.8#53

Non-authoritative answer:
example.com     nameserver = ns1.exampledns.com.
example.com     nameserver = ns2.exampledns.com.
```

## 補足：よく使うオプション
- `server <DNSサーバー>` : 指定したDNSサーバーに問い合わせたいときに使用します。
  ```bash
  nslookup -type=ns example.com 8.8.8.8
  ```

## まとめ
`nslookup -type=ns` コマンドは、ドメインに紐づくネームサーバーの情報を確認したいときに非常に便利です。

インフラ構築やドメイン設定、トラブルシューティングの現場で活用する場面が多いため、基本的な使い方を覚えておくと役立ちます！
コード進行を入力するとローマ数字に変換してくれるWebアプリを作った

まあとりあえずこれを使ってくれや

https://summer498.github.io/chord-to-roman-list/

スクショはこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2676125/a0eeb8c1-459b-438c-94cc-8d598f41a918.png)

アルファベットで書かれたコード進行を入力すると、ローマ数字に変換されたものが出てきます。

# 考え方
コードをローマ数字記法に書き換えるには調がわかっている必要があります。
しかし、巷の曲は転調したり他の調からコードを借りてきたり[^1]と忙しいものです。
中には僅かな時間転調した後に戻ってこずに別の調へ行ってしまうものまであります。
例えば、DECO*27氏のゴーストルールでは半音上げ転調して1フレーズだけ歌った後で更にもう1回半音上げ転調します。
こんなことをされては調推定なんてめんどくさくてたまらない（でもカッコいい）。

そこで、調を推定せずに全部の調に対するローマ数字変換を出すことにしました。
コンピュータがあれこれ考えるのではなく、ユーザがローマ数字列を見て直感的に良さげなものを選べばいいのです。

# 実行可能性
ローマ数字変換を行う際にコードクオリティをそのまま表示する流派があります[^2]。
この流派の方法でローマ数字変換を行えば、音高（ピッチ）を表す部分を音度（ディグリー）に変換するだけで良くなります。
更に、この考え方を用いると、ダイアトニックコード以外のコードも統一的に変換できます。もはや構成音が1つも調に含まれない和音とかでも形式的に変換できます。[^3]

# 良さげな順にソートする
ここまで、雑に全てのキー候補に対してローマ数学変換を列挙する前提で考えてきました。
しかし、良さげな調を選択することを完全に諦めるわけではありません。
ある調に対する変換後のローマ数字列の中に臨時記号が含まれる場合は、その調は不適切である可能性が高いです。調の構成音中に臨時記号が含まれることはよくありますが、根音（ルート）に臨時記号がつくということはほぼ無いと言ってよいでしょう[^4]
従って、とりあえず変換後のローマ数字列中の臨時記号を数え上げて、少ない順にソートすることにしました。

# おわり
なんか不満点があったら [issue](https://github.com/Summer498/chord-to-roman-list/issues) 投げてください
直したくなったら[プルリク](https://github.com/Summer498/chord-to-roman-list/pulls)投げてください
気づいたときに対応すると思います。多分。
あと、音楽に詳しい人、マサカリお待ちしてます。これも気づいたときに直します

[^1]: 借用和音/モーダルインターチェンジ
[^2]: 逆に、そうではない流派としては、長和音(メジャーコード)を大文字で短和音(マイナーコード)を小文字で書く（文字 $m$ は消える）流派があります。クラシック分析を行う場合、こちらの方がよく使われます。
[^3]: 例えば、$\rm II\sharp m$ は $\rm IIm$ を半音上げたものなので全て長調の構成音から外れます。いきなり鳴らされたら最悪の響きですね。
[^4]: よくある例外として、例えば裏コードを考えるときに、 $\rm II_7-II\flat_7-I$ のように考えることがあります。
JSONシリアライズで空白、スペース値の文字列を無視する方法

## はじめに
CSVファイルのレコード一覧をもとに
APIを使って連携先システムのデータを一括登録・更新したいな～って時ありますよね？

また文字列型の項目にブランクやスペースが入っていた場合、
その値で更新されちゃわないか不安になるときありますよね…？

そんな方のために、
データをシリアライズする際に空白、スペース値が入っている項目を無視する方法を紹介します。
（ただの備忘録です）

## サンプルコード

JsonConvert.SerializeObject にオプション情報を追加しました。

```c#
        /// <summary>
        /// 文字列をシリアライズ化
        /// </summary>
        /// <typeparam name="T">独自クラスの定義</typeparam>
        /// <param name="obj">文字列</param>
        /// <returns>シリアライズ後の文字列</returns>
        private static string SerializeObject<T>(T obj)
        {
            var settings = new JsonSerializerSettings
            {
                NullValueHandling = NullValueHandling.Ignore, // Null値を無視
                ContractResolver = new CustomContractResolver() // カスタムリゾルバを使用
            };

            return JsonConvert.SerializeObject(obj, settings);
        }
```

オプションの設定は以下の通りです。

```C#
    /// <summary>
    /// シリアライズ化する際のオプション
    /// </summary>
    public class CustomContractResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            var property = base.CreateProperty(member, memberSerialization);
            if (property.PropertyType == typeof(string))
            {
                property.ShouldSerialize = instance =>
                {
                    var value = (string)property.ValueProvider.GetValue(instance);
                    return !string.IsNullOrEmpty(value); // 空白、スペース値を無視
                };
            }
            return property;
        }
    }
```
[PowerBI service] 組織内のメンバーへのアクセス許可

# 手順

1. `PowerBI service`を開く
1. `My Workspce`を開く
1. `Import`から`PowerBI Desktop`で作成した分析用ファイル(`pbix`ファイル)を読み込む
1. `report`のアイコンの分析用ファイルを開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/b81050ae-2bee-4a34-adfa-f4ccad08cf0f.png)
1. `share`を開く
1. `Anyone in your organization ,,,`を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/ab48760c-d9c5-476e-9efa-bd012b3d7b47.png)
1. `People in yout organization`を選択し、`apply`する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/c393d9c6-2df9-4691-8cbb-70c929d42e8e.png)

# 参考リンク
- [Compare Power BI Desktop and the Power BI service](https://learn.microsoft.com/en-us/power-bi/fundamentals/service-service-vs-desktop)
- [Share Power BI reports and dashboards with coworkers and others](https://learn.microsoft.com/ja-jp/power-bi/collaborate-share/service-share-dashboards)
BlockNoteの基本的な使い方


## BlockNoteとは

https://www.blocknotejs.org/docs

BlockNoteは、Reactアプリケーション向けのブロックベースのリッチテキストエディタです。最小限のセットアップで優れたユーザー体験を提供することに焦点を当てています。

サンプル:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325856/22cfe0a9-cf7b-4ee2-8c4c-11c1f2a0b0ab.png)


BlockNoteの特徴：

- ブロックベースの設計により、ドキュメントの構造化が容易
- NotionみたいなUIを提供
- 拡張性を考慮して設計され、カスタマイズが可能
- 最小限のセットアップで使用可能

## なぜBlockNoteを使うのか

リッチテキストエディタのライブラリは多数存在しますが、BlockNoteは以下の点で優れています：

1. **使いやすさ** - 他のライブラリ（ProseMirror、TipTapなど）は強力ですが、学習曲線が急で、エディタの細部までカスタマイズする必要があります。BlockNoteは最小限のセットアップで優れた体験を提供します。

2. **モダンなブロックベース設計** - ドキュメントにより多くの構造を与え、より豊かなユーザー体験を可能にすると同時に、エディタの機能をカスタマイズしやすくします。

3. **アニメーション付きの既製UI** - すぐに使えるUIコンポーネントが含まれています。

## インストール方法

BlockNoteをReactプロジェクトに追加するには、以下のコマンドを実行します：

```bash
# npmを使用する場合
npm install @blocknote/core @blocknote/react @blocknote/mantine

# yarnを使用する場合
yarn add @blocknote/core @blocknote/react @blocknote/mantine

# pnpmを使用する場合
pnpm add @blocknote/core @blocknote/react @blocknote/mantine
```

## 基本的な使い方

### 1. 最小限のセットアップ

最も基本的な実装は以下のようになります：

```jsx
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView, useBlockNote } from "@blocknote/react";
import "@blocknote/mantine/style.css";

function Editor() {
  // エディタインスタンスを作成
  const editor = useCreateBlockNote();

  // エディタビューを表示
  return <BlockNoteView editor={editor} />;
}

export default Editor;
```

### 2. 初期コンテンツの設定

エディタに初期コンテンツを設定するには：

```jsx
import { BlockNoteView, useBlockNote } from "@blocknote/react";
import "@blocknote/react/style.css";

function Editor() {
  // 初期コンテンツを持つエディタインスタンスを作成
  const editor = useCreateBlockNote({
    initialContent: [
      {
        type: "paragraph",
        content: "これはBlockNoteエディタです！",
      },
    ],
  });

  return <BlockNoteView editor={editor} />;
}
```

### 3. エディタの内容を取得する

エディタの内容を取得するには：

```jsx
// JSONとして内容を取得
const blocks = editor.document;
console.log(JSON.stringify(blocks));

// マークダウンとして内容を取得
const markdown = editor.blocksToMarkdownLossy();
console.log(markdown);

// HTMLとして内容を取得
const html = editor.blocksToFullHTML();
console.log(html);
```

## 主要な機能

### 1. ブロックタイプ

BlockNoteは以下のようなデフォルトのブロックタイプを提供しています：

- 段落（Paragraph）
- 見出し（Heading）- レベル1〜6
- 箇条書きリスト（Bulleted List）
- 番号付きリスト（Numbered List）
- チェックリスト（To-do List）
- 引用（Block Quote）
- コードブロック（Code Block）

### 2. テキストフォーマット

以下のようなインラインフォーマットが可能です：

- 太字（Bold）
- イタリック（Italic）
- 下線（Underline）
- 取り消し線（Strikethrough）
- コード（Code）
- リンク（Link）

### 3. UIコンポーネント

BlockNoteには以下のUIコンポーネントが含まれています：

- フォーマットツールバー - テキスト選択時に表示されるフォーマットオプション
- スラッシュメニュー - 「/」を入力すると表示されるブロック挿入メニュー
- サイドメニュー - ブロックの横に表示される操作メニュー

## カスタマイズ

BlockNoteは様々な方法でカスタマイズできます：

1. **テーマのカスタマイズ** - CSSを上書きしてエディタの外観を変更
2. **UIコンポーネントのカスタマイズ** - ツールバーやメニューのカスタマイズ
3. **カスタムブロックの作成** - 独自のブロックタイプを定義
4. **カスタムインラインコンテンツ** - 独自のインラインフォーマットを追加

ここら辺のカスタマイズは割愛します。

## まとめ

簡単にNotionみたいに使えて最高だった
【EC-CUBE4.3】プラグインを開発してみる その５

## 本記事で分かること
- プラグインでのイベントリスナーの使い方

## 手順
### 1. イベントリスナーで`order_no`をフォームにセット
- 現時点だと、受注問合せボタンを押しても、問い合わせフォームの受注番号が空のまま。
```php
namespace Plugin\OrderInquiry\EventListener;

use Doctrine\ORM\EntityManagerInterface;
use Eccube\Event\EccubeEvents;
use Eccube\Event\EventArgs;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ContactFormInitializeListener implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return [
            EccubeEvents::FRONT_CONTACT_INDEX_INITIALIZE => 'addOrderNoField',
        ];
    }

    public function addOrderNoField(EventArgs $event)
    {
        $builder = $event->getArgument('builder');
        $request = $event->getRequest();

        $orderNo = $request->query->get('order_no');

        if (!$orderNo) {
            return;
        }

        $data = $builder->getData() ?? [];
        $data['order_no'] = $orderNo;
        $builder->setData($data);
    }
}
```
イベントリスナーは、プラグインでも通常の使い方と同じ。

### 2. 実際に確認してみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3850968/245eb2bf-a1a3-4322-aac6-701a8981fdc0.png)
- 注文番号がセットされるようになった
Salesforce CLIの使用を認証する

# 前置き
Salesforceの設定を管理画面からポチポチやりたかったが、Salesforce CLIでごりごり設定しないと対応できない機能があり、渋々やったメモです。

# Salesforce CLIをインストール
[ここ](https://developer.salesforce.com/docs/atlas.ja-jp.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm)からインストーラをダウンロードします。

今回はWindows版をインストールしました。
インストールしたらコマンドプロンプトを開いてバージョンを確認します。

```
cd C:￥Program Files￥sf￥client￥bin
sf version
```

# Salesforce CLIの認証
以下コマンドでSalesforce CLIを使用するために認証を行います。
```
sf org login web -r https://test.salesforce.com -a エイリアス名
```

ブラウザが開くので、ユーザ名とパスワードを入力して、アクセスを許可します。

認証の確認は以下コマンドが正常に表示されていればOKです。
```
sf org list
```
Github Actionsで使われる「ubuntu」について調べてみた

![スクリーンショット 2025-04-21 14.46.40（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/c343a6d3-adf5-4546-9a87-8d1298ac5852.png)


# はじめに
正直なところ、僕自身はGithub Actions自体をあまり使っていませんでした。仕事ではすでにセットアップされている状態で仕事をしていたり、個人開発ではあくまでもアプリ側がちゃんと動けばいいかと思っていたので、リポジトリをみたところ、数年前に追加したものが失敗されている状態で野晒しになっていました。

そんなときに、Github Actionsを触れる機会を提供してもらえたので、学習をしながら手を動かすことができました。おかげで今まであった苦手意識は薄れてきたと思います。ありがてぇぇ


ということでおそらく「ubuntu」について知っている方はどのぐらいいるでしょうか？僕は全く知らないどころかスルーしていました。

いくつかのサイトから引用させていただきます。


## 「ubuntu」について

https://techmania.jp/blog/linux0002/

> Ubuntuとは「誰にでも使いやすいOS」をコンセプトに開発されたLinux系のOS。
Linux 系OSとはLinuxをベースにして作られたOS のことで、一般的にLinuxディストリビュージョンを指します。オープンソースであるLinuxには多くのディストリビューションがありますが、なかでもUbuntuは、特に人気があります。

え、OSなの・・・？
WindowsやmacOSは、知っているのになんで知らなかったんだろう...

## なぜGithub Actionで使われることが多いのか？

### 安定性と信頼性
Ubuntuは安定した動作が保証されており、CI/CDパイプラインで重要な信頼性を提供しており、システムのクラッシュや予期せぬ動作が少ない点・ビルドやテストの実行が安定して行えるメリットもあります。

### パフォーマンス
リソース効率が良く、CI/CDジョブの実行時間を短縮でき、軽量なイメージサイズで、ジョブの起動が高速
メモリ使用量の最適化されています。

### 開発環境としての適性
多くの開発ツールが標準でサポートされており、様々なプログラミング言語の実行環境を簡単に構築可能です。またコンテナ化された環境との相性が良いという点もあります。

### カスタマイズ性
Ubuntuは必要最小限の構成から始められ、必要なツールだけを追加できます。macOSやWindowsは不要なサービスや機能が多く含まれている場合があります。

### コスト面での優位性
macOSランナーはUbuntuの約10倍、Windowsランナーは約2倍のコストがかかります。GitHub Actionsの無料枠（月2,000分）を最大限活用するならUbuntuが最も効率的です。

追記：macOSランナーはUbuntuの約２倍ではなく、１０倍でした。教えていただきありがとうございます。

https://docs.github.com/en/billing/managing-billing-for-your-products/managing-billing-for-github-actions/about-billing-for-github-actions#minute-multipliers

## 最後に
いつも見逃していたり、しっかりとみれていないところも知っておくと大切なのですね。これらについて理解できるともっと領域が広がると思うと嬉しいですね。
【リモートワーク】椅子、買おう！！！！！！！！

# 椅子、買った？？？
みなさんこんにちは。25年4月で社会人2年目に突入しました、熊谷です。
この記事を開いたということは少なくとも椅子に関心があるんじゃないですか？
そしてタイトルも見たはずです。
椅子、買いましたか？
この記事はこれからの社会人生活を過ごす新卒の方にぜひ快適なリモートワークを過ごしていってほしいので新卒エンジニアタグをつけていますが、新卒じゃない方でもぜひ見ていってください。

# 椅子を買った経緯
私は昨年の秋まで大学生になるときに買ったニトリの3000円くらいの椅子を使っていたのですが、リモートワークでの業務中に一つ問題点がありました。

<font color = red>__「おしりが痛すぎる」__</red>

流石に5年目の3000円の椅子はクッション性は失われており、その椅子に座って作業を1日中するどころか会議の間でも場所を変え、立ってみたり座ってみたり、集中の妨げになっていました。

そして、秋から参画したPJでたまに出社をするようになります。出社先は「リモートワークができる中でも来たくなるようなオフィス」を目指していたオフィスでした。(全然覚えていませんがPJ前に伺った際に多分そんなことを言っていた気がします)
もちろん出社しても椅子には座ります。そこでこう感じたのです。

<font color=green>__「俺は今くつろぎに来ているのか？」__</green>

勿論、仕事をしに来てはいるのですが自宅よりもクッション性の良い椅子に座り、会社のフリードリンクの紅茶を飲み、腰を落ち着けるその空間はくつろぎ空間でしかありえません。
その椅子は、生地は同じメッシュなのにクッション性が高いうえに座面も厚く、座面の作り方から違うのか「へこたれるわけないでしょう」と私が座るたびに訴えかけるようでした。
私は会社の椅子のメーカーを確認し、値段を見たら納得。そのオフィスの椅子は自宅の椅子の10倍以上の値段でした。
そこで私は椅子がどれだけ値段で差があるのか思い知り、自宅の椅子を買い替える決心をしました。

# どんな椅子を買う？
最近Twitter(現X)で残念なことにつぶれてしまったベンチャー企業が出してる有名ブランドの椅子を買えなどの話を見かけましたが、私が買ったときのポイントはこちらです。
- ブランド(私の場合は会社のものが心地よかったのでそちらを軸に探しました)
- 値段は少なくとも1万円以上(私が買ったのはItoki salidaYL6で約30,000円)
- 生地(蒸れ感が嫌いなので私は絶対メッシュ！革はなし)
- ひじ掛け(リラックスにはいいけどなんだかんだ邪魔だなというのが結論)


# 最後に
リモートワークに欠かせない椅子、特に新卒の方などは値段のところで手が引っ込むかもしれません。自分よりもベテランのエンジニアの方は、今更椅子にお金かけるのか...と思うかもしれません。
ただ数年、もしくはそれ以上使う可能性がある椅子、日割りで計算したら10万円したって価値には見合うのではと今思います。
私は新しく椅子を買って半年以上たちますが、今でもこの椅子に変えてよかったと座るたびに思えています。皆さんもぜひ心地いいリモートワークライフを。

追記：椅子を廃棄するのに粗大ごみとして出すのも忍びないというか思い入れがあるんだよなという方は、軽く掃除してジモティーなどで引き渡しするのも良いと思います。
状態がよければ粗大ごみにせずに使ってもらえてWIN-WINですよ。
【EC-CUBE4.3】プラグインを開発してみる その２

## 本記事で分かること
- プラグインでのtwigテンプレートのカスタマイズの仕方

## 手順
### 1. プラグイン用の Twig テンプレートファイルを作成する
- `template/default/Mypage/history.twig` を作成
```php
{% block script %}
<script>
    // 再注文ボタンの下に配置
    $(function () {
        $('#order_inquiry_btn').insertAfter($('.ec-blockBtn--action'));
    });
</script>
{% endblock %}
{% block main %}
    <a id="order_inquiry_btn" class="ec-blockBtn--primary w-100 mt-3"
       href="{{ path('contact', {order_no: Order.order_no}) }}">
        {{ 'order_inquiry.front.mypage.history.inquiry_btn'|trans }} 
    </a>
{% endblock %}
```

### 2. Event クラスにテンプレート読み込みの処理を追加する
```php
namespace Plugin\OrderInquiry;

use Eccube\Event\TemplateEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class Event implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            'Mypage/history.twig' => 'onHistoryDetail',
        ];
    }

    public function onHistoryDetail(TemplateEvent $event): void
    {
        // １．で作成したtwigファイル
        $twig = '@OrderInquiry/default/Mypage/history.twig';
        $event->addSnippet($twig);
    }
}
```
- `$event->addSnippet()` で追加したコードは, `</body>`タグ直前に出力される

### 3. ブラウザで表示を確認して反映をチェックする
WindowsのPowerShellでBashを実行

PowerShellでBashを実行するのに苦労したので、備忘録。

まず、内容は以下の通りです。
```shell:test.sh
#!/bin/bash

# echo "bashでこの行はコメントです"
echo "bashでこの行はコメントではありません"
```

これを実行したくて色々試しました。
結論は、shのあるディレクトリに移動して、以下のコマンド。
```PowerShell:PowerShell
 bash ./test.sh
```

どうやらWindowsのPowerShellではbashを経由しないとファイルとして認識されるみたいです。
何度./test.shでファイルを開いたことか……。

何故Windowsではbashを経由しないといけないのか、はまた別途調べてこの記事に追記します。

あ～、解決してよかった～！！
Simple Membership × Stripe SCA (3Dセキュア) 対応カスタマイズ事例【WordPress + オンラインサロン】

# Simple Membership × Stripe SCA (3Dセキュア) 対応カスタマイズ事例【WordPress + オンラインサロン】

オンラインサロン向けに構築されたWordPressサイトで、Stripeによる3Dセキュア（SCA）対応のサブスクリプション決済を実装した際のメモです。

対象サイトはビルドサロン社が製作したオンラインサロンで、「Simple Membership」プラグインをベースに会員管理を行っています。

---

## 🎯 ゴール

- StripeのSCA（Strong Customer Authentication）対応により、3Dセキュア必須環境でも安定して動作するサブスクリプション決済を導入
- Simple Membership の支払いボタンを Checkout Session 経由に変更
- 支払い完了後のリダイレクトや metadata で会員連携が可能な状態に

---

## 🔧 カスタマイズ対象ファイル

```text
wp-content/plugins/simple-membership/views/payments/admin_create_payment_buttons.php
wp-content/plugins/simple-membership/views/payments/payment-gateway/admin_stripe_sca_subscription_button.php
wp-content/plugins/simple-membership/views/payments/payment-gateway/stripe_sca_button_shortcode_view.php
```

## 実装内容

### 1. 管理画面：ボタン作成タイプの追加

```
$options .= '<option value="stripe_sca_subscription">' . SwpmUtils::_('Stripe SCA Subscription') . '</option>';
```

これで「Stripe SCAサブスクリプション」という新しい選択肢が追加されます。

### 2. SCAサブスクリプションボタンの設定画面を拡張
```
<tr class="form-field form-required">
    <th scope="row"><label for="price_id">Stripe Price ID</label></th>
    <td><input name="price_id" type="text" id="price_id" value="<?php echo esc_attr($button->price_id); ?>" /></td>
</tr>
```
Stripeダッシュボードで作成した price_id を手動で設定できるように。

### 3. フロント出力：Checkout Sessionへリダイレクト
```<script>
const stripe = Stripe('<?php echo esc_js($publishable_key); ?>');

document.getElementById('<?php echo esc_attr($button_id); ?>')
  .addEventListener('click', () => {
    fetch('<?php echo esc_url(admin_url("admin-ajax.php")); ?>?action=create_stripe_sca_session&button_id=<?php echo esc_attr($button_id); ?>')
      .then(response => response.json())
      .then(session => stripe.redirectToCheckout({ sessionId: session.id }))
      .catch(error => console.error('Stripe session creation failed:', error));
  });
</script>
```

導入後の結果
	•	✅ モバイル含め、すべての決済で3Dセキュアが正常に動作
	•	✅ 海外からのアクセス・カードでも問題なし
	•	✅ 会員登録処理と連動し、metadataでログイン情報が連携可能に


 📝 まとめ

Simple Membership はシンプルで使いやすい反面、Stripeとの高度な連携（特にSCA周り）は手動実装が必要になります。

今回のように、カスタムボタン＋Checkout Sessionによる設計を行うことで、より安定・確実なサブスクリプション決済が実現可能です。


🔗 参考リンク
	•	Stripe Checkout - 公式ドキュメント
	•	Simple Membership - プラグイン公式
	•	ビルドサロン株式会社 - オンラインサロン構築専門企業
【EC-CUBE4.3】プラグインを開発してみる

## 動機
- EC-CUBEをカスタマイズする方法はある程度理解できたつもり。
- プラグインについて構造などまだよくわかっていない。
- 既存のプラグインをいじる必要が有りそうなのでこれを機会に実際に触ってみる。

## やりたいこと
- まずは、簡単なプラグインをイチから自分で開発してみる
- プラグイン内容
    - マイページ購入履歴から、直接受注問合せができるようにする

## 本記事でわかること
- プラグインの生成からインストール完了の確認まで
- 作成したプラグイン：https://github.com/to19960425/order-inquiry-plugin/

## 参考
- 公式ドキュメント：https://doc4.ec-cube.net/plugin_development

## 手順
### 1. プラグインの雛形を生成
- プラグイン名は、`OrderInquiryPlugin` とする。
```bash
bin/console eccube:plugin:generate
```
```bash
 name [EC-CUBE Sample Plugin]:
 > OrderInquiryPlugin

 code [Sample]:
 > OrderInquiry

 ver [1.0.0]:
 > # 空
 ```
 
### 2. プラグインをインストール
```
bin/console eccube:plugin:install --code OrderInquiry
```

### 3. プラグインを開発
- 管理画面を確認すると、プラグイン一覧の「ユーザー独自プラグイン」に追加される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3850968/a7d9a19e-c238-4e0d-8755-2bcbbb17c690.png)
これで準備OKです。
[Linux][command] シェル変数と環境変数_表示_env, printenv, set, declare -f

# 一覧
|コマンド|説明|
|:--|:--|
|env|全ての環境変数を表示|
|printenv|全ての環境変数を表示(指定可能)|
|set|全ての環境変数とシェル変数を表示|
|declare -f|全てのシェル変数を表示|

# envコマンド
```terminal
$ env [オプション] [環境変数=値] [コマンド]
```

| オプション     | 由来              | 説明                                      |
| :-------- | :-------------- | :-------------------------------------- |
| `default` |      | 全ての環境変数を表示（引数なしの場合）                   |
| `-i`      | ignore          | 現在の環境変数を**すべて無視**してコマンドを実行（クリーンな環境で実行）  |
| `環境変数=値`   |  | 一時的に環境変数を設定してコマンドを実行（そのセッション・コマンド中のみ有効） |
| `コマンド`    |        | 指定したコマンドを、環境変数を反映させて実行                  |


# Ping-t
- [3072_env, printenv, set](https://mondai.ping-t.com/question_subjects/31/question_sessions/32193725/progressing_questions/493221758)
- [3440_set](https://mondai.ping-t.com/question_subjects/31/question_sessions/32209448/progressing_questions/493463153)
- [34264_set](https://mondai.ping-t.com/question_subjects/31/question_sessions/32527688/progressing_questions/498427182)
- [4672_env](https://mondai.ping-t.com/question_subjects/32/question_sessions/33502345/progressing_questions/513098366?result=true)
- [4821_set, declare -f](https://mondai.ping-t.com/question_subjects/32/question_sessions/33449680/progressing_questions/512330529?result=true)