OmniAICreator/Qiita-1.07M huggingface dataset:
新卒エンジニアが今年を振り返ります

新卒エンジニアです。Railsを中心に開発してます。
年末が近くキリを付けたいので今年を振り返ります。

## 学び・成長

### 仮説を持つ
ここではコーディングの文脈での仮説として書いています。不具合に遭遇したとき、がむしゃらに手を動かして試行錯誤するのが良い場合もありますが、頭の中で色々可能性を考えて仮説を立てると効率的に問題解決できている気がします。わかりやすくエラーが出てくれた場合はまだ良いですが、それが出ないまま意図しない動作をしている場合は特に仮説を立てることが重要だと感じています。情報量が少ない分、可能性が増えてしまうので仮説を立てて対応策を絞った方が良い気がしています。ただ、焦っている場合などは先に手が動いてしまうので、まだ意図的にやっているんだろうなと思います。なので今後も仮説を立てることに継続して取り組んでいき自然にできるようになっていきたいです。

### 技術イベントへの参加
今年はconnpassで開催されたイベントやKaigi on Railsのようなカンファレンスに参加しました。
正直、今の自分の知識レベルでは内容を理解しきれないセッションが多いです。ですが、自分のレベルを知ることができたり、技術に対する知的好奇心が刺激されるので参加できてよかったです。
それだけでなく、色々な会社のエンジニアと交流できることにも良さを感じています。様々な仕事の価値観に触れられたり、面白い文化を知れたりするからです。今年は自分と関わりの深いRailsに限定していましたが、来年はもう少し範囲を広げてみようと思います。

### 現実的な楽観性
自分は悲観的に考えてしまう傾向が強いので、初めて経験するタスクに取り組む場合、自分にできるのか毎度不安になります。ですが周囲のサポートもあり、実際にやってみると意外となんとかなったということ経験を多くしました。ここから現実逃避的な楽観性ではなくて、経験から得た現実的な楽観性が身についた気がします。経験によって強化された「なんとかなる」って感覚は自分の挑戦範囲を広げてくれそうなので良い傾向だと思います。（ただのマッチョイズムかもしれないです。）

## 課題感
### プロダクト知識・ドメイン知識不足
自分が携わるプロダクトの知識やドメイン知識が不足している感覚があります。社内で歴史の長いプロダクトということもあり、把握できていない領域がまだ多いです。また他のプロダクトと連携している場合もあるので、そちらについては全然知識が足りていないです。ドメイン知識も同様です。しかし、要件定義の段階ではそれらの知識が必要になってくるので、今の状態だと議論の途中から話の内容に理解が追いつかなくなることがあります。せっかく議論の場に参加できているのに、内容を理解できないまま終わってしまうのはもったいない気持ちが強く優先的に解決したい課題だと思っています。日々のタスクに取り組んだり、議論の中でキャッチアップして少しずつ解消されているので継続してキャッチアップしたいです。
また、先輩に相談や質問をする際に、自分なりの答えを持って臨んでいますが、これらの知識が不足している分野の話になると答えの質が低かったり、見当違いな考えを持っていることがありました。こういった問題も、知識の積み重ねで解決していくと思うのでやはり重要だなと思います。

### もっと上手くタスクを進めたい
ここでいう「上手く」とは、期待する結果まで真っ直ぐ進みたいという意味で書いています。タスク進める途中で修正が入り、ジグザクした進みになるのは仕方ないことだとは思います。しかし、その角度が大きくなるのは、修正するたびに負担が大きいですし、無駄も多く発生するため、できるだけ避けたいなと思っています。
これまではタスクに取り組む中で修正が必要そうだと思うタイミングで相談していました。しかし、実はもっと早い段階で修正すべき兆候があった、ということがありました。やはり自分だけで判断せず複数の視点で見てもらうことがより重要だと感じました。なので自分のタイミングで相談することも重要ですが、自分では修正が必要な段階だと気づけず、発見が遅れる可能性があるので、定例会のような形で同期的に相談する時間を作るのも良いかもしれないと思いました。

## 来年の抱負
### 文章としてのアウトプットを増やす
技術的な情報を整理するアウトプットと日々の中で感じたことの言語化することの2つを頑張りたいです。前者では学んだことを他人に説明しようとする過程で技術の理解が深まると思います。後者は言語化能力が高い人はかっこいいと思っているのと自分の中のモヤモヤした感覚をはっきりさせるのは自分にとって気持ちが良いからです。しかし、今年はアウトプットが十分にできたと言える結果ではありませんでした。原因を考えてみると「アウトプット」の基準を高く設定してたからかもしれません。実際、ブログとして文章にまとめるレベルのことが自分の中の最低基準になっていました。なので当然自分の中のアウトプットのハードルを下げる必要があります。その手段として日々の分報、日報が重要だろうなと思います。初めの頃は継続できていたのですが、ここ最近はサボりがちの傾向にあります。なのでこれを機に初心を思い出して、再開したいです。そして分報、日報から抽出して日々のアウトプットを続けて、定期的にまとまった文章としてブログなどでアウトプット継続していきたいなと思っています。

## 振り返ってみて感じたこと
ここ最近は振り返りをする機会が少なくなってきているので、今回をきっかけに自分を見つめ直すことができました。先ほども書きましたが、これを機に小さく続けたいです。
また、技術、プロダクトが現在の興味の中心になっている気がしました。まだマネジメントへの興味は小さい感じがしています。今は２つのことに関することに取り組む楽しさが強いのでこれらに集中して能力を高めていきたいです。ただ、興味の範囲を固定化しすぎず柔軟に色々挑戦していきたいと考えています。
Javaで「文字列をパターンとマッチする部分で分割する」の動作を確認してみた

# 概要

Javaで「文字列をパターンとマッチする部分で分割する」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/start/regex/index30.html

# 実装

以下のファイルを作成しました。
```JSample30_1.java
import java.util.regex.*;

class JSample30_1{
  public static void main(String[] args){
    String regex  = "\\|";
    Pattern p = Pattern.compile(regex);

    String[] result = p.split("AA|BBB|CC|", -1);
    for (int i = 0 ; i < result.length; i++){
      System.out.println("[" + result[i] + "]");
    }

    System.out.println("-- --");

    result = p.split("AA|BBB|CC|", 0);
    for (int i = 0 ; i < result.length; i++){
      System.out.println("[" + result[i] + "]");
    }

    System.out.println("-- --");

    result = p.split("AA|BBB|CC|", 2);
    for (int i = 0 ; i < result.length; i++){
      System.out.println("[" + result[i] + "]");
    }
  }
}
```

以下のコマンドを実行しました。

```
$ java JSample30_1 
[AA]
[BBB]
[CC]
[]
-- --
[AA]
[BBB]
[CC]
-- --
[AA]
[BBB|CC|]
```

# まとめ

何かの役に立てばと。
Elixir で ArtNet パケットを Parse してみる

