OmniAICreator/Qiita-1.07M huggingface dataset:
【仮想化】 今日の学習まとめ

# ☁ AWSの仮想化とは？
物理マシンをソフトウェアで分割・統合して「仮想リソース」として扱う技術！

## 🔹 仮想化の種類と概要
| 種類        | 目的            | 主な技術・サービス       |
| --------- | ------------- | --------------- |
| サーバー仮想化   | サーバー分割・集約     | EC2, Hypervisor |
| ストレージ仮想化  | ストレージ統合       | S3, EBS         |
| ネットワーク仮想化 | 仮想ネットワーク構築    | VPC, SDN        |
| デスクトップ仮想化 | デスクトップをクラウド上に | WorkSpaces, VDI |

## 📦 コンテナ仮想化（Docker）
軽量な仮想化技術

ホストOSの カーネルを共有 してプロセス単位で分離

開発環境をそのまま本番へ持ち込める

### 💡 VMとの違い
| 項目     | 仮想マシン（VM） | コンテナ（Docker） |
| ------ | --------- | ------------ |
| 起動速度   | 遅い（数分）    | 速い（数秒）       |
| OSの重さ  | フルOS搭載    | 共有カーネルで軽量    |
| 使用リソース | 多い        | 少ない          |

### 🔶 仮想マシン（VM）の構造
━━━━━━━━━━━━━━━━━━
🔹物理マシン (Server)
 ┗🧠 ハイパーバイザ
    ┣ 🖥️ ゲストOS①
    ┃   ┣ アプリ①
    ┣ 🖥️ ゲストOS②
    ┃   ┣ アプリ②
━━━━━━━━━━━━━━━━━━
OSごと仮想化 ➡️ 重い

起動が遅いし、リソースを余分に使う

その分、お互い完全に独立


