OmniAICreator/Qiita-1.07M huggingface dataset:
【個人用】AWS Solution Architect Associate対策ノート(VPC編)

## VPCの基礎知識
・一つのリージョン内に複数作成できる
・一つのVPCは、リージョン内のすべてのAZにまたがる
・デフォルトでは、他のVPCやインターネットと通信できない

## サブネットの基礎知識
・VPC内のネットワーク空間を論理的に分割したもの
・各サブネットは、１つのAZに属し、１つのAZ内に複数のサブネットを作れる

## VPCからインターネットへの接続に使うもの
VPCからインターネットにつなぐには以下のものを使う

### NATゲートウェイ

・プライベートサブネットからインターネットへのアクセスを可能にする
・マネージド型である
・AWSによってAZ内で冗長化されている
・プライベートIPアドレスをElastic IPアドレスに変換してくれる
・パブリックサブネットに配置する

### NATインスタンス

・プライベートサブネットからインターネットへのアクセスを可能にする

・**アンマネージド型**である(EC2インスタンスから作成するため)

・AWSによってAZ内で冗長化されて**いない**

・プライベートIPアドレスをElastic IPアドレスに変換してくれる

・パブリックサブネットに配置する

・ポート転送機能の設定ができる
→ポート転送とは、インターネットから送信された特定のポート番号あてのデータを、プライベートサブネット内のインスタンスの別のポートへ転送すること

・VPC外からプライベートサブネット内へ接続する際の踏み台サーバーとしても使える

※
・踏み台サーバーとは
たとえば、インターネットからプライベートサブネット内のサーバーの保守をしたいときに、いったんNATインスタンス(踏み台サーバー)にSSH接続をした後、そのNATインスタンスから保守したいサーバーへ再度SSH接続をすることで、外から直接接続できないプライベートサブネット内のサーバーへの接続を可能にするもの

## IPアドレス

### Erastic IPアドレス
・インターネットと通信可能な固定のパブリックIPアドレス
・AWSリソースに手動で割り当てる
・AWSリソースが停止・削除されても、IPアドレスは変わらない。そのかわり、利用料金が発生し続ける。

### パブリックIPアドレス
・AWSリソースを削除するとIPアドレスが解放されるので、変化する

### プライベートIPアドレス
・インターネットと通信不可のIPアドレス
・VPC内のAWSリソースに自動で割り当てられる
・AWSリソースが停止・起動されても、IPアドレスは変わらないが、削除されると解放される

## VPCエンドポイントについて
プライベートサブネット内のAWSリソースから、インターネットゲートウェイを経由せずに外のAWSサービスに接続するには**VPCエンドポイント**をつかう

VPCエンドポイントからどこに接続するかを、**VPCエンドポイントポリシー**で設定できる

VPCエンドポイントは２種類ある
・**ゲートウェイ型**

・**AWS Private Link(インターフェース型)**

## インターネットゲートウェイについて
プライベートサブネット内のAWSリソースとインターネットを接続する機能
インターネットゲートウェイへのルーティングが設定されたサブネットは、パブリックサブネットになる

## Egress-Onlyインターネットゲートウェイ
NATゲートウェイとインターネットゲートウェイの特徴を併せ持つ、IPv6専用の機能
VPCからインターネットへの接続はできるようにする(egress)が、インターネットからVPCへの接続はできないようにする

## CIDRについて

CIDR(Classless Internet Domain Routing)とは、ネットワークの範囲を指定するIPアドレスの指定方法のこと

CIDRは、IPアドレスを「172.16.0.100/24」のように表記する
この「/24」を**プレフィックス長**といい、IPアドレスとプレフィックス長によって、どのネットワークに所属するのかが決まる
IPアドレスが「172.16.0.100/24」だった場合、IPアドレスを2進数表記にしたとき、左から24ビット目までの範囲がプレフィックスになる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751890/4b904b1f-c74b-804d-1d13-31556c2b9536.png)

プレフィックスに該当するIPアドレスの部分をネットワークアドレスと呼び、このネットワークアドレスの範囲のことを「CIDRブロック」と呼ぶ

VPCとサブネットのCIDRブロックは、**/16から/28**のプレフィックス長を指定する

## IPv4アドレスの範囲
・10.0.0.0 ～ 10.255.255.255
・172.16.0.0 ～ 172.31.255.255
・192.168.0.0 ～ 192.168.255.255

## VPCのファイアウオールについて

### セキュリティグループ
・VPC上で、ネットワークアクセスをインスタンスごとに制御するファイアウオール
・**許可ルールのみ指定でき、拒否ルールは指定できない**
・デフォルトでは、すべてのインバウンド通信を拒否、すべてのアウトバウンド通信を許可している
・送信元や送信先にIPアドレスの範囲や、別のセキュリティグループを指定できる

### ネットワークACL
・VPC上で、ネットワークアクセスをサブネットごとに制御するファイアウオール
・許可ルール、拒否ルールどちらも設定可能
・デフォルトでは、すべてのインバウンド通信とアウトバウンド通信が許可されている
・送信元や送信先にIPアドレスの範囲のみ指定できる。別のACLやセキュリティグループは指定できない。
・通信の状態を管理しないステートレスである
Azure AIのSpeech Studioを軽く触ってみた

# 概要

Azure AIのSpeech StudioというWebサービスを使うと、トレーニング済みのモデルを利用して、ブラウザで、音声の解析や、音声とテキストの相互変換のデモを試すことができます。

https://speech.microsoft.com/portal

# 主な機能

Speech（音声）の主な機能は以下のとおりです。
* テキストを読み上げる。
    * 音声合成マークアップ言語（SSML）を利用して、読み上げ方を変える。
* 音声をテキストに変換する。（文字起こし） 
* 意図認識を実装する
    * 何をして欲しいか、何を教えて欲しいかと言った意図をあらかじめ登録して、それにヒットさせる。
* キーワード認識
    * 「Hey, Siri~」のように、ある処理を呼び出す開始合図となる言葉を登録できる。

# Speech Studioとは

Copilotに聞いてみました。

> AzureのSpeech Studioは、アプリケーションに音声サービスの機能を組み込むためのUIベースのツールセットです。コーディングなしでプロジェクトを作成し、音声テキスト変換、テキスト読み上げ、音声翻訳などの機能を簡単にテストおよび統合できます12。
> 
> 具体的には、以下のような機能があります12：
> 
> リアルタイム音声テキスト変換：音声をリアルタイムでテキストに変換します。
> バッチ音声テキスト変換：大量の音声データを一括で文字起こしします。
> カスタム音声モデル：特定のボキャブラリや話し方に合わせた音声認識モデルを作成します。
> 発音評価：発音の正確性と流暢性を評価します。
> 音声翻訳：音声を他の言語に翻訳します。
> カスタム音声：独自のカスタム音声を作成し、テキスト読み上げに使用します。
> これにより、開発者は音声認識や音声合成の機能を簡単にアプリケーションに組み込むことができます。

URLはこちらです。

https://speech.microsoft.com/portal

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/42010d9a-a4cc-72b7-3900-d8b8744b4463.png)

それでは、早速使ってみましょう。

# Captioning with speech to text

リアルタイム、またはオフライン（あらかじめ録音（録画）したデータ）に、キャプションをつけることが出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/a60eba70-281e-e47f-d687-2c60e978dee6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/4e798c81-9ef7-d812-7507-d1590b64a738.png)

リアルタイムの方は、後から、単語が書き換えられることがあり、やや読みにくいです。
オフラインの方は、よくある洋画の字幕のように表示され、表示タイミングが絶妙で読みやすいです。

手元のmp3, mp4ファイルなどをアップロードして、文字起こしもできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/3e7aed53-5664-cc76-1ed0-a300596a2055.png)
日本語のサンプルmp3ファイルをダウンロードして試してみました。

# Language learning

マイクとスピーカーを使って、AIと話ができます。
いずれは、言語学習の教材になりそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/1e8a27c6-87ed-fd67-7f7a-b69159617fa4.png)

終了時には、スコアが表示されます。
結果が良かったものを貼り付けておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/6ecd755f-6e4b-1243-5a95-7376c2f7e8c5.png)

将来は英語のスピーキングテストの本試験を、AIが実施することになるかもしれません・・。人間の試験官を、各試験会場に複数貼り付けるより、公平性が保たれそうです。

# Post call transcription and analytics
コールセンターの録音データを元に、文字起こし、センテンスごとのポジネガ評価、個人情報のマスキング、要約をしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/2134c237-ca69-37bc-981e-6ebc8991db5d.png)
Auth.js v5とnext-intlを組み合わせてmiddlewareを構築する方法

Auth.jsのv5-betaと、next-intlを組み合わせてmiddlewareを書く方法が載ってなかったのでメモを残します。

```typescript
import { auth } from '@/auth';
import { routing } from '@/i18n/routing';
import createMiddleware from 'next-intl/middleware';

const handleI18nRouting = createMiddleware(routing);
export default auth(handleI18nRouting);

export const config = {
  matcher: ['/((?!api|_next|.*\\..*).*)'],
};
```

