OmniAICreator/Qiita-1.07M huggingface dataset:
SAP Business Data Cloudについてのまとめ

2月にSAPからSAP Business Data Cloud(以下BDC)という新しいソリューションが発表されました。SAPに関わっている(特にBI系)身としては気になるところなので調べてみました。

:::note warn
3/13時点での調査内容なので今後変更になる可能性があります。
また私の認識違い等ありましたらご指摘頂けると幸いです:bow_tone1:
:::

# 1.SAP Business Data Cloudとは？
BDCの1か所にSAPデータ・非SAPデータの保存・管理・接続を支援しSAP HANA Cloud、SAP Datasphere、SAP Analytics Cloud(以下SAC)などの戦略的ソリューションとその機能を１つのソリューションに統合したものがBDCというSaaSソリューションになります。

またBDCのアーキテクチャは以下の図になります。
![DBC図1_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110632/8a880b7e-7b28-4ac6-a82e-81a216212f4a.png)

## 1-1.SAP Analytics Cloud・Insight Apps
1.は分析とダッシュボードを提供する層となり、SAC・Insight Appsが位置します。
Insight AppsとはSAPから提供されるデータの抽出・モデリング・ダッシュボードまで作成された事前定義済みアプリケーションでSap Business Data Cloud Cockpit(以下BDC Cockpit)からインストールを行い使用可能となります。

SACはInsight Appsを使用したすぐに使用できるレポートシナリオで必要なダッシュボードを提供する為に使用されます。
またInsight AppsはSACを使用したダッシュボードだけではなく、SAP BTPベースのInsight Appsも予定されているとのこと。

ここで気になるのは現在SACを使用しているユーザーはBDCを導入しないとSACが継続使用できないのかどうかですが、そのまま現在のSACのみで使用するのも可能なようです。

## 1-2.BDC Cockpit・SAP Datasphere・SAP BW PCE・SAP Databricks
2.はモデリング・機能拡張の層となりBDC Cockpit、SAP Datasphere、SAP BW PCE、SAP Databricksが位置します。
BDC Cockpitは先ほど記載した通りInsight Appsのインストール、ほかにInsight Appsを見つけるマーケットプレイス的な機能、SAP Databricksとデータプロダクトを共有してAIを拡張するものとなっています。

SAP DatasphereはBDCの中核機能となりデータ モデルを定義する基礎構造を提供します。
こちらもSACと同様に、そのまま現在のSAP Datasphereのみで使用するのも可能なようです。

SAP BW PCEは、SAP BW Netweaver Cloud, private editionまたは SAP BW/4HANA Cloud, private editionをBDCに含めることによりBW内のデータをBDCで使用できるデータプロダクトに変換できます。

SAP DatabricksはAIと機械学習に基づく機能を使用してInsight Appsの分析等を拡張する機能となります。

## 1-3.Foundation ServicesとSource System
最後に3.と4.ですがデータソースとデータを取得・調整・変換・保存する層となります。
Foundation ServicesはBDCにおける重要なバックボーンとなっており、SAP Source System(Cloud)からは自動的に、SAP Source System(On-Prem)やNon-SAP Source Systemからは変換処理を行い、関連ビジネスデータと調整、変換されデータプロダクトとなります。
データはHANA Data Lake Files形式で保存されます。

# 2.所感
一般リリースは4月からだそうで、最近は頻繁にWebibarを行っているので気になっている方は参加してみるのもいいかもしれません。(本日(3/13)もデモがあったので参加してきました)
私的に気になるところはFoundation Servicesのところ。どういった技術でSAP以外のシステムから取得したデータを統一させるのか(それともさせないのかｗ)気になるところです。
まだ発表されたばかりのソリューションなので新しい情報があれば更新していきます。

# 3.リンク
調べている過程で有用になったリンクを貼っておきます。

SAP Business Data Cloud

https://www.sap.com/japan/products/data-cloud.html

ロードマップ

https://roadmaps.sap.com/board?PRODUCT=73555000100800004851&range=CURRENT-LAST#Q1%202025

アーキテクチャ概要

https://community.sap.com/t5/enterprise-architecture-discussions/architecture-overview-of-sap-business-data-cloud-bdc/td-p/14034914

SAP Business Data Cloudとは？

https://community.sap.com/t5/technology-blogs-by-sap/what-is-sap-business-data-cloud-benefits-architecture-amp-use-cases/ba-p/14033086

FAQs

https://community.sap.com/t5/technology-blogs-by-sap/sap-business-data-cloud-faqs/ba-p/14022781
仮想化技術の概要

## この記事の概要
AWSソリューションアーキテクトアソシエイトの認定試験のために勉強している内容を記載しています。
今回のテーマは「仮想化技術」です。
バーチャルってことですね！

## はじめに
エンジニア見習いのTeyo3Mと申します。
JavaとAWSをメインに勉強しています。

# 仮想化とは

仮想化とは、1台の物理的なサーバーやPCのリソース（CPU、メモリ、ストレージなど）を、仮想的に分割して複数の環境を動作させる技術のことです。

## 仮想化でできること

仮想化技術を活用すると、以下のようなことが可能になります。

- **1つのPCでMac環境もLinux環境もWindows環境も使いたい！** → 可能！
- **本番環境と同じ環境を手元で再現したい** → 可能！
- **1つのサーバーを分割して、異なる用途のシステムを動かしたい！** → 可能！

もう物理的な制約に縛られる時代は終わりました…！

## 仮想化の対象

仮想化には、以下のような種類があります。

### 1. サーバーの仮想化

- 1台の物理サーバー上に複数のOSを動作させる技術
- **主な方式**: ハイパーバイザ型、ホスト型、コンテナ方式

### 2. ストレージの仮想化

- 複数のストレージを仮想的に統合して1つの大きなストレージプールを構成する技術
- **主な方式**: ブロックレベル仮想化、ファイルレベル仮想化

### 3. ネットワークの仮想化

- ソフトウェアにより動的に仮想ネットワークを構築・制御する技術
- **主な方式**: SDN（Software-Defined Networking）、VLAN（Virtual LAN）

### 4. デスクトップの仮想化

- サーバー上のPC環境を遠隔地の端末に転送する技術
- **主な方式**: 仮想PC方式、ブレードPC方式
- **メリット**: セキュリティ向上（ローカルにデータを保存できない）
- **例**: AWS WorkSpaces（会社のPCを家でも使えたら便利ですよね！）

## サーバー仮想化の種類

サーバー仮想化は、OSの動作方式によっていくつかの種類に分けられます。

### 1. ホスト型

- 物理サーバー上にホストOSをインストールし、その上に仮想化ソフトウェアを導入して仮想マシンを稼働させる方式
- **特徴**: 主にテスト環境などで使用
- **代表的なソフトウェア**: VirtualBox, VMware Workstation, Parallels Desktop

### 2. ハイパーバイザ型

- 物理サーバーに直接ハイパーバイザーをインストールし、仮想マシンを動作させる方式
- **特徴**: ホストOSが不要なため、動作が高速
- **代表的なソフトウェア**: VMware ESXi, Microsoft Hyper-V, KVM（Linux）, Xen

### 3. コンテナ型

- ホストマシンのカーネルを共有しながら、プロセスやユーザを分離する仮想化方式
- **特徴**: 軽量で起動が高速、環境をコードで管理できる
- **代表的なソフトウェア**: Docker, Kubernetes, LXC（Linux Containers）

:::note info
**ざっくり用語解説**
- **コンテナ**: コンテナエンジンによって分割された1つの単位
- **カーネル**: OSを動かすための仕組み
:::

## 仮想化のメリット

仮想化には多くのメリットがあります。

- **サーバースペースの削減 / データセンター費用の削減**
  - 物理サーバーの台数を減らし、運用コストを削減
- **効率的なサーバー利用によるコスト削減**
  - 必要最低限のリソースを確保し、無駄を削減
- **調達の迅速化**
  - 仮想マシンを即座に作成できるため、新規システムの導入がスムーズ
- **構成変更やメンテナンス対応の柔軟性**
  - 仮想環境であれば、リソースの変更やシステムの移行が簡単
- **セキュリティの向上**
  - アクセス制御を厳格に管理できる

## コンテナ技術の活用

コンテナ技術は、従来の仮想化技術と比較して次のようなメリットがあります。

1. **環境構築のコード化**
   - 環境設定をコードとして管理し、同じ環境を再現しやすい
2. **配布・共有が容易**
   - コードを共有するだけで、他の人も同じ環境を構築可能
3. **CI/CDの促進**
   - 環境の即時構築や削除が可能で、開発の自動化がしやすい

## SDI（Software-Defined Infrastructure）とは

SDIは、インフラをソフトウェアによりコード化して管理する技術です。

- **特長**:
  - JSONやYAMLなどのコードに基づいて仮想化インフラを構築可能
  - ビジネスの変化に柔軟かつ迅速に対応できる

**SDIのメリット**:
- **仮想化の自由度が高い** → 必要な範囲で柔軟に仮想化を適用できる
- **インフラの自動管理が可能** → 人手を介さずシステム構成を変更できる