### 🔷 コンテナの構造（Docker)
━━━━━━━━━━━━━━━━━━
🔹物理マシン (Server)
 ┗🧠 コンテナエンジン (Docker）
    ┣ 📦 コンテナ①
    ┃   ┣ アプリ①
    ┣ 📦 コンテナ②
    ┃   ┣ アプリ②
━━━━━━━━━━━━━━━━━━
ホストOSのカーネルを共有して軽量化

プロセス単位で隔離 (高速起動)

各コンテナは独自ライブラリを持つ

### 💡 ポイントまとめ
| 比較   | 仮想マシン（VM）   | コンテナ (Docker)      |
| ---- | ----------- | ------------------ |
| 起動速度 | 遅い（数十秒〜数分）  | 速い（ほぼ即時）           |
| リソース | オーバーヘッド大    | 軽量、「必要なものだけ」       |
| 利用用途 | OS単位で分離     | アプリ/機能単位で分離        |
| 代表例  | EC2, VMWare | Docker, Kubernetes |


## ✅ 仮想化のメリットまとめ
✅ リソースの効率活用（コスト削減）

✅ スピーディな環境構築・拡張（スケーラブル）

✅ テストや運用環境を簡単に分離

✅ 復旧や移行が簡単（ポータビリティ）

✅ セキュリティ管理も強化できる
フェミニストの道具と線形代数学

フェミニストの道具
・ベクトル空間と線形空間
・固有値問題
・スペクトル分解
・特異値分解
・LU分解とQR分解
・ 次元削減と	PCA（主成分分析）
・K-means, 階層クラスタリング
・	NMF（非負値行列分解）
・ランク・評価	PageRank
```Python# プログラム名: feminist_linear_algebra_tools.py
# 概要: 社会学・フェミニズム分析に役立つ線形代数・行列分解・次元削減・クラスタリング・評価モデルの統合ツール

import numpy as np
import pandas as pd
from numpy.linalg import eig, svd, qr
from scipy.linalg import lu
from sklearn.decomposition import PCA, NMF
from sklearn.cluster import KMeans, AgglomerativeClustering
from sklearn.preprocessing import normalize
import networkx as nx

# --- 疑似データ生成（5質問×5回答者） ---
np.random.seed(42)
data = np.random.randint(1, 6, size=(5, 5))
df = pd.DataFrame(data, columns=[f"Person_{i+1}" for i in range(5)],
                  index=["GenderEquality", "DomesticWork", "Leadership", "FemaleAdvancement", "PayEquality"])
print("--- 入力データ（質問 × 回答者） ---")
print(df)

# --- ベクトル空間：列ベクトル ---
print("\n--- 列ベクトル（各人の価値観） ---")
print(df.values.T)

# --- 固有値問題（共分散） ---
cov = np.cov(df.values)
eigenvals, eigenvecs = eig(cov)
print("\n--- 固有値と固有ベクトル（質問間の共分散） ---")
print("固有値:", eigenvals)
print("固有ベクトル:")
print(eigenvecs)

# --- スペクトル分解 ---
D = np.diag(eigenvals)
P = eigenvecs
reconstructed = P @ D @ np.linalg.inv(P)
print("\n--- スペクトル分解による再構成 ---")
print(reconstructed.round(2))

# --- 特異値分解（SVD） ---
U, S, VT = svd(df.values)
print("\n--- 特異値分解（SVD） ---")
print("特異値:", S)
print("左特異行列U:")
print(U)
print("右特異行列V^T:")
print(VT)

# --- QR分解 ---
Q, R = qr(df.values)
print("\n--- QR分解 ---")
print("Q行列:")
print(Q)
print("R行列:")
print(R)

# --- LU分解 ---
P_lu, L, U_mat = lu(df.values)
print("\n--- LU分解 ---")
print("L行列:")
print(L)
print("U行列:")
print(U_mat)

# --- PCA（主成分分析） ---
pca = PCA(n_components=2)
pca_result = pca.fit_transform(df.values.T)
print("\n--- PCA（次元削減） ---")
print("主成分スコア:")
print(pca_result)

# --- K-meansクラスタリング ---
kmeans = KMeans(n_clusters=2, random_state=0)
labels_km = kmeans.fit_predict(df.values.T)
print("\n--- K-means クラスタリング ---")
print("クラスタラベル:", labels_km)

# --- 階層クラスタリング ---
hc = AgglomerativeClustering(n_clusters=2)
labels_hc = hc.fit_predict(df.values.T)
print("\n--- 階層クラスタリング ---")
print("クラスタラベル:", labels_hc)

# --- 非負値行列分解（NMF） ---
nmf_model = NMF(n_components=2, init='random', random_state=0)
W = nmf_model.fit_transform(np.abs(df.values))  # NMFは非負値限定
H = nmf_model.components_
print("\n--- 非負値行列分解（NMF） ---")
print("基底行列W:")
print(W)
print("係数行列H:")
print(H)

# --- PageRank：社会構造の評価 ---
# 疑似的に人物間の関係ネットワークを生成してPageRankを算出
g = nx.DiGraph()
g.add_edges_from([("Person_1", "Person_2"), ("Person_2", "Person_3"),
                  ("Person_3", "Person_1"), ("Person_4", "Person_2"),
                  ("Person_5", "Person_3"), ("Person_1", "Person_5")])
pageranks = nx.pagerank(g)
print("\n--- PageRank（人物影響評価） ---")
for k, v in pageranks.items():
    print(f"{k}: {v:.3f}")


```
微分と積分(日記)


```python
# プログラム名: integral_autodiff_pytorch.py
# よく使う積分公式と自動微分（PyTorch）の統合スクリプト

import sympy as sp
import torch

# --- SymPyによる積分公式（代表例） ---
x = sp.Symbol('x')

# いくつかの積分例（代表的なもののみ）
integrals = {
    '∫ x dx': sp.integrate(x, x),
    '∫ x^n dx': sp.integrate(x**3, x),
    '∫ sin(x) dx': sp.integrate(sp.sin(x), x),
    '∫ cos(x) dx': sp.integrate(sp.cos(x), x),
    '∫ 1/x dx': sp.integrate(1/x, x),
    '∫ e^x dx': sp.integrate(sp.exp(x), x),
    '∫ ln(x) dx': sp.integrate(sp.log(x), x),
    '∫ 1/(1+x^2) dx': sp.integrate(1/(1 + x**2), x),
    '∫ 1/sqrt(1-x^2) dx': sp.integrate(1/sp.sqrt(1 - x**2), x),
}

# 結果を表示
print("--- SymPyによる代表的な積分 ---")
for name, expr in integrals.items():
    print(f"{name} = {expr}")

# --- PyTorchによる自動微分（例: f(x) = x^3 + sin(x)） ---
print("\n--- PyTorchによる自動微分 ---")

# 入力値
x_val = torch.tensor(2.0, requires_grad=True)

# 関数定義: f(x) = x^3 + sin(x)
f = x_val**3 + torch.sin(x_val)

# 微分（backward）
f.backward()

# 微分結果
print(f"x = {x_val.item()}")
print(f"f(x) = {f.item()}")
print(f"df/dx = {x_val.grad.item()}")

```
【2025年版】エンジニアの情報収集がはかどる、技術系サービス5選

# 概要
エンジニアをやっていると、毎日の情報収集って本当に大事だなと感じます。  
でも、技術ブログ、スライド、動画、イベント、ニュース...とにかく情報源が多すぎて、「結局どこを見ればいいの？」と悩むこともよくありました。

そこで今回は、**僕が実際に使っていて「これは便利」と感じた技術系サービスを5つ**紹介します。  
ブログやニュースだけじゃなく、トレンドを俯瞰できるサービスも入れているので、ぜひ参考にしてみてください。

---

## 1. [teckura.com](https://teckura.com)

**技術ブログ・YouTube動画・勉強会・スライドなどを横断して収集・まとめてくれるWebサービス。**

Zenn・Qiita・SpeakerDeck・Connpass・YouTubeなど複数の技術系サイトから情報を拾ってきてくれていて、UIもシンプルで見やすく、よく**空いた時間に「今日はどんな話題が出てるかな」とざっとチェック**しています。


## 2. [TechFeed](https://techfeed.io)

エンジニア向けニュースをパーソナライズして届けてくれるサービス。  
タグやキーワードでフィードを調整できるので、**自分の興味に合った記事だけを効率よく追える**のが気に入っています。

最近は「TechFeed Pro」で、分野ごとの専門家のおすすめも見られるようになっていて、こちらもけっこう参考になります。


## 3. [daily.dev](https://daily.dev)

海外の技術ニュースやブログを自動で集めてくれる、Chrome拡張＋Webサービス。  
新しいタブを開くたびに最新記事が表示されるので、**ブラウジングついでに自然とキャッチアップできる**のがいい感じです。

英語圏のトレンドを追いたい人には特におすすめ。


## 4. [POSTD](https://postd.cc/)

エンジニア向けの**海外技術記事を翻訳して紹介しているメディア**。  
内容のセレクトが渋くて、**設計思想やパフォーマンス改善、開発文化に関する深い話が多い**のが特徴です。

最近も定期的に更新されていて、**ただのTipsではなく“読み物として面白い技術記事”** を探したい人にすごくおすすめです。  
時間をかけてじっくり読む価値のある記事が多く、僕も定期的にチェックしています。


## 5. [menthas](https://menthas.com/)

🧠 **話題の技術記事を「キーワードクラウド」で俯瞰できるちょっと変わったサービス。**

よくある記事一覧じゃなくて、**今どんなキーワードが注目されているか**を視覚的にパッと見られるのが面白いです。

僕は「最近あまり追えてない分野」をざっと把握したいときに使っていて、まるで**技術トレンドの地図を眺めるような感覚**です。


## おわりに

情報収集って、使うサービスやスタイル次第で効率も視野もかなり変わってくると思います。  
今回紹介した中に、もしまだ使ったことがないサービスがあれば、ぜひ一度チェックしてみてください。
初投稿：自己紹介

# はじめまして
普段は **Twilio** というクラウドコミュニケーションプラットフォームで **プリセールスエンジニア（Solutions Engineer）** をしています。

これまでのキャリアはざっくりこんな感じです：

- 小規模の開発会社でシステム開発や客先への出向
- 外資系IT企業でプロフェッショナルサービスやアーキテクトの経験
- 現在はTwilioで **通信API＋〇〇** のようなソリューション提案やデモ開発を担当

最近は **ChatGPT／Claude／Gemini** などのAIツールを業務でも趣味でも活用していて、  
「プリセールス × AI × 開発」の三位一体で毎日楽しく技術に触れています。

## なぜQiitaを始めたのか？

周りにはプログラマーや開発エンジニアの方はたくさんいるのですが、  
**プリセールスエンジニア** として情報発信している人は意外と少ないな、とずっと感じていました。

プリセールスエンジニアって「技術」「ビジネス」「お客様対応」が全部混ざった面白い仕事なのに、  
世の中ではまだ認知の低い役割かなと思っています。

そこで、これからQiitaでは **TwilioのTips** や **AIと通信APIの連携方法** に加えて、  
**プリセールスエンジニアの仕事術やキャリアの話** も書いていこうと思っています。

「プリセールスエンジニアってどんな仕事？」と思っているエンジニアや、  
これからキャリアチェンジを考えている方に役立つ情報を発信できればうれしいです！

## 最近作ったもの

最近仕事では、**通話内容のリアルタイム翻訳／文字起こしシステム** などを作っています。
一方趣味では、**PC内の動画をYoutubeのように一覧表示・再生できるMacアプリ**などをつくりました。

コードを書くこと自体は趣味でもあり、**プロトタイプを素早く作って動かしてみる** のが得意です。
でも最近では誰でもAIによって本当に素早く作れるようになってしまいました。

## 趣味も少し

仕事以外では **ガジェット集め** が趣味です。  
スマートフォン、イヤホン、カメラ、スマートホーム機器など、  
「面白そう！」と思ったらすぐ手を出してしまいます（笑）

## 最後に

もともと社内での情報共有はよくやっていましたが、  
これからは **社外にも発信していきたい** と思いQiitaを始めました。

技術のことも、プリセールスのことも記事として書いていく予定です。  
どうぞよろしくお願いします。
Python を使って PowerPoint で画像を追加または削除する

デジタルオフィスの時代において、Pythonはオフィス文書の自動処理に最適なツールとなっています。PowerPointの画像管理に関しては、Pythonを使用することで、複数のPowerPointファイルの一括操作が可能になり、手動操作によるエラーを減らすことができます。この記事では、無料のPythonライブラリを使って**PowerPointスライドに画像を追加する方法**、または**PowerPointから画像を削除する方法**を紹介します。

## 無料のPythonライブラリをインストールする
この作業には、[Free Spire.Presentation for Python](https://www.e-iceblue.com/Download/free-presentation-python.html) ライブラリが必要です。以下の pip コマンドを使ってインストールできます。
```
pip install Spire.Presentation.Free
```
>[無料版のページ制限を確認するにはクリック](https://www.e-iceblue.com/Introduce/free-presentation-for-python.html)

## PythonでPowerPointスライドに画像を追加する
無料のPythonライブラリが提供する **`ISlide.Shapes.AppendEmbedImageByImageData()`** メソッドを使用することで、指定されたスライドに画像を追加することができます。操作手順は以下の通りです。

1. PowerPointプレゼンテーションを作成し、**`Presentation.Slides[index]`** プロパティを介してその中の指定されたスライドを取得します。
1. 画像を読み込み、スライド上での画像の位置を指定します。
1. **`ISlide.Shapes.AppendEmbedImageByPath()`** メソッドを介して、画像をスライドに追加します。
1. `Presentation.SaveToFile()` メソッドを使用して、生成されたプレゼンテーションを保存します。


**Pythonコード**
```python
from spire.presentation.common import *
import math
from spire.presentation import *

# PowerPoint プレゼンテーションの作成
presentation = Presentation()

# 最初のスライドを取得する
slide = presentation.Slides[0]

# 画像を読み込む
imageFile = "logo.png"

# スライド内で画像の位置を指定する
left = math.trunc(presentation.SlideSize.Size.Width / float(2)) -100
rect1 = RectangleF.FromLTRB (left, 120, 180 + left, 300)

# スライドに埋め込み画像を追加する
image = slide.Shapes.AppendEmbedImageByPath (ShapeType.Rectangle, imageFile, rect1)

# 画像の外枠線を塗りつぶしなしの効果に設定する
image.Line.FillType = FillFormatType.none

# PowerPoint 文書を保存する
presentation.SaveToFile("AddPowerPointImage.pptx", FileFormat.Pptx2016)
presentation.Dispose()
```
![AddImageToPowerPoint.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2811193/2e7460b7-792f-4c74-80e8-a7864b1a157c.png)


## Python で PowerPoint のスライドから画像を削除する
PowerPoint のスライド内のすべての画像を削除するには、スライド内の各シェイプを反復処理し、シェイプ内の画像のタイプ（**`SlidePicture`**）を特定し、その後 **`ISlide.Shapes.Remove(Index)`** メソッドを使って画像を削除します。

1. `Presentation.LoadFromFile()` メソッドを使って PowerPoint 文書を読み込みます。
1. `Presentation.Slides[index]` プロパティを使って指定されたスライドを取得します。
1. 指定されたスライド上のすべてのシェイプを反復処理します。
1. 現在のシェイプが **`SlidePicture`** のタイプかどうかを判定し、そうであれば **`ISlide.Shapes.Remove(Index)`** を使って画像を削除します。
1. `Presentation.SaveToFile()` メソッドを使って生成されたファイルを保存します。

**Pythonコード**
```python
from spire.presentation.common import *
from spire.presentation import *

# PowerPoint プレゼンテーションの作成
ppt = Presentation()
ppt.LoadFromFile("AddPowerPointImage.pptx ")

# 最初のスライドを取得する
slide = ppt.Slides[0]

# スライド内のすべてのシェイプを反復処理する
for i in range(slide.Shapes.Count - 1, -1, -1):
   
    # 現在のシェイプが画像（SlidePicture）であるかどうかを判定する
    if isinstance(slide.Shapes[i], SlidePicture):
       
        # もし画像であれば、そのシェイプをスライドから削除する
        slide.Shapes.RemoveAt(i)

# PowerPoint 文書を保存する
ppt.SaveToFile("RemovePowerPointImage.pptx", FileFormat.Pptx2016)
ppt.Dispose()
```

上記の例では、Python を使って PowerPoint の画像を追加および削除することができます。さらに、この無料ライブラリは PowerPoint から画像を抽出することもサポートしています。

https://www.e-iceblue.com/Tutorials/Python/Spire.Presentation-for-Python/Program-Guide/Image-and-Shapes/Python-Extract-Images-from-PowerPoint-Presentations.html
数式の計算（ 1 桁）

Paizaの「文字列から数式を計算する」問題をやってみたら、数字と演算子が混ざって混乱？！　問題の解説と失敗しそうなところについて書いたよ！

<br>

## 問題概要

与えられるのは、1桁の数字と + – だけで構成された数式の文字列（例：”1+2-3+4“）。
この式をちゃんと計算して数値で出力する

例として、`1-2`, `2+1-7` のような文字列は与えられる可能性があるが、`1+(-2)` や `-4-2+4`, `5+-2` のような文字列は与えられないことが保証されている点に注意。

```
入力例:
1-3-5-6-2-1+9

出力例2:
-7
```
<br>

https://paiza.jp/works/mondai/string_primer/advance_step8

<br><br>
## ✅ 完成コード例

```js
const rl = require('readline').createInterface({ input: process.stdin });

rl.once('line', (input) => {

    // ステップ1: 一文字ずつの配列に
    const chars = Array.from(input);


    // ステップ2: 初期値は最初の数字
    let result = Number(chars[0]);


    // ステップ3: 演算子と数値のセットで処理
    for (let i = 1; i + 1 < chars.length; i += 2) {
        const op = chars[i];
        const num = Number(chars[i + 1]);

        if (op === '+') result += num;
        else if (op === '-') result -= num;
    }

    // ステップ4: 結果を出力
    console.log(result);

    rl.close();
});
```
1: `Array.from(input)` で1文字ずつに分割

2:  最初の数値をresultとして確保

3.`for` でインデックス1から、2つずつ

- 演算子（`+` or `-`）を取得
- 数字を`Number()`で変換して加減算

4: 結果を`console.log(result)`で出力！

<br><br>

## for ループの終了条件の設定ミスによる NG例（バグが起きやすい書き方）

### ❌ NG例1：i <= chars.length

```js
for (let i = 1; i <= chars.length; i += 2) {
    const op = chars[i];

    // ↓ ここで undefined にアクセスする可能性！ 
    const num = Number(chars[i + 1]); 
}
```
❗問題点：

- `chars.length` は「要素数」。
- インデックスは 0 ~ chars.length – 1。

`i <= chars.length` だと、`chars[i + 1]` が範囲外になる可能性　→ `undefined` を `Number()` に渡して `NaN` に！

<br>

### ❌ NG例2：i < chars.length だけど、i + 1 のチェックをしていない

```js
for (let i = 1; i < chars.length; i += 2) {
    const op = chars[i];

    // ↓ ここも念のため注意
    const num = Number(chars[i + 1]); 
}
```
⚠ 注意点：
通常の数式（演算子と数字が交互に並ぶ）では問題ないが、
万が一、入力が “`1+2+`” のように末尾に演算子だけ残った場合、`chars[i+1]` が `undefined` になる。

<br>

### ✅ 安全な OK例（おすすめ）i + 1 < chars.length
```js
for (let i = 1; i + 1 < chars.length; i += 2) {
    
    const op = chars[i];
    const num = Number(chars[i + 1]);
    if (op === '+') result += num;
    if (op === '-') result -= num;
}
```

<Br>

## 気づきメモ

- `i + 1 < chars.length` が地味に超大事
- 最初の数字を初期値にすることで、後は演算子と数字を交互に読むだけでOK！

<br>

### 📘新しく学んだこと　&　まとめ

- `Array.from()` で文字列を1文字ずつ扱えるのは便利！
- `for (i + 1 < length)` の形で「次の値」を安全にチェック
- `Number()`で変換する前に`undefined`対策を考えるクセが大事

<br><br>
 [僕の失敗談と解決話！](https://paizabeginner.wordpress.com/about/)
React + Redux Toolkit + nanoid でユニークID付きの状態管理を実装してみた

こんにちは。今日は React + Redux Toolkit を使って、状態（state）にユニークなIDを付けて管理するシンプルなアプリを作りながら学んだことをまとめます。

🎯 目的
Redux Toolkit を使って状態管理する

nanoid() でユニークなIDを生成する

useSelector, useDispatch の基本的な使い方を理解する

状態の変更フロー（作動形）を把握する

📦 使用した技術
React（create-react-app）

Redux Toolkit

nanoid

🧱 ディレクトリ構成
css
복사
편집
src/
├── app/
│   └── store.js
├── features/
│   └── whiteboard/
│       └── whiteboardSlice.js
├── App.jsx
└── main.jsx
1️⃣ Redux store の作成（store.js）
js
복사
편집
import { configureStore } from '@reduxjs/toolkit';
import whiteboardReducer from '../features/whiteboard/whiteboardSlice';

export const store = configureStore({
  reducer: {
    ワイトボード: whiteboardReducer,
  },
});
2️⃣ slice の作成（whiteboardSlice.js）
js
복사
편집
import { createSlice } from '@reduxjs/toolkit';

const whiteboardSlice = createSlice({
  name: "whiteboard",
  initialState: [],
  reducers: {
    作成: (state, action) => {
      console.log("作成アクション:", action.payload);
      return [...state, action.payload]; // 不変性を保つ
    },
  },
});

export const { 作成 } = whiteboardSlice.actions;
export default whiteboardSlice.reducer;
3️⃣ React コンポーネント（App.jsx）
js
복사
편집
import React, { useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { 作成 } from './features/whiteboard/whiteboardSlice';
import { nanoid } from 'nanoid';

function App() {
  const [入力文字, set入力文字] = useState("");
  const ワイトボード = useSelector((state) => state.ワイトボード);
  const dispatch = useDispatch();

  const 作成する = () => {
    const データ = { 番号: nanoid(), 内容: 入力文字 };
    dispatch(作成(データ));
    set入力文字("");
  };

  return (
    <div style={{ padding: "20px" }}>
      <h2>ワイトボード</h2>
      <div className="ワイトボード">
        {ワイトボード.map((文字情報) => (
          <div key={文字情報.番号} className="文字">
            {文字情報.内容}
          </div>
        ))}
      </div>
      <input
        value={入力文字}
        onChange={(e) => set入力文字(e.target.value)}
      />
      <button onClick={作成する}>作成する</button>
    </div>
  );
}

export default App;
✅ 今日学んだポイント
nanoid() を使えばユニークIDが一瞬で作れる

useDispatch でアクションを発行して、状態を変更できる

useSelector で Redux store の状態を監視できる

Redux Toolkit の slice は reducer と action を同時に管理できて便利

状態は直接変更せず、...state を使って不変性を保つ

🔚 まとめ
nanoid() を使えば、UIやリストの key 管理がとても簡単になり、Redux の状態管理と組み合わせることで効率的に開発できます。
また、状態の「作動の流れ（Action → Reducer → Store）」を理解することで、より安全でバグの少ないコードが書けるようになります。
個人向けメモ　




① プレイヤーの自動右移動スクリプト（2D）
```
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public float moveSpeed = 5f;　//playerの速度
    public float jumpForce = 5f; //playerのジャンプ
    private Rigidbody2D rb;
    private bool isGrounded = true;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        // 常に右へ移動
        rb.velocity = new Vector2(moveSpeed, rb.velocity.y);

        // スペースキーでジャンプ
        if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
        {
            rb.velocity = new Vector2(rb.velocity.x, jumpForce);
            isGrounded = false;
        }
    }

    void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.collider.CompareTag("Ground"))
        {
            isGrounded = true;
        }

        if (collision.collider.CompareTag("Obstacle"))
        {
            Debug.Log("Game Over");
            Time.timeScale = 0; // 一時停止
        }
    }
}
```
【参加レポ】RubyKaigi 2025 に行ってきました！

# はじめに

今年も RubyKaigi に行ってきました。今回で3回目です。

RubyKaigi 2025 は 4/16 ~ 18 に愛媛県松山市で開催されました！

https://rubykaigi.org/2025/

この記事では、印象に残ったセッションをいくつか紹介します！
（おまけとして、次回以降のRubyKaigi参加の際に役立つかもしれない情報も一番下に書いてあります。）

去年の参加レポはこちら:

https://qiita.com/wataru86/items/feb43c1835ab68ddeaa9

# 印象に残ったセッション

## Ruby Taught Me About Encoding Under the Hood

https://rubykaigi.org/2025/presentations/ima1zumi.html

<script defer class="speakerdeck-embed" data-id="0a7e33e668e7481ab760985a6b03de0e" data-ratio="1.7777777777777777" src="//speakerdeck.com/assets/embed.js"></script>

1日目の Keynote です。

エンコーディングの話で、 irb で特定の絵文字を入力した時にクラッシュするバグなど紹介されました。

これまで僕はエンコーディングの難しさをなんとなく感じていましたが、書記素クラスタまわりの話はほとんど知らなかったので、とても興味深かったです。

## TRICK 2025: Episode I

https://rubykaigi.org/2025/presentations/tric.html

1日目最後のセッションの TRICK です。

雑に TRICK を説明すると、Ruby で書かれたすごいプログラムのコンテストです。

例として、TRICK 2022 の金賞受賞作品を紹介します。

https://x.com/tompng/status/1582322388678549504

去年の RubyKaigi で TRICK 2025 開催の発表があった時からずっと楽しみにしていました。

今回もどの作品も超絶技巧で意味不明で楽しかったです。

今年の受賞作品はこちら↓

https://github.com/tric/trick2025

## Performance Bugs and Low-level Ruby Observability APIs

https://rubykaigi.org/2025/presentations/KnuX.html

<iframe src="https://docs.google.com/presentation/d/1lDnxFkc4URsi0LP4w1M5IXv5A02AG_HUy3gW_SpEWOA/embed?start=false&loop=false&delayms=3000" frameborder="0" width="960" height="569" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>

2日目の Keynote です。

パフォーマンス関連のバグを特定するために、Ruby の様々な低レベルの API を使う必要があり、それらを活用した gem を作成した、という内容だったかと思います。（理解できていない部分が多い）

普段僕も Rails などを使った開発をしていて、パフォーマンスの改善を検討することありますが、「低レベルの API を使ってパフォーマンス悪化の原因を特定しよう！」という発想には普段至らないので、とても参考になりました。

# おわりに

今年は Qiita がスポンサーブースを出展していて、僕もそのメンバーとして参加していました。

ブースでの対応が忙しく聴講できたセッションは少ないですが、聴講したセッションはすべて面白かったです！！

Qiita のスポンサーブースの様子や、上記以外のセッションの感想などはこちらに記載してあるので、ぜひ読んでいただけと幸いです。

https://qiita.com/official-columns/event/202505-rubykaigi2025-report/

# おまけ: 次回以降の RubyKaigi に参加する時に役立つかもしれない情報

- RubyKaigi 2026
    - 次回は函館！会場が2箇所！？
        - https://rubykaigi.org/2026/
        - > Hakodate Citizen Hall (函館市民会館)
        - > Hakodate Arena (函館アリーナ)
    - [Rubyistに向けた函館地理情報 v0.1.0 - Re: 醤油の一升瓶じゃあ戦えない](https://uvb-76.hatenablog.com/entry/2025/04/24/014639)
        - すでに函館の地理情報をまとめている方もいる
- お昼ご飯
    - お弁当の配布があるけど、数が少ない場合が多い
    - RubyKaigi 2025 ではキッチンカーが来ていたけど、タイミングによっては並ぶのに時間がかかる
    - お昼の時間が割と長いので、飲食店を探してもよい
    - 会場近くにスーパーがあるなら、そこに行ってお弁当を買うのもよい
        - 来年だと、コープさっぽろ湯川店が会場の近くにある
- ドリンクアップ
    - 各スポンサーが開催している
        - RubyKaigi 2025: https://rubykaigi.org/2025/events/
        - [RubyKaigi 2025 では Qiita もドリンクアップを開催しました！](https://increments.connpass.com/event/349155/)
    - 公開されたらすぐに定員を超えることが多いですが、キャンセルされる方も結構います
        - 定員を超えている場合でも申し込んでおくと参加できる可能性があります
- 体力
    - RubyKaigi は3日間あります
    - 前泊後泊などを含めると、5日間歩き回ることになります
    - 普段リモートワーク中心で運動不足だと途中で力尽きます
    - 定期的に運動して体力をつけておきましょう
🧑‍💻✨Reactが初めてでも大丈夫！ 📚「The Easiest React」講座でサクッと理解しよう💡


みなさん、こんにちは　韓国在住のsanaです！
充実したGWを過ごしましたか？？ 私は旅行に行ってリフレッシュしてきました！

・・・

💭「Reactって聞いたことあるけど、なんか難しそう…」　
そんな方にぴったりの講座がこちら👇

https://u.inf.run/435ZEO4


👇この講座のポイント

👶 完全初心者OK！
🛠️ Reactの基本構成から実際のコードの書き方まで！
📦 SX・props・state・イベント処理など、必要な知識をコンパクトに学べる！
⏱️ 忙しい人でも取り組みやすい短時間構成🎉

//

📘おすすめな方
・Reactをゼロから学びたい方
・ドキュメント読むより動画で理解する派の方
・これからWebフロントエンド開発にチャレンジしたい初学者

//

🤔注意点・補足
・字幕ベースの学習なので、聞くより読むのが得意な人向き
・あくまで**「最初の一歩」**として最適な内容なので、中級以上の内容を求める場合は他の講座も検討が必要

・・・

「The Easiest React」は、React入門者にとって本当にちょうど良い難易度で、自分のペースでReactの全体像を掴むのに役立つ内容です！

Reactを独学しようとして最初につまずきがちな**「何から始めるか」**という部分で、基礎を限られた時間で簡単に押さえたい方には特におすすめです。

連休明けでモチベーションも落ちてしまってる方多いと思います。
正直私もそのうちの一人です…。

今週はゆったりと自分のペースで頑張っていきましょう...！　ファイティン！
R - エラー対処記録

# FUN(X[[i]], ...) で: 強制変換により NA が生成されました
状況：qPCRの結果をグラフで描画しようとしている。
エラー：FUN(X[[i]], ...) で: 強制変換により NA が生成されました

```r:wrong code
# グラフの大元
p <- ggplot()  +
    theme(
          axis.title = element_text( size = 15), 
          axis.text = element_text(size = 15),
          panel.grid.major.x = element_blank(),
          panel.grid.minor.x = element_blank()
        )

# 描画します
p + 
  ggtitle("title")  + #タイトル
  geom_point(
    data = df, #使用するデータフレーム (列名：temperature, cps_mL, time）
    aes(x=as.numeric(temperature), y = as.numeric("cps_[mL]"), #ここにバグ
        color = time)
  ) +
  scale_y_log10(limits = c(10^5,100000000), labels = label_log(digits = 2), minor_breaks = minor_breaks_log) 
```

原因：列名を間違えて記載していた。
データフレームの列名を"cps_mL"に変更したのを忘れて、前の列名(" 'cps_[mL]' ")のままにしていた。

```r:修正
p + ... +
  geom_point(
    aes(x=as.numeric(temperature), y = as.numeric(cps_mL), #ここにバグ
        color = time)
  ) + ...

```

# グラフのエラーバーがなぜか表示されない

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1139020/2141cbbc-3ae0-416b-9979-7b985f930845.png)

困りごと：本来は真ん中のようにエラーバーが表示されるはずだ。しかし、左右のプロット(x=4, 37)に対してエラーバーの横棒が表示されていない。縦棒だけになっている。
原因：グラフのx軸の描画範囲(=c(0,40)) に対して、エラーバーの横棒が収まらなかったため描画されなかった。
対処：エラーバーの横幅を短くする。描画範囲を広くすることも可能だが、そもそもエラーバーの幅が広すぎると感じたので横幅を短くする方法を選んだ。

元凶のコード：
```r: bad
ggplot()  +
  # グラフの設定
  theme(
    axis.title = element_text( size = 15), 
    axis.text = element_text(size = 15),
    panel.grid.major.x = element_blank(),
    panel.grid.minor.x = element_blank()
  )+
  #### 元凶部分 (limits = c(0,40)) ####
  scale_x_continuous(limits = c(0, 40), breaks=c(4,20,37),minor_breaks = seq(0,40,5), labels=c(4,20,37)) +
  ####################################
  scale_y_log10( ... ) +

  # 散布図
  geom_point(
    data = df, 
    aes(x=as.numeric(temperature), y = as.numeric(cps_mL), color = time)
  ) +
  # エラーバー
  geom_errorbar(
    data = df, 
    aes(
      x=as.numeric(temperature),
      y = as.numeric(cps_mL),
      ymin=ymin, 
      ymax =ymax, 
      color = time)
    )  
```

修正コード：
```r: 修正
ggplot()  +
  # グラフの設定
  theme( ... )+
  #### 元凶部分だけど残す ####
  scale_x_continuous(limits = c(0, 40), breaks=c(4,20,37),minor_breaks = seq(0,40,5), labels=c(4,20,37)) +
  ###########################
  
  scale_y_log10( ... ) +

  # 散布図
  geom_point( ... ) +
  # エラーバー
  geom_errorbar(
    data = df, 
    aes(
      x=as.numeric(temperature),
      y = as.numeric(cps_mL),
      ymin=ymin, 
      ymax =ymax, 
      color = time,
      width = 0.7) ##### この行を追加 #####
    )  

```
修正結果：ちゃんと表示されるようになりましたとさ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1139020/3eb2e14c-570c-4f17-9da0-18d1130d8dcf.png)
技術志向のエンジニアとプロダクト志向のエンジニア、あなたはどっち？

# 技術志向とプロダクト志向の違いって？―自社開発企業で働き始めて気づいたこと

初めまして！株式会社sumarch（スマーチ）のWebエンジニアチーム、小笹です。  
2025年3月に入社し、この記事がQiita初投稿になります

今回は、直近でエンジニアとして働く中でふと気になったテーマ――  
**「技術志向」と「プロダクト志向」って何が違うのか？**  
について、自分の実体験も交えながらまとめてみました。



## ✅ この記事はこんな方におすすめ！

- 自分のエンジニアとしての方向性に悩んでいる
- 転職を考えていて「自社開発ってどんな感じ？」と思っている
- 技術に興味があるけど、ビジネスにも関わってみたい



## 💡 そもそも「志向」ってなに？
**志向**とは、簡単に言うと物事に対する考え方や取り組む方向性のことです。エンジニアリングにおいて「志向」とは、自分がどのような観点で開発業務に取り組むか、その軸となる価値観や基準を指します。

エンジニアの「志向」は主に2つのタイプに分けられると自分自身考えていて、それが「技術志向」と「プロダクト志向」です。どちらが正解というものではなく、自分の性格や得意分野、仕事に対する価値観によって自然に形成されるものだと考えています。

私自身、これまではどちらかというと**0→1**の開発業務に携わることが多く、要件定義、技術選定やプロダクト開発、DB設計、コーディング業務など幅広く裁量を持たせてもらい、その中でモダンな技術を自由に採用してサイトパフォーマンスや開発スピードを底上げしたりなど技術を吸収しながら行なっていく開発の仕事が好きだった一方で、 
「この機能やサービスってユーザーに本当に使われてるのかな？」「ユーザーの立場になって開発できているのかな」「利用者を増やすために何かしたいけどどうすればいいか分からない」というモヤモヤを感じる時がありました。

対照的に現職に入社してからは、既存で稼働しているWebサイトやインフラの保守や運用業務、稼働しているプロダクトに対して追加の機能設計/追加などをチームで行うことが増えました。
1→10や10→100のグロースフェーズの開発経験が乏しかった自分からするとチームで協力して1つのプロダクトを大きくしていくことや、もっとユーザーにとって良い体験を届けるために開発することは少なかったのでこの点においてひたすらにモダンな技術でパフォーマンス、速さ、正確さを追求した技術志向的なプロダクト開発と比較すると0→1開発では感じることのなかった制約による難しさとプロダクトを育てる楽しさを今感じることができています。


## ⚔️ 技術志向 と プロダクト志向 ― 比較してみた！

|  | 技術志向エンジニア | プロダクト志向エンジニア |
|--|------------------|----------------------|
| 主な関心 | 技術そのもの、品質、最適化 | ユーザー価値、課題解決 |
| 技術についての考え方 | 目的　/　目標 | 手段 |
| モチベーション | 新しい技術・効率化 | プロダクト改善・成長 |
| 強み | 技術選定の幅、圧倒的な設計力と実装力、スペシャリスト | 要件定義、施策提案、ドメイン理解、事業理解、ジェネラリスト |
| 向いている職場 | SIer / 受託開発 / SES / スタートアップ | 自社開発  / Webサービス運営 |


## 🧠 両者は対立するものではなく共存するもの？

大切なのは、**どちらが正しいかではなく、どちらが自分に合っているか**。  
そして現代のWebエンジニアリングでは、**両者のバランス**感覚がますます重要になっていると思います。

私自身、技術にこだわる部分や技術好奇心は日常的に持ちつつも、「どうすればユーザーが使いやすくなるか？」という視点を持てるようになったのは、自分が携わったプロダクトやサービスを使ってくれる人がもっと増えてほしいと思うようになってからで、それまでは自分本位にシステムを構築していた面や技術選定ばかりに目が行きがちで実装の細かいところまでは目が行き届いていなかったように覚えています。

プロダクトに対しての理解やよくしたいという思いだけで最低限の技術力がない場合は、肝心な実装がガタガタになり低クオリティ・パフォーマンスなサービスに仕上がってしまう恐れや保守性の悪いソースコードになる可能性があり、逆に技術志向だけが強すぎてしまう場合や業務に対するドメイン知識が不足していると特にチームで実装を行うシチュエーションではチームメンバーがついてこれない技術選定を行なってしまったり、組織が求めているプロダクトの方向性とブレてしまう可能性があるので、志向の偏りのなく志向性が共存しているエンジニアが理想的な形なのかなと個人的には最近考えています。


## ✍️ おわりに

「技術志向 or プロダクト志向」という視点は、キャリアを考えるうえでも役立つキーワードだと思っています。
エンジニアと単に言ってもその範囲は非常に大きく、自分が思い描くキャリアも組み合わせ方によっては無限に選択肢が出てくると思います。
読んでくださった皆さんが、自分に合った働き方を見つけるヒントになれば嬉しいなと思いました。


## 🙌 最後まで読んでくださった方へ

よければ「いいね」や「コメント」でフィードバックいただけると励みになります！  
Qiitaでの発信もこれから増やしていく予定なので、よろしくお願いします！
Excelで閏日を数える数式


## 用途
- 残存期間が1年以上（償還日が受渡日の1年応当日以降）である債券の残存年数の算出
※残存期間が1年以上である債券の残存年数＝閏日を除く残存日数（片端）÷365

## Excelでの数式
`SEQUENCE`関数を使うことができないExcel 2019以前でも使用可能な関数で構成する。
[コメント](#comment-9510957765a2b0d1a206)いただいているとおり、`SEQUENCE`関数を用いれば、簡素に構成可能。

### 前提
次のとおり日付が入力されているものとする。
- A1セル：受渡日
- B1セル：償還日
※A1<B1

### 閏日の日数を得る数式
次のとおり数式を設定すれば、両日付の間の閏日の数を得られる。
```
=SUMPRODUCT((DAY(DATE(ROW(INDIRECT(CONCAT(YEAR(A1),":",YEAR(B1)))),2,29))=29)*1,(INT(A1)+1<=DATE(ROW(INDIRECT(CONCAT(YEAR(A1),":",YEAR(B1)))),2,29))*1,(DATE(ROW(INDIRECT(CONCAT(YEAR(A1),":",YEAR(B1)))),2,29)<INT(B1)+1)*1)
```

2つの年を与えた場合にその間の年を含む配列を返すための方法として
`ROW(INDIRECT(CONCAT(YEAR(A1),":",YEAR(B1))))`
を用いている。

その外側に`SUMPRODUCT`関数を用いているので、配列数式ではあるが`Ctrl+Shift+Enter`不要。

日付の比較において`INT(A1)+1<=`や`<INT(B1)+1`としているのは、A1セル又はB1セルに時刻入りの日付が含まれている可能性を想定。

### 閏日を除く残存日数（片端）を得る数式
次のとおり数式を設定すれば、両日付の間の日数（片端）であって、閏日を除く日数を得られる。
```
=INT(B1)-INT(A1)-SUMPRODUCT((DAY(DATE(ROW(INDIRECT(CONCAT(YEAR(A1),":",YEAR(B1)))),2,29))=29)*1,(INT(A1)+1<=DATE(ROW(INDIRECT(CONCAT(YEAR(A1),":",YEAR(B1)))),2,29))*1,(DATE(ROW(INDIRECT(CONCAT(YEAR(A1),":",YEAR(B1)))),2,29)<INT(B1)+1)*1)
```

### 残存期間が1年以上であるか1年未満であるかに応じて残存日数（片端）を得る数式
IF関数及びEDATE関数を組み合わせて
```
=IF(B1>=EDATE(A1,12),INT(B1)-INT(A1)-SUMPRODUCT((DAY(DATE(ROW(INDIRECT(CONCAT(YEAR(A1),":",YEAR(B1)))),2,29))=29)*1,(INT(A1)+1<=DATE(ROW(INDIRECT(CONCAT(YEAR(A1),":",YEAR(B1)))),2,29))*1,(DATE(ROW(INDIRECT(CONCAT(YEAR(A1),":",YEAR(B1)))),2,29)<INT(B1)+1)*1),INT(B1)-INT(A1))
```
とする。残存年数を得るには365で除すればよい。

## 補論
http://seesaawiki.jp/w/minus_alpha/d/%B4%FC%B4%D6%B7%D7%BB%BB
にて紹介されている修正ユリウス日を用いる方法では、起算日又は満了日が閏日である場合に不具合を生じる。
Ubuntu DesktopをKAGOYA VPSで構築してみた。

以前から時間があれば触ってみようと考えていた「Ubuntu Desktop」。
今回まとまった時間ができましたが、構築から始めると時間が足りなくなりそうでしたので、KAGOYAのVPSを使って構築して、いろいろと触ってみようと思います。

## Ubuntu DesktopをVPSで作成
まずはUbuntu DesktopをKAGOYA VPSで構築します。

VPSアカウント作成後に入れるコントロールパネルから「インスタンスを作成」を選択。

OSの選択画面でUbuntu Desktop 24.04LTSを選択。

![ubuntudesk1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3993170/61288941-891c-403a-9b6c-3d505e76c9ba.png)

その後、スペックやパスワードを設定してインスタンスを作成。

リニューアルでインスタンス作成の待ち時間も大幅に短縮されたので、1分もかからずUbuntu Desktopの準備が完了しました。

![ubuntudesk2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3993170/164f616d-d62f-4937-b1fb-1198a8e6d98b.png)

## コンソールから起動
Ubuntu Desktopはコンソールから起動させます。

![ubuntudesk3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3993170/7a3d2915-313f-4cb9-8086-423fca7ceb4b.png)

※ポップアップ禁止の設定を行っていると、コンソールは開きません。

コンソールが開きますと、そのまま各種設定が始まるので、画面の指示に従い設定を進めます。

![ubuntudesk4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3993170/54c82d14-953f-4cc2-be91-85fb83c13f2b.png)

最後までセットアップが完了しましたら、以下のような画面が表示されます。

![ubuntudesk5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3993170/059f75c7-e660-460e-8169-f567e740ea30.png)

### 「display output is not active」表記について
恐らくVPSでUbuntu Desktopを構築した大半の人が「display output is not active」という表記を目にしたと思います。

![ubuntudesk6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3993170/4dffc3ab-eefa-4e35-a008-f083bf495fe4.png)

これはエラーというよりも仕様に近いもので、物理的なディスプレイが接続されていないVPS環境ではよくある現象となっています。

対処法は、単純にこのまま待ち続けるのみとなります。

## Ubuntu Desktopを触ってみた感想
実際にUbuntu Desktopを触ってみた感想ですが、私のような少しかじっていますレベルの人間にとっては、やはりGUIがあるのは安心できました。

中級～上級者レベルになってくるとVPSでのUbuntu Desktopに対して否定的な意見も増えてくるそうですので、私としては万人にオススメはできません。

ただ、まだまだ勉強中だという方にとっては、Ubuntu Desktopは安心感を得られるディストリビューションだという事は間違いありませんので、そういった方には是非触ってみてほしいと思いました。
【登壇裏話】パネルディスカッションって、けっこうライブ感あるんです【WordPressセキュリティウェビナー】

こんにちは、みたにです。

今回は、2025年4月16日、22日に開催された  
「WordPress × Webフォーム：最新の脅威と守るべきセキュリティ対策」  
ウェビナーに登壇したときの裏話を、  
ほぼメモ帳感覚でゆる〜くまとめてみました。

---

## 登壇のきっかけ

ある日、東京本社のとある部長さんから相談があるんですが、と。

「さくらさんとウェビナーやるんですが、登壇おねがいしますね。」

いや、ざっくりすぎん？？って思ったけど、とりあえず「いいっすよ！」と二つ返事で返しました。

話を聞くと、どうやら**セキュリティに強いスパイラルと、さくらインターネットさんのサービスでシナジー生まれるんじゃない？** という企画だったらしい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201694/434d01a0-cac8-4260-b838-6a5169a397e4.png)


そんなわけで、流れるように登壇が決まりました。（ありがたや）

---

## 準備はどんな感じだったか

今回は「パネルディスカッション形式」だったので、  
ガチガチに資料を作り込む、みたいなことはなし。

準備は、2〜3ヶ月前からちょいちょい打ち合わせ。  
だいたい月1〜2回ペースで集まって、

- 「このテーマどうする？」
- 「こんな流れで話せばいけそう？」

みたいな、わりかし行き当たりばったり（失礼）を繰り返してました。

ちなみにネタを作るときに一番気をつけたのは、  
**「セキュリティって聞いたことがある！」って人にも届くようにすること。**
（↑ いや難しいのはわかってるんですけどね）

---

## 当日のリアル（ドタバタ編）

### スタート直前バタバタ事件

開始30分前の控室。

「え、これ、どの順番でしゃべる？？」  
「最初の自己紹介、誰からいくんだっけ？」  
「Zoomのリンク、もう一回貼ってもらえます？？」

……みんな心の中で「やばい」を連呼してたのは秘密です。

でも不思議なことに、配信が始まった瞬間、  
**「今日も快晴ですね（ﾆｺｯ）」みたいな顔して**しゃべり始めました。

### 実は、めちゃくちゃ参加者多かった

当日は事前登録もかなり多くて、  
**想定よりずっとたくさんの方が参加してくれました。**

（ログイン者数見た瞬間、「うわ、ちゃんとしゃべらなきゃ…」って背筋伸びた。）

ありがたいプレッシャーでした！

### 印象的だった質問

参加者から飛んできた質問。

「𓏸𓏸プラグインは安全ですか？」

心の声：  
（わぁ…これ、どっちに答えても詰むやつじゃん…！）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201694/d8faf301-2452-40a7-afae-e23e61b86fed.png)


とりあえずニッコリ笑って、  
「安全性については刻一刻と変わっていくので……**僕ならアップデート体制とかを気にしますね！**（無難）」って返しました。
生き延びた。

---

## セキュリティについて伝えたかったこと

ここは割と真面目に。

- セキュリティ対策に「これ一発で完璧！」みたいなものはない。
- **二重三重の対策が必要。めんどくさいけど、それが正義。**

そしてWordPressのフォームに関しても、

- 重要な情報はひとつの場所にまとめるな。
- 本気で守りたいなら、ちゃんとコストをかけよう。

って話をしました。

あと、**「不安だったらプロに頼れ」** っていうのも大事。

---

## 振り返って思ったこと

- 事後アンケートの満足度、そこそこ高かった。  
  （なんか……安心した……）

- パネルディスカッションでも、ちゃんと興味持って聞いてもらえるんだなと発見。

- 次は、セキュリティ以外のテーマでもしゃべってみたいなと思った。

（AIとか？SaaSとか？ なんか面白いやつ！）

- 司会のタニグチさんともう一人のパネリストのウエキさん、さすが慣れてらっしゃるのかとってもやりやすかった！ありがとうございます！

---

## まとめ

というわけで、  
**パネルディスカッションはめちゃくちゃライブ感あるよ**って話でした！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201694/eb825466-172d-479a-a258-dc4d3afea3e4.png)

台本きっちり決めてるイメージあるかもしれないけど、  
**実際はその場の空気でけっこうしゃべってます。**

次回もしウェビナーとか登壇することがあったら、  
「まあ、なんとかなるっしょ」くらいの気持ちで臨んでも大丈夫！

以上、現場からお届けしました〜！

---

今回共催したさくらインターネットさんではユーザーコミュニティを展開されてます。
気になる方は是非ご登録を！

https://support-community.sakura.ad.jp/

今回のウェビナーでもちょろっと紹介しましたが、弊社ではSPIRALというローコード開発プラットフォームを提供してます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201694/b0f54617-ea0d-48b0-82a6-a9dd0b84927d.png)
こちらも気になる方は、無料でいじれちゃうトライアルがありますので、気になる方はいじってみてください！

https://www.pi-pe.co.jp/regist/is?SMPFORM=man-lanerf-2473a633d82734eb22aa64cad426ae23&f000099824=https://www.spiral-platform.co.jp/service/spiralv1/&f000099864=Qiita%E8%A8%98%E4%BA%8B%E7%B5%8C%E7%94%B1%E3%81%AE%E7%94%B3%E3%81%97%E8%BE%BC%E3%81%BF%E3%81%A7%E3%81%99%E3%80%82&sales_flg=2
 
使い方はこちらもご参照を！👇
 
https://knowledge.spirers.jp/
「F#きしょ」ってなる瞬間

 F#を愛用している私ですら「きしょ」ってなります

# 本編
　私が知っているだけ書きました
```fsharp
// 以下はVS2022で動く、1~10の整数が順番に並んだ配列を表示する

// Array.zeroCreate => Array.mapi
printfn "%A" (Array.zeroCreate 10 |> Array.mapi (fun i _ -> 1 + i))

// Array.init
printfn "%A" (Array.init 10 (fun i -> 1 + i))

// Array.collect
printfn "%A" ([|1..10|] |> Array.collect (fun x -> [|x|]))

// コンピューテーション式 シーケンス
printfn "%A" (seq { for i in 1 .. 10 do yield i } |> Array.ofSeq)

// コンピューテーション式 シーケンス 2
printfn "%A" [|for i in 1 .. 10 do yield i|]

// レンジ構文
printfn "%A" [|1..10|]

// レンジ構文 2
printfn "%A" [|1..1..10|]
```

#### 出力
```
[|1; 2; 3; 4; 5; 6; 7; 8; 9; 10|]
[|1; 2; 3; 4; 5; 6; 7; 8; 9; 10|]
[|1; 2; 3; 4; 5; 6; 7; 8; 9; 10|]
[|1; 2; 3; 4; 5; 6; 7; 8; 9; 10|]
[|1; 2; 3; 4; 5; 6; 7; 8; 9; 10|]
[|1; 2; 3; 4; 5; 6; 7; 8; 9; 10|]
```


　一言言います。**「きしょい」**

# 終わりに
　他にもあれば、コメントして教えてください
[PHP] isset・empty・is_null の違いをまとめてみた

# はじめに
PHPをつかっていく中で、配列が空かどうかをチェックする方法としてemptyを使っていましたが、issetやis_nullメソッドが登場する解説もあり、具体的に何がどう違うのかを理解できていないという課題がありました。
この記事では、そもそも null とは何かについ整理し、これらの関数の違いをまとめていきます。

# null とは
**null** とは、「変数やデータに何の値も設定されていない状態」を意味する特別な型・値です。
具体的には以下のようなときに null と判定されます。
・変数に明示的に null を代入した場合
・関数から return; だけで値を返さなかった場合（戻り値が null）
・存在しないオブジェクトのプロパティにアクセスした場合
・存在しない配列のキーにアクセスした場合（未定義のキーの値は null として扱われる）
つまり、変数自体は定義されているが、その中身が空である（存在しない）ことを表します。


## isset()について
```php: 基本構文
isset(mixed $var, mixed ...$vars): bool
```

公式ドキュメントには以下のように解説されています。
> 変数が宣言されていること、そして null とは異なることを検査する

つまり、このメソッドでは、
指定した引数である変数が定義されていて、null でない場合に true を返す
変数が未定義 または null の場合に false を返す
という動作をします。

isset() は null のみを「値なし」とみなし、null 以外の false, 0, '', [] などは 「値あり」とみなします。
これは empty との大きな違いです。


## empty() について
```php: 基本構文
empty(mixed $var): bool
```

公式ドキュメントには以下のように解説されています。
> 変数が空であるかどうかを検査します。 変数が空であるとみなされるのは、変数が存在しない場合や 変数の値が false に等しい場合です。

empty() は、PHPで「変数が空であるかどうか」を調べるための関数です。
具体的には、
・""（空文字列）
・0（整数 0）
・"0"（文字列の 0）
・0.0（小数 0）
・false（ブール値 false）
・[]（空配列）
・null（null値）、未定義の変数（存在しない変数でもOK）
が**空**に該当します。

empty()がisset()と異なっている点は、変数が未定義でもエラーを出さずに false として扱えること、
null だけでなく、0 や '' なども「空」とみなす点です。

値が何か入っているかどうかをざっくり知りたいときに使用するのに適していると言えるでしょう。


## is_null について
```php: 基本構文
is_null(mixed $value): bool
```

公式ドキュメントには以下のように解説されています。
>指定した変数が null かどうかを調べます。

つまり、単に変数の値が null かどうかを調べるための関数です。
上記の2つの関数と異なる点は、変数が未定義の場合に Warning が発生すること点です。


# まとめ
守備範囲の広さ順でいうと、「空であるか」をざっくり調べるempty()、「定義されていて null でないか」を調べる isset()、「値が null かどうか」を正確に調べる is_null() と言えるでしょう。
これらを目的に応じて使い分けられるようになっていきましょう！

最後までお読みいただき、ありがとうございました。


# 参考URL
https://www.php.net/manual/ja/function.isset.php
https://qiita.com/YutaManaka/items/94a6c4a1d19d88ce2e3a
https://frog-song.hatenablog.com/entry/2021/12/04/013245
https://www.rstone-jp.com/column/139760/
https://www.w3schools.com/php/func_var_empty.asp
https://techplay.jp/column/1813
https://www.sejuku.net/blog/22964
【UiPath】【PiP】クリップボード共有課題の回避実装サンプル

# はじめに

- 本記事は、PiPモードで実行した際のクリップボード共有課題の回避実装サンプルを扱います。
- 記事の内容は、個人の見解または確認結果であり、UiPath の公式見解ではありません。
- 製品仕様や参考画像は 25.0.161 バージョンのもので構成しています。

# クリップボード共有課題

https://docs.uipath.com/ja/assistant/standalone/2023.10/user-guide/pip-child-session#known-issues-and-limitations

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/be7765da-cb15-4ac3-97bd-eb31c2333e9f.png)

::: note warn
***クリップボードは PiP セッションとメイン セッション間で共有されます。***
***※PiPの種類は「新しいセッション（子セッション）」と「新しいデスクトップ（仮想デスクトップ）」の両方で発生します。***


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/2017facd-a88d-4ef4-ad46-03a9817c368e.png)

