OmniAICreator/Qiita-1.07M huggingface dataset:
AWS GuardDutyとは？初心者でもわかる使いこなしガイド


# はじめに

クラウドセキュリティは、現代のビジネスにおいてますます重要になっています。特にAmazon Web Services（AWS）を利用する企業にとって、セキュリティ対策は欠かせません。そこで登場するのが **AWS GuardDuty（ガードデューティ）** です。

この記事では、GuardDutyについて初心者の方にもわかりやすく説明し、効果的な使い方を紹介します。

## GuardDutyとは？

**AWS GuardDuty**は、AWS環境内の脅威を見つけるためのサービスです。
このサービスはマネージド型で、AWSアカウントやインフラ全体を24時間365日監視し、怪しい活動や脅威をリアルタイムで検出します。
機械学習や異常検知、最新の脅威情報を活用して、セキュリティインシデントを早く見つけるのに役立ちます。

## GuardDutyの主な機能

1. **脅威の検出**
   - 不正なAPI呼び出しや怪しいネットワークの動きを自動で見つけます。
   - マルウェアの通信や異常なログイン試行など、さまざまな脅威を特定します。

2. **継続的な監視**
   - AWSアカウント全体を常に監視し、リアルタイムで脅威を検出します。

3. **最新の脅威情報**
   - AWSや他の情報源から得た最新の脅威情報を使って、より正確に脅威を識別します。

4. **簡単な設定と管理**
   - 数クリックでGuardDutyを有効にでき、複雑な設定は不要です。
   - 他のAWSサービス（例えば、AWS Security HubやAmazon CloudWatch）と連携できます。

## GuardDutyのメリット

- **コスト効率**: 使用した分だけ支払う従量課金制なので、初期費用がかかりません。
- **スケーラビリティ**: AWSインフラに自然に組み込まれ、大規模な環境でも対応できます。
- **専門知識不要**: セキュリティの専門知識がなくても、効果的にセキュリティを監視できます。
- **迅速な対応**: 脅威を早く見つけて、素早く対応できます。

## GuardDutyの導入手順

### 1. GuardDutyを有効にする

1. **AWSマネジメントコンソールにログイン**します。
2. **GuardDutyのダッシュボード**に移動します。
3. 「**GuardDutyを有効化**」ボタンをクリックします。
4. 必要に応じて、複数アカウントの設定やデータソースのカスタマイズを行います。

### 2. アラートの確認と対応

- GuardDutyが見つけた脅威は「**検出結果**」としてダッシュボードに表示されます。
- 各結果には、脅威の種類、影響を受けるリソース、推奨される対応策が記載されています。
- Amazon CloudWatchやAWS Security Hubと連携させると、アラートの自動化や統合管理ができます。

### 3. 継続的な監視と改善

- 定期的にGuardDutyのダッシュボードを確認し、新しい脅威や傾向を把握します。
- 検出結果を基に、セキュリティポリシーやインフラを改善します。
- 必要に応じてGuardDutyの設定を調整し、検出精度を高めます。

## GuardDutyの活用事例

### 1. 不正アクセスの検出

GuardDutyは、不正なIPアドレスからのログイン試行や、通常とは異なる地域からのアクセスを見つけます。
これにより、不正アクセスを早く発見し、被害を減らすことができます。

### 2. マルウェアの通信の監視

インスタンスから怪しいドメインへの通信があった場合、GuardDutyはこれを検出してアラートを出します。
マルウェア感染を早期に発見し、対応することが可能です。

### 3. 内部脅威の検出

内部ユーザーによる不正な活動やデータの不正転送など、内部からの脅威もGuardDutyが見つけます。
これにより、内部のセキュリティを強化できます。

## GuardDutyの料金体系

GuardDutyは、使用量に応じて料金が発生する従量課金制です。
主な料金要素は以下の通りです：

- **脅威検出**: 分析したイベント数に基づいて課金されます。
- **データソースの利用**: VPCフローログ、AWS CloudTrailイベントログ、DNSログの解析に対して料金がかかります。