なお、`auth`は以下。詳しい書き方は[こちら](https://authjs.dev/getting-started/installation)。
```typescript
export const { handlers, signIn, signOut, auth } = NextAuth({
  // ...
});
```

また、`routing`は以下。詳しい書き方は[こちら](https://next-intl.dev/docs/getting-started/app-router/with-i18n-routing)
```typescript
import { createNavigation } from 'next-intl/navigation';
import { defineRouting } from 'next-intl/routing';

export const routing = defineRouting({
  // A list of all locales that are supported
  locales: ['en', 'ja'],
  // Used when no locale matches
  defaultLocale: 'ja',
});

export type Locale = (typeof routing.locales)[number];

// Lightweight wrappers around Next.js' navigation APIs
// that will consider the routing configuration
export const { Link, redirect, usePathname, useRouter, getPathname } =
  createNavigation(routing);

```
【GitHub Actions エラー】CDした時に出たエラーその1 "Error: firebase use must be run from a Firebase project directory."

# はじめに
GitHub ActionsでFirebaseにデプロイした時の遭遇した複数のエラーについて書いていきます。

# 問題
```plaintext:エラーメッセージ その1
Error: firebase use must be run from a Firebase project directory.

Run firebase init to start a project directory in the current folder.
```

# 解決方法
ChatGPTに聞くと、エラーメッセージの解説、原因、解決策を教えてくれました。
私は、以下の「ChatGPTによる原因解説」にある**2.firebase.json や .firebaserc ファイルがない**という指摘にピンッときて、そういえば**前述の2つのファイルと最新のプロジェクトファイルをpushしていなかった**ことに気づき、pushをすることでこのエラーは解決できました。

```plaintext:ChatGPTによるエラーメッセージの解説
1.firebase use must be run from a Firebase project directory.
    •意味: firebase use コマンドは、Firebaseプロジェクトディレクトリの中でしか実行できません。
    •Firebase CLIは、ディレクトリ内にfirebase.jsonや.firebasercなどの設定ファイルがあることを前提としています。
        
2.Run firebase init to start a project directory in the current folder.
    •意味: 現在のフォルダで firebase init コマンドを実行して、Firebaseプロジェクトを初期化する必要があります。
```

```plaintext:ChatGPTによる原因解説
1.プロジェクトディレクトリが設定されていない
	•GitHub Actionsでのワークフローが、Firebaseプロジェクトとして初期化されていないフォルダで実行されている。

2.firebase.json や .firebaserc ファイルがない
	•Firebase CLIが必要とする設定ファイルが、リポジトリやワークフロー実行環境に存在していない。

3.GitHub Actionsでのセットアップが不完全
    •ワークフローでリポジトリを正しくチェックアウトしていない。
    •Firebase CLIを適切にインストール・設定していない。
```

:::note warn
ChatGPTによる解決策の提案は実施せずに解決できたのでこの記事では割愛しています。
:::

# おわりに
初歩的なミスですが、このミスでFirebaseのプロジェクトにおいてfirebase.json、.firebasercが必要だということが理解できました。
DCDCコンバータを設計しよう

みなさん、DCDCコンバータを設計したいと思ったことはありますか？

今回は、回路初心者の方でもできるDCDCコンバータ回路設計ということで、TPS5430を使用したDCDCコンバータを作ってみたいと思います。

# DCDCコンバータとは
直流電源の電圧を変える装置です。昇圧型、降圧型、昇降圧型などがあります。
電圧を変換する部品として三端子レギュレータもありますが、これは電圧を下げる分を熱として放出するため、あまり大きな電流は流せません。
それに対してDCDCコンバータは比較的大きな電流を流すことができます。
その一方で回路設計が大変という欠点があります。

# 今回作るもの
今回は電圧7.2V、電流3AのDCDCコンバータを作ります。

# 使用部品
今回はTexas InstrumentsのTPS5430という降圧DCDCコンバータを使用します。

製品情報・データシートは↓こちらにあります。

https://www.ti.com/product/ja-jp/TPS5430

# 回路設計しよう

データシートの7.2に回路図の例が示されています。基本的にはデータシートに回路図が載っていればそれを利用しましょう。そして、それぞれの部品の値は作りたいものによって変わるので計算しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124670/5df7e70f-b476-c3a2-0c6a-f5a6d030af95.png)
（TPS5430データシート 「図 7-1. アプリケーション回路、12V 入力から 5.0V 出力」より）


VINが電源入力、VOUTが電源出力、ENがDCDCコンバータのON/OFFです。

5V・3Aのものでよければこの図の通りでよいです。しかしそれではつまらないので今回は7.2V・3Aのものを作ってみたいと思います。


まず、直接出力電圧に関わるのはVSNSにつながっているR1とR2だけです。
多くのDCDCではこのように電圧を測るピンがあり、そのピンに抵抗で分圧して出力電圧とつなげることで、出力電圧を調整します。

この部品の場合は、VSNSの値が1.221Vになるように出力電圧を調整するので、欲しい電圧の時にVSNSが1.221VになるようにR1とR2の値を決めます。

R1は10kΩにしてR2の値を変えるのが推奨されているようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124670/0ffcb1f1-a232-9591-0b6d-867258a2362a.png)


オームの方式からこのような式で計算することができます。

今回は7.2Vに設定したいので、R2は2.04kΩとなります。2kΩでもよいですし、可変抵抗を使ってもいいかもしれませんね。（可変抵抗を使うと自由に電圧が変えられるようになります。）

他の部品の値は回路図の例そのままでも基本的には大丈夫です。データシートにそれぞれの値と特性の計算式がのっていますので、サンプルと大きく違う電圧・電流にするという場合には確認するとよいかもしれません。

というわけで、こんな回路が完成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124670/7a752801-f121-cccd-42b9-da13c7036ef9.png)

これはTPS5430を使ってDCDCモジュールを作ったものです。電源入出力やENピンをピンヘッダに出しています。
また、出力電圧は可変抵抗で調整できるようにしました。インジケータとしてLEDもつけています。

# 最後に
恐れずにデータシートを読みましょう！少しずつ読み進めながら設計すれば回路は完成します！たぶん
npm, Yarn, Bunの比較

## はじめに

本記事では、**npm**、**Yarn**、および**Bun**の似ている点や違いについて解説します。

## 似ている点

### 1. 基本的な機能
これらはすべて、JavaScript/JavaScript/\uNode.js開発におけるパッケージの管理を目的としたツールです。機能は一般的に次のようなものが含まれます：

- **パッケージのインストール、アップデート、削除**
- **package.json**のサポート
- プロジェクトの依存関係の管理

### 2. npm Registryとの使用性
これらのツールはすべて、**npm Registry**に接続してパッケージをダウンロードしたり、記録を検索したりすることができます。

### 3. node_modules構造の使用
3つのツールはすべて、`node_modules`ディレクトリを作成し、その中にダウンロードしたパッケージを格納します。

## 違いの点

### **npm**

- **源源**: Node.jsに入っているデフォルトのツール
- **速度**:
  - npm v7以降では改善されたが、YarnやBunと比較すると更に遅い場合もある
  - キャッシングは弱め
- **特徴**:
  - `npx`で、ローカルインストールツールを実行
  - **Workspaces**によりモノレポ構成をサポート

### **Yarn**

- **源源**: Facebookによって開発された
- **速度**: npmより早い (キャッシングとダウンロードの実行の同時処理により高速)
- **特徴**:
  - **キャッシングの強化**: 再ダウンロード不要
  - **Plug'n'Play (PnP)**: `node_modules`を削除し、実行時のスピードを改善
  - **Workspaces**をサポート

### **Bun**

- **源源**: Zigで書かれた新しいツール
- **速度**: npmやYarnより比較的に高速 (最優化されたコードによる)
- **特徴**:
  - **多機能統合**: パッケージマネージャのみならず、ランタイムやバンドラーも搭載
  - **TypeScriptのネイティブサポート**: 構成不要
- **注意点**:
  - 資料はまだ有限
  - 一部の大規模プロジェクトにはまだ未完全

## トータル比較表

| **カテゴリ**      | **npm**              | **Yarn**            | **Bun**              |
|------------------|------------------|------------------|-------------------|
| **速度**        | 中等             | 高速             | 極めて高速      |
| **キャッシング**  | 弱い             | 強い             | 強い              |
| **Workspaces支援** | 有り             | 有り             | 一部未完全       |
| **TypeScriptサポート**| 要構成          | 要構成          | ネイティブサポート |
| **バンドラー**       | 無し             | 無し             | 有り              |
| **コミュニティの大きさ** | 極大              | 中等             | 小 (成長中)   |
| **安定性**        | 楽解             | 楽解             | まだ未確定       |

## いつどのツールを選ぶべきか

- **npm**:
  - 安定性を重視する場合
  - 小規模プロジェクトに最適

- **Yarn**:
  - Monorepoの管理が必要な場合
  - 高速なパッケージマネージャを求める場合

- **Bun**:
  - 最高速なパフォーマンスが必要な場合
  - 新しいプロジェクトやTypeScriptを主に使用する場合
Qiitaの書き初め

![first_blog-removebg-preview.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625609/ad410b0f-5818-56b8-7074-3cea5a91d3ea.jpeg)


# はじめに