ロボット内でクリップボードの操作をするケースはあまりないとおもいますが、セレクタをうまく認識しないフィールドへの値貼り付け等で利用することはあったりします。ロボの実装をよく知らない利用者の方がPiP実行しながら仕事した場合、困ったことが起きそうですよね( ﾟДﾟ) gkbr
:::

# 回避実装サンプル

たとえば、
***「クリップボードに設定」で値Xをコピー***し、
***「キーボードショートカット（Ctrl+V）」で値を貼り付ける***実装があった場合、
次の様に回避実装をおこないます↓↓↓

***「代入」でクリップボードの中身を退避***
左辺：退避用オブジェクト（System.Object型）　右辺：ClipboardX.ObjectValue

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/2a7e6d1a-85f1-41f6-b31d-a0ef1d977c80.png)
→
***「クリップボードに設定」で値Xをコピー***
→
***「キーボードショートカット（Ctrl+V）」で値を貼り付ける***
→
***「代入」でクリップボードの中身を戻す***
左辺：ClipboardX.ObjectValue　右辺：退避用オブジェクト（System.Object型）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/4e5f6d95-1d81-4b3f-9fcd-d90f851e1307.png)

::: note
（ClipboardX.StringValue で値をログした際の出力例）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/5803bb97-5893-4893-b5b3-d55a054c226e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/1f87b765-96d9-4e07-9387-8ed8ce821e93.png)
:::

