OmniAICreator/Qiita-1.07M huggingface dataset:
【ぼくのJavaScript備忘録】document.getElementById の使い方徹底解説


## 1. `document.getElementById` とは？

`document.getElementById` は、**HTML 要素の ID を指定して要素を取得するメソッド** です。

> **ポイント**：指定した `id` に一致する **最初の要素** を取得する。

---

## 2. 基本的な使い方

```javascript
const element = document.getElementById("myElement");
```

- `myElement`：取得したい要素の `id` を指定
- `element`：取得した要素（`null` の場合もある）

### ☑️ 例1：要素を取得してテキストを変更
```javascript
const heading = document.getElementById("title");
heading.textContent = "新しいタイトル";
```
> **ID `title` の要素のテキストを変更**

---

## 3. 取得した要素の操作

### ☑️ 例2：CSS スタイルを変更
```javascript
const box = document.getElementById("box");
box.style.backgroundColor = "lightblue";
```
> **ID `box` の背景色を変更**

### ☑️ 例3：クリックイベントを追加
```javascript
const button = document.getElementById("btn");
button.addEventListener("click", () => {
    alert("ボタンがクリックされました！");
});
```
> **ID `btn` のボタンをクリックするとアラートが表示**

---

## 4. `getElementById` の注意点

### ☑️ 取得できない場合（`null` になる）

```javascript
const nonExistent = document.getElementById("notFound");
console.log(nonExistent); // null
```
> **ID `notFound` が存在しないと `null` が返る**

### ☑️ 要素が `null` のときの対処

```javascript
const element = document.getElementById("myElement");
if (element) {
    element.textContent = "見つかった！";
} else {
    console.log("要素が見つかりません");
}
```
> **要素が存在するかチェックしてから操作する**

---

## 5. `querySelector` との違い

`document.getElementById` は `id` による **直接検索** に特化していますが、
`querySelector` は **CSS セレクターを利用** できます。

### 🔍 `getElementById` vs `querySelector`

| メソッド                   | 概要 |
|---------------------------|------------------------------------------------|
| `document.getElementById("id名")` | `id` による **高速な要素取得**（単一要素） |
| `document.querySelector("#id名")` | `CSS セレクター` を使用（より柔軟） |

### ☑️ 例4：`querySelector` を使った場合
```javascript
const element = document.querySelector("#myElement");
```
> **CSS セレクターを使用して ID を取得する方法**

---

## 6. まとめ

☑️ `document.getElementById("id")` を使うと、ID から要素を取得できる  
☑️ 存在しない ID を指定すると `null` になるので注意  
☑️ `style` や `textContent` で要素の変更が可能  
☑️ `querySelector("#id")` との違いを理解する  

`getElementById` を活用して、DOM 操作をスムーズに行おう！
【初心者向け】SQL文　副問い合わせ

<!--

## 技術記事のタイトル

最も伝えたいこと。

簡潔かつ分かりやすく過不足ないタイトルを考えましょう。

### 【 】(墨付き括弧)

- 【言語やサービス】
    - 例1.【Python】すぐにpytestで単体テストを実行するまでの手順
- 【言いたいこと】
    - 例1.【必見】Objectはどこに消えた？
- 【前提】
    - 例1.【個人開発】○○を○○できるサービスをリリースしました
    - 例2.【初心者向け】Reactとはそもそも何なのか説明します
- 【続き物の番号】
    - 例1.【2024年版】新入社員向け研修資料を公開します
    - 例2.【環境構築編】Windows11でPythonを実行するまで

【前提】詳しいタイトル【言語やサービス】のように、複数を併用するパターンもあります。

-->

## はじめに
<!--
何についての記事なのか、誰に向けた記事なのかを簡単に説明しましょう。
-->
初めて副問い合わせを使用する場面があったので知識の整理として記事にしました。


### この記事でわかる・できること
<!--
読んだら何がわかるようになるのか、何ができるようになるのかを書きましょう。
-->

- 副問い合わせとは何か
- 具体的な使用場面


### この記事の対象者
<!--
誰に向けた記事なのかを明確にすることで読者に選んでもらいましょう。
-->

- SQL文初心者





## 仮　SQL文　副問い合わせ
<!--
章全体の要約や、何について書くのかをここに書きます。
記事が長い時や資料として作るときは番号を振ることをおすすめします。
章を増やすときは章から項までをコピーしてください。
-->



### 
<!--
記事の主要な部分です。ここに思い思いの内容を書いていってください。

画像やGIFがあると分かりやすいです。
画像があるとUIが変わったとしても読者がアタリをつけて対応しやすくなります。

コードを記載する場合は必ずコードブロックを使いましょう。
バッククオート3つで囲んでください。
```python:表示名

    print('Hello World')
    
```
-->
#### 副問い合わせとは何か
副問い合わせとは、SQL文の中で別のSQL文をネスト（入れ子）して使用する方法です。副問い合わせを使うことで、複雑な条件を指定したり、実行時の条件や状況に応じてのデータ取得を行うことができます。


#### 具体的な使用場面
2つのテーブル（ここではA,Bとする）からファイル作成のためのデータ抽出を行う際、以下のような抽出条件を指定する際に副問い合わせを使用しました。

【抽出条件】
Aテーブル.結果 = 正常　かつ　Bテーブル.処理日＞Aテーブル.処理日が存在しない
 
【SQL文】
SELECT　項目
FROM　Aテーブル
WHERE 条件①
AND    条件②
AND    条件③
NOT EXISIT（Aテーブル.結果 = 正常　かつ　Bテーブル
　　　　　　　AND　Bテーブル.処理日＞Aテーブル.処理日）
       
<!--
より詳細な内容を書いたり、事例を挙げたりするときに使います。
- 節の内容の列挙
- 節の補足事項
- 例外
-->





## おわりに
<!--
どちらかを書きます。あってもなくても良いです。
-->
最近、設計書に記載されている抽出条件からSQL文を考える場面がありましたが、設計書から具体的なコードに落とし込むのは難しいですね。。（最初は単に結合すればできそうだと考えていました。）
基本的な文法を知ってできた気がしてましたが、今回は自分がどれほど理解していないかを知ることができました。
Turbo備忘録

Ruby on Railsのバージョン:7.2.1
Rubyのバージョン:3.3.5

# Turboについて

**Turbo Drive**　
ページ全体のリロードを不要にすることで、リンクやフォーム送信を高速化する

**Turbo Frames**　
ページを独立したコンテキストに分解し、ナビゲーションをスコープ化し、遅延ロードできるようにする

**Turbo Streams**	
HTMLとCRUDライクなアクションのセットを使用するだけで、WebSocket、SSE、またはフォーム送信に応答してページの変更を配信する

**Turbo Native**	
（モバイル開発用）Webセクションとネイティブセクション間のシームレスな遷移により、壮大なモノリスをネイティブiOSおよびAndroidアプリの中心に配置できる

## Turbo Frames
```index.html.erb
<h1>Turbo</h1>

<hr>
<%= turbo_frame_tag "new_post" do %>
  <%= link_to "新規投稿", new_post_path %>
<% end %>
<hr>
```
```new.html.erb
<%= turbo_frame_tag "new_post" do %>
  ここが更新
<% end %>
```
上記のように記載したら下記のスクショのようになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3931580/8d3632fc-1520-c10f-d7be-c542154dc188.png)
↓新規投稿リンクを押下すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3931580/0a124345-0b04-244f-8962-d15a0aa496ec.png)
となる。

**turbo_frame_tagのブロック内の内容だけが更新されているということ**
turbo_frame_tag のブロック内にあるリンクを踏むと、Turbo Frames により、リンク先のビューファイル、今回ならば new.html.erb の中の、同じ id をもつ turbo_frame_tag を探し出し、この内部だけを置き換える処理を行う。
**new_post**を目印にして、どこを更新するかを決めているためここの値が一致していない場合はエラーになる。
また、原則として link_to を使用する場合は、下記のように data-turbo-frame 属性を指定する方が無難です。これで、link_toの行がturbo_frame_tag外に移動したとしても効果を発揮する。

```
<%= turbo_frame_tag "new_post" do %>
  <%= link_to "新規投稿", new_post_path, data: { turbo_frame: "new_post" } %>
<% end %>
```

この技術で、一覧表示とページネーションがあるページ（index.html.erb）から２ページ目を閲覧する時に投稿一覧の部分をTurbo Framesで更新すること（turbo_frame_tagで囲む）ができる。

## dom_id
dom_id ヘルパーメソッドを利用してnew_postを表す

```
<h1>Turbo</h1>

<hr>
<%= turbo_frame_tag dom_id(Post) do %>
  <%= link_to "新規投稿", new_post_path, data: { turbo_frame: dom_id(Post) } %>
<% end %>
<hr>
```
new_postをdom_id(Post)と記載することで表すことができます。


## Turbo Streams
Turbo Streams には７つの action が設定されています。

action	解説
append	タグ内の一番下に追加
prepend	タグ内の一番上に追加
before	タグ外の一番上に追加
after	タグ外の一番下に追加
update	タグ内を置換
replace	タグを含めて丸ごと置換
remove	タグを含めて丸ごと除去