詳細な料金情報は[AWS GuardDutyの公式ページ](https://aws.amazon.com/jp/guardduty/pricing/)をご覧ください。

## まとめ

AWS GuardDutyは、AWS環境内で強力な脅威検出を行うサービスで、初心者でも簡単に導入・運用できます。
機械学習や最新の脅威情報を活用して、継続的なセキュリティ監視を実現し、企業のセキュリティ体制を強化します。
クラウド環境の安全性を高めるために、ぜひGuardDutyの導入を検討してください。

# 参考リンク

- [AWS GuardDuty 公式ページ](https://aws.amazon.com/jp/guardduty/)
- [GuardDutyのドキュメント](https://docs.aws.amazon.com/ja_jp/guardduty/latest/ug/what-is-guardduty.html)
- [AWS Security Hubとの連携](https://docs.aws.amazon.com/ja_jp/guardduty/latest/ug/guardduty-securityhub.html)

# さいごに

クラウドセキュリティは常に進化しています。AWS GuardDutyを活用することで、最新の脅威から守られ、安心してクラウドサービスを利用できます。セキュリティ対策を強化し、ビジネスの成長を支えるために、GuardDutyの導入をぜひご検討ください。

---

---
### 会社紹介

**株式会社 Mosaica**  
最先端テクノロジーで社会課題を解決し、持続可能な未来を創造する IT カンパニー。
AI ソリューション、クラウド統合、DX 推進、経営コンサルティングなど包括的なサービスでビジネス変革を支援しています。  

詳しくは [公式サイト](https://mosaica.co.jp/) までお気軽にご相談ください。
公式サイト： https://mosaica.co.jp/
OpenCVで写真を線画化してみた

# はじめに
こんばんは。
MYJLab Advent Calendar 2024の6日目を担当する宮治研3年の水野です。
これを機に何か新しいことをやってみようかな～と思っているうちにあっという間に自分の番が回ってきてしまいました。。計画力どうにかしたいです。(笑)
そんなわけで、先日テックプレゼンで発表した「OpenCVで写真を線画化してあそぼう」というテーマで紹介させていただきます！
3年生の皆さんはこんなのやってたな～くらいで読み飛ばしてもらえればうれしいです。

# 用意するもの
- Google Colaboratory
- 好きな画像ファイル

# コードの説明
## 1. ライブラリ等を読み込む
```
import numpy as np
import cv2
from google.colab import files
from google.colab.patches import cv2_imshow  # 画像を表示するために追加

# ファイルをアップロード
uploaded = files.upload()
```
cv2はOpenCVのことです。

## 2. 一旦カラーで写真を確認してみる
```
# カラーで読み込み
img = cv2.imread('hachi.jpg')

# 出力画像のサイズを小さくする
# 幅と高さを1/3にリサイズ
resized_img = cv2.resize(img, (img.shape[1] // 3, img.shape[0] // 3))  # img.shape(高さ, 幅, 色チャンネル数)

print('------')
print('カラー')
cv2_imshow(resized_img)
```
![hachi.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3897313/b2e54565-9a21-96ff-c205-b2fb1dd9da4b.jpeg)

img = cv2.imread('hachi.jpg')この部分のファイル名は自分の好きな画像に置き換えてください。
ちなみにこれは、うちのはちわれちゃんが青森旅行に行った時の写真です。

## 3. 白黒にする
```
# グレースケールで読み込み
img2 = cv2.imread('hachi.jpg', cv2.IMREAD_GRAYSCALE)
resized_img2 = cv2.resize(img2, (img2.shape[1] // 3, img2.shape[0] // 3))
print('------')
print('グレースケール')
cv2_imshow(resized_img2)
```
![gray.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3897313/ece81cc9-cc38-41d9-196e-77121d07cfec.png)
白黒になりました。これはこれでかわいいですね。

## 4. 画像処理を行う
```
im = img2

# 閾値設定による二値化処理
Threshold = 120
im[im < Threshold] = 0
im[im >= Threshold] = 255

# 特徴量フィルター生成
kernel = np.array([[0, -1, 0],
                   [-1, 4, -1],
                   [0, -1, 0]], dtype=np.uint8)

# 膨張処理
dilation = cv2.dilate(im, kernel, iterations = 3)
resized_dilation = cv2.resize(dilation, (dilation.shape[1] // 3, dilation.shape[0] // 3))
print('------')
print('膨張処理')
cv2_imshow(resized_dilation)
```
- 画像の各ピクセルの輝度値をしきい値に基づいて白または黒に変換します。今回は120という値を基準に、120未満をすべて黒に、120以上をすべて白に設定しています。​
- kernel部分では、画像の輝度の変化が大きい（つまりエッジにあたる）部分を強調します。​今回は中心のピクセル値を4倍し、周囲のピクセル値を引いています。
- 膨張処理​はエッジを太くする操作です。​iterationsの値を増やして繰り返すことで、線がより濃くなります。

## 5. 完成
```
# 差分処理(膨張処理を行ったデータからグレースケール画像を引く)
Difference = dilation - im

# 色反転
Difference[:, :] = 255 - Difference[:, :]

# リサイズした画像を表示
resized_difference = cv2.resize(Difference, (Difference.shape[1] // 3, Difference.shape[0] // 3))
print('------')
print('差分処理')
cv2_imshow(resized_difference)
```
![finish.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3897313/455f20ad-8ca4-dff0-9884-bbb5b1e80716.png)
​膨張処理を3回繰り返したことで、かなり綺麗に線画化することができました。
画像によって明るさなどが異なるので、お好きな画像に合ったしきい値やiterationsの値に変えてもらえれば綺麗に線画化できるかと思います。

# おわりに
最後まで読んでくださりありがとうございました！
よかったら好きな画像に置き換えて遊んでみてください！

# 参考文献
https://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_tutorials.html

https://qiita.com/KengoKudou/items/b101cef271cc17fddd2d
【Jetpack Compose】LazyColumnの上部に要素を固定させてスクロールさせる方法

## やりたいこと

↓の動画の「Look for the book!」のように、上部にTextなどの要素を固定させたままリストをスクロールさせたい


<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308202/5c74630d-ce1e-0ccc-f29a-e2b930373a4e.gif" />


## 実現方法
以下のようにLazyColumn上にitemを定義して、その中に要素を指定するだけ。

```Kotlin
    @Composable
    private fun SampleList() {
        Scaffold(
            topBar = { TopBar() },
        ) { innerPadding ->
            LazyColumn(
                contentPadding = innerPadding,
            ) {
                item { //このitemカッコ内に固定したい要素を指定する
                    Text(
                        "Look for the book!",
                        modifier = Modifier.padding(start = 8.dp, top = 8.dp),
                        color = colorResource(id = R.color.book_orange),
                        fontWeight = FontWeight.Light,
                        fontSize = with(LocalDensity.current) { 23.dp.toSp() }
                    )
                }
                items() { 
                    // リスト表示
                }
            }
        }
    }
```

余談：ここらへん地味に詰まってたら、このやり方をつよつよの技術者が教えてくれました。
Raycastでおすすめの拡張機能"Google Chorome"

この記事はRaycast Advent Calendar 2024に参加しています。
昨日は [Nishii](https://zenn.dev/ystknsh) さんの「Fullstack Al Dev & Raycast Summit イベントレポート（2024-11-23開催）」でした。

## はじめに
Raycastは無数の拡張機能からユースケースにあったものを選んで入れていくほど便利になっていきます。今回は[Google Chrome Extension](https://www.raycast.com/Codely/google-chrome)を紹介します。

## 概要
Google Chrome Extensionを入れるとRaycast上でChromeを操作できるようになります。
主な機能を紹介します。

### Search History: 検索履歴を検索する
![Search History](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408705/676a27e2-a38b-8c24-25a6-dde4f089fef0.png)
上記のように検索履歴を検索することができます。僕はこれをよく使っています。最近開いたサイトを直接開いたり、昨日アクセスしたサイトを探したりします。Slackを開きながら最近見たPRを探して貼り付けるような他のアプリを使っているときに検索履歴の情報を使いたい時は特に便利です！(これを入れる前はChromeの検索履歴とアプリの往復が発生して面倒でした)

### Search Tabs: タブを検索する
![Search Tabs](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408705/e8521b69-8e25-b305-fefe-217344c9bb65.png)
他のアプリを開いていて特定のタブへ直接切り替えたいときにとても便利です。
`cmd + k`でタブを閉じることもできます。

### Search Bookmarks: Bookmarkを検索する
![Search Bookmarks](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408705/4ba6d10e-2721-ba3e-7855-505420aea3ec.png)
Bookmarkを探すときに便利です！
僕はQuicklinksをbookmarkのようにも使うのであまり使わなくなりました。

### New Tab: 新しいタブを開く
Raycast上で新しいタブを開くことができます。

### Create New Window: 新しいウィンドウを開く
Raycast上で新しいウィンドウを開くことができます。

## まとめ
Chrome Extensionは他のアプリを使いながらChromeのデータを参照したり必要に応じて飛べるところがすごく好きです。
特にSearch Historyが一番使っていておすすめの機能です。僕は使わないが他の人にとって便利な機能も合わせて紹介しました。

RaycastユーザーにはArcを使う人が多いと思うので貼っておきます。
ArcはRaycastとArcの開発元the Browser Companyがコラボして開発が始まったのもあって活発にアップデートされている印象です。Chrome Extensionより機能が充実している気もします。
[Arc Extension](https://www.raycast.com/the-browser-company/arc)
pythonの開発・実行テストをChatGPT先生にお願いしました。短文

・以下は旧いようです。(2025-01-05)





**pythonの開発・実行テストをChatGPT先生にお願いすることはいけない事?**

sympy。
mathml?
積分記号が現れて、見やすくてステキ。

日本語で。
結果の出力をお願いします。

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
日本語で。結果も出力して下さい。


#### 解答例

・以下は、与えられたコードの日本語での説明と改善されたバージョンです。
...(省略)

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
**コードをローカル環境で実行してみることをおすすめします。** 必要に応じて、コードの具体的な修正や実行手順についてお手伝いできますので、引き続きお知らせください！ ​
HULFT10 for zOS グレードについて

この記事は [**セゾンテクノロジー Advent Calendar 2024**](https://qiita.com/advent-calendar/2024/saison-tech) 7日目の記事です。
シリーズ2は [**HULFT10**](https://www.hulft.com/software/hulft-10) のエンジニアによる投稿をお届けします。

<h1>HULFT10 for zOSは2グレードになっています</h1>
おはようございます。<br>
タイトルの通りzOS版では初となる<strong>Enterpriseグレード</strong>と<strong>Standardグレード</strong>の2グレードに分けた提供になっています。<br>
何が違うのかを下記に記載します。

<h2>グレードの差異</h2>
今回zOS版でDEFLATE圧縮<sup>※1</sup>が実装されました。<br>
そのDEFLATE圧縮機能を利用するのに<strong>Enterpriseグレード</strong>が必要となります。<br>
いくつかの制限事項<sup>※2</sup>はありますが、今までと同じように圧縮方式から選択して利用できます。<br>
もちろん今までの機能で十分な場合は<strong>Standardグレード</strong>もあるのでユーザーさんが好きな方を選べます。<br>
<sup>※1Deflate（デフレート）とはLZ77とハフマン符号化を組み合わせた可逆データ圧縮アルゴリズム。<br>
フィル・カッツが開発した圧縮ツールPKZIPのバージョン2で使われていた。<br>
ZIPやgzipなどで使われている。1996年5月に RFC 1951 としてドキュメント化された。<br>ヘッダーやフッターをつけた zlib (RFC 1950) 形式や gzip (RFC 1952) 形式とともに使われる事が多い。
<br>参考サイト：https://ja.wikipedia.org/wiki/Deflate</sup><br>
<sup>※2ワークファイル転送は未対応やチェックポイント再配信およびチェックポイント再送は使用できない等</sup><br>

<h2>グレードの確認方法</h2>
現在利用しているグレードが分からない。<br>
確認したいときはHULFTユーティリティーの<strong>XRHULVER</strong>で確認できます。

<strong>Enterpriseグレード</strong>の場合下記の通り確認できます。
<strong>PRODUCT   : HULFT10 FOR ZOS-ENTERPRISE</strong>

<h2>終わりに</h2>
記事を書きなれていないいので見づらい記事と思います。<br>
HULFTの知識が浅い自分ですが、何か有益な情報をお伝えできればと思います。
Elixir 開発でよく使う Mix について。使い方と場面についてまとめておく

Mixコマンドの主な使い方と使用シーンについて説明します：

### 基本的なコマンド

1. **新規プロジェクト作成**
```bash
mix new プロジェクト名
```
新しいElixirプロジェクトを作成する時に使います。基本的なプロジェクト構造を自動生成してくれます。

2. **依存関係の管理**
```bash
mix deps.get      # 依存パッケージをダウンロード
mix deps.compile  # 依存パッケージをコンパイル
mix deps.update   # 依存パッケージを更新
```
プロジェクトの依存関係を管理する時によく使います。`mix.exs`に新しいパッケージを追加した後などに実行します。

3. **開発時によく使うコマンド**
```bash
mix compile  # プロジェクトをコンパイル
mix test    # テストを実行
mix format  # コードフォーマット
iex -S mix  # 対話型シェルでプロジェクトを起動
```

### 実践的な使用シーン

1. **新規プロジェクト立ち上げ時**
```bash
mix new my_app
cd my_app
mix deps.get
```

2. **テスト駆動開発（TDD）時**
```bash
mix test        # 全テストを実行
mix test --only name:test_name  # 特定のテストのみ実行
```

3. **本番環境用のリリース作成時**
```bash
mix release.init  # リリース設定ファイルを生成
mix release      # リリースビルドを作成
```

4. **コード品質管理時**
```bash
mix format      # コードフォーマット
mix xref        # コードの依存関係チェック
```

### 便利な機能

- `mix help [タスク名]` - 特定のタスクの詳細なヘルプを表示
- `mix do` - 複数のタスクを連続実行（例：`mix do deps.get, compile`）
- `mix clean` - コンパイル生成物を削除してクリーンな状態に

### 使用上のポイント

- 開発の初期段階では `mix new` と `mix deps.get` が頻繁に使用されます
- 日常的な開発では `mix test` と `mix compile` が最も使用頻度が高いです
- コードレビュー前には必ず `mix format` を実行することをお勧めします
- 本番デプロイ時は `mix release` を使用してリリースビルドを作成します

これらのコマンドを使いこなすことで、Elixirでの開発効率が大幅に向上します。
Elixirのチートシートを作ろう#5 enumその1

# 1. OverView
…Enumには、戦車道に必要な事が全部詰まってます、要するにチェスト。（薩摩ホグワーツ悩）

５日で、さくっと初級全部を終わらせる予定だったんですが、諦めました。
チートシートなんですが、ここ、コピペで終わらせると後悔しそうな気がする。誰が？俺がだ。
ぶっちゃけ、みなさん、ラムダ式とかでほかの言語で経験済みでしょ、とか思うんですが、くどくやります。

さて、ちょっと話が前後しますが、enumには、匿名関数（anonymous function)が使われます。
応用範囲もすっごく広がるのですが、これでサンプルコードがわかりにくくなってみます。

なので例によって、説明順を変更します。
訳が分からん文章が続きますが、例まで待ってください。
例みたら「くどいんだよ、馬鹿野郎」とお怒りになると思います。

# 2. まずは解説

他の言語でも出来るやい！みたいな議論は楽しいので、Xでやるとして、関数型プログラミングの
パラダイムでは、「関数の引数に関数を渡す」と言うことをやります。

Enumの関数によっては、関数を引数にとり、一定の条件で、コレクションから抽出した要素に対して
引数でとった関数で処理します。

…何を言ってるんだから日本語にするとわからんのですが、実際に見ると、簡単です。

まず、操作対象のコレクション(list型)を作成します。
testlist=[1,2,3,4]

...ハンガリー記法とかあったね、やらないよ。
さて、このtestlistの各要素に対して、関数を適用するEnumの関数を選びましょう。

map/2を使用します。
ヘルプを見てみましょう
```
iex(102)> h Enum.map/2

                            def map(enumerable, fun)

  @spec map(t(), (element() -> any())) :: list()

Returns a list where each element is the result of invoking fun on each
corresponding element of enumerable.

For maps, the function expects a key-value tuple.

## Examples

    iex> Enum.map([1, 2, 3], fn x -> x * 2 end)
    [2, 4, 6]

    iex> Enum.map([a: 1, b: 2], fn {k, v} -> {k, -v} end)
    [a: -1, b: -2]

```

第二引数が
    element() -> any()となってますが、これから、二つを解説しますわ。

以下の例では、第一引数に、上で定義したtestlist、第二引数に「匿名関数」fn x -> x * 2 endを
引き渡します。

```
iex(103)> Enum.map( testlist, fn x -> x * 2 end)
[2, 4, 6, 8]
```

testlistの各エレメントが、「匿名関数」 fn ～ endまでに引き渡されてます。
そう、fn x -> x * 2 endと言う関数自体が、Enum.mapに引き渡されて、毎回、呼び出されてます。

つまり、Enum.map関数が、testlistから、一個ずつ要素を取り出し、fn x -> x * 2 endに渡して
行き、処理させて、結果をlistで返します。

じゃ、引数をmapにしてみましょう。


```
iex(1)> testmap=%{c: 3, a: 1, d: 4, b: 2}
%{c: 3, a: 1, d: 4, b: 2}
iex(2)> Enum.map( testmap, fn({key, value}) -> {key, value} end)
[c: 3, a: 1, d: 4, b: 2]
iex(3)> Enum.map( testmap, fn({key, value}) -> {key, value + 5} end)
[c: 8, a: 6, d: 9, b: 7]
```

…mapがlistになってるのに注意してください。上に戻り値:: list()と書いてありますね。

# 3. 本日のチートシート

匿名変数の際に、作りますね。
Nerves system, Buildroot のビルドを早くする tips

### どのくらい早くなるか

私は Nerves システムのビルドに AMD Ryzen 9 5950X 16-Core Processor のマシンを使っており、紹介する tips を使わないとフルビルドには 15 分程かかります。（ビルド内で走るダウンロードすべきソースが全て手元にダウンロード済みでも、それだけかかります。）

それが本設定で以下になります。

#### cchace 作成前❗

```
real    6m12.237s
user    92m27.004s
sys     19m55.984s
```

Yay!

#### cchace 作成後❗❗❗

```
real    2m58.663s
user    14m10.062s
sys     4m58.480s
```

Yay!Yay!Yay!

### この結果をもたらす tips

```
BR2_CCACHE=y
BR2_CCACHE_DIR="$(NERVES_DEFCONFIG_DIR)/.nerves/buildroot-ccache"
BR2_CCACHE_INITIAL_SETUP="--max-size=0"
BR2_JLEVEL=0
BR2_PER_PACKAGE_DIRECTORIES=y
```

を nerves_defconfig に追加して、 `make -j` でビルドしてみてください。
※時間計測をする場合は `time make -j`

#### 注意点

この tips を利用してビルドをすると、メモリが足りなくなって OOM Killer にビルドプロセスが殺されるかもしれません。その場合は `BR2_JLEVEL` と `make -j args` を調整してやる（使用するコアを減らす）必要があります。

#### BR2_CCACHE* について

ヘルプには以下の記載があります。

> This option will enable the use of ccache, a compiler cache. It will cache the result of previous builds to speed up future builds.

コンパイル時にキャッシュを作りそれを利用してビルドの高速化をはかる Ccache を利用するようになるようです。

> Ccache is a compiler cache. 

https://ccache.dev/

#### BR2_JLEVEL について

> Number of jobs to run simultaneously. If 0, determine automatically according to number of CPUs on the host system. 

ビルド時に用いるホストマシンの CPU コア数を設定できるようです。 `0` 指定時はいい感じ（全部使う）にしてくれるはずです。

#### BR2_PER_PACKAGE_DIRECTORIES について

最後の文に `experimental feature` と記載があります。

>  This option will change the build process of Buildroot package to use per-package target and host directories.
>
> This is useful for two related purposes: 
> - Cleanly isolate the build of each package, so that a given package only "sees" the dependencies it has explicitly expressed, and not other packages that may have by chance been built before.
> - Enable top-level parallel build.
>
> This is labeled as an experimental feature, as not all packages behave properly with per-package directories. 

このオプションを

- 有効にしない場合、 Buildroot はパッケージをひとつずつビルドしていきます。
- 有効にする場合、 Buildroot はパッケージを並行にビルドしていきます。

なので、有効にすると早くなります。

### この tips はどこから

Elixir slack の #nerves チャンネルで Abelino Romo が紹介してくださいました

が、これは [Lawik さんが立ててくださったフォーラムのスレッド](https://elixirforum.com/t/what-are-your-best-workflow-hacks-in-nerves/64799) で Alex McLain さんが回答してくださっている内容です。

Abelino さんは Alex さんがファウンダーの [redwire labs](https://redwirelabs.com/) の会社で共に働いている方なので２人がいかに効率よく Nerves をビルドするかを調べており、その知見を共有してくださったということなのだと思います。

※ Alex さんはファウンダーですがゴリゴリのエンジニアです。

### 参考

Lawik さんが立ててくださったフォーラムのスレッド

https://elixirforum.com/t/what-are-your-best-workflow-hacks-in-nerves/64799

Alex さんの会社 redwire labs の記事

https://redwirelabs.com/blog/fast-builds-low-price

以上です！
Rustacean見習い始めました🦀🔰

# 概要

はじめまして、bonusun(ぼぬすん)です。
技術者として何か誰にも負けないものを持ちたいと思い、
Rustaceanになろうと思いました。
(今後、Rustの代替言語がすぐでなければいいけど。。。)

## やること

以下がやることです。
ゴールがまだふわふわしているので、具体的になったらまた更新します。

1. Rustについて勉強したことを記事としてアウトプットします。
    1. https://google.github.io/comprehensive-rust/ja/
    1. https://learn.microsoft.com/ja-jp/training/paths/rust-first-steps/
2. ネットに転がっているRust関係の質問・問題に対して回答する
    2. 最初は難しいと思うので、簡単そうなやつを選ぶかも
3. Rust関係の記事で100いいねをもらう

## 最後に

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333125/ec5e97b0-7953-29a9-a697-51b97b13a1e5.jpeg width=80%>
ＬＣＤカラーデイスプレー買いました　＆　結線

大須（名古屋：当方　名古屋市熱田区）　アメ横ビル２Ｆの「ボントン」によらせて頂きました。
買ったのが以下　1.8インチTFT LCD 解像度　160*128 カラーディスプレー　ST7735S　Voc　3.3 or 5V
インターフェースの8ピン配列　接続を調査すると以下の様である。
参考サイト
https://learn.adafruit.com/1-8-tft-display/python-wiring-and-setup

GND　電圧の基準　0V　アースと似たようなもの
　ラズパイのGNDピン　9番ピン　●
Vcc　電源（3.3V - 5V） 
　ラズパイの電源　3.3V　1番ピン　●
SCK　I2Cクロック信号
　ラズパイの　GPIO11　SCLK 　23番ピン　●
SDA　I2Cデータ信号
　ラズパイのMOSI　GPIO10　19番ピン　●
RES　リセットピン（アクティブロー）
　ラズパイのGPIO 24　18番ピン　●
DC　 データ/コマンド制御ピン
　ラズパイのGPIO 25　22番ピン　●
CS　 チップセレクト
　ラズパイのCE0　GPIO8　24番ピン　●
BLK  バックライトコントロール
　 ラズパイの電源　3.3V　17番ピン　●
  　  
![IMG_0008[1].jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/433305/3d4ad99c-1e52-0b8d-3d9c-9dde10c33bdd.jpeg)

RPZ-IR-Senserの湿度、温度、気圧、照度の情報をこれに表示していくぞ。
1号機ではピンが無いので2号機で1号機のパイソンを実行して表示させてみよう。

i2cとSPIの通信設定が必要なようだ。
LCDの制御はSPI通信のようだ。
エンジニアのコミュニケーションについて

# はじめに
エンジニアといえば、寡黙で、多少正確に難があり、でも結果はちゃんとだすみたいなイメージがありました。
でもそれじゃ世の中やっていけない。
どんなにいい意見があってもチームで行動する以上、伝達できないと何もならないです。どんなにいいものでも知られなければゴミです。
さらに、エンジニアもクライアントと話さなきゃいけないし、PM相手にもちゃんと会話をしないといけない世の中ですよね。
調査タスクがあって正しく伝えられなければ意味がないですよね。

# 講座について
- タイトル
  「エンジニアのための「コミュニケーション」講座」
- 特徴
  この講座は、IT開発現場でお客様や事業企画に対して仕様説明や障害報告を行う新入社員や若手、中堅社員に最適です。コミュニケーションの基礎を学び、信頼関係を築く方法や効果的な伝え方を身につけることで、職場での対話がスムーズになります。より良いコミュニケーションを実現し、職場での成功を目指しましょう！

 - 学べるスキル
   `信頼関係構築の技術`、`効果的な伝え方`、`論理的な資料作成`、`聞き方と反応の技術`

https://www.udemy.com/course/communication-skills-for-engineers

# TL;DR
- エンジニアなら脳死で一度受けておいて良いコミュニケーションの基本
- 個人的には、なんとなくおもっていたことが言語化されて肯定されたのでいい機械だった
- やっぱりリアルコミュニケーションと飲み会って大事だよね


# 講座概要

- 信頼関係構築
  - ラポール構築
  - ラポール破壊

- 伝える
  - 伝える相手の理解
  - 伝える内容の論理構成
  - 伝えるための資料作成
  - 話し方

- 受け取る
  - 聞き方
  - 異なる意見を言われたときの対応

# 講座を受けておもったこと
- ラポールは、会話の土台で諸刃の剣。盃を交わす、雑談をするのは大事。リモートじゃ厳しいなと
- 話すということは相手がいて、心がある。正しさだけが全てを決める世界ではないし、伝えられなかったものがあったらそれは存在しないのと一緒。相手が受け入れやすい形で順序立てて説明しないといけない。

# どんな人におすすめか
- エンジニアをしていて他の人と会話をしているが、うまく伝わる気がしない人。相手にはてなを浮かべられている人
- エンジニアと会話しているが、うまく何をいっているかわからず、エンジニアの話し方を理解したい人
- 何となく会話がうまく噛み合わない気がしている人

# 最後に

[12/9]
アドベントカレンダーで書きましたがちょうど、割引セールを今日までしています。2kなのでとりあえず聞くだけで一度自分の中でだいぶ腑に落ちる部分が多いです。
とはいえ、新しいってことばかりではないので注意が必要ではありますが...
セール中価格なら全然価値ありです。
(リンクだけです)「カスチリアノの定理(Castigliano's method)」を調べた。




# wikipedia

https://en.wikipedia.org/wiki/Castigliano%27s_method

https://ja.wikipedia.org/wiki/%E3%82%AB%E3%82%B9%E3%83%81%E3%83%AA%E3%82%A2%E3%83%8E%E3%81%AE%E5%AE%9A%E7%90%86

カスチリアノの第2定理＜wikipedia

https://ja.wikipedia.org/wiki/カスチリアノの定理#カスチリアノの第2定理


# 参考

https://www.google.com/search?q=dummy+load+Castigliano%27s+method&sca_esv=1552668f5b995b5e&rlz=1CAUHAM_enJP1105&sxsrf=ADLYWILPeEBd9D-bbsT9hpGUJEeqrl4rQA%3A1733376225713&ei=4ThRZ5qVK4Ck2roP3obl2QI&ved=0ahUKEwjaicjR8Y-KAxUAklYBHV5DOSsQ4dUDCA8&uact=5&oq=dummy+load+Castigliano%27s+method&gs_lp=Egxnd3Mtd2l6LXNlcnAiH2R1bW15IGxvYWQgQ2FzdGlnbGlhbm8ncyBtZXRob2QyCBAAGIAEGKIESPIQUFBYgApwAXgBkAEAmAHhAaAB7wKqAQUwLjEuMbgBA8gBAPgBAfgBApgCA6ACmAPCAgoQABiwAxjWBBhHwgIHEAAYgAQYE5gDAIgGAZAGCpIHBTEuMS4xoAeTBA&sclient=gws-wiz-serp

https://docs.sympy.org/latest/modules/physics/continuum_mechanics/beam.html

https://docs.sympy.org/latest/modules/integrals/integrals.html#module-sympy.integrals

https://www.delftstack.com/howto/python/python-partial-derivatives/
新卒エンジニア１年目が考える、楽しいプレゼン

:::note info
この記事は、[LITALICO Engineers Advent Calendar 2024](https://qiita.com/advent-calendar/2024/litalico)シリーズ１の７日目の記事です！
:::

# はじめに
皆様こんにちは！
今年の4月に入社したエンジニアの@ryunosuke_sakoです！
最近、業務内外で発表やプレゼンを行うことが多くなってきています。
そこで本記事では、本番前に手のひらへ人の字を何十回も書くほど緊張しいな私が、いつもプレゼンの準備で意識していることや、考えていることについて書いてみようと思います！

# プレゼンとは何か
本題へ入る前に、そもそもプレゼンとは何かについて改めて考えてみます。
プレゼンはプレゼンテーションの略語であり、プレゼンテーションを調べると以下のような情報が出てきます。

>プレゼンテーション（英: presentation）は、英語で、「表現」「紹介」「提示」などの意味。 情報伝達手段の一種。 相手に情報を提示し、理解を得るようにするための手段。 特に視覚情報が重視され、視覚情報伝達手段の一種と定義されている場合もある。

（引用：https://ja.wikipedia.org/wiki/%E3%83%97%E3%83%AC%E3%82%BC%E3%83%B3%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3）

つまり、プレゼンの目的は発表そのものではなく**情報伝達**にあるということです。
私も、事前に準備していたものが本番の雰囲気や流れにマッチしていなかった場合に、修正できるだけの「あそび」を持たせることを意識しています！

# 楽しいプレゼン -準備編-
準備編では、私がプレゼン準備をする際に意識している３つの要素について、それぞれ準備しているものや意識していることついて詳しく記載します！

### 1. 資料（スライドや動画）
デザイン性に富んだ資料を作ることが苦手なので、口頭で説明する内容を阻害しないかつ補足するために、少なめの単語や画像、グラフなどを配置するだけにしています。
どうしても資料として一定の文量を記載する必要がある場合は、その次に要点をまとめた別資料を配置したり、色やサイズで見て欲しい部分を強調したりしています！

![スクリーンショット 2024-12-06 16.47.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641629/1cdb44ea-4edb-045d-5883-74d848806c3e.png)
（このようなスライドを出しつつ、口頭で説明しています）

### 2. 台本（話す内容や時間配分）
話す内容を一言一句用意しておくと、本番で間違えたときに慌てて総崩れしてしまうので、開始と終了の挨拶、各項目の繋ぎ方のみ準備しておいて、メインの部分は概要をメモするだけにしています。
どの内容も想定している量より少し多めに練っておくことで、プレゼン本番の雰囲気に合わせて説明をより詳しくしたり、質問への回答の準備もすることができます！

### 3. 表現（声のトーンや身振り手振り）
声のトーンや身振り手振りなどは、メリハリをつけて強調したい場所では大きく、それ以外は抑えられるように、練習の段階からどこでどのような表現をするか練るようにしています。
特に、首の動きや目線は一人や少人数で練習していると小さくなりがちなので、本番の状況を想定したロールプレイをしたり、自分の発表練習を録画して見直したりをして本番との差異を無くすようにしています。
また、本番では多少表現が小さくなってしまいがちなので、大きい表現を練習するときには気恥ずかしくなるくらいがベストです！

# 楽しいプレゼン -本番編-
本番編では、緊張しいな私がプレゼン本番に意識していることについて、その理由とともに記載していきます！

### 緊張を忘れようとしない
緊張すると普段しないようなミスをしてしまったり、意識していない行動をとってしまったりすることがあります。
以前は緊張することが問題だと思って考えないように勤めていたのですが、最近は、緊張を普段では味わえないものと思って楽しむことで、ネガティブではなくポジティブなものとして捉えるようにしています。
今でも本番前は手汗が止まりませんが、緊張とともに高揚感を持って臨むことができるようになりました！

### 一息を欠かさない
緊張した際の変化は人によって様々ですが、私はものすごく早口になります。
なのでこの対策として、「一息」を意識的に各タイミングで入れるようにしています。
例えばプレゼンの項目の繋ぎ目であったり、盛り上がる流れの後であったり。気持ちが前のめりになりそうなタイミングで必ずこの「一息」を入れることで、焦ってミスをして更に焦って…というループに嵌ってしまうことを減らしています！

### 聞き手を意識する
プレゼン本番、緊張して大人数の前に立つとどうしても「発表し切ること」がゴールになってしまいがちです。
そういうときには、聞き手の方達の顔や目をしっかり見るようにしています。
リアクションや相槌を見ることができると、「発表すること」から「聞いてもらうこと」に意識がフォーカスしていくので、しっかり聞き手の反応を踏まえての発表内容や表現にすることができます！

# おわりに
改めて自分のプレゼンに対する考え方を書き出してみると、余裕を持たせた構成や緊張への対策で、リラックスした本番を迎えるための準備に対して力を入れていることに気が付きました！
プレゼン道はまだまだ奥が深く、人の数だけテクニックや手法があります。皆様もぜひ、楽しいプレゼンライフをお過ごしください！

ここまで読んで下さった皆様、アドカレへの参加にご協力頂いた皆様、本当に有難うございます！
明日のアドベントカレンダー８日目は、
- @kamesennin さん
- @michiokay さん
- @machi_machi さん

です！引き続き、お楽しみください！
AWS StepFunctionsでJSONataを使えば簡単に日付取得ができる

## はじめに

[フューチャー Advent Calendar 2024](https://qiita.com/advent-calendar/2024/future)の8日目です。

GlueやDynamoDBを用いたデータ分析のためのワークフローを、Step Functionsで構築しようとしていたところ、どうやらちょうどアプデが来ていて色々便利になっていました。


## アップデートについて

主に2つのアップデートがあったようで、
- 変数が使えるようになった
- JSONataが使えるようになった

今回は、2つ目について取り扱います。
1つ目に関しては他の方の記事を参考にしてください。かなり便利になったみたいです。

https://dev.classmethod.jp/articles/step-functions-variables/

https://docs.aws.amazon.com/ja_jp/step-functions/latest/dg/workflow-variables.html

## 本題

今回は、Step FunctionsでDynamoDBのS3エクスポートを行う際に、出力先のS3パスに日付情報をつける場合を想定します。

![スクリーンショット 2024-12-06 164342.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3947768/08c733fb-34ec-e847-9b05-4f72ea9f8e83.png)

このステートに対して、日付情報を渡してあげたいわけです。

### JSONateで日付を取得

JSONataで日付を取得するには
```
$fromMillis($millis())
```
`$millis()`が現在の経過ミリ秒で、`$fromMillis()`で日時に変換しています。これはUTC時刻なので注意してください。

```
$fromMillis($millis(), '[Y0001][M01][D01]', '+0900')
```
これで、時差を考慮したうえでかつ`YYYYMMDD`の形式になります。

JSONataの日時関数に関する公式ドキュメント

https://docs.jsonata.org/date-time-functions

JSONataの出力が確認できるページ

https://try.jsonata.org/

### Step Functionsに導入

これを、Step Functionsで書いてステートに渡してあげます。

目的のステートの手前に、日付を渡してあげるためのpassステートを置いて"出力"に定義してあげます。
JSONateを扱うには、`"{% %}"`で囲ってあげる必要があります。

![スクリーンショット 2024-12-06 172821.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3947768/a53a08df-84ee-8c71-6334-43f95bf49bfe.png)

S3エクスポートの引数に、`"S3Prefix": "{% $states.input.date_prefix %}"`と定義してあげるとpassステートの出力で定義した値を受け取ることができます。

![スクリーンショット 2024-12-06 173251.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3947768/e429419d-4edd-cce7-3b84-469d9df4a1ec.png)

実際に実行してみた結果です。
ステートの入力のS3Prefixの値が、想定通り`YYYYMMDD`形式の日付になっています。
（テーブル名が架空なので、実行自体は失敗しています。）

![スクリーンショット 2024-12-06 173505.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3947768/c1a60fab-fdb8-5871-601b-6e724ea0b8fb.png)


## おわりに

今回はたまたまアップデートが来ていた内容に触れる機会があったので記事にすることができました。
以前まではここまで柔軟に日時を扱えずLambdaを使うケースが多かったようで、今回僕はちょうど恩恵を受けることができてラッキーでした。

最初アップデートに気づかず作業していた時は、他の記事の通りやっても変数の受け渡しがうまくいかず苦労していました。
自分が使うAWSサービスのアップデート情報はキャッチアップしておかないといけませんね。

## 参考にした記事

https://qiita.com/tseigo/items/e7deb8d6d4902a4aef30

https://aws.amazon.com/jp/blogs/compute/simplifying-developer-experience-with-variables-and-jsonata-in-aws-step-functions/
re.subで柔軟に文字列置換 #Python

Pythonでの文字列置換といえば`replace`ですよね。
99%の場面ではこれで問題ないですが、ごく稀に特殊な文字列置換をしたい場面が発生します。
置換対象の文字列の内容によって置換する文字列を変えたいときに役に立つのが`re.sub`です。

https://docs.python.org/ja/3/library/re.html#re.sub

長いことPythonを使ってきましたがそんなことができることを知らなくて衝撃を受けたので記事に残しておきます。

いくつか具体的なパターンを見ていきましょう。
以下のパターンでは全て`<>`で囲まれた部分を置換していきます。
使用している正規表現`<.*?>`は`<>`で囲まれた部分に最短一致します。

## 置換対象文字列から生成

置換後の文字列がマッチした文字列から関数で生成できる値なら、以下のように置換できます。

```python
def repl(match_obj):
    # マッチした文字列の前後の`<>`を取り除く
    match_str = match_obj.group(0)[1:-1]
    idx = int(match_str)
    if idx % 15 == 0:
        return 'FizzBuzz'
    elif idx % 3 == 0:
        return 'Fizz'
    elif idx % 5 == 0:
        return 'Buzz'
    else:
        return match_str

text = '''when 1 then <1>,
when 3 then <3>,
when 5 then <5>,
when 15 then <15>'''

print(re.sub('<.*?>', repl, text))
```

出力は以下になります。
関数`repl`で`<>`内の数値によって置換内容を変えています。

```
when 1 then 1,
when 3 then Fizz,
when 5 then Buzz,
when 15 then FizzBuzz
```

## 辞書を使って置換

辞書でもリストでもいいですが、置換の関数に引数を渡したい場合のパターンです。
置換に使う関数だけを`re.sub`に渡すのでそのままだとマッチしたオブジェクトしか引数として受け取れません。
ラムダ式で引数を渡すことができます。

```python
def repl(match_obj, dct):
    # マッチした文字列の前後の`<>`を取り除く
    match_str = match_obj.group(0)[1:-1]
    return dct[match_str]

user_info = {
    'name': 'John',
    'age': '25',
    'country': 'Japan'
}
text = '''My name is <name>.
I am <age> years old.
I am from <country>.
Please call me <name>.'''

print(re.sub('<.*?>', lambda x: repl(x, user_info), text))
```

```
My name is John.
I am 25 years old.
I am from Japan.
Please call me John.
```

## 日時のフォーマットを置換

さっきとやっていることは同じですね。
ラムダ式で渡しています。

```python
from datetime import datetime

def repl(match_obj, dt):
    # マッチした文字列の前後の`<>`を取り除く
    match_str = match_obj.group(0)[1:-1]
    return dt.strftime(match_str)

dt_now = datetime(2024, 12, 8, 9, 10, 11)
text = '''The time now is <%-H:%M:%S>.
Today is <%A>, <%B %-d>th.'''

print(re.sub('<.*?>', lambda x: repl(x, dt_now), text))
```

`{}`で囲んでいれば`format`で普通にできるのでそっちがいいと思いますが、自力でも頑張れます。
`%-H`とかで0埋めしない表記ができますが、ここがハイフンでいけるかは環境に依存するようです。

```
The time now is 9:10:11.
Today is Sunday, December 8th.
```

## おわりに

今回挙げた例だと実感しきれないかもしれないですが、`re.sub`を使うことでコードがシンプルになった経験があったのでその感動を伝えたかったというただそれだけです。
【クソアプリ】瞬き耐久チャレンジを作った

本記事は[クソアプリアドベントカレンダー2024](https://qiita.com/advent-calendar/2024/kuso-app)の記事です！

めでたい10周年ということで参加してみましょう。🎉

ということで、

## 瞬き耐久アプリつくった

瞬き、していますか・・・？
あまりにも無意識にしているので、いざ言われてみるとどうでしょう。
まぶたの重み、目の乾燥、感じませんか・・・？

意識しているかどうかで視界は変わるのです。

そう、瞬きを止めてみましょう！

## できたもの
(急な顔面失礼します)

![CleanShot 2024-12-06 at 16 27 29](https://github.com/user-attachments/assets/7cb6db84-3ea6-4653-b435-256f842e72b7)

https://blinking-endurance.vercel.app

https://github.com/nitaking/blinking-endurance/




## ポイント

- 瞬きの判定が正確ではない

構成の解説記事を書こうと思っていたが、生成AIベースで中身を理解することなく実装されてしまったため、生成物から紐解いていく。

## 流れ
1. [v0.dev](https://v0.dev/)にて叩きを作る
    - `tailwind`ベースでのザックリレイアウトが完成
    - `Webcam`の実装方法をゲット
    - `tensorflow`を用いた目と瞬き判定方法をゲット
2. 瞬きの判定がされないなどの動作を修正(with GPT4o/GPT4o1-mini)

## 構成要素

- webcam: `react-webcam`
    - ユーザーの顔と瞬きを検出
- 機械学習: TensorFlow.js, MediaPipe FaceMesh
    - TensorFlow.js
        - ブラウザ上での機械学習モデル実行のライブラリ
        - 顔認識と瞬き検出
    - MediaPipe FaceMesh[^1][^2]
        <img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103475/5b6af9d9-7bbe-5a41-91a9-39dff70deb68.png width=300 />

        - 顔のキーポイントを検出する、高度な顔ランドマーク検出モデル
        - 目のキーポイントを使用して、瞬きを検出
        - Eye Aspect Ratio: 瞬き判定のために目の開閉状態を計算
- 瞬き判定
    - 目の開閉状態の評価指標。一定の閾値を設定することで判定。


## 瞬き判定: Eye Aspect Ratio

目の複数のキーポイント間の距離から計算

```ts
const calculateEAR = (eyePoints) => {
  // EAR = (|p2 - p6| + |p3 - p5|) / (2 * |p1 - p4|)
  const A = distance(eyePoints[1], eyePoints[5]);
  const B = distance(eyePoints[2], eyePoints[4]);
  const C = distance(eyePoints[0], eyePoints[3]);
  return (A + B) / (2.0 * C);
};
```

- distance関数: 2点間のユークリッド距離を計算。
- しきい値 (blinkThreshold): EARがこの値以下になると瞬きと判定（通常0.2～0.25）。

```ts
const distance = (p1: faceLandmarksDetection.Keypoint, p2: faceLandmarksDetection.Keypoint) => {
    return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
  };  
```

連続フレーム数 (requiredBlinkFrames): 瞬きを安定して検出するために、連続してEARがしきい値以下であるフレーム数を必要とする。

👉️ こちらは生成AIは瞬き検出の精度向上の為に2フレームを何度も求めてきたが、そうなると20ms目を閉じたときだけしか判定されなかったので、1フレーム(10ms)で仮設定。

## アニメーションフレーム管理

こちらはブラウザの再描画に合わせて瞬きの継続的検出を用いているとのことだが、このやり方でなくてもよいとは思っています。

> - **ループの作成**: detectBlink関数内でrequestAnimationFrameを再帰的に呼び出すことで、リアルタイムに瞬き検出を行います。
> - **キャンセル**: コンポーネントのアンマウント時やチャレンジの終了時にcancelAnimationFrameを呼び出し、ループを停止します。

```javascript
useEffect(() => {
  if (model) {
    requestRef.current = requestAnimationFrame(detectBlink);
  }

  return () => {
    if (requestRef.current) {
      cancelAnimationFrame(requestRef.current);
    }
  };
}, [model]);
```

実装構成ファイルは[こちら](https://github.com/nitaking/blinking-endurance/blob/main/app/page.tsx)。

https://github.com/nitaking/blinking-endurance/blob/main/app/page.tsx

## さいごに

所要時間は約2時間で、レンダリングエラーを修正することに時間を当て込まれる軍配となりました。

Webcamを使った実装も、TensorFlowを使った実装も経験がなかったため、学びが深いです。
意外と簡単に実装ができると思いつつ、生成AIがなかったら瞬き判定で時間が溶けそうだなという所感でした。

ということで、クソアプリを作るつもりがなんだかそこまでクソでもなく、学ばせて頂いた件でした〜！




[^1]: https://github.com/google-ai-edge/mediapipe/blob/master/docs/solutions/face_mesh.md
[^2]: https://qiita.com/nemutas/items/6321aeca27492baeeb92
未経験PdMの1年奮闘記

:::note info
この記事はLITALICO Engineers Advent Calendar 2024 シリーズ3の8日目の記事です
:::
# はじめに
こんにちは！プロダクトマネジメント部の寺町です。
障害福祉事業所向けの業務支援SaaSである「かんたん請求」というプロダクトのPdMを務めています。
2023年8月に中途入社し、未経験のPdMとして約1年奮闘してきました。
この記事ではこの1年の奮闘の記録と、コンサルから事業会社PdMに転職しての所感についてお話したいと思います！

# 経歴
新卒で総合コンサルティングファームに入社し、官公庁向けのシステム開発PMOやIT監査のPJに参画していました。
当時は進捗管理や、コード以外の成果物（取扱説明書等）の品質管理を担当していました
ジュニアながらに提案フェーズに関わらせていただいたり、様々な経験を積ませて頂いたと考えています。

# なぜ転職してきたか？
コンサルタントとして様々なクライアントにご支援を提供し、国家単位のシステム開発に関われることはとても興味深い経験でした。
しかし、経験を積むうちに誰かの意思決定の伴走をするだけでなく、自分自身で意思決定を行いながら物事を前に進めたいと考えるようになって転職を決意しました（月並みな動機かもしれません）。

PdMになると決め選考を受ける中で様々な業界の選択肢がありましたが、もともと、母が障害を抱えている関係で障害福祉業界に馴染みがあったことから障害福祉業界を選びました。
手触り感を持って仕事を続けていくためにも、もともと馴染みがある障害福祉業界が自分が一番興味を持って働けると確信していたためです。

# 担当しているプロダクト内容
入社以来、「かんたん請求」というプロダクトの主担当PdMを務めています。
「かんたん請求」は障害福祉事業所向けの業務支援SaaSで、10年以上の歴史を持ち、多くのお客様にご利用いただいています。
歴史がある分、古いプロダクトでもあり、コアとなる計算基盤をはじめ、リファクタリングが必要なフェーズに直面しています。

# 具体的にしていること
この1年間を通して、古い基盤を新しい基盤に入れ替える基盤入れ替えPJの推進、障害福祉関連法の改正に伴う計算ロジックの見直し対応、その他グロース開発の内容立案と推進等様々な開発PJに参画してきました
顧客への訪問インタビューを繰り返し、要求の抽出から要件定義まで上流工程を主に担当しています

また、営業やマーケ等の「製品を売って顧客を獲得する」というプロセスの経験がない状態でしたが、事業部リーダー陣との定例打合せ等に参加し手触り感を持って実業の理解を深めています

# 転職時の期待値と現状
転職当時に期待していたとおり、自分で意思決定を行い製品開発を前に進められ続けています。期待していた以上に任せて頂ける幅が広く、大きなやりがいを感じています。
しかし同時に、自分で意思決定を行う怖さも感じています。
前職時代はファーム内の1チームの下っ端ジュニアとして、非常に限られた範囲の意思決定しか行ってきませんでした。
さらに、あくまでも最終決定はクライアントが行うもののため、自分が決めたものが世に出る感覚は一切ないまま過ごしていたように感じます。

自分で物事を推進したくて転職を決意したため、今の環境に不満はありません。
しかし、自分が決めた要件が誤っていて、開発メンバーや事業部に迷惑をかけることの怖さは常に持ち続けています。

# どうやって怖さを克服するか
意思決定をする際に何が怖いのか分解をすると、以下のようになると考えています。

前提がわからない→何を根拠にすればいいかわからない→ふわふわした決定をする→間違っているかどうかもわからない→漠然とした不安だけが残る

前提と根拠を詰めるために知識があれば不安は軽減されるはずと考え、武器となる知識の獲得に全力を注ぎました。
未経験のジュニアPdMとして、一番手っ取り早く身につけられる武器として目をつけたのがドメインの知識です。
意思決定に必要な知識には、ビジネス知識やIT知識など様々なものがありますが、ビジネス知識やIT知識は座学だけでなく、経験を通してじっくりと培っていく必要があります。
一方で、ドメイン知識であれば、若手としての機動力を活かし、足を使って顧客訪問を行ったり、関連文書や法令をとにかく勉強したりすることで一定のレベルに達することができるからです。


# どのようにドメイン知識を獲得するか
担当している障害福祉ドメインでドメイン知識を獲得する方法は、大きく分けて3つあります。
少しハードルは高いですが、①の方法が最も効果的な獲得方法だと感じています。
**①業界で働いてみる**
顧客のイメージを掴むには、自分も業界で働いてみるのが一番確実です。
私も実際に転職前の期間、グループホームという障害者向け施設で支援員として現場に出ていました。現場で得る肌感覚は理屈では判断しきれない決断の根拠になるように感じています。
また、**顧客インタビューに行ったときに働いたエピソードを話すと「業者の人」というより「現場の後輩」として扱って頂けるため、話が盛り上がって何かと便利**です。

**②足を使って顧客訪問をする**
顧客が何を考え、どのような環境で日々を過ごしているのかをイメージできるように、時間を見つけて何度も訪問しました。現場を直接見ることで、ユーザーのニーズや課題を深く理解することができます。

**③法令解釈を鍛える（座学）**
法律を理解するには、法令の適用解釈が重要です。法令の趣旨や目的、先例を調べ、自分なりの適用解釈の正当性を確認し続けました。繰り返すうちに、適用解釈の軸ができ、法令理解が深まりました。

# 前職の経験から活きたこと
前職では、社会人として最も重要な「成果が出るまでは何があってもやめない・諦めない」ということを学びました。コンサルタントは結果に対して報酬をいただいているため、結果を出せなければ何の意味もないと教えていただいたことは大きな財産です。

この基本スタンスを持って転職してきたことで、自分の怖さが薄れるまで情報を集めてから意思決定を行うというサイクルを続けることができています。コンサルで得たガッツは、事業会社でも大きな力になります！

# 今後の展望
転職の経緯で記載したとおり、もともと、母が障害を抱えている関係で障害福祉ドメインに親和性を感じていました。
障害を抱えた人の家族として、プライベートでは障害福祉サービスのお世話になっています。
実際に施設への入所を目指し、事業所に当事者家族として連絡を取ったりしています。

プライベートでの経験から、障害がある人の生きづらさや、頼るあてのない家族の辛さは痛いほど感じています。
その痛みを知っている自分だからこそ、このドメインの発展に寄与できることがあるのではないかと考えています。
今後の展望として、単純な事業所数を増やすだけではなく、障害がある人それぞれに見合った「心地いい居場所」を作る支援ができるプロダクトを作っていきたいです！

まだまだできないことの方が多いジュニアPdMですが、弊社にはやる気さえあれば様々なことを任せてもらえる環境があります。
チームの皆さんのお力を借りながら、全ての人に居場所を作れるようなプロダクトを作れるよう今後も精進していきます！

明日は@marst_xxさんのユーザストーリーに関する記事です。お楽しみに！
Oracle Analytics Cloud でのデータ加工する段階の考え方について

# はじめに
通常、BIツールでデータ加工するときに、BIツールか、前段階のETLか、どの段階で実施するべきか検討することが多いと思います。BIツールでは、「システム構築の半分は、データの準備」と言われるぐらい、データの準備（加工）は重要な部分を占めています。この記事では、Oracle Analytics Cloud(OAC) でのデータ加工をどの段階でするべきか、方向性の参考となるような情報を提供したいと思います。

# Oracle Analytics Cloud でのデータ加工する段階
OAC では、データ加工する段階は、データソース（データベース）側から列挙すると、データ ビジュアライゼーション（セフルサービスBI）の場合、テーブルの列追加、ビュー、データモデル、データフロー、データセット、マイ計算となります。テーブルの列追加とビューは、データベース側の機能です。
基本的には、できるだけ**上流（データソース側）でデータ加工したほうが、うまくいくケースが多い**です。BIツールよりデータベース・サーバーのほうが、計算処理能力が高いからです。データを二次利用するケースも考えて、データベース・サーバーのほうが効果的でしょう。例を上げますと、「売上金額」と「原価」の列を持った表があるとして、「利益額」を表示したい場合、「利益額」は、「売上金額」ー「原価」で列同士から計算できるので、データベース側で処理したほうがいいでしょう。表にデータを入れるときに計算して実体として列をINSERTするでもいいですい、ビューとして、計算列を追加しておくでもいいでしょう。ただ、ビューの場合は、検索時に計算されるので、データ行数が多い場合には、パフォーマンスに影響ででる場合があります。最終的に、BIツールで、合計「利益額」を集計するときよりも、データベース側で高速に処理できるメリットもあります。

* 売上表

|売上金額 |原価|利益額   |
|:-:|:-:|:-:|
| 100  |  80 | 20  |


ただ、組織によっては、データベースを操作する部門権限がなかったり、データベース・サーバーの負荷の懸念で、データベースでデータ加工できない場合もあると思います。

## データ・セット
データ・セットとは、ワークブックの元データとなるデータソースです。データ・セットでも式を使った列の追加をすることができます。**もし、データベース側で加工処理できない場合、データ・セットには加工処理できることが多く、データ・セットで加工処理をしたほうがいいと思います**。データ・フローのように、処理実行しなくてもいいですが、機械学習のような複雑な処理は実行できません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3112379/9dd9289b-2abc-7ec7-6be7-e7c8a8bdc67b.png)

## データ・フロー
データ・フローは、データセット、サブジェクト領域またはデータベース接続からデータを加工できます。データ・フローはGUI（画面）で、アイコンを追加していくて、フローを定義することができます。ただし、データ・フローを実行しないと、データ・セットができないので、手動もしくはスケジュール実行する必要があります。データ・フローには機械学習などの高度な処理のアイコンもあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3112379/992c69aa-13e7-0858-51e8-d861b1aa8911.png)

## ワークブックのマイ計算
ビューワー側のワークブックのマイ計算でもデータ加工できますが、制限事項があり、データ・セットでデータ加工できるのであれば、データ・セット側でデータ加工したほうがいいと思います。ただし、**利益率や歩留まり（不良品率）を計算するときは、データ集計後に計算するべきなので、マイ計算で計算するべきかと思います**。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3112379/0c90d522-c43e-f712-146c-458508e0de53.png)

# おわりに
Oracle Analytics Cloud でデータ加工する段階はいくつもあるので、どの段階でデータ加工するべきかについて記載しました。基本的に、データソース側で加工し、割合を求めるときはワークブックのマイ計算で処理したらうまくいくのではないかと思います。Oracle Analytics Cloud で分析するときに、参考になれば幸いです。
ABC256 Eの解法メモ【Ruby】

入水目指して過去挑戦して解けてないAtCoder Problems上でDifficultyが水色の問題を解いていく。

# [ABC256 E: Takahashi's Anguish](https://atcoder.jp/contests/abc256/tasks/abc256_e)概要

$N$人の人を1列に並べたとき、並んでいる人の嫌いな人がその人よりも前に並んでいると不満度が増える。
好きな順に並べられるときの不満度の最小値を求める問題。

# 解法イメージ

$N$頂点$N$辺の有向辺グラフとしてみると、いくつかのループとループの頂点へ向かう枝からなるグラフになる。
この時、連続ではないグラフの頂点同士はどの順で並んでいても不満度は増えないので、以降は連結なグラフについて考える。

ループへと向かう枝についてはその枝の端から順に並べば嫌いな人よりも前に並ぶので不満度は増えない。異なる枝同士は嫌い合っていないのでどの順で並べても良い。
ループの中においては辺の向きに沿って並べれば不満度は増えないが、ループをどこかの辺で切る必要が出る。この切られた辺の不満度が各ループで発生する。

よって、それぞれのループに対してループを作っている辺の内、不満度が一番小さいものの合計を求めてあげれば答えとなる。

# 実装例

```ruby
n = gets.to_i
xarr = [0] + gets.split.map(&:to_i)
carr = [0] + gets.split.map(&:to_i)

c = 0
h = {}
max = carr.max
(1..n).each do |i|
  next if h[i]

  flag = false
  arr = [i]
  hash = {i=>0}
  while hash[xarr[i]].nil?
    if h[xarr[i]]
      flag = true
      break
    end
    i = xarr[i]
    hash[i] = arr.length
    arr << i
  end
  arr.each{|j| h[j] = true }
  next if flag
  
  min = max
  arr[hash[xarr[i]]..].each do |j|
    min = [min, carr[j]].min
  end
  c += min
end

puts c
```
HuggingFaceでFlaskを実行しても起動しないときの対処法

# 「 * Running on http:// 127.0.0.1:5000」と表示される場合
Pythonの`app.run()`の部分に`port=7860,`を追加するか、`README.md`に「app_port: 5000」を追加する
# 「 * Running on http:// 127.0.0.1:7860」と表示される場合
①`README.md`に「app_port: 7860」を追加する
②Pythonの`app.run()`に`host='0.0.0.0'`を追加する
【Android】特殊なUI要件を満たすリッチなStickyHeaderを作ってみた

※ 12/13 こちらのサンプルプログラムは改良を加え、ライブラリとして公開しました。
https://qiita.com/abks45ft/items/952c403f0e299d3cc312

I created a rich StickyHeader that meets special UI requirements.
You can translate this page into English.

# はじめに
アプリのUI要件として以下のような画面の要望をリクエストされたことはないでしょうか。
1. 画面内に非常に多くのViewが存在する
1. 画面は上下スクロールする
1. 画面の一部のセルは画面上部に張り付く(StickyHeader)
1. 張り付いたセルにボタンなどを配置しても反応する

いわゆるStickeyHeaderです。StickyHeaderのサンプルはググればいくつも出てきますが、このUI要件を完全に満たしたものは私が探した限り見つけることはできなかった。

ないものは作るしかない。ということで作成したのですが、同じような悩みを抱えている人はきっといらっしゃるはず。と思い、汎用性をもたせるように改良してサンプルプログラムを公開させていただこうと思った次第です。

# GitHub
[こちら](https://github.com/s-y-droid/example.stickyheader)
（アプリの要件にあわせて自由に修正していただきたいのでライブラリ形式ではなく、ソースをコピペして使って頂くような想定をしています）

# 簡単な使い方

MainActivityを斜め読みすれば使い方がすぐに理解できるようにしています。(改良せず使うだけであればlibstickeyheaderモジュールの中を解析する必要はありません)

```kotlin:MainActivity.kt
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        getStickyHeaderFragment().bind(
            // Note: Specify here a list of all the Fragments that make up the screen.
            listOf(
                P1CellFragment.newInstance(),
                P2CellFragment.newInstance(),
                // .... (omit)
            )
        )
    }

    private fun getStickyHeaderFragment() =
        binding.stickyHeaderFragment.getFragment<StickyHeaderListFragment>()
}
```
StickyHeaderListFragmentを画面に配置し、bind()を呼ぶだけです。
P1CellFragment, P2CellFragmentは、リスト上に表示される個々のセルです。これらのFragmentはIStickyHeaderListCellを実装する必要があります。

```kotlin:IStickyHeaderListCell.kt
interface IStickyHeaderListCell {
    fun isStickyHeader(): Boolean
    fun fragment() : Fragment
}
```
isStickyHeader ... そのセルをStickyHeaderとして使用する場合はtrue。普通のセルとして使用する場合はfalse
fragment ... thisを返します

百聞は一見に如かず。ソース見た方が早いと思います

# 動作確認(Animation Gif)
（作成中）

# 仕組み
非常にシンプルな実装です。
まず、普通のScrollViewで画面を表示。その上にStickyHeaderとして表示するセルを重ねているだけです。

また、セルの高さが変化したときに、Stickyなセルも追従するようにしています。(サンプルのChange View Sizeボタンを押下)。これはセルの中にExpandViewなどを使用できるようにするための対応です。

# あとがき

このUI要件に潜む罠として一番悩んだところは、試行錯誤した結果、結局<b>RecyclerViewは使えなかった</b>ということでした。

なぜなら、非常に多くのViewが1つのセルに存在するからです。表示領域外から表示領域内にセルが移動したとき、RecyclerViewはcacheの上限設定を変えることはできますが、リバインドは不可避です。スクロールのたびにリバインドが発生するとViewの多さのためカクついてしまい、製品として使い物になりませんでした。（当時、RecyclerViewで作成したStickeyHeaderは全部捨てて書き直した苦い経験があります）
かといって、スクロール時にリバインドが発生しないListViewで実装する気にもならず、それならLinearLayoutで十分だよね？と思いこの形になりました。

このような手戻りが開発の現場で起こらないように、少しでもお役にたてれば幸いです。
VSCode DevContainer で Ruff を使う方法

# はじめに
先日、Djangoオンラインミートアップ #4 にて、「Djangoの開発環境で工夫したこと」というタイトルで、リンターやフォーマッターに関する発表をしてきました。その際に、参加者の皆さんの多くが Ruff を採用しているとのことだったので、私も試しに使用してみることにしました。この記事はその備忘録も兼ねた内容です。

https://speakerdeck.com/hiroki_yod/devcontainer

改めて、Ruff とは、Astral社が開発しているRust製のPythonのリンター兼フォーマッターです。下図（出典は Ruff の公式サイト）のように、他のリンター等と比較して、非常に実行速度が速いのが特徴です。

![スクリーンショット 2024-12-06 16.24.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2065133/068f6c83-ae47-a352-3ba6-2ca4f17876b9.png)

https://docs.astral.sh/ruff/

今回はこの Ruff を VSCode DevContainer の開発環境に導入する手順を備忘録も兼ねて記事にします。DevContainer を使用しない場合も手順はほとんど同様です。


# 1. Ruff のインストール
Ruff は同じくAstral社が開発している uv と使用されることが多いと思うので、今回はパッケージ管理ツールに uv を採用します。

まずは、次のコマンドで Ruff をインストールします。

```bash
uv add ruff
```

続いて、Ruff に関する設定を `pyproject.toml` に記載します。最初の時点では、下記のように設定を記述しました。重要なのは、select の部分で、例えば "I" は isort の i であり、リンターやフォーマッターに採用する規約を選択することができます。

```toml
[tool.ruff]
line-length = 128
target-version = "py313"

[tool.ruff.lint]
# 不要なルールは随時ignoreに追加してください
ignore = []
select = [
    "E",
    "F",
    "I",
    "B",
]

[tool.ruff.format]
# 公式ドキュメントに準拠した
quote-style = "double"
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "auto"
docstring-code-format = false
docstring-code-line-length = "dynamic"
```

参考：「規約の選択」に関するページ

https://docs.astral.sh/ruff/linter/#rule-selection


# 2. Ruff の基本的な使い方
ここまでの手順で、Ruff を開発環境にインストールして、設定を記述するところまでの準備ができました。続いては、実際に ruff をコマンドラインで実行してみます。

## 基本的な操作
基本的な操作は下記の通りです。

**コードスタイルのチェック**
```bash
ruff check .  # 現在のディレクトリ内のPythonファイルをチェック
```

**自動修正**
```bash
ruff check . --fix  # 自動的に修正可能な問題を修正
```

**自動フォーマット**
```bash
ruff format .  # 自動的にフォーマット
```

## 初回導入時等に使う操作
開発途中で導入すると大量のエラーや警告が発生してしまいます。そのような際などに、検証したエラー内容をコマンドで指定することもできます。

```bash
ruff check . --select E501 # E501は特定のエラーのコード
```

参考：「ルール」に関するページ

https://docs.astral.sh/ruff/rules/


# 3. ファイル保存時の自動実行
black や yapf などのフォーマッターを使用していた時は、ファイル保存時にフォーマットを自動実行した際の実行速度の遅さが気になって、結局は使わなくなってしまいました。一方で、Ruff は圧倒的に実行速度が向上しているので、気にならないのではないかと思い、エディターでファイル保存時に自動実行する設定を追加してみました。

普段の開発には VSCode DevContainer を使用しているので、devcontainer.json に下記のような設定を記載しました。`charliermarsh.ruff` は VSCode における Ruff の拡張機能であり、`editor.formatOnSave` `editor.codeActionsOnSave` の部分で保存時のフォーマット自動実行の設定をしています。

```json
{
...省略
  "customizations": {
    "vscode": {
      "extensions": [
        ...省略
        "charliermarsh.ruff"
      ],
      "settings": {
        "[python]": {
            "editor.formatOnSave": true,
            "editor.codeActionsOnSave": {
                "source.fixAll": "explicit",
                "source.organizeImports": "explicit"
            },
            "editor.defaultFormatter": "charliermarsh.ruff"
        }
      }
    }
  }
}
```

実際に試してみたところ、想定以上に高速な実行速度で自動フォーマットしてくれました。エディターでの自動実行に加えて、GitHub Actions を用いて、CI にリンターやフォーマッターを組み込んでいくことで、規約を開発サイクルに取り込んでいく想定です。

以上、VSCode DevContainer で Ruff を使う方法でした。
Unityマイクラ風の地形の生成です。ChatGPTで作りました。

csファイルを保存して、cubeにアタッチします。プレハブはcubeでいいです。
```c#
using UnityEngine;
using System.Collections;

public class VoxelTerrain : MonoBehaviour
{
    public GameObject grassBlock;  // 草地用ブロック
    public GameObject sandBlock;   // 砂地用ブロック
    public GameObject snowBlock;   // 雪地用ブロック
    public GameObject treeBlock;   // 木用のブロック
    public int width = 100;        // 地形の幅
    public int depth = 100;        // 地形の奥行き
    public int maxHeight = 10;     // 地形の最大高さ
    public float treeDensity = 0.1f; // 木の密度（0.0f～1.0f）

    private bool isGenerating = false; // 生成中フラグ

    void Start()
    {
        StartCoroutine(GenerateTerrainCoroutine());
    }

    IEnumerator GenerateTerrainCoroutine()
    {
        isGenerating = true;

        for (int x = 0; x < width; x++)
        {
            for (int z = 0; z < depth; z++)
            {
                // 高さを計算
                int height = Mathf.FloorToInt(Mathf.PerlinNoise(x * 0.3f, z * 0.3f) * maxHeight);
                GameObject blockType = SelectBiomeBlock(Mathf.PerlinNoise(x * 0.1f, z * 0.1f));

                for (int y = 0; y <= height; y++)
                {
                    Vector3 position = new Vector3(x, y, z);

                    if (y == height)
                    {
                        // 最上層ブロック
                        InstantiateBlock(blockType, position);

                        // 木の生成
                        if (Random.value < treeDensity && y < maxHeight - 1)
                        {
                            // 木の生成位置を調整
                            GenerateTree(x, y + 1, z);
                        }
                    }
                    else
                    {
                        // 下層は砂
                        InstantiateBlock(sandBlock, position);
                    }
                }

                // フレームごとに少しずつ処理を実行
                if (z % 10 == 0) yield return null;
            }

            if (x % 5 == 0) yield return null;
        }

        isGenerating = false;
    }

    GameObject SelectBiomeBlock(float noise)
    {
        if (noise < 0.33f) return grassBlock; // 草地
        if (noise < 0.66f) return sandBlock;  // 砂地
        return snowBlock;                     // 雪原
    }

    void InstantiateBlock(GameObject blockType, Vector3 position)
    {
        // ブロックを生成し、回転を適用
        Instantiate(blockType, position, Quaternion.Euler(-90f, 0f, 0f));
    }

    void GenerateTree(int x, int y, int z)
    {
        // 木の高さをランダムに設定
        int treeHeight = Random.Range(3, 7);

        // 木の生成位置を決定（地面より上に木を生成）
        for (int i = 0; i < treeHeight; i++)
        {
            Vector3 treePosition = new Vector3(x, y + i, z);

            // 木の生成位置がmaxHeightより高くならないように制限
            if (treePosition.y <= maxHeight)
            {
                // 木のブロックを生成
                Instantiate(treeBlock, treePosition, Quaternion.identity);
            }
        }
    }

    public bool IsGenerating()
    {
        return isGenerating;
    }
}

```
【2024年12月】年末に大規模サイトのSEOを少し語る

## 筆者紹介

スタンバイでスクラムPOをしている者です。  
主にスタンバイのSEO全体を管理、兼務出向先のLINEヤフーにて複数サービスのSEOアドバイザリーを担当、職場の許可を得て進めている副業でも大規模サイトのSEOコンサルティングを数社携わっており、社内外広くSEOやっています。

過去、いわゆる電博の広告代理店側でウェブマーケティングを広く経験してきており、かれこれトータル10年以上SEOを経験しております。年末ですし、ちょっとだけ真面目にSEOの話でもしてみようかと思いました。誰か読んでくれますよね。

俗にキャリアにおける30代はスペシャリティ、40代はオリジナリティと言います。40代に向けてまずはスペシャリティを磨き、徐々にオリジナリティを出せるように頑張っていこうと思っています。

---

## 大規模サイトSEOにおける3つの重要なポイント

あんまりウェブでも語られなさそうな【スタンス】【キーワード】【SERP】という観点からシンプルに3つにまとめてみました。

### 1. 【スタンス】問いを常に立て続けられるか

100万ページ以上を保有するような大規模サイトでは、従来のSEO常識は当てになりません。Googleのスターターガイドもすべてを鵜呑みにしない方が良いコトもあるでしょう。基本的には検証を通じて答えを見つける姿勢が求められます。


例えば：
 - TOPページからの内部リンクは本当に高い効果を持つのか？
 - sitemapファイル内のURL階層は浅い方が良いのか？
 - 商品一覧ページの2ページ目以降から1ページ目にcanonical設定をするべきか？

```※これホントによく聞くのですが、大規模サイトにおける一覧ページのページネーションのベストプラクティスは1つではないため、ウェブ情報を鵜呑みにしないで正解を導いてくださいね。```

教科書通りの実装からスタートする、でも良いのですが、しっかりと現状の検索順位やクロール、インデックスの傾向に合わせて、問いを立て、検証し続けることが大切です。検索ユーザーが変化する以上、Googleも変化し、SEO担当者も変化し続けていかなくてはなりません。

例：
 - 仕事を探しやすいエリアのカットは行政区画に通り細かくすべきなのか？
 - クロール頻度の低いページは検索ニーズがそもそも無いのでは？
 - 商品一覧ページのテーマと商品の関連性はSEO順位に大きく関係するのか？

余談ですが、外部SEOコンサルの方が求人アグリゲーションサイトのSEOを解説するウェブコンテンツを拝見させていただいてましたが、「あー言いたいことは分かる」と思いつつ、内情を知らない限り、正しくSEOを論じるのは難しいなぁと感じます（汗）特にスタンバイのSEOは、外から見るとやや謎めいているような、意図を掴むのが容易ではない気がしてます。


---

### 2. 【キーワード】マジョリティの気持ちを想像できるか

これは大規模サイトに限った話ではないですねｗ

「このキーワードを検索した際、多数派が何を考えているか？」は重要な問いです。Googleは検索者の大多数を満足させることを目的とした検索エンジンですし、特定キーワードに対して、マイノリティな検索意図を満たすよりも、マジョリティの検索意図を重視する方が理にかなっています。「こんなゴミ結果ならBingの方が良いじゃん」って乗り換えられたら困るんですね。

例えば、「事務 バイト 東京」というキーワードを対策する場合、以下のようなマジョリティの検索意図が考えられます：
 - フルタイムではなく、柔軟な働き方を希望。
 - 都内で接客不要、特別なスキルが不要な仕事を求めている。
 - 地理的条件や通勤のしやすさを重視。
 
 逆に、東京以外の求人や接客業寄りの内容は、マジョリティの意図から外れる可能性があります。したがって、いきなりマイノリティな検索意図をメインコンテンツに掲載してしまうとユーザーが求める内容と異なり、期待した検索順位に達しない可能性があります。
一方でマイノリティな検索意図は内部リンクやレコメンドなどで救ってあげると良いでしょう。


---

### 3. 【SERP】競合とのポジショニングを意識する

最後はテール系キーワードに多いかなーと思う話です。大規模サイトはテールまで狙いに行くのが自然なので３つ目に盛り込みましたが、SERP（Googleの検索結果画面）も見に行くとヒントがあります。

前述の通り、検索キーワードには様々な検索意図が隠れています。そのため、Googleの検索結果には、多様な検索意図を持つ検索者を満足させるための多様性が一定求められます。
意外と見落とされがちなのですが、1-10位までの検索結果画面には、必ずしも検索クエリに完全一致する内容だけが表示されるわけではありません。

例えば、「事務 バイト 東京」で検索した際、1ページ目の上位には「事務 バイト 東京」の求人一覧といった、検索キーワードドンピシャのLPが出がちですが、1ページ目後半に行くにつれ「事務 バイト 東京 未経験OK」のような検索キーワードを少し外したLPも含まれることがあります。

であれば、無理に検索キーワードドンピシャの求人一覧を磨き込むより、少し検索意図をズラした「未経験OK」を含んだ求人一覧の体験向上を引き上げた方が良いユーザー体験を提供できる確率が上がりますよね。

このように、SERPsを冷静に見ながら、自社・競合サイトのポジショニングや検索結果の傾向を踏まえ、自社サイトがどのキーワードで戦うかを戦略的に考える必要があります。


---

## SEOerの生存戦略

SEOにおいて、Googleのアルゴリズムや検索ユーザーの意図に寄り添うことは重要不可欠です。検索エンジンに評価される構造や、ユーザーに価値ある情報を提供する施策は、成果を上げるための基本的な柱です。しかし、寄り添うべきはGoogleや検索ユーザーだけではありません。SEOに関わるすべての人々――チームメンバーやクライアント、関係者――に対しても、同様に配慮し、共に歩む姿勢が求められます。

１のスタンス部分でも述べた通り、SEOは単なる技術ではなく、多くのサービス関係者と連携し、地道な検証を通じて進化させるものです。ゆえに、SEO担当者は単なるGoogleのアルゴリズムを知ってる人、なんかSEOの引き出し多い人、ではなく、究極的には「一緒に働いていて気持ち良い人」であることこそが生存戦略において重要だろうなと思います。

特に事業会社では、SEO担当者が「単独の専門家」ではなく、「チームを繋ぐ架け橋」として機能することが求められます。マーケティング、プロダクト開発、営業、さらには経営層との連携を通じて、SEOを事業成長に結びつける役割を担うからです。一方でコンサル側でも、クライアントの事業背景や文化を理解し、ただの指示出しではなく、共に課題解決に取り組むパートナーである姿勢が求められます。

「一緒に働いていて気持ち良い人」であることは、最終的に信頼を生み、結果として長期的な成功に繋がる。技術だけではなく「人の仕事」であることを忘れず、相手に寄り添う姿勢が、時代を超えてSEOに必要とされる能力になることでしょう。