OmniAICreator/Qiita-1.07M huggingface dataset:
[Docker][構築ファイル] Node.js（フロントエンド）と Python（バックエンド）を 1 つの Docker コンテナにまとめたい

# [Docker][構築ファイル] Node.js（フロントエンド）と Python（バックエンド）を 1 つの Docker コンテナにまとめたい

## はじめに

開発時などに、Node.js（フロント）と Python（バックエンド）を同じ Docker コンテナ内でまとめて動かしたいことがあります。
この記事では、`python:3.11-slim` ベースの軽量イメージを用い、1 つの Docker コンテナ内で Node.js + Python を構築・起動する方法を解説します。

---

## Dockerfile のサンプル

```dockerfile
FROM python:3.11-slim

# Node.js を追加
RUN apt-get update && apt-get install -y curl gnupg \
    && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
    && apt-get install -y nodejs \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

# 作業ディレクトリ
WORKDIR /app

# Python & Node.js の依存ファイルをコピー
COPY requirements.txt .
RUN pip install -r requirements.txt

COPY package.json .
RUN npm install

# アプリ全体をコピー
COPY . .

# start.sh に実行権限を付与
RUN chmod +x start.sh

# 起動コマンド
CMD ["./start.sh"]
````

---

## 2 つのサーバーを実行する方法（フロント + バックエンド）

### 方法1: シェルファイルで 2 プロセス同時起動

まず `start.sh` ファイルを作成します：

```sh
#!/bin/bash

# フロントエンドをバックグラウンドで起動
cd frontend
npm run start &

# 少し待ってから（任意）
sleep 2

# バックエンドを起動
cd ..
python main.py
```

このスクリプトにより、Node.js（例: Vite, Next.js）と Python の両方を同時に起動できます。

---

### 方法2: Python コードからフロントを起動する

Python の `subprocess` を使って Node.js をバックグラウンド起動することで、1 ファイルで管理できます。

```python
import subprocess
import time
from fastapi import FastAPI

# Node.js フロントエンドをバックグラウンドで起動
subprocess.Popen(["npm", "run", "start"], cwd="./frontend")

# 少し待機してバックエンド起動（任意）
time.sleep(2)

# FastAPI サーバー起動（例）
app = FastAPI()

@app.get("/")
def read_root():
    return {"message": "Hello from backend"}
```

この方法では、スレッドを使わずにノンブロッキングに起動可能です。

---

## TL;DR

* `subprocess.Popen(...)` は非同期（ノンブロッキング）でプロセスを起動できます。
* **エラー処理やログ監視が不要であれば、`threading.Thread(...)` は基本不要です。**
* 最小構成であれば、以下のコードだけでも起動可能：

```python
subprocess.Popen(["npm", "run", "start"], cwd="./frontend")
```

---

## まとめ

開発環境であれば、Node.js と Python を 1 つの Docker コンテナでまとめて起動することは現実的かつ便利です。
ただし本番環境では、コンテナを分離して Docker Compose などで連携する構成が推奨されます。
Lessもう要らない？！変数と入れ子

## 過去の投稿・CSSメタ言語

- [CSSメタ言語のすすめ](https://qiita.com/jabaraster/items/5cf6b5266451ac96220a)
- LessやSaas
- セレクタの入れ子
- 変数

----
## 実はCSS単体で可能！

- CSS入れ子
- CSSカスタムプロパティ

----
## CSS入れ子

- LessやSassと同じく直感的に書ける
- 省略可能だが、& を使うのが正式な書き方らしい

```css
.main {
  width: 100vw;
  height: 100vh;

  & .enphasis {
    color: red;
    font-weight: bold;
  }
}
```

-----
## CSSカスタムプロパティ（変数）

- --で始まる名前を付ける
- var()で使う
- セレクタでスコープを形成する

```css
:root {
  --main-color: rgb(230, 230, 230);
  --main-bgcolor: rgba(30, 30, 30, .8);
}
body {
  color: var(--main-color);
  background-color: var(--main-bgcolor);
}
```

----
## CSSカスタムプロパティの使い心地（個人の感想）

- ちょっと非直感的
- 当面はシンプルに使える範囲で利用したい

----
## CSSメタ言語は死んだのか？

まだ利点はある！

----
## CSSメタ言語の利点

- ミックスインで複数のプロパティを同時に当てる
- 関数で冗長性排除
- コンパイルの機会の提供：最適化など
  ただし最近はCSSも加工されるのが一般的
- 多数の成果物

----
## 最後に

- Web技術の進化早いですね
- CSSメタ言語は依然として有用
- CSSはブラウザで直接解釈できるという利点を失わない範囲で進化するだろう
windows11で、sketchup6 その111

# 概要
windows11に、sketchup6を入れてみた。
rubyで、3Dを書く。
練習問題やってみた。

# 練習問題
タートルグラフィックスを実装せよ。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/48f03676-1413-4594-9803-3c476cfdf988.png)


# サンプルコード

```

class Kame3
	def initialize
		model = Sketchup.active_model
		@entities = model.active_entities
		@ANGLE = 0
		@LX = 10
		@LY = 10
		@pen = 1
		run()
	end
	def fmod(a, b)
		x = (a / b).floor
		return a - b * x
	end
	def up()
		@pen = 0
	end
	def down()
		@pen = 1
	end
	def turn(a)
		@ANGLE = fmod(@ANGLE + a, 360.0)
	end
	def walk(l)
		p = []
		rd = Math::PI / 180.0
		x = l * Math::cos(rd * @ANGLE)
		y = -l * Math::sin(rd * @ANGLE)
		px = @LX
		py = @LY
		p << [px, py, 0]
		@LX += x
		@LY += y
		p << [@LX, @LY, 0]
		if @pen == 1
			@entities.add_curve(p)
		end
	end
	def run()
		walk(10)
		up()
		turn(-90)
		walk(10)
		down()
		turn(-90)
		walk(10)
		turn(-90)
		walk(10)
		up()
		walk(30)
		down()
		turn(30)
		walk(10)
		turn(30)
		walk(10)
		turn(30)
		walk(10)
		turn(30)
		walk(10)
		turn(30)
		walk(10)
		turn(30)
		walk(10)
		turn(30)
		walk(10)
		turn(30)
		walk(10)
		turn(30)
		walk(10)
		turn(30)
		walk(10)
		turn(30)
		walk(10)
		turn(30)
		walk(10)
	end
end