[JISOU](https://projisou.jp/) という実践重視のプログラミングスクールへ通うことにしました。これを機に定期的にOutputをしていこうと思います


# 現在の自分について
## ざっくりとした経歴

* 2016年に新卒としてIT未経験でSierに入社
* AWSを利用したインフラ寄りのシステム設計・構築に8年ほど従事
     * いわゆるシステムアーキテクト・プロジェクトマネジメント的な業務が得意
     * 一通りのAWSサービスは使えるが、ネットワーク・セキュリティ・IVR周りの経験が多い
 * 一方でプログラミングは好きではあるものの得意とはいえない状態
     * Pythonについて、API・バッチ・ETL・機械学習の推論等々での実装経験はぼちぼちある
     * 一方で、本格的なWebアプリ開発の経験は薄く、特にフロントエンドの技量はかなり未熟な状態


## JISOUに通うことにしたきっかけ
### 遠因

* 4~5年ほど前にインフラレイヤーは一通りやり切ったかな？という感覚があり、アプリ寄りの部署に異動したもののアプリ部門の歴史が薄い会社であるため、思ったような開発経験がつめず、モヤモヤが募った
* 副業で3年ほど前からアグリテック系のベンチャーに草創期から携わることになり、そこである程度充実した経験は積むも、IoTや機械学習系の機能がコアのプロダクトであるため、フロントエンド実装の経験はわずかしか積めなかった
    * 一定の充実感を感じた一方で、自分自身のフロントエンドの知識が浅いがためにリリースを少し遅らせてしまったような感覚があり、同時に課題感も感じる

### 直接のきっかけ

* 2022年に縁あって群馬県に移住した。約2年経って、地域の交友がだいぶ増えて、愛着が芽生えはじめる
* 「こういうシステムができたらもっといい街になる」という妄想が捗るようになるも、2024年の11月~12月に「結局、妄想だけで終えてしまった」自分を情けなく感じる
* 振り返ると、1 => 2 => 3の構造であり、しかも以前も同じようなことがあったなと気づく
    * 1.「営利目的ではないシビックテックだから、ランニングコストの安さとインフラのお守りに手間かからないことを重視したいからNetlifyとかCloudflareとかでSPA組むような構成がいいよな」
    * 2.「でも、俺React・Vueそんな得意じゃないからな・・・」と勢いが萎む
    * 3.ちょっと勉強しようとはするも、少し忙しくなると仕事で使う技術の習得を優先するようになり、結局フロントエンドの知識・技量は身につかず0に近い形でリセットされる
* 「フットワーク軽く、アイデアをすぐ形にできるエンジニアになりたい」、「将来的に『プログラマー』をメインの仕事にするかしないかは置いておいて『書けるエンジニア』ではありたい」とあらためて強く思う
* この1年の反省を生かして、短期間で意識的に本気でコミットした方がいい・お金をかけてでも最初はその道のプロに習って効率よく学習できた方がいい・・・と思い、コンセプトに合うスクール・メンターサービスを探していたところJISOUに出会う

# 目標

* 短期：自分の中である程度自信をもって「React書けます」と言えるような状態になりたい
* 中期：アプリを2~3個ローンチしていたい
* 長期：その気になれば月に1個（あるいはそれ以上）コンスタントにアプリ・サービスを立ち上げられるようになっていたい

# おわりに

1~2年後の自分がこのQiita記事を見て「成長したな」としみじみ実感できるように、これから頑張っていきます！
【JavaScript】WebブラウザとNode.jsで共通の処理を実行する

# この記事の目的

JavaScript で、共通の処理をWebブラウザとNode.jsからそれぞれ実行できるようにする。
これにより、Webブラウザ上で手軽に実行することも、ファイルシステム上で大量の対象に対して一括で実行することもできる、のような利便性を提供できる。

# 方法

## モジュールを用いる方法

* [`export` 宣言](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/export)を用いて関数をエクスポートし、[`import` 宣言](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/import)を用いてインポートする
* Webブラウザでは、[`script` タグ](https://developer.mozilla.org/ja/docs/Web/HTML/Element/script)で読み込む際に `type="module"` 属性をつける。共通の処理は `import` 宣言でスクリプトから読み込み、HTML では指定しなくてよい
* Node.js では `node test1node.mjs` として実行する

```html:test1.html
<!DOCTYPE html>
<html lang="ja">
	<head>
		<title>WebブラウザとNode.jsで共通の処理を用いるテスト</title>
		<script src="test1web.mjs" type="module"></script>
	</head>
	<body>
		<div id="testout"></div>
	</body>
</html>
```

```javascript:test1.mjs (共通の処理)
export function sample() {
	return "hello, world";
}
```

```javascript:test1web.mjs (Webブラウザ用の呼び出し処理)
import { sample } from "./test1.mjs";

window.addEventListener("DOMContentLoaded", () => {
	document.getElementById("testout").textContent = sample();
});
```

```javascript:test1node.mjs (Node.js 用の呼び出し処理)
import { sample } from "./test1.mjs";

process.stdout.write(sample() + "\n");
```

:::note warn
この方法では、Webブラウザで直接HTMLファイルを開くと (基本的には) エラーになってしまい、**実行ができない。**
![ファイルを直接開くとエラーになる](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/cd1bdcbf-5021-fe38-54c7-5e225ae8005d.png)

HTTPサーバを経由すれば、実行できる。
![サーバ経由なら実行できる](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/ae593f73-15c0-482a-8346-fab054aa8a82.png)
:::

## CommonJS を用いる方法

* Node.js では、`module.exports` にエクスポートする値を代入することでエクスポートし、`require` 関数で値をインポートする
* Webブラウザでは `module.exports` は使えないので、エラーにならないように存在チェックを行う。インポートのかわりに通常の `script` タグを用いて取り込む
* Node.js では `node test2node.js` として実行する

```html:test2.html
<!DOCTYPE html>
<html lang="ja">
	<head>
		<title>WebブラウザとNode.jsで共通の処理を用いるテスト (CommonJS)</title>
		<script src="test2.js"></script>
		<script src="test2web.js"></script>
	</head>
	<body>
		<div id="testout"></div>
	</body>
</html>
```

```javascript:test2.js (共通の処理)
"use strict";

function sample() {
	return "hello, world";
}

if (typeof module !== "undefined") {
	module.exports = { sample };
}
```

```javascript:test2web.js (Webブラウザ用の呼び出し処理)
"use strict";

window.addEventListener("DOMContentLoaded", () => {
	document.getElementById("testout").textContent = sample();
});
```

```javascript:test2node.js (Node.js 用の呼び出し処理)
"use strict";

const { sample } = require("./test2.js");

process.stdout.write(sample() + "\n");
```

:::note info
この方法であれば、Webブラウザで直接HTMLファイルを開いても、**問題なく実行できる。**
![js-commonjs-20241229.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/c259bf5e-f150-af00-0269-03278738acfb.png)
:::

# まとめ

通常通りプログラムを書き、最後に `module.exports` にエクスポートする値を代入することで、Node.js (の `require` 関数) からプログラムを読み込んで利用できるようになる。
ただし、Webブラウザでは `module` が定義されていないので、`typeof module !== "undefined"` のチェックを行い、`module` が存在するときのみこのエクスポート処理を行うようにするとよい。

また、共通の処理にはプラットフォームに依存しない計算などの処理のみを置き、入出力などのプラットフォームに依存する処理はそれぞれのプラットフォーム用のファイルに分けて書くとよい。
(ファイルを分けずに機能の存在チェックで分岐する方法もあるかもしれない)
2024年に触れた技術と振り返り


2024年に触れた技術と振り返り
----------------

2024年も色々な技術に触れて、めちゃくちゃ学びが多かった1年でした。特にFlutterの便利さには感動したし、他にも色々新しいツールやライブラリを使ってみて、結構成長できた気がしています。今回は、今年触った技術や、開発中に苦労した部分をまとめてみたので、同じように何か新しい技術を学びたい人の参考になれば嬉しいです。

### 1\. **地震情報アプリの開発**

**苦労した点**  
地震情報アプリを開発する際に大変だったのは、新しいライブラリを使うところでした。特に、JMAからデータを取ってきて、Flutterで表示する部分が楽しかったです。これまで使っていなかったライブラリを試してみるのも面白かったし、少しずつ落とし込んでいく感じが良かったです。

**解決方法**  
最終的には、`dio`でAPI通信を効率化する形に落ち着きました。`dio`は`axios`みたいなもので、すごく便利でした。これを使うことで、データの取得もサクサク進み、ユーザーにリアルタイムで地震情報を届けることができたので、苦労した甲斐がありました。

### 2\. **`go_router`の利点**

**便利だった点**  
Flutterでのナビゲーション管理に`go_router`を使ったのですが、これが超便利でした。`Navigator`で長いコードを書かなくて済むし、パラメータを渡すのも簡単でした。これまでの`Navigator`だと結構煩雑になりがちだったのですが、`go_router`を使えばコードがスッキリして、遷移先にパラメータを渡すのも簡単にできました。これでかなり開発が楽になりました。

### 3\. **2024年に学んだ技術**

2024年に触れた技術の中で、特に印象に残ったものを紹介します。

#### **Express & MongoDB**

ExpressでAPIを作るのは簡単でサクサク進み、MongoDBとの相性も抜群でした。スキーマレスなデータベースなので、途中でデータ構造を変えたくなっても対応しやすいです。柔軟に扱えるので、すぐに変更できる点が良かったです。ただ、`Hono`も試してみたのですが、やっぱりTypeScriptがあんまり好きじゃないので、結局`Express`に戻ってしまいます。

#### **Rails**

Railsはやっぱり直感的で気に入っています。`ActiveRecord`でのデータ操作がめっちゃ楽だし、APIの設計もスムーズに進みました。全体的にシンプルで、余計なことを考えずに開発に集中できるので、Railsでの開発は快適でした。ただ、ちょっとしたWebアプリだと大きすぎるので、**Express & MongoDB**に頼ることが多いです。

#### **Dart & Flutter**

Dartは最初、なんか「気持ち悪いな〜」って思っていたのですが、慣れてくるとめっちゃ書きやすくなりました。静的型付け言語が苦手だったのですが、Dartはちょうどいい感じの型の量で、負担にならなくていいです。JSを知っていればほぼ違和感なくいけるし、シンプルな文法でFlutterでのUI構築が本当に楽でした。最初は結構戸惑いましたが、慣れるとどんどん快適になり、`Widget`を使ってUIを作る感覚がすごく楽しかったです。

### 4\. **AIツールを活用した開発経験**

**AIツールの使い方と学び**  
最初の頃は、AI（GPT）があれば何でもできると思っていたのですが、今は全然そんなことないなと感じています。確かに便利な部分も多いのですが、AIに頼りすぎるとクオリティが落ちるし、うまく動かないことも多いです。やっぱりAIは補助ツールとして使うもので、自分の理解があってこそのサポートだなと感じています。

**具体的な活用例**  
例えば、APIのエンドポイント作成やUIのテンプレート生成はAIに頼るとめっちゃ早く終わります。でも、最終的には自分でコードをしっかり読んで、修正したり、バグをチェックする必要があります。AIを使うときは、やっぱり自分の頭で考えながらやるのが大事だなと思いました。

### おわりに

2024年は、色んな技術に触れて、新しい知識を吸収できた年でした。FlutterでのUI構築が楽だったり、`go_router`でルーティングがめっちゃ楽になったり、個人的にはすごく充実した1年でした。来年も新しい技術にチャレンジして、もっと成長できるように頑張ります！来年もよろしくお願いします！
MiuzeiのMS18サーボモータをArduinoで使う

SG90のような見た目をしたMiuzei製のサーボモータ「MS18」を使ってみようと思います。

# MS18とは
SG90互換（？）のサーボモータです。
Amazon等で購入できます。
コスパがよいです。
サーボホーンはSG90と少し違うようでSG90の物ははまりませんでした。

https://www.amazon.co.jp/dp/B07PHFQY6B

# 使い方

他のサーボモータと同じです。
赤に電源（4.8～6V）、黒にGND、橙が制御信号です。
PWMで制御できます。50Hzでパルス幅は900~2100μsecとなっています。

Arduinoにつないでみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124670/498dad20-edb1-8c6b-e95b-6340dc47927b.png)


パルス幅900～2100μsecだと120度ほどしか曲がりません。

パルス幅を500~2400μsec（SG90と一緒）にしたら特に問題なく180度回転するようになります。

プログラムは標準のServoライブラリを使って簡単に書くことができます。
``` servo.ino
#include <Servo.h>
#define pin 2

Servo servo ;

void setup() {
  servo.attach(2,500,2400);
}

void loop() {
  servo.write(0);
  delay(500);
  servo.write(90);
  delay(500);
  servo.write(180);
  delay(500);
}

```


3.3V系のマイコンにもつないでやってみましたが問題なく動作しました。信号は3.3Vでも大丈夫なようです。

# 最後に
今の所特に問題なく使えています。
トルクなどはSG90には劣るようですが、ほとんどの用途においてはSG90と代替可能だと思います。
Laravel Sail環境でPHP-CS-Fixer使ってVSCode上でファイルをフォーマットする方法

ググっても正しい設定方法が出てこなかったのでChatGPTと会話しながらなんとか設定完了。

## 環境
- Ubuntu 22.04.5 LTS
- PHP 8.2
- Laravel 10
- Sail 1.39.1

## PHP-CS-Fixer 本体のインストール
https://github.com/PHP-CS-Fixer/PHP-CS-Fixer

Sail環境なので下記のコマンドでインストール
```
sail composer require --dev friendsofphp/php-cs-fixer
```

## PHP-CS-Fixer VSCode拡張機能のインストール
https://marketplace.visualstudio.com/items?itemName=junstyle.php-cs-fixer

トラップのように似たような名前の拡張機能がたくさんあるので気をつけるように！

## shファイル作成
ググると直接`php-cs-fixer.executablePath`にdockerのパスを設定する方法があるみたいですが、色々試してみるも私の環境では動きませんでした。
そのため、下記のshを作成。
`laravel.test-1`はコンテナ名を設定してください。
``` php-cs-fixer.sh
#!/bin/bash
docker exec -i laravel.test-1 php /var/www/html/vendor/bin/php-cs-fixer "$@"
```

そして、実行権限を付けましょう。
```
chmod +x php-cs-fixer.sh
```

## settings.json追記
`php-cs-fixer.executablePath`は私の場合、`php-cs-fixer.sh`をワークスペースの直下に置いたので、こんな感じ。

ここで大事な部分は、`php-cs-fixer.config`を設定すること。
デフォルトだとコンテナ外のubuntu上でのパスになってしまうのでコンフィグファイルが正しく読み込めません。
コンテナ内のパス`/var/www/.php-cs-fixer.php`を書くことで読み込まれるようになります。

`php-cs-fixer.allowRisky`と`php-cs-fixer.onsave`は、ご自由に。
``` settings.json
{
    "php-cs-fixer.executablePath": "${workspaceFolder}/php-cs-fixer.sh",
    "php-cs-fixer.config": "/var/www/.php-cs-fixer.php",
    "php-cs-fixer.allowRisky": true,
    "php-cs-fixer.onsave": true
}
```

## docker-compose.yml
最後にこれを設定しないと、`/tmp`内のファイルが読み込めませんとエラーが出ます。
`- /tmp:/tmp`を`docker-compose.yml`に追加して読み込めるようにするとやっと完成です。

``` docker-compose.yml
        volumes:
            - ".:/var/www/html"
            - /tmp:/tmp
```

以上になります。
これでフォーマットを行うと正しくフォーマットされるかと思います。

他にもっとスマートなやり方を知ってる人は教えて下さい。
インテルPCマイスター ＜中級＞認定講座を受講してみた

# 概要
インテルが監修しているカリキュラムの講習を受講し、認定試験に合格するとPCマイスターという資格が貰えるということをたまたま知りました。９月の酷暑の最中講習を受講し、:cherry_blossom:無事合格:cherry_blossom:したので記憶が残っているうちに記事にまとめておこうと思います。

* 以下、合格通知メールの抜粋
>インテルPCマイスター中級
>受講者の皆様
>
>お世話になります。
>インテルPCマイスター事務局です。
>
>表題の件、お知らせいたします。
>
>皆様はインテルPCマイスター中級試験に
>合格となりました。
>
>今回の合格率は
>15/20、75%となりました。

# PCマイスターとは？
公式サイトにはこの認定制度のカリキュラムの目的について以下の様に記載されています。

>インテルPCマイスターカリキュラムの目的
>PCを初歩から理解し、知識を得ることでより良い活用へ。
>クリエイティブ、ゲーム、プログラミングなどやりたい事に合ったPCスペックの選定
>PCについて資格へのチャレンジなど楽しみながら学んでいただく。
>チャレンジする楽しみをもって、PCに関する知識の向上
>店舗スタッフの知識、サービスの平均化、相談しやすい環境の構築。
>上級マイスターではサービスに関する項目もあり、初めての方でもマイスターを目印にして相談しやすい環境を作ります。

中級講座は申し込み定員が20名ですが、あっと言う間に満員となりました。筆者は以前申し込みを行ったのですが、定員オーバーで受講出来ず、今回もすぐに満席になりましたが、前回申し込んだにも関わらず、参加出来なかった人枠で参加出来ました。当時は受講料が6,600円と割引価格だったことも起因しているのかもしれません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469079/e0843569-eb77-65a5-0a35-b2ff3ed6d212.png)