::: note warn
空振り対策でリトライスコープを入れる場合、クリップボードの退避・戻しの挿入位置にご注意ください。
※退避と戻しの間隔が開いてしまうと意図しないコピー発生リスクが上がってしまうため

【 ×：良くない例 】
「代入」：クリップボード退避
　　「リトライスコープ」
　　　「クリップボードの設定」
　　　「キーボードショートカット（貼り付け）」
「代入」：クリップボード戻し

【 〇：良い例 】
「リトライスコープ」
　　「代入」：クリップボード退避
　　「クリップボードの設定」
　　「キーボードショートカット（貼り付け）」
　　「代入」：クリップボード戻し
:::

# さいごに
いかがでしたでしょうか。
値設定＆値利用の直前・直後に「代入」アクティビティを挿入してクリップボードの中身を退避・戻すだけです！
UiPathのPiPは、クローンをつくるものではなく、Microsoftの”子セッション”という技術をもちいて疑似的にロボットの実行環境をもう一つ作っています。
https://learn.microsoft.com/ja-jp/windows/win32/termserv/child-sessions
このため、メインセッション（親セッション）と子セッションでリソースを共有する部分も多く、資格情報を求めずに自動ログオンからロボット実行ができるメリットなどありますが、今回の様にセッション毎にリソース分けられずデメリットになるケースもでてきます。
コンマ数秒に手元のコピペが被るケースはそれほどないとおもいますので、「PiP × クリップボード」で困っている方がいたら本記事を教えてあげていただけますと幸いです(・ω・)ノ
Google Agile Essentials を受講しcredlyのバッジを得た。