```

以上。
プログラミング初学者が知っておくと得しそうな用語を図解にしてみた

プログラミング初学者の方が知っておくと得しそうな用語を図解にしました。

ただし、体系的でもなければ、何かを網羅をしているわけでもありません。
私が日々、Ｘでポストしている中から抜粋しただけのものです。

あらかじめご了承下さい。

Pythonに偏っていますが良ければフォローお待ちしております。

https://x.com/python_academia

それではいってみましょう！

## GUIとCUI
GUIとは、グラフィカルユーザインターフェース(Graphical User Interface)の略で画面上にボタンやアイコンを表示し、直感的に操作できるようにしたものです。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638073/3a5a0735-8243-4ae5-8dbe-798fbf2d51ec.png width=70%>

反対にCUIというものもあり、こちらはキャラクターユーザーインターフェイス（Character User Interface）の略で命令をすべて文字によって行います。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638073/8f4558e2-bc12-4165-8016-6317bcb4bd5f.png width=70%>

## 絶対パスと相対パス
パスとはディレクトリ（フォルダ）構造内の場所を表すために使用する文字列のことで、絶対パスと相対パスの2種類があります。

絶対パスとは、別名フルパスとも言われており、最上位に位置するディレクトリ（ルートディレクトリ）から、対象のファイルまでの道順(階層構造)を記述する方法になります。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638073/8e9fe06c-ad27-47c1-9d09-185bacacf104.png width=70%>

相対パスとは現在作業しているディレクトリ（カレントディレクトリ）を基準にして、対象ファイルまでの道順を記述する方法になります。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638073/e40bdd1e-654f-4409-a42a-85af412aac56.png width=70%>

## パスを通す

パスを通すとは、ファイル名を指定するだけで実行できるようにすることです。

プログラムを実行したい場合、場所を指定したり、その場所に移動することで実行できますが、毎回となると面倒なのでパスを通します。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638073/57222bc4-72ed-449f-bf08-4496d2f32645.png width=70%>

## マジックナンバー

ソースコードに、べた書きされた意味の分からない値をマジックナンバーと言います。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638073/9f585bb7-286d-47d4-9240-87bbb06af0e7.png width=70%>

## 三項演算子
if文を一行で書くことができます。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638073/21db7bba-0e58-4227-87fb-a04de6a65dc7.png width=70%>

## デバッグとデバッガー
デバッガーとはバグを見つけるツールで、デバッグはバグの原因を探して取り除く作業です。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638073/93658add-25ba-4cf1-ad32-7cebbd1b4f69.png width=70%>

## 同期処理と非同期処理
同期処理は処理を順番に実行することです。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638073/81c7a1bd-6b9e-4b88-94ab-f63a6359deaa.png width=70%>

非同期処理とは、あるタスクが終了するのを待っている間、別のタスクを実行することです。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638073/ebea368f-9364-4ed6-871f-e2174551db94.png width=70%>

## 安定ソート
同じ要素がある場合、元々の順序が維持されるということ。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638073/2b1f5ce6-d089-488a-875b-dd085bfdc13f.png width=60%>

## データドリブン
勘や経験に頼らず、データをもとに考えること

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638073/5328c476-f046-4e3a-9197-7a84ef5f4203.png width=60%>

## おわり

最後までお読みいただきありがとうございました！
１つでも参考になれば幸いです。

「図解で学べる」を意識して書籍を書いています。
こちらもよろしければご活用ください。

https://zenn.dev/python_academia/books/eabcc6b22afff5

https://zenn.dev/python_academia/books/6df147d8b82939
ChatGPTを使用したアプリ開発記【編集したアイコンを投稿画面に反映】

## 🔧【UI部分】アイコンの表示場所（ようこそ〜ログアウト）
```App.js
{user.photoURL ? (
  <img src={profilePhotoURL} alt="アイコン" className='w-8 h-8 rounded-full inline-block mr-2' />
) : (
  <img src="/default-icon.png" alt="アイコン" className='w-8 h-8 rounded-full inline-block mr-2' />
)}
```
解説：
	•	user.photoURL ?：Firebase Authのuserオブジェクトに写真URLがあればそれを使う。
	•	img src={profilePhotoURL} ... /：Firestoreのusersコレクションに保存されているプロフィール画像（profilePhotoURL）を表示。
	•	className='w-8 h-8 rounded-full inline-block mr-2'：幅8、高さ8（=32px）、丸型、インラインブロック、右にマージン（スペース）2。
	•	elseブロック：写真URLが無ければデフォルトアイコン/default-icon.pngを表示。

## 🔧【UI部分】投稿者一覧でのアイコン表示
```App.js
{user.photoURL ? (
  <img
    src={post.photoURL || "/default-icon.png"} alt="アイコン"
    className='w-8 h-8 rounded-full inline-block mr-2'
  />
) : (
  <img src="/default-icon.png" alt="アイコン" className='w-8 h-8 rounded-full inline-block mr-2' />
)}
```
解説：
	•	user.photoURL を条件に分岐しているが、本来 post.photoURL の有無で分岐すべきかもしれません（※改善の余地あり）。
	•	src={post.photoURL || "/default-icon.png"}：投稿時に保存されたアイコン画像 or デフォルト。
	•	以降のクラス指定は上と同じ。

## 🔁【ロジック部分】ログインユーザーのアイコン読み込み（useEffect）
```Appp.js
const unsub = onAuthStateChanged(auth, (currentUser) => {
  setUser(currentUser);
```

•	Firebaseのログイン状態監視。ログインユーザーが変更されたら currentUser を取得し、状態に保存。
    
```Appp.js
if (currentUser) {
  const profileDoc = await getDoc(doc(db, 'users', currentUser.uid));
```
•	Firestoreの users コレクションからログインユーザーのプロフィールを取得。

```Appp.js
if (profileDoc.exists()) {
  const data = profileDoc.data();
  setProfileName(data.name || currentUser.displayName || '匿名');
  setProfilePhotoURL(data.photoURL || currentUser.photoURL || '');
}
```
•	プロフィール情報が存在すれば name と photoURL を状態に保存。
•	データが無い場合は Firebase Auth のデフォルト値を代用。
    
## 🔁【ロジック部分】投稿一覧取得時のアイコン読み込み
```Appp.js
const userDoc = await getDoc(doc(db, 'users', postData.uid));
```
•	投稿ごとに、投稿者の uid を使って users コレクションからプロフィール取得。

```Appp.js
if (userDoc.exists()) {
  const userData = userDoc.data();
  nameFromUserCollection = userData.name || nameFromUserCollection;
  profilePhotoURL = userData.photoURL || profilePhotoURL;
}
```
•	Firestoreにあれば名前とアイコンURLを上書き。

```Appp.js
return {
  id: docSnap.id,
  ...postData,
  displayName: nameFromUserCollection,
  photoURL: profilePhotoURL || postData.photoURL || ''
};
```
•	投稿データのオブジェクトに photoURL を含めて setPosts() に渡す。

##  📝【投稿処理】投稿時にプロフィール画像を保存
```Appp.js
let profileName = '匿名';
let profilephoto = '';
if (user) {
  const profileDoc = await getDoc(doc(db, 'users', user.uid));
  if (profileDoc.exists()) {
    const data = profileDoc.data();
    profileName = data.name || user.displayName || '匿名';
    profilephoto = data.photoURL || user.photoURL || '';
  }
}
```
•	投稿時にも Firestoreからユーザー情報（名前・アイコン）を取得し、投稿データに含める。

```Appp.js
const newPost = {
  ...
  displayName: profileName,
  photoURL: profilephoto || user?.photoURL || '',
  ...
};
```
•	投稿に photoURL を付けて保存 → 他ユーザーが読み取るために使う。
  
## UI

![スクリーンショット 2025-05-16 11.35.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1058366/a6dcaa11-4fd6-42ee-8ed8-c793fe9354a3.png)
【Docker buildxトラブルシューティングTips】QEMUでDockerfileをクロスコンパイル時にSegmentation fault (core dumped)が発生する時の対処方法

# はじめに

Docker buildxコマンドを使って、クロスコンパイルすると、Segmentation fault (core dumped)が頻発する際の対処方法を紹介する。Segmentation fault (core dumped)は、再現性がなく、発生したりしなかったりする。

# 動作確認環境
* Ubuntu 22.04 x86_64
* Docker
    ```bash
    docker version
    Client: Docker Engine - Community
     Version:           28.1.1
     API version:       1.49
     Go version:        go1.23.8
     Git commit:        4eba377
     Built:             Fri Apr 18 09:52:18 2025
     OS/Arch:           linux/amd64
     Context:           default
    
    Server: Docker Engine - Community
     Engine:
      Version:          28.1.1
      API version:      1.49 (minimum version 1.24)
      Go version:       go1.23.8
      Git commit:       01f442b
      Built:            Fri Apr 18 09:52:18 2025
      OS/Arch:          linux/amd64
      Experimental:     false
     containerd:
      Version:          1.7.27
      GitCommit:        05044ec0a9a75232cad458027ca83437aae3f4da
     runc:
      Version:          1.2.5
      GitCommit:        v1.2.5-0-g59923ef
     docker-init:
      Version:          0.19.0
      GitCommit:        de40ad0
      ```

# 原因

エラー発生時のクロスコンパイル時に利用していたQEMUは、[multiarch/qemu-user-static](https://github.com/multiarch/qemu-user-static)であった。buildxが出た当時は、こちらが推奨されていたが、既に開発が終了している。QEMUを変更するとエラーが解消されたため、QEMUが古かったことが原因と考えられる。

# 対策

QEMUを、[公式ドキュメント](https://docs.docker.com/build/building/multi-platform/#install-qemu-manually)の推奨の[tonistiigi/binfmt](https://github.com/tonistiigi/binfmt)に変更する。執筆時点のbinfmtの最新版は、[deploy/v9.2.2-52](https://github.com/tonistiigi/binfmt/releases/tag/deploy%2Fv9.2.2-52)なので、こちらを適用する。

Dockerビルド実行前に、QEMUの設定をBefore（変更前）からAfter（変更後）に変更する。

```bash:Before（変更前）
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
```

```bash:After（変更後）
docker run --privileged --rm tonistiigi/binfmt:qemu-v9.2.2-52 --uninstall qemu-*
docker run --privileged --rm tonistiigi/binfmt:qemu-v9.2.2-52 --install all
```

# 結果

QEMUを変更したところ、Segmentation fault (core dumped)が発生しなくなった。

# まとめ

Docker buildxコマンドを使って、クロスコンパイルすると、Segmentation fault (core dumped)が頻発する際の対処方法を紹介した。QEMUを最新のものに変更することでSegmentation fault (core dumped)が発生しなくなった。Docker buildxコマンドでクロスコンパイルに失敗する場合に試してみてほしい。

# 参考

https://docs.docker.com/build/building/multi-platform/#install-qemu-manually

https://github.com/docker/buildx/issues/2028

https://discuss.circleci.com/t/docker-image-build-failing-with-segmentation-fault-previously-worked/52752
【公ド読】ユーザー フィードバックの分析と取り込み

【公式ドキュメントを読もうシリーズ】ユーザー フィードバックの分析と取り込み

## シリーズ概要

[https://qiita.com/yasu_programming/items/cec66f9e8d5d571e9ce3](https://qiita.com/yasu_programming/items/cec66f9e8d5d571e9ce3)

## URL

[https://docs.github.com/ja/copilot/copilot-chat-cookbook/functionality-analysis-and-feature-suggestions/analyzing-and-incorporating-user-feedback](https://docs.github.com/ja/copilot/copilot-chat-cookbook/functionality-analysis-and-feature-suggestions/analyzing-and-incorporating-user-feedback)

## 説明

Githubでリポジトリを管理しているときに、たくさんのissueがあると、どれが重要で重要ではないかを判断することが難しくなってくると思われるが、それをGithub Copilotで代替してくれる。

多分Github上で行うものだと思われる。

Github上で下記プロンプトを入力することで、分類をしてくれる。

> Find the issues with the feature-request label that have the most reactions, and categorize them based on sentiment.

日本語訳

`最も反応が多い機能リクエストラベルを持つ問題を見つけ、感情に基づいて分類します。`

### Github上での操作

ずっとvscodeでやってきたが、GithubでGithub Copilotを触るのは初めてだった。

Copilotマークの隣の三角をクリック、Assistiveをクリックすることで、立ち上がる。
Shift + c でもGithub Copilotが立ち上がる。

## 所感

今までvscodeでしかGithub Copilotを触っていなかったが、Githubでも簡単に使えることを初めて知った。
オープンソースのissueとか確かに便利そうだなと思った。
【初心者向け】AWSセキュリティグループをわかりやすく解説

---
この記事では、AWSのセキュリティグループ（SG）について、なかなか理解できなかった部分があったので整理して解説していきます。

---

## セキュリティグループとは？

セキュリティグループ（SG）は、AWSにおける通信ルールのまとまりです。EC2インスタンスなどに適用され、「誰がアクセスできるか」「どこへ通信できるか」を制御します。サーバーの前に立つ“門番”のような存在と考えるとイメージしやすいです。

- **インバウンドルール**：外部からインスタンスへの通信を制御  
- **アウトバウンドルール**：インスタンスから外部への通信を制御
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3982291/7e7bd8c4-463b-4877-ad19-ba81c51b3177.png)

引用：https://tech-camp.in/note/technology/14602/

## インスタンスとIPアドレスの関係

インスタンスとはサーバー本体のことであり、IPアドレスはインスタンスに一時的に割り当てられる住所のようなものです。

AWSではインスタンスを再起動すると**パブリックIPが変わることもある**ため、インスタンスとIPは必ずしも固定ではありません。  
（IPを固定したい場合は：**Elastic IP** を使用）

そのため、セキュリティグループはインスタンスに対して適用され、**IPアドレスの変化に左右されません。**



## セキュリティグループの割り当て方

セキュリティグループはインスタンスに対して割り当てます。  
SGが自動的にインスタンスを管理するわけではなく、**インスタンスを作成・管理する際に明示的にセキュリティグループを選択**します。

- セキュリティグループは単なるルールセット  
- インスタンスが「このルールを使う」と設定する形です



## セキュリティグループをソースにする仕組み

AWSでは、セキュリティグループのインバウンドルールに「IPアドレス」ではなく  
**「別のセキュリティグループ」**をソースとして指定することが可能です。

これにより、指定したセキュリティグループに属するインスタンスからの通信は、**送信元IPに関係なく許可**されます。  
個別にIPを管理する必要がなく、運用が非常にシンプルになります。

---
[管理サーバー (SG-管理)] ───▶ SSH接続 ───▶ [Webサーバー (SG-Web)]

---


管理サーバー群に割り当てたSGをソースに設定することで、  
新たに管理サーバーを追加した場合も、IP設定を変更せずに自動的に接続が許可されます。



## セキュリティグループ設定手順（AWSコンソール）

1. 管理サーバー群用のセキュリティグループ（SG-Management）を作成・確認  
2. Webサーバー群用のセキュリティグループ（SG-Web）を開く  
3. **インバウンドルールを編集**  
4. ソースに「SG-Management」を指定し、保存  

これだけで、管理サーバー群からWebサーバー群への通信が許可されます。

## セキュリティグループ参照を使うメリット

- ✅ IPアドレスの管理が不要  
- ✅ サーバー増減時も設定不要  
- ✅ 設定ミスのリスクが減る  
- ✅ 運用がシンプルで安全  

## まとめ

AWSにおいてセキュリティグループは非常に強力なセキュリティ機能です。  
インスタンスに対して割り当て、ソースにセキュリティグループを指定することで、**効率的かつ安全な通信制御**が可能になります。

IPアドレスにとらわれず、インスタンス単位で柔軟に管理できる便利な仕組みです。  
初心者のうちにこの仕組みを理解しておくと、今後のAWS運用がぐっと楽になると思います！


参考記事
https://qiita.com/white_aspara25/items/48e91e671bff25474b02
競プロ日記#25/05/20

# アルゴ式
[Ex. エラトステネスの区間篩](https://algo-method.com/tasks/332)
- 素数判定の関数をそのまま使ってもBの入力制約が1e12なのでTLEしそう
- シンプルに考えるなら√B以下で探せばいいかなと思ったが問題文にヒントっぽく配置されている「A,B はとても大きな整数となる可能性がありますが、B−A は小さな整数であることに注意しましょう。」の利用の仕方が良くわからなかった
→√B以下で探せばよいらしかった...
```

int main() {
    // 入力が 32 ビット整数型に収まらないので long long 型
    long long A, B;
    cin >> A >> B;

    // √B 以下の素数を炙り出すための篩
    // ここでは大きめにサイズ 1100000 まで確保しておく
    vector<bool> isprime(1100000, true);

    // A 以上 B 以下の整数 v が素数かどうか
    // その答えは isprime2[v-A] に格納される
    vector<bool> isprime2(B - A + 1, true);

    // ふるい
    for (long long p = 2; p * p <= B; ++p) {
        // すでに合成数であるものはスキップする
        if (!isprime[p]) continue;

        // p 以外の p の倍数から素数ラベルを剥奪
        for (long long q = p * 2; q * q <= B; q += p) {
            isprime[q] = false;
        }

        // start: A 以上の最小の p の倍数
        long long start = (A + p - 1) / p * p;
        if (start == p) start = p * 2;

        // A 以上 B 以下の整数のうち、p の倍数をふるう
        for (long long q = start; q <= B; q += p) {
            isprime2[q - A] = false;
        }
    }

    // 答え
    long long res = 0;
    for (long long q = A; q <= B; ++q) {
        if (isprime2[q - A]) ++res;
    }
    cout << res << endl;
}
```
- 解説AC

[A を割ると B あまる数](https://algo-method.com/tasks/345)
- 式変形に気づけず...

[あまりが等しい](https://algo-method.com/tasks/549)
- 差の絶対値の約数を求めればよいということに自力で気づけた
- 自力AC

[メビウス関数](https://algo-method.com/tasks/494)
- 新たな概念（メビウス関数）に引っ張られて指数に着目すればよいだけという単純な部分に気づけなかった...

[√(AN) を整数にせよ](https://algo-method.com/tasks/455)
- 高校数学でよくやったやつ
- 既にAが平方数であるばあいにもたいおうで
```
// 素因数分解
// 460 = 2^2 x 5 x 23 の場合
// 返り値は {{2, 2}, {5, 1}, {23, 1}}
vector<pair<long long, long long> > prime_factorize(long long N) {
    // 答えを表す可変長配列
    vector<pair<long long, long long> > res;

    // √N まで試し割っていく
    for (long long p = 2; p * p <= N; ++p) {
        // N が p で割り切れないならばスキップ
        if (N % p != 0) {
            continue;
        }

        // N の素因数 p に対する指数を求める
        int e = 0;
        while (N % p == 0) {
            // 指数を 1 増やす
            ++e;

            // N を p で割る
            N /= p;
        }

        // 答えに追加
        res.emplace_back(p, e);
    }

    // 素数が最後に残ることがありうる
    if (N != 1) {
        res.emplace_back(N, 1);
    }
    return res;
}


int main() {
    long long A;
    cin >> A;
    vector<pair<long long, long long> > aPrimeFactorization = prime_factorize(A);
    long long ans = 1;
    for (auto p : aPrimeFactorization) {
        if (p.second % 2 == 1) {
            ans *= p.first;
        }
    }
    cout << ans << endl;

}
```
【Node.js axios】params利用時のURLクエリ文字列に意図しない「+」が混入？原因と解決策


Node.js環境で `axios` ライブラリを使い、外部APIに対してリクエストを行う際、クエリパラメータを params オブジェクトで指定したところ、生成されるURLに意図しない + 文字が混入し、APIが期待通りに動作しないという問題に直面しました。
この記事では、その原因と具体的な解決策を、特定のAPIサービス名を伏せた形で共有します。

### 生じた事象：生成されたURLに予期せぬ「+」記号
特定のIDに基づいて情報を検索する外部APIのエンドポイントに対し、処理を実装していました。`axios`の設定は以下の通りです。

```JavaScript

// 問題発生時のコード一部抜粋
import axios from 'axios';
import config from '../config.js'; // 設定ファイル

// ... (中略) ...

const apiClientConfig = {
    method: 'GET',
    url: `${config.apiSettings.baseUrl}/search-endpoint`, // APIのベースURLと検索用エンドポイント
    headers: {
        'Authorization': `Basic ${Buffer.from(/* ... */).toString('base64')}`, // 認証ヘッダー
    },
    params: {
        query: `searchId: ${config.apiSettings.targetId}` // ← 問題の箇所 (targetIdは検索対象のID)
    },
};

axios(apiClientConfig)
    .then(response => {
        console.log(response.data);
    })
    .catch(error => {
        console.error(error);
    });
```
このコードでAPIリクエストを実行した際、APIサーバーから期待する検索結果が得られませんでした。

### 試したこと：まずは、生成されるURLをログに出力して確認
問題の原因を特定するため、`axios` が実際にどのようなURLを生成してリクエストを送信しているのかを確認することにしました。`axios.getUri()` メソッドを使うと、設定オブジェクトから最終的なリクエストURL文字列を取得できます。

```JavaScript
// デバッグコード
const generatedUrl = axios.getUri(apiClientConfig);
console.log('Axios generated URL:', generatedUrl);
```
ログに出力されたURLは、以下のような形式になっていました。
```
Axios generated URL: https://api.example.com/v1/search-endpoint?query=searchId:+some123id
```
ここで、`searchId:` と実際のID (some123id は仮の値) の間に、意図しない `+` が挿入されていることが明らかになりました。連携先のAPIはおそらく searchId:some123id という形式のクエリ文字列を期待しており、この `+` が原因でAPI側がクエリを正しく解釈できていなかったと推測されます。

### 原因の特定：テンプレートリテラル内の半角スペース
この予期せぬ `+` 文字が混入した原因は、`params` オブジェクト内の `query` プロパティを定義しているテンプレートリテラル (``) 内の半角スペースでした。

```JavaScript
params: {
    query: `searchId: ${config.apiSettings.targetId}` // "searchId:" の直後に半角スペースが存在した
},
```
URLのクエリパラメータでは、半角スペースは一般的に `+` または `%20` にURLエンコードされます。axios は、このテンプレートリテラル内の半角スペースを `+` としてエンコードし、最終的なリクエストURLを生成していたのです。

### 解決策：テンプレートリテラル内の不要なスペースを削除
この問題の解決策は非常にシンプルで、テンプレートリテラル内の不要な半角スペースを削除することでした。

```JavaScript
// 修正後のコード
const apiClientConfig = {
    method: 'GET',
    url: `${config.apiSettings.baseUrl}/search-endpoint`,
    headers: {
        'Authorization': `Basic ${Buffer.from(/* ... */).toString('base64')}`,
    },
    params: {
        query: `searchId:${config.apiSettings.targetId}` // "searchId:" と ${...} の間のスペースを削除
    },
};
```
この修正を適用した結果、生成されるURLは期待通りの形式になりました。

```
Axios generated URL: https://api.example.com/v1/search-endpoint?query=searchId:some123id
```
これにより、外部APIはクエリを正しく解釈し、期待されたデータを返すようになりました。

### まとめ
`axios` の `params` オブジェクトを利用してAPIリクエストのクエリパラメータを動的に生成する際、テンプレートリテラル内の記述には注意が必要です。意図しない半角スペースがURLエンコーディングの過程で予期せぬ文字（今回のケースでは `+`）に変換され、APIの動作に影響を与える可能性があります。

API連携で問題が発生した場合は、まず `axios.getUri()` などの手段を用いて実際に送信されるリクエストURLを確認し、APIのドキュメントで期待されるURL形式と比較することが、原因究明の第一歩となります。

一見単純なスペースの見落としが、API連携においては思わぬトラブルの原因となることがあります。日頃から生成されるリクエスト内容を意識し、丁寧な実装を心がけることが重要です。
EXCEL快捷键



✅ Excel办公最常用快捷键一览（中日对照）
| 快捷键                    | 中文说明       | 日文说明         |
| ---------------------- | ---------- | ------------ |
| **Ctrl + H**           | 查找替换       | 置換（Replace）  |
| **Ctrl + Arrow（左右上下箭）**       | 快速跳转到边界单元格 | セルの端にジャンプ    |
| **Ctrl + Shift + L**   | 添加/取消筛选    | フィルターの切り替え   |
| **Alt + =**            | 自动求和       | オートサム        |
| **Ctrl + 1**           | 单元格格式设置    | セルの書式設定ダイアログ |
| **Ctrl + T**           | 将区域变成表格    | テーブル作成       |
| **F2**                 | 编辑当前单元格    | セルを編集        |
| **Ctrl + ;**           | 插入当前日期     | 今日の日付を入力     |
| **Ctrl + Shift + "+"** | 插入新单元格     | セルの挿入        |


🔧 实用小技巧补充：
想查看所有快捷键？按下 Alt，你会看到顶部菜单显示快捷键提示

追加：
按住ctrl加某个格子，可以跳行选中内容。
F2对文件重命名
SAP表に大量データを検索

在其他地方复制多个品目号数据。点击右下角这个按钮。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3795764/3dc71f19-1ba1-46fd-a0c7-43d11ef6847b.png)
复数的数据粘贴在这里
然后点击「データ転送」、读进检索条件里面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3795764/5f1bd9df-f621-4b13-b168-1a6e9a0611fa.png)
读进检索条件里面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3795764/3e0a73aa-455f-417d-a56e-c35fed8b7336.png)
点击左上角执行即可。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3795764/1247b9d1-8076-4f96-a937-6ba3a57226d6.png)

如果想要清掉数据。选择「全エントリー」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3795764/0a6e4b82-7b09-4a39-8e02-e47b2c13f615.png)
然后点击「データ転送」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3795764/be357a09-b8cb-4747-bcb7-b3b4e3be6a11.png)
数据就被清空了。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3795764/75d30963-63e9-4a41-9a8b-9b7159e5db05.png)
購買情報（Purchasing Info Record：PIR）の設定

購買情報レコード（Info Record, 日本語：購買情報）は、仕入先×品目の組合せで設定する基本マスタです。
以下のような情報を登録します：

購入価格（Net Price）

通貨

納入リードタイム

最小発注数量

発注単位

条件（スケール価格、数量割引など）

🧭 購買情報の設定手順（T-code：ME11）
🔹 手順：
T-code にて ME11 を入力

下記情報を入力：

仕入先（Vendor）

品目（Material）

購買組織（Purchasing Organization）

プラント（Plant） ←あれば
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3795764/9309593f-4342-4067-913e-53441e6381a2.png)
入力完后点击enter，进入下面画面，在这里输入必要信息，保存
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3795764/30de589a-48aa-45ca-9200-678a2d7b954e.png)

📦 関連Tコード一覧：
T-code	内容
ME11	購買情報作成
ME12	購買情報変更
ME13	購買情報表示
ME1M	品目別の購買情報照会
ME1L	仕入先別の購買情報照会

📂 購買情報の主なテーブル：
テーブル	説明
EINA	購買情報（一般データ）
EINE	購買情報（購買組織データ）
A018	品目×仕入先×購買組織の条件レコード
[Java]Accept-Encoding。サーバー実装の注意点（java.net.httpserver.HttpServer など）

## 1. Accept-Encoding に応じた処理を明示的に行う必要がある

HttpServer や低レベルのサーバーでは、自動で gzip などを適用してくれません。サーバー側で対応する圧縮処理を実装する必要があります。

例えば、GZIP を適用する場合はこうします：
```java
String acceptEncoding = exchange.getRequestHeaders().getFirst("Accept-Encoding");
OutputStream responseBody = exchange.getResponseBody();

if (acceptEncoding != null && acceptEncoding.contains("gzip")) {
    exchange.getResponseHeaders().set("Content-Encoding", "gzip");
    exchange.sendResponseHeaders(200, 0); // chunked transfer
    try (GZIPOutputStream gzipOut = new GZIPOutputStream(responseBody)) {
        gzipOut.write("GZIP compressed response".getBytes(StandardCharsets.UTF_8));
    }
} else {
    exchange.sendResponseHeaders(200, 0);
    responseBody.write("Uncompressed response".getBytes(StandardCharsets.UTF_8));
    responseBody.close();
}
```

## 2. Content-Encoding ヘッダーを必ずレスポンスにつける
```java
Content-Encoding: gzip
```
これはクライアントに「このレスポンスは gzip 圧縮されている」と知らせるためです。

## 3. identity を優先したりフォールバックを設ける
クライアントが特定の形式にしか対応していない場合、サーバー側はフォールバック（identity = 無圧縮）を提供するのがベストプラクティスです。
[Java]Transfer-Encoding: chunked がある場合に HttpResponse のボディが空になるという問題について

## 背景：Transfer-Encoding: chunked とは？

HTTP で Transfer-Encoding: chunked が使われると、ボディは「チャンク（塊）」に分割されて送られます。この形式では、Content-Length ヘッダーは使われません。

Java の HttpClient はこのチャンク化されたレスポンスを自動で扱うことができますが、処理の書き方によってはボディを正しく読めないことがあります。

## 確認ポイント（受信側）
#### 1.BodyHandler の指定

HttpClient.send() でレスポンスを受け取る際、以下のようにしてますか？
```java
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
```
これがない、あるいは BodyHandlers.discarding() を使っていると、ボディは読み込まれません。

#### 2.InputStream で受け取って自前で読む方法


Chunked エンコーディングに問題があると感じた場合は、ofInputStream() で受け取り、自前で確認するのも手です：

```java
HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
try (BufferedReader reader = new BufferedReader(new InputStreamReader(response.body(), StandardCharsets.UTF_8))) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
}
```
これで実際にチャンクが届いているか確認できます。

#### 3. サーバーが Transfer-Encoding: chunked を明示的に設定しているか

HttpServer の実装で Transfer-Encoding: chunked を自分で追加している場合、それが誤ったフォーマットになっている可能性があります。

Java の com.sun.net.httpserver.HttpServer などでは、ボディサイズが不明なときに自動で chunked にしてくれることもあります。ヘッダーを手動でいじる場合は注意が必要です。

## 確認ポイント（送信側：HttpServer）

HttpExchange を使っていると仮定して、以下のように書くのが一般的です：

```java
exchange.getResponseHeaders().set("Content-Type", "text/plain; charset=UTF-8");
exchange.sendResponseHeaders(200, 0);  // ← 0 を指定すると chunked エンコーディングになる

OutputStream os = exchange.getResponseBody();
os.write("Hello chunked world".getBytes(StandardCharsets.UTF_8));
os.close();
```
ポイント：

sendResponseHeaders(200, 0)：この 0 は「ボディサイズが不明」を意味し、自動で chunked にしてくれる。

自分で Transfer-Encoding: chunked をヘッダーに追加しても、それだけでは機能しません。正しくチャンク形式で送信される必要があります。
Linuxのコンテナ(LXD)でデスクトップ環境i3と日本語入力のセットアップ方法

# 内容

LinuxにはLXD(あるいはincus)というコンテナ技術があます. ということは, このコンテナでデスクトップ環境なんか作れたら, 遊びがいがあるとおもいませんか？

例えば

- 開発環境の分離や統一
- 再現性を確保するためにコンテナ内で実験をする
- サーバーの練習台やコードの試験
- 擬似的なKVM

などなど. 遊び方は無限大.

しかし, コンテナですから, GNOMEのデスクトップ環境を中で動かのはちょっと苦しいことも多い.

なので**i3というタイル型のウィンドウマネージャを入れ, さらに日本語入力もできるようにしよう**というのが本稿の趣旨です.


# セットアップ方法

そんなに難しくないのでざっくり説明.

1. LXDでUbuntu24.04のコンテナを作る
2. i3, xrdp, 言語パックとibusのインストール
3. ibusの設定
4. 再起動

```bash
# 言語パックとibusのインストール
sudo apt install i3 xrdp language-pack-ja ibus ibus-mozc mozc-utils-gui

# ibusの設定
ibus-setup

# おまけ
sudo apt gnome-terminal
sudo apt nautilus # nautilusはterminalのあとに入れないとインストールできても起動できない
```

# ありうる問題 

## Firefoxだけ日本語入力ができない

注意としてfirefoxはsnap版だと日本語入力ができない. deb版だと上手くいく.

deb版をaptで入れるには次のスクリプトを実行する. スクリプトの内容は[公式](https://support.mozilla.org/ja/kb/install-firefox-linux)のパクリ. (2025/05/21)

フィンガープリントのチェックなど安全性には甘いのでそこら辺は自己責任で.

```bash
#!/bin/bash

sudo install -d -m 0755 /etc/apt/keyrings

wget -q https://packages.mozilla.org/apt/repo-signing-key.gpg -O- | sudo tee /etc/apt/keyrings/packages.mozilla.org.asc > /dev/null

echo "deb [signed-by=/etc/apt/keyrings/packages.mozilla.org.asc] https://packages.mozilla.org/apt mozilla main" | sudo tee -a /etc/apt/sources.list.d/mozilla.list > /dev/null

echo '
Package: *
Pin: origin packages.mozilla.org
Pin-Priority: 1000
' | sudo tee /etc/apt/preferences.d/mozilla 

sudo apt-get update && sudo apt-get install firefox
```

Snap版のFirefoxは次でアンインストールできる.

```bash
sudo snap remove firefox
```

## Rootユーザーだと日本語入力できない

コンテナ環境だと手を抜きたくて一般ユーザを使わずにRootユーザですべてやりたくなるけど, 一般ユーザでないと日本語入力はできない.

Ubuntuディストリビューションではインストール直後からubuntuという名のユーザがいるため, 面倒ならubuntuを使おう. パスワードの設定が必要ならRootユーザで

```bash
passwd ubuntu
```

を実行し新たにubuntuにパスワードを設定しよう.

## Windowsキー+Enterを押しても反応しない！

日本語のセットアップ前に修飾キーをWindowsキーに設定してるとちゃんと機能せず困ったことになったりします. 原因はおそらくキーボードレイアウトの問題. わからないけど.

解決策はAltを使うこと.

```text:~/.config/i3/config
set $mod Mod4
```

を

```text:~/.config/i3/config
set $mod Mod1
```

に変えよう.

もちろん日本語入力の設定が終わったらMod4(Windowsキー)に戻しても問題ない. そのときにはちゃんと機能する.
イミュータブルの嬉しさって何だっけ

## はじめに

日頃、Kotlinでコーディングしている際に、「変数の宣言には`var`ではなく`val`を使う」「ミュータブルではなくイミュータブルなコレクションを使う」などはいつも意識してきました。

ただ、ある日ふと「何でそうした方がいいんだったっけ？」と湧いた疑問に即答できなかったので、おさらいとして記事にまとめます。

ちなみに本記事のサンプルコードではKotlinを使用しますが、考え方などは他の言語にも通ずるものかと思います。

:::note
この記事ではプログラムの変数やデータ構造の不変性についてのみ触れ、データベースやログの不変性などには触れません。
:::

## イミュータブルの基礎

まず、そもそもの前提ですが**イミュータブル**（`immutable`）とは「不変（変更できない）」ことを指す言葉です。この「変更できない」ことによる恩恵を本記事では解説します。

なお、具体的にどうやってコードをイミュータブルにするのか、という観点はこの記事では割愛し、別の記事で解説する予定です。


## 嬉しさ

### 1. 動作が安定し、コードが読みやすい

これが、イミュータブルがもたらしてくれる恩恵のメインです。

変数の値やオブジェクトの状態が変わらない（常に同じ）ので、いつどのタイミングでも同じ値が取得できます。
「当たり前じゃん、それの何が嬉しいの？」と言われそうなので、ミュータブルな（変更可能な）場合と対比しながらもう少し詳しく説明します。


#### 値が常に変わらないため、認知負荷が小さい

ミュータブルな場合、変数やオブジェクトの状態がどこかのタイミングで変わっている可能性があります。例えば、特定の条件で（特定のif分岐を通ると）少し値が変わる、などですね。
こうなると、「この時点では、このデータは何になってるんだろう？」と常に気を配りながらコードを読む必要があり、認知負荷が大きくなります。

簡単に言うとコードを読むのがしんどいです。

ミュータブルなコードのつらさが極まっている例として「グローバル変数」があります。グローバル変数はいつでも誰でも変更可能な変数です。そのため、いつ、何のきっかけで、どんな値に変更されたのか把握するのがとても大変です。
グローバル変数が絡んでいる処理で不具合が発生した場合、その原因調査も困難を極めます。もう経験したくない思い出です。

反面、イミュータブルなコードでは変数やオブジェクトの状態が生成された時点から変わりません。変更を加える場合、元のオブジェクトを変更するのではなく、異なる値を持つ別オブジェクトを新しく生成します。


```kotlin
val items: List<Item> = listOf(...)

// 元のitemsは変更されず、新しい価格を持つリストが生成される
val discountedItems = items.map { it.copy(price = it.price * 0.5) }
```

コードの特定の箇所でオブジェクトがどんな状態なのかは明白なため、コードの予測可能性や可読性が高まり、デバッグも容易になります。


#### スレッドセーフティの向上

イミュータブルな設計は、マルチスレッド環境でも有利に働きます。
他のスレッドによって変更されていることを心配しなくていい（データの一貫性が保証されている）ため、複雑なロック処理などを設ける必要がありません。

簡潔で安定した並行処理を実現しやすくなります。   


### 2. 関数型プログラミング原則との整合性

関数型プログラミングにおいて、イミュータビリティは核心的な概念の一つです。
前述した「スレッドセーフティ」に加えて、「純粋関数の実現」にも深く関連しています。

#### 純粋関数と宣言型プログラミング

`純粋関数`とは、下記の条件を満たす関数のことを言います。

* 同じ入力に対して常に同じ出力を返す
* 副作用を持たない、つまり（意図せず）外部の状態を変更することがない

純粋関数とイミュータブルデータを組み合わせると、常に安定した挙動が得られるので複雑さが大幅に削減されますし、状態変更できないことで副作用も排除しやすくなります。

関数型プログラミングで純粋関数が重視されているのは、振る舞いを予想しやすいシンプルな部品を作成することで、より**宣言型プログラミング**のアプローチを実現しやすくなるためです。言い換えれば「どのように（How）達成するか」ではなく「何を(What)達成するか」に注力できるため、コードの意図が明確になります。

```kotlin
val numbers = listOf(1, 2, 3, 4, 5, 6)

val result = numbers
               .filter { it % 2 == 0 } // 「偶数である」という条件で絞る
               .map { it * 10 }       // 「10倍する」という変換を施す
               .take(2)               // 「最初の2要素を取る」
```

このコードには「どのように」フィルタリングや変換を行うかは登場せず、あくまで「何を達成したいか」だけを羅列した宣言的なコードになっています。
このため意味を理解しやすいですし、将来的な変更が必要となった場合の保守も容易です。

## 注意点

では、常にイミュータブルな設計が最善なのかと言えば、必ずしもそうではありません。
あえて（部分的に）ミュータブルな設計を取り入れることが合理的な場合もあります。その代表例はパフォーマンスが問題になるケースです。

例えば、あるオブジェクトのプロパティが頻繁に変更されるようなケースを考えてみます。

変更される度にオブジェクトを再生成するのでは、メモリの使用量などが増大してパフォーマンスを悪化させる懸念があります。そのようなケースでは、あえて再代入可能なプロパティとして定義し、イミュータブルな設計を（部分的に）崩すことにも一考の余地があります。
ただ、その場合もプロパティをpublicに公開すると無秩序に変更される恐れがあるため、アクセサ経由でしか参照や変更ができないようなカプセル化は意識するべきでしょう。

この他にも、たとえば数百万件規模の大規模なデータコレクションに対する操作などは、ミュータブルに扱おうとするとパフォーマンスを悪化させる懸念があります。


## おわりに

即答できなかった「イミュータブルって何が嬉しいんだっけ」という問いについて整理してみました。

基本的なことですが、とても大事なことなので、忘れたり思い出したりするのではなく、当たり前に自分の中に在るようにしたいですね。
Laravelのルートエラー：該当箇所じゃないルート名の記述を正しくしたら何故か治った件を調査


```php
BadMethodCallException: Method App\Http\Controllers\SimpleController::index does not exist.
```

今日はこれが出ましたよ。
ルート設定は
```php
Route::resource('simple', SimpleController::class);
```

の形。
今回の仕様は他のindexにお邪魔させてもらう形だったので、SimpleControllerにはindexは書いていなかったんだ。

なのに出たエラー

結局はdestroyメソッド内のリダイレクトの文字を間違えていたので、そこを修正したら治ったのだ。
ただ、そのリダイレクト先も他の〇〇.indexだったので別名だ。

私が考えたのは

```
コントローラー全体のメソッドをインスタンス化するときにタイプミスを発見。
削除メソッドのリダイレクトは通常Laravelではそのコントローラーのindexが入る。
indexを探したがindexがないよ。
エラー出す。
```

storeメソッドを呼び出すときもコントローラー全体を呼び出してルートの確認をするならまだ分かる。
がそういった機能はLaravelにはないようだ。



調査結果のまとめは下記
#### 未実装メソッドは “呼ばれなければ無害”

`Route::resource()` で index ルートが登録されても、  
実際に **GET /resource** を叩かなければ Laravel は `index()` を探しに行かない。  
メソッドが無いことによる *BadMethodCallException* は  
**リクエスト or リダイレクトが発生した瞬間** だけ起こる。


治した場所が直接関係していなかったのかな。
色々思い当たる節を治して回ったから覚えてない。。。もう一回同じ事象に遭遇しないかな。
Slack × AIエージェントの設計思想をClean ArchitectureとDDDで考える

この記事では、Slackからの質問に応答するAIエージェントを構築する際に、設計思想（Clean Architecture × DDD）を整理・検討してみました。

# 📘 Slack MCP Agent - Architecture Guide

## 🎯 設計思想：Clean Architecture × DDD

本プロジェクトは [Clean Architecture](https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html) と [Domain-Driven Design (DDD)](https://en.wikipedia.org/wiki/Domain-driven_design) を基盤とし、変更容易性・再利用性・テスト容易性を実現します。

- **ビジネスロジックは外部依存から独立**
- **ユースケースがドメインとインフラを仲介**
- **I/Oは外部に押し出す**
- **各層の責務を厳格に分離**

---

## 📊 アーキテクチャ図（Mermaid）

```mermaid
graph TD
  UI[🖥️ UI層<br>Slack / Web UI]
  UI --> API[🚏 ルーティング層<br>FastAPI Routes]
  API --> Usecase[📦 ユースケース層<br>Usecases]
  Usecase --> Domain[🧠 ドメイン層<br>Entity/Interface]
  Usecase --> Infra[🔧 インフラ層<br>DB/API]
  Infra --> DB[(💾 SQLite)]
  Infra --> ExtAPI[🌐 外部API<br>OpenAI / Gmail / Drive / Serper]
```

---

## 🗂 ディレクトリと責務

| ディレクトリ | 説明 |
|--------------|------|
| `app/domain/models/` | ビジネスの核を成す Entity / ValueObject。状態と振る舞いを定義 |
| `app/domain/repositories/` | Repository のインターフェース。インフラ層に依存しない抽象 |
| `app/usecases/` | アプリケーションの振る舞い。外部の要求を実現する処理単位 |
| `app/infrastructure/` | 外部との接続（DB, APIクライアント, Adapter, 設定など） |
| `app/interfaces/` | FastAPIによる Web / Slack のエンドポイントと依存注入層 |
| `app/agent/` | LangChain / MCP による AI 構成。Prompt定義・Runner実装など |
| `app/shared/` | JWT, 認証、Slackヘルパーなどの共通処理 |
| `app/core/` | 設定ファイル読込・スケジューラなど汎用サービス |
| `app/database/` | DB初期化など、1回限りの処理群（DDLなど） |

---

## 🔁 各層の依存関係（矢印の方向）

```
UI (HTML/Slack)
  ↓
Interfaces (FastAPI Routes)
  ↓
Usecases (Application Services)
  ↓
Domain (Entity / Interface)
  ↑
Infrastructure (DB/API/Adapter)
```

→ **依存の向きはすべて内側へ**

---

## 🚀 モジュール追加時の拡張指針

### 例：X（例：Teams連携）を追加したい場合

| 対象 | 対応内容 |
|------|----------|
| `domain/` | 必要があれば ValueObject を定義（例：Message） |
| `usecases/teams/` | Teams 連携ユースケースを新設（例：teams_usecase.py） |
| `infrastructure/apis/teams_client.py` | Teams API クライアントを新設 |
| `interfaces/routes/teams.py` | POSTエンドポイントやWebhookイベントを追加 |
| `shared/utils/teams_helper.py` | 共通フォーマット処理が必要ならヘルパーで切り出し |

### ポイント：
- **常に「ビジネスロジック→ユースケース→インフラ→I/O」の責務分離を維持**
- **インターフェースの実装（`implements`）はインフラ層に限定**

---

## ✅ ベストプラクティスまとめ

- **ドメイン層は最も重要、かつ不変**
- **ユースケース層は「何をするか」に集中**
- **インフラ層は「どう実現するか」に限定**
- **インターフェース層は「どこから来たか」の責務**

---

## 📌 推奨資料

- [The Clean Architecture by Uncle Bob](https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html)
- [Domain-Driven Design: Tackling Complexity](https://www.domainlanguage.com/)
- [LangChain 文書](https://docs.langchain.com/)

---

## 📝 まとめ

* 本記事では、Slackからの質問に応答するAIエージェントの設計思想を、Clean ArchitectureとDDDに基づいて整理しました。
* 各層の責務を明確に分離することで、**拡張性・テスト容易性・保守性**を高めることができます。
* Mermaidを活用したアーキテクチャ図やディレクトリ構成の整理により、**全体像が直感的に把握**できるようにしました。

## 🔭 今後の展望・課題

* ChatGPTだけでなく、ClaudeやGeminiなど**複数のLLMへの切り替え対応**
* **SaaS連携の追加**（例：Notion, Confluence, Miroなど）に対応するユースケースの設計
* WebSocketベースのブラウザ連携や、**Slackとのマルチチャネル対応**
* LangGraphやAgentExecutorなどを使った**状態管理付きエージェントの導入**
機械学習モデルの「透明性」と「説明可能性」についてまとめてみました

# 1.はじめに
どうも、ARIの名古屋支社に勤務している愛知県民こと、
新藏（にいくら）と申します♪
(/・ω・)/

生成AI、引き続き盛り上がっていますね！

先日、社内勉強会のコンテンツとして、
**機械学習モデルの「透明性」と「説明可能性」について考える機会がありました。**

そこで今回は上記2つについて、記事にしたいと思います

AIや機械学習について勉強中の方の参考になれば幸いです。
(*^^)v

# 2.機械学習モデルの透明性とは
## 2.1.定義
まず初めに定義ですが、**機械学習モデルの「透明性がある状態」とは、
モデルの内部構造・動作が明確で、第三者がそのプロセスを理解できる状態のことです。**

参考

https://atmarkit.itmedia.co.jp/ait/articles/1909/26/news013.html


具体的には、以下のような要素が含まれます。

* 解釈可能性: モデルがどのようにして予測や判断を行っているかを説明できること。
* 再現性: 同じデータと条件で同じ結果を再現できること。
* トレーサビリティ: モデルのトレーニングデータやアルゴリズムの選択理由など、意思決定の過程を追跡できること。


## 2.2.透明性を高める方法
続きまして、透明性を高める方法についても調べてみました。
以下の3通りの方法があるようです。

* ホワイトボックスモデルの利用
→ 決定木、線形回帰など、内部構造が人間にとって分かりやすいモデルを使う

* ドキュメントの整備
→ モデルの設計・学習過程・パラメータなどを記録し、誰でも追跡できるようにする
* コードやデータの公開
→ オープンソース化や、データセットの共有により第三者検証を可能にする

# 3. 機械学習モデルの説明可能性とは
## 3.1. 定義
こちらも定義ですが、
**機械学習モデルの「説明可能性がある状態」とは、モデルが出した予測・判断の理由や根拠を、利用者や第三者に分かりやすく説明できる状態のことです。**

参考

https://ja.wikipedia.org/wiki/%E8%AA%AC%E6%98%8E%E5%8F%AF%E8%83%BD%E3%81%AAAI

透明性が「中身が見える」ことに対し、
説明可能性は「なぜその結果になったのかを説明できる」ことに重点があります。

## 3.2. 説明可能性を高める方法
説明可能性を高める方法についても調べては見たのですが、
自分自身は40%くらいの理解です・・・

* 特徴量の重要度評価
→ どの入力（特徴量）が予測にどれだけ影響したかを示します

* モデル解釈ツールの利用
→ LIMEやSHAPなど、ブラックボックスモデルでも説明を与えるツールを活用します

* 局所的説明
→ 特定の予測結果について、なぜその判断に至ったかを個別に説明

# 4.透明性はあるが、説明可能性がない例
具体例から理解してみるということで、
透明性はあるが、説明可能性がない例を考えてみました。

社内のワークフローシステムを例として

A部署はtest.txtというファイルを受けとり、B部署に送る
→B部署はExcelに転記し、C部署とD部署に送る
→C部署はExcelからcsvに変換し、B部署に送り返す
→B部署はExcelとcsvをPDFに変換し、E部署に送る
→D部署はExcelを複製してファイルの先頭にyyyymmdd_作業前_、yyyymmdd_作業後_をつけ、E部署に送る
→・・・
→test.pdf　と　yyyymmdd_作業後_test.xlsx　と　test_before.png
というファイルがアウトプットになる

上記の例は
**フロー自体は決まっている（=透明性がある）のですが、
最終的なアウトプットがどうできたのか説明するのが難しい（=説明可能性がない）** 
となります。

# 5.透明性はないが、説明可能性はある例
こちらも前章と同様に、考えてみたのですが思いつかず、WEBを調べました・・・

各テキストが「無神論者(atheism)」か「キリスト教徒(christian)」
のどちらが書いたものかを予測するタスクを考えます。

ここにLIMEを使用すると
**判断のロジックはよく分からない（透明性がない）が、
単語が判断にどのくらいの影響を与えたかが分かる（説明可能性がある）**
とのことです。

参考

https://qiita.com/matsuda_tkm/items/06d19830766907080dcf

# 6.おわりに
ここまで読んで下さり、ありがとうございます！！！
(^^)

個人的には軽い気持ちで調べ始めたのですが、違いを整理するのが難しかったです・・・
いつか、この辺りも説明できるように引き続き頑張ります♪
(:3_ヽ)_

# 7.仲間を募集しています！
最後に告知ですが、
ARIでは東京本社・関西支社・名古屋支社の各拠点に対し、
エンジニア・ITコンサルタント・PM職等の全方位で仲間を募集しています♪
　
カジュアル面談も随時受付中です。
**「このQiita記事を書いた人と話してみたい」というオーダも可能ですので、
ぜひお気軽にお問い合わせください！**
 
https://note.com/ari_hr/n/n4aed9ba75421
Azure Arc Enabled SQL Server / Azure VMware Solution  (おまけ) のライセンス形態 について

Azure Arc Enabled SQL Server と Azure VMware Solution のおまけ的な話をまとめました。

以下のリンク先で Azure SQL VM のライセンスについてもまとめてます。
[Azure SQL VM のライセンス形態 について](https://qiita.com/CODEPLS/items/1c8642913390d537c8ea "Azure SQL VM のライセンス形態 について")

## Azure Arc Enabled SQL Server のライセンス形態

Azure Arc Enabled SQL Server (長いので Arc SQL Server と呼称します) ではコア ベース ライセンス のみサポートされていて、こちらも従量課金もしくはソフトウェア アシュアランス付きライセンスの持ち込みで特典を受ける事ができます。

コア ベースには 物理コア ベース / 仮想コア ベース / 無制限の仮想化ができる物理コア ベース の 3 つのコア ベース タイプがあります。

また、Standard と Enterprise では 1 コア単位の料金が異なり、Normalized Cores (NCs) といった単位で以下のように計算されます。

Standard エディション   = 1 NC
Enterprise エディション = 4 NC

### 物理コア ベース

サーバーの物理的なコア数を基に料金が計算されます。
物理コア ベースでは VM 上の SQL Server へライセンスを適用することができません。

Standard または Enterprise ライセンスが適用対象となり、サーバー上で Standard と Enterprise エディションで SQL Server を稼働している場合、Enterprise エディションで計算がされます。

例: 物理コア 10 のサーバーで以下のように SQL Server を構成している場合

SQL Server SE = 10 NCs
SQL Server EE = 40 NCs

合計: 40 NCs

### 仮想コア ベース

サーバー上で稼働している各 VM のコア数を基に料金が計算され、Standard または Enterprise ライセンスが適用対象です。

Azure 以外のクラウド環境の VM の場合は仮想コア ベースでのライセンス適用が可能です。

Standard エディションでは仮想コアが最大 24 コアに制限、Enterprise エディションでは無制限のコアで構成できます。

また、仮想コア ベースのライセンスに限っては従量課金とソフトウェア アシュアランス付きライセンスのほか、ライセンスのタイプとして LicenseOnly といった Developer / Express / Web / Evaluation エディション と Server+CAL ライセンスに対して適用できるものもあるようです。

例: サーバーで以下のように VM 毎に SQL Server を構成している場合

SQL VM SE 24 vCores * 1 = 24 NCs
SQL VM EE 32 vCores * 4 = 128 NCs

合計: 152 NCs

### 無制限の仮想化ができる物理コア ベース

このライセンスでは Standard エディションが使用できず、Enterprise エディションのみ適用可能なライセンスです。

物理コア ベースで各 VM 上にホストされている SQL Server へライセンスの適用でき、仮想コア ベースと違い VM 毎にコストが発生せず、さらに VM 数に制限がありません。

また、Enterprise エディションなのでコア数制限もなく、大量にインスタンスを構成している大企業向けのサービスといったところでしょうか。

しかしながら、こちらのライセンスでは以下のプロパイダーにデプロイしている VM に対して適用することができません。

- Alibaba
- Amazon
- Google
- Microsoft

また、通常の SQL VM のライセンスと同様に、パッシブ インスタンスに対して HA/DR ライセンスを適用することもできるようで、可用性グループと FCI でそれぞれ条件が少し異なります。

===== Microsoft の公開情報から一部抜粋

可用性グループ

- オペレーティング システム環境 (OSE) に存在するすべてのレプリカは、Always On 可用性グループのセカンダリ レプリカであるか、分散型可用性グループのフォワーダーである必要があります。
- データベースの状態に関係なく、AG の外部にスタンドアロン データベースはありません。
- master、msdb、tempdb、またはモデル データベースを除くデータベースへのアクティブな接続はありません。
- 同じ OSE に関連付けられているサービスのインスタンスはありません。

OSE に複数の SQL Server インスタンスがある場合、すべてのインスタンスとレプリカが上記の条件を満たしている必要があります。

FCI

- ノードは、存在するすべての FCI のパッシブである必要があります。
- AG パッシブ レプリカの対象ではないスタンドアロン インスタンスがノードに存在しません。
- 同じ OSE に関連付けられているサービスのインスタンスはありません。

=====

## AVS 上の SQL Server に対するライセンス適用

AVS 上の SQL Server ライセンスについておまけ的な部分となります。

この構成では Azure Arc を介してライセンスを適用することで ESU (延長セキュリティ更新プログラム) 特典が得られます。

Azure VMware Solution でライセンスを登録する

https://learn.microsoft.com/ja-jp/azure/azure-vmware/license-sql-windows-in-avs#register-licenses-in-azure-vmware-solution

ここからややこしい話になりますが、Microsoft の公開情報では AVS 上の SQL Server にライセンスを適用するには Azure Arc を使用するとの記載がありますが、ESU 特典などを受けれないだけで Azure Arc を使用せずライセンス適用を行ってもライセンス違反となることはないようです。

このあたりの定義が結構曖昧な感じで、Microsoft からライセンスについての監査があった場合などでちゃんとライセンスが管理されている状態が確認できれば問題がないとかなんとか…

### おまけのおまけ

Azure Arc を使用する場合の料金については Azure の料金計算ツールで計算することができます。

料金計算ツール

https://azure.microsoft.com/ja-jp/pricing/calculator/?service=azure-arc

ライセンス、ムズカシイ…
tryhackme practice day2

# はじめに
[前の記事]()のつづき。あくまで自身のセキュリティ意識の向上のための自己研鑽です。wslでインストールしたkali linuxの選択を間違えたのか，ツールが軒並みインストールされてなかった

# day2. はじめてのハッキング
特定のRoomを解いていくわけではなく，淡々とハッキング用のツールを紹介していく流れ

## nmap
ポートスキャン用のツール。
```
sudo apt install nmap
nmap -sV -Pn -oN nmap.txt -v <スキャン先ipアドレス>
```

各ポートでなんのサーバーが立ってるかも分かるのか
![スクリーンショット 2025-05-20 231612.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/774226/63590def-4c8c-4df7-8fb9-a4a56891d611.png)

## ページのソースを開く
普通のサイトなら今どきビルドかけるから，人間では読めないのではと思った。
どちらかというと，次のdirbへの導入のためか

## dirb
ウェブサーバー上の隠しディレクトリやファイルを発見するために使われるウェブコンテンツスキャナー。辞書攻撃。
```
sudo apt install dirb
dirb <スキャン先> <辞書ファイル>
```

smallでも5分くらいかかった
![スクリーンショット 2025-05-20 230044.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/774226/beaac7ed-2865-4b42-b032-5942bbac6f93.png)

## gobuster
本には載ってないが，勉強に使ったRoomで紹介されていた。
dirbの改善版で，goで書かれていて，高速らしい。

Roomで紹介されていた辞書ファイルの指定が良く分からんかったので，dirbの辞書を使用。
dirbだと体感5分かかったのが，gobusterだと体感30秒といった感じ。
```
sudo apt install gobuster
gobuster -u <スキャン先> -w <辞書ファイル> dir
```
![スクリーンショット 2025-05-20 233345.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/774226/614ffb17-6aac-43c1-a6eb-0455ac8583d9.png)


## sambaのポートが開いてる場合の手口
今回のRoomではsambaのポートが開いてなかったので，また今度

## 辞書攻撃・wordlists
パスワードによく使われる単語を集めた辞書を使い，一つずつパスワードを試す攻撃。
辞書はwordlistsというパッケージで取得できる。
```
sudo apt install wordlists
sudo gzip -d /usr/share/wordlists/rockyou.txt.gz
```
rockyou.txtはRockYouというWebサービスから漏洩した1400万個のパスワードでよくハッカーに使われるらしい。

## Hydra
ネットワークログインクラッカーとして知られる強力なセキュリティテストツール。ブルートフォース攻撃や辞書攻撃をサポートしたオンラインパスワードクラッキングツール。

本内ではwordlistsの辞書を使い，Hydraでsshを辞書攻撃していたが，今回のRoomはそのような感じではなさそうなので．また今度

## 横展開
一度ハッキングに成功してから，別のユーザーにもアクセスを試みることを水平展開・横展開という。特により強い権限のユーザーを試す場合，権限昇格という。

本内ではパーミッション設定が不適切なパスワードファイルを探すなどのヒントがあった。

## 使用したRoom
Offensive Security Introというビギナー用Room
```
「ハッカーを出し抜くには、ハッカーのように考える必要がある。」
```
システムの脆弱性を見つけるために，ハッカーの行動をシミュレーションするのが`Offensive Security`とのこと。Offensive securityを学ぶキャリアパスの紹介用Roomなのかな。

Roomの課題自体はダミーの銀行サイトについて，gobusterで送金用ページを見つけ，不正に自分のアカウントに振り込むという流れ。

dirbの辞書ファイルでは送金用ページを見つけられずに，結局見つけられた体で問題文にある送金用ページのリンクに飛んじゃいました。課題用のマシンに既に辞書ファイルが用意されているところを，無理やり自分のkali linuxでやろうとしたためです。多分辞書ファイルにも良い悪い古い新しいがあるんでしょうね。

## サマリー
- nmap: ポートスキャンツール
- gobuster: 隠しディレクトリ検索ツール（ベーシックなものにdirbがある）
- wordlists: 辞書攻撃用辞書パッケージ
- Hydra: 辞書・ブルートフォースアタック用ツール

## ぼやき
普通に本に書かれてて，AIにも聞いたら答えられて，aptでインストールできるパッケージをまとめてるだけなんですが，なんかBANされないか不安になってきますね
MCP+ChatBOT最強説、ChatOps復活！Opsに限らず社内ツールとの連携で全社員がハッピー

ChatOps、もう当たり前になって言葉すらあまり聞かなくなったんですが

MCPとLLMによって、かつてエンジニアがOpsのために使ってたChatOpsが今後は全社的にグローバルに使えるのでは？と思ったので書きます

たとえばWebメディアなら・・・

slackから、ライターが記事更新
slackから、お知らせ枠更新
slackから、掲示板荒らしをBAN

こんな感じで夢はひろがりそう

タイトルがすべてなので以上です

終わり
陰陽師的解釈「君たちはどう生きるか」

この映画では、冥界・天界・式神（人間の言葉を使う生き物たち）といった陰陽師要素が詰め込まれています。  
ここでは陰陽師になぞらえて物語を解釈していきます。  
小説を書く練習として、小説風にして書いていきます。

---

## 陰陽師の基本設定

陰陽師は**心の悩みを式神として具現化**し、それを祓うことで悩みを抑え込みます。

---

## 第1話：新しい母親（死んだ母の妹）

元あった家も病院も燃え尽きた。  
私の脳裏には、母の入院中の姿しか残っていない。  
母もろとも焼け野原になった東京を離れ、私は父とに横浜へと移った。父には横浜で戦闘機開発の仕事があったため、御屋敷を買い取り、新たな住まいとしたのだ。

駅につくと、商店や通り過ぎる車が歪んで見えた。夏の暑さのせいだろうか。  
ぼやけた視界から一人の女性が現れた。女性は父に手を振り、私の顔をのぞき込み、何かを言った。

何を言ったのかは分からなかった。ただ、彼女のルージュの唇が激しく上下しただけだった。  
振り返ると、父は手を振りながら、小走りでバスへと駆けていった。  
女性もまた手を振っている。指にはめた銀色の輪が煌めいている。

気が付くと私は人力自転車の荷台に乗せられていた。  
視界が上下に揺れて、街はロールを巻き取られるかのように、激しく移ろい消えていった。  
ぞぞっと背筋が震えた。

少しすると、生暖かい温度が皮膚に届いた。  
隣を見やると、女は貼り付いたような笑顔でこちらを向いている。  
太陽が逆光となり、赤い口紅だけがやけに脳裏に焼き付いた。

後に、私は女の存在を理解した。  
女は**新たなハハ**であった。
Azure SQL VM のライセンス形態 について

Azure SQL Server のライセンス形態ってなかなかややこしいですよね…

SQL VM に加えて Azure Arc Enabled SQL Server、Azure VMware Solution 使用時のライセンスについてもまとめてこの記事に投稿しようとしましたが、思いのほか長ったらしくなったので分割で投稿。
[Azure Arc Enabled SQL Server / Azure VMware Solution (おまけ) のライセンス形態 について](https://qiita.com/CODEPLS/items/40a61f050b6c4d80eb15 "Azure Arc Enabled SQL Server / Azure VMware Solution (おまけ) のライセンス形態 について")

以下に SQL VM のライセンスについてまとめてみました。

## SQL VM のライセンスの種類

SQL VM のライセンスは 3 種類存在します。
なお、いくつかのライセンスのうち、有料ライセンスとなるのは Web、Standard、Enterprise のみとなります。

### 従量課金
使用した分の VM のコストに加えてライセンス コストが発生します。
また、ライセンス コストに関しては VM の vCPU 数分によってコストが異なるので注意が必要です。

### ハイブリット特典 (AHB)
保有している SQL Server のライセンスを持ち込むことで VM のコンピューティング リソース 分のみの料金となり、SQL Server のライセンス コストが発生しません。

AHB 特典を適用するには ソフトウェア アシュアランスまたはサブスクリプション ライセンス付きの SQL Server コア ベース ライセンスである必要があります。

### HA/DR
HA および DR 用の SQL VM を構築する際に追加のライセンス コストを支払う必要がなく、無料でデプロイが可能です。

ただし、あくまで HA/DR 用となるので、HA/DR ライセンスが適用されているセカンダリに対して読み取り専用データベースなど何かしらの処理を行う必要がある場合、このライセンスの適用はできません。

なお、このライセンスについては従量課金および AHB ともに適用が可能です。

## SQL VM のライセンス適用について
ライセンスの適用方法として、以下のようないくつかのシチュエーションがあると思います。

### 既存の VM に後から SQL Server をインストール
SQL Server をインストール後、SQL IaaS Agent 拡張機能へ登録する必要があります。

また、SQL IaaS Agent 拡張機能へ登録時にライセンスの種類として、従量課金であれば PAYG、ライセンス持ち込みであれば AHB を指定することで AHB 特典の利用が可能です。

従量課金の場合はどこからプロダクト コードを持ってくるんだ？ってなると思いますが、SQL Server 付きイメージの Windows Server をデプロイしてその中からプロダクト コードを引っ張ってくることが可能です。(C:\SQLServerFull\x64\DefaultSetup.ini の PID 箇所)

引っ張ってきたプロダクト コードを適用後、PAYG で登録しましょう。

### マーケット プレイスから SQL Server 付きのイメージで VM をデプロイ

上記と違い、SQL Server 付きイメージの Windows Server でデプロイした場合はデプロイ時に自動的に SQL IaaS Agent 拡張機能への登録が行われます。

注意点として、デプロイ時に従量課金を選択していて後から AHB を適用している環境では、SQL IaaS Agent 拡張機能の登録時に生成される SQL 仮想マシン リソースを削除した際に、手動で再登録を行わない場合は計画メンテナンス時に SQL 仮想マシン リソースが自動的に生成されることとなり、自動で生成されるとデプロイ時の設定を基に生成するのか従量課金で生成されてしまいます。

そのため、削除してしまった際には再度手動で AHB で SQL IaaS Agent 拡張機能に登録しておいた方がよいです。

補足として、従量課金から AHB もしくは AHB から従量課金へライセンスを切り替える際にはダウンタイムの発生などがなく、シームレスに切り替えが行われます。
【lazy.nvim】たまに使うプラグインはcondプロパティを使うと便利

:::note
本記事は[Vim駅伝](https://vim-jp.org/ekiden/) 2025-05-21の記事です。
前回の記事はthincaさんの「[Meguro.vim #29 を開催しました](https://thinca.hatenablog.com/entry/2025/05/megurovim-29)」でした。
:::
## はじめに
小ネタ記事です。
プラグインマネージャーである[lazy.nvim](https://github.com/folke/lazy.nvim)で、特定条件のときにだけ読み込みたいプラグインを読み込む方法の解説です。

- 使用環境
  - Neovim: `v0.11.1`
  - lazy.nvim: `v11.17.1`(`6c3bda4`)

## 結論
特定条件のときにだけ使用したいプラグインは、lazy.nvimの`cond`を使うとアンインストール対象にならなくなります。

e.g. 環境変数`PLUGIN_ENABLED`が定義されていたら`some/plugin.nvim`を有効にする場合
```lua:load-plugin-nvim.lua
{
  "some/plugin.nvim",
  cond = function()
    local plugin = os.getenv("PLUGIN_ENABLED")
    if plugin ~= nil then
      return true
    else
      return false
    end
  end,
  opt = { plugin_spec }
}
```

## `enabled`プロパティじゃだめなの？

lazy.nvimのドキュメントを確認すると、プラグインの読み込み設定を制御するプロパティには`enabled`と`cond`があります。

https://lazy.folke.io/spec#spec-loading

名前からして`enabled`を使用すれば良さそうですが、こちらを使うとプラグインが削除対象になってしまいます。

私は`OLLAMA_HOST`という環境変数があるときにのみ、`avante.nvim`を読み込むような設定をしています。
`enabled`プロパティを使って以下のような設定を記述した時、`OLLAMA_HOST`という環境変数が無い場合には、lazy.nvimの削除対象に`avante.nvim`が含まれてしまいます。
このままでは、他の削除したいプラグインといっしょに削除してしまいます。

```lua:avante.lua
{
  "yetone/avante.nvim",
  -- (省略)
  enabled = function()
  local ollama_host = os.getenv("OLLAMA_HOST")
    if ollama_host ~= nil then
      return true
    else
      return false
    end
  end,
}
```

![スクリーンショット 2025-05-14 23.20.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320986/283659b4-f8bf-486b-84a1-fd19b8ed2aa3.png)


削除対象のプラグインが並ぶ`Clean`セクションに`avante.nvim`がいる図。

## `cond`プロパティを使う

lazy.nvimのドキュメントを確認すると、次のように書かれています
> Behaves the same as enabled, but won't uninstall the plugin when the condition is false. Useful to disable some plugins in vscode, or firenvim for example.

 ChatGPTによる日本語訳
> 有効化（enabled）と同じ動作をしますが、条件が偽の場合でもプラグインはアンインストールされません。VS Code や firenvim などで一部のプラグインを無効化したいときに便利です。

つまり、一部のプラグインを無効化したいときは`enabled`ではなく`cond`プロパティを使ったほうが良いということですね。
先程の設定の`enabled`を`cond`に変更し、lazy.nvimのダッシュボードを確認してみます。

```diff_lua:avante.lua
 {
   "yetone/avante.nvim",
   -- (省略)
-  enabled = function()
+  cond = function()
   local ollama_host = os.getenv("OLLAMA_HOST")
     if ollama_host ~= nil then
       return true
     else
       return false
     end
   end,
 }
```

![スクリーンショット 2025-05-14 23.21.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320986/51ff906c-d32b-4c08-ae11-94e226db6325.png)

`avante.nvim`が`Clean`セクションから`Disabled`セクションに移動している図。

これで特定条件でないときにはプラグインを無効化でき、なおかつ削除対象から外すことができました。

## まとめ

`init.lua`を育てていたときにこの仕様を知りました。公式ドキュメントを読むって大事ですね。
私の場合は環境変数でプラグインを読み込みを制御する形で使っています。
VSCode Neovimとかと`init.lua`を共存させたいときには`vim.g.vscode`を参照してあげると便利かもですね。
【git-spice】ブランチ作成時にコミットしないようにする方法

以下のコマンドを実行するとブランチ作成時にコミットされなくなる。

```terminal
git config --global spice.branchCreate.commit false
```

https://abhinav.github.io/git-spice/recipes/#create-branches-without-committing

```terminal
gs branch create my-branch
```

上記のコマンドを実行してもコミットはされない。
コミットしたい場合には`--commit`をつける。

```terminal
gs branch create my-branch --commit
```