OmniAICreator/Qiita-1.07M huggingface dataset:
Azure OpenAI ServiceのAPIをPowerShellで実行する

# この記事の目的

いつも間違えるのでメモとして記載する

----

# 実行するAPI
Azure OpenAI Service REST API である Chat completions APIを実行する

https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#chat-completions

Azure OpenAI StudioのChat playground で実行されているAPI
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232184/1929db86-dda5-9019-4ba7-96dfca8b27b7.png)

----

# 実行方法
PowerShell の Invoke-RestMethod を使用して実行する

https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.utility/invoke-restmethod?view=powershell-7.4

----

# 実行例

```Powershell
$key = "<api key>"
$AOAIresource = "<Resource 名>"
$model = "<モデル名>"
$apiversion = "<REST APIのバージョン>"
$url = "https://$AOAIresource.openai.azure.com/openai/deployments/$model/chat/completions?api-version=$apiversion"
$headers = @{}
$headers["Content-Type"]  = "application/json"
$headers["api-key"] = "$key"
$body = '{
  "messages": [{"role":"system","content":"You are an AI assistant that helps people find information."},{"role":"user","content":"test"}],
  "max_tokens": 800,
  "temperature": 0.7,
  "frequency_penalty": 0,
  "presence_penalty": 0,
  "top_p": 0.95,
  "stop": null
}'


Invoke-RestMethod -Uri $url -Method POST -Headers $headers -Body $body
```

key などの取得方法はこちらを参照

https://learn.microsoft.com/en-us/azure/ai-services/openai/chatgpt-quickstart?tabs=command-line%2Cpython-new&pivots=rest-api

APIのバージョンはREST APIのリファレンスを参照

https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#chat-completions
【2024年版】JavaScript(React)におけるリーダブルコードのチートシート10~13章

:::note
2024/3/18
コードの再構成
10章 無関係の下位問題を抽出する
### 10.1 入門的な例: findClosestLocation()

:::

こちらの記事の続編になります。

https://qiita.com/kntmaan/items/8894acf58d801b0712bc

### 10.1 入門的な例: findClosestLocation()
```javascript:
const findClosestLocation = (lat, lng array) => {
     let closest;
     let closes_dist = Number.MAX_VALUE;

     for(var i = 0; i < arrya.length; i += i){
         //2つの地点をラジアンに変換する
         const lat_rad = radians(lat);
         const lat_rad = radians(lnt);
         const lat2_rad = radians(array[i].latitude);
         const lat2_rad = radians(array[i].longitude);
    
         //「球面三角法の第二余弦定理」の公式を使う
         const dist = Math.acos(Math.sin(lat_rad) * Math.sin(lat2_rad) +
                              Math.cos(lat_rad) * Math.cos(lat2_rad) *
                              Math.cos(lang2_rad - lng_rad));
    
         if(dist < closest_dist){
            closest = array[i];
            closest_dist = dist;
         }
     }
     
     return closest;
}
```


```diff_javascript:javascript:ループ内の無関係の下位問題を抽出
const sphericalDistance = (lat1, lng1, lat2, lng2) => {
     const lat1_rad = radians(lat1);
     const lng1_rad = radians(lng1);
     const lat2_rad = adians(lng2);
     const lng2_rad = radians(lng2);

     return Math.acos(Math.sin(lat1_rad) * Math.sin(lat2_rad) +
                               Math.cos(lat1_rad) * Math.cos(lat2_rad) *
                               Math.cos(lng2_rad - lng_rad));
} 

const findClosestLocation = (lat, lng array) => {
     let closest;
     let closes_dist = Number.MAX_VALUE;

     for(var i = 0; i < arrya.length; i += i){
         //関数に切り出した
-        const lat_rad = radians(lat);
-        const lnt_rad = radians(lng);
-        const lat2_rad = radians(array[i].latitude);
-        const lng2_rad = radians(array[i].longitude);
    
         //「球面三角法の第二余弦定理」の公式を使う
-        const dist = Math.acos(Math.sin(lat_rad) * Math.sin(lat2_rad) +
-                             Math.cos(lat_rad) * Math.cos(lat2_rad) *
-                             Math.cos(lng2_rad - lng_rad));
         //切り出した関数を使用
+        const dist =  sphericalDistance(lat, lng, array[i].latitude, array[i].longitude) 
         if(dist < closest_dist){
            closest = array[i];
            closest_dist = dist;
         }
     }
     
     return closest;
}
```
Bootstrapを使ってデザインする


<h1>Bootstrapとは？</h1>
デザインを簡単にできるフレームワーク！<br>
CSSにこだわる時間を省きたいときに使うと便利。<br>
カスタムもできるため、好みにも変えられる。

公式ドキュメント：

https://getbootstrap.jp/

<h1>インストール方法</h1>
<b>1.公式ドキュメントのダウンロードページを参照する。<br>

https://getbootstrap.jp/docs/5.3/getting-started/download/

　今回はPHPで実装するため、<font color="DeepPink">composer</font>を使ってrequireする。
```PHP:Docker
   docker-compose exec app composer require twbs/bootstrap:5.3.0
```
<br>

<b>2.エディタに戻り、vendor/twds/bootstrapがあることを確認。<br>

 　詳しいファイル構成は公式ドキュメントのコンテンツを確認。↓

  https://getbootstrap.jp/docs/5.3/getting-started/contents/

  こうなっているみたい。（自分のエディタでも確認。）
```
bootstrap/
├── dist/
│   ├── css/
│   └── js/
├── site/
│   └──content/
│      └── docs/
│          └── 5.3/
│              └── examples/
├── js/
└── scss
```
<br>
<b>3.Bootstrapを適用させたいファイルに以下のコードを追記。

```php
<link rel="stylesheet" href="../vendor/twbs/bootstrap/dist/css/bootstrap.css">
```
<br>
<b>4.ページをリロードするとBootstrapが適用されている！

<h1>Sassを使ってBootstrapをカスタマイズする</h1>
<b>1.Sassをインストール<br>

公式ドキュメント：

https://sass-lang.com/

今回はComposerを使ってインストールしたい。<br>しかし、公式ドキュメントにはComposerを使ったインストール方法がない...

<font color="DeepPink">GitHub</font>で"php scss"と調べる！
SCSSのコンパイラーを見つける。↓

https://scssphp.github.io/scssphp/

インストール方法を調べる。↓
![スクリーンショット 2024-03-20 10.00.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3698182/19877d5c-f3d4-9812-b305-07b2e3530a1d.png)

Dockerでrequireする。

```PHP:Docker
docker-compose exec app composer require scssphp/scssphp
```

エディタに戻り、vendorの下にscssphpが入っているか確認。<br><br>

<b>2.BootstrapをSassでカスタマイズする<br>

公式ドキュメントで確認。↓

https://getbootstrap.jp/docs/5.3/getting-started/vite/

方法としては、新しくファイルを用意し、インポートする。
→インポート定義の前に新しく変数定義して（カスタマイズ定義）上書きとなる。<br>みたいなので、まずは **新しいファイル** を作成。

私はsrc/companies/ **stylesheets/scs/app.scss** を作成しました。

app.scssに、以下を追記。
```SCSS:SCSS
@import '/var/www/html/vendor/twbs/bootstrap/scss/bootstrap';
```
<br>
<b>3.カスタマイズしたSassをCSSにコンパイルする<br>

公式ドキュメントを確認。

https://scssphp.github.io/scssphp/

↓該当箇所
![スクリーンショット 2024-03-20 10.20.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3698182/8a33d89f-169d-92f0-fc1d-3f38a1906eb4.png)

一旦appコンテナに入り、
```PHP:Docker
docker-compose exec app /bin/bash
```

公式ドキュメント通りに、自分のコンパイルしたいファイルへコンパイルする。
```PHP:Docker
vendor/scssphp/scssphp/bin/pscss < companies/stylesheets/scss/app.scss
```
Bootstrapのscssファイルを読み込んで、CSSに変換されたものがコマンドに表示されたらOK!![スクリーンショット 2024-03-20 10.35.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3698182/4689f0af-ca81-22d0-62f8-27bf80f0c636.png)


今はターミナルに出力されているため、<font color="DeepPink">ファイルに置き換えて</font>保存する。<br>ファイル名 **（> companies/stylesheets/css/app.css）** を付け足してコマンドを実行！

```PHP:Docker
vendor/scssphp/scssphp/bin/pscss < companies/stylesheets/scss/app.scss > companies/stylesheets/css/app.css
```
 

<br>
<b>4.コンパイルしたCSSをHTMLで読み込む<br>

該当ファイルの<font color="DeepPink">href=</font>を変更する。
```php
<link rel="stylesheet" href="stylesheets/css/app.css">
```

完了！
HelloWorld本 第7章

# 組み込みOSと汎用OS

組み込みOSには、主に最適化されたLinuxが利用される。
汎用OSはカーネルと必須アプリケーションから構成され、Windows・macOS・Ubuntu等が存在する。
汎用OSでは任意のアプリケーションが実行され、システムコールAPI・仮想メモリ・スケジューリング等が必要である。

# UNIX

UNIXはベル研究所で開発された汎用OSであり、BSDとSystemVに分派した。
UNIXのシステムコールAPIはPOSIXで定義される。
正統なUNIXでは無いがPOSIXに準拠したOSはUNIXライクと呼び、ソースコードの移植性を持つ。