```
<%= turbo_stream.アクション名 対象のid do %>
  コンテンツ
<% end %>
```
を書くことで、対象のid属性に対して、上記の操作をJavaScriptを書かずに実現できるという、非常に便利な機能がTurbo Streamsです。

### 補足
turbo_streamで指定するidは**turbo-frame**タグである必要はありません。 
**divタグでもpタグでも対応可能です。**
常識ですが、HTML内に同じ id 属性を複数箇所で使用してはいけないルールがあります。このルールを守っている限り対象となるタグは一つに決まります。


途中
カテナリー曲線のシミュレーション

# はじめに
ロープを水平にすると電柱の電線のようにカテナリー曲線を描くことが一般的に知られている。これは、ロープを細かく分割して質量を持った短いロープの集合体として考え、微分方程式を立てることで証明することができる。もしくは、変分法でも証明することができる。そこで、今回はPythonを用いて水平にしたロープの描く軌跡をシミュレーションする。

![カテナリー曲線2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/236d3927-41b6-4cee-86e3-5fbdcd3e2759.gif)


# 運動方程式

左から等間隔に$n$個の質点を並べる。そこで、$i$番目の質点に対して以下のような運動方程式を考える。
ただし、質点の座標を$X_i=x_i+jy_i$とした。

```math
m\frac{dX_i^2}{dt^2}=-j\{ -k(X_i-X_{i-1})-k(X_i-X_{i-1})=-k(X_{i+1}+X_{i-1}-2X_i)\}
```

# プログラム

上記の運動方程式を用いて、プログラムを作成する。

``` python catenary.py
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
import math
import matplotlib.animation as animation

fig = plt.figure()

ims = []
g=-9.8
m=1

k=1
n=10
X=np.linspace(0,10,n,dtype=complex)
dxdt=np.zeros(n,dtype=complex)
ddxdtt=np.zeros(n,dtype=complex)
dt=0.03
Y=np.zeros(n)

t=0
#オイラー法による微分方程式の数値解析
while t<10:
  for i in range(n):
    if 0<i<n-2:
      ddxdtt[i]=-(k/m*abs(X[i+1]+X[i-1]-2*X[i])-m*g)*(-1j)
    #境界条件（両端固定）
    elif i==0:
      X[0]=0
      ddxdtt[0]=0
    else:
      X[-1]=0
      ddxdtt[-1]=0
    dxdt[i]=dxdt[i]+ddxdtt[i]*dt
    X[i]=X[i]+dxdt[i]*dt
  im=plt.plot(X.real,X.imag,"o",color="red")
  ims.append(im)
  t=t+dt
# 10枚のプロットを 100ms ごとに表示
ani = animation.ArtistAnimation(fig, ims, interval=10)
#保存
ani.save("カテナリー曲線2.gif", writer="pillow")
```

これを実行すると以下のようになる。

![カテナリー曲線2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/236d3927-41b6-4cee-86e3-5fbdcd3e2759.gif)

確かに、落下するにつれてカテナリー曲線を各質点は描写していくのが分かる。

# まとめ
今回は、オイラー法を用いて、カテナリー曲線のシミュレーションを行った。結果見事に、曲線を描写することができた。

# 参考文献

https://sci.tea-nifty.com/blog/2020/09/post-f9df20.html
todoリストと日記をまとめて管理できるサービスをNextjsで作った

# はじめに
今回はtodoリストと日記をまとめて管理できるサービスをNextjsで開発して公開しました。
技術スタックや開発を通しての気づきなどを紹介します。

サービス
https://todo-nikki.vercel.app/

動作デモ動画
https://youtube.com/shorts/l6RYrl_xFNk?si=J2D6e9JYS9iWkuAB

GitHub
https://github.com/yamaneko05/todo-nikki

# サービスのコンセプト
普段から一般的なメモアプリを使って毎日のTODOリストや日記を管理していました。
そこで、日付でグループ分けされるこの2つの情報をもっと効率的に管理できるサービスがほしいと思い、このサービスを開発するのに至りました。

利用のしかたイメージ
- 前日の夜：明日やることを明日のtodoリストに追加する
- 当日：前日に追加したtodoをこなす、完了したものにチェックする
- 当日の夜：当日のtodoの完了状況をふりかえり、日記を作成する
- 週末：一週間の未完了のtodoを確認し、来週の計画をたてる

ほかのTodoリストや日記アプリにない機能
- カレンダーから日別の完了/未完了のタスク数、日記の有無を確認できる
- todoリストの内容をもとに生成AIを用いて日記の文章を自動生成する（未実装）

#
【UE5】ファーストパーソンで作成してVRモードに対応させるまで

# 導入（茶番）
好きな扉作ったり、テクスチャも自由に操作できるようになったし、
UnrealEngineもちょっと慣れてきたかな〜（勝者の笑み）

ええ感じのレベルも作ったぞい！
これをMetaquestに入れてっと・・・・・・ん？

＿人人人人人人人人人人＿
＞　VR状態にならない　＜
￣Y^Y^Y^Y^Y^Y^Y^^Y^￣

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967203/42b6c169-283a-2ef0-df6e-895761dec344.png)
圧倒的没入感😅😅😅😅

## なぜこうなってしまったのか
というわけで原因調査＆解決をしていきたいと思います。
ことの始まりはプロジェクト作成時でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967203/f0d07187-2c67-a61f-9ce2-15a5a7db4ad7.png)

通常であれば「バーチャルリアリティ」を選択するのが無難らしいですが、
このモードではテストプレイが大変という話を聞いたため、今回はあえてファーストパーソンで作成していました。
よってデフォルトの設定では映画館になってしまう説。


:::note warn
注意
本記事の目的はファーストパーソンで作成したコンテンツをバーチャルリアリティに適応させることです。
本来であれば最初からバーチャルリアリティで作成するべきであり、筆者の横着でこうなっているため、いわゆるベストプラクティスではない恐れがあります。
:::

# 試してみたこと
色々な記事を読んで試してみたけど解決せず。
結局他のプロジェクトをVRモードで作成して設定を比較する感じにしてみた（ゴリ押し）

以下、変更した設定です。
時系列順に記載していますが、正直どれが直接的に起因したかは不明・・・

## 足りていないパックを追加する
コンテンツドロワー ＞ 追加 ＞ 
機能またはコンテンツパックを追加 ＞ バーチャルリアリティ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967203/0b6ec22f-2d8f-3b8d-f816-56bcba4ee2a8.png)
これでコンテンツドロワーにVRTemplateが追加された。

## プラグインをいじる
OpenXRが有効になっていなかったので投入してみる。ユーザ体感の変化はなし。
正直OpenXRだけでも良さげ。
 - OpenXR
 - OpenXR Eye Tracker
 - OpenXR Hand Tracking

## プロジェクト設定周りをいじってみる
 - プロジェクト　＞　説明　＞　設定
VRで開始は必要そうな感じですねぇ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967203/0326cf72-c9c8-d7b6-f145-ab50bfa1110e.png)

 - プロジェクト　＞　ターゲットハードウェア　
DesktopをモバイルにしてScalableに！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967203/6ef61632-6f7d-e84a-64c4-136752dc65e9.png)

 - プロジェクト　＞　マップ＆モード　＞　Default Modes
VRGameModeに変更してみる。実行するとターミナルが走るので何か効いていそう？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967203/1b88e07a-7121-7ae9-3873-cf61db3295c2.png)

プラットフォーム　＞　Android ＞　Advanced APK Packaging
の設定でMetaquest2をデバイスを指定してみる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967203/1c4d34bc-ae3f-cd1f-1e5c-b8fb1a6435c0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967203/e1acc3b8-7d24-6e4c-cdeb-39fcda12ac27.png)

お、これで3D空間が表示されるようになった！解決！！！
ただし移動ができないので、コンフィグ周りの設定も見比べて直す必要がありそう。

:::note warn
コメント
言わずもがな、この状態だとPCからのテストプレイで操作が効かなくなる。
VRでなくPCでテストプレイをしたい場合は2つ前の
プロジェクト　＞　マップ＆モード　＞　Default Modes
をFirstPersonに戻せば動くよ〜！！
:::


# プラスアルファの設定（移動操作）
TODO（気が向いたら書く）

追記：
いくつか設定をいじってみましたが、スティックの割り当ては厳しそうでした。（もしかしたらバグなのかもしれない。。。）
本記事は「ファーストパーソンで作成し、VRモードの設定に変更する」というテーマでしたが、むしろ「VRモードで作成して、ファーストパーソンのような動作確認を出来るようにする」の方が適切なのかもしれません。

その場合は下記設定でできそうでした！
1. 足りていないパックを追加する
2. プロジェクト　＞　マップ＆モード　＞　Default Modes　で「BP_FirstPersonGameMode」に設定する 

また、本記事では触れていませんでしたが、別途ワールドセッティングを行っている方はその内容も「BP_FirstPersonGameMode」に合わせる必要がありました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967203/33529189-efd9-4539-9ebd-0832fdce33fd.png)


悔しいのでいつかリベンジしたい...!!!!


# 参考
直接は利用していませんが、本記事で解決しなかった方はご参考までに！

https://zenn.dev/eightbeat/articles/4d7b764c795c21

https://dipross.co.jp/eng/2024/12/%E3%80%90ue5%E3%80%91vr%E9%96%8B%E7%99%BA%E3%81%82%E3%82%8B%E3%81%82%E3%82%8B%E8%A8%98.html
上野敦稔のTips：フロントエンド初学者向けの学習方法