## まとめ

仮想化は、物理的なリソースを効率的に活用するための技術であり、サーバー、ストレージ、ネットワーク、デスクトップなど様々な分野で活用されています。

特に、サーバー仮想化には「ホスト型」「ハイパーバイザ型」「コンテナ型」の3つがあり、それぞれ用途や特徴が異なります。

仮想化技術を活用することで、コスト削減や運用の効率化を実現し、よりスムーズなシステム管理が可能になります。
SORACOMのIoTゲートウェイ　SmartFitPRO Basicスターターキットを使ってみた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/68dd4e85-9607-4519-9bb1-3e22f5289732.png)
今回は、ある設備の接点情報をクラウド上で監視したいと依頼を受けましたので、
SORACOM社が提供しているIoTゲートウェイのSmartFitPRO Basicスターターキットを使用して、
クラウド監視システムを構築しました。

## システム概要
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/11e70118-92ca-43a0-add6-591afa52ef2c.png)

構成としては、SmartFitPROに接点入力を行い、SORACOM Harvestを経由して、
SORACOM Lagoonでデータを表示させます。

## ハードウェア
・SmartFitPRO　SRL-420-CM1A
・アナログ入力用ケーブル　KHF0000075-01
・接点入力用ケーブル KHF0000076-01
・Type-C　充電器（電源用）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/9a7f8e56-e6e3-406e-94a5-09afcf5ec652.png)



## ハードウェアのセットアップ
１、本体の蓋を開けてSIMカードを挿入します。
※挿入方法はメーカーさんの取説に記載されていますのでそちらを参照して下さい。

２、ケーブルをそれぞれSmartFitPROに接続します。

ハードウェアの設定は以上です。
なお送信間隔はデフォルトで１０秒になっているので、
変更したい場合は、旭光電機様が提供している「SmartFitPro設定ツール」を使用して、
パラメータ変更を行って下さい。

## SORACOM側（クラウド）の設定
１、https://auth.soracom.io/login/
　　にアクセスして下さい。

２、注文時に登録した、メールアドレス・パスワードを使用してログイン。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/b9918541-3e5a-4883-9b40-9715f0fa4d8e.png)

３、ログイン後、左上の「SORACOM Air for セルラー」のSIM管理を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/df39981f-e6c4-48b0-b617-3c7b2ee2e183.png)

４、今回使用するSIMにチェックマークを入れて、操作をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/d5d8e889-1e3d-46cf-8176-dc3cbb85cf1a.png)

５、SIMを使用中に変更する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/a5eff30e-8cfd-4261-89cf-6ff6d8df6ce7.png)

６、状態が使用中になればOK！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/17bfbb2c-0ccc-46ca-82e8-8223ae85bff0.png)

７、また使用するSIMを選択し、操作＞所属ブループを変更
　　を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/754e733e-f926-47e1-94c8-c5b4ae39b549.png)

８、今回は新しい所属ブループでRUNを入力し、グループ変更をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/c8e4e89c-291f-491f-95f7-7fbef68adf57.png)

９、グループの「RUN」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/59f46721-79c5-4a88-b291-c5a01a6ad4fd.png)

１０、SORACOM Harvest DataをONにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/163e0de0-4aee-4a16-8eff-34f15bcfefca.png)

クラウドの設定は以上です。

## SmartFitPROの起動
１、USB-Cに電源接続をします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/68dd4e85-9607-4519-9bb1-3e22f5289732.png)

２、あとは自動起動して、定期間隔でSORACOM Harvest Dataにデータを送信します。

## SORACOMLagoonの設定
１、SORACOMLagoon>プラン＆ライセンスパックからFreeを選択し、利用を開始して下さい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/dff80d16-7eb0-4b72-821d-12beec3f968a.png)

２、あとはSORACOMLagoonのサイトに入り、画面をカスタマイズ。（こちらは説明はぶきまｓ）

## まとめ
今回初めてSmartFitPROを使用しました。
簡単な設定でクラウド上にデータを送信できるので、
おすすめです。

SIMに関しては、plan-D（LTE-M系）は使用できるがLTE系は使用できないなど
制約がありますのでご注意下さい。
git gcで.git/objetcsを掃除する

## 実施に至るまで

開発サーバの空き容量が大分減っているとの連絡があったので、調査したところ.git/配下が一番容量を食いつぶしている事が分かった。

* デプロイしているソースの総容量は 1.3GB くらい
* 容量の大半を占めるのはUnityのビルドデータ<br>WebGLビルドをしていて、Asset関連がとにかく多い
* .git配下の容量は気づいたら6GBほど<br>.git/objects/packが大半を占めている

以上のことから、過去、ビルドしては消していたUnityのWebGLビルドデータが積りに積もっている事が分かった。

どうにかして容量を削減をしたいので、以下の2案を検討して、そのうちgit gcを今回採用してみました。

## 案 その1

**gitの履歴データを削除して、過去のビルドデータの痕跡を消す案**

対応としては一番わかりやすいが、「履歴を消す」様なコマンドはgitに用意されていない。

下記の記事を参考に、メンテナンスを行うことを検討したが、WebGLビルドデータ（一回のビルドで大量のAssetsファイル群が出来る）が非常に多く、ミスが怖いので今回は見送った。

https://qiita.com/kaneshin/items/0d19fc1cd86f931dc855

## 案 その2

**git gcコマンドを利用して、不要なオブジェクトなどの掃除を行う案***

こちらを採用した。

* git gcコマンドのみで完結できるので、作業としては簡単に行うことが出来る。
* 開発リポジトリと本番リポジトリは分離されており、何かあった時でも対応可能。

コマンド自体はgit備え付けなので、下記の通りgcを叩くだけで実行できた。
```
git gc
```
→結果として1GBほど容量が減りました。


しかし、過去のデータが多いこともありどうせならと`--aggressive + --prune` 付きのgcも実行した。
```
git gc --agressive --prune=now
```
→git gc後から更に結果として2GBほど減りました。

また、--agressiveオプションをつけるとエラーが発生することがあるみたいです。
私の環境だと以下のエラーが発生しました。
```
error: pack-objects died of signal 975)
fatal: failed to run repack
```

調べてみると、メモリ容量が足りない事によるエラーの模様。
この為にスペックアップするのも微妙なので、packするときに割り振られるメモリ容量を制限しました。
```
## --globalオプションはつけず、作業しているリポジトリのみに適用
git config pack.windowMemory 512m
git config pack.packSizeLimit 512m
git config pack.threads 1
```

ここまでで、agressive込みの`git gc`完了

## 最後に
gitだからといって、どかどかファイルコミットするのはやっぱり微妙でした。反省。。
（過去のコミットに戻れるのだから、どこかでオブジェクト管理をしているのは当然ではありますが…）

UnityのWebGLビルドの様に「ファイル数が多い＋容量もそこそこ大きいもの」を扱う際は、デプロイの仕方などを考慮したいと思います。
【Next.js15】ページ遷移時にスクロール位置を維持したくない時


## はじめに

ページ遷移したときに、前のページのスクロール位置が保持されてしまい最上部から表示されなかったため、それを無効にしたかったのですが、以下の方法を試しても改善されませんでした。

1. 画面遷移時にスクロール位置を最上部に移動させるため、`scroll`プロパティを`true`（または指定なし）にする。
2. RootLayoutなどで `<script>` タグを用いて設定。（Next.jsのナビゲーションとブラウザの内部動作との間に複雑な相互作用があり、期待通りにスクロール位置がリセットされないケースが報告されているみたいです。）


## 環境
- Next.js: 15.1.6
- ブラウザ: Google Chrome


## 原因

Next.js 13以降のApp Routerでは、SPA的なページ遷移がデフォルトになっています。そのため、ページ遷移時にブラウザのスクロール位置が自動的に保持される仕様になっています。




## 解決策
### 方法①  `scrollRestoration` を設定する

クライアントコンポーネントを作成して、`useEffect`と`usePathname`を利用することで、遷移後に常にページ最上部へスクロールできます。

#### 具体的な手順

**① コンポーネントを作成する**

例：  
`components/ScrollReset.tsx`

```tsx
"use client";

import { useEffect } from "react";
import { usePathname } from "next/navigation";

const ScrollReset = () => {
  const pathname = usePathname();

  useEffect(() => {
    if ("scrollRestoration" in history) {
      history.scrollRestoration = "manual";
      window.scrollTo(0, 0);
    }
  }, [pathname]);

  return null;
};

export default ScrollReset;
```

**② 作成したコンポーネントをRootLayoutに追加する**

例：  
`app/layout.tsx`

```tsx
import "./globals.css";
import ScrollReset from "@/components/ScrollReset";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ja">
      <body>
        <ScrollReset />
        <main>{children}</main>
      </body>
    </html>
  );
}
```



これで全ページでスクロール位置をリセットできます。


---

### 方法② 特定のリンクだけに作用させたいとき

URLに `#top` をつけることでスクロールをリセットできます。

```tsx
<Link href="/page#top">リンク</Link>
```

ブラウザのデフォルト挙動により、ページ最上部へスクロールされます。
ただしURLに `#top` が表示されます。