# GNU/Linuxディストリビューション

LinuxとGNUアプリケーションを組み合わせた汎用OSをGNU/Linuxディストリビューションと呼ぶ。
POSIXについて、Linuxは機能を提供し、glibcはAPIを実装する為、GNU/LinuxディストリビューションはUNIXライクである。

# ビルドコマンド

```
# プリプロセッサ(cpp)
$ gcc -E hello.c > hello.i

# コンパイラ(cc1)
$ gcc -S hello.i -o hello.s

# アセンブラ(as)
$ gcc -c hello.s -o hello.o

# リンカ(ld)
$ gcc hello.o -o hello

# ビルドコマンドの確認
$ gcc -v hello.c -o hello
```

# その他

ソースコードの開発者を知ると、効率的に検索できる場合がある。
#includeの時、ダブルクォーテーションを使用するとカレントディレクトリから、山括弧を使用するとインクルードパスから検索する。
libc.aは静的ライブラリ、libc.soは共有ライブラリであり、readelfやobjdumpで解析できる。
【Ruby】paizaラーニング問題集解答（3けたごとにカンマ区切りで出力）（リベンジ）

# 大きな数値を 3 けたごとにカンマ区切りで出力 (paizaランク C 相当)
https://paiza.jp/works/mondai/stdout_primer/stdout_primer__specific_split_step6

前回正答できなかった問題に再挑戦しました。
### 誤答
```ruby:practice.rb
# 入力の受け取り
input = gets.chomp.to_s

# 出力用変数の定義
output = ""

# 出力用変数に3桁ずつ区切った文字列とカンマを追加
input.length / 3.times do |i|
    output += "#{input[i*3,3]},"
end

# 末尾のカンマを除去して出力
puts output.chomp(",")
```
`input.length / 3`が正しく評価されないようです。

### 正答
```ruby:practice.rb
# 入力の受け取り
input = gets.chomp.to_s

# 出力用変数の定義
output = ""

# 出力用変数に3桁ずつ区切った文字列とカンマを追加
(input.length / 3).times do |i|
    output += "#{input[i*3,3]},"
end

# 末尾のカンマを除去して出力
puts output.chomp(",")
```
`input.length / 3`を`()`で囲うことで正しく評価されるようです。
`count = input.length / 3`としてから`count.times do |i|`とする方がより確実かもしれませんね。
Raspberry Pi 5をM.2 SSDから起動してみた

## やってみたこと
Raspberry Pi 5を入手して、しばらく遊んでいたのだが、M.2 SSDから起動できるという噂を聞いてやってみたくなった。
しかし、NVMe Base for Raspberry Pi 5というキットが某サイトで売れ切れていて入手不能だったのだが、このたび晴れて入手できたので、M.2 SSDからの起動を試みることとした。

結論から言うと、「とても快適」です。

**注意：下記要件での完全動作を保証するものではありません**

## 用意したもの
- Raspberry Pi 5（公式アクティブクーラー付き）
- Raspberry Pi OS (64 bit) 最新版
- USB ACアダプター Type-Cオス 5.1V3.8A
- NVMe Base for Raspberry Pi 5（Rasberry Pi 5用NVMe Baseボード）
- Crucial P3 Plus PCIe 4.0 NVMe 2280 M.2 SSD 1TB
- NVMe/SATA両対応RGB LED搭載M.2 SSDアルミケース
- プラスドライバなど小道具一式

## 前提条件
- Raspberry Pi 5は、SDカードから起動できている

## 大まかな手順
1. Raspberry Pi Imagerユーティリティを用いて、M.2 SSDにRaspberry Pi OSを書き込む
1. Raspberry Pi 5をSDカードから起動して、raspi-configから、Advanced OptionsのBoot OrderでNVMe/USB Bootに変更する
1. Raspberry Pi 5の電源を落とし、SDカードを抜く
1. Raspberry Pi 5に、NVMe Base for Raspberry Pi 5をセットアップする
1. Raspberry Pi 5に電源を入れると、めでたく起動する。速いっ！

## 解説のようなもの

### 電源
5.1V3.8Aで足りているみたいです。

### M.2 SSD
公式サイトのDrive Compatibilityリストに載っているが、容量の記載はなかったので、とりあえず1TBを用意してみたら、あっさり動いた。
実は、WD_BLACK SN850X 2TBも用意したのだが、OSを書き込む際のM.2 SSDケースに、SSDのクーラーが干渉して入らないという事態が発生（ダサすぎる）し、つまるところ起動する・しない以前の問題により断念した。公式サイトにSN850Xは載っていないので試してみたかっただけに、とても悲しかった。次の自作PCに使うこととしよう。

### 手順
公式サイトでは、NVMe Base for Raspberry Pi 5にM.2 SSDを組み込む → Raspberry Pi 5にセットアップ → SDカードから起動 → M.2 SSDをフォーマット → スタートメニューからRaspberry Pi Imagerを用いてM.2 SSDにOSを書き込む → raspi-configでBoot OrderをNVMe/USB Bootに変更 → リブート、となっているが、当方、基本ヘッドレス使用のため、上記手順に変更している。

### 組み立て
NVMe Base for Raspberry Pi 5には、ネジ類も一式付属しているのだが、もちろん他のネジでも代用可能である。当方は、ヒロスギの真鍮製スペーサ（10mm）を使用したが、見栄えやバランスがとても良い（と思う）。ただし、Raspberry Pi 5とつながっているフレキシブルケーブルの長さにも限度があるので、あまり長いスペーサは使用できないと思われる。

### 発熱
調子に乗って使っていると、M.2 SSDが結構熱くなっているように思える。適当なクーラーをつけた方が良いのかもしれない。

おしまい
Vitestに入門しよう

## はじめに
Vitestは、JavaScriptフロントエンド開発のための高速なテストフレームワークです。学んだ内容をまとめていきます。

## Vitestの特徴

- **HMRによるテストの高速化:**
HMR（ホットモジュール交換)を使用しているため、開発効率を上げることができます。
HMRは、ソースコードの変更を検出し、関連するテストだけを即座に実行できるため、変更による影響をすぐに把握できます。
開発しながら、テストも一緒に書いている場合に、とても便利ですね。

- **Jestとの互換性がある:**
VitestはJestと互換性があり、Jestの影響を受けています。
既存のプロジェクトでも採用しやすいです。

- **Viteとの統合:**
Vitestは、高速なビルドツールであるViteをベースにしています。
ViteはJavaScriptの依存関係を事前にバンドルし、実行時の処理を最小限に抑えて高速化を図っています。
ちなみに、Viteを使っていないプロジェクトでも、Vitestは使用できます。

## インストール

まずは、vitestをインストール

```
npm install -D vitest
```

インストールしたら、vite.config.tsファイルを以下のように編集する。

```vite.config.ts
/// <reference types="vitest" />
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  test: {
    include: ["src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
  },
});

```
VSCodeを使用している人は、以下の「Vitest」という拡張機能を入れれば便利です。
![スクリーンショット 2024-03-14 22.57.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/c25796bc-a194-45d2-24ae-9f52e94c9496.png)


## 簡単なテストを書いてみよう
それでは、簡単なテストを書いていきます。
「sum.ts」ファイルと「sum.test.ts」ファイルを書いていきます。
Jestと同様に、[ファイル名].test.tsのようなファイル名にすれば、自動的にテストファイルとみなしてくれます。
```sum.ts
export function sum(a: number, b: number) {
  return a + b;
}
```
```sum.test.ts
import { expect, test } from "vitest";
import { sum } from "./sum";

test("adds 1 + 2 to equal 3", () => {
  expect(sum(1, 2)).toBe(3);
});
```

こちらをテストしてきましょう。
VSCodeのサイドバーにある「テスト」ボタンをクリックします。

![スクリーンショット 2024-03-20 10.04.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/ef9bf953-c837-dc92-0fee-e016851b7994.png)

すると、作成したテストケースが一覧で表示されており、テストしたい項目を選ぶことができます。
![スクリーンショット 2024-03-20 10.06.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/0a722342-f942-5f4a-5a31-244194f2bb70.png)

テストを実行してみましょう。
成功すると、以下のように表示されます。
![スクリーンショット 2024-03-20 10.07.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/871fe187-083d-02a6-02a0-b5cf00a7d894.png)

コードを以下のようにして、テストが失敗するようにしてみましょう。

```sum.test.ts
import { expect, test } from "vitest";
import { sum } from "./sum";

test("adds 1 + 2 to equal 3", () => {
  expect(sum(1, 2)).toBe(5);
});
```
テスト実行してみましょう。
失敗すると、エラーの原因などが赤く表示されます。

![スクリーンショット 2024-03-20 10.09.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/cca476c0-415a-2f41-f147-a5c5059dc871.png)


# 最後に
他にも色々な記事を書いているので、よければ読んでいってください、、、

https://qiita.com/hukuryo/items/97797a91d7e2ee0bcabc

https://qiita.com/hukuryo/items/2c07c52ff3386d5d75b9

https://qiita.com/hukuryo/items/ebeb26823f944f143b11
Viteについて

# Viteとは
Vite (フランス語で"速い"という意味) は、新しいフロントエンドビルドツールです。
主な目的は、開発サーバーの高速な起動とモジュールのホットリロードを実現することです。