# フロントエンド初学者向けの学習方法

フロントエンド開発は、ウェブサイトやウェブアプリケーションのユーザーインターフェースを作成する重要なスキルです。初心者が効率的に学習を進めるために、基本的な学習方法を紹介します。

## 1. HTML・CSSの基礎を学ぶ

フロントエンド開発の基本はHTMLとCSSです。これらを理解しないと、ウェブページの構造やデザインを作成できません。

### 学習方法
- **公式ドキュメント**: [MDN Web Docs](https://developer.mozilla.org/ja/)
- **オンライン教材**: Udemy、Progate、ドットインストール
- **実践**: シンプルな静的サイトを作成してみる

## 2. JavaScriptの基礎を習得する

JavaScriptは、ウェブページに動的な機能を追加するために必須の言語です。

### 学習方法
- **基本文法を学ぶ**: 変数、関数、条件分岐、ループ
- **DOM操作を練習**: イベントリスナーや要素の取得・操作
- **おすすめ教材**:
  - MDN Web DocsのJavaScriptガイド
  - JavaScriptチュートリアル（JavaScript.info）

## 3. バージョン管理（Git/GitHub）を学ぶ

チーム開発やプロジェクト管理にはGitとGitHubの理解が欠かせません。

### 学習方法
- **Gitの基本コマンドを習得**: `git init`, `git add`, `git commit`, `git push`
- **GitHubでリポジトリを作成し、公開する**
- **無料で使える学習リソース**: GitHub Docs, Atlassian Git Tutorial

## 4. フレームワーク・ライブラリを学ぶ

基本を習得したら、フロントエンド開発を効率化するためのフレームワークやライブラリを学びましょう。

### おすすめの技術
- **CSSフレームワーク**: Bootstrap, Tailwind CSS
- **JavaScriptフレームワーク**: React, Vue.js, Angular

### 学習方法
- 公式ドキュメントを読む
- チュートリアル動画を視聴する
- 実際に小さなプロジェクトを作成してみる

## 5. 実践的なプロジェクトを作成する

学んだ知識を活かして、実際に動くものを作ることが大切です。

### プロジェクトのアイデア
- **ポートフォリオサイト**: 自分の学習成果をまとめる
- **ToDoアプリ**: JavaScriptの基礎を活用
- **APIを利用したアプリ**: 天気予報アプリ、ニュースアプリなど

## 6. コミュニティに参加し、情報をキャッチアップする

フロントエンド開発は進化が早いため、常に新しい情報を学ぶことが重要です。

### 参加方法
- **技術ブログやYouTubeをチェックする**
- **TwitterやDiscordで開発者と交流する**
- **勉強会やハッカソンに参加する**

## まとめ

フロントエンド開発を学ぶには、基礎を固め、実践を積み、最新技術をキャッチアップすることが大切です。自分に合った学習方法を見つけて、継続的にスキルを磨いていきましょう！
"SQLSTATE[23000]: Integrity constraint violati～..."の原因

## エラーの出た経緯
ユーザー新規登録をする際にメアドなどなどを記入して登録ボタン押した
→"SQLSTATE[23000]: Integrity constraint violati～..."のエラー発生


## 原因
過去に同じメアドを登録していたため、値がかぶるんですけど～っていうエラーだった。

どうやらプライマリキーが設定されているカラムで値がかぶると出てくるエラーらしい。
→https://umebius.com/eccube/sqlstate23000-integrity-constraint-violation-1062-duplicate-entry-0-for-key-primary/


→同じエラーが出た投稿者さん
https://qiita.com/Halu_wimps/questions/31b3f710e974689aa264

## 解決方法
動作確認で過去に色々登録していたデータを、全部データベースから削除した。
【ぼくのJavaScript備忘録】addEventListener の使い方徹底解説

## 1. `addEventListener` とは？

`addEventListener` は、JavaScript で **イベントリスナーを設定** するためのメソッドです。  
`document` や特定の要素を指定して、イベント（`click`、`keydown` など）を監視し、特定の処理を実行できます。

> **`document` とは？**  
> `document` は、ブラウザが読み込んだ **HTML ドキュメント全体** を指すオブジェクトです。  
> ただし、`document` に直接イベントを設定するのではなく、**特定の要素を変数に格納して扱うことも可能** です。

---

## 2. 基本的な使い方

```javascript
document.addEventListener(イベント名, イベントハンドラ, オプション);
```

または、特定の要素を変数に格納してイベントリスナーを追加することもできます。

```javascript
const button = document.getElementById("myButton");
button.addEventListener("click", () => {
    console.log("ボタンがクリックされました！");
});
```

- `イベント名`：監視するイベント（例：`click`、`keydown`、`scroll` など）
- `イベントハンドラ`：イベントが発生したときに実行される関数
- `オプション`（省略可）：イベントの詳細設定

---

## 3. 具体的な使用例

### ☑️ 例1：クリックイベントを監視

```javascript
document.addEventListener("click", function() {
    console.log("ページがクリックされました！");
});
```

または、特定の要素のみに設定する場合：

```javascript
const myButton = document.getElementById("myButton");
myButton.addEventListener("click", function() {
    console.log("ボタンがクリックされました！");
});
```

> **ページ全体** または **特定の要素** でクリックイベントを監視できる。

---

## 4. `removeEventListener` でイベントを削除

イベントリスナーを削除するには `removeEventListener` を使います。

### ☑️ 例2：クリックイベントを削除
```javascript
function handleClick() {
    console.log("クリックされました！");
}

document.addEventListener("click", handleClick);
document.removeEventListener("click", handleClick);
```

または、変数に格納した要素に対して削除：

```javascript
const myButton = document.getElementById("myButton");
function handleClick() {
    console.log("ボタンがクリックされました！");
}

myButton.addEventListener("click", handleClick);
myButton.removeEventListener("click", handleClick);
```

> **削除するには、関数を変数として渡す必要がある**

---

## 5. `useCapture` と `passive` オプション

イベントリスナーには **オプション** を設定できます。

```javascript
document.addEventListener("touchmove", function(event) {
    console.log("タッチイベント発生！");
}, { passive: true });
```

### 🔍 オプションの解説

| オプション           | 説明                                            |
| --------------- | --------------------------------------------- |
| `capture: true` | **キャプチャフェーズ** でイベントを処理（通常は `false`）           |
| `passive: true` | **スクロール最適化**（イベント内で `preventDefault()` を使わない） |
| `once: true`    | **1回だけ実行** したらイベントリスナーを削除                     |

---

## 6. どのようなイベント名があるか？

JavaScript のイベントの種類は多岐にわたります。  
主要なイベントについては、**Mozilla Developer Network (MDN)** の `Element` API のページで確認できます。

[イベントの一覧はこちら](https://developer.mozilla.org/en-US/docs/Web/API/Element#mouse_events)

---

## 7. まとめ

☑️ `document.addEventListener(イベント名, ハンドラ)` でページ全体のイベントを追加できる  
☑️ 特定の要素を変数に格納して `addEventListener` を適用できる  
☑️ `removeEventListener` で不要なイベントを削除できる  
☑️ `passive` や `once` などのオプションを使うと最適化ができる  
☑️ イベントの一覧は [MDN の Element API](https://developer.mozilla.org/en-US/docs/Web/API/Element#mouse_events) を参照  

このメソッドを活用すれば、**インタラクティブな Web ページ** を作れます！
統計検定1級　2024　統計応用(理工学)  問3　解説

不十分な内容がありますが私の実力ではこの程度が精いっぱいです。
![img20250204_08531098.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/528702ed-5855-fa75-9fa2-2c66d78b874d.jpeg)
![P2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/70197b0f-0bac-296d-a535-52ebae0b5694.jpeg)
![P3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/60111483-2404-5786-7ffc-d984b607f818.jpeg)
![P4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/5d2c97a7-768e-de46-e123-d215b8c79f83.jpeg)
【前半】Unityを使ったARコンテンツの開発

# はじめに
　株式会社GENEROSITY様でインターンをさせていただき、AR技術を使ったサービスの企画提案と必要最小限の機能を持ったプロダクト(Minimum Viable Product)を制作しました。AR技術を使った制作で普段とは違った開発に戸惑いながらなんとか形にすることができました。
　前半では作ったサービスの概要と開発環境、位置情報の求め方についてまとめてあります。
# 目次
[概要](#概要)
[開発環境](#開発環境)
[位置情報を把握するための技術](#位置情報を把握するための技術)
[制作](#製作)
[実行・テスト](#実行テスト)
[まとめ](#まとめ)


# 概要
「屋内で行きたい場所にARを使って案内するアプリ」を制作しました。
##### この製品を作った理由
ショッピングモールや大型施設を訪れた際、目的の店舗や施設にたどり着けず困ったことはありませんか？ そんな悩みを解決するために「屋内で行きたい場所にARを使って案内するアプリ」を開発しました。

広大なショッピングモールや大型施設内で目的地が見つからないこと。どこに行きたいお店があるのか、どんなお店があるのか。全体のレイアウトが分からずストレスを感じることはありませんか？ 私は売り場がどこにあるかわからず右往左往した経験があります。

このアプリは、そんな問題を解消するために生まれました。目的の場所やお店を選ぶと、AR（拡張現実）技術を使って、スマートフォンの画面上に矢印を表示し案内してくれます。これにより、道に迷うことなく、スムーズに目的地に到達できます。
#### イメージ図
![スクリーンショット 2025-01-20 125452.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4001685/1f67a3ce-406f-dad4-93c0-0d4067fc1961.png)


# 開発環境
・Unity (2022.3.56f1)
・ARFoundation 5.1.5
・Google ARCore XR Plugin 5.1.5
###### 実行デバイス
・OPPO Reno 10 Pro 5G

#### Unity Habとプロジェクトの生成
:::note warn
注意
こちらではUnityアカウントを持っている前提で話していきます。
:::

https://unity.com/ja/download

上のリンクからUnity Habをインストールしプロジェクトを作ります。
インストールが完了したら自分のアカウントでログインし、Unity Habの**Installs**に移動してInstall Editorを押しUnity(2022.3.56f1)をインストールします。
次にProjectに戻りNew Projectを押し3D Coreを選択しプロジェクトを作成します。
![スクリーンショット 2025-02-04 sub.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4001685/753ced00-595a-cfcf-16d5-c9668ce15f82.png)
これらを選択していればプロジェクトを作ってOKです。

#### ARFoundationとGoogle ARCore XR Pluginのインストール
次にAndroidでARを開発するのに必要なパッケージのインストールを行います。
プロジェクトが開いた後、左上にある Window > Package Manager を選択します。
その後 Package: In Project を Package: Unity Registry に変更します。
![スクリーンショット 2025-02-04 150818.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4001685/508590df-e361-b789-f6b8-4bb3de67742a.png)
その後**AR**という項目が出てくるので選択しInstallを押します。

#### その他の調整箇所
次に左上の `File` > `Build Setting...` を選択しBuild Settingsの画面を出します。
左下にある `Player Settings...` を押して `Project Settings` の中の `Player` の設定を変更します。
１．`Other Settings` を開き `Auto Graphics API` のチェックを外し `Vulkan` を消します。
２．`Minimum API Level` を `API level 27` 以上にします。
３．`Scripting Backend` を `IL2CPP` に変更します。
４．`Traget Architectures` の中の `ARM64` にチェックを入れます。
次に `XR Pulg-in Management` を `Android settings` にして `Google ARCore` にチェックを入れます。

以上で Unity を使ったAR開発に必要な基本的な環境が整います。


# 位置情報を把握するための技術
・**GPS( Global Positioning System )**

・**Wi-Fi位置情報**

・**Bluetoothビーコン**

・**カメラおよびコンピュータビジョン**

・**IMU（慣性計測ユニット）**

・**SLAM（Simultaneous Localization and Mapping）**

・**NFC（近距離無線通信）**

主にこの７つが位置情報を把握するのに必要なシステムとなっています。
今回 GPS は屋内での使用を想定しているため使いません。
今回は **SLAM** の一種 **vSLAM**(Visual SLAM) を利用して開発していきます。

**vSLAM**(Visual SLAM) とは…
　カメラやイメージセンサーを用いて自己位置（自分がいる場所）の推定と周囲の環境地図作成（周辺の空間把握）を同時に行う技術のことです

https://qiita.com/iitachi_tdse/items/b89547548cb733e8cf00

今回vSLAMを使う理由は
１．屋内環境に強いこと
２．スマートフォンを使うため
３．様々な場所で動作させるため
などの理由があります。

# おまけ
 Android端末に Build した際 `Deubug.Log` を読み取ることができないためどこでスクリプトが止まっているのかわからないという事はないですか？
 そんなときに便利な **`Android Logcat`** という Package があり、端末をパソコンにつないだ状態でアプリを起動すればLogを確認することができます。
Logを確認したい時に `Window` > `Analysis` > `Android Logcat` からウィンドウを出すことができるのでぜひ試してみてください。
MQTT over WebSocket: MQTT.js で接続

こちらで立てたブローカーを使います。
[MQTT over WebSocket: localhost でのテスト](https://qiita.com/ekzemplaro/items/51c929024740de5e70f7)

## Publish

```js:pub_8083.js
const mqtt = require('mqtt')

// MQTTブローカーに接続
const client = mqtt.connect('mqtt://localhost:8083')

client.on('connect', () => {
    console.log('Connected to MQTT broker')

    // メッセージをパブリッシュ
    client.publish('example/testTopic', 'Good Evening Everybody', (err) => {
        if (err) {
            console.error('Failed to publish message:', err)
        } else {
            console.log('Message published')
        }

        // 接続を閉じる
        client.end()
    })
})

client.on('error', (err) => {
    console.error('Connection error:', err)
})
```

実行結果

```text
$ node pub_8083.js 
Connected to MQTT broker
Message published
```

## Subscribe

```js:sub_8083.js
const mqtt = require('mqtt')

// MQTTブローカーに接続
const client = mqtt.connect('mqtt://localhost:8083')

client.on('connect', () => {
    console.log('Connected to MQTT broker')

    // トピックをサブスクライブ
    client.subscribe('example/testTopic', (err) => {
        if (err) {
            console.error('Failed to subscribe to topic:', err)
        } else {
            console.log('Subscribed to topic: example/testTopic')
        }
    })
})

// メッセージを受信したときの処理
client.on('message', (topic, message) => {
    console.log(`Received message on topic "${topic}": ${message.toString()}`)
})

client.on('error', (err) => {
    console.error('Connection error:', err)
})
```

実行結果

```text
$ node sub_8083.js 
Connected to MQTT broker
Subscribed to topic: example/testTopic
Received message on topic "example/testTopic": Good Evening Everybody
```

## 確認したバージョン

```text
$ node --version
v23.7.0
```
【エンジニア初心者へ】プログラム三箇条

# プログラミングの初心者向けメモ
ただ実践を通して身に着けた考え方を書いていく記事。初心者なら参考になるかも。

## ゴールを決める
ソースを書き換えるうえで最も大切なのは最初にゴールを決めてしまうこと。
ゴールが不明な状態では、間違いなくソースコードを書いていくうえで迷いやブレが生じる。
例えば、MVCモデルにおいてモデル側を修正する場合は、それが最終的にどういうクエリをDBへ投げたいのか？のゴールを明確にしないと、ソース上の変更ができなくなる。

## 定数を上書きするような処理を作らない。
どうしても上書きしなければならない状況以外は新しい変数を定義して使用する。
再度、定数を使用するような機会が訪れる可能性があり、それを考慮するならば確実に定数を上書きするような処理をしてはならない。
ただし、パフォーマンスやデバッグのことを考えると定数が増えたときに重くなるので、そこは規模と相談。

## とりあえずデバックツールを使う
ローカル上でデバッグツールを使用して、関数内における各変数ごとの持つ値や具体的な配列の中身まで把握すれば、具体的にどのように実装すればいいのかイメージが付く。デバックツールを動かさないでどのように実装すればいいのかを判断するのは完成されたサービスにおいては難しい（ソースコードが膨大であるため
個人的な備忘録：LDAP認証を活用した勤怠管理システムを作りたいと思い、要件定義してみた

## はじめに

今回の記事の内容については、企業の従業員および管理者が勤怠情報を記録・管理するための **Webベースの勤怠管理システム** を作ってみたいと思ったので、要件定義をした内容となっています。

:::note alert
つきまして、内容については **個人の備忘録程度** になりますので、その点はご了承ください。
:::

**Active Directory (AD) のLDAP認証** を活用することで、安全かつ統一的なユーザー認証を実現し、従業員・管理者の **権限に応じた機能を提供** することができます。

## こんなイメージです

本システムは、**LDAP認証を活用した勤怠管理システム** であり、**Active Directoryと連携** することで **企業内の統一認証を実現** します。  

また、**従業員と管理者の権限に応じた機能提供** を行い、勤怠データの管理を効率化します。

```text
[1] ユーザーが勤怠管理システムにアクセス  
    ↓  
[2] ログイン画面でユーザー名・パスワードを入力  
    ↓  
[3] システムがLDAPサーバー (Active Directory) に認証リクエストを送信  
    ↓  
[4] ADが認証情報を照合し、結果をシステムに返す  
    ├── OKなら → [5] セッションを作成し、ユーザーをダッシュボードにリダイレクト  
    │           ↓  
    │   [6] システムがユーザーの権限情報を取得 (例: 従業員 or 管理者)  
    │           ↓  
    │   [7] ユーザー権限に応じた機能・データが表示  
    │           ├── **従業員** → 勤怠打刻、勤務時間確認、有給申請  
    │           └── **管理者** → 従業員の勤怠データ管理、シフト作成、承認作業  
    ↓  
    └── NGなら → [エラーメッセージ表示: IDまたはパスワードが違います]  
```

-  **セキュアな統合ログイン環境を構築したい場合** に適した設計です。

## システムの流れ

### **認証成功時のフロー**

**[1] ユーザーが勤怠管理システムにアクセス**  
- ユーザーはWebブラウザを使用し、勤怠管理システムのログイン画面にアクセス。  
- **URL例:** `https://attendance.example.com`

**[2] ログイン画面でユーザー名・パスワードを入力**  
- ユーザーは **会社のActive Directoryの認証情報（ユーザー名とパスワード）** を入力。  
- **メリット:** 社内の統一認証情報を利用でき、別途システム専用アカウントの作成不要。

**[3] システムがLDAPサーバー (Active Directory) に認証リクエストを送信**  
- システムは入力された認証情報を元に、LDAPサーバー (Active Directory) に対して認証リクエストを送信。  
- **送信される情報:**  
  - ユーザー名 (`sAMAccountName` や `UPN` など)  
  - パスワード  
- **通信方式:** `LDAP` または `LDAPS (SSL/TLS)`

**[4] ADが認証情報を照合し、結果をシステムに返す**  
- **認証成功（OK）:**  
  - ユーザーがADに登録されており、正しいパスワードを入力した場合、ADは **成功レスポンス** を返す。  
- **認証失敗（NG）:**  
  - IDが存在しない、またはパスワードが誤っている場合、ADは **認証失敗レスポンス** を返す。

**[5] セッションを作成し、ユーザーをダッシュボードにリダイレクト**  
- 認証が成功すると、システムは **セッションを作成** し、ユーザーを **勤怠管理のダッシュボード (`/dashboard`)** にリダイレクト。  
- **セッション情報:**  
  - ユーザーID  
  - 権限情報  
  - ログイン時間  

**[6] システムがユーザーの権限情報を取得**  
- システムは **Active Directoryのユーザーグループ情報 (`memberOf` 属性) を取得** し、ユーザーの権限を判定。  
- **例:**  
  - `CN=Employees,OU=Groups,DC=example,DC=com` → **従業員**  
  - `CN=Admins,OU=Groups,DC=example,DC=com` → **管理者**  

**[7] ユーザー権限に応じた機能・データを表示**  
- **(a) 従業員の場合:**  
  - 勤怠打刻（出勤・退勤）  
  - 勤務時間の確認  
  - 有給休暇の申請  
- **(b) 管理者の場合:**  
  - 従業員の勤怠データ管理  
  - シフト作成・編集  
  - 有給休暇や勤務時間の承認  

---

### **認証失敗時のフロー**

**[NG] エラーメッセージの表示**  
- 認証失敗時は **エラーメッセージを表示** し、ログイン画面に留まる。  
- **例:** `IDまたはパスワードが違います。再度入力してください。`

**セキュリティ対策**  
- **過度なエラーメッセージを防ぐ**  
  - 「IDが違う」「パスワードが間違っている」などの詳細情報を表示しない。  
- **一定回数以上の失敗でアカウントロック**（AD側で設定）  
  - 例: **5回失敗で一時ロック、管理者解除が必要**

## まとめ

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

:::note warn
本記事は、現時点での私の考えを整理したものですが、今後さらに **技術スタックや設計方針をブラッシュアップ** していきたいと考えています。
:::

引き続き、同様のテーマについてまとめていく予定ですので、今後ともよろしくお願いいたします！
C#でIoTプログラミング on ESP32 #1 - Lチカ

[前回の記事](https://qiita.com/linyixian/items/912cfca9e76b7c9bc287)でESP32S3にC＃プログラミングができる環境を準備しました。
今回から実際のプログラミングを行っていきたいと思います。

最初はやはりLチカからやってみましょう。オンボード上のLEDを点灯させてみましょう。

## ハードウェア
・Freenove ESP32-S3-WROOM Board or Espressif ESP32-S3-DevKitC

## プログラミング
・VisualStudio2022を起動して新しいプロジェクトを開いてください。プロジェクトテンプレートは「Blank Application(.NET nanoFramework)」を選択しましょう。

・次にLEDのコントロールに必要なパッケージをインストールします。メニューの「ツール」>「NuGetパッケージマネジャー」>「ソリューションのNuGetパッケージの管理」を選択し、ソリューションのパッケージの管理を開きます。

![esp32s3-1-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/710bdeca-9354-54ce-cc90-453430a81fcf.png)

・左上の参照タブをクリックし、検索ボックスに「gpio」と入力します。下に表示されたリストの中から「nanoFramework.System.Device.Gpio」を選択します。右側のプロジェクト名にチェックを入れ、インストールをクリックするとパッケージのインストールが始まります。
![esp32s3-1-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/0286bfa0-8d1d-7001-3fbe-82e920f5c3f1.png)

・パッケージの依存関係をチェックしてインストールするパッケージのリストが表示されます。「適用」をクリックしてインストールを完了させます。「readme.txt」と「ソリューションのパッケージの管理」は必要ないので閉じておきましょう。
![esp32s3-1-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62606/00a849b0-f068-134c-392d-9bfda0ec8c13.png)

・Program.csは次のようになります。namespaceはプロジェクト名に置き換えてください。

``` C#:Program.cs
using System.Device.Gpio;   //GPIOを使うためのパッケージ
using System.Threading;

namespace ESP32S3_Blink
{
    public class Program
    {
        private static GpioController controller;

        public static void Main()
        {
            GpioController controller = new GpioController();

            //GPIO2を出力モードで使用する
            GpioPin led = controller.OpenPin(2, PinMode.Output);

            //一旦出力をOFFにする
            led.Write(PinValue.Low);

            while (true)
            {
                //出力をONにする
                led.Write(PinValue.High);
                //1秒停止
                Thread.Sleep(1000);
                //出力をOFFにする
                led.Write(PinValue.Low);
                Thread.Sleep(1000);
                //Toggleを使うとONとOFFを切り替えることができる
                led.Toggle();
                Thread.Sleep(1000);
                led.Toggle();
                Thread.Sleep(1000);
            }
        }
    }
}
```

・デバッグの開始をクリックしましょう。しばらくしてボード上のLEDが点滅を始めます。

・プログラムの内容はコメントを読んでいただければ理解できると思います。

いかがでしょうか？プログラムの内容は他の言語とほとんど違いはないと思います。また、今までマイコンのプログラミングをしたことがない人でもプログラムそのものは通常のコンソールアプリケーションとほぼ一緒ですので理解しやすいと思います。

[ソースコード一式](https://github.com/linyixian/ESP32S3_Blink)はGitHub上にも上げています。

次回はオンボード上のRGB LEDを使ってみたいと思います。
【合格体験記】AWS Certified DevOps Engineer - Professional(DOP)

## はじめに
今回、AWS Certified DevOps Engineer - Professional試験に合格することができましたので、その体験を共有したいと思います。

この記事では、試験の準備方法、勉強スケジュール、使用したリソース、試験当日の感想、そして合格後に感じたことなどについて詳しくお話ししたいと思います。この体験記が、同じようにDevOpsエンジニアを目指す方の励みになり、試験合格への道のりの一助となれば幸いです。

では、早速私のAWS Certified DevOps Engineer - Professionalへの道のりをお伝えしていきます

## AWS Certified DevOps Engineer - Professionalとは
Amazon Web Services（AWS）が提供する認定資格の一つで、DevOpsの実践に特化した上級レベルの資格です。

※以下、公式より抜粋
> AWS 認定 DevOps エンジニア - プロフェッショナルは、AWS プラットフォーム上の分散アプリケーションシステムのプロビジョニング、運用、管理に関する技術的専門知識を示し、仲間や関係者、お客様からの信頼と信用を強化するものです。これらの適格なプロフェッショナルがいる組織は、安全でコンプライアンスに準拠した、高い可用性とスケーラビリティを持つシステムを迅速に提供することができます。

|  |  |
|:-:|:-:|
| カテゴリ  | 専門知識  |
|  試験時間 | 180分  |
|  コスト | 300USD  |
|  形式 | 75個の質問(複数選択または複数応答のいずれか)  |

## 学習期間
今回は約2か月間準備期間として設けました。
個人差はあると思いますが、筆者にとってはProfessionalレベルの試験の準備期間として適切だったと思います。

## 学習方法
#### AWS Skill Builderの練習問題
[AWS Certified DevOps Engineer - Professional Official Practice Question Set (DOP-C02 - 日本語)](https://explore.skillbuilder.aws/learn/courses/14541/aws-certified-devops-engineer-professional-official-practice-question-set-dop-c02-ri-ben-yu/lessons/68355/aws-certified-devops-engineer-professional-official-practice-question-set-dop-c02-japanese)

まずは、無料で提供されている問題集を解いてみます。
試験問題や回答の選択肢の文章量に慣れるのがメインだと思って下さい。
本試験では似たような問題は一切出ないくらいの心づもりでいた方が良いと思います。

ちなみに、、
Skill Builderの[有料サブスクリプション](https://aws.amazon.com/jp/builders-flash/202307/aws-skill-builder-subscription/)専用の模擬試験はかなり参考になるみたいです。
契約している方はそちらを活用するのがベターです。

#### Udemyの演習問題
今回は以下の講座を利用させていただきました。
他の講座に比べて問題数が多いのが、購入した決めてです。
[【DOP-C02対応 2024年版】AWS認定 DevOpsエンジニア プロフェッショナル 問題集【2回+α 205問】](https://www.udemy.com/course/dop-c02-2024aws-devops/?couponCode=ST5MT020225BROW)

#### AWSサービス別資料集を活用
演習問題で出題された各種サービスを理解するために、公式の資料集を使いました。
存在自体は知ってたのですが、演習問題をひたすら解いた方が合格への近道と信じていました。
が、、やはりサービスの概要やユースケースをある程度知ってないと正答率に大きく影響する事が経験して分かりましたので、ご存じないサービスは資料集でインプットしておく事をおススメします。

https://aws.amazon.com/jp/events/aws-event-resource/archive/?cards.sort-by=item.additionalFields.SortDate&cards.sort-order=desc&awsf.tech-category=*all

#### DeveloperIOのAWS再入門記事を眺める
AWSの各種サービスを丁寧に分かりやすく纏めてくれている記事です。
演習問題で出てきたサービスで対象の記事が存在する場合は、是非確認してみて下さい。

https://dev.classmethod.jp/referencecat/aws-re-introduction-2024/1/

## 試験当日
見直しの時間が全然足りませんでした。
180分もあるから、余裕で足りると受験前は高を括っていましたが
1周目の回答に時間をかけすぎてしまいました。
効率よく見直しを進めるためにも、自身無い問題にはマークをつけておく事を強く推奨します。

## 受験結果
点数：803点/1000点
結果：合格

あまり自信はありませんでしたが、無事に合格できました。
見たことない内容の問題も多かったですが、
BlackBeltやDeveloperIOの記事が、選択肢に迷ったときの道しるべとして大いに役立ちました。

## 個人的に要チェックだと思ったサービス
- AWS Service Catalog
    - CloudFormation StackSetsとの違いや使い分け
- Amazon GuardDuty
    - GuardDutyで検知できる事、Inspectorとの違い
- AWS Lambda
    - Lambda使わないと実現できない事と他サービスでも実現できる事を理解しておく
- AWS Config
    - SCPや他アカウントへのアクセス権限
- Amazon EventBridge
    - EventBridgeとトリガーにしないといけない場合と、使わなくても良い場合を把握しておく
- Amazon Route 53
    - フェイルオーバールーティング
- AWS CodeBuild
    - 初歩的なブランチ戦略
- AWS CodePipeline
    - 自前で構築したパイプラインをマネージドサービスに置き換えるには？
- AWS CodeDeploy
    - ブルーグリーンデプロイ
    - カナリアデプロイメント

## 最後に
問題の難易度は勿論高かったですが、問題と回答の選択肢を理解し
正しい回答に行き着く事が出来ていると実感できる場面もありました。
資格試験を通じて着実にAWSへの知見が溜まっていっている証拠です。
これで、全冠まで残り5つとなりました。
来年度には達成したいですが、準備不足による不合格は避けたいところです。
豊島茂樹Tips：AIを駆使することでエンジニア不足を解消できる

## はじめに  
近年、エンジニア不足が深刻化しており、多くの企業がIT人材の確保に苦労しています。特に、AIやデータサイエンスの分野では高度なスキルを持つエンジニアの需要が急増しており、人材不足がビジネスの成長を阻害する要因となっています。しかし、皮肉にもその解決策の一つがAIの活用にあります。本記事では、AIを駆使することでどのようにエンジニア不足を解消できるのかを解説します。  

## エンジニア不足の現状  
### **1. 需要の急増**  
- DX（デジタルトランスフォーメーション）推進により、エンジニアの需要が拡大  
- AI、クラウド、IoTなど新技術への対応が求められる  

### **2. 人材供給の不足**  
- 高度なスキルを持つエンジニアの育成には時間がかかる  
- IT人材の高齢化と若手不足が進行  

## AIによるエンジニア不足の解消策  
### **1. 自動コード生成による開発の効率化**  
近年、AIによるコード生成ツールが登場し、エンジニアの負担を大幅に軽減しています。  
- **GitHub Copilot**: コードの補完や提案を行い、開発スピードを向上  
- **ChatGPTやBard**: プログラムのアルゴリズムやバグ修正のサポート  
- **AutoML**: AIモデルの開発を自動化し、専門知識がなくても高度な分析が可能  

### **2. テスト・デバッグの自動化**  
ソフトウェア開発では、テストやデバッグに多くの時間が費やされます。AIを活用することで、以下のような効率化が可能です。  
- **AIテストツール（例: Applitools）**: UIテストを自動化し、人的ミスを削減  
- **異常検知AI**: ログデータを解析し、バグやシステム異常を事前に検知  

### **3. ノーコード・ローコード開発の活用**  
従来、エンジニアが手作業で行っていた開発プロセスも、ノーコード・ローコードツールの発展により、非エンジニアでもシステムを構築できるようになりました。  
- **代表的なツール**  
  - **Bubble**: Webアプリ開発をドラッグ＆ドロップで実現  
  - **OutSystems**: エンタープライズ向けのローコード開発プラットフォーム  
  - **Power Automate**: 業務プロセスを自動化し、IT部門の負担を軽減  

### **4. AIによる教育・育成支援**  
エンジニア不足を解消するには、新しい人材の育成が不可欠です。AIを活用した教育ツールが増えたことで、初心者でも効率的に学習できる環境が整ってきています。  
- **AI講師（例: Coursera、Udemy、Codeacademy）**: 個々の学習進捗に応じたカリキュラムを提供  
- **インタラクティブなAIチューター**: コードのリアルタイム解析やヒントの提示  

## AI活用の課題と今後の展望  
### **1. AIに依存しすぎるリスク**  
AIの活用が進む一方で、過度に依存することにはリスクも伴います。特に、AIが生成したコードの品質やセキュリティに関する問題は慎重に対応する必要があります。  

### **2. 人間の役割の変化**  
AIがルーチンワークを担うことで、エンジニアにはより創造的な業務や戦略的な思考が求められるようになります。今後のエンジニアは、単なるコーディングスキルだけでなく、AIを適切に活用する能力が必要不可欠となるでしょう。  

## おわりに  
AIの発展により、エンジニア不足は解消の方向へと向かいつつあります。自動コード生成、テストの自動化、ノーコードツールの活用、AIによる教育支援など、多くの技術がエンジニアの負担を軽減しています。  

しかし、AIがどれだけ進化しても、人間の創造性や問題解決能力は不可欠です。エンジニアとしての役割は変化していきますが、AIを上手に活用しながら、より高度なスキルを身につけることが、これからの時代を生き抜く鍵となるでしょう。
MQTT over WebSocket: Paho で接続

次のページを参考にしました。
[PythonでMQTT(Paho) - 2023](https://qiita.com/emqx_japan/items/d33acb84f525853f2a51)

こちらで立てたブローカーを使います。
[MQTT over WebSocket: localhost でのテスト](https://qiita.com/ekzemplaro/items/51c929024740de5e70f7)

## ライブラリーのインストール

```bash
sudo pacman -S python-paho-mqtt
```

## Publish

```py:pub_8083.py
#! /usr/bin/python

import random
import time

from paho.mqtt import client as mqtt_client

broker = 'localhost'
port = 8083
topic = "example/testTopic"

client_id = f'publish-{random.randint(0, 1000)}'

def connect_mqtt():
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT Broker!")
        else:
            print("Failed to connect, return code %d\n", rc)

    client = mqtt_client.Client(client_id)
    client.on_connect = on_connect
    client.connect(broker, port)
    return client

def publish(client):
    msg_count = 1
    while True:
        time.sleep(1)
        msg = f"messages: {msg_count}"
        result = client.publish(topic, msg)
        status = result[0]
        if status == 0:
            print(f"Send `{msg}` to topic `{topic}`")
        else:
            print(f"Failed to send message to topic {topic}")
        msg_count += 1
        if msg_count > 5:
            break

def run():
    client = connect_mqtt()
    client.loop_start()
    publish(client)
    client.loop_stop()

if __name__ == '__main__':
    run()
#
```

## Subscribe

```py:sub_8083.py
#! /usr/bin/python

import random
from paho.mqtt import client as mqtt_client

broker = 'localhost'
port = 8083
topic = "example/testTopic"

client_id = f'subscribe-{random.randint(0, 100)}'

def connect_mqtt() -> mqtt_client:
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT Broker!")
        else:
            print("Failed to connect, return code %d\n", rc)

    client = mqtt_client.Client(client_id)
    client.on_connect = on_connect
    client.connect(broker, port)
    return client

def subscribe(client: mqtt_client):
    def on_message(client, userdata, msg):
        print(f"Received `{msg.payload.decode()}` from `{msg.topic}` topic")

    client.subscribe(topic)
    client.on_message = on_message

def run():
    client = connect_mqtt()
    subscribe(client)
    client.loop_forever()

if __name__ == '__main__':
    run()
#
```

## 確認したバージョン

```text
$ python --version
Python 3.13.1
```
Node.jsでサクッと天気アプリを作ってみた！

## Node.jsでサクッと天気アプリを作ってみた！

こんにちは！最近Node.jsの勉強をしている私ですが、今回は **「簡単な天気アプリ」** を作ってみました！

「APIを叩くってよく聞くけど、実際どうやるの？」という疑問を持っている方に向けて、
**リクエストを投げてデータを取得する流れ** を分かりやすく解説します！

---

### 🌦️ どんなアプリ？

- コマンドラインで都市名を入力すると、その場所の気温を教えてくれる！
- OpenWeatherMap APIを利用して、リアルタイムの天気情報を取得！
- Node.jsの `request` モジュールを使ってAPIにアクセス！

---

### 🛠 必要なもの

- Node.js（インストール済みであること）
- OpenWeatherMapのAPIキー（無料で取得できます）
- `dotenv` モジュール（環境変数を管理）
- `request` モジュール（APIリクエスト用）

---

### 📝 コードを書いてみる！

まず、必要なモジュールをインストールします。

```sh
npm init -y  # package.jsonを作成
npm install request dotenv  # 必要なライブラリをインストール
```

次に、`.env` ファイルを作成して、APIキーを設定します。

```
API_KEY=あなたのAPIキー
```

では、実際のコードを `weather.js` に書いていきます！

```javascript
const request = require("request");
const dotenv = require("dotenv").config();

const argv = process.argv[2];
// console.log(argv)

const options ={
    url : `https://api.openweathermap.org/data/2.5/weather?q=${argv}&units=metric&appid=${process.env.API_KEY}`,
    method:"GET",
    json: true,
};

request(options,(error,res,body)=>{
    if(error){
        console.log("エラーが発生しました",error);
        return;
    }
    if(body.cod !==200){
        console.error("そんな都市ないぞ！！");
        return;
    }

    console.log(`${argv}の気温は`+ body.main.temp+`度だぞ！`)
})

```

---

### 🚀 実行してみよう！

ターミナルで以下のコマンドを実行してみます。

```sh
node weather.js Tokyo
```

すると…

```
Tokyoの気温は15度だぞ！
```

みたいな感じで気温が表示されます！（※温度は実際のものと異なります）

---

### 🧐 解説

1. `process.argv[2]` でコマンドライン引数（都市名）を取得！
2. OpenWeatherMapのAPIにリクエストを送る！
3. `body.main.temp` から温度を取得！
4. 結果を `console.log` で出力！

シンプルだけど、APIを使う基本の流れが身につくのでオススメです💡

---

### 🎉 まとめ

- Node.jsで外部APIを叩いてデータを取得する方法を学んだ！
- `request` モジュールを使ってサクッとGETリクエストを送信！
- `.env` を使ってAPIキーを安全に管理！

「ちょっと試してみたい！」という方は、ぜひこのコードをコピペして遊んでみてください✨

では、また次の記事で！👋
AWS で「LB 経由」で「同一ホスト名」で SSH と HTTP/S にアクセスできるようにする

多分同じこと書いているエントリ多数だと思うが、自分メモ

## やりたいこと
インスタンスで立ち上がっている Git サーバーに、同一ホスト名で SSH も HTTPS アクセスもできるようにしたい

## ここに至る過程
CLB の時はリスナーに HTTP/S も TCP も設定できたので、単純に両方を書いて A/AAAA レコードにその CLB をエイリアスすれば良かった

しかし、NLB/ALB 世代になって、NLB は HTTP を解さず、ALB は HTTP/S 以外を受け付けなくなった
両方を1つのホスト名に割り当てることはできないので、何らか工夫する必要がある

なんでこんな事始めたかというと、大昔に作成した **CLB のセキュリティポリシーが TLS 1.3 とか受け付けない**ことに今更に気付いたから（周回遅れにも程がある）

## 結論
NLB の下に ALB を置けばいいじゃない

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556191/893c5705-68bc-d842-f77b-deceb35621f8.png)

簡単な話だった
※ ここでは SSH のポートを 10022 にしているが、当然どのポートでもいい

### 注意点
- ターゲットグループは HTTP と HTTPS で別々に作成する必要がある、ALB のターゲットポートが異なる為
- 通常、ALB からインスタンスの接続は HTTP で行うだろうからヘルスチェックも HTTP にすると思うが、NLB → ALB の HTTPS ポートのヘルスチェックは HTTPS に設定する必要がある
- ターゲットグループは dualstack に対応していない
- ALB のリクエスト元は NLB になるらしい。アクセス元に応じたセキュリティグループでのアクセス制御は NLB でやればよいが、X-Forwarded-For に影響するかも（未確認）
OPTIONS リクエスト（クロスオリジンプリフライト）

### 背景

最近、私は個人ブログサイトを開発しています。小規模なプログラムなので、バックエンドには Node.js と Express フレームワークを使用し、フロントエンドには Vue 3、データベースには SQLite を選びました。

まずはデータベースとバックエンドプログラムを書き終え、PostMan で API のテストを行い、すべて正常に動作しました。

デバッグを簡単にするため、バックエンドに GET リクエストを受け取るテスト API を作成し、フロントエンドのセットアップ後にバックエンドと接続してテストしましたが、問題なく動作しました。

その後、ログイン API の接続を試みましたが、POST リクエストがバックエンドに届かないという問題が発生しました。

原因を調べてみると、どうやらバックエンドの CORS 設定に問題があったようです。設定を修正した後、無事解決しました。

![image-20250204155324493.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/398965e1-ec9f-6e94-6c51-8a019ff22c39.png)
![image-20250204155336116.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/b17c756b-b814-fe15-841e-070b6ac6d1e6.png)


### さらに考えたこと

ところで、OPTIONS リクエストとは一体何なのでしょうか？もし設定を間違えた場合、なぜ GET テスト API は正常に動作するのでしょうか？

### 調べた結果得られた答え

#### 1. OPTIONS リクエストとは？

OPTIONS リクエストは、HTTP プロトコルの一つで、サーバーがサポートする HTTP メソッドを取得するために使用されます。

- OPTIONS リクエストはブラウザの挙動であり、クロスオリジン（CORS）リクエストが行われる際、ブラウザは予め OPTIONS リクエストを送信してサーバーが対応可能なメソッドを確認します。
- 一般的に、AJAX リクエストにのみ制限がかかり、`link`、`img`、`script`、`iframe` のようなリクエストには制限はありません。
- サーバー間でのクロスオリジンリクエストでは、OPTIONS リクエストは発生しません。
![image-20250204161901725.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/e2c40534-1c96-518c-da15-5cc8ac77cda4.png)


**OPTIONS リクエストの特徴:**

- リクエストボディはありません；
- レスポンスボディもありません；
- セキュア；
- 冪等性（同じリクエストを何度送っても結果が変わりません）；
- キャッシュできません；
- フォーム内で使用できません。

#### 2. シンプルリクエストと複雑リクエスト

CORS の予備チェックリクエスト（OPTIONS）を発生させないリクエストを「シンプルリクエスト」、予備チェックを発生させるリクエストを「複雑リクエスト」と呼びます。

**シンプルリクエスト：**

*（次のすべての条件を満たす場合）*

- リクエストメソッド： GET、HEAD、POST。

- 許可されたヘッダーのみ使用：`Accept`、`Accept-Language`、`Content-Language`、`Content-Type` など。

- `Content-Type` の値が次のいずれかの場合：`application/x-www-form-urlencoded`、`multipart/form-data`、`text/plain`。 

  ※例えば、POST リクエストで `Content-Type: application/json` やトークン系のヘッダーを使用すると、OPTIONS リクエストが発生します。

  ※フロントエンドで axios を使用して POST リクエストを送信する際、JavaScript オブジェクトを直接渡すと、axios は自動的にそれを JSON 文字列にシリアライズし、リクエストヘッダーの `Content-Type` を `application/json;charset=UTF-8` に設定します。（これも私のプログラムで問題が発生した理由です）

**複雑リクエスト：**

*（次のいずれかを満たす場合）*

- リクエストメソッド：PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH。
- シンプルリクエスト以外のヘッダーを設定した場合。
- `Content-Type` の値が次のいずれかに該当しない場合：`application/x-www-form-urlencoded`、`multipart/form-data`、`text/plain`。

#### 3. 特定のリクエストヘッダー、レスポンスヘッダー

**特定のリクエストヘッダー:**

- `Access-Control-Request-Method`: 実際のリクエストで使用するメソッド（例：`GET`、`POST`）をサーバーに通知。 例：`Access-Control-Request-Method: GET`
- `Access-Control-Request-Headers`: 実際のリクエストで送信するカスタムリクエストヘッダーをサーバーに通知。 例：`Access-Control-Request-Headers: token`

**特定のレスポンスヘッダー:**

- `Access-Control-Allow-Methods`: クライアントが使用できるメソッド。 例：`Access-Control-Allow-Methods: PUT`
- `Access-Control-Allow-Origin`: 許可されたオリジン。すべてのオリジンを許可するには `*` を設定。 例：`Access-Control-Allow-Origin: http://localhost:8080`
- `Access-Control-Allow-Headers`: 許可されたリクエストヘッダー。 例：`Access-Control-Allow-Headers: token, Origin`
- `Access-Control-Allow-Credentials`: クッキーを送信するかどうか。 例：`Access-Control-Allow-Credentials: true`
- `Access-Control-Max-Age`: 予備チェックリクエスト（OPTIONS）の結果をキャッシュする期間。 例：`Access-Control-Max-Age: 60`（1分以内は再度 OPTIONS リクエストが発生しない）

------

以上です。お読みいただきありがとうございました。
MQTT over WebSocket: localhost でのテスト

Arch Linux でテストしました。

参考ページ
[MQTT: localhost でのテスト](https://qiita.com/ekzemplaro/items/7da3f7306dd5bcbc0801)

## mosquitto の設定変更

```text:/etc/mosquitto/mosquitto.conf
listener 8083
allow_anonymous true
listener 8080
protocol websockets
```

再起動

```bash
sudo systemctl restart mosquitto
```

## Publish

```bash
BROKER="localhost"
#
echo $BROKER
message="Hello Mqtt "`date`
mosquitto_pub -d -t orz -m "${message}" \
    -h  $BROKER \
    --topic example/testTopic -p 8083
```

## Subscribe

```bash
BROKER="localhost"
#
mosquitto_sub -d -t orz -h $BROKER \
    --topic example/testTopic -p 8083
```

## mqtt コマンドライン　を使って接続

Publish

```bash
mqtt pub -t 'example/testTopic' -h 'localhost' -p 8083 -m 'Good Afternoon'
```

Subscribe

```bash
mqtt sub -t 'example/testTopic' -h 'localhost' -p 8083 -v
```
SnowflakeでJSONのNull値をSELECTする時はSTRIP_NULL_VALUEを付ける

JSONのNULL値を含む項目のSELECTについて調べました。
STRIP_NULL_VALUEをかませばいいようです。
STRIP_NULL_VALUEを付けた場合と付けない場合でどう違うの？ということを実験したメモです。

https://docs.snowflake.com/ja/sql-reference/functions/strip_null_value

この公式ドキュメントの例にあるSQLを使います。
```
--テーブル作成
CREATE OR REPLACE TABLE mytable
(
  SRC Variant
);

--データを２行追加
INSERT INTO mytable
  SELECT PARSE_JSON(column1)
  FROM VALUES
  ('{
  "a": "1",
  "b": "2",
  "c": null
  }')
  , ('{
  "a": "1",
  "b": "2",
  "c": "3"
  }');
```

![スクリーンショット 2025-02-04 155455.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487310/814e32bd-2ccf-fbb5-dd25-e563490e8a2b.png)
SnowsightのGUI上で見るデータプレビューだとこんな感じです。
cという項目に1行目：null、2行目："3"という値が入っています。

aとbはどうでもいいので、cだけに絞ってSELECTしてみます。

```
--普通にSELECT
SELECT src:c FROM mytable;
```
![スクリーンショット 2025-02-04 155927.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487310/c6535bfb-a312-f41d-278d-7f8c303a5e8f.png)

```
--STRIP_NULL_VALUEを付けてSELECT
SELECT STRIP_NULL_VALUE(src:c) FROM mytable;
```
![スクリーンショット 2025-02-04 155951.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487310/5528e3dd-ee7b-b1c6-2701-d456635351cc.png)
STRIP_NULL_VALUEを付けた方はnullの文字の色がうすい状態になってます。

ちょっとわかりづらいので、結果欄をコピーしてテキストエディタに貼り付けてみました。

```
--普通にSELECTの結果
SRC:C
null
"3"

--STRIP_NULL_VALUEを付けてSELECTの結果
STRIP_NULL_VALUE(SRC:C)

"3"
```
普通にSELECTした方はnullというテキストが入っていますが
STRIP_NULL_VALUE付きでSELECTした方はNull値になってることが確認できました。
MQTT: localhost でのテスト

Arch Linux でテストしました。

## サーバーの構築

インストール

```bash
sudo pacman -S mosquitto
```

バージョンの確認

```text
$ mosquitto -h
mosquitto version 2.0.20

mosquitto is an MQTT v5.0/v3.1.1/v3.1 broker.
```

サーバーの起動

```bash
sudo systemctl start mosquitto
```

## Publish

```bash:go_pub_mqtt.sh
BROKER="localhost"
#
echo $BROKER
message="Hello Mqtt "`date`
mosquitto_pub -d -t orz -m "${message}" \
    -h  $BROKER \
    --topic example/testTopic
```

実行結果

```text
$ ./go_pub_mqtt.sh 
localhost
Client null sending CONNECT
Client null received CONNACK (0)
Client null sending PUBLISH (d0, q0, r0, m1, 'example/testTopic', ... (53 bytes))
Client null sending DISCONNECT
```

## Subscribe

```bash:go_sub_mqtt.sh
BROKER="localhost"
#
mosquitto_sub -d -t orz -h $BROKER \
    --topic example/testTopic
```

実行結果

```text
$ ./go_sub_mqtt.sh 
Client null sending CONNECT
Client null received CONNACK (0)
Client null sending SUBSCRIBE (Mid: 1, Topic: orz, QoS: 0, Options: 0x00)
Client null sending SUBSCRIBE (Mid: 1, Topic: example/testTopic, QoS: 0, Options: 0x00)
Client null received SUBACK
Subscribed (mid: 1): 0, 0
Client null received PUBLISH (d0, q0, r0, m0, 'example/testTopic', ... (53 bytes))
Hello Mqtt 2025年  2月  4日 火曜日 16:05:35 JST
```
【初心者向け】Sourcetreeの初期設定（アカウントの接続）の方法をまとめてみた

Sourcetreeの初期設定（アカウントの接続）の方法をまとめてみました！



![01.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674173/fee1d46b-818a-32d1-e04a-d26d8447fe82.jpeg)


![02.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674173/e0db1bcc-5352-7e30-d1d4-2216fc87b503.jpeg)


![03.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674173/cf9135fd-8960-8936-184f-e055804158e6.jpeg)


![04.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674173/68b62ca0-e6c7-28fa-d5f5-c5893209f6e8.jpeg)


SSH鍵については、以下のブログを参考にさせて頂きました。

https://0forest.com/github-sourcetree-ssh/#index_id3

https://qiita.com/shizuma/items/2b2f873a0034839e47ce


![05.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674173/638cf7df-7583-f0ce-287b-38d403ca449d.jpeg)




![06.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674173/a76bfeda-8c63-4f21-cc1f-2ebf9ad1cad1.jpeg)


![07.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674173/2a4ebd9e-0aa3-b32e-09a9-c66a474486d4.jpeg)


私はこの一連の流れがなかなか分からず苦戦しましたが、
やっとSourcetreeが使えるようになりました！
NGINX - upstream sent invalid header: "\x20..." while reading response header from upstream

# Step 1.
I upgraded the NGINX version from 1.18 to 1.26.2 and then encountered an error.
```
upstream sent invalid header: "\x20..." while reading response header from upstream
```

# Step 2.
I checked the NGINX CHANGE LOG and found that version 1.21.1 had relevant modifications.
```
Changes with nginx 1.21.1                                        06 Jul 2021

    *) Change: now nginx always returns an error for the CONNECT method.

    *) Change: now nginx always returns an error if both "Content-Length"
       and "Transfer-Encoding" header lines are present in the request.

--> *) Change: now nginx always returns an error if spaces or control
       characters are used in the request line.

--> *) Change: now nginx always returns an error if spaces or control
       characters are used in a header name.

--> *) Change: now nginx always returns an error if spaces or control
       characters are used in the "Host" request header line.

    *) Change: optimization of configuration testing when using many
       listening sockets.

    *) Bugfix: nginx did not escape """, "<", ">", "\", "^", "`", "{", "|",
       and "}" characters when proxying with changed URI.

    *) Bugfix: SSL variables might be empty when used in logs; the bug had
       appeared in 1.19.5.

    *) Bugfix: keepalive connections with gRPC backends might not be closed
       after receiving a GOAWAY frame.

    *) Bugfix: reduced memory consumption for long-lived requests when
       proxying with more than 64 buffers.
```

# Step 3.
Then I used CURL to access the URL and found that the response header had errors.
```
johnny$ curl -I -k -L "https://10.10.223.223/service"
...
...
Strict-Transport-Security: max-age=31536000;       <---
        includeSubDomains                          <--- It should be one line.
...
...
```

# REFERENCE
https://nginx.org/en/CHANGES

https://github.com/openresty/openresty/issues/833

https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Headers/Strict-Transport-Security

https://blog.csdn.net/KaiKaiWaWa/article/details/135279155

https://github.com/nginx/nginx/commit/9ab4d368af63e9c4a0bebc0eda82d668adaa560a

https://www.cjkuo.net/centos-8-nginx-1-18/
FirebaseAuthenticationでidTokenを取得する方法

## 前提

- プロジェクトは事前に作成済み
- APIキーも `サイドバーの⚙️ > プロジェクトの設定 > 全般 > ウェブ API キー` から取得済み

## 取得方法

#### アカウント未作成の場合

```shell
curl -X POST \
  'https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[YOUR_API_KEY]' \
  -H 'Content-Type: application/json' \
  -d '{
    "email": "user@example.com",
    "password": "your-password",
    "returnSecureToken": true
  }'

# response
{
  "kind": "identitytoolkit#SignupNewUserResponse",
  "idToken": "*****",
  "email": "user@example.com",
  "refreshToken": "*****",
  "expiresIn": "3600",
  "localId": "*****"
}
```

#### アカウント作成済みの場合

```shell
curl -X POST \
  'https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=[YOUR_API_KEY]' \
  -H 'Content-Type: application/json' \
  -d '{
    "email": "user@example.com",
    "password": "your-password",
    "returnSecureToken": true
  }'

# response
{
  "kind": "identitytoolkit#VerifyPasswordResponse",
  "localId": "*****",
  "email": "user@example.com",
  "displayName": "",
  "idToken": "*****",
  "registered": true,
  "refreshToken": "*****",
  "expiresIn": "3600"
}

```