認定の階級は下表の様に、４段階になっています。最上位のTOPマイスター以外は講習と試験への合格で取得出来る様です。筆者は今回下から２番目の中級の認定講習を受講しました。

|階級|概要|推奨ユーザー|取得方法|
|---|---|---|---|
|TOPマイスター|卓越した PC 全般の知識と技術、コミュニケーション力を兼ね備え、インテル PC マイスターを牽引する方々をインテルが認定。|－|インテルが特別に認定|
|上級マイスター|PC 全般の知識を持ち、PC ショップなどで接客や相談が可能なレベルの方。|大学生、専門校生、社会人|オンライン講習 (座学) の修了<br>オフライン講習 (実技) の修了<br>認定テストへの合格|
|中級マイスター|PC で使用するパーツの違いを理解し、パーツの選定～組立てを独力で行えるレベルの方。|中学生、高校生、大学生、専門校生、社会人|オンライン講習 (座学) の修了<br>オフライン講習 (実技) の修了<br>認定テストへの合格|
|初級マイスター|PC の仕組みや組立て方について大まかに理解しているレベルの方。|小学生、中学生、および帯同する保護者|以下のどちらかへの参加<br>[A] オンライン講習 の修了<br>[B] 関連イベントや体験会への参加|

* 参考

https://intelpcmaster.redee.co.jp/

# 実際の講習について
上表の中級マイスターの欄を参照すれば、取得方法については一目瞭然ですが、各講習の概要についてまとめておこうと思います。

## オンライン講習(座学)
オンライン講座として事前に視聴する動画は、参加申し込み後の受講料支払い完了後にメールで案内が届きました。以下のYouTube動画でした。PCの組み立てについて丁寧に解説した動画です。

https://www.youtube.com/watch?v=3BgK-u-U0-g

## オフライン講習(実技)
講習会当日にオフライン講習を受講します。と言っても、認定の合否には影響しないとのことです。講習会は大きく2部構成で、第1部は実際に配布された部品を組み上げてデスクトップPCを組み立て、完了後BIOS起動までを確認して貰うというものでした。筆者はそれほどPC組み立ての経験が豊富な訳でも無く、毎回マニュアルを見つつ配線をしているのですが、配布されたマザーボードにはマニュアルは同梱されていませんでした。。。:scream: :scream_cat: 電源ボタン、電源LED、ストレージその他のLEDの配線方法の簡単な覚え方を習得出来たのは良かったと思います。第2部はグループワークです。少人数のグループに班分けされ、グループ毎に異なるペルソナが与えられます。グループ内で議論し、与えられたペルソナに合ったスペックのPCを与えられた予算内で購入する方法を考えます。そして、最後に各グループ毎に導き出した結論を発表します。筆者が参加したグループはインテルの営業をしている方や、自作PCに精通した方もそれなりに居たので、スムーズに議論が進みました。

## 認定テスト
最後に筆記試験の認定試験が有りました。PCの専門用語をあまりPCに詳しく無い人に説明することを想定した問題やPCの購入を相談されたことを想定して、どの様にスペックを見れば良いか、最終的にどちらを勧めるべきかの考えを問うなど、ただPCについて知っているだけでは回答出来ない様な試験問題が出題されている印象を受けました。

# 結果発表
結果発表はメールで合否と合格率の発表という形で行われました。20人中15人合格ということで、合格率75%とかなり合格率は高いですが、グループワーク後の発表を聞いていても、参加者の知識レベルは総じて高かったので、この合格率は自然な数字かもしれません。下の写真は実際の認定カードです。(保護のためラミネートをしています。)