## 参考資料

- [MDN Web Docs: History.scrollRestoration](https://developer.mozilla.org/ja/docs/Web/API/History/scrollRestoration)
- [Next.js Docs: Layouts and Pages](https://nextjs.org/docs/app/getting-started/layouts-and-pages)
Pythonのクラス定義における__new__について説明してみました

学校で各種言語のプログラミングを教えています．
Pythonのクラス定義における__new__についてよく理解できずに悩んでいる人がいるように思いますので，使っている教科書から抜粋します．

●[__new__の解説部分（PDF）](http://www.k-techlabo.org/www_python/PythonNewMethod.pdf)

テキスト本体の最新版は[こちらの記事](https://qiita.com/KatsunoriNakamura/items/b465b0cf05b1b7fd4975)で配布しています．

__new__と__init__の違いがよくわからないという方，ご参考まで．
GitHubActionsのキャッシュ化使ってJavaのbuild高速化してみた

# はじめに

こんにちは、Gakken LEAP のエンジニアの shogawa です。
現在自分が携わっているJavaのプロジェクトでは、ソースコードが肥大化（リファクタリングしろ！）しており、
GitHub Actionsでのbuild時に時間が掛かりすぎてしまう問題がありました。

例えばステージング環境にリリースするのにも、多少の待ち時間が発生してしまうので工数的にももったいないので、
それを解消するために実践したことを書いていきます。

# 前提

- Javaプロジェクトで、GitHubActionsでbuildしている
- buildツールは、gradleまたはmaven
　※今回はgradleとmavenでやったのでそれの紹介です。

参考：GitHub 公式ドキュメント

https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows

# 修正前コード（抜粋）

元々のGitHubActionsは以下のようになっていました。
buildジョブがシンプルに ./gradlew bootWar（./mvnw package -DskipTests） してるだけです。
（いまだにJava8かよ。。。とかいうツッコミは禁止！）

```yaml
jobs:
  build:
    runs-on: ubuntu-latest
    concurrency:
      group: build-app-stg
      cancel-in-progress: true
    environment: stg
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          distribution: 'corretto'
          java-version: '8'
      - name: build war
        id: builder
        run: |
          # gradleの場合
          ./gradlew bootWar
          # mavenの場合
          #./mvnw package -DskipTests
```

# 修正後コード（抜粋）

公式ドキュメントを参考に、build前にキャッシュ関連の設定を追加していきます。
cacheアクションでは、key, pathが必須で、keyにヒットしない場合も考慮してオプションのrestore-keysも設定しておきます。

設定値は公式ドキュメントを見つつ、プロジェクトに合わせた形で設定していきます。

修正後のGitHubActionsは以下の通り。

```diff_yaml
jobs:
  build:
    runs-on: ubuntu-latest
    concurrency:
      group: build-app-stg
      cancel-in-progress: true
    environment: stg
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          distribution: 'corretto'
          java-version: '8'
+      # Gradleキャッシュの設定
+      - name: Cache Gradle dependencies
+        uses: actions/cache@v4
+        with:
+          path: |
+            ~/.gradle/caches
+            ~/.gradle/wrapper
+          key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+          restore-keys: |
+            gradle-${{ runner.os }}-
+      # Gradleキャッシュの設定ここまで
+      # Mavenキャッシュの設定
+      - name: Cache Maven repository
+        uses: actions/cache@v4
+        with:
+          path: ~/.m2/repository
+          key: maven-${{ runner.os }}-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            maven-${{ runner.os }}-
+      # Mavenキャッシュの設定ここまで
      - name: build war
        id: builder
        run: |
          # gradleの場合
          ./gradlew bootWar
          # mavenの場合
          #./mvnw package -DskipTests
```

# 実際の動作

キャッシュ設定をする前と後でどれくらいの速度の違いが出るのかを確認してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455950/41985a8d-dc84-4784-91e9-cb2632164c33.png)

buildジョブの実行時間に着目すると、
修正前は［8m31s］掛かっていたものが、
修正後は［1m27s］とおよそ7分の短縮に繋がりました！

# エンジニア募集中

Gakken LEAP では教育をアップデートしていきたいエンジニアを絶賛大募集しています！！

https://gakken-leap.co.jp/recruit/
YOLOv8 物体検出の処理速度改善

## 自作の物体検出アプリのFPSを改善したい！
ゲームの動画からユーザー名を黒塗りしたい！と願望からスタートし、処理速度改善のためにVC++にまで手を出したのですが、それだけでは物体検出の処理速度は改善しませんでした。
何か手はないか？と考えを巡らせていたのですが、入力テンソルの形状に無駄があり、対応することで処理速度を約2倍に改善できました。
今は生成AIがホット、物体検出は既に枯れた技術であり"何を今さら"という内容に感じられる方も多いとは思いますが、あまりまとまったものも見かけなかったので、（改善できた嬉しさから）ここに記録しておきます。

## 結論：入力テンソルを正方形ではなく、入力画像の形状に合わせると効率があがるよ！
詳しい方からは"何を今さら"という声が聞こえてくるようですが、
入力テンソルを正方形ではなく、入力画像の形状に合わせることで物体検出の推論処理の効率が上がり、FPSをあげることが可能です。
精度と処理速度は基本的に相反するものですが、今回は入力テンソルの形状を正方形から長方形に変更することで、精度は従来のまま、処理速度を改善することができました。

## 入力テンソルと、実際の入力画像の形状
アプリの物体検出には、Ultralytics YOLOv8を利用しています。
デフォルトの入力テンソル（入力解像度）は、`imgsz=640`となっています。
これは、640x640を意味しています。

ユーザーのパソコンや設定によってゲームの解像度（≒動画の解像度）は異なりますが、恐らく多いのは1920x1080、大きいものでは4kの3840×2160あたりまでが多くなります。
16:9が多いだろうと思いますが、FF14では横長のゲーム画面とした方が周りをよく目視することができ有利なため、私は2560x1080というかなり横長の画面でプレイしています。

アプリで検出対象としているユーザー名は、入力画像の中ではかなり小さい物体のため、これまで`imgsz=1280`（1280x1280）で利用していました。
Ultralytics yolov8では、入力画像の縦と横の大きい方を`imgsz`に合わせて縮小してくれるのですが、既に書いた通り、ゲーム画面の多くは横長で、16:9が一番多いと考えられます。
そのため、入力テンソルでは下図のように縮小され推論されますが、特に画像が無い部分も推論するためムダが多いことがわかります。
![tensor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679605/71eaf04a-5d40-4fd3-b88d-9b79302ab1cf.png)

## 長方形（矩形）入力テンソル形状の検討
私のアプリの場合、ほとんど16:9の横長のはずなので、1280x720が良いだろう、と考えました。ただyolov8は32ピクセル単位に区切って処理を行っているとのことで、1280x720に一番近い1280x736とすることにしました。

## Ultralytics yolov8での学習
学習時にも長方形の入力テンソルとし、長方形のまま学習させます。
```python:train.py
results = model.train(data='my_yolov8m1.yaml',epochs=3000,batch=12,device=0,imgsz=[736,1280],rect=True,save_period=10,patience=150
```
ここで大事な部分は、`imgsz=[736,1280]`と`rect=True`です。
縮小サイズはリスト[height,width]で指定します。またそのままでは画像がリサイズされて正方形になるらしい(?)ので`rect=True`と書いて矩形での学習を指定します。長方形にすることで必要メモリも圧縮できるようです。

## ONNX、TensorRTへのエクスポート
ONNXで利用するだけであれば、
```python:export.py
model.export(format="onnx",imgsz=[736,1280],half=True)
```
`half=True`でFP16による処理速度改善を狙いします。

出力したONNXからTensorRTに更にエクスポートする場合には、
```python:export.py
model.export(format="onnx",imgsz=[736,1280],dynamic=True)
```
`half=True`,`dynamic=True`は排他利用のため、ONNXからTensorRTにエクスポートしたい場合には`dynamic=True`とします。

## アプリに改善適用結果
アプリに改善を適用した結果、当方の環境（intel 11400F,Geforce4700tiSUPER）では、次のようになりました。
|  | 1280x1280 | 736x1280 |
|:-:|:-:|:-:|
| ONNX（DirectML）  | 16FPS  | 34FPS |
| TensorRT  | 28FPS | 42FPS |

TensorRTが伸び悩んでいるのは、CPUの負荷が100%になっているためで、より良いCPUであれば更に処理速度が伸びるのだろうと思います。

## まとめ
カメラなど入力画像のアスペクト比に入力テンソル形状を合わせると、パフォーマンスアップするよ！
VSCode周りの環境構築メモ

# はじめに
最近新たに開発環境を整えることがあったので、そこでやったことをメモとして残しておきます。
良ければ参考にしてください。

# 拡張機能

[Japanese Language Pack for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja)
[Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
[Code Spell Cheker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker)
[Git Graph](https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph)

# ユーザ設定

`editor.fontSize:` フォントサイズの変更
`editor.fontFamily:` フォント指定
`editor.fontLigatures:` フォントの合字
`workbench.colorTheme:` テーマ変更
`files.autoSave:` 自動保存
`files.trimTrailingWhitespace:` 保存時に余分なスペースを削除
`files.insertFinalNewline:` ファイル末尾に改行を追加
`editor.formatOnSave:` 保存時に自動フォーマット
`editor.formatOnPaste:` 貼り付け時にフォーマット
`editor.formatOnType:` 入力中にフォーマット
`editor.rulers:` 指定の文字の位置に縦ラインを表示
`editor.tabSize:` タブサイズを指定
`editor.insertSpaces:` インデントにスペースを使う
`editor.autoIndent":` 自動インデント
`editor.detectIndentation:` ファイルのインデントを利用する
`prettier.printWidth:` 折り返しする文字数
`prettier.semi:` 行の最後にセミコロンをつけるか
`prettier.bracketSameLine:` HTMLタグの閉じかっこを同じ行にまとめるか

## settings.json

```
{
  // 全体の設定
  "editor.fontSize": 14,
  "editor.fontFamily": "'Fira Code', Consolas, 'Courier New', monospace",
  "editor.fontLigatures": true,
  "workbench.colorTheme": "Default Dark+",
  "files.autoSave": "afterDelay",
  "files.trimTrailingWhitespace": true,
  "files.insertFinalNewline": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.formatOnPaste": true,
  "editor.formatOnType": true,
  "editor.rulers": [80, 100],
  "editor.tabSize": 2,
  "editor.insertSpaces": true,
  "editor.autoIndent": "full",
  "editor.detectIndentation": false,

  // Pretter
  "prettier.printWidth": 100,
  "prettier.semi": true,
  "prettier.bracketSameLine": true,
}
```

# フォント

[Fira Code](https://github.com/tonsky/FiraCode)

# 最後に

こんなのおすすめだよ！ってのがあったら教えてください。
Django　どこまでテストすべきか？

## はじめに

Djangoを用いた開発では、アプリケーションの品質を維持するためにテストの自動化が重要です。しかし、どこまでテストを書くべきか、どの種類のテストを優先すべきかを悩むことが多々ありました。本記事では、Djangoのテスト戦略と、適切なテスト範囲について個人的にまとめたもの書き出しました。

---

## 1. Djangoのテストの種類

Djangoでのテストは、一般的に以下のように分類されます。

### 1.1 ユニットテスト（Unit Test）
- 主に`unittest.TestCase`を使用
- 個々の関数やメソッドの動作を検証
- モデルやビューのロジック、ユーティリティ関数などに適用

**例:**
```python
from django.test import TestCase
from myapp.models import Product

class ProductModelTest(TestCase):
    def test_product_str(self):
        product = Product.objects.create(name="Test Product", price=1000)
        self.assertEqual(str(product), "Test Product")
```

### 1.2 統合テスト（Integration Test）
- `TestCase` を使用
- データベースや他のコンポーネントと統合した動作を検証
- フォームやモデルのバリデーション、シグナルの動作確認

**例:**
```python
from django.test import TestCase
from myapp.forms import ProductForm

class ProductFormTest(TestCase):
    def test_valid_form(self):
        form_data = {"name": "Test Product", "price": 1000}
        form = ProductForm(data=form_data)
        self.assertTrue(form.is_valid())
```

### 1.3 機能テスト（Functional Test / End-to-End Test）
- `LiveServerTestCase` や `SeleniumTestCase` を使用
- 実際のブラウザを使って、ユーザーの操作をシミュレーション
- UIの確認やシナリオテストに適用

**例:**
```python
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from selenium import webdriver

class ProductUITest(StaticLiveServerTestCase):
    def setUp(self):
        self.browser = webdriver.Chrome()
    
    def test_homepage_loads(self):
        self.browser.get(self.live_server_url)
        self.assertIn("Welcome", self.browser.title)
    
    def tearDown(self):
        self.browser.quit()
```

---

## 2. どこまでテストすべきか？

### 2.1 重要なビジネスロジックはユニットテストを優先
- ユニットテストは実行速度が速く、デバッグが容易
- モデルのメソッドや、フォームのバリデーションロジックをテスト

**例:**
- 価格計算メソッド
- 在庫管理の更新処理
- ユーザー権限チェック

### 2.2 統合テストでコンポーネント間の動作を確認
- ビューとモデル、フォームの連携を検証
- DBとのやり取りが発生するため、ユニットテストより遅いが重要

**例:**
- 商品登録フォームのバリデーション
- 認証機能（ログイン・ログアウト）
- ユーザーのアクションに応じたDBの変更確認

### 2.3 クリティカルなユーザーフローはE2Eテストを追加
- ログインや決済フローなど、ユーザーに直結する重要な機能を対象
- 開発コストが高いため、最小限に留める

**例:**
- 購入フロー（商品追加→カート確認→決済）
- 管理画面でのデータ登録

### 2.4 コード変更時に壊れやすい部分を重点的にテスト
- 頻繁に変更される機能
- 他のモジュールと密接に関連する機能

**優先度が高い例:**
- 価格計算ロジック
- 商品の在庫更新処理

---

## 3. 効率的なテスト自動化のためのTips

### 3.1 テストデータの管理
- `setUp()` で事前にデータを用意
- `factory_boy` や `pytest-django` でテストデータを簡潔に作成

### 3.2 テストの実行時間短縮
- `@classmethod` を使い `setUpTestData` でテストデータを共有
- `pytest-xdist` で並列実行

### 3.3 CI/CDに組み込む
- `GitHub Actions` や `GitLab CI` で自動実行
- PRごとにテストを実行して品質を維持

---

## まとめ

Django開発において、テストは品質を担保する重要な要素ですが、すべてのコードを網羅的にテストするのは現実的ではないです。

- **ユニットテスト:** 重要なロジックは必ずテスト
- **統合テスト:** コンポーネント間の連携を確認
- **E2Eテスト:** クリティカルなユーザーフローのみ

上記のようにテスト範囲を適切に決めることで、開発効率を維持しながら高品質なアプリケーションを実現できます。
Jetpack Composeのプレビューを画像として取り出す

Jetpack Compose のプレビューではプレビューで表示されているものをそのまま PNG の画像として取り出すことができます。


## 方法

Android Studio で任意のプレビューに対してメニューを表示させて、「Copy Image」を選択するとクリップボードに PNG 形式で保持されます。

![スクリーンショット 2025-03-13 15.17.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/798c11bb-7583-47f2-b9bd-ddfeb23374f3.png)

あとは Qiita なり任意の場所でペーストすれば PNG の画像ファイルになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/a17de7d5-b0e1-4da6-83b3-953086acb8e9.png)

`showSystemUi = true` や `device` が設定されている場合でも設定をそのままにプレビューで表示されたままの内容でコピー可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/9f9a41d2-d611-48dc-8cf0-1f346dc15921.png)


## リンク
- https://developer.android.com/develop/ui/compose/tooling/previews#preview-copy-render
[C] malloc 動的メモリ管理のメカニズム概要

質問：「mallocはOSから一括して大きなメモリを取得し，アプリケーションプログラムに小売りにしていると聞いたのですが，どういうことですか？」
以下はChatGPTの回答．

---

`malloc` がメモリを「小売りにする」という表現は、動的メモリ管理のメカニズムに関するものです。ここでは、`malloc` の動作とその背後で行われているメモリ管理の詳細について説明します。

### 1. **OSからメモリを一括で取得**
   `malloc` を使って動的にメモリを確保する際、`malloc` はまずオペレーティングシステム（OS）からメモリを一度に大きく確保します。この動作は、OSが提供するシステムコール（例えば、Linuxでは `sbrk()` や `mmap()`）を通じて行われます。

   OSがアプリケーションにメモリを提供する方法は次のようになります：
   - **sbrk()**: プロセスのヒープ領域を拡張するために、`sbrk()`というシステムコールを使って、OSが一度に大きなメモリブロックをプロセスに割り当てます。このメモリブロックは、アプリケーションのメモリ空間の一部として確保され、`malloc` がこの領域から必要な分だけを動的に提供します。
   - **mmap()**: 一部のOSでは、`mmap()`システムコールを使ってメモリをマッピングすることがあります。この場合も、OSがメモリ領域を確保し、そのメモリ領域をアプリケーションに提供します。

### 2. **アプリケーションへの小売り**
   `malloc` は一度大きなメモリ領域を確保した後、そのメモリを「小売り」する形で、プログラムの要求に応じて小さなチャンク（ブロック）に分割して提供します。これは、プログラムが個別にメモリを要求するたびに、OSに何度もメモリを要求するのではなく、一度のシステムコールで確保した大きなメモリ領域から必要なサイズを切り出して返すことで、パフォーマンスを向上させるためです。

   具体的には、`malloc` はヒープ領域内で管理されているフリーリスト（使われていないメモリのリスト）を参照し、要求されたサイズのメモリブロックを割り当てます。もし十分な空き領域がない場合、`malloc` は再度OSにメモリの確保を依頼して、さらにメモリを取得します。

### 3. **ヒープ領域とフリーリスト**
   `malloc` はヒープ領域（プログラムのメモリ空間内の動的に割り当てられる領域）を管理するため、内部でフリーリスト（空き領域リスト）を使用します。ヒープにはプログラムが動的にメモリを確保し、`malloc` がそれを分割して小さなメモリブロックとして提供します。この方法により、メモリの再利用が効率的に行われます。

   - 例えば、最初に大きなメモリ領域を確保し、その後、`malloc` はプログラムが必要とするメモリサイズを確保して返します。
   - `free` は不要になったメモリをフリーリストに戻すことで、再利用可能な領域を作り出します。

### 4. **メモリの断片化と最適化**
   一度 `malloc` がメモリを確保すると、そのメモリ領域は後で異なるサイズのブロックに分割されて使用されます。しかし、もし異なるサイズのメモリが頻繁に割り当てられては解放されると、ヒープ領域内で「断片化」が発生することがあります。この断片化が進むと、ヒープ内に小さな空き領域が散在するようになり、十分な連続したメモリ領域を確保できない場合があります。

   そのため、`malloc` の実装では断片化を最小限に抑えるためにさまざまな最適化手法が使われることがあります（例えば、異なるサイズのメモリブロックをまとめて管理する、空き領域を最適に配置するなど）。

### 5. **例：malloc の動作**
   以下のような手順で `malloc` はメモリを割り当てます：
   1. プログラムが `malloc(size)` を呼び出します。
   2. `malloc` はヒープ領域内のフリーリストから空き領域を検索し、要求されたサイズに合ったメモリブロックを見つけます。
   3. 見つからなければ、`malloc` はOSに対してメモリを新たに要求します（例えば `sbrk()` や `mmap()` を使って大きなメモリを確保します）。
   4. その後、プログラムに必要なサイズのメモリが返されます。

   **簡単な例**：
   ```c
   int *arr = malloc(10 * sizeof(int)); // 10個のintを格納するメモリを確保
   ```

   この場合、`malloc` はヒープから10個の`int`が格納できるだけのメモリ領域を確保し、そのポインタを返します。

### 結論
`malloc` は、OSから一度に大きなメモリを確保し、その中からプログラムが要求した分だけを「小売り」するように動作します。これにより、効率的にメモリを管理し、OSへのシステムコールを最小限に抑えることができます。
batファイルで簡単なテンプレが書かれたtxtファイルを作成する

#目的
日付つきのテンプレtxtファイルをbatで作成してみる



#コード
```
@echo 
set str_date=%date:~0,4%%date:~5,2%%date:~8,2%
type null > ファイル名_%str_date%.txt
chcp 932
echo テキストに表示する内容 >> ファイル名_%str_date%.txt
echo. >> ファイル名_%str_date%.txt
pause
```

#tips
・txtファイル内のテンプレ化したい日本語テキストは
chcp932で記述
・テキスト内の改行はecho.で行う
Jetpack ComposeのイベントをFragmentに伝える方法

## はじめに
歴史あるアプリでは画面のベースはFragmentですが、UIコンポーネントの実装はJetpack Composeという構成があるかと思います。
そのようなFragmentとJetpack Composeの相互運用において、Compose側のイベント（ボタンのクリックなど）をFragmentで受け取り処理する方法を記録として残したいと思います。

また、初心者の私が理解に苦しんだ部分でもあるため、同じ境遇の方にも参考としてもらえたら嬉しいです:thumbsup_tone1:

## ざっくり手順
1\. 全体像を確認（親子関係の理解）
2\. Compose関数でイベントを受け取る
3\. FragmentでCompose関数から伝わってきたイベント内で任意の処理をする

## 1\. 全体像を確認（親子関係の理解）
まずは全体像を確認しておきます。
当たり前なことかもしれませんが、親子関係を把握していないと混乱してくるのでしっかり確認します:family_mmb:

この記事では以下のような親子関係になります。
```
（親）ExampleFragment -> ComposeScreen -> ExampleButton（子）
```

## 2\. Compose関数でイベントを受け取る
Compose関数にクリックイベントを受け取るために、ラムダ関数を引数として渡します。
これは、ボタンがクリックされた時に`onExampleButtonClick`という関数型の引数を用意し処理内容を渡しています。

```kotlin:ExampleButton.kt
@Composable
fun ExampleButton(
    modifier: Modifier = Modifier,
    onExampleButtonClick: (String) -> Unit,
) {
    Column(
        modifier = Modifier.fillMaxSize(),
    ) {
        Button(
            onClick = { onExampleButtonClick("メッセージです") }, // クリック時に渡された関数を呼び出す
            modifier = modifier,
        ) {
            Text(text = "クリック！")
        }
    }
}
```
⬇︎　`ComposeScreen.kt`で`onExampleButtonClick`を`ExampleButton`に渡してクリックイベントを処理します
```kotlin:ComposeScreen.kt
@Composable
fun ComposeScreen(
    onExampleButtonClick: (String) -> Unit,
) {

// ~省略~

    ExampleButton(
        onExampleButtonClick = onExampleButtonClick,
    )
}
```

## 3\. FragmentでCompose関数から伝わってきたイベント内で任意の処理をする
[補足] `handleButtonClick`: この記事ではトーストを表示する処理を行っています

- `setContent`の中でCompose関数`ComposeScreen`を呼び出します
- `onExampleButtonClick = { message -> handleButtonClick(message) }`
    - ボタンクリック時にメッセージをラムダ式で受け取ります
- 受け取ったメッセージは`handleButtonClick`関数に渡され、トーストで表示されます

```kotlin:ExampleFragment.kt
class ExampleFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = ComposeView(requireContext()).apply {
            setContent {
                ComposeScreen(
                    onExampleButtonClick = { message ->
                        handleButtonClick(message)
                    }
                )
            }
        }
        return view
    }

    private fun handleButtonClick(message: String) {
        Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
    }
}
```
このように書くことで`クリック！`ボタンを押下したときに、渡されたメッセージがトーストとして画面下部に表示されます。

以上がFragmentとJetpack Composeの相互運用の流れとなります。
私自身、親子関係の把握やラムダ式のやり取りで混乱したので、この記事が同じように悩んでいる方の助けになれば幸いです:fist_tone1:

最後までご覧いただきありがとうございました！
Docker 基本操作

# Docker 基本コマンド　一覧表
|役割|コマンド|例|
|---|---|---|
|イメージの確認|```docker images```|```docker images```|
|コンテナの稼働状況|```docker ps```|```docker ps```|
|イメージの取得|```docker pull <REPOSITORY>```|```docker pull ubuntu```|
|イメージからコンテナを作成|```docker run -it <REPOSITORY>```|```docker run -it ubuntu```|
|コンテナの起動|```docker start <CONTAINER ID or NAME>```|```docker start ubuntu```|
|コンテナにログイン|```docker attach <CONTAINER ID or NAME>```|```docker attach ubuntu```|
|(コンテナ側で)コンテナの停止|```exit```|```exit```|
|(ホスト側で)コンテナの停止|```docker stop <CONTAINER ID or NAME>```|```docker stop ubuntu```|
|コンテナの削除|```docker rm <CONTAINER ID>```|```docker rm aaa111```|
|イメージの削除|```docker rmi <REPOSITORY>```|```docker rmi repo```|

# 実用編
## イメージのインストール=>コンテナの初期作成=>開始
```PWD := {gitで管理している作業ディレクトリ}```とします。

### イメージのインストール
```
docker pull <IMAGE>
```
### コンテナの初期作成
```
docker create \
  --name <NAMES> \
  -it \
  -v $(pwd):/root/app \
  <IMAGE>
```

- ```-v $(pwd):/root/app```は、ホスト側のカレントディレクトリをコンテナ内の ```/root/app```にマウント
    - コンテナ内の```/root/app```ディレクトリとホスト側のファイルが同期される
=> **gitで管理しているホスト側のプロジェクトをコンテナ側の```/root/app```で実行可能！**

### コンテナの実行
```
docker start <NAMES>
```

## 実はrunを使うと楽
```docker run``` = ```create + start + attach``` の手順を一気に行うコマンド
これを使うと以下のように書ける
```
docker run \
　-it \
  --name <NAMES> \
  -v $(pwd):/root/app \
  <IMAGE>
```

## 単発コマンド実行のためだけの使い捨てコンテナを作成・破壊する用
CIでテストを回すときに、一時的なコンテナを起動して使い捨てるパターンを想定しています。

```
docker run --rm -it \
  -v $(pwd):/root/app \
  <IMAGE> \
  /bin/zsh -c "cd /root/app/ && {実行したいコマンド}"
```
- ```docker run```でイメージからコンテナを作成し起動
- ```-rm```でコンテナの実行後、削除
- ```-it``` インタラクティブモードでターミナルを割り当て(後のコマンド実行用)
- ```-v $(pwd):/root/app```でホスト側のカレントディレクトリをコンテナ内の ```/root/app``` にマウント
- ```/bin/zsh -c "cd /root/app/ && {実行したいコマンド}"```
    - ```/bin/zsh -c```でシェルで複数コマンドを実行
From Beginner to Data Analyst: Hands-On with Google Colab, Neon, and Supabase for Data Preprocessing and Importing

## Table of Contents
1. [Introduction](#introduction)
2. [Setting Up Data Processing: Google Colab Environment Setup](#setting-up-data-processing-google-colab-environment-setup)
3. [Loading and Preprocessing CSV Files](#loading-and-preprocessing-csv-files)
4. [Connecting to Neon and Importing CSV Data](#connecting-to-neon-and-importing-csv-data)
5. [Introduction to Supabase and Future Plans](#introduction-to-supabase-and-future-plans)
6. [Conclusion](#conclusion)

### 1. Introduction
I am currently studying to become a data analyst.  
To learn the basics of data preprocessing, I decided to leverage Google Colab and other tools.  
This article outlines my progress, starting from data preprocessing with Google Colab to importing data into Neon and planning to use Supabase for future work.

### 2. Setting Up Data Processing: Google Colab Environment Setup
I used Google Colab to execute Python code.  
I installed the necessary libraries, including:

- `pandas` for data manipulation,  
- `chardet` for encoding detection,  
- `glob` for listing CSV files.

### 3. Loading and Preprocessing CSV Files
I uploaded CSV files from my local machine to Google Colab and started preprocessing:

- Detected the file encoding using `chardet`.  
- Loaded the data into a `pandas` DataFrame.  
- Checked the shape of the data, verified missing values, and examined data types.  
- Summarized statistical information and reviewed the correlation matrix.

### 4. Connecting to Neon and Importing CSV Data
I successfully connected to Neon and created a table to store my preprocessed CSV data. The data import initially went well, but when I attempted to upload seven CSV files at once, the database size quickly exceeded three times the free plan’s limit. As a result, even after attempting to free up space, the capacity issue persisted.

In hindsight, I should have checked the storage limits more carefully in advance, and I could have reached out to Neon’s support team for guidance. However, since my priority was to continue studying data analysis without interruptions, I decided to close my account and switch to another platform. This decision was not due to any issue with Neon itself but rather my own lack of preparation.

That said, I still see great value in using Neon alongside Google Colab for integrating Python and SQL workflows. In the near future, I plan to revisit this combination, ensuring I better manage storage limits to fully leverage Neon’s capabilities for data processing.

### 5. Introduction to Supabase and Future Plans
I plan to continue my work with Supabase, as it offers an easier and more efficient platform for managing data and performing queries.  
This tool will be part of my journey to streamline the data processing workflow.

### 6. Conclusion
In this article, I covered the steps I took to preprocess data using Google Colab, import it into Neon, and my decision to explore Supabase for future projects.
This journey marks an important step in my path to becoming a skilled data analyst.
Jetpack Composeで点線のDividerを表示する

よく作るのである程度パラメータで調整可能にしています。

## 横向き

```kotlin
@Composable
fun DashHorizontalDivider(
    modifier: Modifier = Modifier,
    color: Color = MaterialTheme.colorScheme.outlineVariant,
    thickness: Dp = 1.dp,
    gap: Dp = 4.dp,
    length: Dp = 8.dp
) {
    Canvas(
        modifier
            .fillMaxWidth()
            .height(thickness)
    ) {
        drawLine(
            color = color,
            strokeWidth = thickness.toPx(),
            start = Offset(0f, thickness.toPx() / 2),
            end = Offset(size.width, thickness.toPx() / 2),
            cap = StrokeCap.Square,
            pathEffect = PathEffect.dashPathEffect(
                intervals = floatArrayOf(
                    length.toPx(),
                    gap.toPx(),
                ),
            ),
        )
    }
}
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/b6ffd6c4-06ee-4bbb-a2c3-23f0bbda8078.png" width="300px" />



## 縦向き

```kotlin
@Composable
fun DashVerticalDivider(
    modifier: Modifier = Modifier,
    color: Color = MaterialTheme.colorScheme.outlineVariant,
    thickness: Dp = 1.dp,
    gap: Dp = 4.dp,
    length: Dp = 8.dp
) {
    Canvas(
        modifier
            .fillMaxHeight()
            .width(thickness)
    ) {
        drawLine(
            color = color,
            strokeWidth = thickness.toPx(),
            start = Offset(thickness.toPx() / 2, 0f),
            end = Offset(thickness.toPx() / 2, size.height),
            cap = StrokeCap.Square,
            pathEffect = PathEffect.dashPathEffect(
                intervals = floatArrayOf(
                    length.toPx(),
                    gap.toPx(),
                ),
            ),
        )
    }
}
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/3f672540-cbdf-4d2b-bb65-2317a806ba48.png" width="300px" />
バッファリングとは

質問：「バッファリングとは」
以下はChatGPTの回答．

---

**バッファリング**とは、データの一時的な格納（バッファ）を行い、効率的にデータの転送や処理を行う技術のことです。一般的には、データの入出力処理の速度差を補うためや、リアルタイムでの処理を効率化するために用いられます。バッファは一時的にデータを保持するためのメモリ領域であり、そのデータが後で処理されるまで待機します。

### バッファリングの目的
- **速度差の調整**: 例えば、ディスクI/O（読み書き）やネットワーク通信は遅いことが多いですが、CPUやメモリの処理速度は非常に速いため、直接的にデータを読み書きすると効率が悪くなります。バッファを使うことで、データを一時的に保持し、遅い処理の間に次のデータを準備できるため、全体の処理がスムーズに進みます。
  
- **効率的なデータ処理**: データを逐一読み書きするよりも、ある程度の量をまとめて読み書きするほうが効率的です。バッファを使用することで、必要なデータを一度にまとめて取得し、処理が終わったらまとめて結果を書き出すことができます。

### 代表的なバッファリングの使用例

1. **ファイルI/Oのバッファリング**
   ファイルを読み書きする際、データを一度にすべて読み書きすると効率が悪くなる場合があります。そのため、バッファを使用してファイルの内容を一定量ずつ読み書きすることで、処理速度を向上させます。
   
   例えば、C言語の`fread()`や`fwrite()`、C++の`ifstream`や`ofstream`は、内部でバッファリングを行っています。

   ```cpp
   #include <iostream>
   #include <fstream>
   
   int main() {
       std::ifstream infile("example.txt");
       std::ofstream outfile("output.txt");

       if (infile.is_open() && outfile.is_open()) {
           char buffer[1024];  // バッファ
           while (infile.read(buffer, sizeof(buffer))) {
               outfile.write(buffer, infile.gcount());  // バッファを出力ファイルに書き込む
           }
           // 残りのデータも書き込む
           if (infile.gcount() > 0) {
               outfile.write(buffer, infile.gcount());
           }
       }

       infile.close();
       outfile.close();
       return 0;
   }
   ```

2. **ネットワーク通信のバッファリング**
   ネットワーク通信においても、データを逐次的に送受信するのではなく、バッファを使って一定量のデータをまとめて送信したり受信したりすることで、効率よくデータ転送を行います。例えば、Webブラウザがサーバーからファイルをダウンロードする際、データを少しずつ受信してからユーザーに表示することがあります。

3. **音声・動画ストリーミング**
   音声や動画をストリーミング再生する際にも、バッファリングが重要です。ネットワーク越しにデータが遅延しても、あらかじめデータをバッファに貯めておくことで、再生がスムーズに行えます。これにより、接続の速度差を補い、再生の途切れを防ぐことができます。

### バッファリングの種類

1. **ダブルバッファリング**
   ダブルバッファリングは、2つのバッファを使用して、1つのバッファでデータを処理しながら、もう1つのバッファに次のデータを読み込む方法です。この方法により、処理の待ち時間をなくし、データのスムーズな転送や処理を実現します。例えば、グラフィックの描画においては、画面の表示を2つのバッファに分けて行うことで、描画中に画面がちらつくことなく滑らかな表示が可能になります。

2. **循環バッファ（リングバッファ）**
   循環バッファは、バッファがいっぱいになった場合に、先頭から再び使えるように回るような構造を持つバッファです。リアルタイムシステムや音声の処理でよく使われます。データの流れが常に一定の速度で発生する場合に、効率的に動作します。

### バッファリングの利点
- **パフォーマンス向上**: データの処理を一度にまとめて行うことで、I/O操作が効率的になります。
- **非同期処理の可能**: 入出力が遅延する場合でも、非同期でデータ処理を行うことができ、他の処理と並行して進めることができます。
- **リソースの節約**: データを一時的に格納することで、システムリソース（メモリやディスク）を効率的に使用できます。

### バッファリングの注意点
- **メモリの使用量**: バッファリングを行うためにはメモリを使用します。大きすぎるバッファは、メモリを無駄に消費することになります。
- **バッファオーバーフロー**: バッファのサイズを超えてデータが書き込まれると、バッファオーバーフローが発生し、プログラムが予期しない動作をする原因となります。このため、バッファのサイズは適切に管理する必要があります。

### 結論
バッファリングは、データの入出力操作を効率的に行い、システムのパフォーマンスを向上させるための技術です。適切なバッファの使用により、処理をスムーズにし、リソースを効率よく利用できます。
T-Code显示

没有显示之前是这样
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3795764/ce7ae5a3-fe59-4957-b6a0-308c13f7277f.png)

右键，设定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3795764/323eb999-84f5-4b3a-9d53-b4185125108c.png)

选择技术名称表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3795764/6b8930dd-a0e9-467b-9e90-635756dbb5bb.png)

全部T-code都可以表示了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3795764/488aabef-cdc1-41ad-911a-587f1738e255.png)
データサイエンティストの面接で質問すること

10年近く前に[データサイエンスの面接において知っておくべき２１のQ＆A（日本語訳まとめぺーじ）](https://qiita.com/ogamiki/items/8d69d938bc0d3171c203)という元々KDnuggetsの記事を和訳許可をもらって書いていたものがいまだにたまに読まれているというのが通知で分かりました。
10年の間に私自身も数々のデータサイエンティスト面接を行なってきました。
今回はそんな私がデータサイエンスの技術チェックで使っていた面接質問をいくつか紹介し、引用を交えつつ、私自身の経験に基づいて書かせていただきたいなと思いました。（最近、私は技術面接自体を他のメンバーに任せているため、ここに記載した面接内容を予習したからといって弊社の面接を突破できる保証はございません。悪しからず。）

#### ツリー系のモデルと線形系のモデルでそれぞれ欠損値を埋める時に、一般的にどういう手法を用いるのか、それぞれの違いと、その違いはどうして生まれるのかを教えてください。
この質問の意図は、アルゴリズムごとの前処理の違いを認識しているか、そしてアルゴリズム一つに対する興味の深さを確認することです。今の時代、アルゴリズムのロジックを完璧に理解している必要はありませんが、データサイエンティストとして成長する上で探求心は重要だと思っており、自身が使う道具の古典的な情報を全く知らない人は伸び悩む傾向があると考えているため、このような質問をしています。私の学生時代の指導教官が「まずは古典」と繰り返し言っていた教えが、今も私の中に残っているせいかもしれません。

#### 顧客ターゲティングのモデルを構築した時に、検証精度では良い感じのAUCが出ており、過学習もしていないように感じました。ただ、本番環境では予測値と実測値が大幅にずれてしまっていました。どうしてでしょうか。最大5回まで質問を受け付けます。
この質問を出す時には、裏でいくつかの正解パターン（パーソン・ピリオド・データにおけるパーティション方法、ダウンサンプリングからのキャリブレーション忘れ、Training-Serving Skew問題、etc）を私の中で決めておき、質問を繰り返して正解に辿り着けるかを確認しています。限られた質問回数の中で、いかに核心に迫る質問を効果的に投げかけ、選択肢を絞り込んでいくかが重要です。これは、モデル構築時のみならず、運用時のスキルも測る上で有効な手法です。機械学習モデルは構築して終わりではなく、継続的に運用し、精度を維持していくことが求められます。

#### あなたの一番好きなライブラリやアルゴリズム、指標など、なんでも良いので一つ選んで、それを選んだ理由を教えてください。
昔、知り合いがある面接で聞かれた「最も好きな数式」という質問を気に入ったので、それをアレンジしたものです。ちなみに、サポートエンジニアの面接では、この派生として「最も好きなLinuxコマンド」という質問をしていました。どんなものを選んでも良いのですが、「好き」と選んだテクノロジーをどこまで語れるかを見ています。また、知らない人への説明力も確認しています。どうしてもデータサイエンティストは技術に深く入り込んでしまいがちですが、ビジネスで利用してもらわなければ価値はないため、そのコミュニケーション能力を見ています。

#### 二値分類の時に、LoglossとAUCを最適化指標に利用する時のメリット・デメリットについて教えてください。
二値分類問題はデータサイエンスの予測AI課題の7割くらいを占めていると思っています。その中で、最適化指標をどうするのか、どうしてそれを選ぶのかを知っているかどうかは非常に重要です。評価指標を知らずにモデルを作って「良いものができました」と言う人は、データサイエンティストとは言えません。その中で、基礎的な指標は最低限押さえておいてほしいという視点になります。私が大好きな[FVE Binomial](http://datarobot.com/jp/blog/fve_binominal/)を理解していれば加点します。

#### テキストデータの前処理が面倒で、テキストの長さだけを特徴量に入れていました。モデルへの寄与度は高かったのですが、テキストが長くなると精度のばらつきが目立ちました。どうしてでしょう。
この質問に関しては一例ですが、私が過去に経験した面白い予測値と実測値の乖離の仕方を具体的に挙げ、その原因を推測させる問題を出していました。他のパターンとして、「Tweedie Devianceを最適化指標に利用したプロジェクトにおいて、ランダムパーティションして交差検定したのに、交差検定とホールドアウトで何らかの一様な上振れが起きましたが、どうしてでしょう」とか、「LLMでシステムプロンプトを日本語で書いていたのに、出力は日本語になってしまいましたが、どうしてでしょう」といった具合です。AI・機械学習がどのように動くかという構造を捉えていれば難しくありませんが、コードを暗記しているだけのタイプだと、イレギュラーな動きをした時に弱かったりします。ただの勘ではなく、構造的に推測できているかを見ています。もちろん、当時の原因と同じものを言い当てられたら加点していました。

いかがでしょうか。データサイエンティストの面接受けるという方だけでなく、データサイエンティストの面接をするという人もどんな技術的な質問をしたらいいかわからないということはよく聞くので少しでも参考になれば幸いです。
Decorator

Decoratorは再帰的な構造をとって機能を追加していく。Componentとの違いはどちらも再帰的な構造ではあるがComponentは容器と中身を同一視して利用することであるのに対して、Decoratorは容器のクラスを追加して中身を包んでいくことで、中身に機能を付け足していくことである。
箱庭でUnityを動かしてみる（4日目&5日目）

# 2025/03/07(4日目)実施内容
## 勉強！
https://www.youtube.com/playlist?list=PLvZDKbhDfoh2VO6nlYgKKQjdA74LcXw5I
どこにコントローラがあって，どうやってパラメタをいじるのか確認

-> やっぱり分からない...おそらくUnityのアタッチされているスクリプトの中で，ロボットの定義に関するものの中のパラメタをいじればいい（具体的に，`Scripts/Hakoniwa/PluggableAsset/Assets/Robot/Parts/Class/Controller` の中にあるスクリプトのメンバなど）のだが，いじっても値が変化しない...
-> 結局この日は原因を割り出せずに終了

# 2025/03/13(5日目)実施内容
## 先日の続き
### たった1つの誤解
原因は...
- `WhellMotor.cs` の `ForceLimit` は，入力値の超過分を除去するのではなく，超過した入力値は0とみなしていた！！！

なので，「元の速度が遅いなぁ，もっと大きい値を入れてやろう」とすると，入力値が超過して0となり，ロボットが動かなくなっていたということでした

-> 無事移動/回転制御が完成，次はセンサのコンポーネントをいじる

## 次回予定
- センサのコンポーネントをいじる
- 射撃を実装する
Thymeleaf 日付のフォーマット

# 背景
画面のインプットボックスに**2025/03/11 18:01**を入力して、バックエンドに送信して、再表示は**Tue Mar 11 18:01:00 JST 2025**になっています。

# 原因
Dateフォーマットが未設定なっています。
```
public class form {
    @DateTimeFormat (pattern = "yyyy/MM/dd HH:mm")
    private Date startDate;
}
```
# 調査経緯
```
<form th:object:testform>
  <input id="startDate" name="startDate" th:field="*{startDate}"   
    th:value="${#dates.format(start, 'yyyy/MM/dd')}" type="text">
  </input>
</form>
```
最初はth:fieldとth:valueの関係が分かりません。js側で日付のフォーマットを"yyyy/MM/dd HH:mm"にして、表示するのは問題ないはずと思いました。
このth:valueがここでは余計なものだと思います。

# 参考：
https://stackoverflow.com/questions/20361691/formatting-thfield-in-thymeleaf

https://casual-tech-note.hatenablog.com/entry/2018/10/10/224250
Amazon VPC

## VPC(Amazon Virtual Private Cloud)とは
AWS上で作成できるプライベート仮想ネットワーク空間です
### IPアドレス帯
- 10.0.0.0～10.255.255.255
- 172.16.0.0～172.31.255.255
- 192.168.0.0～192.168.255.255

## VPCの構成要素
### Subnet（サブネット）
VPC内のIPアドレス帯を設定する機能
#### パブリックサブネット
インターネットに接続可能なサブネット
#### プライベートサブネット
インターネットに接続不可なサブネット

### IGW（インターネットゲートウェイ）
サブネット内の仮想サーバーなどのリソースをインターネットと通信可能にする機能

### Route Table（ルートテーブル）
サブネット内のインスタンスの通信経路を決定するルール。
VPC内にルートテーブルを配置し、サブネットごとに使用するルートテーブルを選択します

### Elastic IP（静的IPアドレス）
固定のパブリックIPアドレス。
NATゲートウェイやEC2インスタンスに割り当てて利用します

### NATゲートウェイ
プライベートIPアドレスをパブリックIPアドレスに変換できる機能
#### 使用場面
プライベートサブネットからインターネットに接続するとき
#### 安全性
VPC内からインターネットへの送信は可能ですが、インターネットからVPCへのアクセスはできないため、セキュリティが保たれます

### VPC Endpoint（VPCエンドポイント）
サブネット内のインスタンスからAWSのサービス（S3、DynamoDBなど）にインターネットを経由せず接続するための仕組み

## まとめ
AWSのVPCは、プライベートな仮想ネットワークを提供し、リソース間の通信やインターネット接続を柔軟かつ安全に管理します。主要なコンポーネントには、サブネット、インターネットゲートウェイ、NATゲートウェイ、VPCエンドポイントなどがあり、セキュリティを保ちながらネットワークを構成できます。
【ChatGPT】アイゼンハワーマトリクスをPromptにしました。


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

　今回は、アイゼンハワーマトリクスをPromptにしました。

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

　OpenAIから
　　YouTube動画が出ました。

　iOSアプリの
　　AdvancedVoiceModeについての
　　　ユーザーからの質問に
　　　　答えています。

　[ChatGPT's Team Responds to Your Advanced Voice Questions #Shorts](https://youtu.be/7Nuf8CrYdaI?si=uq3nUWHJxd6J6P6U)
***（Google Gemini抽出）***
主なポイントは以下のとおりです。
 * 背景ノイズの問題: ChatGPTが背景ノイズを音声として誤認識し、不適切な応答をすることがあります [00:06]。OpenAIはノイズフィルタリングの改善に取り組んでいます [00:12]。
 * 会話の途中で応答する問題: ユーザーが話し終わる前にChatGPTが応答してしまう問題に対して、OpenAIはモデルが会話の終わりを理解する方法を模索しています [00:23]。
 * iOSでの対策: iPhoneユーザーは、コントロールセンターから「ボイスアイソレーション」マイクモードを選択することで、周囲のノイズを低減できます [00:47]。また、画面をタッチしている間は、一時停止してもChatGPTは応答しません [01:06]。
 * Android版について: 現在、これらの機能はiOS版のみですが、Android版も開発中です [01:22]。
 * フィードバックの募集: OpenAIはユーザーからのフィードバックを歓迎しており、それが新機能の開発につながる可能性があると述べています [01:29]。
***
　では、【本題】です。

　今回は、
　　アイゼンハワーマトリクスを
　　　Promptにしました。

　こちらの記事を参照しました。
　　[仕事が速い人は”しない仕事”を決めている — タスク整理の王道『アイゼンハワーマトリクス』とは](https://studyhacker.net/shinai-eisenhower-matrix_)

　アイゼンハワーマトリクスは、
　　優先順位を明確にするための
　　　タスク管理の手法として
　　　　広く知られています。

　その名のとおり、
　　第34代アメリカ大統領
　　　ドワイト・D・アイゼンハワーの
　　　　言葉に基づき考案されました。

　「緊急なものは重要ではなく、
　　重要なものは決して緊急ではない」

　これに基づき、
　　四つの象限に分けます。

　１．重要かつ緊急
　　　　即時対応が必要なタスク

　２．重要だが緊急ではない
　　　　計画的に取り組むべきタスク

　３．緊急だが重要ではない
　　　　他者に任せるべきタスク

　４．緊急でも重要でもない
　　　　やる必要のないタスク

　しかし、
　　この方法ではタスクの優先順位や
　　　実行に必要なエネルギー、
　　　　時間の見積もりが
　　　　　十分に考慮されていません。

　そこで上記記事では
　　次のように分けています。

　１．重要度: 
　　　　タスクが目標達成に
　　　　　どれだけ寄与するか

　２．緊急度: 
　　　　タスクの期限や時間的制約

　３．エネルギー: 
　　　　タスクを完了するために
　　　　　必要なエネルギー量

　４．時間: 
　　　　タスクを完了するのに
　　　　　必要な時間

　この新しいマトリクスを
　　活用することで、
　　　以下のようなタスク管理の
　　　　改善が期待できます。

　１．タスクの見える化: 
　　すべてのタスクを一覧化し、
　　　優先順位や必要なリソースを
　　　　明確化する。

　２．リソースの最適化: 
　　エネルギーや時間を
　　　効率的に配分し、
　　　　重要なタスクに集中する。

　３．委任の促進: 
　　他人に委任できるタスクを
　　　明確にし、
　　　　チーム全体の効率化を図る。
***
　これをもとに
　　作成したPromptがこちら。

　＊＊＊に課題を入力して、
　　送信してください。
```Text:新アイゼンハワーマトリクスPrompt
課題: {＊＊＊}  

以下の基準に基づいて、この課題に関連するタスクを4つのカテゴリに分類してください。  

分類基準:  
1. **クイックウィン（Quick Wins）**:  
   - 重要度・緊急度・エネルギー・時間が低いタスク  
   - 短時間で完了しやすく、手軽に進められるもの  

2. **デリゲート（Delegate）**:  
   - 重要度・緊急度が高いが、エネルギー・時間が低いタスク  
   - 他者に委任可能なもの  

3. **プラン（Plan）**:  
   - 重要度・エネルギーが高く、緊急度・時間が低いタスク  
   - 計画的に進めるべきもの  

4. **エリミネート（Eliminate）**:  
   - 重要度・緊急度・エネルギー・時間がすべて高いタスク  
   - 可能なら削減・削除すべきもの  

この基準に基づいて、{課題} に関連するタスクを具体的に分類し、それぞれのカテゴリごとに適切なアクションプランを提案してください。
```

　“お金持ちになる”と入れましたが、
　　最後に、エリミネートで
***（ChatGPT出力）***
短期間で大儲けしようとするギャンブル的な投資（ハイリスク投機・FXの短期売買）

過剰な節約でQOLを下げる（楽しみを完全に排除する生活）

時間がかかりすぎる低収益な副業（時給換算で効率が悪いもの）

使っていないサービスの継続課金（ジム・高額な自己啓発プログラムなど）
***

　“こんなことはやめろ”と
　　言われたようで、
　　　笑ってしまいました😅

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

　今回は、ここまで。
1-React开发环境创建

#### 1.创建项目文件夹EasyReact
流程：
①在文件中打开命令行cmd:输入创建命令
```java
npx create-react-app react-basic(项目名称)
```
②命令执行完毕后，文件夹中会被创建出一个react-basic文件夹
③依次执行两个命令，让项目跑起来
😊cd react-basic 进入文件夹
😊npm start 启动项目
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/90caaf72-bc2d-4737-a036-8e21fa5504f0.png)
④启动成功：展示出来项目的初始界面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/47ecd097-9b39-4825-b74b-26db5ab1d3f2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/71dde567-dee0-408a-ac40-3a1556be2793.png)
#### 2.项目瘦身，删除不必要的文件
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/93ba79d3-a52d-4a22-82c2-f226c8d719e1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/b50c176b-a350-4390-8e2e-a46657720851.png)
個人的ﾒﾓ

Sub ExportSQLToTextFile_SafeAndFixed()
    Dim rawName As String
    Dim safeName As String
    Dim fileContent As String
    Dim cell As Range
    Dim outputFolder As String
    Dim filePath As String
    Dim fso As Object
    Dim stream As Object

    ' ブックが保存されていない場合の対策
    If ThisWorkbook.Path = "" Then
        MsgBox "このブックを保存してから実行してください。", vbExclamation
        Exit Sub
    End If

    ' D2セルの値取得
    rawName = Trim(Range("D2").Value2)
    If rawName = "" Then
        MsgBox "D2セルが空です。", vbExclamation
        Exit Sub
    End If

    ' 禁止文字を "_" に置換
    Dim invalidChars As Variant: invalidChars = Array("\", "/", ":", "*", "?", """", "<", ">", "|")
    Dim ch As Variant
    safeName = rawName
    For Each ch In invalidChars
        safeName = Replace(safeName, ch, "_")
    Next ch

    ' 拡張子がすでに .sql でないなら追加
    If LCase(Right(safeName, 4)) <> ".sql" Then
        safeName = safeName & ".sql"
    End If

    ' 保存先フォルダ（output）
    outputFolder = ThisWorkbook.Path & "\output"
    Set fso = CreateObject("Scripting.FileSystemObject")
    If Not fso.FolderExists(outputFolder) Then fso.CreateFolder outputFolder

    ' フルパス
    filePath = outputFolder & "\" & safeName

    ' ファイル内容生成（B155:B310）
    fileContent = ""
    For Each cell In Range("B155:B310")
        If cell.Value <> "" Then
            fileContent = fileContent & cell.Value & vbCrLf
        End If
    Next cell

    ' 保存処理（UTF-8 BOM付き）
    Set stream = CreateObject("ADODB.Stream")
    With stream
        .Charset = "utf-8"
        .Open
        .WriteText fileContent
        .SaveToFile filePath, 2 ' 2 = 上書き
        .Close
    End With

    MsgBox "保存しました：" & vbCrLf & filePath, vbInformation
End Sub