# Google Agile Essentials を受講
https://www.coursera.org/learn/google-agile-essentials?action=enroll

# 動画→問題
英語の動画、英語の問題。問題の正解率を一定まで上げないと、完了のステータスにならない。問題は空き時間にスマホで、携帯ゲームをするような感覚で、動画は歩きながら聴くだけなど、気軽に進められた。

# 得たもの
ふわっとした概念になりがちなアジャイル、スクラム、リーン、について、具体的な理解を得られた。
自分の組織に当てはめながら、考える時間は有意義だった。

# AWS試験でお馴染み、credlyのバッジを獲得

予想外にもらえた。ラッキー。
![スクリーンショット 2025-05-07 16.31.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780693/b28d2ad0-7ad1-4e14-8ce6-ea52e57361d4.png)
自分用まとめメモ(openAI API価格最新版

# OpenAI Chat API モデル料金比較表（2025年5月時点）

| モデル名                  | 入力料金（1K tokens） | 出力料金（1K tokens） | 備考                           |
|---------------------------|------------------------|------------------------|--------------------------------|
| `gpt-3.5-turbo`           | $0.0005                | $0.0015                | 最安・PoC・趣味用途向き         |
| `gpt-3.5-turbo-0125`      | $0.0005                | $0.0015                | 現行安定バージョン             |
| `gpt-3.5-turbo-1106`      | $0.0005                | $0.0015                | 旧バージョン                   |
| `gpt-3.5-turbo-16k`       | $0.003                 | $0.004                 | コンテキスト長16K              |
| `gpt-4.0`                 | $0.03                  | $0.06                  | 高精度・コスト高               |
| `gpt-4.0-mini`            | $0.01                  | $0.03                  | バランス型・速度◎             |
| `gpt-4.0-mini-long`       | $0.01                  | $0.03                  | コンテキスト長対応             |
| `gpt-4.5-preview`         | $0.01                  | $0.03                  | 最先端・Preview版              |

> 💡 補足：
> - `1K tokens` は約750語（日本語で500〜600文字相当）です。
> - モデル名に日付（例：`-0125`）があるものはバージョン識別子。
> - 実際の請求は OpenAI [Pricing](https://openai.com/pricing) ページで要確認。

でこれはGPTちゃんが吐き出してくれただけなのでキチンとソース見ようね
【Reactアプリ100本ノック】08 Calendar

## はじめに
ゆかっしゅです。
2021年に事務職からデザイナー/コーダーにジョブチェンジをし、現在はフロントエンドエンジニアにスキルアップするべく、モダンフロントエンドを学習しています。

ReactやTypeScriptの基礎学習は終了したのに、なかなか0から自分だけでアプリを作れないので手を動かすべく「Reactアプリ100本ノック」 に挑戦してみようと思います。

https://qiita.com/Sicut_study/items/3bd13a266feade56a4d0

## Reactアプリ100本ノックルール
- 主要なライブラリやフレームワークはReactである必要がありますが、その他のツールやライブラリ（例: Redux, Next.js, Styled Componentsなど）を組み合わせて使用することは自由
- TypeScriptを利用する
- 要件をみたせばデザインなどは自由


## 08. Calendar
![スクリーンショット 2025-05-07 153701.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4068307/de27b6c2-b7bd-42c0-a2df-0386c3d04ae7.png)

## 問題
カレンダーアプリを作成します
予定をカレンダーに登録できるようにします

## 目的
以前作成したTODOアプリの派生としてカレンダーに予定を登録できるようにします
またグリッドを使ってカレンダーを表現します

## 達成条件
- カレンダーが表示されている
- 土日は赤色で表示する
- 前の月、次の月をページネーションできる
- 日付に対して予定を複数追加できる
- 予定の編集削除ができる

## 実際に解いてみた
### 利用技術
React(19.0.0)
TypeScript(5.0)
Next.js(15.3.1)
Tailwindcss(4.0)
jotai(2.12.3)
date-fns(4.1.0)
@holiday-jp/holiday_jp(2.4.0)
Vercel

解答時間:3時間半

実はカレンダースケジュールアプリは自分でも作ったことがあるのですが、
その時はJSとFullCalendarを使用して作成したので、今回はdate-fnsを使用して作成してみました。
date-fnsだけでは日本の祝日がわからないので、@holiday-jp/holiday_jpを使用しました。
@holiday-jp/holiday_jpはとても使いやすかったです。


### リンク
https://react-app-100.vercel.app/
[Thoughtspot]ピボットテーブルのブレンド軸を試してみた

## はじめに
Thoughtspotの10.8.0.clで「ピボットテーブルのブレンド軸」という機能が加わり、ピボットテーブル形式のチャートを使うと「値（values）」というものが列や行に設定できるようになりました。
これを設定するとどうピボットの表示が変わるのか、試してみたいと思います。

## ピボットでのグラフ構成と実際の見え方
今回は新ピボットで試します。
この構成をしたらこういう見え方になるよ、という感じで画像を張り付けていきます。
それぞれ「値（values）」の設定位置と、ピボット上での表示位置を見比べてもらえたらと思います。

ピボットの見せ方のバリエーションが広がりますね！

### 通常ver
![画像1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1658354/7a0133ce-2b72-4e6a-a5ce-d4617c9603f3.png)

### 列の最下層ver
![画像2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1658354/49e39c78-83f8-430c-9427-8cc9af7d7912.png)

### 列の間ver
![画像3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1658354/0d4c901f-0116-4280-920f-a3dd14181ed7.png)

### 列の最上層ver
![画像4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1658354/12059556-8cf8-42c8-9116-a2f16826482b.png)


## 旧ピボット（クラシック）の場合
旧ピボットの場合もだいたい同じですが、列のところに配置すると折り畳みができるようになるみたいです（ただ折り畳んだところで……ではあるのですが）。
![画像5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1658354/5279e8d3-8791-46fd-873e-4e8dd32d42b0.png)

展開要素が増えるからなのか、今までよりは表示速度が少し遅くなる印象はあります。
使わないのであれば「値」は **「未使用項目」** にもっていってしまうのが無難な気がします。

また旧ピボット（クラシック）では値を列で表示するか行で表示するかの設定ができましたが、「値」がグラフ上でアクティブになっているとこの設定が非活性になって利用できません。「値」を未使用項目にすると元通り使えるようになります。

## おわりに
使いどころがわからなかったので紹介しなかったですが、新ピボットの「Slice with color」のところに配置してもなかなか面白い見せ方になるので、みなさん好きに試してみてくだしあ。
使いどころ見つけた方のレポ待ってます。
2025年3-4月の学習記録

## WordPress

実務で「WordPress **.com** 」（≠ WordPress）に初めて触れた。
アカウントの管理方法・UIにクセがあり、何度も原因不明のエラーに襲われた。今回はお客様からの希望だったので「.com」を使うよりなかったが、できれば今後は使いたくない。
個別のサーバーに「WordPress」を別々にインストールするほうが、スムーズに管理できると思う。

＜.com 限定の注意点＞
* デフォルトで入っている「**Jetpack**」プラグインが、勝手にソーシャルボタンや関連記事を追加表示する場合がある。OFFに設定する必要あり。

＜WP全般の注意点＞
* 移行前、移行先のプラグインを揃えてから Export / Import したほうがよい。
（Migration でデータ移行したとき、プラグインは「置換」ではなく「足し算」になる。）
* プラグインを無効化してから Export / Import することで、エラーを回避できる場合もある。

## CSS

相変わらず、CSS は仕様変化の波が激しい。

新しい機能を解説してくれる技術ブログ・𝕏アカウントが数多くあり、ありがたい。ありがたい、のだが...。ごく一部のブラウザでしかサポートされていない（`Limited availability`）本当に**最先端**の機能を紹介している場合が多い。勉強したところで結局、実務で使うのはかなり先（ものによっては数年後？）になってしまう。

標準的な全ブラウザで使用可能な機能（`Baseline`）にしぼって、新しい機能を紹介してくれる日本語サイトはないものだろうか。


[#1]

実務でモーダルを作る機会があったので、「top-layer」という新しい機能を使ってみた。

https://coliss.com/articles/build-websites/operation/css/what-is-the-top-layer.html

過去にモーダルを作ったとき、ハンバーガーメニューと `z-index` が干渉して再修正が必要なことがあった。「top-layer」を使えば、そうした「思わぬバグ」「再修正」は減らせるだろう。

新しい CSS を使うのは「カッコイイから」ではない。
新しい CSS のほうが、後々思わぬバグが発生することを防げる、優秀な設定方法であることが多いのだ。

[#2]

SCSS変数（`$example`）と、CSS変数（`--example`）の違い。
　→　CSS変数は、ネストの内側からネストの外側を上書きできる。
　　　SCSS変数は、スコープ制限が厳格で、内側から外側を上書きできない。

従って、基本クラスから派生した modifier クラスを（ネストの内側に）作りたい場合、SCSS変数よりもCSS変数を使うほうがスムーズに管理できると思われる。

```scss
.baseClass {
  --color: red; // 派生クラスで上書きしたい箇所だけ変数として定義しておくと、コードの意図が分かりやすくなる
  --fontSize: 14px;

  color: var(--color);
  font-size: var(--fontSize);
  text-decoration: underline;

  &--modifierClass {
      --color: blue; // ネストの内側からでも上書きできる
      --fontSize: 20px;
  }
}
```

[#3]
`@layer` や `@scope` など、画期的な機能が続々と標準ブラウザで使用できるようになっている。
`@layer` は使い道がピンと来なかったが、`@scope` は実務ですぐに活かせそうだ。近いうちに使ってみたい。

## mix

弊社は、フロントエンジニアの作業環境で mix を使って SCSS などのコンパイルを行っている。
大量の SCSS・JS を常に watch しており、数行のSCSSを修正するたびに、それらを全てコンパイルし直している。そのため歴史の長い案件では、**数行のSCSSを修正するたびに20秒程度（！）の待ち時間が発生することもある**。
長すぎる...。作業が分断されて、なんの作業をしたかったのか段々忘れてしまう。

先日、新しい案件で一から環境構築をする機会があった。
**ライブラリを（npm で管理せず）CDN で読み込む**ことで、mix のコンパイルの対象となる SCSS や JS の量を極力減らすようにした。

Bootstrap ライブラリを CDN で読み込んでいいものかどうかは悩んだ。というのも、Bootstrap を SCSS としてワークディレクトリ内に用意しておくと、変数（`$hogehoge`）の上書きによるカスタマイズが容易になるからだ。
しかし、SCSS の変数機能を利用しなくとも、Bootstrap のデフォルト設定を（素のCSSで）上書きすることはできる。やや愚直な設定方法になってしまうが、コンパイル時間が短く済むメリットのほうが大きいと判断し、こちらの方法を採用した。

## VSCode

* 小ネタ： `// MARK:` とコメントすると、ミニマップでコメントした位置が強調表示できる。`// TODO:` よりも便利そうだ。

## 見積もり

https://qiita.com/wannabehime/items/d82cae8a38991bf6c00e

今の会社に入って1年半経つが、未だに見積もりをどうすればいいのか分からない。
上記の記事を読む。
「２時間刻み」で考えればよい、というのをひとまず取り入れたい。
【Android /Kotlin】WebViewでblobURLをダウンロードできるようにする

# はじめに

AndroidのWebViewでblobURLをダウンロードできるようにする方法について解説。

1. JavaScriptInterface.ktを作成し、Android側のダウンロード時の処理を記述
2. download_hander.jsを作成し、javascript側の処理を記述
3. WebView使用時に、上記2つをセット

という流れで作成を行う。

# 1. JavaScriptInterfaceの作成

```JavaScriptInterface.kt
class JavaScriptInterface(private val context: Context) {
    @JavascriptInterface
    fun base64ToFile(base64: String, mimeType: String, fileName: String) {
        Log.d("base64ToFile", "base64:$base64")

        // Base64ヘッダーを除去
        val pureBase64 = base64.substringAfter(",")

        // バイナリにデコード
        val byteArray = Base64.decode(pureBase64, Base64.DEFAULT)

        val contentValues = ContentValues().apply {
            put(MediaStore.Downloads.DISPLAY_NAME, fileName)
            put(MediaStore.Downloads.MIME_TYPE, mimeType)
            put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
            put(MediaStore.Downloads.IS_PENDING, 1)
        }

        val resolver = context.contentResolver
        val uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)

        if (uri != null) {
            resolver.openOutputStream(uri)?.use { outputStream ->
                outputStream.write(byteArray)
            }

            // IS_PENDING → 0 にして公開状態にする
            contentValues.clear()
            contentValues.put(MediaStore.Images.Media.IS_PENDING, 0)
            resolver.update(uri, contentValues, null, null)
        }
    }
}
```

2. download_hander.jsの作成

下記に保存

```
app/
└─ src/
   └─ main/
      └─ assets/
         └─ js/
            └─ download_handler.js
```

コードは下記

```download_handler.js
(function(blobUrl) {
    try {
        var anchors = document.querySelectorAll('a[href="' + blobUrl + '"]');
        var fileName = "file_" + Date.now() + ".bin";

        if (anchors.length > 0) {
            var downloadAttr = anchors[0].getAttribute("download");
            if (downloadAttr) {
                fileName = downloadAttr;
            }
        }

        fetch(blobUrl)
            .then(response => {
                const contentType = response.headers.get("Content-Type") || "application/octet-stream";
                return response.blob().then(blob => ({ blob, contentType }));
            })
            .then(({ blob, contentType }) => {
                var reader = new FileReader();
                reader.onloadend = function() {
                    android.base64ToFile(reader.result, contentType, fileName);
                };
                reader.readAsDataURL(blob);
            })
            .catch(error => {
                console.error("fetchエラー:", error);
            });
    } catch (e) {
        console.error("JS実行時エラー:", e);
    }
})
```

最後に、`download_hander.js`と`JavaScriptInterface.kt`をWebViewにセットすれば良い。

WebView使用時に上記2つをセットするコードについては、[こちら](https://note.com/naka_inc/n/n3a27a58d1f25)に記述。

https://note.com/naka_inc/n/n3a27a58d1f25