# Viteを使うメリット
- 開発サーバーの起動が非常に高速
- モジュールのホットリロードが即時に行われる
- 本番ビルドも高速
- Webpackに比べて設定が簡単
- プリバンドルされたデータを利用し、高速なHMRを実現
- ロールアップをベースとしているため、最新のブラウザとNode.jsの機能を利用可能

# Webpackとの比較
Webpackは長年にわたり主流のビルドツールでしたが、大規模なプロジェクトでは起動が遅く、ホットリロードの応答が遅くなる傾向がありました。また、設定が複雑になりがちでした。

一方、Viteは開発サーバーの起動が非常に高速で、モジュールのホットリロードもスムーズに行われます。設定も比較的シンプルです。本番ビルドの速度も高速化されています。

# インストールして実行してみよう

まずはインストール
```: npm
npm create vite@latest
```

```: yarn
yarn create vite
```

インストーラーの質問に答えると、新しいViteプロジェクトが作成されます。

# 開発サーバーを起動
プロジェクトディレクトリに移動し、次のコマンドを実行します:

```: npm
npm run dev
```

```: yarn
yarn dev
```

ローカルサーバーが起動し、アプリケーションが自動的にブラウザで開きます。

# 参考

https://ja.vitejs.dev/


# 最後に
他にも色々な記事を書いているので、よければ読んでいってください、、、

https://qiita.com/hukuryo/items/97797a91d7e2ee0bcabc

https://qiita.com/hukuryo/items/2c07c52ff3386d5d75b9

https://qiita.com/hukuryo/items/ebeb26823f944f143b11
WebSpeechAPIでカタカナ禁止ゲーム作ってみた

WebSpeechAPIを使ってNGワードゲーム・カタカナ禁止ゲームを作ってみたので、背景や技術やら感想やらここに記録させてください。

今回作ったアプリ
↓
https://web-ng-word-game.vercel.app/

コード
↓
https://github.com/kyonpara/ng-word-game