![intel_pc_meister.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469079/e734fb11-ca7f-dd09-889b-70323f0e43fb.jpeg)

# まとめ
ひょんなことから参加を決めたインテルPCマイスター認定講座ですが、無事合格出来て良かったです。更に上のレベルは有りますが、受講料や求められるスキルを考えると上級は恐らく今後受講することはないだろうと思います。自作PCが好きな方は受講してみるのも一興かもしれません。
Treeviewでツリー構造表示とファイルクリック時のハイライトを実装してみたメモ

# はじめに
Treeviewでツリー構造データを表示する実装をされている記事を参考にサイドバーを開発してみて、ハイライトの機能が動くようにjsを追加したのでメモ。

# 実装
ツリー構造データをブラウザで表示するための手順はこちらの参考記事に詳しく書いてあるので、読んでください。

https://qiita.com/kimisyo/items/a4a181b6cd75a2ef37eb

APIはほとんど同じ実装のため割愛しますが、ファイル名をクリックすると、swagger uiのドキュメントが読み込まれるようにreturnしています。

このままだとクリックしたファイル名にハイライトがつかなかったので、追加で以下のjavascriptを実装しました。

```js
document.addEventListener('DOMContentLoaded', function() {
    document.getElementById('treeview').addEventListener('click', function(event) {
        if (event.target && event.target.matches('a.link')) {
            event.preventDefault();
            var links = document.querySelectorAll('#treeview a.link');
            links.forEach(function(l) {
                l.classList.remove('selected');
            });
            event.target.classList.add('selected');
        }
    });
});
```

ここでファイルをクリックしてみると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919187/7f5b7dfc-0827-e94d-1c4c-ec845e8ee19c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919187/ef4c6952-1a86-32a1-5340-cb87d3d51bee.png)

classにselectedが追加されて、ハイライト機能が動きました!

# 最後に
Qiitaはたくさんの記事があって本当に助かります。。。ありがとうございますmm
参考になれば幸いです🍏

# 参考
https://github.com/jzaefferer/jquery-treeview

https://qiita.com/kimisyo/items/a4a181b6cd75a2ef37eb
ABC389個人的備忘録

コンテスト30秒前にVScodeが使えなくなった男の備忘録です

### コンテスト概要
トヨタ自動車プログラミングコンテスト2025（AtCoder Beginner Contest 389）

https://atcoder.jp/contests/abc389

開催日:2025年1月18日 21:00-22:40

## [A - 9x9 ](https://atcoder.jp/contests/abc389/tasks/abc389_a)
#### 考察
xを無視してだけを抽出。あとは2数をかけるだけ。
...なんだが、前述の通りVScoderがなぜか使用できなくなる。なのでコードテストを縛りでコンテストに参加する羽目に。

#### 提出
``` c++:A.cpp
#include <iostream>
using namespace std;

int main(){
  int x,y;
  char z;
  cin >> x >> z >> y;
  
  cout << x*y << endl;
}
```

## [B - tcaF](https://atcoder.jp/contests/abc389/tasks/abc389_b)
#### 考察
1から順番に掛けていき特定の値になったら終了。
最後に掛けた値を出力。

#### 提出
``` c++:B.cpp
#include <iostream>
using namespace std;
using ll = long long;

int main(){
  ll x;
  cin >> x;
  
  ll ans = 1;
  for(ll i=1;i<21;i++){
    ans *= i;
    
    if(ans == x){
      cout << i << endl;
      return 0;
    }
  }
}
```

## [C-Snake Queue](https://atcoder.jp/contests/abc389/tasks/abc389_c)
#### 考察
先頭のindexを管理する変数を持って置き、どんどん蛇には並んでもらい、それぞれの蛇の頭の位置を記録した配列を作成する。蛇が抜ければindexを1増やす。
ここでk番目の蛇の位置は[index+k]番目-[index]番目で求まる。

```c++:C.cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int main(){
   int n;
   cin >> n;
   
   vector<ll>num (1,0);
   int now  = 0;
   for(int i=0;i<n;i++){
     int x;
     cin >> x;
     
     if(x == 1){
       ll y;
       cin >> y;
       
       ll s = num.back();
       num.push_back(s+y);
     }
     if(x == 2){
       now++;
     }
     if(x == 3){
       int k;
       cin >> k;
       k--;
       
       cout << num[k+now] - num[now] << endl;
     }
   }
}
```

## [D-Squares in Circle](https://atcoder.jp/contests/abc389/tasks/abc389_d)
#### 考察
正方形の右角を基準に考えたとき、$(i+0.5)^2+(j+0.5)^2 \leq R^2$ となる$(i,j)$の数を考える。
ここで$i$を固定すると$j \leq {\sqrt{R^2 - (i+0.5)^2}} - 0.5$という式でかけるのである$i$に対する$j$の個数が簡単に求まる。
あとは$i$を全探査。

なお、この時動揺がMAXに達していたためまともなコードが書けなくなる。

#### 提出
``` c++:D.cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

ll che(ll n){
  ll h = 0,t = 2000001;
  while(h != t){
    ll c = (h+t) / 2LL;
    
    if(c*c > n)t = c;
    else h = c+ 1LL;
  }
  
  return h / 2LL;
}

int main(){
   ll r;
   cin >> r;
   
   r *= 2LL;
   r *= r;
   
   vector<ll>ans (0);
   ll now = 0;
   while(true){
     ll i = 2LL*now + 1LL;
     ll s = r - i*i;
     if(s < 0) break;
     
     s = che(s);
     
     if(s == 0) break;
     ans.push_back(s);
     now++;
   }
   
   if(ans.size() == 0)cout << "0" << endl;
   ll cnt = 0;
   for(auto x:ans) cnt += x;
   
   cnt = cnt*2LL - ans[0];
   cnt = cnt*2LL - (ans[0]*2LL - 1LL);
   
   cout << cnt << endl;
}
```

## [E - Square Price](https://atcoder.jp/contests/abc389/tasks/abc389_e)
#### 考察
どうやったら安い順に買えるかが思いつかずTIME UP

## [F - Rated Range](https://atcoder.jp/contests/abc389/tasks/abc389_f)
#### 考察
遅延セグ木で範囲の両端を探しその間に１を足せばいいと残り10分で気づく。
10分でまともな写経なんてできるわけもなく遁走。

## 結果
結果　ABCD(1)　4完 68:23

順位　3207位
パフォーマンス 972

## 感想
突発的にコードテスト縛りなんて聞いてない。
せっかくの前回のアドバンテージが消し飛ぶ結果に。

みんなコンテストの15分前には動作確認をしよう！
DELL PowerEdge T630 設定の覚え書き

# TL;DR
「私は問題の判別をミスって、5 万円のシステムボードを買いました」の札を首から下げています。

# 中古サーバー構築時の注意点
StackOverflow や Reddit など色々見ましたが、解決できなかったエラーメッセージに関しての覚え書きを残します。
前提として
 - サーバーメーカーが出している サーバー構成ガイド はちゃんと読みましょう
 - CPU の入れ替えやメモリの入れ替えは、サーバー構成ガイド記載の内容 (=新規購入時のサポートされた構成) であれば動くはずです

ちゃんと読んでれば、ムダな出費は抑えられたはずです(涙目)。

# エラーメッセージ

## 起動時の BIOS/UEFI 画面で "Configuring Memory ...." で止る
サポートされていないメモリを使用している可能性があります。

T630 は RDIMM と LRDIMM をサポートしますが、一般的に安価に手に入る(PC で使われる) UDIMM はサポートしていません。
メモリコントローラからメモリをコントロールする仕組みが違うので、機能制限云々ではなく動きません。

私も適当に余っていた DDR4 SDRAM でよかろうと適当に挿した結果起動しませんでした。
内部的な動作は不明ですが、電気的には繋がるけど、期待した応答が返ってこないなどの理由でスタックしていると思われます。