## はじめに
この記事は [Elixir Advent Calendar 2024](https://qiita.com/advent-calendar/2024/elixir) の 12/23 の記事です。


Unity(C#) で ArtNet を送受信する内容を[以前投稿](https://qiita.com/nasshu2916/items/94ce93caf9beecf09e90)し、[GitHub](https://github.com/nasshu2916/ArtNet-Unity) にライブラリとして公開していますが、今回は同様の ArtNet パケットの Parse を Elixir でやってみようと思います。

https://qiita.com/nasshu2916/items/94ce93caf9beecf09e90

## ArtNet とは

[以前書いた記事](https://qiita.com/nasshu2916/items/94ce93caf9beecf09e90)にも書いてますが、ArtNet とは舞台照明などの制御で使われているプロトコルの一つです。舞台照明の制御は RS-485 を基にした DMX512-A という規格で制御されているのが一般的です。
この DMX512-A は 1 本のケーブルで 512 チャンネルで、1チャンネルあたり 0~255(8bit) の値で制御することができます。
この DMX を Ethernet を介してやり取りできるようにしたものの一つが ArtNet です。

ArtNet は UDP 6454 番ポートが使われ、ArtNet の規格は以下のドキュメントに書かれています。

https://artisticlicence.com/WebSiteMaster/User%20Guides/art-net.pdf


ArtNet の 1~8 バイト目はそのパケットが ArtNet のパケットかどうかを識別するための場所で、`Art-Net\0` の固定値になっています。9~10 バイト目は OpCode(operation code) と呼ばれる値で、この値で ArtNet パケットの種類を識別します。

11 バイト目以降は OpCode によって内容が異なりますが、
OpCode が OpDmx(DMXパケット) の場合、11~12 バイト目はプロトコルバージョン、13 バイト目は シーケンス番号、15~16 バイト目には Universe 番号が入ります。

18 バイト目以降から DMX の値が順に入れられているのですが、16~17 バイト目には、18 バイト目以降の DMX の長さが格納されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3081963/544c7eba-1459-abbb-2772-3d9f91f1eb62.png)

## 実装

Elixir はバイナリに対してパターンマッチが可能です。

今回 OpCode が ArtDmx で、DMX のデータが 255 の値が 1 つだけが入ってる Universe 0 の ArtNet パケットを Parse してみます。

まずはじめに、ArtNet のパケットかどうかの判別は、パケットの先頭 8 バイト目が `Art-Net\0` になっているかどうかで判別できます。
Elixir ではパターンマッチを使って、以下の様な感じで行えます。

```elixir
packet = <<0x41, 0x72, 0x74, 0x2D, 0x4E, 0x65, 0x74, 0x00, 0x00, 0x50, 0x00, 0x0E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF>>
<<65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 1, 0, 0, 0, 0, 1, 255>>

case packet do
 "Art-Net\0" <> _ -> true
 _ -> false
end

結果: true
```

また、9~10 バイト目の OpCode(little endian) を文字列で以下のようにすることで取得できます。
今回は OpCode の値が分かりやすいように 16 進数の文字列に変換して返しています。

```elixir
case packet do
  "Art-Net\0" <> <<op_code::little-size(16)>> <> _rest -> {:ok, "0x" <> Integer.to_string(op_code, 16)}
  _ -> :error
end

結果: {:ok, "0x5000"}
```

11~12 バイト目はプロトコルバージョンは 14 の固定値なので、ArtDmx のパケットを Parse するには以下の様になります。

```elixir
case packet do
  <<
    "Art-Net\0"::binary,
    0x5000::little-size(16),
    14::size(16),
    sequence::size(8),
    physical::size(8),
    sub_universe::size(8),
    net::size(8),
    length::size(16),
    data::size(length)-bytes
  >> ->
    {:ok,
      %{
        sequence: sequence,
        physical: physical,
        sub_universe: sub_universe,
        net: net,
        length: length,
        data: (for <<byte::size(8) <- data>>, do: byte)
      }}

  _ ->
    :error
end

結果: {:ok,
  %{
    sequence: 0,
    physical: 0,
    sub_universe: 0,
    net: 0,
    length: 1,
    data: [255]
  }}
```

このように Elixir のパターンマッチを使うことで、ArtNet のパケットを簡単に Parse することができます。
パレート分析の話

## パレート分析とは
パレート分析を活用すると、問題を分類し、数値化することで、対策をすることで大きな効果が見込めるポイントを見つけることができます。軽めの工数で分析が完了するので、比較的扱いやすい方法です。

## パレート図の作り方
パレート図の作り方自体は、Excelでの動画なども豊富に公開されていますので、簡単にご紹介します。なお、パレート図を作るために、BTSなどで不具合が管理されており、不具合の記録が残っていることが、始めるにあたっての最低限の条件になります。

### 分類項目の作り方
分析項目は、製品の特性から考えて作るのがよいでしょう。たとえば、オンプレで運用している場合と、SaaSで運用している場合とでは、インフラなどで見るポイントが変わります。Webアプリのみを対象にする場合も、また問題の傾向が変わってきます。ですので、自社製品の特長や、洗い出したい課題などを挙げるとよいでしょう。

参考までに、私がつかっている指標としては、以下のものになります。
    1. Function (機能)　
    2. Spec (仕様)
    3. Privacy Breaches (プライバシー違反)
    4. Performance
    5. Combination (組み合わせ)
    6. Temporal Issues (時間的問題)
    7. Data (データ)
    8. Environment (環境)
    9. External Factors (外部要因)
    10. Cosmetics (見た目)


実際に振り分けを行う際には、分類の判断には一定の熟練度が求められます。また、開発に深く関与しているメンバーが担当することで、本当の原因を把握しやすくなり、正確な状況を反映できるでしょう。

[[パレート図の書き方　（引用）なるほど統計学園]](https://www.stat.go.jp/naruhodo/9_graph/jyokyu/pareto.html)


### グラフの書き方

では、分析に使うパレート図の作り方です。
パレート図は、棒グラフと折れ線グラフを使います。

#### 棒グラフの書き方
左側に、一番問題の多い棒をもってきて、右に行くにしたがって少ない問題を順番に並べます。

#### 折れ線グラフ（積み上げグラフ）の書き方
これは、棒グラフを積み上げた数字を書いていきます。最後は、不具合の全数になります。



分類が終わって、件数を数字にし、グラフを書くと、この形になります。


## パレート図で何がわかるか
こうしてできたパレート図をつかって、分析を進めていきます。

私の経験からいうと、概ねの企業で、３割ほどが上流工程の問題、４割～６割が組み合わせの問題、残りはそれ以外で、経営戦略に関わるものだったり、単純な実装ミスだったりです。面白いのが、同じ会社においては、違う部署であってもこの割合がだいたい同じになる傾向があります。会社の文化が品質に影響を与えている例でしょうか。

もちろん、この上流の問題は、単純にエンジニアリングだけの問題ではなく、複合的な要因があることが多いので（予算がなくて適切な設備が買えない、など）、深堀する際には、魚の骨を使ったり、プロセス改善を行うなど、次の手を打つ必要があります。

ここで注意が必要なのは、単純に製品や環境が違う場合、数字だけを比べても分析はできない、という点です。なぜなら、「テストは条件しだい」とも言われるように、製品の開発難易度やエンジニアの習熟度、リソース、いろいろな要素がプロジェクト開発には絡んでくるものであり、一様ではないからです。最低限、同じ指標を使って、一定の傾向を分析していくことになります。このため、私が行う場合は、単純に数字だけを見るのではなく、問題全数に対する割合も、参考にしています。


## パレート分析の頻度
パレート分析の頻度は、３か月から半年ぐらいがよいでしょう。また、問題に対策することで数字の割合が減ったら、（問題が減ったと実感できたら）分類項目を見直しすることも必要になってくるでしょう。


## まとめ
パレート分析は、開発体制の、「健康診断」とも言えます。なかなか品質を数字化するのは難しいですが、これは数字化できるのと、傾向が量で見られるので説明がしやすいです。また、分析に多大な時間を要しないため、軽く始めやすいのも特徴です。


#
### 用語解説

#### BTS
よく、アーティストと間違われやすいのですが、「バグ・トラッキング・システム」の略で、不具合を登録し、修正状況などが追跡できるようになったものです。

#### 魚の骨
イシカワダイアグラム、フィッシュボーンチャートなど、いろいろな呼び方がありますが、魚の形のモデリングをすることで、因果関係を明白にしたり、作りたいもののゴールシークなどを行ったりします。
Code for Fukuoka 2024年の振りかえり

# 1月
## TownTech教育
2023年度も実施となったTownTech教育を前年11月から実施しており、1月が最後のWebサイトまとめ〜最終成果発表となりました。最終成果発表は5年生に向けた発表となり、5年生からはたくさんの質問も出て来年度は対象となる学年であるだけに良い機会となりました。
### TownTech教育概要
TownTech教育は以下の二つを目的として、４つのステップで進める地域探求学習です。
#### 目的
・自分たちの住んでいるまちのことを知りまちを誇りに思う気持ちを育てること
・調べた結果をWebサイトにまとめる過程で相手に伝わるようにまとめることやWeb上に記載する際の注意点、正しい情報の判断などを身につけること
#### STEP
1. 見る・知る：フィールドワークでお話を聞いたり実物を見て回る
2. 調べる：本やWebで調べる→リファレンスサービスを知る・使う
3. まとめる：紙と言う範囲の限られたものに調べた内容をまとめる
4. 発信する：Webサイトに調べた内容をまとめる→情報モラル教育も合わせて行うことでWeb上のものの著作権などを気にして、情報の取り扱いを知る

# 2月
## TownTech教育
TownTech教育のふりかえりと今後に向けた方針について検討しました。

# 3月
InternationalOpenDataDay
各地で行われていたオープンデータリブート会議をCode for Fukuokaでも実施してみました。テーマはビジネス事例、民間オープンデータ。今現在、オープンデータを使ったビジネス事例や民間から出ているオープンデータがどれくらいあるのかをみんなで調べて共有しました。

そしてTownTech教育の対応で一時休会としていた隔週オンライン定例MTGを再開しました。

新たなTownTech教育候補小学校に内容の説明に行きました。

# 4月
元寇防塁AR体験授業の福岡市ご担当が変わったので挨拶、また今年の内容について協議しました。

TownTech教育を本年度もお願いしたいとの連絡を小学校から受け、お打ち合わせを実施しました。
今年度は１学期のうちに２か所、２学期に２か所として進めることになりました。

引き続き隔週オンライン定例MTGで今年度の活動など検討しました。

# 5月
メンバーで久しぶりに飲み会をしました。
自衛隊幹部候補生学校を訪問しました。

引き続き隔週オンライン定例MTGを実施しました。

# 6月
引き続き隔週オンライン定例MTGを実施しました。
## UDC2024
アーバンデータチャレンジ２０２４(UDC2024)は今年も福岡拠点として参加申込しました。
今年のテーマは給食献立アプリです。
福岡市博物館の職員さんと意見交換しました。
## TownTech教育
TownTech教育の校外見学が始まりました。語り部を継がれた方から地域のことを聞きながら周りました。

# 7月
引き続き隔週オンライン定例MTGを実施しました。
## UDC2024
キックオフシンポジウムに東大駒場キャンパスまで行きました。
アーバンデータチャレンジ２０２４(UDC2024)の取り組みとして、生駒メンバーと協議しました。
UDC2024にBODIK賞ができたことを受け、CodeforKyushuイベントとしてBODIKオープンデータを活用する際のAPIの使い方など紹介するイベントを実施しました。
## TownTech教育
TownTech教育の校外見学２か所目。
公民館の方から地域のことを聞きながら周りました。
今後のイベント場所としてNPOセンターあすみんへ登録しました。
西日本新聞社と協議しました。
# 8月
引き続き隔週オンライン定例MTGを実施しました。
## UDC2024
子育て市民の声を聞くためのイベントとして夏休みに子どもを対象としたワークショップを福岡市植物園内ボタニカルライフスクエアで開催しました。自分も子育て中だからこそ、忙しい親からヒアリングするには、時間を取ってくれるには、と子ども向けの数学ワークショップにし、その後半のワーク中に実施しました。結構色々な意見をもらえました。
# 9月
引き続き隔週オンライン定例MTGを実施しました。
## TownTech教育
今年度のTownTech教育の流れを決めました。
# 10月
引き続き隔週オンライン定例MTGを実施しました。
## TownTech教育
リファレンスサービスを体験するよう福岡市総合図書館へ行きました。
# 11月
引き続き隔週オンライン定例MTGを実施しました。
## TownTech教育
### 情報モラル教育
TownTech教育の関連授業としての情報モラル教育の授業を実施しました。
著作権や利用規約の話はとっても難しくて全てを理解することは難しいですが、子どもたちが当たり前に触れることのあるWebコンテンツには利用するためのルールがあるということだけはしっかり伝わりました。使える＝使ってよいではないことに気づいてもらった回でした。
## 元寇防塁AR体験授業
元寇防塁のAR体験授業を今年も実施しました。海岸でのAR体験後、掃除して出てきた元寇防塁を3Dスキャンしてスキャニングを体験しました。
## UDC2024
生駒メンバーと打ち合わせしChatGPTsの勉強会イベント開催を決めました。
# 12月
## TownTech教育
お寺へフィールドワークに行き、和尚さんのお話を聞きました。
今年度初めて蒙古山へ行きました。地元の自治会長の方から経緯などいろいろ教えていただきました。
## UDC2024
ChatGPTs勉強会を開催しました。今回作りたいアプリのイメージも含めてみんなで考えていけるところかと思います。

Code for Fukuoka再スタートからの7年目、振り返りました。
# 最後に
2022年度より実施した小学校との授業はもう3年目となりました。担当の先生が代わり、また今年は雰囲気が違いますが小学校や地域の方との信頼関係はできてきたように感じています。

やっぱり振り返りは良いですね。
今年は毎月何かしらの活動があったように思う1年でした。来年はもっと開発系の活動進めていけたらと思います。
bタグとstrongタグの違いってなに？

## はじめに
HTMLで文字を太字にする方法として、**bタグ**と**strongタグ**の2つがありますが、明確な使い分け方が分からなかったので調査してみました。

## bタグとstrongタグの基本的な違い
機能と意味の違いについて**bタグ**と**strongタグ**は、見た目上は同じように文字を太字にする効果がありますが、それぞれの役割が異なるようです。

- **bタグ**
    - 純粋にテキストを視覚的に目立たせることが目的で、特別な意味を持たない
    - 言葉に意味は無いが、目立たせたい時に利用する
- **strongタグ**
    - コンテンツの重要性や緊急性を示すために使用され、検索エンジンに対して指定したテキストが重要であることを伝える
    - 要素が「緊急」「重要」「深刻」「重大」である際に利用する
    - スクリーンリーダーが囲まれた文字を読み上げる際に強調して読み上げられることがある
        - macのVoiceOverを使ってみたが変わらなかった…

https://developer.mozilla.org/ja/docs/Web/HTML/Element/strong

## SEO観点での使い分け
**bタグ**と**strongタグ**にはSEOの効果に差はないようです。
2013年にGoogleのマット・カット氏が以下のようにコメントを残していました。
>Googleはstrongタグやbタグ、emタグ、iタグを同じように扱う。ランキングには影響を与えない

<iframe width="560" height="315" src="https://www.youtube.com/embed/awto_wCeOJ4?si=sFXHyzODWDESA63w" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

そのため、SEOの観点から使い分けをあまり意識する必要はなさそうでした。
しかし、strongタグを多用しすぎると検索エンジンからマイナス評価を受けることがあるようです。
そのため、重要なキーワードにのみ利用するようにした方が良さそうです。

https://tecchanblogs.com/wordpress-storong-tag/#strongSEO


## まとめ
**bタグ**と**strongタグ**それぞれの意味合いや使い分けの雰囲気は少し理解できたが、人の主観によって使い分けのラインは異なりそうだなと感じました。
ただ、自分が使う際には意図を持って使い分けを行なっていこうと思います。
包含ブロックとposition

## 包含ブロックとは
CSSにおける包含ブロックとは、要素の位置や大きさを計算する際に基準となるブロックのことです。
`width`や`height`が`%`によって指定されているときには、包含ブロックの大きさをもとに計算されます。
例えば、`width:50%`と指定されていて、その要素の包含ブロックの横幅が`400px`と指定されているときには、その要素の横幅は`200px`と計算されるといった具合です。

包含ブロックは、要素の直近のブロックレベルの祖先要素が該当することが多いですが、例外もあります。

https://developer.mozilla.org/ja/docs/Web/CSS/Containing_block

## 包含ブロックの決まり方
包含ブロックは、基本的には`position`（デフォルト値は`static`）の値によって決まります。
### `static`,`relative`,`sticky`
`static`,`relative`,`sticky`はどれも通常のフロー（Normal Flow）で配置される`position`値です。

https://www.w3.org/TR/CSS2/visuren.html#normal-flow

`position`が`static`,`relative`,`sticky`のいずれかのときには、**ブロックコンテナ**か**ブロック整形コンテキスト**(BFC)を形成する直近の祖先要素のパディングボックスの辺が包含ブロックとなります。

**ブロックコンテナ**には、`div`などのブロック要素やインラインブロック要素、テーブルのセル`th`、`td`やflex アイテム、grid アイテムが該当します。

**ブロック整形コンテキスト**(BFC)とは、**レイアウトを管理する独立した空間**のことです。
異なるBFC 同士ではマージンの相殺が起こらなかったり、float 要素とは重ならないなど、独立性をもっています。

BFC を生成する代表例には、以下のようなものがあります。
- `<html>`（root要素）
- `float`要素
- `position: fixed`、`position: sticky`が指定されている要素
- `display: inline-block` の要素
- overflow が visible 以外の値であるブロック要素
- テーブルのセル
- flex アイテム
- grid アイテム

上のような条件を満たす直近の祖先要素の（パディングボックスの）辺の長さや位置が`%`や`top`の基準になるわけですね。

### `fixed`
`positon:fixed`の場合、基本的にはビューポート（画面の表示領域）が包含ブロックとなります[^1]。

### `absolute`
`positon:absolute`の場合、`position:static`以外の直近の祖先要素のパディングボックスが包含ブロックとなります[^1]。

https://developer.mozilla.org/ja/docs/Web/CSS/CSS_flow_layout/Introduction_to_formatting_contexts

## `%`がうまくきかないとき
`width`や`height`で`%`値を指定しているのに大きさがかわらなかったり、想定とは異なる大きさになっているときには、その要素の包含ブロックがどの要素で、包含ブロックに幅が設定されているかを確認してみると原因が見つかるかもしれません。

以下の構造を考えてみます。
```html
<div class="block_div">
    <span class="inline_span">
        inline span
        <div class="div1">div1</div>
    </span>
    <div class="div2">div2</div>
</div>
```
```css
.div1 {
  height: 40%;
  background-color: orange;
}
.div2 {
  height: 40%;
  background-color: red;
}
.block_div{
  height: 160px;
  background-color: yellow;
}
.inline_span{
  height: 40px;
  background-color: green;
}
```
![bfc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806599/f266074c-d6ff-691d-af2e-898d11aeb2fc.png)

このHTML では、`div1`の親要素が`span`要素となっています。

しかし、`div1`の高さは`span`の高さの`40%`にあたる`16px`ではなく、`div2`と同じ`64px`となります。
これは、`div1`の包含ブロックが`span`ではなく、`<div class="block_div">`となるためで、`%`の基準が`span`の高さ`40px`ではなく、`<div class="block_div">`の高さ`160px`になるためです。

計算の基準となっている包含ブロックを見つけ、`%`指定を使いこなしていきたいですね。

[^1]:`position:fixed`や`position:absolute`が指定されている要素については、`transform`、`perspective`、`will-change`、`filter`、`contain` などが指定された祖先要素があるときにはその要素が包含ブロックとなることがあります。
FlutterでFirebase実装

## はじめに
今回は、アプリ制作の過程でリモートデータベースを使用したいと思い、もともと気になっていたFirebaseの勉強をしようと思いました。
Firebaseでデータベースを作成し、Flutterでデータを取得するまでを記事にしようと思います。

## 環境
- M2 MacBook Air 14.6.1
- Flutter 3.24.3
## Firebaseの設定
https://firebase.google.com/?hl=ja

1. 上のFirebaseホームページにアクセスし、右上の`Go to console`をクリック
　
2. 「Firebaseプロジェクトを使ってみる」を押す
　
3. プロジェクト名を記入し、以下のチェックマークに印をつける。
　
![スクリーンショット 2024-12-19 23.40.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3669980/90598006-9031-35e3-8aab-9770426dce94.png)
　

4. 住んでいる国や諸々の情報を記入し、プロジェクトを作成します。
　
5. 黄色で囲んだボタンを押します。
　
![Untitled design.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3669980/be82883e-b1df-068a-45e2-5c9be1521959.png)
　
6. 画面の指示に従い、FlutterアプリにFirebaseを実装する。
　
7. pubspec.yamlに以下の依存関係を追加
```
dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.8

  //ここから追加
  firebase_core: ^3.8.1
  cloud_firestore: ^5.5.1
  //ここまで追加
```

## Firebaseでデータベースを作成する。

![名称未設定のデザイン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3669980/5eb87147-92ed-50e6-89e9-f31eb54814fc.png)

1. 左の`Firestore Database`を開きます。
　
2. 「データベースを作成」を押します。
    - 　本番環境ではなく、テスト環境を選ぶ

 　
3. 「コネクションを開始」を押し、以下の項目を入力する。(自分が入力したもの)
- コレクションID：posts
- ドキュメントID：自動生成
- フィールド：text
- 値：初めてのポスト


## 実際のコード

```
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';

void main() async{

  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  
  runApp(const MyApp());
}


    //firebaseからデータを取得する
    void _fetchFirebaseData() async{
    await FirebaseFirestore.instance.collection("posts").get().then((event) {
      for(var doc in event.docs) {
        print("${doc.id}=>${doc.data()}");
      }
    });
    }



    floatingActionButton: FloatingActionButton(
        onPressed: _fetchFirebaseData,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
    ),
```

## 解説
`WidgetsFlutterBinding.ensureInitialized();`
・runAppを呼び出す前に非同期処理をする際に使用する

　
 `options: DefaultFirebaseOptions.currentPlatform,`
 ・現在のプラットフォーム（iOS、Android、Webなど）に適したFirebase設定を提供します。これにより、プラットフォームごとに異なるFirebase設定を簡単に適用できます。
　
　
・`FirebaseFirestore.instance.collection("posts")`：Firestoreのインスタンスを取得し、posts コレクションを参照します。
・`.get()`：posts コレクション内のすべてのドキュメントを取得する非同期操作する。
・`.then((event)`：get() メソッドが完了した後に実行されるコールバック関数を指定します

　
`event.docs`：Firestoreから取得したドキュメントのリストです。
`doc.id`：現在のドキュメントのIDを取得
`doc.data()`：現在のドキュメントのデータを取得。Map形式で返される
　


## 実行
このプログラムを実行し以下のメッセージがターミナルで表示されれば成功です。
`I/flutter ( 6017): jsfRUGfHXgUiAADCndlR=>{text: 初めてのポスト}`
Module-LLMでCPU推論とNPU推論を比べてみた。


## 目的
Module-LLMが搭載しているaxera-techのax630cは、CPUに2-coreのCoretex-A53を搭載していることに加えて、3.2Tops @int8のNPUを搭載しています。Module-LLMで、PythonにてCPU推論とNPU推論を行ったときの速度を比べてみました。

## 結果
Module-LLMのresnetモデルで、onnxruntimeを使ったCPU推論とNPU推論の速さの違いのグラフを描いてみると以下のような結果となりました。CPU推論では、onnxruntimeの機能を使って、元のFloat32の推論のものと、INT8量子化を行った推論のものを掲載しています。


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Module-LLMで色々なクラス分類のモデルでonnxruntime(CPU)とpyaxengine(NPU)の速度を色々比べてみた。やはり、NPUは早い…30倍～100倍くらい早い感じだろうか。 <a href="https://t.co/Mk7i6nZ9X3">pic.twitter.com/Mk7i6nZ9X3</a></p>&mdash; nnn (@nnn112358) <a href="https://twitter.com/nnn112358/status/1868131856006447346?ref_src=twsrc%5Etfw">December 15, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 注意事項
　今回は、Pythonでの評価を行いましたが、PythonよりもC++を使った方が、推論は早くなることがわかっています。また、axengineもまだ実装が行われているため、今後、評価値が変化する可能性があります。
よって、この結果は、Module-LLMのベストエフォートを示すものではありません。

 https://github.com/nnn112358/ax_classification_python_vs_cpp


## ONNXモデルのエスクポートとAXモデルへの変換

UbuntuPCを使い、Pytorchのクラス分類のモデルから、ONNXモデルへのエスクポートを行いました。次に、onnxruntimeの機能を使って、INT8量子化を行いました。
更に、ONNXモデルにAxera-techのモデル変換ツールpulsar2を使って、Module-LLMのNPUが対応するAXモデルへの変換を行いました。

```
$ pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
$ cd model_conv
$ mkdir -p models
$ mkdir -p quantized_models
$ mkdir -p calibration_images
$ cd models
$ python classification_torch_model_export.py
$ cd ..
$ python onnx_quantize_static_image_batch.py
```


## Module-LLMでの実行
変換したモデルをModule-LLMにコピーし、Module-LLMのNPUをPythonで扱う開発環境である、axengineをインストールしました。
ONNXモデルからonnxrutimeでCPU推論を行い、AXモデルからaxengineでNPU推論を行いました。


```
root@m5stack-LLM:# wget https://github.com/AXERA-TECH/pyaxengine/releases/download/0.0.1rc3/axengine-0.0.1-py3-none-any.whl
root@m5stack-LLM:# pip install axengine-0.0.1-py3-none-any.whl
root@m5stack-LLM:# ./batch_run_onnx.sh
root@m5stack-LLM:# ./batch_run_axmodel.sh
```

axengineは、onnxrutimeと同じく、推論をsession.run()関数から呼び出すことができます。そのため、onnxrutimeからの移植が大変容易です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73020/3534a94f-b5d7-b974-2d8d-c1aee471d962.png)

実行した結果とソースコードは、以下のリポジトリに掲載しています。

https://github.com/nnn112358/ax-classification_benchmark/
Module-LLMでDepthAnythingを動かしてみる

## 目的
　Module-LLMでDepthAnythingのモデルを実行する手順を説明します。
　Module-LLMのNPUは、Transfomerモデルに対応しており、DepthAnythingの量子化モデルを動かすことができます。今回は、AxeraチップのPython環境である、pyaxengineを使用しました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Module-LLMのdepth anythingがPythonでも動くようになりました。<a href="https://twitter.com/hashtag/M5StackLLM?src=hash&amp;ref_src=twsrc%5Etfw">#M5StackLLM</a> <a href="https://t.co/f0xtwI7LdW">pic.twitter.com/f0xtwI7LdW</a></p>&mdash; nnn (@nnn112358) <a href="https://twitter.com/nnn112358/status/1865777711869985277?ref_src=twsrc%5Etfw">December 8, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## Install

Module-LLMにルートでログインし、pyaxengineをインストールします。
```
root@m5stack-LLM # wget https://github.com/AXERA-TECH/pyaxengine/releases/download/0.0.1rc1/axengine-0.0.1-py3-none-any.whl
root@m5stack-LLM # pip install axengine-0.0.1-py3-none-any.whl
```

更に、 fastapi opencv-python uvicornをインストールします。
```
root@m5stack-LLM # pip install fastapi opencv-python uvicorn
```


https://qiita.com/nnn112358/items/b284763de0d333dfdb73


USBカメラから画像を取得し、depth_anythingをかけた後、httpにストリーミングを行うサンプルです。
 Pythonが起動した後、 ブラウザ で　http://{Module-LLMのアドレス}:7777/video　にアクセスします。

```
root@m5stack-LLM:# python3 depth_anything_camera_stream.py
```

depth_anything_camera_stream.pyのソースコードはこちらをコピーしてください。
 
https://github.com/nnn112358/ax_pyaxengine_test/blob/main/depth_anything_camera_stream.py


depth_anythingのモデルは、こちらから入手します。

https://drive.google.com/drive/folders/11aRxsFqJfGXhFMlInudj3Bi8SR-08TXl



## 参考資料

ax-samples/Depth-Anything
https://github.com/AXERA-TECH/ax-samples/tree/main/examples/ax620e#Depth-Anything
Amazon Connect における日本の携帯電話「060」番号解放に関するメモ

ジャーニーマン( @beajourneyman )です。長いの"ジャニ"と呼ばれています。

こちらは [Amazon Connect Advent Calendar 2024](https://qiita.com/advent-calendar/2024/amazon-connect) の20日目の記事です。

> このアドベントカレンダーはクラスメソッド、ギークフィード、クラウドビルダーズ、ネットプロテクションズ、AWSJの有志が募ってチャレンジする企画となっています。

日付が空いていたのでお邪魔しましたが上記の通りですので、他社が入れない場合は離脱いたします。押しかけておいてお手数ですが、コメントで教えていただけますと幸いです。

今回は「060」番号の携帯電話利用開始に関して2024年12月中に解放されるスケジュールを受けて、今後の Amazon Connect での対応についてメモを残していく趣旨で執筆します。電話番号にまつわる知見はAWSの中でもユニークな位置付けなので、今回も言及したいと思います。これまでの記事は以下の通りです。

https://qiita.com/beajourneyman/items/d385bf9e139048630038

https://qiita.com/beajourneyman/items/57a662d3b164ea7cb481

https://qiita.com/beajourneyman/items/ca4df6e7ca4c241fc5b9

# 「060」番号の解放について

現在の「090」「080」「070」番号の枯渇により、「060」で始まる番号の解放が予定されています。記事内の"2日"は2024/10/02(水)となります。

> スマートフォンの普及などを背景に、先月末の時点で割り当てられる残りの番号は、「070」から始まる530万件となっていて、電話番号の不足が懸念されています。このため総務省は「060」で始まる番号の開放に向けて2日、「情報通信行政・郵政行政審議会」に諮問するとともに、一般からの意見の募集を始めることになりました。

https://www3.nhk.or.jp/news/html/20241002/k10014598901000.html

情報通信行政・郵政行政審議会 諮問資料
https://www.soumu.go.jp/main_content/000970568.pdf

上記諮問資料「今後の進め方（案）」
![スクリーンショット 2024-12-20 1.17.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155285/13639aa8-b1f9-c828-fd09-184672f20293.png)

# 「060」番号への Amazon Connect への発信について

上記記事の通り、日本の携帯電話番号は、巻頭の記事「Amazon Connect 日本の携帯電話発信制限解除」の通り上限緩和申請を行い発進可能とする手続きがあります。

AWSサポートに今後の対応予定を確認しても、他サービス同様「公開情報以外の将来の計画やロードマップに関するご案内はなし」ですので現時点でお知らせできるコトはありません(実際にAWSサポートに確認済)。

個人的な予想ですが、以下2パターンを想定しております。

- 「090」「080」「070」発信上限緩和済の場合は「060」番号への発信も自動で解除される
- 「090」「080」「070」発信上限緩和済かは関係なく、「060」番号への発信の上限緩和申請を行う

# 今後想定されるスケジュール感

過去に同様の事象があったとすればPHS番号として使われていた「070」番号の携帯電話番号への開放です。その際は、2011年前半に方針が出て、実際に一般利用開始となったのは2013年後半だったようです。実に2年以上を要しています。ひとつ参考になるスケジュール感かと思います。

上記を踏まえると「060」の一般利用開始については、2025年中ではなく早くて2026年ではないかと考えています。

今後のアップデートがあると思いますので、自分自身キャッチアップしておきたい情報として気付き次第追記していきたいと思います。

## 2024/12/21(土)追記
早速、12/20(金)付けで総務省・携帯電話事業者からニュースリリースがありました。想定通りのスケジュール感でした。

> 総務省は、音声伝送携帯電話番号の枯渇に対応するため、本日、新たに060から始まる11桁の番号を携帯電話事業者に指定可能とする内容の電気通信番号計画の変更を行いました。今後、関連する電気通信事業者における対応が完了した後、060から始まる音声伝送携帯電話番号が、**令和8年7月以降順次利用可能**になります。

https://www.soumu.go.jp/menu_news/s-news/01kiban06_02000126.html

> **株式会社NTTドコモ、KDDI株式会社、沖縄セルラー電話株式会社、ソフトバンク株式会社、楽天モバイル株式会社**は、2024年12月20日に総務省が発表した「音声伝送携帯電話番号への060番号の追加」（該当項目へジャンプします注）のとおり、新たに060番号が携帯電話番号事業者に指定可能となる電気通信番号計画の変更を受け、060から始まる携帯電話番号の利用を**2026年7月以降に順次開始できるように対応**していきます。

https://newsroom.kddi.com/news/detail/kddi_nr-371_3640.html

電話関連の仕組みを担当しているので、その1年前2025年中には「060」番号でテストをしておきたいところです。

以上です。
【SchooMyでIoT】ゼロから環境構築してLチカするまで中学生に授業してみた

# はじめに

[IoTLT （IoTや電子工作ネタなど） Advent Calendar 2024](https://qiita.com/advent-calendar/2024/iotlt)の21日目の記事として執筆しております。仲条高幸（ナカジョウタカユキ）と申します。

今年（2024年）から、藤村女子中学校の新しいプログラム「デジタル・クリエイティブ」の授業を担当しておりまして。

https://fujimura.ed.jp/junior-high-school/school-life/digitalcreative/

そのカリキュラムの一個として、「IoTデバイス」があり、学校側からの要望で
「SchooMy を使ってほしい」
とのことで、でもほぼ全員「なんやそれ？」な状態だったので、**こちらの記事を読めば、誰でも『環境構築からLEDを光らす』までできるようになれる！** と願いを込めて、SchooMy をインストールするところから、ブロックを組んで実際に動かしてみるところまで共有させていただきます。

## YouTube でも全て解説しています

<iframe width="560" height="400" src="https://www.youtube.com/embed/nu1jsT24tT8?si=1zDR7-SBQD7hhiBw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

# SchooMy インストール

まず、パソコンにデスクトップアプリ「SchooMy」をインストールする必要があります。
※iPadではできません！

SchooMy公式サイト: https://schoomy.com/
SchooMyダウンロード：https://hello.schoomy.com/startflow/

インストールする際、マックの場合認証されなくてインストールできないため、下記の方法でお試しください。
https://support.apple.com/ja-jp/guide/mac-help/mh40616/12.0/mac/12.0


# SchooMyIDE_with_arduino 立ち上げよう！

インストールが終わると、アプリケーションの中に「SchooMyIDE_with_arduino」が入っています。

![【共有用・藤村中３】SchooMy  に触れてみよう (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216701/8b4b35a8-4efb-d329-8480-09a2d874ca2f.png)

クリックしてアプリを立ち上げると、エディタの画面が出現しますが、怖がらずに上のメニューバーのTools(ツール)から「SchooMyBlockEditor 日本語版」を選択します。

![【共有用・藤村中３】SchooMy  に触れてみよう (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216701/f7258787-4fcf-b639-6e95-1eb004a26a46.png)

そうすると、ブロックプログラミングできそうな画面が開きます！

試しに、アクションの中にLEDを光らせるブロックが用意されているので、カチッとブロック同士をはめて、右上の「アップロード」のボタンを押してみましょう。

![unnamed (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216701/880ffe39-ffbb-8f27-28e3-5247bd5b525f.png)

下記の画像のようにSchooMyがしっかり繋がっていれば、LEDが光ると思います。

![unnamed.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216701/e7050075-46a7-aa49-ca76-2fafd7f08463.jpeg)

# 応用

スイッチを押したらLEDが光る、みたいなことも、下記のようにブロックを組めば実装することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216701/6060964d-2c3d-7812-7a00-cf5af6f7ded2.png)

※下記の公式サイトを参考にしました。

https://hello.schoomy.com/category/orange-board/

# 宣伝

現在、日本の美味しいお茶を海外に販売しようとするクラウドファンディングを実施中ですので、ご支援いただけると嬉しいです！

https://kickstarter.com/projects/teabreak/sustain-japans-600-year-tea-legacy-with-shizuokas-teabreak

最後までご覧いただきまして、誠にありがとうございました。
素敵なIoTライフをお過ごしください。

仲条高幸
Power AutomateでOfficeファイルをクライアントアプリケーションで開くリンクを作成する

# やりたいこと
SharePointのドキュメントライブラリに保存されたExcelファイルを、Officeクライアントアプリケーションで開くリンクを作成したい。


# 実装方法
HTMLのaタグを使用して、リンクの前に``ms-excel:ofe|u|``を付与します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640497/ba235286-5e8b-2138-51f5-45c7c7a36cba.png)

実際に、フローを実行してメールのリンクをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640497/d0e1a8bd-1b52-cfb9-8f6f-fa746794a043.png)

Officeクライアントアプリケーションで開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640497/edd5aa3f-44c7-8c28-d2e2-473b05a7ed41.png)

# 参考
Excelだけでなく、WordやPowerPointなどのOfficeアプリをアプリケーションで開きたい場合は、以下のドキュメントを参照し、適切なURIスキームを付与するだけで実現できます。

https://learn.microsoft.com/ja-jp/windows/uwp/launch-resume/reserved-uri-scheme-names
非同期Core間でのセンサーデータの同期

# 初めに

presenseの大きな特徴として、マルチコアという点があります。

このマルチコアの各コアごとに、センサーを高速で読み出しかつ信号処理などを独立して実装するとPortability や Modifiability がかなり向上するかと思います。

ただ、その場合、それらのセンサーのデータが同期できないという問題が発生しますが、これは、RTCを使うことで解決できるのでその方法を書いておきます。

# ブログ（元ネタ）
この記事は、以下のブログに過去に投稿したもののまとめです。

https://spresense.livedoor.blog/archives/37420100.html

# SpresenseのRTCライブラリ

RTC（Real Time Clock）とはリアルタイムクロックの略称で、SpresenseにはすべてのCoreから読み出せるRTCがあります。

<a href “https://developer.sony.com/spresense/development-guides/arduino_developer_guide_ja.html#_rtc_%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA">![RTC.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526253/48122816-661f-2976-5138-b8c56ea72692.png)
</a>

RTCの使い方に関しては、こちらにライブラリの説明があるのでわかりやすいです。

# 使い方

MainCoreの中で、起動時にRTCを設定します。

```C++
#include <RTC.h>

void setup()
{
  // Initialize RTC at first
  RTC.begin();

  // Set the temporary RTC time
  RtcTime compiledDateTime(__DATE__, __TIME__);
  RTC.setTime(compiledDateTime);
  
```

このように設定したRTCは、SubCore側で以下のように読み出すことができます。

```C++

#include <RTC.h>

void printClock(RtcTime &rtc)
{
  printf("%04d/%02d/%02d %02d:%02d:%02d:%08ld\n",
         rtc.year(), rtc.month(), rtc.day(),
         rtc.hour(), rtc.minute(), rtc.second(),rtc.nsec());
}

void setup()
{
  int ret = 0;

  ret = MP.begin();
  if (ret < 0) {
    errorLoop(2);
  }

  // Initialize RTC at first
  RTC.begin();
}

void loop()
{
  RtcTime now = RTC.getTime();
  printClock(now);

}

```

このようにRTCを取得し、この時刻をセンサーデータに付与するとで、
各データを同期させることが可能になります！

# サンプルコード

SubCore1でアナログのデータを、SubCore2でI2Cセンサーのデータを非同期に取得し、それぞれにRTCのタイムスタンプをつけて、MainCoreに渡すサンプルです。

https://github.com/Interested-In-Spresense/sketches/tree/master/MultiCore/SensorSync


分、秒、ミリ秒までの時間を付与しています。
Clojure: DuctでRSSリーダーを作る - 環境変数

![advent_calendar_2024.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/f4cd8ce0-6352-a1d8-4cae-f39dd44f4def.png)

[*Advent Calendar 2024 Day 22*](https://qiita.com/advent-calendar/2024/clojure)

昨日は以下のようにDB接続を設定しました。

```clojure:config.edn
  :duct.database.sql/hikaricp
  {:adapter "postgresql"
   :server-name "localhost"
   :port-number "5432"
   :username "user"
   :password "password"
   :database-name "feed"}
```

今日は環境変数から読み込めるようにします

## 環境変数に置き換える

とはいってもやることは簡単です

```clojure:config.edn
  :duct.database.sql/hikaricp
  {:adapter "postgresql"
   :server-name #duct/env "DB_HOST"
   :port-number #duct/env "DB_PORT"
   :username #duct/env "DB_USER"
   :password #duct/env "DB_PASS"
   :database-name #duct/env "DB_NAME"}
```

`#duct/env "変数名"`で環境変数を参照できます

試しに起動します

```bash
$ DB_HOST=localhost DB_PORT=5432 DB_USER=user DB_PASS=password DB_NAME=feed lein run
```

```bash
$ curl localhost:3000/v1/feeds | jq .

{
  "feeds": [
    {
      "id": 1,
      "url": "https://www.google.com",
      "title": "Google",
      "description": "Googleのトップページです。",
      "created_at": "2024-12-19T05:24:36Z"
    },
    {
      "id": 2,
      "url": "https://www.yahoo.co.jp",
      "title": "Yahoo! JAPAN",
      "description": "Yahoo! JAPANのトップページです。",
      "created_at": "2024-12-19T05:24:36Z"
    }
  ]
}
```

ちゃんと接続ができてそうですね

## デフォルト値を設定する

ただこれだと特にlocal環境では毎回環境変数を設定するのが億劫です

そこで、デフォルト値をlocalでの設定として設定してみます

```clojure:config.edn
  :duct.database.sql/hikaricp
  {:adapter "postgresql"
   :server-name #duct/env ["DB_HOST" :or "localhost"]
   :port-number #duct/env ["DB_PORT" Int :or 5432]
   :username #duct/env ["DB_USER" :or "user"]
   :password #duct/env ["DB_PASS" :or "password"]
   :database-name #duct/env ["DB_NAME" :or "feed"]}
```

このように設定しました。

`:server-name #duct/env ["DB_HOST" :or "localhost"]`のように`:or`でデフォルト値を設定できます

また、`#duct/env ["DB_PORT" Int]`このようにすることで数値として変数を扱うことができます

環境変数を外から渡さずに起動してみます

```
$ lein repl
user=> (dev)
:loaded
dev=> (go)
:duct.server.http.jetty/starting-server {:port 3000}
:initiated
```

無事起動し、DB接続プールを作ることができてそうです
CLionでArduino+Nucleo F303K8をやろうとして詰まった話し

# PlatformIO付属のOpenOCDで書き込み失敗

引用記事そのまま、ではありますが...

MacにCLionとplatformIOをインストールして、実行しようとした下記のエラー

```CLion
** Programming Started **
Warn : Adding extra erase range, 0x08003224 .. 0x080037ff
Error: error writing to flash at address 0x08000000 at offset 0x00000000
embedded:startup.tcl:1516: Error: ** Programming Failed **
in procedure 'program' 
in procedure 'program_error' called at file "embedded:startup.tcl", line 1581
at file "embedded:startup.tcl", line 1516
*** [upload] Error 1
================================================================== [FAILED] 
```

PlatformIOに付属しているOpenOCDのバージョン0.12.0に問題があるらしく、0.11.0に戻してやると動くとのこと。

https://community.platformio.org/t/cant-load-to-nucleo-f303k8/34819/10

# 成敗!

platoformio.iniにopenocdのバージョンを指定するコマンドを追記します。この@以下のバージョン指定子は妙な感じがするが、下記のリポジトリのページで指定されているものの3つのうちの一つになっているので仕方ない。

```platformio.ini
[env:nucleo_f303k8]
platform = ststm32
board = nucleo_f303k8
framework = arduino

upload_protocol = stlink

platform_packages = platformio/tool-openocd@2.1100.211028 << 追記
```

追記するとBuildのときに自動でツールを引っ張ってきてくれる。で、無事動く。

# 考察
OpenOCDの最新バージョンは0.12.0-4で、2024/8/2に更新されている。
https://xpack-dev-tools.github.io/openocd-xpack/blog/2024/08/02/openocd-v0-12-0-4-released/

一方platformIOで指定可能な最新バージョンは3.12.0000で、二年前で更新が止まっている。

https://registry.platformio.org/tools/platformio/tool-openocd/versions

platformIOでの指定子とOpenOCDのバージョンの対応はいまひとつよくわからない。

PlatformIOを普通にインストールすると入ってくるopenOCDのバージョンは
0.12.0-01004-g9ea7f3d64-dirty (2023-01-30-17:03)
となっているので、番号からすると最新版のようだ。0.12.0から更新されているバージョンのはずだが、やはりエラーは出る。


ということで、ターゲットがSTM32F303K8の場合、現状0.11.0系を使うしかないというところか。
迷子のスクリーンショットとはおさらば！Raycastで実現する究極の画像管理術

この記事は、[Raycast Advent Calendar 2024](https://qiita.com/advent-calendar/2024/raycast) に参加しています。
昨日は windhorn さんの[さりげない機能だけど、とても便利な Quicklink](https://qiita.com/windhorn/items/e413d93ec56476fec589) でした。

## はじめに

「あのスクリーンショット、どこに保存したっけ...」
「この画像、確かコピーしたはずなんだけど...」
「Raycast の Clipboard History で画像を探すの難しいなあ...」

こんな経験、ありませんか？

Mac ユーザーの多くが日々活用しているスクリーンショット。Command+Shift+4 で撮影した画像や、ブラウザからコピーした画像は、気づけばあちこちに散らばってしまいがちです。

実は Raycast の「Search Screenshot」機能を使えば、スクリーンショットだけでなく、クリップボードを経由した画像まで、すべての画像を一元管理できるんです。今回は、この意外と知られていない便利な使い方をご紹介します。

## Search Screenshots とは
![Raycast 2024-12-19 at 23.50.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478527/a4d979e4-ffaa-8dd7-3f64-2bc11f9bbcba.png)

Raycast から簡単にアクセスでき、グリッド表示で視覚的に分かりやすい検索が可能です。（私は⌘+⇧+Sをホットキーに設定しています．）

以下のような特徴があります：
- 直感的なインターフェースで素早く目的の画像を見つけられる
- Quick Look プレビュー対応で素早く内容確認が可能
- スクリーンショット内の英語テキストを自動認識（OCR 機能搭載）し，キーワード検索が可能
- Annotate in Preview で即座に画像を編集可能

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478527/f08d4122-2ef8-8fa6-a979-78c5f559ed9c.gif
![https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478527/f08d4122-2ef8-8fa6-a979-78c5f559ed9c.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478527/f08d4122-2ef8-8fa6-a979-78c5f559ed9c.gif)

（もちろん，マウスを使わずCommand+Enterで直接貼り付けることもできますよ！）

## クリップボード画像の管理方法
### 基本設定
最も重要なことは，クリップボード履歴を保存しているディレクトリを検索対象に追加することです：
1. Raycastの設定を開く
2. Extensions > Screenshots > Add Directories
3. `~/Library/Caches/com.raycast.macos/Clipboard` を追加

![Screenshot 2024-12-20 at 0.07.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478527/3cde4ca7-db2e-b959-d2e3-2dbb1934dfd5.png)

これにより、スクリーンショットだけでなく，以下の画像も自動的に管理対象となります：
- ブラウザからコピーした画像
- アプリケーション間でコピーした画像
- その他クリップボードを経由するすべての画像

### 活用シーン

- **ウェブ閲覧中の画像保存**
  - 右クリック→コピーした画像を後から簡単に検索
  - 一時的にコピーした画像も自動的に保存

- **アプリケーション間の画像移動**
  - SlackやDiscordでコピーした画像を簡単に再利用
  - デザインツールでコピーした要素を効率的に管理

- **スクリーンショットの統合管理**
  - Command+Shift+4で撮影した画像
  - Command+Shift+Control+4でクリップボードにコピーした画像
  - すべてを一元的に検索可能

## まとめ

Raycastの「Search Screenshot」は、Mac上の画像管理を劇的に時短できる強力なツールです。
無料で利用できる機能なので、ぜひ一度試してみてください！
Amazon Bedrock の Custom model import を使ってIBM Granite 3.0をインポートしてみたがうまく行かなかった件

# はじめに
最近は生成AI関連のアップデートが目まぐるしい中で、気になるアップデートがあったのでその2つを組み合わせてみました。
一つ目はIBM Granite 3.0リリースしたということです。IBM社のブログを見ると何かすごいらしい。また、これらのモデルはオープンソースモデルとして公開されているため、Hugging Faceからダウンロードできます。

https://www.ibm.com/new/ibm-granite-3-0-open-state-of-the-art-enterprise-models

https://huggingface.co/ibm-granite

2つ目はAmazon Bedrock カスタムモデルインポートが一般提供開始されたことです。これで独自に開発したモデルをBedrockに取り込むことができ、単一の統合APIを介して様々なモデルにアクセスすることができます。（モデル毎に利用するAPIや環境など意識しなくできるのはいいなと思いました。）またブログにはIBM Graniteにも対応していることが記載されていました。しかしマニュアル（12/20時点）をみると、対応しているアーキテクチャにはGraniteの記述はありませんでした。

https://aws.amazon.com/jp/blogs/machine-learning/amazon-bedrock-custom-model-import-now-generally-available/

https://docs.aws.amazon.com/bedrock/latest/userguide/model-customization-import-model.html

# やってみた
物は試しにやってみよと思います。

## Hugging Faceから必要なモデルをダウンロードする
今回は一般的な使用をも目的とした「Granite-3.0-2B-Base」を利用したいと思います。gguf形式でも提供されていますが、カスタムモデルインポートではSafetensors 形式である必要があるので、直接ファイルをダウンロードしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232966/66d5df53-8b10-4244-8f9d-531a6bfcb366.png)

https://huggingface.co/ibm-granite/granite-3.0-2b-base

## S3にアップロード
`us-east-1`リージョンにS3を作成して、その中に先ほどのモデルをアップロードしました。バケット直下にモデルを入れると、カスタムモデルインポート時にうまく読み込めなかったので階層を作っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232966/3cbb96df-3985-907a-f019-e13b2cdc3ca3.png)

## カスタムモデルインポートをする
インポート名は適当で、先ほどのS3のURIを設定してインポートジョブを作成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232966/ef98c5a5-383c-9da5-7bd6-1455cff9537b.png)

すこし待っているとエラーメッセージが・・・・
まだGraniteには対応していないメッセージがでました。残念。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232966/f432c558-94f2-9620-7e3d-cd685d894a9a.png)

もしかすると現状では、AWSのブログにもあるように言語モデルではなく、コードモデル（Granite 3B-Code、8B-Code、20B-Code、34B-Code など）の方は利用できるかもしれません。
ただ、こちらも試していると別のエラーになったので、要調査です。（お正月にゆっくりみてみようかなと）

```
Amazon Bedrock cannot import the model. Make sure the model files are in Huggingface weights format and that you can load them with the Huggingface method.
```
# 所感
まだGranite3.0シリーズの言語モデルには対応していないようでしたので、アップデートを待ちたいと思います。現状はモデルカタログの方にはGranite3.0シリーズがいるので、利用したい場合はこちらからになるかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232966/6afce0cd-2b42-fd4b-f562-2eba9941ff2c.png)
Pythonで音を生成して奏でたい

# はじめに
ふとPythonで音を生成して奏でたいと思ったためchatGPTさんに教えてもらいました。

`sounddevice`というライブラリと`numpy`を組み合わせて使えばできるみたいなので、インストール
```bash
pip install sounddevice numpy
```

## まずはドレミファソラシドを奏でてみる

```python
import numpy as np
import sounddevice as sd

def generate_sound(frequency, duration, sample_rate=44100):
    """
    1つの音を作る関数
    - frequency: 音の高さ（Hz）
    - duration: 音の長さ（秒）
    """
    t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
    # 音を作る（正弦波を使う）
    sound = 0.5 * np.sin(2 * np.pi * frequency * t)
    return sound

# ドレミファソラシの音階と周波数
notes = {
    "ド (C)": 261.63,
    "レ (D)": 293.66,
    "ミ (E)": 329.63,
    "ファ (F)": 349.23,
    "ソ (G)": 392.00,
    "ラ (A)": 440.00,
    "シ (B)": 493.88,
    "高いド (C5)": 523.25
}

# 各音を1秒ずつ鳴らす
for note, freq in notes.items():
    print(f"Playing {note}")
    sound = generate_sound(freq, duration=1.0)  # 音を生成
    sd.play(sound, samplerate=44100)           # 再生
    sd.wait()                                  # 再生終了まで待機
```
コードの流れ
1. `generate_sound`という関数で1つの音を作ります。これは「正弦波」という波を使って音を作っているみたいです。
2. `notes`には、音階とその周波数（Hz）が登録されています。
3. インストールした`sounddevice`を使って、作った音をスピーカーで再生します。

実行するとドレミファソラシドが奏でられている！

## きらきら星を奏でてみた。
最終的なコード
```python
import numpy as np
import sounddevice as sd

def generate_sound(frequency, duration, sample_rate=44100):
    """
    1つの音を作る関数
    - frequency: 音の高さ（Hz）
    - duration: 音の長さ（秒）
    """
    t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
    sound = 0.5 * np.sin(2 * np.pi * frequency * t)  # 正弦波
    return sound

# 音階と周波数 (ド～高いド)
notes = {
    "ド": 261.63,
    "レ": 293.66,
    "ミ": 329.63,
    "ファ": 349.23,
    "ソ": 392.00,
    "ラ": 440.00,
    "シ": 493.88,
    "高いド": 523.25
}

# きらきら星のメロディ (音階と長さのリスト)
melody = [
    ("ド", 0.5), ("ド", 0.5), ("ソ", 0.5), ("ソ", 0.5),
    ("ラ", 0.5), ("ラ", 0.5), ("ソ", 1.0),
    ("ファ", 0.5), ("ファ", 0.5), ("ミ", 0.5), ("ミ", 0.5),
    ("レ", 0.5), ("レ", 0.5), ("ド", 1.0),
    ("ソ", 0.5), ("ソ", 0.5), ("ファ", 0.5), ("ファ", 0.5),
    ("ミ", 0.5), ("ミ", 0.5), ("レ", 1.0),
    ("ソ", 0.5), ("ソ", 0.5), ("ファ", 0.5), ("ファ", 0.5),
    ("ミ", 0.5), ("ミ", 0.5), ("レ", 1.0),
    ("ド", 0.5), ("ド", 0.5), ("ソ", 0.5), ("ソ", 0.5),
    ("ラ", 0.5), ("ラ", 0.5), ("ソ", 1.0),
    ("ファ", 0.5), ("ファ", 0.5), ("ミ", 0.5), ("ミ", 0.5),
    ("レ", 0.5), ("レ", 0.5), ("ド", 1.0),
]

# メロディを再生する
for note, duration in melody:
    if note in notes:
        print(f"Playing {note}")
        sound = generate_sound(notes[note], duration)
        sd.play(sound, samplerate=44100)
        sd.wait()  # 再生終了を待機
```
少し不安になる音ですが奏でられてます

## まとめ
Pythonで音を奏でるのは初めてだったのでとても面白い体験でした。
ぜひ手元で実行して、サンプルコードの少し不安になる音のきらきら星聞いてみてください！
Structured Outputs

# Structured Outputsって凄いらしい
## 概要
昨今話題のOpenAIのStructured Outputsについて、備忘録としてまとめる

## 何が凄い？
モデルがJSON Schema（JSON形式のルール）に従った出力をより信頼性高く生成できるらしい
よく見るグラフはこちら！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1059368/c70eb25f-c002-fd17-6c0a-7e9d8d11407a.png)

