OmniAICreator/Qiita-1.07M huggingface dataset:
rex0220 計算式プラグイン スペース項目に概要と画像を印刷

[計算式プラグイン](https://qiita.com/rex0220/items/ae83c6d5ce50ff7a9a73)と[シェイプ！プラグイン](https://qiita.com/rex0220/items/45156c9339ab5808dc70)、[項目検証プラグイン](https://qiita.com/rex0220/items/be20fd879f5e1bc9e035)でスペース項目にレコードの概要と画像を表示・印刷してみます。

# 概要

[rex0220 計算式プラグイン スペース項目の概要印刷](https://qiita.com/rex0220/items/895e9bc6ac837b6cf7d7)に画像を追加して印刷します。
シェイプ！プラグインで画像を配置し、項目検証プラグインで、スペース以外の項目を非表示にします。

- 詳細画面

![2025-02-11_19h56_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/a6ac16ef-9f8c-85b6-5e0e-2c65e46b57e6.png)

- 印刷画面

![2025-02-11_19h56_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/08f1acac-bcfa-dfb7-40f7-666a3f86a298.png)

# アプリ設定

スペース項目を配置して、要素IDを設定します。

![2025-02-11_20h17_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/3e1fb311-3b5b-68e3-1215-bd0d37349d7a.png)


# 計算式プラグイン設定

印刷のため、ラベルの設定を変更しています。

![2025-02-11_20h00_29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/fd30ef6a-7c14-2ad0-1a4f-2b5a95f536b7.png)

```.js
OPTION: 

// sp1:(sp1) SPACER
LET(
  label, TAGS_HTML(
    TAG("style", JOIN(ARRAY(
        ".custom-table { width: 100%; table-layout: auto; border-collapse: collapse; }",
        ".custom-table td { border: 1px solid darkgray; padding: 4px 6px; }",
        ".custom-table td:first-child { white-space: nowrap; color: blue; }",
        ".custom-table td:last-child { word-break: break-word; }",
    ), NEWLINE(),1)),
  ),
  table, TAGS_HTML(
  TAG("table", 
    ATTR("class", "custom-table "),
    STYLE("border-collapse", "collapse"),
    TAG("tr", TAG("td", "顧客名"), TAG("td", 顧客名)),
    TAG("tr", TAG("td", "部署名"), TAG("td", 部署名)),
    TAG("tr", TAG("td", "担当者名"), TAG("td", 担当者名)),
    TAG("tr", TAG("td", "案件名"), TAG("td", 案件名)),
    TAG("tr", TAG("td", "確度"), TAG("td", 確度)),
    TAG("tr", TAG("td", "初回商談日"), TAG("td", DATE_FORMAT(初回商談日),
      IF(NOT(初回商談日),STYLE("background-color:#f9bba5;")))),
    TAG("tr", TAG("td", "提案プラン"), TAG("td", 提案プラン)),
    TAG("tr", TAG("td", "オプション"), TAG("td", オプション)),
    TAG("tr", TAG("td", "商談担当者"), TAG("td", 商談担当者)),
    TAG("tr", TAG("td", "プラン費用"), TAG("td", FIXED(プラン費用),
      STYLE("text-align:right;"), IF(プラン費用>1000000,STYLE("color:red;")))),
    TAG("tr", TAG("td", "オプション費用"), TAG("td", FIXED(オプション費用),
      STYLE("text-align:right;"), IF(オプション費用>1000000,STYLE("color:red;")))),
    TAG("tr", TAG("td", "合計費用"), TAG("td", FIXED(合計費用),
      STYLE("text-align:right;"), IF(合計費用>1000000,STYLE("color:red;")))),
    TAG("tr", TAG("td", "受注予定日"), TAG("td", DATE_FORMAT(受注予定日))),
    TAG("tr", TAG("td", "詳細"), TAG("td", 詳細)),
  )),
  ARRAY(label,"",table,"")
)
```

# シェイプ！プラグイン設定

スペース項目に画像の設定を行います。

![2025-02-11_20h02_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/2037bb61-1737-2ee8-2194-3232d9aa8a83.png)

# 項目検証プラグイン設定

スペース項目以外の項目を印刷時は非表示にします。
EV_INFO("cate")="print"

※非表示にする項目欄をまとめて選択して、「EV_INFO("cate")="print"」をコピペできます。

![2025-02-11_20h02_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/6a95bd4e-dbbb-b685-5c63-7d3f20f700b3.png)
OneDrive環境での Excel VBAファイルパス問題の解決策

## OneDrive に保存してある Excel VBAで CSV を読み込もうとするとエラーになった

Excel VBAでローカルファイルを操作する際、OneDriveを使用している環境で想定外の問題に遭遇してしまいました。

具体的には、ローカルファイルパスを指定しているのに、OneDrive の httpsパスに変換されてしまい、ファイル操作に失敗してしまうのです。

エクセルファイルが OneDrive 以外に保存してあればそんなことにはならないので、これまで気づきませんでした。潜在的なバグとなる重大な問題だと思いますが、ググっても公式の説明が見当たらず、Microsoft らしいなぁ、と思いました。

## 問題の詳細

OneDrive でエクセルファイルを同期している場合、VBA で OneDrive 内のローカルファイルを開こうとすると、以下のようなパスに変換されることがあります。

```
https://d.docs.live.net/[ID]/Documents/example.csv
```

または：

```
https://[組織名].sharepoint.com/sites/[サイト名]/Documents/example.csv
```

**Microsoft SharePoint** と呼ぶらしい。

これらのURLでは、**ADO.DB** でファイルを開くことができません。
ちなみに、**ADO.DB** を使う理由は **UTF-8 と シフトJIS を自動判定させるため**です。
未だにエクセルは CSV の読み込みに制約が多いので、こんな面倒が必要です。
そこに追い打ちをかける所業。
**みんなエクセルを使うのをやめて、LibreOffice Calc にすればいいのに**。

## 解決策

この問題を解決するために、OneDrive の httpsパス をローカルパスに戻す関数を実装しました。

```vb
Private Function GetLocalPath(ByVal filePath As String) As String
    ' httpsで始まらないパスはそのまま返す
    If LCase(Left(filePath, 4)) <> "http" Then
        GetLocalPath = filePath
        Exit Function
    End If
    
    Dim lPath As String: lPath = LCase(filePath)
    
    ' SharePoint Online用のパス変換
    If InStr(lPath, ".sharepoint.com") > 0 Then
        GetLocalPath = Environ$("OneDriveCommercial") & "\" & _
                      Replace(Mid(filePath, InStr(filePath, "/Documents/") + 10), "/", "\")
    
    ' 個人用OneDrive用のパス変換
    ElseIf InStr(lPath, "docs.live.net") > 0 Then
        'OneDriveConsumerが存在しない場合はOneDriveを使用
        Dim oneDrivePath As String
        oneDrivePath = Environ$("OneDriveConsumer")
        If oneDrivePath = "" Then oneDrivePath = Environ$("OneDrive")
        
        Dim idEnd As Long: idEnd = InStr(InStr(lPath, "docs.live.net/") + 14, filePath, "/")
        GetLocalPath = oneDrivePath & "\" & _
                      Replace(Mid(filePath, idEnd + 1), "/", "\")
    
    ' 上記以外のパスはそのまま返す
    Else
        GetLocalPath = filePath
    End If
End Function
```

### 使用例

この関数は以下のように使用します：

```vb
Sub OpenFile()
    Dim filePath As String
    filePath = Application.GetOpenFilename("CSVファイル (*.csv), *.csv")
    
    ' ファイルを開く前にパスを変換
    filePath = GetLocalPath(filePath)
    
    ' 変換されたパスを使用してファイルを開く
    With CreateObject("ADODB.Stream")
        .Open
        .LoadFromFile filePath
        ' ... 以降の処理
    End With
End Sub
```

## 実装のポイント

1. **環境変数の利用**
   - `Environ$("OneDriveCommercial")`: 法人向けOneDriveのローカルパス
   - `Environ$("OneDriveConsumer")`: 個人向けOneDriveのローカルパス
   - `Environ$("OneDrive")`: 一般的なOneDriveのローカルパス

2. **パスの判定**
   - SharePointのパス: `.sharepoint.com`を含む
   - 個人用OneDriveのパス: `docs.live.net`を含む

3. **パス区切り文字の変換**
   - Webパスの`/`をWindowsパスの`\`に変換

## 注意点

- この実装は、OneDriveとSharePoint Onlineの標準的なパス構造を前提としています
  - 一部の環境でしか検証できていません
- ファイルが実際にローカルに同期されている必要があります

## まとめ

OneDrive環境でのExcel VBAファイル操作は、適切なパス変換処理を実装することで、問題なく動作させることができます。この記事で紹介した実装は、多くの一般的なケースで利用可能な解決策を提供します。

## 参考情報

- 公式な説明は見つかりませんでした...

---

この記事が、同様の問題に直面している方々の助けになれば幸いです。
もし、このコードではNGな環境があるようでしたら、情報を共有してくださると嬉しいです。
【Hono × Next.js】HonoでAPIを作って、Swagger UIで動作確認する

久々の投稿です。
HonoでAPIを作って、Swagger UIで動作確認していきます。

# プロジェクト作成
まずは公式ドキュメントに記載の通りにプロジェクト作成をします。
```bash
pnpm create hoto@latest todo-app
```
実行すると、実行環境を選べたりするのですが、今後Next.jsでフロントエンドを作っていく予定なので、Next.jsを選びました。
※デプロイまでしたい場合はVercelを選ぶといいようです。

## ディレクトリ構造
プロジェクト内のappディレクトリを示します。
```
app
 ┣ api
 ┃ ┗ [...route]
 ┃ ┃ ┗ route.ts
 ┣ layout.tsx
 ┗ page.tsx
 ```

## route.ts
そしてこれが初期に生成されてるAPIが実装してあるファイルです。
今回の記事では、とりあえずSwagger UIで動作確認することなので、ここに全部書いていきます

`app/api/[...route]/route.ts`
```typescript
import { Hono } from 'hono'
import { handle } from 'hono/vercel'

export const runtime = 'edge'

const app = new Hono().basePath('/api')

app.get('/hello', (c) => {
  return c.json({
    message: 'Hello Hono',
  })
})

export const GET = handle(app)
export const POST = handle(app)
```

 # APIの実装
 ## 準備
 OpenAPIのドキュメント生成に`@hono/zod-openapi`を使うので、まずインポートと生成するインスタンスを変更します。
 ```typescript
import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi' 
// Swagger UIで使用
import { swaggerUI } from '@hono/swagger-ui'
 
 const app = new OpenAPIHono().basePath('/api')
 ```
 
 ## メッセージの取得
 色々書いてありますが、ほとんどはドキュメント生成用のものです。
 動作としては、posts配列の中身を返すだけです。
 `z`を使うことでバリデーションを行えます。
 ```typescript
 // メッセージを格納する配列
 let posts: {message: string}[] = []

app.openapi(
  createRoute({
    method: 'get',
    path: '/messages',
    description: "メッセージを取得する",
    responses: {
      200: {
        description: 'Respond messages',
        content: {
          'application/json': {
            schema: z.array(z.object({
              message: z.string()
            }))
          }
        }
      }
    }
  }),
  (c) => {
    return c.json(posts)
  }
)
 ```

 ## メッセージの投稿
 先述のposts配列に格納するものです。
 GETメソッドは異なり、`request`という項目があり、posts配列の要素の型と同じになっています。
 ```typescript
 app.openapi(
  createRoute({
    method: 'post',
    path: '/messages',
    description: "メッセージを投稿する",
    request: {
      body: {
        required: true,
        content: {
          'application/json': {
            schema: z.object({
              message: z.string()
            })
          }
        }
      }
    },
    responses: {
      200: {
        description: 'メッセージを投稿しました',
        content: {
          'application/json': {
            schema: z.object({
              message: z.string()
            })
          }
        }
      },
    }
  }),
  (c) => {
    const newMessage = { message: c.req.valid
    ('json').message }
    posts = [...posts, newMessage]
    return c.json(newMessage)
  }
)
```

## ドキュメントとSwaggerの公開
`doc`メソッドでドキュメントを公開します。
ローカルで起動して、/api/docにアクセスするとjson形式のドキュメントが確認できると思います。また、/api/swaggerではSwagger UIで動作確認が行えます。
```typescript
app.doc('/doc', {
  info: {
    title: 'An API',
    version: 'v1'
  },
  openapi: '3.1.0'
})

app.get('/swagger', swaggerUI({ url: '/api/doc' }))
```

# まとめ
APIの実装からドキュメントの自動生成、Swagger UIへのAPI公開まで一連の流れを学習できました！（cursor様様ではありますが笑）
実務でもモヤモヤしてたところなので、活かせそうです。

疑問なのは、ドキュメント生成は楽だけど、これをエンドポイントごとに書くのも大変じゃないかなって思いました。

# 参考
- https://hono.dev/examples/zod-openapi
- https://hono.dev/examples/swagger-ui
- https://github.com/honojs/middleware/tree/main/packages/swagger-ui
- https://zenn.dev/praha/articles/d1d6462a27e37e
【React】学習記録アプリの実装をやってみて

<h1> 行った内容　</h1>
１．Udemyで実際に手を動かしながらインプット
ハンズオン形式なため、なぜこの実装なのか常にわからない部分を解消していました。
自分専用のメモをスプレッドシートで可視化し、なぜ実装がうまくいかないのか整理しながらも進めておりました。

２．React環境構築
ViteでReact環境を作りました。

３．React使って要件を満たすようにTODOアプリを開発

# 開発を通して
・Udemyで学習する際に、なぜこの実装なのか、常に頭の中を整理しながら進めることができました
┗メモなどでアウトプットすることで、何に困っているのか常に可視化することが重要
・開発の際にどのタスクがあり、何をしなければいけないのか順序だてることが大切だと感じました
┗今の自分の立ち位置と、何がわからないのかわからない状態を脱却につながる
・実際に開発をすることで、楽しさと達成感を得ることができた

# 終わりに
開発して終わりではなく、自身の何が成長して、何が課題なのか振り返りながら今後も進めていきます。引き続き、アウトプットをしながら学習していきます。

<h2>JISOUのメンバー募集中！</h2>
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。<br>
日本一のアウトプットコミュニティでキャリアアップしませんか？<br>
興味のある方は、ぜひホームページをのぞいてみてください！<br>
▼▼▼<br>

https://projisou.jp/
ZeroSSL で IP アドレスの証明書を取得

こちらのブログで IP アドレスの証明書を無料で取得できると知ったので、やってみました。

https://asnokaze.hatenablog.com/entry/2021/01/18/232358

ACME による自動化は扱いません。90 日間有効なので私は当面不要なのです。必要になったら頑張ります。

https://zerossl.com/features/acme/


## 証明書の発行準備

ZeroSSL の Web サイトで証明書の作成手続きを進めます。

1. ドメインのところに IP アドレスを入力、その他いろいろ入力
1. Verify Domain のページまで進める
1. Auth File をダウンロード


## Web サーバーに Auth File を配置

Web サーバーはなんでもいいんですが、なんとなく ZeroSSL がスポンサーになっている Caddy を使います。Go で書かれているそうです。

```console
$ sudo apt install caddy
```

Ubuntu 24.04 では上記で簡単にインストールでき、サーバーが起動します。service コマンドではなく systemctl コマンドでないと操作できないのでご注意ください。

`/etc/caddy/Caddyfile` を設定ファイルとして読み込み、`/user/share/caddy` をルートとした file_server (SMB とか NFS ではなく、Apache HTTPD みたいな静的なファイルの HTTP サーバー) が構成されています。

```console
$ sudo mkdir -p /usr/share/caddy/.well-known/pki-validation/
$ sudo mv /path/to/your_auth_file /usr/share/caddy/.well-known/pki-validation/
```

として、ファイルを配置します。これで、Verify Domain のページにリンクがある http://public-ip-address/.well-known/pki-validation/your_auth_file にアクセスできるようになるはずです。

クラウドにサーバーがある場合、任意の IP アドレスからポート 80 に接続できるようにセキュリティー グループを構成するのを忘れないようにしてください。


## 証明書のダウンロード

ZeroSSL の Web サイトに戻り、Verify してもらいます。成功すると証明書を zip でくれます。

```console
$ sudo apt install unzip
$ unzip public-ip-address.zip
$ ls
ca_bundle.crt  certificate.crt  private.key
```

忘れがちな中間証明書の結合をしておきます。サーバーで 1 ファイルだけ証明書を設定する場合は certificate.crt ではなく結合したファイルを設定するようにします。


```console
$ cat certificate.crt ca_bundle.crt > chained.crt
```


## 後片付け

もう使わないなら Caddy は削除しちゃいましょう。

```console
sudo apt autoremove caddy
```

クラウド利用の場合はセキュリティー グループの構成も元に戻しちゃってください。
ナレッジ：業務

# システム開発の工程と作業内容一覧
|工程|名称|目的|主な作業内容|
|:-:|:-:|:-:|:-:|
|BI・BD|業務要件定義（業務分析・設計）|システム化する業務を分析し、要件を整理する|<ul><li>業務フローの整理</li><li>分析</li><li>現状の課題の洗い出し</li><li>業務要件の策定</li><li>システム導入の目的を明確化</li></ul>|
|RD|要件定義|何を作るかを決める|<ul><li>システム要件の決定（機能要件・非機能要件）</li><li>画面仕様、業務ルールの策定</li><li>顧客との合意形成</li>|
|BD|基本設計|システム全体の構造を決める|<ul><li>システム全体のアーキテクチャ設計</li><li>画面設計（UI/UX）</li><li>データフロー設計</li><li>外部システムとの連携設計</li></ul>|
|DD|データベース設計|データの構造や関係性を決める|<ul><li>ER図の作成（エンティティ設計）</li><li>正規化</li><li>インデックス設計</li><li>物理</li><li>論理スキーマの作成</li></ul>|
|PD|プログラム設計（詳細設計）|プログラムの細かい仕様を決める|<ul><li>モジュール単位の設計|<li>テーブル設計<li>API設計<li>処理フロー（フローチャート）の作成</ul>|
|PG|開発<li>実装|実際にコーディングする|<ul><li>プログラムの作成（コーディング）</li><li>コードレビュー</li><li>バージョン管理（Gitなど）</li></ul>|
|UT|単体テスト|プログラム単位でのテスト|<ul><li>各プログラムが正しく動作するか確認</li><li>エラーハンドリングのチェック</li></ul>|
|MUT|単体試験（モジュール単位のテスト）|各プログラムが仕様通り動くか確認する|<ul><li>ユニットテストの実施</li><li>テストケース作成（仕様書ベース）</li><li>デバッグ、修正</li></ul>|
|IT|結合テスト|システムの連携をテスト|<ul><li>システム間のデータ連携確認</li><li>APIの動作検証</li><li>インターフェースのテスト</li></ul>|
|SI|結合試験（システム全体を統合して試験）|システム間の連携やデータの流れを確認する|<ul><li>複数システム間のデータフロー検証</li><li>全体の機能連携テスト</li></ul>|
|ST|システムテスト|システム全体の動作を確認|<ul><li>要件定義通りに動作するか検証</li><li>パフォーマンステスト</li></ul>|
|PI|総合試験（本番環境に近い環境で最終確認）|運用環境での最終確認|<li>本番環境に近い環境でシミュレーション</li><li>運用テスト（バックアップ</li><li>障害時対応）</li></ul>|
|UAT|受け入れテスト|ユーザーがテストを行う|<ul><li>ユーザーによる操作検証</li><li>顧客の業務要件との適合性をチェック</li></ul>|
|RT|リリース|本番環境へリリース & 運用開始|<ul><li>本番環境へのデプロイ</li><li>リリース後の監視</li><li>運用開始></li></ul>|
- BI・BD〜PD → 設計フェーズ
- PG〜IT → 実装・テストフェーズ
- SI〜RT → 総合試験・運用フェーズ

# コーディング・開発作業の大まかな流れ
1. 開発
1. コードレビュー
1. テスト
1. テストエビデンスレビュー
1. 内部レビュー
1. 外部へのレビュー
### 用語
- 机上レビュー
書面を目視で確認
- 対面レビュー
会議を設定して口頭で説明する

# 新規着任時、共有してもらって助かったこと・もの
- PD書
- 改修前後のソース差分比較ファイル
- 推奨インストールソフト
- ソース改修方針文書
- システム改修内容
- ソースの処理内容
【学習】git commit の日本語文字化け

## はじめに
今回は`git commit`で英語や数字以外、日本語を入力した時に表示されたメッセージが文字化け状態だったので、解消するためにどのような事を実践したのかについてまとめておきたいと思います。

## 環境
仕様エディタ：VsCode
ターミナル：git bash
PC：Window

## はっせいしてい文字化け
```bash
$ git commit -m 'git statusコマンド追記'
[main cb202c1] git status繧ｳ繝槭Φ繝芽ｿｽ險
 1 file changed, 1 insertion(+)

 ```

 文字化けとなっています。
 これをどうにかしたい。


## どうやら初期値は`true`と設定されているらしい

https://git-scm.com/docs/git-config

 > core.quotePath
パスを出力するコマンド (例: ls-files、diff ) は、パス名を二重引用符で囲み、C が制御文字 (例 \t: TAB、\nLF、\\バックスラッシュ) または 0x80 より大きい値を持つバイト (例: \302\265UTF-8 の「micro」の 8 進数) をエスケープするのと同じ方法で、パス名内の「異常な」文字をバックスラッシュでエスケープします。この変数を false に設定すると、0x80 より大きいバイトは「異常」とは見なされなくなります。二重引用符、バックスラッシュ、制御文字は、この変数の設定に関係なく常にエスケープされます。単純なスペース文字は「異常」とは見なされません。多くのコマンドは、この-zオプションを使用してパス名を完全に逐語的に出力できます。デフォルト値は true です。

サイトから該当部分を読んでみると、初期値は`true`。この状態で文字化けが起こっているので`false`にすれば解決できるという事がわかります


## 記事を参考に文字化け解消してみる

https://dev.classmethod.jp/articles/git-avoid-illegal-charactor-tips/

https://shishimaro.co.jp/blog/619

```bash
# このgitリポジトリのみの設定
$ git config --local core.quotepath false

# 全体に適用したい場合
$ git config --global core.quotepath false
```

## 最後に
いちおう上記コマンドで設定はできるようです。
※コマンド実行してすぐ直りはしなくて、私の場合VsCodeを再起動することで文字化けが解消されました。
Viteで作ったアプリをFirebaseでデプロイする手順

## はじめに
Vite を使って開発したアプリを Firebase Hosting にデプロイする手順をまとめました。
（注意: 本記事では Mac 環境 を前提に手順を説明しています。Windows や Linux では一部のコマンドが異なる場合があります。）

## 1. Firebase Hosting のセットアップ
まず、Firebase Hosting をセットアップします。

1. **Firebase プロジェクトを選択**
   ```bash
   firebase init hosting
   ```
2. **設定を進める**
   - 既存の Firebase プロジェクトを選択
   - 公開フォルダを `dist` に設定（Vite のビルドフォルダ）
   - シングルページアプリ（SPA）の設定を `Yes` にする
   - GitHub との連携は `No`（後で設定可能）

## 2. `firebase.json` の修正
Vite のビルドフォルダを正しくデプロイするために、`firebase.json` を編集します。

```json
{
  "hosting": {
    "public": "dist",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}
```

## 3. アプリをビルド
Vite のプロジェクトをビルドします。

```bash
npm run build
```

このコマンドを実行すると、`dist/` フォルダが作成されます。

## 4. Firebase にデプロイ
ビルドが完了したら、Firebase Hosting にデプロイします。

```bash
firebase deploy
```

デプロイが成功すると、Hosting URL が表示され、公開されたアプリにアクセスできます。

## 5. 変更を反映する方法
アプリに変更を加えたら、以下の手順で再デプロイできます。

```bash
npm run build
firebase deploy
```

これで、最新の変更が Firebase Hosting に反映されます！🎉

## まとめ
✅ Firebase Hosting をセットアップ
✅ `firebase.json` を編集（`public` を `dist` に変更）
✅ `npm run build` でビルド
✅ `firebase deploy` でデプロイ

これで Vite アプリを Firebase に公開できます。
電脳少女プログラミング2088 巨大コーポの最上階　を解いてみた

paiaの電脳少女　SQL問題を解いてみました。
以下、リンクになります。

https://ppg.paiza.jp/denno2088/areas/14

## 問題概要
画像のようなテーブルが与えられます。
ここから memory.id, memory.talk, person.name, battle.created_at を取得してください。
ただし、以下の条件が必要です。

- person (人物) のうち重要度が 5 の人物の person.deleted_at と同じ battle (戦闘) の battle.created_at (戦闘.作成日) 


![スクリーンショット (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1828135/72269e35-66c5-1879-7a79-786bd0fdfea5.png)

## 解法

まずは必要なテーブルを確認。
今回は以下の 4 つ。

- memory, log, battle, person

結合に関しては画像を見れば、つながりが分かるため素直に結合。

条件は 「person の重要度が 5 かつ、person.deleted_at と battle (戦闘) battle.created_at が同じ」なので以下のように書けます。

```sql
person.importance = 5
AND person.deleted_at = battle.created_at
```

これを実装すれば解くことができました。

## 解答例

```sql
SELECT
    memory.id,
    memory.talk,
    person.name,
    battle.created_at
FROM
    memory
INNER JOIN
    log
ON
    memory.id = log.memory_id
INNER JOIN
    battle
ON
    log.person_id = battle.person_id
INNER JOIN
    person
ON
    battle.person_id = person.id
WHERE
    person.importance = 5
    AND person.deleted_at = battle.created_at
;
```

## 余談
並び替えの指定がありませんでしたが、何が想定なのでしょうかね。
私にはわかりません😑
💯一流のOracle 1Z0-149ダンプ [2025年試験問題]

試験合格への道は決して簡単ではありません。広範なシラバスとタイトな準備スケジュールが課題となる中、適切な学習教材を選ぶことが成功のカギです。
そんなときに頼りになるのがPassitCertifyです。PassitCertifyは、認定試験で初回合格を目指すための本物のOracle 1Z0-149試験問題と専門家が検証した回答を提供します。

PassitCertifyがOracle 1Z0-149試験準備に最適な理由
PassitCertifyは、試験に焦点を当てた構成で、成功に向けた万全の準備をサポートします。多くの専門家が信頼するPassitCertifyの特徴をご紹介します。

✅ 本物の試験問題 – 実際の試験形式に基づいた最新の問題を専門家が検証
✅ 広範なトピックカバー – Oracleの基本概念からサービスの詳細、ビジネス価値の分析まで、シラバスのすべてを網羅
✅ 無料90日間アップデート – シラバスの変更にも追加費用なしで対応
✅ 35%割引オファー – プレミアムリソースが今だけお得に利用可能
✅ 24時間年中無休サポート – どんな時でもサポートチームがあなたをお手伝い

3つの学習形式で柔軟な準備が可能
学習スタイルは人それぞれ異なります。PassitCertifyでは、3つのユニークな形式であなたの学習スタイルに応じた準備をサポートします。

📄 PDF形式 – オフライン学習に最適。ダウンロードして印刷、どのデバイスでも利用可能
🖥 デスクトップ模擬試験 – 実際の試験環境をシミュレートし、時間制限付きの練習セッションと進捗管理が可能
🌐 Webベース模擬試験 – インストール不要。ブラウザがあればどこからでもオンラインで練習可能

🔥 特別オファー：全ての教材が35%割引 + 90日間の無料アップデート！

👉 今すぐ始めて、1Z0-149試験に合格しましょう！
https://www.passitcertify.com/oracle/1z0-149-questions.html

PassitCertifyで自信を持ってOracle 1Z0-149試験に合格
古いリソースや信頼性の低い教材を使って時間を無駄にする必要はありません。PassitCertifyは、構造化された学習アプローチと高品質の教材を提供し、合格への最短ルートをサポートします。多くの受験者がすでにPassitCertifyを活用して1Z0-149試験に合格しています。次はあなたの番です！

PassitCertifyの1Z0-149試験問題を使うメリット
🎯 重要なトピックに集中 – 試験の目標をカバーするために特別に設計された教材
⏳ 時間を節約 – 分散したリソースを探す必要はありません。必要なすべてがここにあります
📈 試験当日の自信を向上 – 現実的な模擬問題で準備し、試験前の不安を軽減
🏆 高い合格率 – PassitCertifyを使用した受験者の約90.5%が合格を報告

最短で成功への道を進みましょう。PassitCertifyに参加して、認定目標を楽々達成しましょう！
Google Maps API × Next.js でマップクラスターを実装する方法

# はじめに
Google Maps に多くのマーカーを表示すると、以下の問題が発生します。
- アイコンが重なり、視認性が悪くなる
- パフォーマンスの低下
- ユーザーが情報を把握しにくい

こうした問題を解決するのが Google Maps API の MarkerClusterer です！
本記事では、Next.js + Google Maps API を使い、マーカーをクラスター化する方法 を解説します。

# 参考
https://developers.google.com/maps/documentation/javascript/marker-clustering?hl=ja

# 実際の例
https://quickcleanrestrooms.com/

[![Image from Gyazo](https://i.gyazo.com/0d16c53bba1fab0fb756b710c0d1c6e7.jpg)](https://gyazo.com/0d16c53bba1fab0fb756b710c0d1c6e7)

## 必要なライブラリのインストール
まずは、Google Maps API 用のライブラリをインストールしましょう。

```
npm install @googlemaps/markerclusterer
``` 
また、Google Maps API を使うには Google Cloud Console で APIキーを取得 してください。

## 既存のマーカーをクラスター化する
ここでは、適当な座標データを使い、Google Maps にマーカーを表示し、クラスターを適用 します。

```AddMarkers.tsx
import { MarkerClusterer, DefaultRenderer } from '@googlemaps/markerclusterer';
import { useEffect, useRef } from 'react';

const AddMarkersContainer = ({ map }: { map: google.maps.Map | null }) => {
  const markersRef = useRef<google.maps.Marker[]>([]);
  const clustererRef = useRef<MarkerClusterer | null>(null);

  useEffect(() => {
    if (!map) return;

    // ダミーデータ（適当な座標リスト）
    const locations = [
      { lat: 35.6895, lng: 139.6917, title: '新宿' },
      { lat: 35.6586, lng: 139.7454, title: '東京タワー' },
      { lat: 35.7101, lng: 139.8107, title: '浅草' },
      { lat: 35.6764, lng: 139.6503, title: '渋谷' },
    ];

    // マーカーを作成
    const markers: google.maps.Marker[] = locations.map(({ lat, lng, title }) => {
      return new google.maps.Marker({
        position: { lat, lng },
        title,
        map,
      });
    });

    markersRef.current = markers;

    // クラスターのカスタムレンダラーを作成
    class CustomClusterRenderer extends DefaultRenderer {
      render({ count, position }: { count: number; position: google.maps.LatLng }) {
        const color = count > 10 ? 'red' : count > 5 ? 'orange' : 'blue';
        const size = count > 10 ? 80 : count > 5 ? 60 : 40;

        const svg = window.btoa(`
          <svg fill="${color}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240">
            <circle cx="120" cy="120" opacity=".8" r="70" />
          </svg>
        `);

        return new google.maps.Marker({
          position,
          icon: {
            url: `data:image/svg+xml;base64,${svg}`,
            scaledSize: new google.maps.Size(size, size),
          },
          label: {
            text: String(count),
            color: 'white',
            fontSize: '18px',
          },
          zIndex: 100000,
        });
      }
    }

    // 既存のクラスターをクリア
    if (clustererRef.current) {
      clustererRef.current.clearMarkers();
    }

    // クラスターを適用
    clustererRef.current = new MarkerClusterer({
      map,
      markers,
      renderer: new CustomClusterRenderer(),
    });
  }, [map]);

  return null;
};

export default AddMarkersContainer;
```

## 参考
マーカーはデフォルト以外にもカスタマイズ可能です。

https://github.com/googlemaps/js-markerclusterer

# まとめ
本記事では、Next.js と Google Maps API を使ってマーカーをクラスター化する方法 を解説しました。MarkerClusterer を活用し、マーカーの整理やカスタムデザインの適用、zIndex の調整による描画順序の管理を行いました。これにより、大量のマーカーでも見やすく、パフォーマンスの良い地図アプリ を構築できます！
読み手を配慮して読みやすく書く

# ◆この記事の目的
読みやすい文章を書くためのルールや技術を身に付ける

# 目次
▼[文章の形式に注意する](#文章の形式に注意する)
▼[１つの文が１つの内容を表す](#１つの文が１つの内容を表す)
▼[１文の長さに気を付ける](#１文の長さに気を付ける)
▼[主語と述語の注意点](#主語と述語の注意点)
▼[修飾語を使いこなそう](#修飾語を使いこなそう)
▼[助詞を使いこなそう](#助詞を使いこなそう)
▼[句読点の正しいルール](#句読点の正しいルール)

# ▼文章の形式に注意する
## 「ですます調」と「である調」の使い分け
- 丁寧で柔らかい印象で伝えたい、読み手の不安を解消したい
→「ですます調」

- 自信のある印象で伝えたい、正確な印象を与えたい
→「である調」

※意図がある混在はOK
例）操作内容：「である調」、操作結果：「ですます調」のパターン

> システムの設定を変更するためには、まず管理者権限を取得する必要がある。
その後、設定画面にアクセスし、該当するオプションを選択する。
これらの手順を実行すれば、設定が変更されます。

## 使役形を使わない
操作説明において、「～させる」「～せる」は使わない。

> :x:　カーソルを[保存]ボタンへ移動させます
> :o:　カーソルを[保存]ボタンへ移動します

# ▼１つの文が１つの内容を表す
１つの文に複数の内容があると、読み手は、どこまで読んだのか、どこまで行ったのかわからなくなる。

> :x:　[保存]ボタンをクリックした後、エラーメッセージの表示を確認してください
> :o:　1. [保存]ボタンをクリックしてください
>　　 2. エラーメッセージの表示を確認してください

# ▼１文の長さに気を付ける
１文は５０文字以内が読みやすいといわれている。

# ▼主語と述語の注意点
主語と述語の間に長い語句を入れない。

> :x:　[保存]ボタンは、必須項目を入力しないかぎり、クリックできません
> :o:　必須項目を入力しないかぎり、[保存]ボタンはクリックできません

# ▼修飾語を使いこなそう
## どの語句に係るのか明確にする

> :x:　１週間前に連絡した応募者が辞退したことがわかった
> :o:　１週間前に連絡した応募者が、辞退したことがわかった
> :o:　連絡した応募者が、１週間前に辞退したことがわかった

※読点で明確化する

## 長い修飾語から並べる

> :x:　安価な多様な機能をもっているシステム
> :o:　多様な機能をもっている安価なシステム

※ただし、時を示す修飾語は前に出す
> :x:　比較サイトで一番の、先週新機能を搭載したシステム
> :o:　先週新機能を搭載した、比較サイトで一番のシステム

# ▼助詞を使いこなそう
## 「は」と「が」を区別する
- 「は」：イコールの意味を示す
- 「が」：動作の主体を示す

> :x:　ユーザーは変更を行う
> :o:　ユーザーが変更を行う

## 「に」と「へ」を区別する
- 「に」：動作の到達点を示す
- 「へ」：方向を示す

> :x:　[保存]ボタンへ移動します
> :o:　[保存]ボタンに移動します

## 「の」を注意して使う
- 「の」：所有を示す

> :x:　弊社の推奨するシステム
> :o:　弊社が推奨するシステム

# ▼句読点の正しいルール
## 主語の後に読点
主語を明確にする

> :o:　弊社のサービスは、求職者のデータを管理するものです。

## 文頭の後に読点
内容の展開が把握しやすい

> :o:　しかし、広告のデータは管理できません。

## 理由の後に読点
意味を引き立てる

> :o:　検証環境のため、利用時間に制限があります。

# **参考文献**

[日本語スタイルガイド（第3版）](https://jtca.org/learn-tc/publication/guide_jsg/)
MSAにおけるサービスの分解とサブドメインパターン

# **MSAにおけるサービスの分解とサブドメインパターン**  

## **1. MSAにおける分離/分解の意味**  
- **定義**：「Business Capability（ビジネス能力）を持つ方向でサービスを定義すること」  
- **方法**：ビジネスの動作から問題領域（ドメイン）を導き出し、各領域で集中すべき部分をサブドメイン（Sub-Domain）として識別し、サービス化する  

## **2. サブドメインを基準としたサービスの分解（DDDより）**  
ビジネスの動作をもとにサブドメインを定義し、それに基づいてサービスを分解する  

### **例：注文サービス（顧客視点）**  
- **注文受付サービス**：注文を「正確に」受け付けることに集中  
- **注文決済サービス**：受けた注文の決済を「適切に」処理することに集中  
- **注文時の推薦サービス**：注文プロセスの中で「適切な」方法で追加商品購入を促すことに集中  

## **3. ドメイン駆動設計（DDD, Domain-Driven Design）**  
### **ドメインモデルの定義と役割**  
- **ドメインモデル**：ビジネス要件を満たすために、コア概念やルールを表現するオブジェクトの関係  
- **ドメインモデルの例**  
  - 「注文サービス」（顧客視点）  
  - 「配達サービス」（会社視点）  
  - 「飲食管理サービス」（飲食店視点）  

### **ドメインモデリングの目的**  
単にドメインを識別するのではなく、ドメイン間のコア概念やルールを表現し、適切に分離できるようにすること  

### **コア概念**  
- **エンティティ（Entity）**：1つのオブジェクト、データのまとまり（例：注文、商品）  
- **アグリゲート（Aggregate）**：データ変更の単位として扱う関連エンティティのまとまり  
- **アグリゲートルート（Aggregate Root）**：アグリゲートの中で中心となるエンティティ  


## **4. Bounded Contextとサブドメインパターン**  
### **Bounded Contextの基本原則**  
- 各ドメインは互いに排他的な問題を解決する必要がある  
- Bounded Contextを明確に定義し、ドメイン間の境界を設定する  

### **サブドメインパターンを活用したサービスの識別**  
- **Bounded Contextを持つサブドメイン**を各サービスとして識別  
- **各アグリゲート**が独立したBounded Contextを持てるように分離  
- **サービス分解**:  
  **サブドメインパターン**を使用すると、各ドメインを独立したサービスとして分割して管理でき、これによりMSAでの柔軟性と拡張性を確保できます。
Supabase の insertを使ってデータを登録する

Supabaseを使ってReact アプリ内でデータを **insert（追加）** する方法にフォーカスします。

### 前提

このチュートリアルでは、簡単な **学習記録アプリ** を作成

- ユーザーが学習内容と学習時間を入力し、登録ボタンを押すとデータが保存される
- 登録後にリストが自動更新され、リロードしてもデータが保持される
- Supabase の `insert` を使用してデータを追加

---

## 1. Supabase クライアントのセットアップ

`supabaseClient.js` を作成して以下を記述。

```javascript
import { createClient } from "@supabase/supabase-js";

const SUPABASE_URL = "https://xxxx.supabase.co";  // 自分のURLに変更
const SUPABASE_ANON_KEY = "your-anon-key";  // APIキーをセット

export const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
```

---

## 2. Supabase の `insert` を使ってデータを登録

### **① データを追加する関数**

```javascript
const onClickAdd = async () => {
  if (text === "") {
    setError("学習内容を入力してください");
    return;
  }
  if (time <= 0) {
    setError("学習時間を1以上にしてください");
    return;
  }
  setError("");
  
  // Supabase の `insert` を使ってデータを追加
  const { error } = await supabase.from("study-record").insert([{ text, time }]);
  if (error) {
    console.error("データ追加エラー:", error);
    return;
  }
  
  await fetchData();  // 最新データを取得
  setText("");
  setTime(0);
};
```

### **② データ取得用の `fetchData` を作成**

```javascript
const fetchData = async () => {
  const { data, error } = await supabase.from("study-record").select("*");
  if (error) {
    console.error("データ取得エラー:", error);
    return;
  }
  setRecords(data);
};
```

### **③ 初回データ取得を実行（マウント時の処理）**

```javascript
useEffect(() => {
  fetchData();
}, []);
```

#### **マウントとは？**

React では、コンポーネントが最初に画面に表示（追加）されることを **「マウント」** と呼びます。
この `useEffect` は、コンポーネントがマウントされたとき **（初回表示時）** に `fetchData()` を実行し、Supabase からデータを取得します。

#### **`useEffect(() => { fetchData(); }, []);` の動作**
-  `fetchData()` をコンポーネントの初回レンダリング時に実行  
-  `[]`（空の依存配列）を指定することで、初回のみ実行
- Supabase からデータを取得し、リロードしても表示されるようにする

#### **依存配列 `[]` とは？**

`useEffect` の第2引数には **「依存配列」** を指定できます。

```javascript
useEffect(() => {
  fetchData();
}, []);
```

- `[]`（空の配列）を指定すると、**最初の1回だけ実行される**  
- 例えば `[text]` を指定すると、`text` が変わるたびに `fetchData()` が実行される  
- `[]` を使うことで、**無駄な再実行を防ぐ**  

## まとめ

- Supabase の `insert` を使ってデータを追加
- 追加後に `fetchData()` でリストを最新化
- リロードしてもデータが保持される 
- マウント時に `fetchData()` を実行し、データを初期表示
- `[]`（依存配列）を使い、初回だけ実行されるよう制御


## 参考資料
https://supabase.com/docs/reference/javascript/insert

https://supabase.com/docs/reference/javascript/javascript
ナレッジ：業務で使ったSQL

PostgreSQLで使ったSQL
```:table_nameテーブルから全カラムを対象に（*はワイルドカード）where句でカラムの値を絞って上位5件を表示
select *
from table_name 
where column_name1 ='hoge' and column_name2 ='piyo' 
limit 5;
```

```SQL:left join
select カラム名
from 外部キーを持つ子テーブル
join 主キーを持つ親テーブル
on  子テーブル.外部キーを持つカラム名 = 親テーブル.主キーであるカラム名
left join 主キーを持つ親テーブル
on 子テーブル.外部キーを持つカラム名 = 親テーブル.主キーであるカラム名
where 条件

select hoge.column_name1,fuga.column_name2,hoge.column_name3,hugahuga.column_name4,hoge.column_name5,piyo.column_name6,hoge.column_name7
from table_name1 as hoge
left join table_name2 as piyo
on hoge.key_column_name = piyo.key_column_name 
and hoge.column_name5 = piyo.column_name5
left join table_name3 as fuga
on hoge.key_column_name = fuga.key_column_name 
and hoge.column_name1 = fuga.column_name1
left table_name4 as hugahuga
on hugahuga.key_column_name = hoge.key_column_name
and hugahuga.column_name1 = hoge.column_name1
and hugahuga.column_name3 = hoge.column_name3
where hoge.key_column_name = 'aaa' and hoge.column_name7 = '11';
```

```psql:実行結果をファイルに出力
\o [出力先ファイル名]
\i [ファイルを読み込んで処理を実行]
\o [出力先ファイルへの書き込み終了]
```
```psql:これでもイケる：実行結果をファイルに出力
\o [出力先ファイル名]
select文実行
\o [出力先ファイルへの書き込み終了]
```

```SQL:テーブルの定義とテーブルに含まれるカラムの情報を取得
\d+ table_name
```
```:↑の出力例
                                                  テーブル"public.table_name"
                 列                  |           型            | 照合順序 | Null 値を許容 | デフォルト | ストレージ | 統計目標 | 説明
-------------------------------------+-------------------------+----------+---------------+------------+------------+----------+------
 hoge                                | character varying(10)   |          | not null      |            | extended   |          |
 piyo                                | character varying(5)    |          | not null      |            | extended   |          |
 fuga                                | character varying(20)   |          | not null      |            | extended   |          |
【初投稿】記録①

## JavaScriptの勉強

始めてJavaScriptを組んでいる。勉強のためのメモとして残しておく。
なお、僕自身は全くのプログラミングの素人だが、こうして少しずつ勉強を進めて、エンジニアになれるように努力をしている。

## jQuery thisとchildren

thisはクリックされた時にJavaScriptの機能を発生させるというもの。

childrenは()で与えられた要素はすべて子供になり、それはJavaScriptの対象になるというものだった。


## Swiper

よくある画像を次に移動させるJS。
ボタンを押すと横に移動する。これ使ってたのか、という感じ。

## pagetopのボタン

ボタンを押すと反応し、ページの上部まで行ってくれる。
時間数も決めることが出来て面白い。

※本当にメモ書き程度です
暗号方式について学ぼう！

# この記事の対象者
- 暗号方式の仕組みをイメージとともに覚えたい人
- 基本情報等の試験に挑戦する人

# 暗号方式とは
混乱しやすいですが、暗号方式と暗号化アルゴリズムは別の概念となります。
- **暗号方式**：暗号化と複合のプロセス全体を含む<INS>枠組みや方法論</INS>
- **暗号化アルゴリズム**：データを暗号化する具体的な<INS>数学的手順や規則</INS>

当記事では暗号化方式を紹介するので、また別の記事でアルゴリズムについては扱っていきたいと思います。
暗号化方式で代表的なのは暗号鍵・復号鍵を使った「共通鍵暗号方式」「公開鍵暗号方式」「ハイブリッド暗号方式」の３つ！余裕があったら今後他の方式も調べようかと思います。

# そもそも「鍵」って？？
暗号化・復号化で用いられる「鍵」とは、データを変換するときに用いられる<INS>値</INS>です。
暗号化アルゴリズムそのものだと思われがちなのですが、内容をしっかり押さえておきましょう！

例えば以下の前提の上で相手にデータを送る場合を考えてみます。
＜前提＞
・相手に送るデータ：「リンゴがおいしい」
・暗号化アルゴリズム：鍵の文字列をデータに1文字ずつ挟む
・鍵：「あいうえお」

＜暗号化と復号化の流れ＞
鍵のデータを「リンゴがおいしい」に1文字ずつ挟むと暗号化データが作成できます。
![暗号化の仕組み.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4007480/5d241aed-4402-b5fd-6140-f6bc09812c85.png)
（図１．暗号化の流れ）

相手にデータが送られた後は逆に暗号化データから鍵のデータを1文字ずつ抜くことで解読できます。
![復号化の仕組み.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4007480/8b570cef-9e9e-8063-c75a-b3f41c198562.png)
（図２．復号化の流れ）

アルゴリズムは「方式」で、鍵はデータ変換時の「設定値」だということが分かりましたね。

# 暗号方式の仕組み
## １．共通鍵暗号方式
準備中

## ２．公開鍵暗号方式
準備中

## ３．ハイブリット暗号方式
準備中

# まとめ
準備中
表を使って説明・・・メリット、デメリット、利用例

:::note info
暗号化のポイント！
・暗号化を実現する枠組みや方法論が「暗号方式」、具体的な手順や規則が「暗号化アルゴリズム」、データを変換する設定値が「鍵」と呼ばれる
・暗号方式は「鍵」の使い方で「共通鍵暗号方式」「公開鍵暗号方式」「ハイブリッド暗号方式」の3つに分かれる
:::
useRefとuseStateって何が違うん？

## 前提

* 環境
  * vite 3.6.0
  * react 18.2.0

* 主にuseStateとの違いに重きを置いて説明しています。
  * 変数やDOMの状態管理だけではなくDOM操作（ボタンをクリックすると別DOMへフォーカスする、など）にも利用できますが今回はその説明はしていません、ご了承ください。

## 結論：`useRef` と `useState` の違い

| フック       | 再レンダリング時の値の保持 | 変数の変更による再レンダリング発火 |
|-------------|---------|-----------------|
| `useRef`   | される  | されない  |
| `useState` | されない | される    |

### `useRef` の特徴![Videotogif (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3909033/c838b541-b19b-0d6d-fbf4-02528427764d.gif)
![Videotogif (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3909033/daa1c127-0988-e1ca-49bc-30caf61c96f8.gif)


- **値は保持される** → 再レンダリングしても `useRef` の値はそのまま
- **変更してもレンダリングを引き起こさない** → UI の更新が必要ないデータを管理するのに向いている

### `useState` の特徴

- **値は保持されない** → 再レンダリングされるたびに初期化される
- **値を変更するとレンダリングが発生する** → UI の更新が必要なデータを管理するのに向いている

## それぞれの例を深ぼるよ

### `サンプルコード`

```jsx
import React, { useRef, useState } from "react";

const RefExample = () => {
  const countRef = useRef(0);
  const [count, setCount] = useState(0);

  const incrementRef = () => {
    countRef.current += 1;
    console.log("useRefの値: ", countRef.current);
  };

  const incrementState = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>useRef の値: {countRef.current}</p>
      <p>useState の値: {count}</p>
      <button onClick={incrementRef}>useRef の値を増やす</button>
      <button onClick={incrementState}>useState の値を増やす</button>
    </div>
  );
};

export default RefExample;
```

### 実行画面の挙動

**useRef の場合**
![Videotogif (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3909033/89e97657-8439-8cb4-80f9-b6b3978db60a.gif)

**useState の場合**
![Videotogif (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3909033/3df4f50c-e76c-7f3f-8fb0-c7a22fea6a3b.gif)

### 実行結果の解説

**再レンダリング時の値の保持について**

   - ボタンを押すと `countRef.current` の値は増えるが、画面上の表示は変わらない。（UI再レンダリングが発生しない）
   - だが実際には値は増える。`console.log()` で値の変化を確認できる。クリックするたびに+1が呼ばれしっかりとその値が保持されているのが確認できる

   - ボタンを押すと `count` の値が更新され、画面の表示も変わる（レンダリングが発生する）。

**変数の変更による再レンダリング発火について**
    ●   stateは更新されるたびにUIも変化する。つまりRefExampleコンポーネントが再実行され
```react
<p>useState の値: {count}</p>
```
の部分が更新されている。
    
   - countRedは該当する関数だけ実行しRefExampleコンポーネントは再実行しない。
       - そのため
       **console.log(countRef.count)** は実行されるが
       **<p>useRef の値:{countRef.current}</p>** には反映されない。


## どちらを使うべき？

- **再レンダリングが不要なデータの管理** → `useRef` を使う
- **UI の変更が必要なデータの管理** → `useState` を使う

## まとめ

- `useRef` は値を保持する＆基本再レンダリングは発生しない。
- `useState` は値を変更すると再レンダリングが発生する。

`useRef` と `useState` を正しく使い分けることで、効率的な React コンポーネントを作ることができます。ぜひ試してみてください！
MonoGameのカスタムパイプラインを作ろうとして躓いたところと対応

# 概要
MonoGameのカスタムパイプラインを作成するにあたり参考にしたサイトと、躓いた箇所と対応方法
あとでちゃんとした記事にしたい

# 参考にしたサイト
https://aristurtle.net/tutorials/content-pipeline-extension/01_introduction.html

このサイトのチュートリアルで、JSON形式のファイルのカスタムパイプラインの作成を参考にした。

# 躓きポイント
### カスタムパイプラインのターゲットフレームワークのバージョンは6.0
Create the MonoGame Content Pipeline Extension Projectの章
ここでプロジェクトのターゲットフレームワークを **6.0** から変更してはいけない。
あとの章で説明されるが、このプロジェクトのビルドdllをMGCBエディタで参照します。
MGCBエディタは.NET6.0対応で8.0以降は対応していない、このプロジェクトのターゲットフレームワークを変更すると後々MGCBエディタが想定の動きをしてくれない。(2025/02/11)

### 書き込みデータのクラス名を統一
Create the MonoGame Content Pipeline Extension Projectの章
JsonContentProcessorResultクラスを作成する項目で、ソースコードのクラス名と説明文が統一されてない。
これ以降の文でも統一されていないので、都度読み替えましょう。

### Runtimeパラメータ
Edit The JsonContentTypeWriterの章
MGCBエディタで設定するパラメータであるRuntimeパラメータを利用していない。
以下のソースコードを
``` C#:JsonContentTypeWriter.cs
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;

using TInput = JsonContentPipelineExtension.JsonContentResult;

namespace JsonContentPipelineExtension
{
    [ContentTypeWriter]
    internal class JsonContentTypeWriter : ContentTypeWriter<TInput>
    {
        protected override void Write(ContentWriter output, TInput value)
        {
            output.Write(value.Json);
        }

        public override string GetRuntimeReader(TargetPlatform targetPlatform)
        {
            return "JsonContentPipeline.JsonContentReader, JsonContentPipeline";
        }
    }
}
```
こう置き換えた
``` C#:JsonContentTypeWriter.cs
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;

using TInput = JsonContentPipelineExtension.JsonContentProcessorResult;

namespace JsonContentPipelineExtension
{
    [ContentTypeWriter]
    internal class JsonContentTypeWriter : ContentTypeWriter<TInput>
    {
        private string _RuntimeType;

        protected override void Write(ContentWriter output, TInput value)
        {
            _RuntimeType = value.RuntimeType;
            output.Write(value.Json);
        }

        public override string GetRuntimeReader(TargetPlatform targetPlatform)
        {
            if (string.IsNullOrEmpty(_RuntimeType) == false)
            {
                return _RuntimeType;
            }
            else
            {
                return "JsonContentPipeline.JsonContentTypeReader, JsonContentPipeline";
            }
        }
    }
}
```
defineEmitsに引数を与える


## defineEmitsとは
子コンポーネントから親コンポーネントの関数を実行する。

例）
1. 子コンポーネントのボタンをクリック
2. 親コンポーネントでメッセージを表示

```vuejs
<!-- 子コンポーネント ButtonComponent -->
<template>
  <button type="button" class="btn btn-success" @click="$emit('pushbutton')">
    ボタン
  </button>
</template>

<script setup lang="ts">
const emit = defineEmits(["pushbutton"]);
</script>
```
子コンポーネントにpushbuttonイベントを定義して、親コンポーネント側でハンドラー関数を紐づける。

```vuejs
<!-- 親コンポーネント -->
<template>
  <div>
    <ButtonComponent @pushbutton="handlePushButton('なんかのメッセージ')" />
    {{ buttonMessage }}
  </div>
</template>

<script setup lang="ts">
const buttonMessage = ref("")

// 子コンポーネントから呼ばれる関数
const handlePushButton = (msg: string) => {
  buttonMessage.vue = msg;
};
</script>
```

## 引数を持っていることを明示したい

親コンポーネントから引数を与える場合は、最初の例のように引数の定義がなくても問題ない。
これが気持ち悪いので子コンポーネント側で引数の型情報を与えても、子コンポーネント側で引数を矯正されるだけで親コンポーネント側で引数があることはわからない。

チェックしたい場合はどこかに型を定義して親コンポーネントと子コンポーネントで共有する必要がある。


```vuejs
<script setup lang="ts">
const emit = defineEmits<{
  (e: "pushbutton", msg: string): void;
}>();
</script>
```
Amazon Cognito備忘録：「Invalid input: Temporary password has expired and must be reset by an administrator.」エラーについて

## はじめに  
Cognito を利用している環境で、新規ユーザー登録時やパスワードリセット時に発行される一時パスワードの期限切れエラーに遭遇しました。  

:::note warn
AWS マネジメントコンソールではリセットができず、CLI を使う必要がありました。
:::

この経験をもとに、エラーの発生原因や解決方法をまとめます。  

## 書こうと思ったきっかけ  
受講しているITスクールのチーム開発（ハッカソン）で、一時パスワードの期限切れによりログインできない問題が発生しました。

***特に、AWS マネジメントコンソールでは直接リセットできない点が意外でした。（※私の環境の場合）***

:::note info
**CLI を使えば解決できることがわかったため、同じ問題で困る人の参考になればと思い、記録することにしました。**
:::

また、今後の対策を考える上でも、整理しておくことで役立つと感じました。

## 発生していたエラー

```エラー.log
Invalid input: Temporary password has expired and must be reset by an administrator.
```

**このエラーは、Cognitoで発行された一時パスワードの有効期限が切れている場合に発生します。**

そのため、通常のログインでは認証が通らず、管理者によるパスワードのリセットが必要になります。

**実際のマネコン画面**

![Screenshot 2025-02-11 at 17.55.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/169e05bf-9d41-7f59-c9ed-ab55467507f0.png)

### 原因
Amazon Cognitoでは、新しいユーザーを作成した際や、パスワードをリセットした際に、一時パスワードが発行されます。

しかし、この一時パスワードには有効期限が設定されており、期限を過ぎると使用できなくなります。

:::note alert
**そのため、ユーザーが一定期間ログインしない場合や、パスワードの変更をしないままでいると、期限切れとなりログイン不可の状態になります。**
:::

また、AWSマネジメントコンソールでは直接パスワードをリセットできない場合があるため、適切な対応方法を知っておくことが重要です。

## 実際にリセットしてみた
AWSマネジメントコンソールからパスワードをリセットしようと試みましたが、「**リセット**」ボタンがグレーアウトされており、操作できない状態でした。

**このため、コンソール上では直接リセットできないことが確認できました。**

**実際のマネコン画面**

![Screenshot 2025-02-11 at 17.59.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/73605650-600e-1e81-bc28-86225ae23c7a.png)

### AWS CLI でリセットしてみた
マネジメントコンソールでのリセットができなかったため、AWS CLI を使用してパスワードをリセットしました。

**以下のコマンドを実行することで、対象ユーザーのパスワードを恒久的なものに変更できます（今回はあくまで検証のため）。**

```sh
aws cognito-idp admin-set-user-password \
  --user-pool-id <ユーザープールID> \
  --username <対象ユーザー名> \
  --password <新しいパスワード> \
  --permanent
```

**コマンドの説明**

`<ユーザープールID>` → Cognito のユーザープール ID  
`<対象ユーザー名>` → 対象のユーザー名  
`<新しいパスワード>` → 任意の新しいパスワード  

また、`--permanent` オプションを付与することで、新しいパスワードを「**一時パスワード**」ではなく、恒久的なパスワードとして設定できます。

**実際のマネコン画面（リセット後）**

![Screenshot 2025-02-11 at 18.05.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/019f8c20-87d9-c977-8315-8ef8dc5a815d.png)

## 今後の対策

- **一時パスワードの期限を考慮して、早めにログインさせる**  
- **ユーザー登録時に仮パスワードをすぐに変更させる**  
- **自動パスワードリセット機能（Forgot Password）を実装する**  

## まとめ
Amazon Cognito の一時パスワードには有効期限があり、期限を過ぎると使用できなくなります。

**その場合、AWS マネジメントコンソールではリセットできないことがあるため、CLI を使用してリセットする必要があります。**

:::note info
**今後は、ユーザーに早めのログインを促し、仮パスワードの変更を義務付ける仕組みを整えることが重要だと感じました。**
:::

さらに、今後も積極的に遭遇したエラーを記録し、同じ問題に直面した際の解決策を素早く見つけられるようにアウトプットを続けていこうと思います！
OracleDBのKeepAliveについて

# はじめに
参画している案件でOracleDBのKeepAlive設定を行う機会があったのでまとめてみました。


# KeepAliveとは
KeepAliveとはネットワーク接続が有効であるか確認するため定期的に行われる通信のことを指します。

接続先がハングや強制停止されエラーを戻さなかった場合でも、接続元からの定期的なチェックにより、エラーとして検知できるようになります。

また非アクティブ状態が一定時間続いた場合に強制切断する設定を入れている環境(例えばDBサーバとクライアントサーバの間にあるNW機器がアイドル状態の接続に対してタイムアウト設定を持っているときなど)での、意図しない切断の回避などにも有効です。

# OracleDBのKeepAlive設定について
## クライアントサーバ側
KeepAliveの設定はデフォルトではオフになっています。
設定する際は以下のようにtnsnames.oraに(ENABLE = BROKEN)を追加することで有効化できます。

```:tnanames.ora
ORCL =
  (DESCRIPTION =
    (ENABLE = BROKEN)
    (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = orcl)
    )
  )

```
### OSのデフォルト値
RHEL8.6の場合以下のコマンドを実行して確認することができます。

```
# sysctl -a | grep tcp_keepalive
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_time = 7200
```
- **net.ipv4.tcp_keepalive_intvl**
　KeepAlive 送信開始後、何ミリ秒間隔で次の KeepAlive を送信するか


- **net.ipv4.tcp_keepalive_probes**
　TCP コネクション開始から KeepAlive の送信を開始するまでの時間　


- **net.ipv4.tcp_keepalive_time**
　KeepAlive を送信し、何回応答が無かったら TCP コネクションを切断するか

### KeepAliveのチェック間隔値変更方法
RHEL8.6の場合以下のようにsysctl.confを編集して変更します。
※デフォルト値が適用されている場合は追記が必要

```
# vi /etc/sysctl.conf

<!--以下の内容を記載 -->
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_time = 3600

# sysctl -p
#
# sysctl -a | grep tcp_keepalive
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_time = 3600

```



## DBサーバ側
デフォルトでOSのKeepAliveが適用されています。
sqlnet.oraに SQLNET.EXPIRE_TIME が設定されている場合はそちらが優先されます。 SQLNET.EXPIRE_TIME に指定した数値（分単位）の間隔で、KeepAlive(プローブ・パケットの送信)を実行します。
チェック間隔を短くする場合、特にプロセス数が多い場合などはネットワークへの負荷が多少増加するため、注意する必要があります。
下の例では10分ごとにKeepAliveを実行します。

```:sqlnet.ora
SQLNET.EXPIRE_TIME=10

```

## 最後に
ご覧いただきありがとうございました。
この記事がどなたかのお役に立てれば幸いです。
pythonでcsvファイル等から三角図を出力する


材料系で頻出グラフの三角プロットを`python`で行うときのメモ。

# モジュールのインストール

今回紹介するのは、`mpltern`
https://mpltern.readthedocs.io/

`pip`でのインストールは、以下の通り。

```python
pip install mpltern
```


# 実例

## デモデータ

たとえば`Excel`等で以下のようなデータが入っているとする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221968/b58cc14d-730d-817d-8364-83a5fbf80cbd.png)

そして、それが、`data.csv`として保存されているとする。
なお、例題のミソとして、文字列と数値が混在しているものを用意した。ただし文字列にスペースは入ってはいけない。

## コード

```python
import numpy as np
import matplotlib.pyplot as plt
import mpltern

f = np.loadtxt("data.csv",delimiter=",",dtype = "unicode")
ff = np.zeros(f.shape,"float32")
ff[1:10,1:10]=f[1:10,1:10].astype("float")


top=4   #for Si
left=2  #for Mg
right=6 #for Fe

ax = plt.subplot(projection="ternary")

for i in range(1,6):
  ax.scatter(ff[top][i],ff[left][i],ff[right][i], alpha=0.5, label="filt"+f[0][i])

ax.set_tlabel(str(f.T[0][top]),fontsize=16)
ax.set_llabel(str(f.T[0][left]),fontsize=16)
ax.set_rlabel(str(f.T[0][right]),fontsize=16)

ax.legend()

plt.show()
```

## 出力

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221968/69e5d906-c9e6-0430-9c92-268746a8d8e2.png)

## コメント

### 文字列として読み込み

```python
f = np.loadtxt("data.csv",delimiter=",",dtype = "unicode")
ff = np.zeros(f.shape,"float32")
ff[1:10,1:10]=f[1:10,1:10].astype("float")
```

`csv`の読み取りには`np.loadtxt`をつかいます。
`delimiter=","`で、カンマ区切り、
`dtype = "unicode"`で文字列として読み込みです。

その後、2,3行目で、数値だけの配列を作成します。

文字列として読み込むことで、凡例やラベルに使えるようにします。

### 軸の選択

ここでは、Si,Mg,Feを軸として使うための指定をします。
わざわざ定数化することにより、汎用性を持たせています。

```python
top=4   #for Si
left=2  #for Mg
right=6 #for Fe
```

### グラフ描画の本体

```python
ax = plt.subplot(projection="ternary")

for i in range(1,6):
  ax.scatter(ff[top][i],ff[left][i],ff[right][i], alpha=0.5, label="filt"+f[0][i])

ax.set_tlabel(str(f.T[0][top]),fontsize=16)
ax.set_llabel(str(f.T[0][left]),fontsize=16)
ax.set_rlabel(str(f.T[0][right]),fontsize=16)

ax.legend()

plt.show()
```

for文を使うことで、データ点を増やしている
【ShellScript】shコマンドとsourceコマンドの違いについて

# 1. はじめに
ARアドバンストテクノロジ株式会社（略称：ARI）でクラウドエンジニアをしている大畑と申します。

突然ですが、皆さんがShellScriptを実行するときに、何のコマンドを利用されていますでしょうか。

```
sh example.sh
```
のように **sh** を利用することもあれば、

```
source example.sh
```

のように**source** を利用する場合もあると思います。

この記事では、それぞれのコマンドの違いと適切な使い方を解説したいと思います。

# 2. shコマンドとは

## shコマンドの概要（新しいシェル環境を作成してスクリプトを実行）
`sh` コマンドは、**新しいシェル環境を作成**し、その環境内でスクリプトを実行します。  
実行後は元のシェル環境に戻るため、スクリプト内で設定された**変数や関数は親シェルには影響しません**。

## 基本的な使い方（例：sh script.sh）
シェルスクリプト `script.sh` を `sh` コマンドで実行する方法は以下のとおりです。

```sh
sh script.sh
```



# 3. sourceコマンドとは

## sourceコマンドの概要（現在のシェル環境でスクリプトを実行）
`source` コマンドは、**現在のシェル環境を維持したまま** スクリプトを実行します。  
そのため、スクリプト内で定義した **変数や関数** は、実行後も親シェルに残ります。

通常、環境変数やエイリアスの設定を適用する目的で使用されます。

## 基本的な使い方（例：source script.sh または . script.sh）

スクリプト `script.sh` を現在のシェル環境で実行するには、以下のコマンドを使用します。

```sh
source script.sh
```

または、source の短縮形である ドット (.) コマンド も利用できます。

```sh
. script.sh
```




# 4. shとsourceの主な違い
まとめると以下のようになります。

| 項目           | shコマンド              | sourceコマンド                   |
|--------------|---------------------|-----------------------------|
| シェル環境      | 新しいシェルを作成      | 現在のシェルを使用             |
| 変数の引き継ぎ  | 親シェルに影響なし      | 親シェルに影響あり             |
| 実行対象      | 実行可能なスクリプト    | スクリプト内の設定や関数の適用 |
| 使いどころ    | 独立したスクリプト実行  | 設定ファイルの適用（環境変数・エイリアス） |


# 5. shとsourceで実行結果を比較してみる

実行環境はAWSのCloudShellを利用します。（fedoraベースのAmazon Linux 2023が基盤）

http://aws.amazon.com/jp/cloudshell/


## 環境変数への影響
以下のようなテスト用ファイルを作成しました。

```shell
# test.sh
HOGE="Hello"
echo $HOGE
```

shとsourceの両方で実行してみます。

まずはshコマンドでテスト用ファイルを実行します。

```shell
sh test.sh
> Hello # 環境変数が設定され、正しく出力される
```

shell実行後の環境変数がどうなっているかを確認してみます。

```shell
echo $HOGE
> # 出力なし、ShellScriptで設定した環境変数が引き継がれていない
```

続いてsourceコマンドでテスト用ファイルを実行します。
```shell
source test.sh 
> Hello # 環境変数が設定され、正しく出力される
```

shell実行後の環境変数がどうなっているかを確認してみます。

```shell
echo $HOGE
> Hello # ShellScriptで設定した環境変数が引き継がれている
```


## 関数への影響

以下のようなテスト用ファイルを作成しました。
```shell
# func.sh
my_function() {
    echo "This is a function"
}
```

まずはshコマンドでテスト用ファイルを実行し、関数を呼び出してみます。

```
sh func.sh
my_function

> bash: my_function: command not found # shellscriptで定義した関数を呼び出すことができない
```


続いてsourceコマンドでテスト用ファイルを実行し、関数を呼び出してみます。
```
source test.sh 
my_function

> This is a function # shellscriptで定義した関数を呼び出すことが可能
```

# 6. まとめ
環境変数を設定するような場面
 - PATH 環境変数を追加し、コマンドを実行できるようにする
 - gitやJavaなどのアプリを利用するときの設定値を記載する
 - AWSの認証情報の埋め込み

などを効率化するために、shellscriptでツール化している場合は、実行方法に注意が必要です。

**sh** : 新しいshell環境を作成し、実行する
**source**  : 現在のshell環境で実行する

という違いを踏まえたうえで適切に利用しましょう。

以上、**「shコマンドとsourceコマンドの違いについて」** でした。

## 仲間を募集しています！

ARIではエンジニア・ITコンサルタント・PM職全方位で仲間を募集しております。
カジュアル面談、随時受付中です！
ご興味ある方はこちらをご覧ください。

https://note.com/ari_hr/n/n4aed9ba75421
メソッドチェーンとは？

## メソッドチェーンとは？

メソッドチェーン（Method Chaining） とは、
オブジェクト指向プログラミングで 複数のメソッドを連続して呼び出す 書き方のことです。
LaravelのCollectionでは、メソッドチェーンを活用することで、コードをシンプルかつ可読性の高いものにできます。

## メソッドチェーンの基本
通常、複数の処理をするときは変数に代入しながら書くことが多いです。

#### 例：通常の配列操作
```php
$numbers = [1, 2, 3, 4, 5];

// ① 2倍にする
$doubled = array_map(function ($num) {
    return $num * 2;
}, $numbers);

// ② 偶数のみを取得
$filtered = array_filter($doubled, function ($num) {
    return $num % 2 === 0;
});

// ③ インデックスをリセット
$final = array_values($filtered);

print_r($final); // [2, 4, 6, 8, 10]
```

▶ 問題点
- doubled, filtered, final の中間変数が増えるため、コードが長くなりがち。

---

#### Collectionでのメソッドチェーン
```php
$final = collect([1, 2, 3, 4, 5])
    ->map(fn($num) => $num * 2)  // ① 2倍にする
    ->filter(fn($num) => $num % 2 === 0) // ② 偶数のみ取得
    ->values(); // ③ インデックスをリセット

print_r($final->all()); // [2, 4, 6, 8, 10]

```
▶ メリット

- 中間変数が不要になり、コードがスッキリする。
- 処理の流れが直感的に理解しやすい。
- 無駄な配列操作が減るため、パフォーマンスが向上する。

## メソッドチェーンの活用例
#### ユーザー情報の処理について
例えば、以下のようなデータがあるとする。
```php
$users = collect([
    ['id' => 1, 'name' => 'Alice', 'age' => 25],
    ['id' => 2, 'name' => 'Bob', 'age' => 17],
    ['id' => 3, 'name' => 'Charlie', 'age' => 30],
]);
```

このデータから **年齢20歳以上のユーザー名を取得する**とする

##### メソッドチェーンを使った場合

```php
$adultNames = $users
    ->filter(fn($user) => $user['age'] >= 20) // ① 20歳以上にフィルタ
    ->map(fn($user) => $user['name']) // ② 名前だけ取得
    ->values(); // ③ インデックスをリセット

print_r($adultNames->all()); // ['Alice', 'Charlie']
```

##### 通常の配列を使った場合
```php
$filtered = array_filter($users, function ($user) {
    return $user['age'] >= 20;
});

$names = array_map(function ($user) {
    return $user['name'];
}, $filtered);

$final = array_values($names);

print_r($final); // ['Alice', 'Charlie']
```

▶ Collectionを使うと 簡潔 になるのが分かる！
vue.jsのバージョン確認方法

## npm list

```
npm list
```
リストが表示されるのでvue@を探す。下記の例で3.5.12。
```
├── @vuepic/vue-datepicker@10.0.0
├── bootstrap-icons@1.11.3
├── bootstrap@5.3.3
├── nuxt@3.14.159
├── vue-router@4.4.5
└── vue@3.5.12
```

## npm listから検索

```shell
npm list vue --depth=0
```
コマンドで指定した名前のパッケージのみが表示される。
--depth=0を指定してトップレベルのパッケージ名のみに限定する。
そうしないと依存関係のあるパッケージも検索されてしまう。
```shell
└── vue@3.5.12
```

## package-lock.jsonから探す

package-lock.jsonを開いて`node_modules/vue`で検索する
versionのところを見る。
```json
    "node_modules/vue": {
      "version": "3.5.12",
      "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.12.tgz",
      "integrity": "sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==",
      "dependencies": {
        "@vue/compiler-dom": "3.5.12",
        "@vue/compiler-sfc": "3.5.12",
```