# なんでこのアプリ作った？
皆さん、[ラムダ技術部](https://www.youtube.com/@lambdatech)というYoutubeチャンネルをご存知でしょうか。
感情の起伏のない淡々としたトークが個人的に大好きでよく視聴しているのですが、ある日こんな動画を見つけました。

**[自慢に反応するアラート装置を作った【アプリ】](https://www.youtube.com/watch?v=UuX8xPx8rWo&t=141s)**

この動画でラムダさんが作ったアプリが紹介されているのですが、アプリに利用されている音声のテキスト化を実現する**Web Speech API**と無料Webホスティングサービスの**Vercel**
が気になったのでこれを使って何か作ってみようと思ったことがきっかけです。

何を作ろうか悩んだのですがラムダさんの動画のコメントにこんなものがありました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3536965/62c9275e-4e1d-7167-8276-14716d4570ba.png)

なるほど、確かに。

ならばカタカナ禁止ゲームもアリじゃないか。

ということで安直に開発に着手。
私はごく一般の会社員なので業務後の空いた時間でちまちまアプリ制作。。

# どうやって作った？
以下の流れで作りました。
1.Figmaでデザイン構想(所要時間：たぶん3hくらい)
2.プログラミングカリカリ(所要時間：たぶん8hくらい)
3.Vercelでデプロイ(所要時間：5m)

***1.Figmaでデザイン構想(所要時間：たぶん2hくらい)***
自分のデザイン力が皆無なのはわりと課題意識があって、そろそろ本格的にUI/UX学ぼうということでまずはFigma入門。こんな感じでデザイン案を構想していました。
はじめてFigmaを使うわけではなく、前回作った飲み会傾斜計算アプリ(詳細は→[飲み会の傾斜計算が面倒だったのでアプリ作ってみた](https://qiita.com/Kyon_/items/aaa4af3110167194091f))開発時も実は少し使っています。あのときは
時間もなかったのでレイヤーとか配色とか超絶テキトーでもうすこし腰を据えてやりたいなと思っていたので今回は
満を持してリベンジしました。

*実際にFigmaで作ったデザイン*
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3536965/784eb67e-1bac-dd7d-d868-877ede4c0c30.png)

実際のデザインと出来上がったアプリにどれだけの乖離があるかは皆さんの目で確かめてください。
改めてFigmaの色んな機能使ってみると素材も豊富だし、画面遷移も表現できるしで結構使いやすいなと感じました。
調べると、作ったデザインをそのままCSSに落とし込んでくれる拡張機能があるっぽいですが使いこなせる気が
しないので今回はデザイン作成のみとしました。

***2.プログラミングカリカリ(所要時間：たぶん8hくらい)***
今回はバックエンド不要なのでReact(JS)でコードをチマチマカリカリ。
特段ポイントございません。音声認識の実装はラムダさんのGithubからコードを一部拝借させていただきました🙇‍♂️
早くリリースしたかったのでとりあえず動けやコードを生産しました。申し訳ございません。

***3.Vercelで5分デプロイ(所要時間：5m)***
普段アプリを公開するときはGCPとかAWSを使うのですが、今回はラムダさんの動画で紹介されていたVercelを利用してみました。
使う前に軽く調査。以下備忘として残しておきたいポイントです。
・無料で使えるよ
・無料枠の場合はアプリの商用利用は不可だよ
・無料枠の場合は月30000リクエストまでだよ
・githubと連携してpushしたらデプロイが走るCI/CDが勝手に設定されるよ
・独自ドメインを2秒で設定できるよ

個人的にはgithub pagesより数段使いやすかったです。

# 改善点あるよね？
改善点ありすぎてとりあえず致命的な部分だけピックアップして記録します。

***改善点①：カタカナ禁止ゲームにて、カタカナともひらがなとも漢字とも取れるワードで期待していない動作となる***
例えば「ダメ」「だめ」「駄目」などがいい例ですが、カタカナ禁止ゲームで「ダメ」を禁止判定されたら
ムカつきますよね。自分はムカつきます。
でも今回作ったアプリはこういうことを平気でやってしまいます。
使っているAPIのレスポンステキストを取得し、テキストにカタカナが含まれているかどうかを判定しているので
APIのご機嫌次第でゲーム性が損なわれます。

***改善点②:音声認識の精度が悪い***
当初の懸念通り、複数人で話した場合の音声認識の精度が著しく低いような気がします。
今回作ったアプリの利用シーンは複数人での会話を想定しているので、ここの精度が鍵となるのですが
うまいこと動作しないことが多々。難しいですねーほんと。

***改善点③:使えるブラウザが限定的***
ラムダさんの動画でも言及されていますが、今回利用しているWeb Speech APIは対応ブラウザが結構
限定的です。最新のバージョンではモバイルのSafariにも対応していると記載はあるものの、自分が試した感じ
動かず。。。Chromeが一番安定して使えるのでChromeでお試しください。

# 感想は？
実用性のないアプリを生成してしまったが色々勉強になったからいいか。。
（UIライブラリはいつものMUIではなく、Chakura UI使ってみり、割と初めて尽くしなことがあったので
勉強にはなりました。）
って感じです。
最初はReact Nativeを使って人生初のモバイルアプリを作ってみたかったのですが、音声をテキスト化する
部分で挫折しました。。Expoとかもそのときに少しだけ勉強したのでいつか記事にしたいですね。
今回作ったアプリは時間あったら改善しようと思います。多分しないけど。
symbol-bootstrap でパスワードが通らなくなる件の原因と解決策

下記コマンド実行時に求められるパスワードを正しく入力しているにも関わらず、パスワードが異なるというエラーが発生する。
- `symbol-bootstrap config -p mainnet -a dual -c my-preset.yml --upgrade`
- `symbol-bootstrap compose --upgrade`


## 原因

### 発生原因

- 2023/10/24 より前に symbol-bootstrap でノードを構築した
- 2023/10/24 以降に symbol-bootstrap を更新した


### 根本原因

symbol-bootstrap で使用される crypto-js パッケージのバージョンが異なるから。

2023/10/24 より前では crypto-js@<font color="1e90ff">**4.1.1**</font> がインストールされるが、
2023/10/24 以降になると crypto-js@<font color="1e90ff">**4.2.0**</font> がインストールされる。

この crypto-js パッケージのバージョン 4.1.1 以前と 4.2.0 で互換性がない。
つまり 4.1.1 で暗号化されたものは、 4.2.0 で復号化できない。逆もまた同様。


#### crypto-js のバージョン確認方法

```bash
cat /usr/lib/node_modules/symbol-bootstrap/node_modules/crypto-js/package.json | grep version
```
環境によってはグローバルの node_modules ディレクトリの場所が異なると思う。上記と異なる場合は、`npm root -g` または `npm list -g` で場所が分かる。




## 解決策

### GitHub からクローンしてインストールする方法

これはづーさんが見つけたやり方。詳しくは下記参照。

https://qiita.com/dusanjp/items/67f5099ec351e5eefa6f

symbol-bootstrap を GitHub からダウンロードすると、 packeage-lock.json が存在するため crypto-js のバージョンが 4.0.0 に固定され復号可能となる。


### symbol-bootstrap-util を使う方法

変換器を作成してみました。

https://www.npmjs.com/package/symbol-bootstrap-util

symbol-bootstrap-util をインストール。
```bash
sudo npm i -g symbol-bootstrap-util
```

現在の addresses.yml を退避。
```bash
mv target/addresses.yml target/addresses.yml.bak
```

addresses.yml 変換。
```bash
symbol-bootstrap-util conv -i target/addresses.yml.bak -o target/addresses.yml
```

ウィザードを使用して構築した場合、custom-preset.yml の中にも暗号化した秘密鍵が入っているので、同じようにバックアップを取った上で変換する。
```bash
mv custom-preset.yml custom-preset.yml.bak
symbol-bootstrap-util conv -i custom-preset.yml.bak -o custom-preset.yml
```

`symbol-bootstrap config` や `symbol-bootstrap compose` のパスワードが通るようになっている***はず！***

symbol-bootstrap-util は、もう必要ないのでアンインストール。
```bash
sudo npm un -g symbol-bootstrap-util
```

バックアップしたファイルも必要ないので削除。
```bash
rm target/addresses.yml.bak custom-preset.yml.bak
```
<details><summary>[備忘録] npm でバージョンが異なるパッケージをインストールするには</summary>

#### [備忘録] npm でバージョンが異なるパッケージをインストールするには
こんな感じにエイリアス付ける。types がコンパイル時に「重複してるヤツあるぞ！」って言うてくるので、namespace を変えるパッチ当てた。
```bash
npm i crypto-js411@npm:crypto-js@4.1.1
npm i crypto-js420@npm:crypto-js@4.2.0
npm i @types/crypto-js411@npm:@types/crypto-js@4.1.1
npm i @types/crypto-js420@npm:@types/crypto-js@4.2.0
```
packeage.json のバージョン指定から `^` を外す。
```packeage.json
    "@types/crypto-js411": "npm:@types/crypto-js@4.1.1",
    "@types/crypto-js420": "npm:@types/crypto-js@4.2.0",
    "crypto-js411": "npm:crypto-js@4.1.1",
    "crypto-js420": "npm:crypto-js@4.2.0",
```

</details>
Data Lake と Data Ware Houseの違い

Google Cloud の勉強を記録するためのメモ。

混同しがちな 「Data Lake」 と 「Data Ware House(DWH)」の違い。

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

## Data Lakeとは

Data Lakeは、大量の Raw Data を保存するための場所。
データ形式は統一性がなくても、とにかく生のデータをそのままストックすることに意味がある
（=構造化されたデータ、非構造のデータ問わず保存する）

Google Cloudでは、Cloud Storageが代表的なサービス。

## Data Ware House とは

Data Ware House は、Data Lake からデータ分析に利用できるよう、データを構造化してストックする場所。意志決定のため、目的別に編成され、統合された時系列で、削除や更新しないデータの集合体。

Google Cloudでは Big Query が代表的なDWHのサービス。

## Data Pipeline（データパイプライン）とは

Data Lakeにストックされたデータを、DWHで利用できるように生データを加工し、DWHへインポートするための手順。データの構造化→インポートを処理する手順を指す。

Google Cloudでは、Data Flow やData Prepが代表的な Data Pipeline 構築のためのサービス。
AndroidタブレットにTermuxを導入する

# 首記の件は、多くの可能性を秘めています。

この小さなアプリケーションは、デバイスを機能するLinux環境に変えることができます。例えば、

- Calcurseを使用すれば、予定管理が簡単になります。
- Todo.txtは、日々のタスクを整理し、
- Gitはプロジェクトのバージョン管理を助けます。
- Rcloneはクラウドストレージへのアクセスを提供し、
- Yt-dlpはお気に入りの動画をダウンロードするためのツール。
- Node.jsやHonkitは、静的サイトを作成する際に役立ちます。

## Termuxはさまざまなパッケージや...

カスタマイズオプションを提供しています。

### あなたがプログラマーであれば、

- Pythonや
- Rubyなどの言語を
 
インストールしてコーディングすることができますし、

### システム管理者であれば...

- SSHや
- Mosquitto（MQTTブローカー）などの

ツールを利用してリモートで作業することも可能です。

## TL;DR

Termuxを使用することで、これらすべてのツールが手のひらの上で利用可能になります。

Termuxを導入することで、Androidタブレットが強力なワークステーションに変わります。仕事でもプライベートでも、このアプリケーションはあなたの生産性を高めるための強力な味方となるでしょう。

## JFYI: メールの管理には...

**K-9 Mail**が最適です。このオープンソースアプリケーションは、使いやすさと機能性を兼ね備えており、Androidユーザーにとって優れた選択肢となります。

## Refs

- https://calcurse.org
- https://todotxt.org
- https://git-scm.com
- https://honkit.netlify.app/
- https://rclone.org/
[回避方法] next-authとFirebaseでGoogleログインすると500エラーが出る

# はじめに

next-authでGoogleログインを実装したときに躓いたことをまとめます
注意 : この記事は根本解決していないため現在も原因を探っています

# 問題

next-authを使ってGoogleでログインができることをローカルでたしかめたアプリケーションをFirebaseでデプロイしました

しかし、なぜか以下のエラーが出ました

```
リクエスト URL:
https://settlement-f6be6.web.app/api/auth/signin/google?prompt=login
リクエスト メソッド:
POST
ステータス コード:
500 Internal Server Error
リモート アドレス:
[2620:0:890::100]:443
参照ポリシー:
strict-origin-when-cross-origin
```

# わかったこと

FirebaseではなくVercelにデプロイしたところうまくログイン認証することができたのでなにかFirebaseに起因してそうなところまでわかりました

# 解決方法

現在探していますので、わかる方はコメントください

# おわりに
とりあえずわかっていることと回避できた方法だけを記事にしました
解決方法も分かり次第こうしんしていきます
BizRobo!のパスワード管理とは~パスワードストアについて~ 

就業先では、RPAツールのBizRobo!を使用しています。BizRobo!開発で悩み、BizRobo!ナレッジベースで日々検索しています。

RPAは、さまざまなシステムにログインし、ログインしたサイトからデータを取得することがあります。しかし、ログインするためのパスワードを直接RPAに記入することは、セキュリティ的に問題があります。そのため、BizRobo!には、パスワードストアというパスワード管理機能が用意されています。

今回は、BizRobo!のパスワードストアについて共有いたします。

※時間が経過して変わってしまった箇所や間違っている箇所、不適切な表現があるかもしれませんが、その時は都度修正いたしますので、ご指摘いただけると幸いです。


## パスワードストアとは
さまざまなシステムに入るには、ユーザー名とパスワードを入力し、ログインする必要があります。
しかし、RPAにアカウント情報を文字列として組み込む訳にはいきません。
パスワードストアとは、BizRobo!が Management Console（以降、MC）に実装されたレポジトリ機能の1つです。

パスワードストア機能を用いることで、開発者がパスワードを知らなくても、ターゲットシステムにログインできるようにRPAの開発をすることができるようになります。

まず、パスワードストアの使い方を簡単に説明します。
1. MCの「リポジトリ」タブ＞「パスワードストア」タブからパスワードを登録します。
2. DSで「パスワード取得」ステップを設定します。この時、MCで設定したパスワード情報を登録する必要があります。
3. 「パスワード取得」ステップで表示されたパスワードアクセストークンをMCに設定します。
これにより、DSでRPAを開発しながら、パスワードを取得できるようになります。


## 就業先で出くわしたエラー
就業先で、パスワードストアを利用しています。
しかし、パスワードストアの使い方に慣れなかったため、就業先でエラーを発生させたことがあります。その出来事を共有したいと思います。

#### スニペットを改修した場合
就業先では、MC内に3つのプロジェクトがあります。1プロジェクトに25個前後のRPAがあり、共通部品として、メール送信スニペットを用意しています。
メール送信スニペットを改修した後にアップロードした際、パスワードアクセストークンを設定する必要がありますが、一部漏れてしまいました。
それが原因で、MCでのスケジュール実行に失敗し、エラーが発生してしまいました。

#### 「パスワード取得」ステップがあるロボットをDSで実行させた場合
「パスワード取得」ステップがあるロボットをDSで実行させた時に、以下のエラーが発生してしまいました。原因は「Password Store client」権限がないことでした。
Error from the Lookup Password action. Error from the Password Store: Password Access token not found, please make sure you have the correct token in the Password Store.
「パスワード取得」ステップがあるロボットをDSで実行させる前に、MCにて権限を確認することをオススメします。


## BizRobo!パスワードストアに関する参考URL
パスワードストアについて整理した際、参考にしたサイトをまとめます。

以下は、パスワードストアの設定方法をまとめてあります。これを読むだけで、パスワードストアの設定は十分です。
[パスワードストアの使用方法](https://my.bizrobo.com/knowledge/detail/360045147832)

MCにアップロードした際に、パスワードアクセストークンが外れてしまう仕組みを調べていた際に見つけたサイトです。パスワードストアの仕組みが書いてあります。RPAテクノロジーズ株式会社のメンバーが記載している記事のため、とても参考になります。
[パスワードストア利用時の「トークン更新漏れに ご注意!!」という話](https://qiita.com/ParakeetOnTheHead/items/dee1e27194a353716bfb)

「パスワード取得」ステップが組み込まれたRPAをDSで実行させた際、「パスワード取得」ステップでエラー終了してしまうことがあります。その原因を調査した際に見つけたサイトです。
[「パスワード入力(Enter Password)」ステップ](https://my.bizrobo.com/knowledge/detail/360056913971)
[パスワードストアの使用で認証（401）エラーになる](https://knowledge.bizrobo.com/hc/ja/articles/360027607511)
[Password Storeのバージョンごとの仕様変更について](https://my.bizrobo.com/knowledge/detail/360027504791)


## 最後に
BizRobo!のパスワードストアについて解説いたしました。

パスワードストアについて理解が足りませんでしたが、今回の調査や整理で、パスワードストアの理解が深まりました。
パスワードストアは、パスワードを管理する上で重要な機能です。パスワードが漏れてしまった場合、重大なセキュリティ事故につながることがあります。パスワードストアは安全にRPAを活用するために大事な機能だと感じました。

今回の記事が、RPA開発で悩んでいる人の為になれば幸いです。
wslで、最小のカーネルをコンパイル その17

# 概要
wslで、kernel.elfのコンパイル、やってみた。
配列のアドレスを取得する実験をしてみた。

# サンプルコード

```

#include <stdio.h>

unsigned char ram[300];

int main(void) {
    printf("ok ");
    printf("%x \n", ram);
    printf("%x \n", (int) ram);
    printf("%x \n", (int) &ram);
    printf("%x \n", (int) &ram[0]);
    printf("%x \n", (int) ram & 0xff);
    printf("%x \n", (int) ram >> 8 & 0xff);
    printf("%x \n", (int) ram >> 16 & 0xff);
}


```

# 実行結果

```
ok 404040 
404040 
404040 
404040 
40 
40 
40 
```

以上。
App Store でアプリを配信する際にiPhoneだけを対象にする（iPadを除外する）

今回、新アプリをリリースする際に <b>iPhoneのみ対応、iPadには非対応</b>という形を試してみました。

これにより、iPhoneにはインストールできるがiPadにはインストールできない、という形が実現できました。

## まず注意点です
[App レビューガイドライン](https://developer.apple.com/jp/app-store/review/guidelines/)（App Store レビューガイドラインから名称が変わりました！）では、iPadを対象から除外することは避けるように求められています。
> 2.4 ハードウェアの互換性
> 2.4.1ユーザーがアプリを最大限に活用できるように、iPhone向けのアプリは可能な限りiPadでも実行できるようにしてください。

つまり、iPadを除外する正当な理由がない場合はアプリ審査リジェクト対象となる可能性があります。ちなみに私のアプリにはiPadを除外する理由があったためかアプリ審査で指摘されることはありませんでした。

## 対応方法
Appleのプラットフォームでは、デバイスに対応しているアプリだけをユーザがダウンロードできるように [UIRequiredDeviceCapabilities](https://developer.apple.com/documentation/bundleresources/information_property_list/uirequireddevicecapabilities/)キーが用意されています。

Xcodeでの開発時にプロパティリストにUIRequiredDeviceCapabilitiesキーを追加し、そのValueとして "telephony"を投入します。

これにより電話アプリであることを宣言でき、結果として電話機能のないデバイス（iPadやiPod touchなど）にはインストールができなくなります。

簡単ですね。

## 新規アプリにしか適応できない
アプリを一度リリースしてしまうと、UIRequiredDeviceCapabilities キーに対するvalueの追加はできなくなります。その理由は次のように説明されています。

[デバイス機能の要件](https://developer.apple.com/jp/support/required-device-capabilities/)
> アプリのアップデートを提出する場合、従来の機能要件を維持するか、要件を緩和することのみ許可されています。新しい要件を含むアップデートでは、以前にアプリをダウンロードした一部のユーザーがアップデートを実行できなくなる可能性があるためです。

つまり、このキーは初回リリース時に設定しておく必要があります。

## 最後に
上記の情報は私が夢で見た内容をテキトーに描いたものです。真実ではありません。
航空宇宙エンジニアが普段使っているスクリプト

自分が使っている日々の業務を効率化するスクリプトを紹介します。
「十分に発達した科学技術は、魔法と見分けがつかない」
プログラミングができない時の私にとって、これらはまさに魔法のようです

# Outlook関連
- Outlookからアドレス帳を取得し、CSVファイルにするスクリプト
- 取得したCSVから複数キーワードでアドレスを検索するスクリプト
- 検索結果のアドレスをコピペできるフォーマットでクリップボードへ入れるスクリプト
- Outlookにスケジュールを追加するスクリプト
- Outlookに休日をまとめて入れるスクリプト
- Outlookのスケジュールを抽出するスクリプト
- Outlookでメールを送信するスクリプト
- Outlookのメールを一括で取得するスクリプト

# Creo関連
- Creoの設定(config)を行うスクリプト
- Creoのパーツツリーを取得するスクリプト
- Creoのパラメータを設定するスクリプト
- Creo用の材料をDBから作成するスクリプト
- Creoの材料設定を行うスクリプト
- Creoでアセンブリと部品を追加するスクリプト
- Creoのファイルを開くスクリプト
- Creo作業フォルダを綺麗にするスクリプト

# CAE関連、設計計算関係
- Nastranのインプットファイルを作成するスクリプト
- Nastranのインプットファイルから情報を抽出するスクリプト
- MSC MARCのインプットファイルから情報を抽出するスクリプト
- 様々なCAEインプットファイルのパラメータを変更するスクリプト
- さまざまなCAEソルバーをsubprocessで実行するスクリプト
- Nastranのアウトプットファイルから直接結果を取得するスクリプト
- MARCのアウトプットファイルから直接結果を取得するスクリプト
- 材料物性をDBから取得して、ソルバに合わせてアウトプットするスクリプト
- 取得した結果をParaViewでGUIを通じて可視化するスクリプト
- 取得した結果をグラフにするスクリプト
- 多変量で非線形性の強いデータをモデル化するスクリプト
- 一次元の熱解析を実行するスクリプト
- STLから任意の断面を取得し、その断面特性を計算するスクリプト
- markdowmをpowerpointに変換するスクリプト

# TeamCenter関係
- TeamCenterからリビジョンルールを適用したBOMデータを取得するスクリプト

# redmine関係
- redmineの情報を取得するスクリプト
- redmineにタスクを入れるスクリプト
- redmineのタスクを更新するスクリプト

# 3Dデータ関連
- 各種中間ファイルを読み込むスクリプト
- 各種中間ファイルを変換するスクリプト
- 様々なCADデータをSTLに変換するスクリプト
- FreeCADで形状を作成、編集、または削除するスクリプト
- Blenderでメッシュデータを作成、編集、または削除するスクリプト
- 複数の断面をつなげてCADデータを作成するスクリプト

# 図面関係
- 図面のdiff(画像)を見るスクリプト

# タスク管理
- タスク管理アプリからデータを取得するスクリプト
- 今日の作業と予定をmarkdownで纏めるスクリプト

# Chrome・HTML関連
- Seleniumでブラウザ操作を自動化するスクリプト
- Excelの勤怠管理ファイルから、勤怠サイトや工数サイト(IEモード)にデータを入力・登録するスクリプト
- HTMLから内容やリンクを抽出するスクリプト
- HTMLからテーブルを取得するスクリプト

# MS Office関連
- Wordからテキストを抽出するスクリプト
- PowerPointからテキストを抽出するスクリプト
- Excelを操作するスクリプト
- Excel帳票に値を入れて出力するスクリプト
- OfficeファイルをPDFに変換するスクリプト

# PDF関連
- PDFを分割するスクリプト
- PDFを結合するスクリプト
- PDFを暗号化するスクリプト
- PDFの暗号を解除するスクリプト

# 画像関連
- 画像の差分を見つけるスクリプト
- 画像サイズを一括でリサイズするスクリプト

# ファイル操作関連
- ファイル名を一括で変更するスクリプト
- フォルダやファイルを一括でコピー、移動、削除するスクリプト

# Git関連
- Git操作を自動化するスクリプト

# その他
- クリップボード内の文字列をプレーンテキストにするスクリプト
- パスワードを生成するスクリプト
- remote desktopで端末を使用しているユーザを取得するスクリプト
- 会議室を予約するスクリプト
- ファイルのハッシュ値を取得するスクリプト
- 重複ファイルを発見するスクリプト
- markdownをリンク毎移動するスクリプト
- ポートが開いているかを確認するスクリプト
MySQL8の2038年問題：CREATE TABLEできなくなるがバグじゃない

# はじめに
MySQL8の2038年問題を調べると、TIMESTAMP型のオーバーフローに関する情報が多数ヒットします。
ではそれだけ対応すればMySQL8でも2038年を超えられるのかな？と疑問を持って確認してみたら、やはり他にもありましたというお話。

# CREATE TABLEできなくなる
サーバの時刻を2038年以降に設定して開発中のシステムの動作検証をすると、ダンプしたデータを復旧できないという問題が発生。解析するとCREATE TABLEを実行できなくなることがわかりました。

実行時のログは次のとおり。ERROR 3507が返されます。

```
Operation failed: There was an error while applying the SQL script to the database.
Executing:
CREATE TABLE `sys`.`new_table` (
  `id` INT NOT NULL,
  PRIMARY KEY (`id`));

ERROR 3507: Failed to update tables dictionary object.
SQL Statement:
CREATE TABLE `sys`.`new_table` (
  `id` INT NOT NULL,
  PRIMARY KEY (`id`))
```

# でもバグじゃないらしい
Oracleに問い合わせをしてみました。回答は「Not a bug.」。
この挙動も日付のデータ型（signed 32-bit integer）が起因しているそうです。

データ型は標準SQLで定義されているためOracleはその改訂待ち。
間違いなく2030年までに改訂される見込みで、改訂されるとすぐに反映する準備ができているとのことです。

> What you report is truly a bug, but the one on which we can not do anything.
> 
> As per the SQL standard, the time is defined as a signed 32-bit integer. This is in line with the ISO standard.
> 
> Hence, we are waiting on the new standard where this variable will be 64 bits wide. Our Worklog entry for that change is already prepared, but the current standard has not changed interim.
> 
> Until that is done , we can not do anything, just like it is noted in the bug report to which you refer.
> 
> Not a bug.

> We can assure you that ISO committee is working on the solution.
> 
> As soon as the new standard is revealed by that committee, we shall implement it immediately.
> 
> Currently, there are two alternative solutions. One is to use unsigned 32-bit integer and the other one is to use singed 64-bit integer.
> 
> When the new standard comes out, we shall implement it immediately.
> 
> We are sure that this will happen before the year 2030.


https://bugs.mysql.com/bug.php?id=114393


# 結論
MySQLの少なくとも8以下で稼働させているシステムを2038年以降も継続して利用したい場合、必ず次期バージョンに移行させましょう。
といっても、公式のサポートが切れるまでに都度移行していれば問題は起きないでしょう。

また、MySQLのTIMESTAMP型は原則使わないようにとされていることが多いですが、アップデートによりこの範囲も改訂される可能性が高いのではないでしょうか。
【Next.js】GitHubでPlaywrightを使って自動テストをする

# はじめに

こんにちは、プログラミングを始めて約3年のエンジニアのkeitaMaxです。

今回は前回作成したPlaywrightのテストを、GitHubActionsを使用してGitHub上で使ってみたいと思います。

前回の記事

https://qiita.com/keitaMax/items/28a414855c81b4c72536


# GitHubActionsを作成

Playwrightをインストールしたときに、`.github/workflows/playwright.yml`ができていましたので、それを使用します。

```yaml:playwright.yml
name: Playwright Tests
on: [pull_request]

jobs:
  test:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: lts/*
    - name: Install dependencies
      run: npm ci
    - name: Install Playwright Browsers
      run: npx playwright install --with-deps
    - name: Build
      run: npm run build
    - name: Run Playwright tests
      run: npx playwright test
    - uses: actions/upload-artifact@v4
      if: always()
      with:
        name: playwright-report
        path: playwright-report/
        retention-days: 30
```

# GitGubにPushする

GitHubにPushしてみます。

そうすると以下のようにテストが成功します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/aa6f24f9-3555-79ce-fe0f-3ed7cb935a73.png)


# テストを失敗させる

さいごに、ちゃんと動いているかどうかを確かめるために、テストを失敗させようと思います。

```ts:count.spec.ts
test('has title', async ({ page }) => {
   await page.goto('http://localhost:3000/count');
});
```
`example.spec.ts`の記述があるので、URLの中を空にしてみます。

```ts:count.spec.ts
test('has title', async ({ page }) => {
   // await page.goto('http://localhost:3000/count');
   await page.goto('');
});
```
この状態でテストを実行してPushしてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/9423f36f-c44a-a100-f57c-a0f725116c41.png)

このようにエラーが出ているのを確認することができたので、正しく動いているのを確認することができました。


# おわりに

この記事での質問や、間違っている、もっといい方法があるといったご意見などありましたらご指摘していただけると幸いです。

最後まで読んでいただきありがとうございました！
ログイン中のユーザー情報を取得する方法

Laravel単体の時は
```
$profile = Auth::user();
```
これで問題なかった。

vueを合わせるために
api.php→コントローラー→vueで受け取り表示
だと上記がうまくいかなくて
以下でうまくいきました。

```
    public function index()
    {
        // $profile = Auth::user();
        // $profile = Auth::user()->get();
        // $profile = Auth::guard('api')->user()->get();
        // $profile = Auth::guard('api')->user()->get();
        // $profile = Auth::guard('api')->user()->get();
        // →これらはユーザー情報を取得できなかった

        // ⭐️これでいけた
        $id = Auth::id(); 
        $profile = User::where('id', $id)->get();
        return $profile;
    }
```
Xquartz.app で xterm を起動したくない

デフォルトでは /opt/X11/bin/xterm を起動するようになっているので

<pre>❯ defaults read org.xquartz.x11
{
    "NSWindow Frame x11_apps" = "1291 362 454 299 0 0 3440 1415 ";
    "NSWindow Frame x11_prefs" = "713 152 484 336 0 0 3440 1415 ";
    SUHasLaunchedBefore = 1;
    SULastCheckTime = "2024-03-18 23:29:35 +0000";
    "app_to_run" = "/opt/X11/bin/xterm";
    "apps_menu" =     (
    );
    "cache_fonts" = 1;
    "done_xinit_check" = 1;
    "enable_iglx" = 0;
    "login_shell" = "/bin/sh";
    "no_auth" = 0;
    "nolisten_tcp" = 1;
    "startx_script" = "/opt/X11/bin/startx -- /opt/X11/bin/Xquartz";
}</pre>

以下のように無害なコマンドに置き換えてあげると良いようです。

<pre>❯ defaults write org.xquartz.X11 app_to_run /usr/bin/true</pre>

その後は以下のような設定になり xterm は起動しなくなりました。　

<pre>❯ defaults read org.xquartz.x11
{
    "NSWindow Frame x11_apps" = "1291 362 454 299 0 0 3440 1415 ";
    "NSWindow Frame x11_prefs" = "713 152 484 336 0 0 3440 1415 ";
    SUHasLaunchedBefore = 1;
    SULastCheckTime = "2024-03-18 23:29:35 +0000";
    "app_to_run" = "/usr/bin/true";
    "apps_menu" =     (
    );
    "cache_fonts" = 1;
    "done_xinit_check" = 1;
    "enable_iglx" = 0;
    "login_shell" = "/bin/sh";
    "no_auth" = 0;
    "nolisten_tcp" = 1;
    "startx_script" = "/opt/X11/bin/startx -- /opt/X11/bin/Xquartz";
}</pre>

https://apple.stackexchange.com/questions/53734/how-do-i-prevent-x11-opening-an-xterm-when-it-starts
you-should-useで大量のaliasと共に生きる(zsh)

# 要約
aliasを貼っているのに使用されていない場合に、利用可能なaliasを提案してくれる[you-should-use](https://github.com/MichaelAquilina/zsh-you-should-use) pluginをインストールする方法から、動作イメージまでを記載しています。

# 大量のエイリアス
私は`oh-my-zsh`を使っているのですが、[プラグイン](https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins)によるaliasが多すぎてほぼ覚えていません。

https://github.com/ohmyzsh/ohmyzsh

覚えるのが面倒なので[gitプラグイン](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/git)の`git add` から `git push`までのaliasしか使っていませんでした。
```sh
ga='git add'
gcmsg='git commit -m'
gp='git push'
```

確認してみると1747個もありました。。:disappointed_relieved:
alias貼りすぎてよくわからん！
```sh
alias |wc -l
1747
```

# you-should-useとは？
一言で言えば、aliasを貼っているのに使われていない場合に「こんなalias貼ってるけど、使わないんか？」と提案してくれます。

https://github.com/MichaelAquilina/zsh-you-should-use

## インストール
- リポジトリをクローンします
 [gitプラグイン](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/git)でaliasを貼っている場合は`gcl <url>`.
```sh
git clone https://github.com/MichaelAquilina/zsh-you-should-use.git $ZSH_CUSTOM/plugins/you-should-use
```
- 私は[oh-my-zsh](https://github.com/ohmyzsh/ohmyzsh)を使っているので以下のようにプラグインを追加します
```.zshrc
plugins=(
    # ...
    you-should-use
    # ...
)
```

## 動作イメージ
プラグインを入れたら追加の設定や呼び出しキーは不要です。(素晴らしい :clap: )

試しに`ga='git add'`というaliasを貼ってるのを知らずに、`git add`を実行してみます。
```sh
git add .
Found existing alias for "git add". You should use: "ga"
```

`ga`というaliasが使えるよ！と教えてくれました :thumbsup: 
持続可能なalias生活を！
顔検出 (WPF+OpenCV)

<FONT COLOR="BLUE">

#### 画像処理・解析用ライブラリ OpenCVで顔検出する

</Font>


::: note info
1.使用するライブラリは下記画像を参考にnugetで入れます。
2.githabにカスケード識別器の定義データがあるので必要なものをDLします。
　https://github.com/opencv/opencv/tree/master/data/haarcascades

3.正面の顔検出でしたら、haarcascade_frontalface_alt.xmlです。
4.ファイル名はhaarcascade_frontalface_default.xmlで保存。
5.ABC.xml等と変えたりすると動きません。例外でます。
6.このファイルをデスクトップに配置。顔認識するjpg画像もデスクトップに配置。
7.実行すると検出結果画像が出ます。あわせて人数がタイトルに表示されます。
:::

・人数カウントして店の混雑具合をWebに自動的に開示する等。
・PC接続カメラで動画を撮影 -> 数秒毎にjpg変換 -> OpenCVで検出、人数算出も
　簡単にできる。 と思ったらもっとスマートな方法があった↓。
 
・動画版。OpenCV等専用ライブラリ使わず自力で作ってみようと思う。
https://kimamani89.com/2019/09/17/post-506/

・OpenCVについて改めて書くまでもなく資料は色々あるので、↓など参照。
https://qiita.com/tnoce/items/c819c85a85c16d246be8

上記リンク先に画像があったのでその画像で顔認識してみる。
入力画像に四角のバウンディングボックスが追加表示される。

![B - コピー (8).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821882/be804a44-981a-7ea5-24ac-f500c694a8dc.jpeg)

左が今回作成したもの。右は上記リンク中にある恐らく19～21年検出結果。

<FONT COLOR="BLUE">

### 1.Nuget
</FONT>


![NUGET.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821882/776e66d3-c370-1a2b-9dec-449dcf890519.jpeg)

<FONT COLOR="BLUE">

### 2.WPF (C#)
</FONT>


``` c#
using OpenCvSharp;
using OpenCvSharp.WpfExtensions;
using System;

namespace OPENCV {

    public partial class MainWindow : System.Windows.Window {
        public MainWindow() {
            InitializeComponent();

            var face_cascade = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "haarcascade_frontalface_default.xml");
            int cnt=0;

            //顔の矩形を抽出
            using (Mat mat = new Mat(System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "3.jpg"))) {

                //グレースケールに加工(精度向上の為)
                var gray = new Mat();
                OpenCvSharp.Cv2.CvtColor(mat, gray, OpenCvSharp.ColorConversionCodes.RGB2GRAY);

                //顔を検知
                using (CascadeClassifier cascade = new CascadeClassifier(face_cascade)){
                    foreach (OpenCvSharp.Rect rectFace in cascade.DetectMultiScale(gray)){
                        OpenCvSharp.Rect rect = new OpenCvSharp.Rect(rectFace.X, rectFace.Y, rectFace.Width, rectFace.Height);
                        Cv2.Rectangle(mat, rect, new OpenCvSharp.Scalar(0, 0, 255), 4);
                        cnt++;
                    }
                }
                ImageData.Source = mat.ToWriteableBitmap();
            }
            Title =cnt.ToString()+"人";
        }
    }
}
```

<FONT COLOR="BLUE">


### 3.WPF (XAML)

</FONT>

``` xml
<Window x:Class="OPENCV.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:OPENCV" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800">
   
    <Grid>
        <Image x:Name="ImageData" Margin="5,5,5,5"/>
    </Grid>

</Window>
```
「if a != a」をそっとしておいて

## Q. ソースコードに「if a != a」という条件分岐があった。このブロックを安易に削除してはいけないのはなぜか？

**回答**

aがNaNかどうかを判定しているから。
- - -

NaNはIEEE 754 で定められた特殊な値であり、Pythonでは`math.nan`や`numpy.nan`などがこれに該当します。

NaNはNaNを含むすべての値との比較演算`==`の結果が`False`になり、`!=`は`==`の結果の否定であるため`True`になります。

したがって、aがNaNのとき `a != a`は`True`になり、分岐先のプログラムが実行されるのです。


> The IEEE 754 special values of NaN, inf, and -inf will be handled according to IEEE rules. Specifically, NaN is not considered close to any other value, including NaN. 
> 
> [PEP 485 – A Function for testing approximate equality](https://peps.python.org/pep-0485/#handling-of-non-finite-numbers)

> **Comparison between NaN and any floating-point value x (including NaN and ±∞)**
> | Comparison | NaN ≥ x | NaN ≤ x | NaN > x | NaN < x | NaN = x | NaN ≠ x |
> | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
> | Result | False | False | False | False | False | True |
> 
> From these rules, comparing x with itself, x ≠ x or x = x, can be used to test whether x is NaN or non-NaN
>
> [NaN - Wikipedia](https://en.wikipedia.org/wiki/NaN)

とは言え、`if pandas.isna(a)`や`if numpy.isnan(a)`の方が意図が分かりやすいですね。もし`if a != a`と遭遇したらそっとしておきましょう。
pygameでの文字列の位置合わせ

# はじめに
pythonのゲーム用ライブラリpygameでちょっとしたゲームを作成したのだが、文字列の位置合わせに若干時間を要してしまったのでまとめた。

# 環境
次の環境で確認

+ pygame V2.5.2
+ Python V3.9.13
+ Windows 10 Pro (64bit) 22H2


:::note info
pygameモジュールのバージョンを確認するコマンド

```
python3 -m pip show pygame
```
:::


# フォントを指定して文字列を表示する

以下のプログラムを実行すると

```py
import pygame

BLACK = (0,0,0)             # 黒色
RED   = (255,0,0)           # 赤色
WHITE = (255, 255, 255)     # 白色

WIDTH  = 320                 # 画面の横幅
HEIGHT = 240                 # 画面の高さ

X = WIDTH/2                  # 基準点（X座標）= 画面の中央
Y = HEIGHT/2                 # 基準点（Y座標）= 画面の中央

FONTNAME = None             # デフォルトフォント（日本語不可なので注意）
FONTSIZE = 40               # フォントサイズ

POINTSIZE = 5               # 基準点のサイズ

STRING = 'Text'               # 表示する文字列（日本語不可）
 
pygame.init()

clock = pygame.time.Clock()

screen = pygame.display.set_mode((WIDTH, HEIGHT))

font = pygame.font.SysFont(FONTNAME, FONTSIZE)

text = font.render(STRING, False, BLACK, WHITE)           # 黒文字、白背景にする

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:                     # 閉じるボタンが押された時
            pygame.quit()                                 # プログラム終了

    screen.fill(BLACK)                                    # 画面をクリア
    screen.blit(text, (X, Y))                             # 基準点を指定して文字列描画
    pygame.draw.circle(screen,  RED, (X, Y), POINTSIZE)   # 基準点を描画
    pygame.display.update()                               # 画面更新
    clock.tick(30)
```

次のような画面が表示される

![3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/774174/6d5ff15d-be5c-ef5a-7908-66452a89f95f.jpeg)

フォントを指定して文字列を表示しているのだが、以下の行で基準点（赤丸、画面中央）を指定しているので基準点の右下（文字列の左上を起点）に文字列が表示されている。

```py
    screen.blit(text, (X, Y))                             # 基準点を指定して文字列描画
```

基準点の右下以外に文字列を表示したい場合（例えば、箱の左側に文字列を表示したい、等）は、`get_rect()`を使用してパラメータに「`topleft`（左上）」「`topright`（右上）」「`bottomleft`（左下）」「`bottomright`（右下）」「`center`（中央）」 等を指定すればよい。

例えば、基準点の左上（文字列の右下を起点）に文字列を表示したい場合は、先ほどの行を変更すればよい

(変更後)
```py
    text_rect = text.get_rect(bottomright=(X, Y))
    screen.blit(text, text_rect)
```

(実行結果)
![4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/774174/25d5f450-e1e7-2403-7a12-57924320f24a.jpeg)


# 文字列の位置合わせの考え方
文字列の位置合わせをするときは「``文字列のどの位置``を``基準点``に合わせるか」を指定する。一般的に使われる「右よせ」「左寄せ」、「上寄せ」「下寄せ」と同じになる。（難しく考えずに素直に考えればよい）

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/774174/8dc7ac69-93b8-4c18-94d7-d82d18e04dc1.jpeg)

:::note warn
「`基準点`に対して`文字列をどの方向に`合わせるか」ではないので注意
:::

![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/774174/46a8b18f-1519-395a-37c1-965b8b02c31b.jpeg)

`基準点`を基準に考えるか、`文字列`を基準に考えるかの違いなのだが、とにかく`文字列基準`と覚えておけばよい。

# 参考情報

+ [Pygame Documentation](https://www.pygame.org/docs/ref/surface.html?highlight=get_rect#pygame.Surface.get_rect)
Flutter環境構築メモ（Windows）

最近Flutterを触りだしたのでメモ。

# ダウンロード・インストール
## Flutter
以下からFlutterをダウンロードし任意の場所に展開する。
Flutter：https://docs.flutter.dev/release/archive?tab=windows

## Android Studio
Android Studio：https://developer.android.com/studio/archive
※ 言語をEnglishにして利用規約の同意を完了していないとダウンロード画面に遷移できない。

### インストール後の設定
以下によってプロジェクトごとにJDK、Flutterのバージョンを変えられる。
ただし、ターミナルでのバージョンはWindowsに依存している模様。

#### AndroidStudioで使用するJDKのダウンロード
・AndroidStudioを起動し、プロジェクトを作成または開いている状態。
・File - Project Structureを開く
・Project Settings - Project - SDK をクリック
・Add SDK - Download JDKをクリック
・使用するバージョンをダウンロード

#### AndroidStudioで使用するFlutterの設定
・AndroidStudioを起動し、プロジェクトを作成または開いている状態。
・File - Settingsを開く
・Languages & Frameworks - Flutterを選択
・Flutter SDK pathにインストールしたFlutterのパスを指定する。

# 参考になりそうなリンクをメモ
公式：https://docs.flutter.dev/
DartPad：https://dartpad.dev/
Flutter Doc JP：https://flutter.ctrnost.com/
flutter-study.dev：https://www.flutter-study.dev/introduction/about-flutter
Android Studioショートカット：https://developer.android.com/studio/intro/keyboard-shortcuts
Androidデバイスを接続する方法：https://developer.android.com/codelabs/basic-android-kotlin-compose-connect-device?hl=ja#2
【C#】XMLドキュメンテーションを GitHub Copilot で生成する手順

# 生成AIを使ってXMLドキュメントを生成する

2024年3月ごろから 『Visual Studio + GitHub Copilot』で色々やっています。
今回は XML ドキュメントを AI で生成する方法について執筆したいと思います。

## 動作環境 

記事執筆時 2024/03/20 時点での環境です。以下の通りです。

```
IDE: Visual Studio Community 2022 - Version 17.9.3
言語: C# 
インストール済み拡張機能: GitHub Copilot - v1.156.0.0
```

GitHub の個人リポジトリを弄りながら検証したため、エディションは Community です。
勤め先プロジェクトの環境ではありません。

また時間の経過と共に Copilot が進化し、異なる結果になる可能性があります。
この点について、ご了承ください。 『2024/03/20』時点での結果です。

なおこの記事を GitHub Copilot にレビューしてもらったところ
『GitHub Copilot が動く要件を書くように』とのことでしたので、追記します。

```:GitHub Copilot 動作要件
GitHub Copilot には Visual Studio 2022 17.5.5 以降が必要です。
Visual Studio 2022 バージョン 17.4.4 ～ 17.5.4 の場合は、拡張機能バージョン1.84.0.1を使用します。
```

## ドキュメンテーションを生成する手順

手順は 1～4 で、画像を用いて説明します。
画像は私のドメイン駆動設計のエンティティ基底クラス実装時のものです。

実際の作業は10秒かからず終了します。

### 1. 生成したい範囲を選択し『Copilot に質問する』を実行。

![SS_2024-03-20_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416365/8ca1900b-49d0-c9dd-f556-d53695f7736f.png)

XMLドキュメントを生成したい範囲を選択し『Copilot に質問する』を実行します。

今回は複数のメソッドに対して実行したかったため4つ選択していますが
1つだけの選択でも問題ありませんし、クラス全体を選択しても大丈夫です。
選択対象はメソッドに限らず、プロパティやフィールドも有効です。

よく使うのであれば、ショートカットキー『Alt + /』は、覚えておいて損は無しです。

### 2. 生成プロンプトを実行する。

![SS_2024-03-20_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416365/fc0c0c1d-c012-3ae6-67bf-e1dba270f1cb.png)

※ コピペしやすいように、上記画像のプロンプトをコードブロックに記載します。
```prompt:GitHub Copilot プロンプト
選択範囲のXMLドキュメントを生成してください。日本語でお願いします。
```

プロンプトのキーワードは『選択範囲』『XMLドキュメント』『生成』です。
オプションワードとして『日本語』を入れないと英文で作成されるケースがあるため
確実に日本語で生成したい場合は、プロンプトで指示して下さい。

これは丁寧な指示の例ですが、もっと短くできると思います。

### 3. プレビューを確認し、生成に問題が無ければ承認する。

![SS_2024-03-20_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416365/6cf17969-ebc5-fd92-395f-959cc058207d.png)

Visual Studio にも記載がある通り GitHub Copilot は間違った解釈をする可能性があるため
承認を押す前に、挿入される内容を確認して下さい。

### 4. 生成結果が反映される。

![SS_2024-03-20_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416365/625d7d05-e970-1bf8-7a3b-699e7073da25.png)

無事に生成されました。

returns に若干、機械的な印象を受けますが、これは学習の問題でしょう。
他の XML ドキュメントの記述方法を参考に文章を書いているようですので
私の場合は、そのうち『～を返します。』などの記述をしてくれるようになるのではと予測しています。

または、外部から『XML ドキュメントは、このように書く』という指示書を作成するのも、非常に有効な手段です。

※ 外部参照については、また別途、記事を書く予定です。

## 応用例など

より詳細なXMLドキュメントを生成したい場合は、以下のようなプロンプトも有効です。

```prompt:GitHub Copilot プロンプト
選択範囲のXMLドキュメントを日本語で生成してください。
可能であれば remarks と example も記載してください。
```

少し試してみた感じ remarks は割と解釈しやすく、自動生成をしてくれることが多いです。
しかし example はなかなか書いてくれません。
絶対に書いてくれないわけではありませんが…
本当に有効活用したいのであれば、外部参照で学習させる必要がありそうです。

## まとめ

今まで仕事として担当したプロジェクトでは、ほとんどにおいて
　XMLドキュメントを記載する時間 >>> コーディングする時間
でしたが、これでだいぶ時間が短縮できそうです。

**（いや本当に今まで保守用XML記載してた時間を返してほしいレベル…）**

職場がまだ GitHub Copilot を導入していないのであれば
作業時間やコストパフォーマンスの面から導入を提案してみてはいかがでしょうか？
私は『自費で払ってもいいから入れてくれ』と直訴します。

## 自筆の関連記事

他にも GitHub Copilot を使用した記事をこれから執筆予定です。
自動でテストコードをキレイに生成できたことや、記事内にある『外部参照について』など
後日そのことを記事にして参考リンクにします。

※ これが Qiita の初投稿です。伝わりにくい点などがありましたら、申し訳ございません。
[WIP] #318 2024-03-17 駄菓子

## 5月24日にGoogle I/Oが開催
https://android-developers.googleblog.com/2024/03/google-io-24-save-the-date.html

geminiが話題になりそうな。
サイトには例年通り意味わからんパズルがあるみたい。

## Jetpack Composeのパフォーマンス最適化
https://getstream.io/blog/jetpack-compose-stability/

Composeの安定性を完全理解する記事。
まず、以下のフェーズを意識することが大事。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599059/d6af6b4a-200a-9de1-9396-bc86844c6d7f.png)

- Compositionは、Composable関数をスロットに割り当てる。これによりツリーを記録として残せるため、不要なreocmposeとかをなくせる。
- Layoutは、コンポーザブルノードの測定と配置を行う。それにより構造内の正確な位置を保証する。
- Drawingは、デバイスの画面にレンダリングする。

Compose　CompilerはComposable関数の引数を安定と不安定の二種類に分ける。これをrecomposeするかどうかの判断に用いる。

primitive型とかラムダ式、immutableなプロパティで構成されたデータクラス、@Stableや@Immutableマークをつけたクラスなどが安定とみなされる。

List, MapなどのintarfaceやAny型のようにコンパイル時に実装が読めない抽象クラスは不安定とみなされる。あと、mutableなプロパティを含むクラス。

新しい引数が渡されるとequalsメソッドで比較される。==

### Composable関数の推論について
Compose CompilerはKotlin-pluginで構築されているので、コンパイル時にソースコードをいじることができる。
その際にCompilerはComposable関数を
- Restartable
- Moveable
- Replaceable

の三つのグループに分類する。

### Restartableについて
コンパイラによって決定される。Restartableは型だよ。
そういう意味での推論。

### Compose Metrics
Compoes Compiler pluginを用いると複雑なコード部分の解析ができるようになる。
以下のファイルが生成される。

- module.json
    - skippableComposableとrestartableComposableの割合などが見れる
- composablex.txt
    - 特定のComposable関数の引数や安定かどうかなど関数の細かい状態がシグネチャ形式でわかる
- classes.txt
    - 特定のクラスの安定性についてどう判断したのかがわかる

### 不安定なクラスを安定なクラスに変換する方法
- @Immutable
    - プロパティが変更されることはないことを保証する
- @Stable
ReactとNext.jsの違い

# React と Next.js の違い

なんとなくは、分かっていましたが、実際説明するとなるとできない事に気が付きました。  
今回は、`React` と `Next.js` の特徴や違いについて、調べました。

## React

`React` は、フレームワークではなく、JavaScriptのライブラリです。  
コンポーネントで構成されています。コンポーネントで管理することで、変えたい部分だけをカスタムできるようにできます。コンポーネント化することによって、いろんな部分やページで使いまわして効率よく開発をすることができます。

参考：[React 公式ドキュメント](https://ja.react.dev/learn)

## Next.js

`Next.js` は、`React` のフレームワークです。  
`React` ベースのため、`Next.js` を使うには、`React` の知識が必要です。  
このフレームワークの特徴がいくつかあります。  
- `SSR`  
  → サーバーサイドでレンダリングできるため、`SEO` に強いアプリケーションの構築ができる
- 自動ルーティング  
  → pagesフォルダにあるファイルは、自動的にルートとして設定されるため、ページ作成の時間を縮小することができる
- 独自のコンポーネント  
  → `Next.js` には、いくつかコンポーネントがあり、中でも `Image` コンポーネントは、画像の最適化をしてくれる

参考：[Next.js 公式ドキュメント](https://nextjs.org/docs)
参考：[Next.js 公式ドキュメント - Components](https://nextjs.org/docs/app/api-reference/components)

## React と Next.js

上記から、`React` と `Next.js` は大前提として、ライブラリとフレームワークという点で違うということが分かりました。  
`React` は、使いたいときに呼び出して使える部品だということ、`Next.js` は、自動ルーティング機能など、開発しやすくなる枠組みだということです。

--- 

**ご覧いただきありがとうございました**

それぞれの特徴を踏まえたうえで、今後も開発を進めていきます。  
間違いなどございましたら、教えていただきたいです。