モデルの性能UPに伴い、単純なプロンプト指定だけでもかなり信頼性高く出力されるが、Structured Outputsを使用するとほぼ100%で指定したJSON Schemaで出力される（たまにrefusalされるらしい。見たことない）

## 利用方法
私が説明するより公式ドキュメントや野良記事を参考ください！どれも同じ（公式ドキュメントの転用）
- https://platform.openai.com/docs/guides/structured-outputs
- https://zenn.dev/chips0711/articles/ab49bde721375e

## 仕組み
2つのアプローチを採用している（ぽい）
- モデル訓練によるアプローチ
    - 最新モデル「gpt-4o-2024-08-06」を訓練し、複雑なJSON Schemaを理解して、それに合った出力を生成。このモデルのパフォーマンスは高く、ベンチマークでは93%の成功率を記録。しかし、生成AIは本質的に非決定的（ランダム性がある）なため、完全な信頼性（100%）には達成できず。。。
- 制約アプローチ（特に重要）
    - SON Schemaに完全に合った出力を生成するため、モデルの出力に「制約」を加える工学的な方法を導入し、信頼性を限りなく100%に引き上げた

## 仕組み詳細
制約を加えるとは何ぞや？
- 制約付きサンプリング（またはデコード）」と呼ばれる技術に基づく。通常、AIモデルが次の単語（トークン）を生成するときは、辞書の中からどの単語でも自由に選択する。この自由度がミスの原因となり、例えば、JSONでは不適切な場所で {（波括弧）を選んでしまうことがある。そこで、モデルが選択できるトークンを「現在のJSON Schemaに基づいて有効なもののみに制限」する。これにより、不適切なトークンを選ぶ可能性をゼロにします
- 具体例として、出力の最初では { や {" といったトークンが有効。しかし、すでに {"val と出力された後では、{ は無効になる。このように「動的制約付きデコード」を採用し、各トークン生成のたびに「次に有効なトークン」を判断する。

## その他
- プロンプトに出力形式を指定する必要はあるか？
    - 必要なし（と思われる）
        - 公式ドキュメントのサンプルスクリプトを見ると、プロンプト内では厳格に指定していない
        - ただ、フューショットで出力構造例を与えることはしたほうが良いかも（私はする）
- JSON Schemaのdescriptionについて意味あるか？
    - 意味なし（と思われる）
        - ここの内容は出力に影響は与えない
        - 同様に、JSONのキー名も影響を与えない
A5M2で登録されているデータからINSERT文やUPDATE文を簡単に取得する方法

A5M2で登録されているデータからINSERT文やUPDATE文を簡単に取得する方法です。

前提として、既にテーブルにデータが1件以上あること。


# １．まずは、A5M2でテーブルを開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3733765/ec0a4af9-71e5-9226-c05c-9dd7aadccfbb.png)

※今回は2件あります。

# ２．レコードを選択して右クリックをする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3733765/f5a07dea-fcc2-2b2a-fd47-9bfe92f7e0cc.png)

# ３．上記画像の「レコードのコピー（その他のフォーマット指定）」 → 「INSERT文」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3733765/af4061f4-65c9-4adb-8358-180bdf0411a1.png)

# ４．表示されたモーダルを「OK」 → クリップボードにコピーされる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3733765/c4b55b75-f47d-f9e1-ba1f-9e3b6204d1f2.png)
※デフォルトのままでもよいが、私は「予約語の大文字/小文字」を「大文字」にする。
　出力されるDMLがかっこいいから。

# ５．テキストに貼る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3733765/8e3b7c65-0b76-768e-91bc-03921a30a1f7.png)


以上です。

# UPDATEも同じ手順で行えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3733765/d25671af-e656-f62a-e6d7-e3331053600b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3733765/04432b0e-05ac-24ba-ede4-bbee34ff09bf.png)



# おすすめ
データ更新をするテストとかの際にとても便利です。
データ更新前に戻したいけど、また、対象のテーブルを開いて対象のレコードまで言って修正しなきゃいけないなどのときです。
戻したいデータでUPDATE文を保持しておけば、実行だけですぐに元通りに。

試してみてください。
ブラウザのデフォルトモーダルを制御してブランドコアを守る

## はじめに
多くのWebサービスでは、ユーザーが編集中のページから離脱しようとする際に確認モーダルを表示します。この機能は非常に重要なUXの一部ですが、実装する際に思わぬ課題に直面することがありましたので、記事を書こうと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552884/12dd7dff-5ccb-73b9-bb41-246f87c4665b.png)

上の画像のようなモーダルを見たことはありませんか？

編集フォームの入力中に、間違えてリロードしてしまった時に出てくる時があります。

このようなモーダルですが、自分/自社で作成してしまおうという場合があります。
特に、プロダクトのブランドコアとしてカスタムデザインのモーダルを実装している場合、ブラウザのデフォルトの離脱防止モーダルと競合してしまう問題があります。この記事では、その解決方法について詳しく解説します。

## 問題：ブラウザのデフォルトモーダルとの競合
### 発生する問題
- カスタムデザインの離脱防止モーダルを実装している
- ページ遷移時に、カスタムモーダルとブラウザのデフォルトモーダルが両方表示される
- 結果として、UXが著しく低下し、ブランドの一貫性が損なわれる

### なぜこれが重要か
1. **ブランドの一貫性**
   - カスタムデザインのモーダルは、プロダクトのブランドアイデンティティの一部
   - ブラウザのデフォルトモーダルは、そのブランド体験を損なう
2. **ユーザー体験**
   - 2つのモーダルが表示されることで、ユーザーを混乱させる
   - 操作の手順が増え、フローが煩雑になる

## 解決策：ブラウザモーダルの制御
### 実装例
```typescript
const historyPushState = useCallback((path: string) => {
  // 1. beforeunloadイベントを一時的に無効化
  const defaultLeaveEvent = window.onbeforeunload;
  window.onbeforeunload = null;
  try {
    // 2. React Routerのnavigateを使用
    navigate(path);
  } finally {
    // 3. 遷移後にbeforeunloadを復元
    window.onbeforeunload = defaultLeaveEvent;
  }
}, [navigate]);
```

### 解決策の詳細説明
1. **beforeunloadイベントの一時的な無効化**
   - ページ遷移時に一時的にブラウザのデフォルトモーダルを無効化
   - 元のイベントハンドラは保存して後で復元
2. **制御された遷移の実装**
   - React Routerの`navigate`を使用して適切な遷移を実現
   - ブラウザネイティブの遷移を避けることで、よりコントロールされた挙動を実現
3. **安全な状態管理**
   - `try-finally`ブロックで確実にイベントハンドラを復元
   - エラーが発生しても、アプリケーションの他の部分は正常に動作

## このアプローチのメリット
1. **ブランドの一貫性維持**
   - カスタムデザインのモーダルのみが表示される
   - プロダクトのデザインシステムに沿った体験を提供
2. **UXの改善**
   - シンプルで明確な離脱フロー
   - ユーザーの混乱を防止
3. **保守性**
   - クリーンな実装で、将来的な変更にも対応しやすい
   - エラーハンドリングが適切に行われている

## 実装時の注意点
1. **イベントハンドラの管理**
   - `beforeunload`イベントの無効化は必要な時のみ行う
   - 必ず元の状態に復元する
2. **ルーティング**
   - 適切なルーティングライブラリを使用する
   - ブラウザネイティブの遷移は避ける

## まとめ
プロダクトのブランドコアを守りながら、優れたユーザー体験を提供することは現代のWebサービスにとって重要な課題です。この記事で紹介した方法を使用することで、ブラウザのデフォルトモーダルを適切に制御し、一貫性のあるブランド体験を実現できました。
また、この解決策は単なる技術的な問題解決以上の価値があります。プロダクトのブランドアイデンティティを守り、ユーザー体験を向上させることで、サービスの品質向上に貢献します。
今後のWeb開発において、このようなブランドコアを意識した実装がますます重要になっていくでしょう。今後も精進します。ではまたっ！

## 補足
### beforeunloadイベント
ウェブページが閉じられる直前に発生するイベントです。以下のような場合に発火します：
- ページのリロード
- ブラウザタブを閉じる
- 新しいURLへの遷移
- ブラウザを閉じる

### ページ遷移の種類と特徴
#### location.href による遷移
最も基本的なページ遷移方法で、ページ全体をリロードします。
```javascript
// - 履歴に新しいエントリーが追加される
// - ブラウザの「戻る」ボタンで前のページに戻れる
// - beforeunloadイベントが発火する
window.location.href = '/new-page';
```

#### location.replace による遷移
現在のページを履歴から完全に置き換える遷移方法です。
```javascript
// - 現在のページを履歴から置き換える
// - ブラウザの「戻る」ボタンで前のページに戻れない
// - beforeunloadイベントが発火する
window.location.replace('/new-page');
```

#### history.pushState による遷移
SPAで一般的な、ページリロードなしでの遷移を実現します。
```javascript
// - 履歴に新しいエントリーを追加
// - ページのリロードは発生しない
// - beforeunloadイベントは発火しない
history.pushState({}, '', '/new-page');
```

#### React Router の navigate
React アプリケーションで推奨される、宣言的な遷移方法です。
```javascript
// - SPAの文脈での遷移
// - デフォルトではページリロードなし
// - アプリケーションの状態を保持したまま遷移
navigate('/new-page');
```

これらの遷移方法は、それぞれ異なる特性を持っています。SPAでは主にReact RouterのnavigateやhistoryPushStateを使用し、必要に応じてlocation.replaceやlocation.hrefを使い分けることになります。