OmniAICreator/Qiita-1.07M huggingface dataset:
📄 日本語OCR革命！🚀 AI「YomiToku」の実力と活用法を徹底解説 🤖📡

# 🎌 **日本語特化AI OCR「YomiToku」の詳細解説と活用法** 📄✨

近年、文書デジタル化の需要が高まる中、OCR（Optical Character Recognition：光学文字認識）技術の進化は目覚ましいものがあります。しかし、多くのOCRエンジンは日本語に最適化されておらず、**縦書きや複雑なレイアウトに対応できない**ことが課題でした。💡

そんな中、日本語文書解析に特化したAI OCRエンジン **「YomiToku」** が登場しました！🚀 本記事では、**YomiTokuの特徴、セットアップ、実装方法、具体的な活用例**について詳しく解説していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917980/9ed77e47-a97b-47a7-bef4-9b3cc2f488ce.png)

---

## **📌 YomiTokuとは？** 🤖

**YomiToku** は、日本語の文書画像を解析するために開発された**AIドキュメント解析エンジン**です。日本語に特化したOCR機能とレイアウト解析機能を備え、**テキストや表、図を高精度で認識・抽出**することができます。📝✨

### **🎯 主な特徴**
✅ **日本語に最適化**（7,000文字以上対応、縦書き解析可能）
✅ **4つの独立したAIモデル**（文字認識、レイアウト解析、表検出、構造解析）
✅ **高精度な文書解析**（読み順推定、レイアウト保持）
✅ **多様な出力フォーマット対応**（HTML, Markdown, JSON, CSV）
✅ **GPU対応で高速処理**（VRAM 8GBでも快適に動作）

YomiTokuは、**Hugging Face** の事前学習済みモデルを利用し、高速かつ高精度な推論を実現しています。📡

---

## **🛠️ YomiTokuのインストールとセットアップ**

YomiTokuはPython 3.10以上が必要です。以下の手順で簡単にセットアップできます。

### **1️⃣ インストール**
```bash
pip install yomitoku
```

### **2️⃣ GPU環境でのセットアップ（オプション）**
GPU環境で動作させる場合、`onnxruntime` を追加インストールします。

```bash
pip install onnxruntime-gpu
```

または、Docker環境でセットアップすることも可能です。

```bash
docker build -t yomitoku .
docker run -it --gpus all -v $(pwd):/workspace --name yomitoku yomitoku /bin/bash
```

---

## **📄 YomiTokuの基本的な使い方**

### **1️⃣ CLI（コマンドライン）での使用**

画像やPDFをOCR解析するには、以下のコマンドを実行します。

```bash
yomitoku ./documents/sample.pdf -o results -v
```

**📌 コマンドオプションの説明**
- `./documents/sample.pdf`：解析対象の画像またはPDFファイル
- `-o results`：出力フォルダの指定
- `-v`：解析結果の可視化

### **2️⃣ Pythonスクリプトでの使用**

```python
import cv2
from yomitoku import DocumentAnalyzer
from yomitoku.data.functions import load_pdf

# サンプル文書のパス
PATH_IMAGE = "sample.pdf"

# YomiTokuのインスタンスを作成
doc_analyzer = DocumentAnalyzer(visualize=True, device="cuda")

# PDFを画像としてロード
images = load_pdf(PATH_IMAGE)

for i, img in enumerate(images):
    results, ocr_vis, layout_vis = doc_analyzer(img)
    results.to_html(f"output_{i}.html", img=img)
    cv2.imwrite(f"output_ocr_{i}.jpg", ocr_vis)
    cv2.imwrite(f"output_layout_{i}.jpg", layout_vis)
```

このスクリプトを実行すると、以下のような処理が行われます。

✅ **OCR解析結果のHTML出力**
✅ **文字認識結果の画像出力**
✅ **レイアウト解析結果の画像出力**

---

## **📊 OCR結果のサンプル出力**

### **入力画像（例）**
📄 `sample.pdf`（新聞記事の一部）

### **出力データ（JSON形式）**
```json
{
  "text": "AI技術の進化と未来について",
  "layout": [
    { "type": "title", "text": "AI技術の進化と未来について" },
    { "type": "paragraph", "text": "近年、AI技術は急速に発展し..." }
  ],
  "tables": [],
  "figures": []
}
```

### **出力画像（OCR結果の可視化）**
🖼️ `output_ocr_0.jpg`（文字認識結果）
🖼️ `output_layout_0.jpg`（レイアウト解析結果）

---

## **📚 応用例：YomiTokuの活用シーン**

### **1️⃣ 歴史文書のデジタル化**
古い文献や新聞記事を電子化し、検索可能なデータに変換。

### **2️⃣ 業務効率化（契約書・請求書の解析）**
契約書や請求書から重要な情報を抽出し、データベース化。

### **3️⃣ AIエージェントとの連携**
YomiTokuでOCR解析した結果を、AIチャットボットや自動翻訳システムに統合。

---

## **🔍 まとめ**

🎯 **YomiTokuは日本語に特化した高精度OCRエンジンであり、文書のデジタル化やデータ抽出に最適！**

✅ **多様なレイアウト解析に対応（縦書き、表、図）**
✅ **CLIとPythonライブラリの両方で簡単に使用可能**
✅ **GPU最適化で高速処理が可能**

日本語OCRでお困りの方は、ぜひ**YomiToku**を試してみてください！🚀

**💬 あなたの活用アイデアや感想をコメントで教えてください！😊**
VBAでクエリの中身を確認、修正するためのベストプラクティス？



今回はAccess VBAで開発を行っている中で、よく使っているクエリの中身を確認する方法をご紹介します。


## はじめに

クエリの中身をデバッグ中、ローカルウィンドウ等で確認することがありますよね。

しかしクエリが長い場合は表示しきれず切れてしまい、全量を確認することができずに困ってしまうことがありました。


全量を確認できないと、クエリのエラーが起こっている場合にとても困りますし、クエリに変数を使っている場合は変数を置換してあげなくてはならず、デバッグのたびにストレスが溜まります。

これから紹介する方法でだいぶデバッグが楽になったので、もしお困りでしたら使ってみてください。


## 方法


方法は簡単です。

#### ①確認用のクエリを作成する

中身は何でもOKなので(後からすべて置換するため)、クエリを確認するためのクエリを作成してください。

今回は**viewQuery**という名前のクエリを作成しました。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3069823/a5ae910f-8004-400b-943e-a7c8656cf091.png)




#### ②プロシージャにコードを記述する

クエリを書き換えるためのコードは以下だけになりますので、ある程度分かる方はコードだけご利用ください。

```vb
    'デバッグ用(クエリ中身確認)
    db.QueryDefs("viewQuery").SQL = query
```

全体はこちらとなっております。



```vb
Sub QiitaTest()

    '変数の宣言
    Dim db As DAO.Database
    Dim query As String
    Dim fruits As String
    
    
    'カレントデータベースを取得する
    Set db = CurrentDb

    fruits = "イチゴ"
    
    query = "SELECT 果物 FROM 果物マスタ WHERE " & fruits
    
    
    'デバッグ用(クエリ中身確認)
    '※括弧の中に①で準備したクエリ名を記述します※
    db.QueryDefs("viewQuery").SQL = query
    

    db.Close
    
End Sub
```


query部分には確認したいクエリをお好きなように記述してください。

右辺に直接クエリを書いても問題ないですが、コードを使いまわしたいため、私は変数に格納したクエリを使用しています。


## 実行する

実行してみましょう。

実行したら、Accessの方に戻って①のクエリをSQLビューで開きます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3069823/09759de7-76be-4299-bf2d-a5db2d0e0549.png)

きちんとクエリが取得できていることが確認できました🎉

このまま、Access側でクエリを実行してデバッグすることで、エラー原因を早く突き止めることができます。

一つデバッグ用のクエリを作っておくと、使い回しができるので便利ですよ。


## おわりに

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

これがベストプラクティスかは微妙なところですが…

個人的によく使っているデバッグ方法をご紹介でした！

この方法の他に良いデバッグ方法があれば教えてください。

お役に立てれば幸いです。
今更聞けないLightGBMのハイパーパラメータの基本をSonnet3.7に聞いてみた

# はじめに
こんにちわ。今回はばんえい競馬予想AIモデルを作る上でSonnet3.7に聞いたLightGBMのハイパーパラメータの意味について軽くまとめます。今更かよ！？な内容なので生暖かい目でご覧ください。

## 各ハイパーパラメータの説明
### learning_rate: 0.032...

意味: 学習率。AIがどのくらい積極的に学習するか
イメージ: 学校での勉強ペース。ゆっくり確実に(小さい値)か、速く大胆に(大きい値)か
効果: 小さいと精度は上がりやすいが学習に時間がかかる。大きいと速いが粗くなりがち


### n_estimators: 2559

意味: 決定木の数。いくつの「判断ルール」を組み合わせるか
イメージ: 選挙での投票者数。多いほど総意は正確になるが、時間がかかる
効果: 多いほど複雑なパターンを学習できるが、過学習のリスクも


### num_leaves: 36

意味: 木の葉の数。1つの判断ルールの中での分岐数
イメージ: 質問の細かさ。「馬の体重は何kg以上？」という質問をいくつの選択肢に分けるか
効果: 多いほど細かく分類できるが、ノイズも拾いやすい


### max_depth: 4

意味: 木の最大深さ。判断の階層の数
イメージ: 「はい/いいえ」の連続質問の最大数
効果: 深いほど複雑な関係性を学習できるが、過学習の危険も


### min_child_samples: 62