UDIMM, RDIMM, LRDIMM の違いは HP さんの記事が参考になります。
[【連載】導入前のアドバイス – メモリ①：メモリの種類・規格について](https://community.hpe.com/t5/hpe-blog-japan/%E9%80%A3%E8%BC%89-%E5%B0%8E%E5%85%A5%E5%89%8D%E3%81%AE%E3%82%A2%E3%83%89%E3%83%90%E3%82%A4%E3%82%B9-%E3%83%A1%E3%83%A2%E3%83%AA-%E3%83%A1%E3%83%A2%E3%83%AA%E3%81%AE%E7%A8%AE%E9%A1%9E-%E8%A6%8F%E6%A0%BC%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/ba-p/7105338)

LRDIMM は eBay あたりで中古を探すと、サーバー抜き取り品が安く出ていることがあるので、そこで妥協しましょう。


## 起動時の BIOS/UEFI 画面で "Configuring Memory ....　Done" で止る

メモリがちゃんと刺さっていない、静電気などの影響の可能性。

最近抜き差しした場合は、ちゃんと奥まで刺さっているか確認しましょう。
何もいじっていない場合は、電源を抜く、再起動するなどで解消する可能性があります。

# ちなみに
DELL PowerEdge T630 は 2023 年頃にヤフオクで購入しました。
3.5インチ HDD ベイ × 18 のシャーシ、電源ユニット、とシステムボード、CPU クーラー×1 のみで購入し、NAS にしようと思って引っ張り出したところ上手く行かず 3ヶ月ほどさまよっていました。

DELL のコミュニティでは、ジャンパピンで設定をリセットしろ、iDRAC で POST ログを確認しろ、最小構成で起動等々書かれていましたが、結局答えにはたどり付けず、システムボードの問題かと思って中古のボードを取り寄せました。
(iDRAC はパスワードが分からず、リセットしようにも BIOS に入れないと分からないので、結局詰んだ状態)

あ、新しいシステムボードには iDRAC 8 の Enterprise ライセンスがついてたからいいんだもん (強がり)。
Honoチュートリアル

OSはUbuntu-24.04を利用
とても親切なのがよろし

```bash
$ npm create hono@latest my-app
create-hono version 0.14.3
✔ Using target directory … my-app
? Which template do you want to use? cloudflare-pages
? Do you want to install project dependencies? yes
? Which package manager do you want to use? npm
✔ Cloning the template
✔ Installing project dependencies
🎉 Copied project files
Get started with: cd my-app
$ cd my-app/
$ npm i

up to date, audited 75 packages in 493ms

7 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

$ npm run dev
  VITE v5.4.11  ready in 2325 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h + enter to show help
h

  Shortcuts
  press r + enter to restart the server
  press u + enter to show server url
  press o + enter to open in browser
  press c + enter to clear console
  press q + enter to quit
q
```
MA735(磁気エンコーダ)をSPI接続してレジスタを弄る

# 1. はじめに

趣味でMA735の磁気エンコーダを搭載したモジュールをswitch-scienceから購入しました。

https://www.switch-science.com/products/9826

このMA735はSPI、A・B・Z相のエンコーダ出力、PWMの3種類の方法で角度を取得することができるのですが、[データシート](https://doc.switch-science.com/media/files/18f19b67-4c2c-442b-bff5-187717dfe2ae.pdf)を参照するとSPI接続でレジスタに直接アクセスすることで、現在の設定の確認や設定変更することができると記載があります。
※レジスタに書き込まれた内容はオンチップの不揮発性メモリ(NVM)に保存されますが、データシートでは20℃で1000回の書き込みサイクルに耐えられるとあるので、毎回起動時に初期化としてレジスタに書き込む使い方はよくないですが部品の脱着などの際に人が任意に初期化するような使い方なら問題なさそうです。

この設定変更のためのArduinoスケッチは

https://github.com/SWITCHSCIENCE/samplecodes/blob/master/9826_MA735_Digital_Angle_Sensor_Module/ma735_setting/ma735_setting.ino

で公開されているのですがReadmeがなくぱっと見では使用方法が分からないので、Readmeを整理してコマンドで簡易的に設定変更できるように機能追加したArduinoスケッチを

https://github.com/todateman/MA735_Setting

で公開しています。

なので、手っ取り早くMA735のレジスタを弄りたい人は上記のリポジトリを活用してください。

---

# 2. 例: 1回転当たりのパルス数を変更する場合

[MA735のデータシート](https://doc.switch-science.com/media/files/18f19b67-4c2c-442b-bff5-187717dfe2ae.pdf)を参照するとP.22に記載があるのですが、10bitの```PPT[9:0]```でエンコーダ出力時の1回転当たりのパルス数を指定する旨で記載があります。
**(実際に欲しいパルス数-1の値を設定せよと書いてあります。)**
ちなみに初期設定では1回転で**1024**パルスです。

PPT(9:0)はアドレス```0x05```の全8bit(```PPT[9:2]```)とアドレス```0x04```の上位2bit(```PPT[1:0]```)で設定します。
初期設定では1回転当たりのパルス数は```1024```で、実際のレジスタ値はアドレス```0x05```に16進数で```0xFF```(2進数では```11111111```)、アドレス```0x04```に16進数で```0xC0```(2進数では```11000000```)として設定されています。
この場合、アドレス```0x05```の全8bitとアドレス```0x04```の上位2bitを合体させると```11111111```と```11```を合わせた```11111111 11```になり、10進数に変換すると**1023**と読み取れるわけです。
※0x04にはZパルスのタイミングや長さの設定も上位3～6bitで```ILIP[3:0]```として設定するのですが、ここでは初期設定のまま```0000```のまま変更していない前提で進めます。

さて、仮に1回転当たりのパルス数を360に変更するとします。
この場合、実際に設定する値は**360 - 1 = 359**です。

10進数の359を2進数に変換すると```0101100111```になります。
この10bitの2進数をアドレス```0x05```とアドレス```0x04```にそれぞれ割り当てる上位8bit+下位2bitに分解すると、
```0x05: 01011001```
```0x04: 11******```
になります。

アドレス```0x05```の方はそのまま書き込んでしまっていいのですが、アドレス```0x04```の方は```******```で表現した下位6bitにはZパルスのタイミングや長さの設定があるので、誤って変更しないように気を付けます。
初期設定のままであれば
```0x04: 11000000```
でいいのですが、もし変更済みなら
```0x04: 11111100```
にしないといけないかもしれません。
なので、変更前に現在の設定を一度確認した方がいいです。


# 3. 10進数と2進数の変換や事前に設定を確認がめんどくさいよう…

なので、比較的使用頻度の多そうなレジスタの書き換え機能を追加したArduinoスケッチを

https://github.com/todateman/MA735_Setting

で公開しています。

Readmeを読んでもらえれば概ね使い方はわかるはずですが、参考元の

https://github.com/SWITCHSCIENCE/samplecodes/blob/master/9826_MA735_Digital_Angle_Sensor_Module/ma735_setting/ma735_setting.ino

にあった

- 全レジスタの確認 (```d``` コマンド)
- 個別のレジスタの読み込み(```r アドレス``` コマンド)・書き込み(```w アドレス 値``` コマンド)
- 角度データの定期出力 (```m 出力間隔(ミリ秒)``` コマンド)

に加えて

- ゼロ位置（```z```コマンド）
- 回転方向（ ```cw```ないし```ccw```コマンド）
- 1回転当たりのパルス数（```p パルス数(10進数)```コマンド）

をコマンドと数値で設定できるようにしています。
ゼロ位置と1回転当たりのパルス数に関しては事前に現状の設定を確認したうえで変更を行うので、誤って違うアドレスやbitを弄ってしまうミスがないようにしたつもりです。
ATOMCam2 カスタムファームウェアで動体検知録画転送通知から動画を保存する

ATOMCam2 のカスタムファームウェアを使った動体検知録画転送通知を PHP で受け取って ffmpeg で HLS に変換します。

# 準備

動体検知動画を受け取るwebサーバをたてます。
自宅サーバがあれば楽ちんです。
GCP でも AWS でも何でもいいと思います。

今回は Apache httpd で作ってみました。
PHP を使いたいので mod_php を読み込みます。

```config
<VirtualHost *:8088>
  DocumentRoot /var/www/atomcam2
  ErrorLog logs/atomcam2-error_log
  CustomLog logs/atomcam2-access_log common

  <IfModule prefork.c>
    LoadModule php_module modules/mod_php.so
  </IfModule>

  <Directory "/var/www/atomcam2">
    AllowOverride All
    Options Indexes FollowSymLinks
  </Directory>
</VirtualHost>
```

# ATOMCam2 の通知設定

ATOMCam2 のウェブ設定画面からイベント通知の動体検知録画転送を有効にします。
通知URLに受け取れるWebサーバのURLを書いておきます。

# PHP で通知を受け取って動画を保存する

ATOMCam2 からの通知は、リクエスト Body の FILES から取得できます。

```php
$f = $_FILES["video"];
move_uploaded_file($f['tmp_name'], '/tmp/atomcam2_savemp4/video.mp4');
```
# HLS に変換する

ここ迄で既に動画保存はできていますが、ffmpeg で HLS に変換してストリーミングできるようにします。

```php
exec('/usr/bin/ffmpeg -i /tmp/atomcam2_savemp4/video.mp4 -c:v copy -c:a copy -f hls -hls_time 10 -hls_playlist_type vod -hls_segment_filename "/tmp/atomcam2_savemp4/output-%3d.ts" /tmp/atomcam2_savemp4/output.m3u8');
```

HLS に変換した後は自分用の配信サーバにアップロードするとか、自宅サーバに置いとくとか色々できますね。

ATOMCam2 カスタムファームウェア作者様に感謝を。

https://qiita.com/mnakada/items/7d0fbcb6e629e1ddbd0c

https://github.com/mnakada/atomcam_tools
VBAでStartsWith関数を実装したい

VBAで`StartsWith`関数を実装したい場合は、`Instr`関数をうまく活用すればよいです。

```
Function StartsWith(str As String, prefix As String) As Boolean
    StartsWith = (InStr(str, prefix) = 1)
End Function
```

例:

```
Debug.Print StartsWith("Hello World!", "Hello")   '=> True
Debug.Print StartsWith("Hello World!", "Goodbye") '=> False
```

環境情報:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105859/974e54ad-cc6e-8067-83d6-f75f5b2d325a.png)
systemd-runでリソース制限してコマンドを実行する

# 1 systemd-runコマンド
```systemd-run```は、systemdを使用しているLinuxで、一時的にsystemdユニットを作成して実行できるコマンドである。
例:
```
 # systemd-run sleep 60
```
このコマンドを実行すると、60秒待機するだけのserviceを生成し、systemdによってserviceが起動される。
通常のserviceと同じように管理されるので、たとえば```systemctl cat```コマンドでserviceの中身を見ることもできる。
```shell
 $ systemctl cat run-re49ded26b30140fe9537410ece21c8e6.service
# /run/systemd/transient/run-re49ded26b30140fe9537410ece21c8e6.service
# This is a transient unit file, created programmatically via the systemd API. >
[Unit]
Description=/usr/bin/sleep 60

[Service]
ExecStart=
ExecStart="/usr/bin/sleep" "60"

```
プロセスが終了すると、生成されたserviceは自動的に削除される。

# 2 通常のコマンド実行のように実行する
```systemd-run```を普通に実行すると、プロセスはsystemdによってバックグラウンドで実行され、出力はターミナルには直接表示されず、ログとして回収される(```journalctl```コマンドで見られる)。
この動作は、デーモンとしてプロセスを実行させたいときには都合が良いが、気軽にコマンドを叩きたいときには不便なので、ここでは通常のコマンド実行のようになるようにオプションで動作を変えてみたい。

結論としては、以下のようにオプションを使用するのが便利だと思う。
```bash
 $ systemd-run --user --scope --quiet --same-dir コマンド
```
各オプションについて
- --user ユーザー側のsystemdを使用する。これによりユーザー権限でコマンドを実行できる。
- --scope  serviceを作成せず、コマンドはユーザーセッションから直接実行される。scopeを一時的に作成し、実行したプロセスはそのscopeに登録される。
- --quiet  systemd-runコマンドの出力を抑制する。
- --same-dir  コマンドの実行ディレクトリをカレントディレクトリにする。

# 3 リソースを制限する
```systemd-run```コマンドでは、```-p```オプションを使ってリソース制限の設定をすることができる。
なお、プロセス内で他のプロセスを起動した場合、その子プロセスも自動的に管理下に入る。(その場合、親と子プロセスの合計値が制限されることになる)


主な設定
| 設定 | 効果 |
|:---------:|:-|
| MemoryHigh=bytes  | 最大使用メモリを指定する。単位としてK, M, G, Tが使える。<br>メモリ制限を超過してもプロセスは停止せず、実行が非常に遅くなる。  |
|  MemoryMax=bytes | 上のMemoryHighと同様だが、メモリ制限を超過するとプロセスが停止する。  |
| CPUQuota=  |  単位として「%」をつけて指定する。CPUの使用量を制限する。<br>複数のCPUを使いたいときは100%より大きい値を指定する。 |
| TasksMax=N  |  プロセス数の最大値を指定する。 |
| IOReadBandwidthMax=device bytes | 指定したdeviceに対するI/Oの読み込み速度(一秒単位)を制限する。<br>バイトの指定にはK, M, G, Tが使える。|
|IOWriteBandwidthMax=device bytes |上記と同様に、I/Oの書き込み速度を制限する。|

たとえば、メモリ使用量を500MBに制限してコマンドを実行したい場合は以下のようになる。
```bash
 $ systemd-run --user --scope --quiet --same-dir -p MemoryMax=500M コマンド
```
# 参考リンク
https://www.freedesktop.org/software/systemd/man/latest/systemd.resource-control.html
https://www.freedesktop.org/software/systemd/man/latest/systemd-run.html
【Chrome】バグ報告を簡単にする方法【Jam】

Chrome拡張機能のJamを使用すると簡単にバグ報告ができるようになります。

https://jam.dev/

## Jamを導入する


[Jamのホームページ](https://jam.dev/)の「Get Jam for Free」ボタンをクリックします。

![スクリーンショット 2025-01-18 22.27.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/407b67cc-33c8-fb8a-4e69-be3b9a4fc2f7.png)

chromeウェブストアの「Chromeに追加」ボタンをクリックします。

![スクリーンショット 2025-01-18 22.29.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/b75e967d-9fa3-d71f-0c2c-a0bd9ab7ccdc.png)

以下の画面が表示されるのでメールアドレスを入力して「Continue」ボタンをクリックします。

![スクリーンショット 2025-01-18 22.30.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/242f9907-e681-8f51-2ccf-66500ab3bfe4.png)

アカウントが作成され、以下の画面が表示されます。

![スクリーンショット 2025-01-18 22.29.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/f667c8e0-5eed-c995-cbfd-4a1c0a0cfeb7.png)

画面に表示されている指示のとおり操作してJamをピン留めします。

## Jamの使用方法

### 画面録画

ピン留めしたJamのアイコンをクリックし、「Record tab」をクリックします。

![スクリーンショット 2025-01-18 22.31.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/f6e2b30b-1d2d-6ec1-de54-d9823a2cd8b0.png)

すると以下のように画面録画が開始されます。

![スクリーンショット 2025-01-18 22.32.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/d3de80d2-e639-1de0-2096-1a782a91c2eb.png)

録画停止ボタンをクリックすると以下のような画面が表示されます。

![スクリーンショット 2025-01-18 22.32.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/698fca17-2489-f38b-43f8-cd3f2becbd09.png)

コメントなどを記入することができます。「Create & copy link」ボタンをクリックするとバグ報告のページが作成され、リンクがクリップボードに保存されます。

作成されたページは以下のとおりOSやブラウザのバージョン情報、ConsoleやNetworkなどの情報を確認できます。

![スクリーンショット 2025-01-18 22.38.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/b72e8418-9602-7236-d7a6-c457cfb0d608.png)

![スクリーンショット 2025-01-18 22.38.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/2b54ceff-ac5d-06ef-8da2-3a61e3943e6c.png)

![スクリーンショット 2025-01-18 22.38.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/86b06a31-b44b-b492-c75d-09a22025b2ae.png)

![スクリーンショット 2025-01-18 22.39.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/7461f17b-ff48-d5d6-415a-7a6b5eec257d.png)

### スクリーンショット

ピン留めしたJamのアイコンをクリックし、「Capture Screenshot」をクリックします。

![スクリーンショット 2025-01-18 23.11.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/e115f266-ea94-dabc-08fe-64c43735374a.png)

スクリーンショットが撮影されると以下のような画面になり、画像に円などを描けます。

![スクリーンショット 2025-01-18 23.07.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/ef69ff45-e419-d429-813c-2d0d0b02eb48.png)

「Create & copy link」をクリックすると画面録画同様、バグに関する情報を閲覧できるページが生成され、そのページへのリンクが

![スクリーンショット 2025-01-18 23.08.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/7c309e64-37f6-c66e-2247-a19f56940baf.png)
Laravelを使った静的サイト制作のメリットと選択肢



静的なサイト制作では、通常HTMLやCSS、JavaScriptのみを使用することが一般的です。しかし、Laravelを活用することで、保守性や効率性を大幅に向上させることが可能です。このようなケースでは、CMSを導入せずにLaravelを使用するアプローチが適しています。

ここでは、静的サイト制作にLaravelを利用するメリットや、その適用シーンについて解説します。

---

## **1. Laravelを使った静的サイト制作のメリット**

### **1.1 Bladeテンプレートによる効率化**
LaravelのBladeテンプレートエンジンを活用することで、共通部分（例: ヘッダーやフッター）の管理が容易になります。これにより、サイト全体で一貫したデザインと構造を保ちながら、コードの重複を防ぐことができます。

**例: Bladeテンプレートの使用**
```php
<!-- resources/views/layouts/app.blade.php -->
<!DOCTYPE html>
<html>
<head>
    <title>@yield('title')</title>
</head>
<body>
    @include('partials.header')
    @yield('content')
    @include('partials.footer')
</body>
</html>
```

このように、共通部分を別ファイルに分けて管理することで、保守性が向上します。

---

### **1.2 Viteとの統合**
Laravelは標準でViteをサポートしており、モダンなフロントエンド開発が可能です。これにより、ホットリロードや効率的なアセットバンドリングを実現し、開発効率が向上します。

**利点:**
- フロントエンドの変更が即座に反映される。
- CSSやJavaScriptのモジュール化が容易。
- モダンなツールチェーンを活用可能。

---

### **1.3 動的コンテンツの対応**
Laravelを使用することで、静的なサイトに動的コンテンツを簡単に組み込むことができます。

**例:**
- 問い合わせフォーム
- ニュース記事の一覧表示
- ブログ記事のダイナミックな読み込み

---

## **2. Laravelを使用するべき静的サイトの例**

### **2.1 コーポレートサイト**
頻繁に更新が必要ではないが、統一感が求められる情報提供サイトに最適です。ヘッダーやフッターのテンプレートを活用して、効率的な制作が可能です。

### **2.2 ランディングページ**
短期間でリリースしたい場合にもLaravelが有効です。Bladeテンプレートを利用することで、コンテンツの構造を簡単に変更できます。

### **2.3 製品紹介サイト**
特定の商品やサービスを紹介するサイトでは、静的なコンテンツと動的な要素（例: 問い合わせフォーム）を組み合わせることで、柔軟な構成が可能です。

---

## **3. Laravelを選択する理由**

| 項目                    | Laravel使用時の利点                              |
|-------------------------|---------------------------------------------|
| **保守性**              | Bladeテンプレートにより、共通部分を簡単に管理できる。 |
| **開発効率**            | Viteのホットリロードで開発がスムーズに進む。       |
| **動的機能の追加**       | 静的サイトにも簡単に動的コンテンツを追加可能。      |
| **拡張性**              | 必要に応じて動的機能やデータベースを統合できる。    |
| **モダンな開発環境**      | フロントエンドとバックエンドの一元管理が可能。      |

---

## **4. 結論**

静的なサイト制作においても、Laravelを活用することで効率的で拡張性の高い開発が可能です。特に、保守性や共通部分の管理、動的コンテンツの追加が求められる場合には、大きなメリットを発揮します。

Laravelは静的サイトと動的サイトの中間に位置する柔軟なアプローチを提供します。Viteとの統合によるフロントエンド開発の効率化やBladeテンプレートによる保守性の向上は、静的なサイト制作においても十分な理由となります。

静的サイトを構築する際、Laravelを検討してみてはいかがでしょうか？
ABC389をPythonで（A～D）

トヨタ自動車プログラミングコンテスト2025（AtCoder Beginner Contest 389）の解答等の速報的まとめ

https://atcoder.jp/contests/abc389



# A問題
https://atcoder.jp/contests/abc389/tasks/abc389_a

入力をeval関数で計算する。ただし$x$は$*$に変換する必要がある。
```python:A
print(eval(input().replace(*"x*")))
```
# B問題
https://atcoder.jp/contests/abc389/tasks/abc389_b

実際に入力された値になるまで足していく。
```python:B
x = int(input())

a = 1
n = 1
while a < x:
    n += 1
    a *= n

print(n)
```
# C問題
https://atcoder.jp/contests/abc389/tasks/abc389_c

累積和の考え方を利用する。
$i$匹目の蛇のしっぽまでの長さを計算して、（求めたい蛇の順番＋抜けた蛇の匹数）の値から（抜けた蛇の匹数）の値を引いたものが答えとなる
```python:C
lst = [0]
head = 0

for _ in range(int(input())):
    com = list(input().split())
    if com[0] == "1":
        l = int(com[1])
        lst.append(l + lst[-1])
    elif com[0] == "2":
        head += 1
    else:
        k = int(com[1])
        print(lst[k - 1 + head] - lst[head])
```
# D問題
https://atcoder.jp/contests/abc389/tasks/abc389_d

円を4分割し、各扇型に含まれる正方形の数を尺取り法で計算する。
ただし、以下のやり方は中心を含む正方形を数えないため1足す必要がある。
```python:D
r = int(input())

ans = 0
h = r + 2
line = 0
for i in range(r + 1):
    while h > 0 and (h + 0.5) ** 2 + (i + 0.5) ** 2 > r ** 2:
        h -= 1
    ans += h
    if i == 0:
        line = h

print(ans * 4 + 1)
```
【React】MUIのDataGridにてソート・フィルター情報やページ情報を保存する方法

# 方法
apiRefのexportState()を使用し、DataGridの状態を取得する。
取得した状態をsessionなどに保存しておく。
状態を戻したいときは、restoreState()を使用する。
```jsx
// 取得
apiRef.current.exportState();
// 復元
apiRef.current.restoreState(/*exportStateで取得したデータ*/);
```

参考URL：https://mui.com/x/react-data-grid/state/?srsltid=AfmBOoqAdmsDdiBdz69gEpHmZcbnB3HPtVBOeh_bzpB90piFpMgorl0t

# サンプルコード
以下は、ソート・フィルター設定変更、またはページ切り替えをしたときに、その情報をセッションに保存し、画面を開いたときにそのセッションを元にDataGridの状態を復元するサンプルコードです。
```jsx
import * as React from 'react';
import { useEffect } from 'react';
import { Box } from '@mui/material';
import { DataGrid, useGridApiRef } from '@mui/x-data-grid';

export default function Sample() {
  // apiRefを使用
  const apiRef = useGridApiRef();

  // 仮データ
  const rows = [
    { id: 1, col1: 'ABC', col2: '123' },
    { id: 2, col1: 'DEF', col2: '456' },
    { id: 3, col1: 'GHI', col2: '789' },
    { id: 4, col1: 'JKL', col2: '123' },
    { id: 5, col1: 'MNO', col2: '456' },
    { id: 6, col1: 'PQR', col2: '789' },
    { id: 7, col1: 'STU', col2: '123' },
    { id: 8, col1: 'VWX', col2: '456' },
  ];

  const columns = [
    { field: 'id', headerName: 'id', width: 150 },
    { field: 'col1', headerName: 'Column 1', width: 150 },
    { field: 'col2', headerName: 'Column 2', width: 150 },
  ];

  /**
   * 画面起動時処理
   */
  useEffect(() => {
    // セッションストレージから保存された状態を取得
    const savedState = sessionStorage.getItem('dataGridState');
    if (savedState) {
      const parsedState = JSON.parse(savedState);
      // 状態を復元
      apiRef.current.restoreState(parsedState);
    }
  }, []);

  /**
   * DataGrid状態保存処理
   */
  const handleStateChange = () => {
    // 現在の状態をセッションストレージに保存
    const currentState = apiRef.current.exportState();
    sessionStorage.setItem('dataGridState', JSON.stringify(currentState));
  };

  return (
    <Box sx={{ height: 400, width: '50%', margin: 4 }}>
      <DataGrid
        apiRef={apiRef}// 使い方は普通のRefと同じ
        rows={rows}
        columns={columns}
        initialState={{
          pagination: {
            paginationModel: { pageSize: 5, page: 0 },
          },
        }}
        onPaginationModelChange={handleStateChange} // ページ移動時
        onSortModelChange={handleStateChange} // ソート時
        onFilterModelChange={handleStateChange} // フィルター変更時
      />
    </Box>
  );
}
```
これで2ページ目以降を開いたり、昇順・降順を変えたときなどの情報を保存しておき、後から同じ状態に戻すことができます。

### apiRefとは？

ここで使われているapiRefというのは、DataGridの扱いに特化したRefらしく、他にも行や列の変更もこれでできるそうです。


参考URL：https://mui.com/x/react-data-grid/api-object/?srsltid=AfmBOooeQ0gpfxI9Yr31T4TC4CDoTF5BkgK56LzoSJV5mO8_0dl68eKX

<br>

以上です。
クロージャの基本的な動きを理解してみる

# はじめに
Swift学習を始めた皆さまがぶつかる問題の1つが**クロージャの扱い**だと思います。
例に漏れず私もクロージャの扱いに苦戦していました（というか今も練習中です）。

**「クロージャ分からん！！！🤯」** となる壁の1つは、下記のようなコードではないでしょうか。
```Swift
func greetUser(greeting: (String) -> String) {
    let message = greeting("こむぎ")
    print(message)
}

greetUser { name in
    return "Hello, \(name)!"
}
```

こちらを理解できるように、順番に解説していきます。

# 「クロージャは無名関数」
タイトルの通りですが、こちらの文言を聞いたことがありますでしょうか。
検索するとこのように説明されている記事が多くヒットします。

理由は下記のコードを見るとわかりやすいかと思います。
```Swift
let greeting = { (name: String) -> String in
    return "Hello, \(name)!"
}
print(greeting("こむぎ"))  // 出力: Hello, こむぎ!
```

`name`という引数を受け取った後に`Hello, {name}!`の形式で値を返しており、メソッド（関数）の動きとよく似ています。
私自身、冒頭に述べたコードは難しいのにこちらは理解できていました。不思議ですね...🧐

実は、理解が難しくなってしまう原因は**クロージャをメソッドの引数として渡すこと**です。

文字だとわかりづらいので、例を見てみましょう。
# クロージャをメソッドの引数として渡す
よく**クロージャ渡し**と言われるヤツです。これが厄介です。
プログラミング初期では、メソッドの引数に`Int`や`String`などの値を表す型を渡す場合が一般的です。しかし、Swiftではクロージャを引数として渡すことができてしまいます。

型名はクロージャが`({受け取ったデータ型}) -> {返り値のデータ型}`で表現されます。
例えば、先ほどのコードをメソッドに渡す場合は下記のようになります。

```Swift
// メソッドの定義
// greetingメソッドは文字列を受け取って文字列を返すので (String) -> String と定義する
func greetUser(greeting: (String) -> String) { 
    let message = greeting("こむぎ") // 1, 2
    print(message) // 3
}

// クロージャの定義
let greeting = { (name: String) -> String in
    return "Hello, \(name)!" // 2
}

// メソッドにクロージャを渡して呼び出し
greetUser(greeting: greeting)  // 出力: Hello, こむぎ!
```

ここで初めて登場した`greetUser`は、先ほどの`greeting`クロージャから返った文字列を出力する役割を持っています。
### 処理の手順
1. 引数として受け取ったクロージャ `greeting` に `"こむぎ"` を渡して実行
1. クロージャから返ってきた結果を変数 `message` に格納
1. `print` メソッドで `message` を出力

このように、クロージャ渡しをすることで、**クロージャの中身が別のメソッドで実行されます。**
形は異なりますが、メソッドとほとんど同じ動きをします。
上記のコードでクロージャを引数として渡すイメージは掴めたでしょうか。

# クロージャの省略表記
では、次にクロージャの省略表記をした場合のコードを見てみましょう。
```Swift
// メソッドの定義
func greetUser(greeting: (String) -> String) {
    let message = greeting("こむぎ")
    print(message)
}

// メソッドにクロージャを渡して呼び出し
greetUser { (name: String) -> String in
    return "Hello, \(name)!"
}
```
**もうなんのこっちゃですね。**

私が最初見た時には、
「`greetUser`がメソッドなのに、なんで処理の内容が続きに書かれてるんだ？どっちを先にやればいいか分からんなぁ...そもそも`name`ってどこから来るんだ？？」
となりました。

省略記法に関してはこちらの記事がめちゃくちゃ分かりやすく説明してくれているのでぜひご覧ください！

https://blog.code-candy.com/swift_closure_basic/

動きとしては先ほどのコードと同一なので、8行目以降のコードは`greeting(こむぎ)`が呼び出された時に実行されます。下記のようなイメージを持っていただければ分かりやすいと思います。

![引数サンプル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935016/24794696-5e1b-1426-9c47-246804ae57ad.png)

図で示した部分を一言で表すなら次の通りです。
**メソッド名の後に`{ }`で囲まれているコードは、引数内のクロージャ引数に格納される**

ここでは3行目に`greeting`クロージャが呼ばれており、クロージャに渡した`"こむぎ"`という文字列を8列の`name`が受け取って処理を続けるイメージです。



さあ、ここまで着いてきたあなた、ありがとうございます。あと少しです。
クロージャの省略表記は、先ほどの例よりもさらに進めることができます。
その結果が下記の通りです。

```Swift
// メソッドの定義
func greetUser(greeting: (String) -> String) {
    let message = greeting("こむぎ")
    print(message)
}

// メソッドにクロージャを渡して呼び出し
greetUser { name in
    return "Hello, \(name)!"
}
```

なんと、クロージャ内の**引数と返り値表記が消えました**。
引数と返り値が無くなると、途端にメソッドと似たような動きであることが分かりづらくなります。
これを違和感なく読めるようになれば、冒頭のコードも読めることでしょう。

既にお気づきの方もいるかもしれませんが、こちらのコードは冒頭と同じです。
読み始める前と比較して、クロージャの動きがイメージできるようになってきましたでしょうか？
**「クロージャ分からん！！！🤯」** と噴火している方々を1人でも鎮火させられていれば幸いです。

この記事がお役に立ったと感じる方は、❤️と私の[X（Twitter）](https://x.com/_komugi0)にコメントを残していただけますと喜びます🙌

ではでは。