意味: 葉ノードの最小サンプル数。判断に必要な最低データ量
イメージ: 結論を出すのに必要な最低限の事例数
効果: 大きいと安定するが細かいパターンを見逃す。小さいと過学習しやすい
(葉ノード：決定木の一番端にある最終的な判断ポイント）

### subsample: 0.603...

意味: データのサブサンプリング率。学習に使うデータの割合
イメージ: 全国調査ではなく一部地域だけの調査で傾向を把握する
効果: 1未満にすると過学習を防げるが、情報損失のリスクも


### colsample_bytree: 0.964...

意味: 特徴量のサンプリング率。判断に使う情報の割合
イメージ: 馬の全情報から「体重」「騎手」など一部だけに注目する
効果: 木ごとに異なる特徴量を使うことで、多様な視点からの判断になる


### reg_alpha: 7.488...

意味: L1正則化。モデルの複雑さを制限
イメージ: 余計なルールを削る「整理整頓係」
効果: 不要な特徴量の影響を0にして、シンプルさを保つ


### reg_lambda: 1.168...

意味: L2正則化。モデルの極端さを抑制
イメージ: 極端な判断を和らげる「バランサー」
効果: 特徴量の極端な重み付けを避け、安定した予測に

# L1正則化とL2正則化について

### L1正則化（Lasso回帰）
L1正則化は、モデルの複雑さを抑えるために絶対値を使ったペナルティを加える

特徴と効果：
特徴量の選択機能: 重要でない特徴量の重みを完全に0にできる（スパース性）
数式: コスト関数 + λ × |重み|の合計
視覚的イメージ: ダイヤモンド型の制約領域を作り、コーナー（軸上）で解が得られやすい
用途: 多くの特徴量から重要なものだけを自動選択したい場合に有効

### L2正則化（Ridge回帰）
L2正則化は、モデルの複雑さを抑えるために二乗を使ったペナルティを加える手法です。

特徴と効果：
重みの縮小: すべての特徴量の重みを小さくしますが、完全に0にはしません
数式: コスト関数 + λ × (重み)²の合計
視覚的イメージ: 円形（楕円）の制約領域を作り、すべての方向に均等にペナルティ
用途: 多重共線性がある場合や、過学習を防ぎたい場合に有効

違いの簡単なまとめ

L1: 「不要な特徴量を捨てる」効果→モデルを単純化したい時
L2: 「すべての特徴量を残しつつ影響を小さくする」効果→バランスよく過学習を防ぎたい時

## つまり特徴量が多い場合はL1、相関の高い特徴量が多い場合はL2が良いってことっぽい。

# おわりに
### いかがでしたか？
正直今まで数字が小さい方がカッコよくて強いくらいのミリしらAI使いだったので非常に勉強になりました。
計算結果待ちの間もログを見ながらニヤニヤできるようになったり、処理の負荷の大小をイメージしやすくなりました。

ばんえい競馬AI予想完成に向けてこれからもLightGBMと仲良くしていこうと思います。
垂直農法：持続可能な未来に向けた農業の革命

導入
急速な都市化、気候変動、そして世界人口の増加の時代において、従来の農法は大きな課題に直面しています。革新的な農業手法である垂直農法は、持続可能で効率的なソリューションを提供します。垂直農法は、テクノロジー、自動化、制御された環境を活用することで、資源の消費を最小限に抑えながら作物の収穫量を最大化します。この記事では、垂直農法の基礎、その利点、課題、そしてそれを可能にするテクノロジーについて説明し、その応用に関心のあるエンジニアやテクノロジー愛好家の要望に応えます。
垂直農法とは何ですか?
垂直農法とは、多くの場合、制御された屋内環境内で、垂直に積み重ねられた層または傾斜した表面で作物を栽培する方法です。従来の農法とは異なり、広大な土地や季節の変化に依存しません。代わりに、水耕栽培、空中栽培、アクアポニックスなどの高度な技術を統合して、最適な栽培条件を提供します。
垂直農法の主要技術
1.	水耕栽培– 栄養豊富な水を使って植物に栄養を与える、土壌を使わない栽培方法。エンジニアは、水と栄養素の使用を最適化するために閉ループ システムを設計します。
2.	エアロポニックス– 植物の根を空中に浮かせ、霧状の噴霧を通して栄養分を摂取しながら生育する技術。この方法では、従来の農法よりも最大 90% 多くの水を節約できます。
3.	アクアポニックス– 魚の養殖と植物栽培の持続可能な統合。魚の排泄物が植物に必須の栄養素を提供します。
4.	LED 照明- 特定の波長に合わせた人工照明は光合成を促進し、植物の成長を最大限に高めます。
5.	自動気候制御- IoT センサーと AI 駆動型システムが温度、湿度、CO₂ レベルを制御し、安定した作物生産を保証します。
詳細はこちら: https://www.marketresearchfuture.com/reports/vertical-farming-market-2779
垂直農法の利点
1. スペース効率
これらの農場では、作物を垂直に積み重ねることで、従来の農業に比べて必要な土地が大幅に少なくなり、都市環境に最適です。
2. 節水
水耕栽培や空中栽培などの高度な灌漑技術では、従来の農業に比べて水の使用量が最大 95% 削減されます。
3. 一年中作物を生産
制御された環境により、気象条件への依存がなくなり、継続的で高収量の農業が可能になります。
4. 農薬使用量の削減
屋内農業では害虫や病気への曝露が最小限に抑えられ、化学農薬の必要性が減るか、あるいはなくなる。
5. 地域に密着した食料生産
垂直農場は都市中心部に設置することができ、食品流通に伴う輸送コストと炭素排出量を削減します。
課題と検討事項
垂直農法には利点があるものの、いくつかの課題に直面しています。
1.	初期コストが高い– 垂直農場を立ち上げるには、技術、インフラ、エネルギーへの多額の投資が必要です。
2.	エネルギー消費– LED 照明と気候制御システムには大量のエネルギーが必要なので、持続可能性が重要な懸念事項となります。
3.	技術的専門知識- エンジニアと農業専門家が協力して、栽培条件と運用効率を最適化する必要があります。
無料のサンプルレポートを入手: https://www.marketresearchfuture.com/sample_request/2779
垂直農法におけるエンジニアリングの応用
エンジニアは、自動化、AI 駆動型分析、IoT ベースの監視システムを通じて垂直農法を最適化する上で重要な役割を果たします。主な分野は次のとおりです。
•	ロボットによる収穫– 自動化システムにより人件費が削減され、効率が向上します。
•	AI を活用した成長最適化– 機械学習モデルが植物の成長パターンを分析し、環境パラメータを最適化します。
•	再生可能エネルギーの統合- 太陽光と風力エネルギーのソリューションにより、垂直農法の持続可能性を高めることができます。
大規模言語モデル（LLM）ってなんだ？

## はじめに
近年、AI関連の技術が急速に進化する中で、「大規模言語モデル（LLM）」という言葉を目にする機会が増えています。しかし、実際にはその意味や仕組みを理解しないまま、なんとなく知った気になってしまうことも多いのではないでしょうか。

そこで、自分（自分と同じように「大規模言語モデル（LLM）」について気になっている方々）が理解して言語化して説明できるようにするために、この記事を作成しました。

## 大規模言語モデル（LLM）とは
この内容については、[大規模言語モデル（LLM）とは](https://www.ibm.com/jp-ja/think/topics/large-language-models)で以下のように説明されています。

> 大量のデータを使ってトレーニングされた基盤モデルのカテゴリーであり、自然言語やその他のコンテンツを理解および生成し、幅広いタスクを実行することができます。

要するに、大規模言語モデル（LLM）とは、AIモデルのカテゴリー名で、言語モデルの学習データセットがより大規模なものを指すようです。
なんとなくそんな気はしていたものの、他のAIモデルと何が違うのかがはっきりしていませんでした。
代表的な例としては、「ChatGPT」と「Gemini」があげられます。
## 学習と技術
LLMは以下のような技術、学習手法を用いて作成されています。
### 技術
- Transformer モデル
LLMの基盤となっている、Transformer モデルと呼ばれるモデル構造です。
これは、従来の畳み込みニューラルネットワーク（CNN）と異なり、自己注意機構（Self-Attention Mechanism）を用いて、文中の単語同士の関係性を効率よく学習します。

- ファインチューニング
大規模言語モデルは、プレトレーニング（事前学習）とファインチューニングの2段階の学習プロセスを経ています。
プレトレーニングでは、一般的なテキストデータを用いて、言語の基本的なルールや知識を学習します。
その後、特定のタスクに合わせたファインチューニングを行い、モデルの性能を高めています。

### 学習の仕組み
1. プレトレーニング（事前学習）
    -  インターネットなど、多様な情報源からテキストデータを収集します。
    -  文章の一部を入力として与え、その続きに来る単語を予測する形式で進めます。
        -  例：「今日は天気が良いので、」→「散歩に行きます。」
        -  教師あり学習が用いられ、正解データ（次の単語）は元のテキストから得られます。
        -  これにより、ラベル付けが不要で、膨大なデータを効率的に活用できます。
2. ファインチューニング
    - プレトレーニングにより、言語の一般的なパターンや知識を学んでいる状態のものをベースにします。
    - 特定のタスクやドメインに関連したデータを準備します。
    - 教師あり学習を行います。準備したデータに対してモデルが学習し、タスクに特化したパラメータを調整します。

これらの過程を通過したモデルが最適化（圧縮や軽量化）、インターフェースの作成（APIの設計）などを経て私たちのもとにサービスとして提供されるようです。

## まとめ
本記事では、LLMの基本的な意味や仕組みを簡単に説明しました。

LLMの仕組みや活用法について理解を深めることで、今後のAI技術の進展に自分自身がより深く関わり、実際に活用できる場面を増やしていきたいと考えています。

## 参考文献
この記事は以下の情報を参考にして作成しました。

- [大規模言語モデル（LLM）とは](https://www.ibm.com/jp-ja/think/topics/large-language-models)
- [Transformer モデルとは](https://blogs.nvidia.co.jp/blog/what-is-a-transformer-model/)
- [ファイン・チューニングとは](https://www.ibm.com/jp-ja/think/topics/fine-tuning)
- [2024-08-28 大規模言語モデル（LLM）の構築：技術的課題から実践的応用まで](https://automation.jp/research-report/2024-08-28-building-large-language-models-from-technical-challenges-to-practical-applications)
colabでPICのコンパイル

自分用

以下の5ブロックを順にコードブロックに貼り付けて実行する
実行は再生マーククリックかShift+Enter

<details><summary>インストールスクリプト（expect使ってEnterするだけ）の作成</summary>


```
%%writefile /content/install_xc8.exp
#!/usr/bin/expect -f
set timeout -1
spawn sudo bash -c  "/content/xc8-v3.00-full-install-linux-x64-installer.run"

while {1} {
    expect {
        "continue:" {
            send "\n"
        }
        "Do you accept this license" {
            send "y\n"
        }
        "Please choose an option" {
            send "1\n"
            break
        }
    }
}

expect "Leave unchecked for optimal compile times"
send "y\n"
expect "Installation Directory"
send "\n"
expect "Apply settings to all users of this machine"
send "y\n"
expect "Add xc8 to the PATH environment variable"
send "y\n"
expect "continue:"
send "\n"
expect "Click to purchase a PRO license"
send "n\n"
expect "Click here to get a free, 60-day evaluation of PRO"
send "n\n"
expect "Click here to activate your license"
send "n\n"
expect "Your Host ID is"
send "\n"

interact
```

</details>

<details><summary>コンパイラのインストール</summary>

```
!sudo apt-get update && sudo apt-get install -y expect
!wget https://ww1.microchip.com/downloads/aemDocuments/documents/DEV/ProductDocuments/SoftwareTools/xc8-v3.00-full-install-linux-x64-installer.run
!chmod +x xc8-v3.00-full-install-linux-x64-installer.run
!chmod +x install_xc8.exp
!sudo bash -c "/content/install_xc8.exp"
```
</details>

<details><summary>コードの作成(コード内容は省略)</summary>

```c
%%writefile /content/main.c
// ここ以降にコードを記載
#pragma config FEXTOSC = OFF           // External Oscillator Selection (Oscillator not enabled)
#pragma config RSTOSC = HFINTOSC_64MHZ // Reset Oscillator Selection (HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1)
...省略
```
</details>

コンパイル(mcpuは使用cpuに合わせる)
```
!/opt/microchip/xc8/v3.00/bin/xc8-cc -mcpu=18F26Q84 main.c -o demo2.hex
```

ダウンロード
```
!cat demo2.hex
```
rex0220 印刷屋プラグイン テーブル複数ページ

[rex0220 印刷屋プラグイン](https://qiita.com/rex0220/items/9be2d9b20a3a1f016c76)で、テーブルから複数ページを作成する例です。

# 概要

テーブルから複数ページの PDF を作成してみます。
テーブル内の画像データも表示します。

- プレビュー画面

![2025-02-27_17h30_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/30a4843b-97c2-4a5b-a73d-2fea2b65bfde.png)

- プレビュー画面 1-2 枚目

![2025-02-27_17h31_23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/e6f5dfde-7534-4998-8dfd-814060ebe0ba.png)

- 作成した PDF イメージ

![2025-02-27_17h34_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/3ec3504a-d37d-452b-8824-1fe9451ee99e.png)

- 元のテーブル

![2025-02-27_17h35_37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/40e42ce4-8072-499d-a76b-15213a971726.png)

# 印刷屋プラグイン設定

TABLE_HTML 関数で、テーブルから複数ページを作成します。
1ページに表示するテーブル行数を指定すると、ページ制御ができます。
画像は、IMGSRC 関数で添付ファイル項目の fileKey を取得し、印刷屋プラグインで img データに変換します。

![2025-02-27_17h40_36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/11dbab43-4f3d-4946-8aeb-6a18f2f53d90.png)

![2025-02-27_17h41_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/11980574-51f1-43bb-aa9c-459e8775a84e.png)

共通CSSの pcraft-table-table クラスを利用し、それに個別のCSSを指定します。

```css:
.row-no,
.value-image {
  text-align: center;
}
.pcraft-table-td-value img {
  width:150px;
}
```

TABLE_HTMLで指定した項目は、項目の設定に従ってカンマ区切り等の書式を適用します。
独自の書式や計算結果を表示したい場合は、ARRAY関数で、項目タイトル、値、クラス名を指定してください。

```js:
TABLE_HTML(テーブル,
  OPT("title","時計","pagination","Y"),
  OPT("perPage","5"),
  ARRAY("#",ROWNO(テーブル)+1,"row-no"),
  名称,
  ARRAY("画像", IMGSRC(添付ファイル,0,"img"), "value-image")
)
```
KAGのLT会に参加してみた感想

## はじめに
こんにちは！みっきーです！
今日は2025年2月27日に開催された第3回KAGのLT会に参加してみたのでその感想を簡潔に記そうと思います。

## イベントページ
https://kddi-agile.connpass.com/event/345657/

## 参加経緯
私は今まで技術系のイベントに参加したことがなく、興味はあるけれど参加するのを躊躇していました。「そもそも前提知識を持っておかないと参加しても意味ないのでは...」なんてことも思ってました。
今回、大学の友人からYouTubeにてKAGのLT会が見られるということを教えてもらったので、気軽に参加してみました。

## イベントの感想
まず最初に、**登壇者の方々の資料が見やすすぎる!!!!**
もうこれだけで勉強になったというか、資料の作り方を見に行くだけでも参加する価値があるなと感じました。
コンテンツについてですが、個人的には「デザイン案件を通じて見つけてもらえた、30代半ばの自分に眠ってた才能」と、「ドラッカーに学ぶスクラムマスターとしての振る舞い方」がすごく印象に残りました。読書で世界が広がるということ、リーダーは何をやるかを決めるより何をやらないかを決める方が大事ということ、今後の人生において大切になることを得ることができました。

## さいごに
イベントはめちゃくちゃおもしろいし、とても勉強になることが分かりました。今日、初めの一歩を踏み出せてよかった。これからはこういう技術イベントには積極的に参加していきたいと思います！
Qiitaのみなさん、初めまして！

# はじめに

初めまして、株式会社レアゾン・ホールディングス（以下、レアゾン・ホールディングス）の開発本部に所属している、るいです。
たくさんのブログの中から、当社のテックブログをご覧いただき、ありがとうございます。

本日より、レアゾン・ホールディングスのテックブログがはてなブログから Qiita に移行しました。
この機会に Qiita の読者の皆様に対して、当社及び当社のテックブログについてご紹介させていただきます。

# レアゾン・ホールディングスとは？

レアゾン・ホールディングスは、成長が著しいインターネット領域にて
<b>【新規事業立ち上げを得意とするスタートアップ企業】</b>です。

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3962794/5b565c5b-3a9a-4de6-b420-17fcebcd1c5c.png">

当社はビジョンに"世界一の企業へ"、ミッションに"新しい当たり前を作り続ける"を掲げ、複数領域での事業展開・新規事業立ち上げを行っております。

現在は「広告」「ゲーム」「フードテック」「ブロックチェーン」「コンテンツ」「ペットテック」などの領域を中心に事業展開をしております。
各事業間のシナジーを高めることで、他社にはない事業展開や新規事業を創出し続けております。

# 過去ブログハイライト

当社のエンジニアはいままで、はてなブログに様々なブログを作成し、公開してきました。
せっかくなので、この機会にみなさんにいくつかご紹介いたします。

### 社内エンジニア調査！ 〜2024 年度の振り返りと抱負〜

<a href="https://techblog.reazon.jp/entry/2025/02/12/130609">
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3962794/a2571774-d9ee-48e7-916c-a3b2a9b41c97.png" alt="社内エンジニア調査！ 〜2024年度の振り返りと抱負〜">
</a>

<br>

皆さんは昨年気になったテックや、また今年の抱負は何ですか。
当社のブランディング事業 - GIFTech のエンジニア、佐藤が今年（2025 年）の 1 月にそのテーマについてのアンケートを作成し、社内のエンジニアから意見を集めました。

私はこちらのブログを通じて知らないテックニュースやツールの情報を沢山手に入れることができて、凄く勉強になりました。

### React Native Meetup #19 現地レポート

<a href="https://techblog.reazon.jp/entry/2025/01/23/155010">
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3962794/2b39faa6-0850-492e-b8bf-ca67c1782263.png" alt="React Native Meetup #19 現地レポート">
</a>

皆さんはデリバリーアプリを利用して、食事などを注文したことはありますか？
当社が展開しているフードテック事業の一つに、「menu」というアプリがあります。
これは React Native を使用して開発され、デリバリーサービスを提供しています。

そして、menu のエンジニアたちは昨年（2024 年）の 12 月に外部の LT 会に登壇し、業務上で使用している技術について発表しました。
その際、参加したエンジニアの方が当日の様子を記録し、記事を作成してくれました。

### Inside View of Training at a Japanese IT Company

<a href="https://techblog.reazon.jp/entry/2024/12/12/134028">
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3962794/4972153d-86a8-4f7b-9de2-df7c357341ae.png" alt="Inside View of Training at a Japanese IT Company">
</a>

<br>

当社では新卒エンジニア向けに、毎年エンジニア研修を実施しています。
現在、当社には多くの国籍を持つ社員がおり、世界中から集まっています。
このような機会を活かし、昨年は外国籍の新卒エンジニアメンバーに参加していただき、エンジニア研修の体験をブログ形式で共有させていただきました。

ちなみに、これはテックブログで初めての英語ブログで、今後も外国籍のエンジニアメンバーに協力していただき、英語のブログを作成していく予定です！

# おわりに

最後までご覧いただき、ありがとうございます！
ここまでで、当社の会社紹介ならびに当社のエンジニアがこれまでに作成したブログの一部をご紹介させていただきました。
当社はこれからも Qiita で皆様に様々な有益な情報を提供できるよう努力しますので、ぜひ当社のアカウントをフォローしてください！！

また、Qiita に移行した関係で、レアゾン・ホールディングスのはてなブログは年内終了を予定しております。
よろしくお願いいたします！！！

<hr>

### **▼ 採用情報**<br>

レアゾン・ホールディングスは、「世界一の企業へ」というビジョンを掲げ、「新しい"当たり前"を作り続ける」というミッションを推進しています。

現在、エンジニア採用を積極的に行っておりますので、ご興味をお持ちいただけましたら、ぜひ下記リンクからご応募ください。

https://recruit.reazon.jp/
アリババクラウドのPolarDB、革新的な「三層分離」アーキテクチャでTPC-Cベンチマークの世界記録を突破

> 本記事は[こちらのブログ](https://www.alibabacloud.com/blog/alibaba-clouds-polardb-breaks-tpc-c-benchmark-world-record-with-innovative-three-layer-decoupling-architecture_602021?spm=a2c65.11461433.0.0.4ee35355udb7vC)を参考にしています。
> 翻訳にはアリババクラウドの[ModelStudio](https://www.alibabacloud.com/en/product/modelstudio)([Qwen](https://www.alibabacloud.com/en/solutions/generative-ai/qwen))を使用しております。

# アリババクラウドのPolarDBがTPC-Cベンチマークで世界記録を達成

**杭州、中国、2025年2月26日** – アリババグループのデジタル技術およびインテリジェンスの中核を担うアリババクラウドは、クラウドネイティブなリレーショナルデータベース「PolarDB」において、TPC-Cベンチマークで新しい世界記録を達成しました。このTPC-Cベンチマークは、Transaction Processing Performance Council (TPC)によって開発されたもので、オンライントランザクション処理（OLTP）システムのパフォーマンスを評価します。

![1](https://img.alicdn.com/imgextra/i3/O1CN011qZ3eb1xDpomKgF4C_!!6000000006410-2-tps-6250-2290.png)

出典: [tpc.org](https://www.tpc.org/tpcc/results/tpcc_results5.asp)

TPC-Cの結果によると、PolarDBは1分あたり20億5500万トランザクション（tpmC）を達成し、これまでの記録保持者と比較して2.5倍の性能を示しました。さらに、トランザクションごとのコスト（price/tpmC）をほぼ40%削減し、1トランザクションあたりCNY 0.8（USD 0.11）に抑えることに成功しました。加えて、8時間にわたる負荷テストでは、PolarDBは2兆2000億のデータ操作を100%のデータ精度で処理し、tpmCの変動率をわずか0.16%に維持しました。これは、TPC-Cベンチマークの要件である2%よりも1桁低い数値です。PolarDBがTPC-Cベンチマークで達成した20億5500万tpmCという数字は、2020年のTmall 11.11ショッピングフェスティバルでのピークトランザクション量の59倍に相当します。

![O1CN01leQm741iGNmiHJ8yU_!!6000000004385-](https://img.alicdn.com/imgextra/i3/O1CN01leQm741iGNmiHJ8yU_!!6000000004385-0-tps-1834-1222.jpg)

アリババクラウドインテリジェンスのデータベース製品事業担当プレジデントである李飛飛（Feifei Li）博士は次のように述べています：

> 「この驚異的な成果は、当社チームがデータベース技術における革新と卓越性を追求し続けていることの証です。PolarDBがTPC-Cベンチマークで示したパフォーマンスは、最も要求の厳しいワークロードに対応できる能力を実証するとともに、コスト効率とスケーラビリティに優れたソリューションを提供するという我々のコミットメントを強調しています。革新的なアーキテクチャにより、クラウドネイティブデータベースの管理は『ブロックを積み上げる』ように簡単になります。私たちは引き続き、顧客がデータを効果的に管理・活用し、デジタル時代に繁栄できるよう支援していきます。」

TPC-Cベンチマークは、極限状態におけるデータベースのパフォーマンスを評価することを目的として設計されています。このベンチマークでは、データベースに対して、大きな負荷下でもデータの正確性を維持し、ソフトウェアやハードウェアの障害時にもデータの一貫性を保ち、ストレス条件下でのデータの可用性、一貫性、整合性を確保することが求められます。TPC-Cは、業界で最も権威あるOLTPベンチマークの一つとされています。

PolarDBの記録破りのパフォーマンスは、その革新的なアーキテクチャによって支えられています。「Limitless Architecture」と呼ばれるこのアーキテクチャは、コンピューティング、メモリ、ストレージを独立してスケールできる三層分離設計を採用しており、最適な弾力性を実現することで効率を向上させています。さらに、ソフトウェアとハードウェアの統合、および高度なデータベースカーネルの最適化技術（トランザクション処理の改善、インデックス構造の改良、I/Oパスの強化など）により、この卓越したパフォーマンスがさらに引き上げられています。

PolarDBは、高速なパフォーマンス、高同時実行性、自動スケーリングが必要なビジネスクリティカルなデータベースアプリケーション向けに設計されたクラウドネイティブリレーショナルデータベースです。このソリューションは、マレーシア最大のフィンテックプラットフォームであるTNG eWallet、香港を拠点とする中国テレビ番組制作の大手企業Television Broadcasts Limited（TVB）、日本のモバイルゲーム開発会社enish, Inc.、インドネシアの主要な決済技術企業DOKUなど、世界中のさまざまな業界の1万社以上の企業顧客のデジタル化の旅をサポートしてきました。

アリババクラウドは、リレーショナルデータベース「PolarDB」、データウェアハウス「AnalyticDB」、マルチモーダルデータベース「Lindorm」、データ管理サービス「Data Management Service (DMS)」など、自社開発の幅広いクラウドネイティブデータベース製品を提供しています。アリババクラウドは、過去5年連続でGartner® Magic Quadrant™ for Cloud Database Management Systems (DBMS)において「リーダー」として評価されています。
【Python】or で初期化するのをやめてほしい

## 言いたいこと

Python で引数が空かもしれない場合には、次のように `or` を使って初期化するのは避けてください。

```python
def f(param = None):
    var = param or default
    :
```

かわりに、次のように引数のデフォルト値を直接指定してください。


```python
def f(param = default):
    :
```

前者の書き方だと引数 `param` が空の場合にデフォルト値が使われてしまい、意図しない動作になってしまいます。


## 細かい説明

Python の `or` 演算子は `True`/`False` を返すとは限りません。左側の[真理値判定](https://docs.python.org/ja/3.13/library/stdtypes.html#truth)の結果が真であれば左側の値を、偽であれば右側の値を返します。

以下に、左側が偽である式の結果を示します。

```python
>>> False or True
True
>>> 0 or 1
1
>>> [] or [1]
[1]
>>> set() or {1}
{1}
>>> {} or {1: 1.0}
{1: 1.0}
>>> None or object()
<object object at 0x0000010DEFB55C30>
```

これを利用して、引数が省略された場合の処理を簡潔に書くことができますが、この方法は避けていただきたいのです。前述の通り、引数が空であってもデフォルト値が使われてしまうからです。

以下の関数を例に説明します。

```python
from typing import Mapping, Iterable

def mapdict(subject: Iterable[str], mapping: Mapping[str, str] | None = None) -> str:
    m = mapping or {"ヰ": "イ", "ヱ": "エ"}
    return "".join(m.get(s, s) for s in subject)
```

この関数は、第一引数の文字列の各文字に、第二引数の辞書を適用し、連結した結果を返します。`mapping` 引数が省略された場合、デフォルトの辞書 `{"ヰ": "イ", "ヱ": "エ"}` が使われます。

以下のようにうまく動くように見えます。

```python
>>> mapdict("ウヰスキー")
'ウイスキー'
>>> mapdict("C:\\path\\to", {"\\": "/"})
'C:/path/to'
```

しかし、何も変換したくない場合に空の辞書を与えても、デフォルトの辞書が使われてしまいます。空の辞書の真理値は偽だからです。

```python
>>> mapdict("ウヰスキー", {})
'ウイスキー'
```

この問題を回避するため、できるだけ引数のデフォルト値を直接指定するようにしてください。

```python
from typing import Mapping, Iterable

def mapdict(subject: Iterable[str], mapping: Mapping[str, str] = {"ヰ": "イ", "ヱ": "エ"}) -> str:
    return "".join(mapping.get(s, s) for s in subject)
```

このようにすることで、空の辞書が与えられた場合も正しく動作するようになります。


## 空の辞書で初期化する場合にも避けてほしい

以下の例は空の辞書で初期化しているので `or` を使っても問題ないでしょうか？

```python
from typing import Mapping, Iterable

def mapdict2(subject: Iterable[str], mapping: Mapping[str, str] | None = None) -> str:
    m = mapping or {}
    ret = ""
    for t in subject:
        try:
            ret += m[t]
        except KeyError:
            ret += t
    return ret
```

この場合にも、以下のような使われ方をする可能性があるので避けていただきたいです。

```python
>>> from collections import defaultdict
>>> mapdict2("すべてがFになる", defaultdict(lambda: "F"))
'すべてがFになる'
```

`defaultdict(lambda: "F")` はどんなキーが与えられても `"F"` を返す辞書です。これを利用してすべての文字を F にしようとしましたが、元の文字列が返ってしまいました。

`defaultdict(lambda: "F")` は長さが 0 なので、`m = mapping or {}` の `mapping` の真理値は偽です。このため、`m` は空の辞書 `{}` で初期化され、KeyError が発生しています。

この場合も、以下のように引数のデフォルト値を直接指定するようにしてください。

```python
def mapdict2(subject: Iterable[str], mapping: Mapping[str, str] = {}) -> str:
    ret = ""
    for t in subject:
        try:
            ret += mapping[t]
        except KeyError:
            ret += t
    return ret
```

以下の通り、正常に動作するようになります。

```python
>>> mapdict2("すべてがFになる", defaultdict(lambda: "F"))
'FFFFFFFF'
```
Unityで画面のサイズとUIのサイズを比例させる方法

# はじめに
- Unityでは画面のサイズを変更した時に、**デフォルトの設定ではUIのサイズや位置はそのままになってしまいます**。しかし、**画面のサイズを変更した時に、UIのサイズと位置を画面のサイズに比例して変更させる方法がある**のでそれをご紹介します。
- **破格の簡単さです**

# 目次
1. **どんな機能なのかの概要**
1. **設定方法**

# どんな機能なのかの概要
- おそらく、UIがデフォルトの設定のままだと画面のサイズを変更したときに以下のようになってしまいます。
![画面録画-2025-02-26-183325.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758326/6e4f56e3-a205-482d-bf17-eda173db3f3e.gif)

- 今回は画面の「New Text」を画面のサイズを変更した時に、その画面のサイズの変更に合わせて位置や大きさも変更するようにさせます。
    - 具体的には下記のような感じになります。
    ![画面録画-2025-02-26-183403.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758326/c54005c8-bdfe-42b0-9330-cc30fd814a1c.gif)


# 設定方法
- 設定方法は、UIである「New Text」の親オブジェクトにあたる「Canvas」の設定を変更します。
    **具体的にはCanvasに含まれている「Canvas Scaler」の「UI Scale Mode」を「Scale With Screen Size」に変更します**。
    ![スクリーンショット 2025-02-27 165132.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758326/d7997aff-676c-4260-8eee-2b065a725452.png)
    こうすることで画面のサイズの変更に比例してUIのサイズや位置も変更されます。

    
# まとめ
- 今回は画面のサイズの変更に対応してUIのサイズや位置も変更するという設定方法をまとめました。この設定はゲーム制作では必須のテクニックだと感じます。そこまで難しくないのが唯一の救い。
ESP32: 簡単な Lチカ

こちらと同じことを行いました。
[【ESP32で電子工作-1】ESP32の入出力ポートを使用してLED点滅【Lチカ】](https://electwork.net/esp32-1/)

![esp32_feb27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/ec59ee8f-84bf-4052-a521-0504bd31e7e1.png)

Arduino IDE 2.3.4 を使いました。
ボードは ESP32 Dev Module です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/ff0982fc-9531-41ef-91d4-0ebb6cfc0e6b.png)

## プログラム

```text:led_test01.ino
// ---------------------------------------------------------------------
/*
	led_test01.ino
						Feb/27/2025
*/
// ---------------------------------------------------------------------
#define	PROGRAM	"led_test01.ino"
#define	VERSION	"2025-02-27 PM 16:22"

#define LED_BUILTIN 12

int icount = 0;
// ---------------------------------------------------------------------
void setup() {
	Serial.begin(115200);
	
	delay(1000);
	Serial.println("*** start ***");
	
	delay(1000);
	Serial.println("*** Feb/27/2025 ***");
	pinMode(LED_BUILTIN, OUTPUT);
	delay(1000);
	Serial.println(PROGRAM);
	Serial.println(VERSION);
	Serial.println("*** setup end ***");
}

// ---------------------------------------------------------------------
void loop() {
	Serial.println("*** Feb/27/2025 ***");
	Serial.println("*** loop *** " + String(icount));
  digitalWrite(LED_BUILTIN, HIGH);
  delay(4000);
Serial.println("*** loop bbb ***");
  digitalWrite(LED_BUILTIN, LOW);
  delay(2000);

	icount++;
}
// ---------------------------------------------------------------------
```
Unity(ゲーム開発)における処理速度の最適化

##前書き
unityでコードを書く際に存在するが存在してはいけない余分なものについて気になったので調べたものをまとめました。
一部チュートリアルやAIにコード書かせたりすると出てくるものが多く私も含め多くの初学者は気づかぬ間に多くの欠陥を持ったコードを量産しています。
コメント分や余分なif文等の基礎的なものは除き勉強し始めで誰もが書いてしまうコードに絞って書いています。
## Unityで書いてはいけないコード
### [大罪１].GameObjectの探し方
例

    Find() / FindObjectOfType()
ほとんどの人は一度は書いたことあるであろうコード。
#### 理由
・シーン内の全オブジェクトを検索する
・シーン内の設定にスクリプトの処理が依存してしまう(可変性の低さ)
・GameObject.Findは名前検索はバグ、エラーの原因になりやすい
・可読性が低い
#### 解決案
    [SerializeField]private GameObjact player;

### [大罪2].string型による制御構文
例

    void OnTriggerEnter(Collider other) {
        if (other.gameObject.name == "Enemy") {
            Debug.Log("敵に当たった！");
        }
    }

if文でゲームオブジェクトの名前で比較する。
StartCoroutineなどでメソッド名をstringで指定する。
などかなり応用範囲が広い巨悪

#### 理由
・シーン内の全オブジェクトを検索する
・シーン内の設定にスクリプトの処理が依存してしまう(可変性の低さ)
#### 解決案
Unityの性質上代替案は実質的になく場面ごとに変えるしかない。
一応の対策法としていくつか

    ・TryGetComponentを使った型チェック（基本これかも）
    ・直接メソッドを指定する

ー大学の授業でならってそのまま来てしまうと書きがちだし、先ほどと違い修正するのが面倒なものが多く挙動が変わってしまうことがあるし癖で書いてそのまま気づかず修正に時間を取られることが多い。

## 注意したいコード
ここからは意識した方がいいコードを簡単にまとめます
ただ、これは解決案や自分の理解が怪しい部分もあるためご愛敬頂けると助かります。
### [注意1]publicメンバ変数
意図しない変更のリスク、コード保守性の低下、データの整合性の問題、オブジェクト指向の原則違反
上げればきりがないレベルだし、書かなくてもどうにかなるのでわざわざ書く必要はあまりない
#### 解決案
・書かない
・外部干渉用のプロパティや関数を用意する
### [注意2] public static変数
他のクラスの変数触りたいからという理由で使う場合public static変数と同様の理由で使わない方がよい。
#### 解決策
依存性注入（DI）を使用して、必要なクラスの参照を適切に渡す

### [注意3]Instantiate() / Destroy()
オブジェクトの生成、削除はそりゃあ重い
正直あんまり気にしなくてもいいかも...
#### 解決案
オブジェクトプール (Object Pooling) を使用する
SetActive(false) で無効化し、使い回す

## 参考にさせていただいたものの中で理解できたもの
Unityプログラミング現場に蔓延る罪
https://note.com/metaformingpro/n/ncabd7dee227d#94067123-9e35-44c6-a3a0-8059d1c3da82
ChatGPT
Qiita社のインフラのコスト削減をどう進めたか

Qiita社では去年の8月からコスト最適化プロジェクトとして、私と @wataru86 の２名が中心となり、複数のインフラコスト削減施策に取り組みました。
行った施策の大半は [Qiita社でインフラコストを抑えるためにやった取り組みを公開する #AWS - Qiita](https://qiita.com/WakameSun/items/0ebf0ebf7a28d7051ae9) で公開していますが、今回はどのようにプロジェクトを進めていったかを記載します。

## 施策候補の洗い出し

まず現状把握をしつつ、コスト削減できそうな施策候補を可能な限り洗い出します。
AWSの[Cost Explorer](https://aws.amazon.com/jp/aws-cost-management/aws-cost-explorer/)、Google Cloudのレポートなどを使って現在のコスト状況を確認し、費用が高い場所を中心に改善案があるか調査します。
また、過去に作成したIssueや、各メンバーの頭の中にある「こうすると安くなるんじゃないか」という施策案も収集して情報をできるだけ取りこぼさないようにしましょう。
削減額が一見小さそうな施策案でも、ここでは実施するかどうかを切り捨てずに案として書き残しておきましょう。
最後に、今後不必要なコストを増やさないための監視施策ついても考えておきましょう。今回減らせてもまた増やしてしまっては意味がありません。

## 施策候補の見積もり

施策候補がある程度出揃ったら、各施策の削減額・かかる工数・制約をそれぞれ見積もったり確認したりしましょう。
制約は行う時期やタスク間の順序関係などです。例として以下のようなものがあります。

- RIで購入しているインスタンスのインスタンスタイプを変更する
    - 現在購入しているRIの、有効期限に近いタイミングで変更を行う必要がある
- Datadogを月ごとの契約から年間契約への切替
    - ECS on EC2からECS on Fargateへの移行など、料金に影響のあるインフラの変更を一通り済ませた後に行う必要がある


## 施策を行う順序・アサイナーの決定

施策の削減額・かかる工数・制約がわかったら、どの施策から行うか・誰が担当するかを決めます。
コストインパクトの大きい試作と、優先度の高い制約(EOL等)がある施策を中心に考えると自然にどの施策から行うかは決まってくると思います。
誰が担当するかはメンバーのスキルや希望などを天秤にかけて決めてください。
Qiitaの場合は、コストインパクトが一番大きいものの少々骨の折れる、CloudWatchに保存していたRDSのAuditログのS3移行を @wataru86 が、インパクトはそこそこだが工数が少ない複数の施策を私がまず第一に取り組むこととしていました。

## 施策に取り組む

やることが決まればあとは遮二無二やっていきます。
たまに新しい施策案が見つかったりするので、その際は優先度の見直しを行ってください。

## 振り返りをする
施策はやりっぱなしにせず振り返りを行いましょう。
どれくらい施策によってコストダウンができたのか確認するのはもちろん、施策を進めている時のKPTも考えるとなお良いでしょう。

## 共有する

振り返りをしたら、プロジェクト外のメンバーやチーム外の社員に施策結果を共有しましょう。
アピールになるのはもちろん、自分達にはない視点のFBをもらえたり、そこから新たなアイデアが生まれることもあります。


## 最後に
今回紹介した手順は、他のプロジェクトでも大きくは変わらないと思います。
取り組み候補を洗い出して、見積もったのちに優先度を決めて取り組む、終わったら振り返りをして共有という流れはどこでも自然とやっているのではないでしょうか？
型を一度覚えると、他のプロジェクトにも応用しやすくなりスムーズに進められると思います。
プロジェクトオーナーを初めて担当する場合などは、まず先述の流れを意識してプロジェクトを進めてみると良いでしょう。
[Windows] 超簡単 誤って作成した数十万のフォルダ、ファイルが削除できないときに使える削除コマンド

# 経緯
フォルダを監視し、変更を検知すると指定フォルダへと自動バックアップするアプリケーションのテストの際、誤って監視フォルダ内にバックアップ先フォルダを作ってしまいました。

```
監視フォルダ/
│── バックアップ先フォルダ
```
```mermaid
graph TD;
    A[監視フォルダの変更検知] --> B[バックアップ]
    B --> C[バックアップ先フォルダも監視対象（監視フォルダ内のため）]
    C --> A
```

その結果、ファイル変更検知とバックアップが無限に起き、一瞬で数十万の（それ以上かも！？）フォルダとファイルが生成されました。

数が多すぎるせいか何度削除しても消えてくれないゾンビにくらわす武器がありました！

# PowerShellで削除

```powershell:PowerShellで実行
Remove-Item -Path "削除したいアイテム群があるフォルダのパス" -Recurse -Force
```
めでたしめでたし

_。。。fin_
- - -

**ちょっと待ってください、些細なことでも一手間加えたいというのがエンジニアの性ですよね。**

# 削除アプリケーションを作る
問題点
* コマンドの手打ち
* 処理中の内容が表示されず、固まっているように見える

特に二番目は何とかしたいです。
私はフロントエンドエンジニアなので、サービス離脱を招く問題は見過ごせません。

```:構成
フォルダ/
│── 削除したいアイテム群
│── delete_file.bat
```
delete_file.batを実行して削除できるようにしましょう。
更に、現在削除中のアイテムを表示してユーザーに安心感を与えます。

:::note warn
メモ帳で作成したあと、**UTF-8 (BOM 付き)** で保存してください。
:::

```powershell:delete_file.bat
@echo off
chcp 65001 >nul
setlocal enabledelayedexpansion

:: delete_file.batがあるフォルダを取得
set "TARGET_DIR=%~dp0"

:: delete_file.batの名前を取得
set "SCRIPT_NAME=%~nx0"

:: 一時フォルダ（WindowsのTempディレクトリ）を作成してdelete_file.batを移動
set "TEMP_DIR=%TEMP%\delete_temp"
mkdir "%TEMP_DIR%"
copy "%TARGET_DIR%%SCRIPT_NAME%" "%TEMP_DIR%\"

:: 削除中のファイル・フォルダをリアルタイム表示
for /f "usebackq delims=" %%A in (`PowerShell -Command "& { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-ChildItem -Path '%TARGET_DIR%' -Exclude '%SCRIPT_NAME%' -Recurse | Select-Object -ExpandProperty FullName }"`) do (
    echo ■■■削除中: %%A■■■
    PowerShell -Command "Remove-Item -Path '%%A' -Recurse -Force"
)

:: 削除が終わったらdelete_file.batを元の場所に戻す
move "%TEMP_DIR%\%SCRIPT_NAME%" "%TARGET_DIR%"
rmdir "%TEMP_DIR%"

echo ■■■■■■■■■■削除が完了しました。■■■■■■■■■■
pause

```

~~これからもファイルを無限に作成するミスを犯し続けようと思います。~~
ありがとうございました。

# おすすめ記事
https://qiita.com/ya_n_n/items/b40f0886d62689d2d053
Flutterで作成したプロジェクトでupdate_project_provisioningが反映されない

Flutter(3.27.1)で作成したプロジェクトにFastlaneでアプリの配布を作成していました。
プロビジョニングを配布用のものにする必要があるので、いつもどおりupdate_project_provisioningを実行したのですが、変更が反映されない現象にであいハマりました。

今回作成したFlutterのプロジェクトのRunner.xcodeprojでは以下のようにプロビジョニングの指定が2箇所できるようになっていました。しかし、以下の図のAny iOS SDKの方が `update_project_provisioning` のコマンドで反映されていないのが原因でした。
![figure1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18273/f16a7d0d-b61c-412c-88b9-eb50f9a99abb.png)

xcodeprojのテキストとしては以下のような状態でした。
```
PROVISIONING_PROFILE = "ここは設定される";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "ここが設定されない";
```

以下にissueがありましたが、特にリアクションもなく自動クローズされているようなので、大きな問題ではないと思うのですが、正しい解決方法がいまいちよくわかりません。
https://github.com/fastlane/fastlane/issues/11895

とりあえず今回は`Any iOS SDK`の項目自体を削除して、ビルドできるようにしました。
Xcodeで新規にiOSアプリのプロジェクトを作成したところ、このように分かれていなかったため、特に問題ないと判断しました。

ただ、先々これが原因でなにか問題が起きたときに思い出せるようにこの記事を残しました。
Dashbitの2025年の計画 by José Valim

原文:https://dashbit.co/blog/dashbit-plans-2025
(監訳: 山崎 進 @zacky1972)

Dashbitで我々はスタートアップ企業やエンタープライズ企業が本番環境でElixirを採用し、運用できるように支援しています。その結果、私たちはこのような関係から、コミュニティに投資するためのリソースやフィードバックを得ることができます。この目標を達成するために、私たちは[Elixir Development Subscription](https://dashbit.co/)というサービスを提供しています。このサブスクリプションを通じて、開発中の着実な進捗を保証し、落とし穴を回避し、新しいチームメンバーを増強し、重要なアーキテクチャー上の決定を下す手助けをします。

歴史的に、私たちは自社のサブスクリプション・チームを3人のエンジニアだけに制限してきました。なぜなら、チームが大きくなると、クライアントに集中し、オープンソース・プロジェクトを発展させる能力が失われる可能性があるからです。
これはうまくいっていたのですが、私たちとの仕事を開始するまでの待ち時間が大幅に伸びてしまい、昨年は平均12ヶ月かかりました。これは、企業がElixirを採用するのを支援するという我々のミッションが部分的に失敗していることを意味します。そのため、今回初めてサブスクリプションチームを4名のエンジニアに拡大することになりました。

- [José Valim](https://github.com/josevalim)（エリクサー創設者
- [Wojtek Mach](https://github.com/wojtekmach)、Reqの生みの親、Ectoチームのメンバー
- [Jonatan Kłosko](https://github.com/jonatanklosko)、LivebookとBumblebeeのクリエーター
- [Steffen Deusch](https://github.com/steffende)、PhoenixおよびLiveViewチームのメンバー

コード・レビュー、技術ミーティング、チーム・ディスカッションで一緒に働くことに興味がある方は、[私たちについての詳細をお読みいただき](https://dashbit.co/)、[contact@dashbit.co](info@dashbit.co) までご連絡ください。

# オープンソースの目標
チームメンバーが増えるということは、オープンソース・プロジェクトへの貢献が増えるということでもあります。私は個人的には、「underpromise and overdeliver 」アプローチの大ファンですが、今回は2025年に向けた計画のいくつかについて、もう少し積極的にしました：

- José Valimと[Guillaume Duboc](https://github.com/gldubc/)(R&Dチームのメンバー)は型システムの開発を続けます。私たちの目標は、Elixir v1.19（2025年5月）までに完全な型推論を実現することであり、できれば2025年11月には構造体に型アノテーションを導入したいと考えています。

- Steffen Deuschの当面の目標は、[Phoenix v1.8](https://phoenixframework.org/)をリリースすることで、LiveViewジェネレータ、認証、セキュリティを合理化することで、オンボーディングエクスペリエンスの一部を改善することです。

- 採用面では、サイドバーの構築、タイプ・アヘッド・オート・コンプリート、無限スクロールなど、新しいLiveView開発者が直面する一般的な問題についての一連のブログ記事を検討しています。ご提案がありましたら、[liveview@dashbit.co](liveview@dashbit.co)へ！

- ここ数年、Wojtek MachとJonatan Kłoskoは、それぞれ[Req](https://hexdocs.pm/req/readme.html)と[Livebook](https://hexdocs.pm/livebook/readme.html)のような新しいエキサイティングなプロジェクトを生み出してきました。計画通りにいけば、今年中に正式なv1.0がリリースされる予定です。

- Livebookといえば、ネイティブアプリケーションにElixirを簡単に組み込める[ElixirKit](https://github.com/livebook-dev/livebook/tree/main/elixirkit)や、インフラ内で動作するPhoenix/Plugウェブアプリケーションに[Zero Trust Authentication](https://identitymanagementinstitute.org/zero-trust-authentication/)を追加する[NimbleZTA](https://github.com/livebook-dev/livebook/blob/main/lib/livebook/zta.ex)など、興味深いプロジェクトをレポジトリ内で作っています。これらは1.0の一部として提供される予定です。これらのプロジェクトを早急に利用できる場合は、ぜひご連絡ください！

- 一方、Livebookチームのメンバーである[Hugo Baraúna](https://github.com/hugobarauna/)と[Alexandre de Souza](https://github.com/aleDsz/)は、ElixirとLivebookを使って社内ツールを高速に構築・デプロイするためのサービスである[Livebook Teams]()の正式リリースに向けて作業を続ける予定です（現在ベータ版）。

また、2025年はElixirの相互運用性にとって素晴らしい年になると信じています。私たちはErlang VMとそのリアルタイムシステム構築のためのユニークな機能を強く支持していますが、他の言語やプラットフォームとのコラボレーションを促進することの重要性も認識しています。今後数週間で、より詳細な情報を共有し、[ElixirConf EU 2025](https://www.elixirconf.eu/)でエキサイティングなコミュニティの最新情報を聞く予定です。

長期的には、「共有するには早すぎる」領域に踏み込みますが、Elixirの次期型システムによって、Phoenixアプリケーションの開発者エクスペリエンスが改善されるかどうか、またどのように改善されるかを、まずはJSON APIやChannelを使用している開発者向けに調査したいと考えています。また、コードエディタだけでなく、AIが開発体験を向上させる新しい方法についても検討しています。

ご期待ください！
Azure Blob StorageからCustom Speechへ音声データを安全にアップロードする

# はじめに

- Custom Speechでのデータセットのアップロードは、1. zip形式でのアップロード、2. 認証などがなくデータセットへパブリックアクセスができるURL経由の2つがあります
- Web上ではどちらでも問題ないのですが、例えばカスタムモデルの開発をすべてREST API経由で行おうとするとzip形式でのアップロードができず、パブリックURLでの方法となってしまい、データセットが外部からアクセスできてしまいます
- 本記事では、この問題を回避するための方法を解説します


# やること

1. Speechリソースのシステム割り当てマネージドIDを有効にする
1. ストレージアカウントへのアクセスを制限する
1. Azure Storageファイヤウォールを設定する
1. Speechリソースにストレージへのアクセスロールを割り当てる


## 1. Speechリソースのシステム割り当てマネージドIDを有効にする

システム割り当てマネージドIDを有効にすると、ロールベースのアクセス制御ができるようになりますので、Blob Storageへのアクセスを許可できます。

Azure Portal上で、
1. Speechリソースを選択
1. 左側の `リソース管理` で `ID` を選択
1. `システムが割り当て済み` タブで `オン` を選択

## 2. ストレージアカウントへのアクセスを制限する

ここで、Azure Blob Storageにアップされているファイルのパブリックアクセスを無効にします。

Azureポータル上で、
1. ストレージアカウントを選択
1. `設定` グループで `構成` を選択
1. `BLOBパブリックアクセスを許可する` を `無効` にする
1. `ストレージ アカウント キーへのアクセスを許可する` を `無効` に設定
1. `保存` を選択

## 3. Azure Storageファイアウォールを設定する

2の設定でアクセス制限をしましたが、Speechリソースのアクセスは許可したいので、下記の設定を行います。

1. ストレージアカウントを選択
1. `セキュリティとネットワーク` グループの `ネットワーク` を選択
1. `ファイアウォールと仮想ネットワーク` タブで `選択した仮想ネットワークとIPアドレスから有効` を選択
1. すべてのチェックボックスのチェックを解除
1. `Microsoftネットワークルーティング` が選択されていることを確認
1. `リソースインスタンス` セクションでリソースの種類として、 `Microsoft.CognitiveServices/accounts` を選択（インスタンス名は使用中のSpeechリソース名を選択）
1. `保存` を選択


## 4. Speechリソースにストレージへのアクセスロールを割り当てる

ファイアウォールを設定しただけだと、ストレージアカウント内のデータにはアクセスできないため、手順1で作成したマネージドIDに対して、ストレージBLOBデータ閲覧者ロールを割り当てます。

1. ストレージアカウントを選択
1. 左側の `アクセス制御（IAM）` を選択
1. `このリソースへのアクセス件を付与` タイルの `ロールの割り当てを追加` を選択
1. `ロール` で `ストレージBLOBデータ閲覧者` を選択し、 `次へ` を選択
1. `メンバー` → `アクセスの割り当て先` で `マネージドID` を選択
1. 手順1のマネージドIDを割り当て、 `レビューと割り当て` を選択
1. 設定を確認したら `レビューと割り当て` を選択



以上の手順で、Speechリソースからストレージアカウントのデータへアクセスできるようになります。
[CakePHP4]find('list')->toArray()でjoinしたテーブルの値を取得する

# containでjoinしたテーブルのカラムをfind('list')でうまく取得できない
joinしたテーブルの値をlistの形で取得したかったのだが、エラー。
また同じところで引っかかりそうなのでメモしておきます。

**エラーになったコード↓**
```
$val = $this->Tests->find('list', array(
    'keyFields' => 'Joins.id',
    'valueFields' => 'Joins.name',
    'contain' => 'Joins'
))->toArray();
```
keyFieldsとvalueFieldsの部分でエラーになっている。

**対応後のコード↓**
```
$val = $this->Tests->find('list', array(
    'keyFields' => 'join.id',
    'valueFields' => 'join.name',
    'contain' => 'Joins'
))->toArray();
```
keyFieldsとvalueFieldsのテーブル名を「Joins」から「join」に変更すると、想定通りの動きになった。
公式リファレンスにも小文字かつsなしで記述するような記載があった。
リンクの項の一番最後「join でつながっている関連テーブルからリストのデータを生成することもできます。」の部分。

https://book.cakephp.org/5/ja/orm/retrieving-data-and-resultsets.html#table-find-list
サーバーサイドとクライアントサイドの理解


## Webアプリケーションとは？

私たちが日常的に使用するSNS、オンラインショッピング、メールサービスなどは、Webアプリケーションとして提供されています。Webアプリケーションは、インターネットを通じて動作し、ユーザーがブラウザを介して利用するプログラムのことです。

Webアプリケーションを理解するためには、主に「クライアントサイド」と「サーバーサイド」の役割を把握することが重要です。本書では、この2つの側面に焦点を当てて解説します。

---

## 1. クライアントサイドとは？

クライアントサイド（フロントエンド）は、ユーザーが直接操作する部分を指します。主にブラウザ上で動作し、Webページの表示や動的な動作を制御します。

### クライアントサイドの技術

- **HTML**：Webページの構造を定義するマークアップ言語。
- **CSS**：Webページのデザインを指定するスタイルシート言語。
- **JavaScript**：ページの動的な振る舞いを制御するスクリプト言語。

### クライアントサイドの動作の流れ

1. ユーザーがブラウザを通じてWebページにアクセス。
2. ブラウザがWebサーバーからHTML、CSS、JavaScriptを取得。
3. JavaScriptが実行され、インタラクティブな動作を提供。

クライアントサイドは、ユーザー体験（UX）を向上させるために重要な役割を果たします。

---

## 2. サーバーサイドとは？

サーバーサイド（バックエンド）は、データの処理や管理を担当する部分です。ユーザーのリクエストに応じて、データベースとやり取りし、必要な情報をクライアントに送信します。

### サーバーサイドの技術

- **プログラミング言語**：PHP、Python、Ruby、Javaなど。
- **データベース管理**：MySQL、PostgreSQL、MongoDBなど。
- **Webフレームワーク**：Django（Python）、Laravel（PHP）、Spring（Java）など。

### サーバーサイドの動作の流れ

1. クライアントがWebサーバーにリクエストを送信。
2. Webサーバーがリクエストを処理し、必要なデータをデータベースから取得。
3. 処理結果をクライアントに返送。

サーバーサイドは、Webアプリケーションのロジックやデータ管理を担い、安全で効率的なサービスを提供します。

---

## 3. クライアントサイドとサーバーサイドの関係

クライアントサイドとサーバーサイドは、HTTPを介して通信し、相互に連携して動作します。

### リクエストとレスポンスの流れ

1. **クライアント**：ブラウザからリクエストを送信。
2. **サーバー**：リクエストを受け取り、処理を実行。
3. **サーバー**：処理結果をレスポンスとして返送。
4. **クライアント**：レスポンスを受け取り、Webページを表示。

この一連の流れを「リクエストとレスポンス」と呼び、Webアプリケーションの基本的な仕組みとなります。

---

## 4. Webアプリケーションのアーキテクチャ

Webアプリケーションは、以下のような3層構造で設計されることが一般的です。

- **Webサーバー**：リクエストを受け取り、適切な処理を行う。
- **アプリケーションサーバー**：プログラムの処理を行い、データベースと連携。
- **データベースサーバー**：データの保存・管理を行う。

また、開発においては **MVC（Model-View-Controller）** という設計パターンがよく用いられます。

- **Model（モデル）**：データの管理・処理。
- **View（ビュー）**：ユーザーに表示する画面。
- **Controller（コントローラー）**：ModelとViewをつなぐ。

これにより、開発の分業がしやすくなり、保守性が向上します。

---

## 5. まとめ

Webアプリケーションは、「クライアントサイド」と「サーバーサイド」が連携して動作するシステムです。

- **クライアントサイド**は、ユーザーが操作するインターフェース。
- **サーバーサイド**は、データ処理や管理を担当。

両者はHTTP通信を通じてやり取りを行い、Webアプリケーションを構成します。

Webアプリケーションを開発する際には、クライアントとサーバーの役割を明確に理解し、それぞれの技術を適切に活用することが重要です。
(初心者による初心者のための)HTTPリクエストヘッダー

## HTTPリクエストヘッダーとは？

🔹 **そもそも HTTP リクエストとは？**

- Webブラウザ（ChromeやSafariなど）は、Webページを表示するために **Webサーバー** に「このページをください！」とお願いする
- **Webサーバー** は、そのリクエストに応じてページのデータを返す
- このやり取りには **「HTTP（エイチティーティーピー）」というルール** が使われる

---

🔹 **HTTP リクエストの3つの部品**

HTTPリクエストは3つの部分でできている：

1. **リクエストライン**（何をリクエストするか）
2. **リクエストヘッダー**（追加情報）
3. **メッセージボディ**（データの本体）

---

🔹 **HTTPリクエストヘッダーとは？**

- **リクエストヘッダー**は、リクエストの追加情報を伝える部分
- 「どのブラウザを使っているのか」「どこからのリクエストなのか」「ログイン情報（Cookie）など」が書かれている

★ **書き方の例**

User-Agent: Mozilla/5.0 （どのブラウザを使っているか） Cookie: PHPSESSID=123abc （セッション情報）


---

🔹 **Cookie とは？**

- **ブラウザに保存される小さなデータ** で、サーバーとやり取りするときに使う
- サーバーは「Set-Cookie」ヘッダーでクッキーを保存し、次回のリクエストで「Cookie」ヘッダーに入れて送られる

★ **Cookieの使い方**

サーバー → ブラウザ：Set-Cookie: PHPSESSID=123abc ブラウザ → サーバー：Cookie: PHPSESSID=123abc




★ **Cookieの例**

Cookie: user_id=1001; session_id=abc123



---

🔹 **Cookie の注意点**

- **プライバシー設定でブロックされる場合がある**
- **同意しないと一部のサイトが利用できなくなることも**
- **サーバーはCookieの情報を使ってユーザーの行動を記録できる**

---

🔍 **まとめ**

- **HTTPリクエストは、Webページを取得するときの「お願い」**
- **リクエストヘッダーには、追加の情報（ブラウザ情報・Cookieなど）が含まれる**
- **Cookieは、サーバーとのやり取りを便利にするためのデータ**
- **ブラウザはCookieを保存し、次回のリクエストでサーバーに送ることでログイン状態を保持する**
elixirにおける%の役割

# はじめに
elixirにおいて ``` %``` はいくつかの用途によって使われている
比較的頻繁に目にするので知っておくとコードを読む力に直結すると考えられる

# %{}の使い方
%{}で使うとマップとして使うことができる
なおマップとはキーと値のペアを複数持つデータ構造のことである

例：
iex > %{}

参考
Elixir 実践入門 基本文法、Web開発、機械学習、IoT
P.48 マップ-複数のキーと値のペアを表す型

# %hogehoge{}

構造体
構造体は拡張されたマップのようなもの
キーの形式が厳密に定められており、アトムである必要があります。
構造体は、モジュールの中で、適切なデフォルト値とともに定義される必要があります。
ルールを持つマップと言えます

引用
https://dev.to/nabbisen/-elixir---508k
DocusaurusでPlantUMLを表示するテーマを作りました

## はじめに

待てど暮せどDocusaurusにPlantUMLを表示するテーマやプラグインが出てこないので自分で作りました

1. npm: **[docusaurus-theme-plantuml](https://www.npmjs.com/package/docusaurus-theme-plantuml)**

## 表示イメージ
ライトモード
![lightmode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704534/06c2aa3e-9b0e-4925-b134-1159b9d27e20.png)

ダークモード
![darkmode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704534/02d54f43-32bc-46cb-9c7a-732c9b32604f.png)


## docusaurus-theme-plantuml とは？
DocusaurusでPlantUMLを表示できるようにするnpmです。

### 🌟 **特徴**
- ライトモード・ダークモード対応
- PlantUMLのレンダリング先を変更可能（デフォルトはPlantUML公式サーバー）
- コードブロック (```でくくる) の書き方でPlantUMLを埋め込み可能

## なぜ作ったのか？
DocusaurusはMermaidの組み込みサポートがありますが、PlantUMLのものがなかったため。

- UMLを使うなら、シーケンス図・クラス図・コンポーネント図などが豊富なPlantUMLを使いたい
- PlantUMLが標準で使えないのは不便

「ないなら作ってしまおう」
ということで作りました 💪

## インストール方法
Docusaurusプロジェクトに以下のコマンドでインストールできます。

```sh
npm install docusaurus-theme-plantuml
```

または、pnpmを使っている場合：

```sh
pnpm add docusaurus-theme-plantuml
```

## 設定方法
1. `docusaurus.config.js` の `themes` に追加

```js
module.exports = {
  // ...other settings
  themes: [
    require.resolve('docusaurus-theme-plantuml'),
  ]
};
```

2. MarkdownにPlantUMLを記述

```md
    PlantUMLの図はコードブロックで `pumld` または `plantuml-diagram` で表示されます
    
    ```pumld
    @startuml
    Alice -> Bob: Hello!
    Bob -> Alice: Hi!
    @enduml
    ```
```

これで、PlantUMLがDocusaurus内でレンダリングされます 🎉

:::note
PlantUMLコードとして表示したい場合も考慮してあえて `plantuml` と違うキーコード、 `pumld` でレンダリングするようにしてあります
:::

## 設定オプション
デフォルトでは、PlantUMLのレンダリングには **公式のPlantUMLサーバー** (`https://www.plantuml.com/plantuml/`) を使用しています。

だけど機密性の高いデータを扱う場合、自前のPlantUMLサーバーを使いたいこともあります。そのため、オプションでレンダリング先を変更できるようにしてます。

### PlantUMLのレンダリングサーバーを変更する
`docusaurus.config.js` で以下のように `themeConfig` を設定してください

```js
module.exports = {
  // ...other settings
  themeConfig: [
    plantuml: {
        serverUrlLight: 'https://www.your-private-plantuml-server.com/svg/',
        serverUrlDark: 'https://www.your-private-plantuml-server.com/dsvg/',
    },
  ],
};
```

## まとめ
DocusaurusでPlantUMLを表示するnpmを作った **docusaurus-theme-plantuml**

✅ MermaidではなくPlantUMLを使いたい人用
✅ ライトモード・ダークモードの表示切り替えに対応 
✅ PlantUMLのレンダリング先を自由に設定可能  

npm: [https://www.npmjs.com/package/docusaurus-theme-plantuml](https://www.npmjs.com/package/docusaurus-theme-plantuml)

Docusaurus使っている方は試してみてください
334日目 「SOA」合格体験記by社畜Ｓ

## :checkered_flag:はじめに
どうも、社畜Sです。  
今回はタイトルのとおり、無事に
**「AWS Certified SysOps Administrator - Associate（通称：SOA）」**
に合格することができたので、いつか受けるかもしれない誰かのためにSAA、DVAに続いて合格体験記として記事にしたいと思います！
完全初心者視点で「学習開始時のスペック」「どのように学習したか」「SAA、DVAと比べてどうだったか」について書いていくので、良ければぜひ参考にしてください！
## :checkered_flag:社畜Sのスペック（SOA版）<br> 
> 所持資格➡基本情報,SAA,DVAを取得済み。応用情報4連敗中。なんとかしたい。
> AWSについての知識➡SAA,DVAを取得済み。業務でAWSを使用し続けて半年以上経つので、知識もそれなりについてきた段階。

今回はSAA,DVA取得済み+実務経験も半年程度積んだ状態での試験だったので、それなりに知識を持っていた状態で受験しました。
ただ、詳しくは後ほど記載しますが、その状態でもかなりぎりぎりの合格になりました。
実務経験やハンズオン経験の有無が、合格に大きく影響する可能性があります。
## :checkered_flag:こういう勉強してました
使用した教材は今回も
**[Cloud License](https://cloud-license.com/)**
の一本勝負です。
学習期間は1か月半程度
過去問を大体700問程度解きました

学習の流れとしては
・過去問を解き、じっくり解説を読んで理解する
・問題のパターンを見つけて、この単語が出てきたらこの答えというのをなんとなく理解する。
・ひたすら過去問を解き続けて答えを暗記する

このようないつもの流れで行いました。
最終的には350問分くらい暗記したと思います。
SAA、DVAと比べると全体的に問題文、回答文共に長文なので、暗記だけで乗り切ろうとするのではなく、大枠を覚えるようにすると幅広い問題に対応できます。
また、実際に作ってみないとわかりにくいもの、経験則に基づく問題等が多いので、実務経験orハンズオン学習を積んでおくとそのような問題が来た際にも対応できると思います。

動画ベース学習の「Udemy」等だとハンズオン教材がついてくるものもあるようなので、実務経験がない方にはまずそちらの方法でハンズオン学習を進めておくと後々過去問を解く際に理解しやすくなるはずです。
## :checkered_flag:SAA、DVAと比べて
個人的にはSOAが最難関だと思います。
問題文、回答文どちらも長いというのもありますが、SAA,DVAと比べると実践的な問題が多く、実際に実務経験を経ていないと理解しにくい問題が多くあるのが大きいと思います。
点数で見ても

> SAA➡723点
> DVA➡771点
> SOA➡723点

と、AWS試験初受験であったSAAと同じ点数でのぎりぎり合格になっていました。
ほぼ未経験で受験したSAAと同じ点数だったことからも、SOAの難易度の高さがわかりますね。
しかも、現在は休止中のようですが過去にはラボ試験（実際のAWS環境でタスクを実行する試験方式）もあったようなので、まだ復活していない今の内に取れたのは結構幸運だったと思います。

とはいえ実践的な問題が多く出てくるということは、SOAの学習は実務にも大きく役に立つということだと思います。
他のAssociateと比べると高難易度ですが、難易度に見合った価値はあると感じました。


## :checkered_flag:まとめ
というわけで、完全初心者によるSOA合格記でした。
SAA,DVA、SOAを取得したのでこれでAWS試験3冠を達成しました。ちょっとだけ自信がついてきました。

次回の資格試験はAssociateレベルを卒業してProfessionalに…と思いましたが、今のレベルで行くのも少し不安なので、新しくAWS試験に追加された「AI Practitioner」と「Machine Learning Engineer - Associate」に挑戦しようと思っています。

今のところ3連続合格ですので、この流れを止めないよう次の資格試験も頑張っていこうと思います！


## :checkered_flag:余談
**[43日目 SAAに挑んだ社畜S](https://qiita.com/QiiTaro_/items/4ec66dae7f8d2ece565e)**
**[149日目「DVA」合格体験記by社畜Ｓ](https://qiita.com/QiiTaro_/items/a82c3d9ece972f386f89)**

社畜SがSAA、DVAに挑んだときの記事です。もし良ければこちらも読んでいただけると幸いです！
スクロール可能なタブとページャー

# ScrollableTabRow
`JetpackCompose`でタブとページャーを組み合わせたサンプルを探すと`TabRow`を使ったものが多く見つかりますが、タブの数が多かったり可変だったりする場合は`ScrollableTabRow`を使った方が便利です。
基本的には`TabRow`を`ScrollableTabRow`に置き換えるだけで動作しますが、若干レイアウトを調整した方が良いと思います。

## MainContent.kt
```kotlin:MainContent.kt
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun MainContent(
    modifier: Modifier = Modifier,
    state: MainContentState,
    onAction: (action: MainContentAction) -> Unit
) {
    val pagerState = rememberPagerState(initialPage = 0, pageCount = {state.itemCount})

    Column(
        modifier = modifier
    ) {
        ScrollableTabRow(
            selectedTabIndex = pagerState.currentPage,
            edgePadding = 0.dp,
        ) {
            for (i in 0 until  state.itemCount) {
                Box(
                    modifier = Modifier
                        .height(64.dp)
                        .clickable{
                            onAction(MainContentAction.ClickTab(i))
                        }
                        .padding(horizontal = 16.dp),
                    contentAlignment = Alignment.Center,
                ) {
                    Text(
                        text = "TabItem[${i}]",
                        style = MaterialTheme.typography.titleMedium,
                    )
                }
            }
        }
        HorizontalPager(
            modifier = Modifier.fillMaxSize(),
            state = pagerState
        ) { page ->
            Box(
                modifier = Modifier.fillMaxSize(),
                contentAlignment = Alignment.Center
            ) {
                Text(
                    text = "PagerItem[${page}]",
                    style = MaterialTheme.typography.headlineLarge
                )
            }
        }
    }

    LaunchedEffect(state.selectedIndex) {
        if (state.selectedIndex != pagerState.currentPage) {
            pagerState.animateScrollToPage(state.selectedIndex)
        }
    }
}
```
## MainContentViewModel.kt
```kotlin:MainContentViewModel.kt
data class MainContentState(
    val selectedIndex: Int = 0,
    val itemCount: Int = 10
)

sealed interface MainContentAction {
    data class ClickTab(val index: Int): MainContentAction
}

class MainContentViewModel: ViewModel() {

    private val _state = MutableStateFlow(MainContentState())
    val state = _state.asStateFlow()

    fun onAction(action: MainContentAction) {
        when (action) {
            is MainContentAction.ClickTab -> clickTab(action.index)
        }
    }

    private fun clickTab(index: Int) {
        _state.update {
            _state.value.copy(
                selectedIndex = index
            )
        }
    }
}
```
## MainActivity.kt
```diff_kotlin:MainActivity.kt
+    val viewModel by viewModels<MainContentViewModel>()
+    val state by viewModel.state.collectAsState()
+
+    MainContent(
+        modifier = Modifier.padding(innerPadding),
+        state = state,
+        onAction = viewModel::onAction
+    )
```

# 動作イメージ
![Screen_recording_20250227_150552-ezgif.com-video-to-gif-converter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115846/3b0089ed-ffa1-454e-8dc0-320625ac7770.gif)