OmniAICreator/Qiita-1.07M huggingface dataset:
初心者がVBAでスクレイピングしてみた

# はじめに
初めてVBAを触り、Webサイトのスクレイピングをするまでにやったことの記録。

# やりたいこと
Webサイトに掲載されている各商品ページについて、特定のclassの3つ目に記載されている文言を抜き出し、Excelのシート上に書き出す。

※Excelのイメージ
| 商品名 | URL | 3つ目に記載されている文言 |
|:-:|:-:|:-:|
| 商品A | http:\\\xxx.com/xxx | ・・・ |
| 商品B | http:\\\xxx.com/yyy | ・・・ |

# 事前準備

## スクレイピングするための準備
「ツール」＞「参照設定」から以下にチェックを入れる。
・Microsoft HTML Object Library
・Microsoft Internet Controls
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319422/74846965-cb08-540f-54e3-47f50900bd67.png)

# ソースコード
class名は固定なので、ソースコードに埋め込み。
ExcelのA列のURLを読み取り、B列に要素を書き込む。

ChatGPT先生に色々お願いして書いてもらいました。

```vb
Sub ScrapeAndWriteToExcel()
    Dim ie As Object
    Dim html As Object
    Dim elements As Object
    Dim element As Object
    Dim targetURL As String
    Dim className As String
    Dim tagText As String
    Dim ws As Worksheet
    Dim lastRow As Long
    Dim i As Long


    ' クラス名を設定
    className = "example-class"
    
    ' 対象のシートを設定
    Set ws = ThisWorkbook.Sheets(1)
    
    ' URLが書かれているA列の最終行を取得
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

    
    ' IEオブジェクトを作成
    Set ie = CreateObject("InternetExplorer.Application")
    ie.Visible = False ' IEウィンドウを表示しない


    ' URLの数だけループ
    For i = 1 To lastRow
        ' A列のURLを取得
        targetURL = ws.Cells(i, 1).Value
        
        ' URLが空でない場合のみ処理を行う
        If targetURL <> "" Then
            ' 指定したURLにナビゲート
            ie.navigate targetURL

            ' ページの読み込み完了を待つ
            Do While ie.Busy Or ie.readyState <> 4
                DoEvents
            Loop

            ' HTMLドキュメントを取得
            Set html = ie.document

            ' 指定されたクラス名の要素を取得
            On Error Resume Next
            Set elements = html.getElementsByClassName(className)
            On Error GoTo 0

            ' 要素が見つかった場合、3つ目の要素のテキストを取得
            If Not elements Is Nothing And elements.Length >= 3 Then
                Set element = elements(2) ' インデックスは0から始まるため3つ目は2
                tagText = element.innerText
                
            Else
                tagText = "クラスが見つかりません"
            End If

            ' 結果をB列に書き込む
            ws.Cells(i, 2).Value = tagText
            
        End If
    Next i

    ' IEオブジェクトを終了
    ie.Quit
    Set ie = Nothing
    Set html = Nothing
    Set elements = Nothing
    Set element = Nothing
    
    ' 完了メッセージを表示
    MsgBox "完了しました", vbInformation, "完了"

End Sub
```


# さいごに
結局、ChatGPT先生様様なのでありました・・・
重い腰を上げて公開記事を初投稿する

# 自己紹介
名前：Joanne（ジョアンヌ）
性別：女
出身：香港
現職：社内SE

６年前未経験からエンジニアに転職し、「文系＋外国出身」というハンデを持ちながら独学でプログラミングを学習。
フロントエンド・バックエンド・インフラ...何でもこなす、器用貧乏なフルスタックエンジニアです。

最近はインターンと新卒の教育に試行錯誤の真っ最中です。
そんな中、新卒の子からの一言で、ずっと避けていた公開記事の投稿を開始しました。

# これまで公開記事を投稿しなかった理由
## ﾆﾎﾝｺﾞ ﾜｶﾘﾏｾﾝ
そもそも母国語は **広東語** です。大前提として日本語で文章書くのが苦手なんです！

日本語能力試験、ビジネス日本語能力テスト 共に最上級取得しています、
学校でこれまで様々な論文を日本語で書いてました。

しかしそれでも、苦手なものは苦手です！言語バリア！！

## アイデアがない
- 自分より優秀な先輩達がたくさんいる中、私が発信できるものは？
- 同じような内容は、もうすでにたくさん発信されたのでは？
- 発信すべき、有益な情報とは？

などを考えていると、良い記事テーマが思いづかず、執筆の手が止まってしまいます。

## ウケるか心配
- 私はめっちゃ有益と思った内容、皆にはいらない情報ではないか？
- 間違えた情報を発信し、めっちゃ指摘受けたらどうしよう？

友達や同僚向けではなく、全世界に公開する内容だからこそ、
適当な内容を軽い気持ちで公開するのはできません。

## シンプルに怠惰
「記事を書いて、公開投稿する」

これだけではないです。
内容調査したり、事実確認したり、時には日本語を調べる必要もあります。

日々仕事をしながら、趣味も楽しむ、最新情報もキャッチアップし、スキルアップもする。
そんな中で、時間と労力を割いて記事を書くのはなかなか腰が重いです。

# 初投稿のきっかけ
自己紹介にも軽く言及しましたが、最近はインターンと新卒教育しています。
彼らとは業務上の話しはもちろん、社会人の在り方や、エンジニアとしての素養とか、時々プライベートの話もしています。

ある日、アウトプットについて話していました。
何を学習するにも、アウトプットが一番大事だと。技術ブログの話にもなりました。
Qiitaでは、様々な方が色んなテーマに関して、日々投稿しているから、読むだけでもかなり勉強になっていることをシェアしました。

すると、
:boy_tone1:**「私はジョアンヌさんが書いた記事を一番読みたいですけど」**
:girl_tone1:「あ、ごめん、私は社内向けでしか書いていないわ」

教育係の身として、そう言われたらもう公開記事を書きしかないだろう。

# 今後の予定
今後も不定期で、気が向いたら記事を投稿する予定です。

開発技術以外、新人教育・エンジニア育成に関しても投稿できたらと思います。
外国語、海外事情に関して需要があるかも知りたいです！

励みになりますので、いいね・コメントなどよろしくお願いします！
Reactで簡単なテーブルを作る

# React で Tableを作る

## シンプルな HTML Table

`HTML`で`Table`を作りたい場合、`th`を`tr`で囲み、`tr`を`table`で囲みます。
例：

```HTML
<table>
  <tr>
    <th>7</th>
    <th>8</th>
    <th>9</th>
  </tr>
  <tr>
    <td>7*7=49</td>
    <td>7*8=56</td>
    <td>7*9=63</td>
  </tr>
  <tr>
    <td>7*8=56</td>
    <td>8*8=64</td>
    <td>9*8=72</td>
  </tr>
  <tr>
    <td>7*9=63</td>
    <td>8*9=72</td>
    <td>9*9=81</td>
  </tr>
</table>
```

それをReact Componentに変えると

```Typescript
function KuKuTable(){
  return(
    <table>
      <tr>
        <th>7</th>
        <th>8</th>
        <th>9</th>
      </tr>
      <tr>
        <td>7*7=49</td>
        <td>7*8=56</td>
        <td>7*9=63</td>
      </tr>
      <tr>
        <td>7*8=56</td>
        <td>8*8=64</td>
        <td>9*8=72</td>
      </tr>
      <tr>
        <td>7*9=63</td>
        <td>8*9=72</td>
        <td>9*9=81</td>
      </tr>
    </table>
  )
}
```

になります。

### 別々のコンポーネントに分割します

Table コンポーネントを TableHeader と TableBody コンポーネントで構成する
それぞれを書きます。

```Typescript
function Table() {
  return (
    <table>
      <TableHeader />
      <TableBody />
    </table>
  );
```

Tbody はいくつの Tr から作られた、またTrはいくつの Td から作られた、Td はその乗算の式。

```Typescript
function TableBody() {
  const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
  const equation = (base: number, multiplier: number) => `${base} * ${multiplier} = ${base * multiplier}`;
  const Tbody = (arrayJsx: JSX.Element[]) => <tbody>{arrayJsx}</tbody>;
  const Tr = (arrayJsx: JSX.Element[]) => <tr>{arrayJsx}</tr>;
  const Td = (equation: string) => <td>{equation}</td>;

  const result =
    Tbody(numbers.map((num, idx) =>
      Tr(numbers.map(num2 =>
        Td(equation(num, num2))))));
        
  return result;
}
```

```Typescript
function TableHeader() {
  return (
    <thead>
      <tr>
        {[1, 2, 3, 4, 5, 6, 7, 8, 9].map(num => <th key={"th" + num}>{num}</th>)}
      </tr>
    </thead>
  );
}
```

最後は`page.tsx`で使います。

```Typescript
export default function Home() {
  return (
    <div className="m-10">
      <Table />
    </div>
  );
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667096/9bda40eb-1a01-912a-876f-48e271c233bc.png)
出来上がり！
ビンゴゲームのモンテカルロ・シミュレーション

# 目的
ビンゴゲームは景品がすべて出るまで続行されることが多いです。
そのため、思ったより早く終わってしまったり、だらだら長引いてしまいがちです。
もし、参加人数や抽選回数が与えられたもとでのビンゴ者数が推測できれば、適切な景品数を事前に計画することができます。
そこで、ある抽選回数時点でのビンゴ者数を算出することで、ビンゴゲームのタイムキープを実現します。

# 方法
上記の問題は恐らく解析的に計算できないので、Rでモンテカルロ・シミュレーションを行います。
### 例の設定
用紙枚数(参加者数)　36名
シミュレーション回数　100000回
用紙のサイズ　5×5
数字の最大値　75（最も一般的なようです）
抽選回数　40回

なお、今回は列ごとに入りうる数字が決まっているビンゴカードを想定しています。たとえば、今回の例ではB列(一番左)には1~15の数字が入ります。


### サンプルコード
<details><summary>折り畳み</summary>

```rb
set.seed(2024)
A <- 36 #用紙枚数
B <- 100000 #シミュレーション回数
L <- 5 #用紙のサイズ(L*L)
M <- 75 #数字の最大値(M>=L*L,M%%L=0)
N <- 40 #抽選回数(N<=M)
bingos <- numeric()#シミュレーション結果保存

for(b in 1:B){	#大会
  	bingo <- 0 #ビンゴ枚数
  	Y <- sample(1:M, N) #抽選
  	for(a in 1:A){	#各カード
		X <- matrix(rep(0, L*L), ncol=L)#用紙
 		for(i in 1:L){
     			X[, i] <- sample(M%/%L, L) + M%/%L*(i-1)
  		}
        	X[ceiling(L/2),ceiling(L/2)] <- 0 #中心に穴あけ
		Z <- matrix(rep(1, L*L), ncol=L) #判定用用紙　穴が0(視覚的に)
       	Z[ceiling(L/2),ceiling(L/2)] <- 0 #中心に穴あけ
		for(i in 1:N){#抽選照合
      		for(j in 1:L){#行
                  	for(k in 1:L){#列
                        	if(X[j,k]==Y[i]){
                                Z[j,k] <- 0
                            	}
                       	}
               	}
        	}
    		Zd <- Z #右上がりの斜め判定用
    		Zd[1,]<-Z[5,]
    		Zd[2,]<-Z[4,]
    		Zd[4,]<-Z[2,]
    		Zd[5,]<-Z[1,]
		
	    	result <- c(colSums(Z),rowSums(Z),sum(diag(Z)),sum(diag(t(Zd))))　#各列各行斜めのビンゴ判定

    		if(0 %in% result){bingo <- bingo+1}#ビンゴのある用紙のカウント
   	}
	bingos[b] <- bingo
}
mean(bingos)
var(bingos)
sqrt(var(bingos))
hist(bingos,breaks=seq(0,A,by=1))
```
</details>
for文を大量に使っているので低速です。

### 出力
<details><summary>折り畳み</summary>

```rb
> mean(bingos)
[1] 16.04541
> var(bingos)
[1] 11.149
> sqrt(var(bingos))
[1] 3.339012
```
</details>

# 結果
サンプルコードの設定だと、平均約16人ビンゴになるようです。
また、ヒストグラムを見ると、やや右に裾が長いことに目をつむれば、だいたい正規分布していそうです。
標準偏差が約3.3なので、景品を16個用意しておけば無難、極力時間内に終わらせたければ9個程度、極力間を持たせたければ23個程度用意しておけば安心でしょう(平均±2×標準偏差の範囲に約95%がおさまるので)。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533896/2de80788-8295-ad10-b41b-d6dd045a88c0.png)
DBクライアントツールが接続できなくなった


## 発生事象

普段、DBクライアントツールに[TablePlus](https://tableplus.com/)を使用しています。
いつも通りDockerで立ち上げているローカルのDBに接続しようとしたところ、
次のようなエラーが出て接続できなくなりました。

```terminal
connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: role "postgres" does not exist
```

前日まで普通に使えてましたし、connectionの情報は保存していますので、
入力値を間違えたという可能性はありません。

Dockerも特にいじってません。

## 試してみたこと

### roleの確認

`role "postgres" does not exist`とあるので、
DBコンテナにアタッチしてPostgreSQLにログインし、roleが存在しているかどうかを確認しました。

**結果、存在していました。**

### 再起動

「再起動は全てを解決する」という名言があります（嘘）
ということで、とりあえず再起動してみました。

**しかし状況変わらず。**

### DBクライアントツールのアンインストール

一度アンインストールし、再度インストールしてみました。
**これでも解決せずでした。**

## 原因

上記のように色々試しつつ、直近で何か変わったことしたかなーと考えていたところ、
ローカルでPostgreSQLを使用したい機会があったため、
homebrewでPostgreSQLをインストールし使っていたことを思い出しました。

これが何か悪さしていそうだと思い、さらに調査。

すると、**ローカルで動作しているPostgreSQLがポート5432を占有していた**ために
TablePlusからDockerコンテナ内のPostgreSQLへの**接続が競合**していることがわかりました。

## 解決方法

### ポート5432が他のプロセスによって占有されていないかを確認

以下のコマンドでプロセスの確認。

```terminal
lsof -i :5432
````

> 実行結果

```terminal
COMMAND     PID       USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
postgres   2116 XXXX    7u  IPv6 0x91d6bd0f8d32a8ab      0t0  TCP localhost:postgresql (LISTEN)
postgres   2116 XXXX    8u  IPv4 0x91d6bd012679c10b      0t0  TCP localhost:postgresql (LISTEN)
ssh        8131 XXXX   26u  IPv4 0x91d6bd01267988a3      0t0  TCP *:postgresql (LISTEN)
TablePlus 11229 XXXX   22u  IPv4 0x91d6bd01268ddb83      0t0  TCP localhost:62633->localhost:postgresql (CLOSE_WAIT)
```

ローカルのPostgreSQLサービスが起動しており、このサービスがポートを占有しています。


### ローカルのPostgreSQLを停止

以下のコマンドでPostgreSQLを停止します。

```terminal
brew services stop postgresql@15
```

（自分の場合は15系を使用していたので`@15`をつけました）

ポートが解放されたことを確認した後、
TablePlusで再度接続を試みると成功しました。


## 最後に

エラーメッセージが分かりづらいのもあり（言い訳）、無駄に時間を溶かしてしまいました。

一度冷静になってこれまでと違ったことをしていないか振り返ることが大切ですねー。。
間違えてgit initをしてしまった時の対処法(取り消し)

## 本日のお悩み

```sh
git init
```

間違えて `git init`  コマンドで関係ないgitリポジトリを作成してしまった。
このコマンドを取り消し、やり直したい。

## 本日の処方箋
```sh
# git initをしたディレクトリで行う
rm -rf .git
```
このコマンド操作を取り消しやり直したい場合、間違えて作成してしまったローカルリポジトリを、上記コマンドを入力し削除すればOK!
上記コマンドを入力したらもう消えているので、あとは該当のディレクトリでもう一度`git init` をする
PowerAutomate: SharePoint 内でファイルのバージョンで抽出する by Filter Query

# 背景

FilterQuery 備忘録シリーズ

{VersionNumber} でフィルター出来ない！！って時の対処法

# 概要

OData__UIVersionString  で指定してやれば OK

嵌まりポイントとして、OData__UIVersion がある。
OData__UIVersion は OrderBy は上手くいくけど、Filter ではうまく動かない。
理由は不明

```text: ファイルバージョンで絞る例: Version 3.0 以上
OData__UIVersionString ge '3.0'
```

## 利用例

<code>OData__UIVersionString ge '3.0'</code> であれば、
3.0 以上で取得出来ているのが分かる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/f86317ad-b960-cf64-b9d3-cb6610a4e24f.png)

OData__UIVersion だと、エラーは出ないけれど、結果は異常

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/8114b77e-840e-6e77-8cf6-f8e582035154.png)

# あとがき

あとは、まとめと、調べ方を書いて終わり、かな

# keyword

How to extract files using a filter query based on file version in SharePoint.
GitHubでC#（.Net8）のWPFアプリを自動テストする

# 概要
自作のC# WPFアプリケーションの作成に自動テストを導入した際の備忘録を残す

### 条件
- .Net8.0アプリケーション
- Visual Studio Community 2022

# 実施したこと
- Visual Studioの拡張機能などのインストール
- ソリューションを作成する
- GitHub Actionを設定

### Visual Studioの拡張機能などのインストール
- .Netデスクトップ開発のオプション機能の中から"MSIX Packaging Tools"をインストール
- ユニバーサルWindowsプラットフォーム開発をオプションなしでインストール
 （実際にはデフォルトでチェックが入っていた"IntelliCode"と"DirectX用グラフィックスデバッガーおよびGPUプロファイラー"だけインストール対象とした）

この2つがないとWindowsユニバーサルパッケージプロジェクトが作成できない

### ソリューションを作成する
ソリューションの構成は、以下の2つに分離して作成
- 対象の開発プロジェクトとテストプロジェクトを含んだもの
- 対象の開発プロジェクトとWapプロジェクトを含んだもの

```plantuml
salt
{
{T
+ Application.sln
++ Application.csproj
++ ApplicationTests.csproj

+ ApplicationWap.sln
++ Application.csproj
++ ApplicationWap.wapproj
}
}
```
最初は全部一緒くたで構築したが、UnitTestsの自動ビルドの際に.sln単位でビルドがかかり、ApplicationWap.wapprojのエラーによりテストが通らない事態となったため、分離した。

### GitHub Actionを設定
1. GitHubの該当のProjectサイトで![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3493988/32f905a1-755d-c8b1-45bf-d27ccaea6c2c.png)を選択
1. ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3493988/4109544e-4d50-5e8b-0315-bcb6c9f55e93.png)を選択しワークフローを追加
1. .Net DesktopのConfigureを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3493988/b2046420-3033-2957-ad23-b38d40a73f8d.png)
1. ソリューション、テストプロジェクト、パッケージパス、パッケージプロジェクトを設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3493988/85224284-d129-2994-1761-3d9bd7b6b62e.png)
この時変数はそれぞれ以下を指定。
Solution_Name: Application.sln（アプリとテストのソリューション）
Test_Project_Path: ApplicationTest.csproj
Wap_Project_Directory: ApplicationWap　（ApplicationWapの保存フォルダ）
Wap_Project_Path: .\ApplicationWap\ApplicationWap.wapproj

1. matrix:の設定にtargetplatformを追加
    ```
    targetplatform: [x86, x64]
    ```
1. Restoreの設定にRuntimeIdentifierを追加
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3493988/81900442-5e36-ec33-a331-1451072ae68f.png)

これはWPFだと必須らしい。

### プロジェクトファイルを設定
1. Application.csprojのプロジェクトプロパティを変更
    1. プロジェクトファイルをダブルクリックしてxmlファイルにてTargetFramewokの設定を
        - ターゲットフレームワーク
        - ターゲットOS
        - ターゲットOSバージョン"
    の組み合わせに修正
    1. PlatformTargetの設定を追記

    ```
    <TargetFramework>net8.0-windows7.0</TargetFramework>
    <PlatformTarget>x86</PlatformTarget>
1. 証明書を作成
今回はオレオレ証明書を作成（.pfx証明書ファイル）
参考：https://qiita.com/ttoori-ttoori/items/f756a1baabda6359995d

1. ApplicationWap.wapproj内に証明書を設定
    - 宣言を選択
    - 使用可能な宣言から"証明書"を選択
    - ストア名：”個人証明書”、コンテンツ：.pfxファイル名
    を設定

1. Power ShellでSigningCertificate_Encoded.txtを作成（Actionのワークフローファイルにしたがって）
ワークフローファイルのコメントの通り以下を実行すると.txtファイルができる
```
# $pfx_cert = Get-Content '.\SigningCertificate.pfx' -Encoding Byte
# [System.Convert]::ToBase64String($pfx_cert) | Out-File 'SigningCertificate_Encoded.txt'
```
できたSigningCertificate_Encoded.txtの内容をGitHubのsecretフォルダに保管
Setting→Secret and variables→ActionsのSecretsタブでNew repository secretを選択し、BASE64_ENCODED_PFXファイルに.txtファイルのデータをコピー
（私はパスワードを設定しなかったのでパスワードファイルはおかなかったが、パスワードがあればPfx_Keyとして同じSecretsに追加）


## その他心得
- テストは色んなパターンで通しておく
- ビルドのwarningはなくす、減らす
- エラーが出たらMESSAGEをちゃんと読んで書かれたことを対応する（意外とそれで治る）
- リモートでfailになる場合は同じことをローカルで実行して確認する
【備忘録】Windows11 102/109キーボードの変更手順

# はじめに

時々英語キーボードを接続することがあるので、キーボード種別の変更手順を残しておく。

兄弟記事：[【備忘録】Windows10 102/109キーボードの変更手順](https://qiita.com/nak435/items/25adbfb17285db7e35fc)

## 1. 「設定」を開く

スタートボタンをクリックしてスタートメニューを表示。そこの「設定」をクリック。

<img width="400" alt="scr1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/4f6d7084-c823-b303-8b1d-49b1b29aae82.png" />


## 2. 「時刻と言語」を開く

「設定」画面の左ペインにある「時刻と言語」をクリック。

<img width="400" alt="scr2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/0c6e9e12-bfaf-4bde-dbc9-48194a4f62b1.png" />


## 3. 「時刻と言語」を開く

「時刻と言語」画面にある「言語と地域」をクリック。

<img width="400" alt="scr3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/6f3e3193-6a01-15a8-a7fb-e82004e1d558.png" />


## 4. 「日本語」を選択

「言語と地域」画面にある「日本語」の右側の「…」をクリック。

<img width="400" alt="scr4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/379c4592-c33c-4a30-2143-96180f53ea27.png" />


## 5. 「言語のオプション」をクリック

<img width="400" alt="scr5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/92c75733-9cb5-f99b-c647-c19547da8daa.png" />



## 6. 「レイアウトを変更する」をクリック

「オプション」画面にある「キーボード」の「レイアウトを変更する」をクリック。

<img width="400" alt="scr6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/945d3134-7aab-43a9-b1fd-0281e63795a2.png" />


## 7. 接続するキーボードを選択する

厳密に10xキーボードを選択するではなく、ざっくり英語キーボードと日本語キーボードを切り替えるイメージでよい。

<img width="400" alt="scr7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/4aca8a79-53e5-b042-fdfa-3973a79a84ee.png" />

## 8. PC再起動後に変更後のキーボードが有効となる

キーボード選択後に「今すぐ再起動する」をクリックする。

<img width="400" alt="scr8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/72c3c393-1247-1fce-80b2-f3d2c6a437ba.png" />

後で再起動する場合、「OK」クリック後、PC再起動後に変更後のキーボードが有効となる。
【AWS Storage Gateway】オンプレミスとクラウドのストレージを連携させる


# はじめに
AWS Storage Gatewayは、**オンプレミスとクラウドのストレージを連携させるためのフルマネージド型のハイブリッドクラウドストレージサービス**です。本記事では、**AWS Storage Gatewayの特徴と4つのゲートウェイタイプ**について解説します。

# AWS Storage Gatewayの特徴
### 標準ストレージプロトコル
Storage Gatewayは**NFS、SMB、iSCSI、iSCSI-VTL**などの標準的なストレージプロトコルに対応しているため、既存のアプリケーションを修正することなくAWSクラウドストレージを導入できます。

### フルマネージドキャッシュ
ローカルのゲートウェイアプライアンスが最近読み書きされたデータをキャッシュすることで、AWSに保管されたデータへの**低レイテンシーアクセスを実現**します。

### 最適化されたセキュアなデータ転送
Storage Gatewayは***SSLを使用してデータ転送を暗号化し、セキュリティ機能とアクセス制御をサポート**します。また、マルチパート管理、自動バッファリング、デルタ転送、データ圧縮などの最適化機能により、効率的なデータ転送を実現します。

### AWSサービスとの統合
Storage GatewayはAWS Backup、Amazon CloudWatch、AWS Identity and Access Management (IAM)、AWS Key Management Service (KMS)などのAWSサービスと連携し、**バックアップ管理、モニタリング、セキュリティ、暗号化などの機能を提供**します。

# ゲートウェイタイプの種類

| ゲートウェイタイプ | 説明 |
|----------|------|
| **Amazon S3ファイルゲートウェイ** | NFSおよびSMBプロトコルを使用して、Amazon S3にファイルをオブジェクトとして保存します。オンプレミスのファイルデータをバックアップしたり、AWS上でビッグデータ分析などの処理を行ったりできます。 |
| **Amazon FSxファイルゲートウェイ** | SMBプロトコルを使用して、フルマネージドなクラウドファイル共有であるAmazon FSx for Windows File Serverへの高速かつ低レイテンシーのアクセスを提供します。 |
| **テープゲートウェイ** | 仮想テープライブラリ（VTL）を提供し、バックアップアプリケーションからAmazon S3およびAmazon S3 Glacierへのテープバックアップを可能にします。これにより、物理テープインフラの管理コストを削減できます。 |
| **ボリュームゲートウェイ** | iSCSIプロトコルを使用したブロックストレージボリュームをアプリケーションに提供します。ボリュームのスナップショットをAmazon EBSスナップショットとしてクラウドにバックアップできます。 |

# まとめ
**AWS Storage Gatewayは、オンプレミスとクラウドのストレージを連携させ、データの保護、バックアップ、移行などを容易にするサービス**です。標準的なストレージプロトコルのサポート、フルマネージドキャッシュ、セキュアなデータ転送、AWSサービスとの統合など、多くの特徴を備えています。ユースケースに応じて適切なゲートウェイタイプを選択することで、ハイブリッドクラウド環境におけるストレージ管理を最適化できるでしょう。

# 参考
https://aws.amazon.com/jp/storagegateway/features/
SPF／DKIM／DMARCが設定されているか確認するコマンド

## はじめに
2024年2月以降、Gmailの「メール送信者のガイドライン」がアップデートされることになり、勤務先の企業でもSPF／DKIM／DMARCの設定をすることに。
設定後の確認用にコマンドをメモ。

## 確認コマンド

### SPF

**Linux**
```bash:bash
dig +short TXT example.com
```

**Windows**
```cmd:cmd
nslookup -q=txt example.com
```

```powershell:PowerShell
Resolve-DnsName -Name example.com -Type TXT
```

**確認方法**
`v=spf1` が含まれているかを確認する。

---

### DKIM
セレクタは、プロバイダによって異なるため要確認。

**Linux**
```bash:bash
dig +short TXT selector1._domainkey.example.com
```

**Windows**
```cmd:cmd
nslookup -q=txt selector1._domainkey.example.com
```

```powershell:PowerShell
Resolve-DnsName -Name selector1._domainkey.example.com -Type TXT
```

**確認方法**
`v=dkim1` が含まれているかを確認する。

---

### DMARC

**Linux**
```bash:bash
dig +short TXT _dmarc.example.com
```

**Windows**
```cmd:cmd
nslookup -q=txt _dmarc.example.com
```

```powershell:PowerShell
Resolve-DnsName -Name _dmarc.example.com -Type TXT
```

**確認方法**
`v=dmarc1` が含まれているかを確認する。


## 補足
SPF レコードの最後の`-all`や`~all`の意味について。

| 修飾子 | 意味 | 説明 |
|:--|:--|:--|
|+   |Pass|当該ドメインの送信メールサーバとして認証する|
|-   |Fail|当該ドメインの送信メールサーバとして認証しない|
|~   |SoftFail|認証情報を公開しているが、正当なメールであっても認証失敗する可能性もある|
|?   |Neutral|認証情報を公開しない|

by. [SPF（Sender Policy Framework）| 有害情報対策ポータルサイト 迷惑メール対策編](https://salt.iajapan.org/wpmu/anti_spam/admin/tech/explanation/spf/)

「`Fail` でなければ、基本的には即座に拒否しなくても良いという判断をするように。」ということのようだ。

## 参考
* [SPF レコードの見方 | Qiita](https://qiita.com/nao_hanpen/items/dcd468833354fbcf97a2)

* [送信ドメインを認証するためのSPFレコードに詳しくなろう | SendGrid](https://sendgrid.kke.co.jp/blog/?p=3509)
【セキュリティ入門】KEVてなに？

# KEVてなに？

https://www.cisa.gov/known-exploited-vulnerabilities-catalog

`KEV`は`Known Exploited Vulnerability`の略称で、日本語訳すると`悪用された既知の脆弱性`になります。

KEVは米国のCybersecurity and Infrastructure Security Agency(CISA)が提供している脆弱性リストです。

KEVには既に悪用された脆弱性が記載されており、米国連邦政府機関を対象とした、優先して対策する必要があるリストです。
脆弱性には`対応期日`が記載されており、米国政府機関は期日までの対応が求められます。

- **KEV例**

![kev 期日.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3005822/9380411c-9aac-3b2c-b0b0-ca4d32879cda.png)

# KEVの取得方法

KEVの情報は公式サイトに記載されている他、csvやjsonでも提供されています。

- **CSVのダウンロード**

https://www.cisa.gov/sites/default/files/csv/known_exploited_vulnerabilities.csv

- **JSONのダウンロード**

https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json

- **JSON SCHEMAのダウンロード**

https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities_schema.json

また、下記サイトからサブスクライブすればKEVの更新があった際に通知を受け取ることができます。

https://public.govdelivery.com/accounts/USDHSCISA/subscriber/new?topic_id=USDHSCISA_136

# KEVの登録条件

KEVに登録される条件として

1. CVE番号が割り振られていること
1. 実際に悪用されている脆弱性であること
1. 明確な是正ガイダンスが公開されていること

の3つがあります。

# 活用事例

KEVの活用事例をいくつかリストアップしました。
`SSVC`と併せて活用するのが有効的みたいです。

:::note info
`SSVC`の記事を投稿しました。
併せてご覧ください。
[【セキュリティ入門】SSVCてなに？](https://qiita.com/kk0128/items/7370eb0801c6bc6a30c1)
:::


https://www.pwc.com/jp/ja/knowledge/column/awareness-cyber-security/epss-kev.html

https://techblog.finatext.com/utilize-kev-7750d68b42c6

https://yamory.io/blog/cisa-kev/#cisa-kev%E3%82%AB%E3%82%BF%E3%83%AD%E3%82%B0%E3%82%92%E5%88%A9%E7%94%A8%E3%81%97%E3%81%9F%E8%84%86%E5%BC%B1%E6%80%A7%E7%AE%A1%E7%90%86%EF%BC%88ssvc%EF%BC%89

https://jpn.nec.com/cybersecurity/blog/231110/index.html

# 参考サイト

https://issuehunt.jp/articles/kevcatalog-introduction1

https://yamory.io/blog/cisa-kev/

https://jpn.nec.com/cybersecurity/blog/221104/index.html
Kasm WorkspacesでOktaを使う

# はじめに

Kasm WorkspacesでOkta (OpenID)で認証する方法
忘れないようにメモ。

~~SAML2.0なら公式から構成例がある。~~
https://kasmweb.com/docs/latest/guide/saml/okta.html

:::note alert
公式の構成ガイドではない手順です。
十分に検証を行ってください。
:::

# 環境
Red Hat Enterprise Linux Release 9.4 (Plow)  ※vSphere

Kasm Workspaces 1.15.0 community edition

Okta Ver 2024.05.0 E (OIE) Developer account

# Kasm Workspaces 設定
基本的には他サービスと同じように設定。

認証URL
https://${yourOktaDomain}/oauth2/v1/authorize

トークンURL
https://${yourOktaDomain}/oauth2/v1/token

ユーザ情報のURL
https://${yourOktaDomain}/oauth2/v1/userinfo

スコープ
openid
email

ユーザー名の属性
email

**OpenID Connect & OAuth 2.0 API**
https://developer.okta.com/docs/reference/api/oidc/

# Okta 設定
サインインリダイレクトURLにKasm WorkspacesのリダイレクトURL記入

セキュリティ　→　認可サーバー　→　設定するドメイン　→　アクセスポリシー

新しいアクセスポリシーを作成

![スクリーンショット 2024-05-15 204517.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/973316/f7a0941b-0b5c-b8de-8b6f-e8a7f4a05304.png)

ルールを追加

![スクリーンショット 2024-05-15 204617.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/973316/d363e524-dc61-e2cc-1281-089bc89a1e9f.png)

カスタム認可サーバでopenid,emailのスコープが使えないとエラーになるみたい？　

# 動作確認

正常にログインでき、Oktaユーザーでログインできることを確認し終了。

# 参考ドキュメント

https://kasmweb.com/docs/latest/guide/oidc.html

https://developer.okta.com/docs/guides/customize-authz-server/main/#create-access-policies

https://auth0.com/docs/get-started/apis/scopes/openid-connect-scopes
GitHub上のコードを簡単にCDNで使う方法


## 結論

```text:url
https://cdn.jsdelivr.net/gh/{ユーザー名}/{リポジトリ名}@{version}/{ファイル名}
```

versionを省略した場合、最新バージョンとして扱われます。

```text:url（version省略）
https://cdn.jsdelivr.net/gh/{ユーザー名}/{リポジトリ名}/{ファイル名}
```

またファイル名の拡張子の前に`.min`をつけると自動でミニファイされます。

## サンプル

https://github.com/mogamoga1024/MedianCut/blob/main/median_cut.js

をCDNで使いたい場合

https://cdn.jsdelivr.net/gh/mogamoga1024/MedianCut/median_cut.min.js

で利用できる。
元ファイルを一切加工せずともミニファイしてくれるのがありがたい。

## 参考元

https://www.jsdelivr.com/?docs=gh
Eclipseの完全無料コード生成AIプラグインWindsurf（Copilot的な）

:::note info
2025/06/15 以降、Pleiads All in One には、GitHub Copilot が標準で付属しています。

2025/02/12 GitHub 純正の GitHub Copilot for Eclipse プラグインがリリースされました。無料枠も提供されています。
https://docs.github.com/ja/copilot/using-github-copilot/getting-code-suggestions-in-your-ide-with-github-copilot?tool=eclipse

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45147/894c9517-af72-49dd-8297-28be472ab562.png)
||Windsurf Plugins|GitHub Copilot|
|---|---|---|
|無料|無制限<br>Llama|補完 2000 回まで/月<br>GPT、Claude|
|有料|15ドル/月<br>GPT、Claude|10ドル/月（100ドル/年）<br>GPT、Claude などの最新|

どちらもアカウントが必要です。Web のプライバシー設定から、プライベートコードの学習を無効化できます。
:::

# はじめに
Windsurf (旧 Codeium) は Eclipse でも利用可能な AI コーディング支援ツールです。
* 永遠無料、商用利用可能
* IntelliJ、VS Code、Visual Studio、Vim、Xcode など 40 以上！のツールに対応
* [次世代のAIツール...すべての開発者に生成AIツールを完全無料提供 (AT PARTNER)](https://www.atpartners.co.jp/ja/news/2024-01-31-codeium-which-builds-next-generation-ai-tools-for-software-developers-raises-65m-in-series-b-at-a-500m-valuation)
* [無料のサービス...Windsurfが最も優秀 (note: NRIデジタル)](https://note.com/nridigital/n/nf514a5db7852)

# インストール
1. プロキシ環境の場合は、環境変数 https_proxy を設定
`http://X.X.X.X:<port番号>` または
`http://<id>:<password>@X.X.X.X:<port番号>`<br><br>

1. Eclipse に Windsurf プラグインをインストール
https://marketplace.eclipse.org/content/codeium
> 2024/10/15 追記
上記からインストールできない場合は、Eclipse メニュー > ヘルプ > 新規ソフトウェアのインストール > 作業対象に https://exafunction.github.io/codeium-eclipse/ を貼り付けてインストールしてください。

# 利用イメージ
### 設定
Windsurf アカウントが無い場合は、ブラウザが開き、アカウント作成画面が表示されます。アカウントを作成すると、下記の API キーなどが自動設定されるため、特にこの設定画面は開いたり、設定する必要はありません。Windsurf のアカウントは、他の IDE やエディターでのコード生成 AI 補完でも共通で使用できます。

<img width="500" alt="Windsurf設定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45147/3f0fb38d-b9bf-71f7-ad1a-f8b34b0aaf79.png">

### チャット・ビュー
「Ctrl + ⏎」または右下の「With Codebase」ボタンで現在のプロジェクトリソースに基づいた AI チャットが可能です。ここでは、Spring Boot のコード書いてもらいました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45147/36b39003-9e7b-f480-ada3-fc97aa816864.png)

### エディター補完

以下の例ではクラス名を元に、main メソッドと System.out が候補として表示されています。タブを押すと補完されます。

<img width="400" alt="Windsurfエディター補完例" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45147/a8376ceb-66e2-e820-9070-1db5c846c374.png">

以下では、クラス名、メソッド名、引数を元にフィボナッチ数列を表示するコードが補完候補として生成されています。GitHub Copilot の衝撃と比べても遜色ない感じです。

<img width="450" alt="Windsurfエディター補完例" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45147/0e338cab-a593-189b-e4cc-ae3af295ab3e.png">

# おわりに
将来、OpenAI GPT-4o のようなマルチモーダル AI で、打ち合わせ音声・映像や仕様書からシステム構築できるようになり、現在の UI 表示や入力デバイスは大幅に変貌し、キーボードやマウスは緊急用のレガシーデバイスとなっていくかもしれませんね。昔は手で入力してたんじゃよとか。それはさておき、ひとまず Eclipse での AI コード補完をお探しの方は、ぜひ Windsurf を試してみてください。

https://qiita.com/cypher256
IT初心者必見！マウントとプロビジョニングの違いを理解しよう

# はじめに
ITの世界では、「**マウント**」と「**プロビジョニング**」という用語をよく耳にします。しかし、この2つの概念の違いを正確に説明できる人は意外と少ないのではないでしょうか。本記事では、マウントとプロビジョニングの違いについて、初心者にもわかりやすく解説します。

# マウントとは？
マウントとは、コンピュータのオペレーティングシステム（OS）において、**ストレージデバイス（HDDやSSDなど）やネットワーク上の共有フォルダを、ファイルシステム階層内の特定のディレクトリ（マウントポイント）に割り当てる操作**のことを指します。
例えば、Linuxシステムでは、mountコマンドを使ってUSBメモリをマウントすることで、ユーザーはUSBメモリ内のファイルにアクセスできるようになります。

# プロビジョニングとは？
一方、プロビジョニングとは、**ユーザーやシステムが必要とするリソース（ハードウェアやソフトウェア）を準備、設定、配備する過程全体**を指します。プロビジョニングには、以下のような作業が含まれます：

- サーバー、ストレージ、ネットワーク機器などのハードウェアリソースの割り当て
- OSやミドルウェアのインストールと設定
- アプリケーションのデプロイと設定
- ユーザーアカウントの作成と権限の設定

近年では、自動化ツールを使ってプロビジョニングを行うことが主流になっています。これにより、リソースの配備と管理を効率化し、ヒューマンエラーを減らすことができます。

# マウントとプロビジョニングの違い
マウントとプロビジョニングの主な違いは、以下の2点です。

# マウントとプロビジョニングの違い

| 観点 | マウント | プロビジョニング |
|------|---------|-----------------|
| 対象となる範囲 | ストレージデバイスをファイルシステムに割り当てる操作に限定される。 | システムが必要とするリソース全般（ハードウェア、ソフトウェア、設定など）を準備、設定、配備する過程全体を指す。 |
| 実行タイミング | OSが起動した後に必要に応じて実行される操作。 | システムを構築する際に、事前に実行される一連の作業。 |

# まとめ
マウントとプロビジョニングは、ITシステムを運用する上で重要な概念です。**マウントはストレージデバイスをファイルシステムに割り当てる操作**であり、**プロビジョニングはシステムが必要とするリソースを準備、設定、配備する過程全体**を指します。この2つの違いを理解することで、ITシステムの構築と運用をより効果的に行うことができるでしょう。
DiscordでIMEのオン/オフがうまくいかなくなった

# 普段，IMEのオンオフをどのように行っているのか
筆者はIMEのオンオフを変換キーと無変換キーに割り当てて使っています．

[入力文字なし] 状態で，
変換キー: IMEを有効化，
無変換キー: IMEを無効化．

という設定です．


# DiscordでIMEのオンオフがうまく動作しなくなった

きっかけはGoogle日本語入力を使い始めたことでした．
Discordでテキストを入力しようとしたら何も文字を入力していない状態なのにもかかわらず，変換キーを押してもIMEがオンになりませんでした．
Microsoft IMEを使っていたときは起きなかったことです．

# 解決方法
Google日本語入力のプロパティから，
[直接入力] 状態について，
変換キーの設定を
再変換 --> IMEを有効化
にしましょう．

筆者はこれでDiscordでのIMEのオンオフが今まで通りできるようになりました．
コードレビュー・不具合調査のため、gitで指定したファイルがいつ誰が作ったものなのか確認するためのコマンド作ってみた

# 需要
プロジェクト資料の中にiosプロジェクトのファイル説明があるシートがあった。
しかし、そのシートにないファイルがあったので、このファイルはいつ誰が作ったんや？？となった。


# コマンド
このように実行すると、コミットiD、コミット者、日時、コミットメッセージがわかる。

```
git log --diff-filter=A --pretty=format:"%H - %an, %ad : %s" -- Hoge/hoge.swift
 ```
複数行グリッド

これは <a href="http://qiita.com/advent-calendar/2016/delphi">Delphi Advent Calendar 2016</a> 21日目の記事です。

## TFrameを使って複数行グリッド作成

複数行表示編集できるグリッドのようなもの（下記のような感じ）ができるか問い合わせがあり、TFrameを使ったものを試作。個人的にいい感じでできたので、TFrameを組み合わせるとこんな感じでできますと言うご紹介させていただきます。

グリッド全体のTFrameにScrollBoxを置き、その中に明細行のTFrame（1行ごとにCreate）で構成しています。ScrollBoxの中に、Panelを1枚置き、その中に明細Frameを必要分Createしています。このScrollBoxの中のPanel位置を移動させることでスクロールを実現しています。
<a href="https://delphi-dev.sakura.ne.jp/FileBox/MultiLineGrid/MultiLineGrid1.png" target="_blank"><img src="https://delphi-dev.sakura.ne.jp/FileBox/MultiLineGrid/MultiLineGrid1.png" alt="MultiLineGrid1.png" width="320" height="204" border="0" /></a>

簡単な機能紹介資料（<a href="https://delphi-dev.sakura.ne.jp/FileBox/MultiLineGrid/Gaiyou.pdf">機能概要.pdf）</a>です。

プログラムはこちらです。動きは確認いただけるかと（<a href="https://delphi-dev.sakura.ne.jp/FileBox/MultiLineGrid/MultiLineGrid.zip">プログラム）</a>です。



ソースは仕事ネタなんで公開できませんが、TFrameを使えばこんな感じでできますというご紹介でした。


#### あとがき
別のブログ(今はない)に書かれていたものをQiitaに再投稿したものです。
【Python x AWS】「botocore.exceptions.ClientError.......is not authorized to perform: sts:AssumeRole」エラーの原因と解決法

# 概要

IAMユーザーでboto3を使ったら以下の権限エラーになりました。
解決できたので原因と解決方法を紹介します。

> botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::xxx:user/taro is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::xxx:role/xxxxx

# 原因と解決方法
エラーメッセージから、IAMユーザー`taro`に`sts:AssumeRole`操作を行う権限がないことがわかります。`sts:AssumeRole`操作は、一つのIAMエンティティ（ユーザー、グループ、ロール）が別のIAMロールを「引き受ける」ために必要なもの。

`Role`という名前が入っているのでややまぎわらしいですが、これ自体はIAMロールではありません。「アクセスキー」、「シークレットキー」、「セッショントークン」、3つの認証情報を発行してくれるサービスです。

> AWS Security Token Service (AWS STS) を使用して、AWS リソースへのアクセスをコントロールできる一時的セキュリティ認証情報を持つ、信頼されたユーザーを作成および提供することができます。
引用元：https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_temp.html


`sts:AssumeRole`操作の権限を付与するポリシーを追加するには以下のようにします。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::xxx:role/xxxxx"
        }
    ]
}
```

これでもまだ同様のエラーが発生する場合は、引き受けようとしているIAMロール（上記では`xxx:role/xxxxx`）の信頼ポリシーが、IAMユーザー`taro`がそのロールを引き受けることを許可していない、という可能性があり。

ロールの信頼ポリシーを更新してあげれば良いということになります。
AWS管理コンソールの「IAM」->「ロール`xxx:role/xxxxx`」->「信頼関係」->「編集」から、以下のように信頼ポリシーを付与します。


```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::xxx:user/taro"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

上記は、あくまで疎通確認的な試験で実施したもの。
恒久的に上記のような例外的な特別な信頼関係とポリシーを付与しておくのはあまり推奨されないと思いますので、あくまで試験的（一時的）に使う時には良いかなと思います。
【AWS】CloudWatch Syntheticsで模擬モニタリングを始めよう

# はじめに
Amazon CloudWatch Syntheticsは、AWSのサービスの一つで、**アプリケーションやウェブサイトの模擬モニタリングを行う**ことができます。本記事では、CloudWatch Syntheticsの基本的な概念と使い方について解説します。

# CloudWatch Syntheticsとは
CloudWatch Syntheticsは、スケジュールに沿って実行される設定可能なスクリプト（Canary）を作成し、**エンドポイントやAPIをモニタリングするサービス**です。Canaryは、実際のユーザーと同じ動作を模擬し、**アプリケーションの可用性やパフォーマンスを継続的に検証**します。
Canaryを使うことで、ユーザーが問題を発見する前に、問題を検出することができます。これにより、アプリケーションの信頼性を高め、**ユーザーエクスペリエンスを向上させる**ことができます。

# Canaryの特徴
Canaryは、以下のような特徴を持っています。

- Node.jsやPythonで記述されたスクリプト
- HTTPとHTTPSの両方のプロトコルに対応
- ヘッドレスブラウザ（Puppeteer）やSelenium Webdriverへのプログラムアクセスが可能
- エンドポイントの可用性とレイテンシーのチェック
- 読み込み時間のデータとUIのスクリーンショットの保存
- REST API、URL、ウェブサイトのコンテンツのモニタリング
- フィッシング、コードインジェクション、クロスサイトスクリプティングなどの不正な変更のチェック

# Canaryの作成と実行
Canaryを作成するには、以下の手順を実行します。


1. AWS Management Consoleから、CloudWatch Syntheticsのページを開く
2. 「Create Canary」ボタンをクリックし、Canaryの設定を行う
3. スクリプトを記述し、Canaryに関連付ける
4. Canaryの実行スケジュールを設定する（cron式またはレート式）
5. Canaryを作成し、実行する

Canaryは、1回だけ実行することも、定期的なスケジュールで実行することもできます。**最大で1分に1回の頻度で実行可能**です。

# Canaryの監視とトラブルシューティング
Canaryが作成されると、**CloudWatchの「Synthetics」名前空間にメトリクスが自動的に作成**されます。これらのメトリクスを使って、Canaryの実行状況や結果を監視することができます。
Canaryが失敗した場合は、**CloudWatchのログやX-Rayのトレースを確認することで、問題の原因を特定し、トラブルシューティングを行う**ことができます。

# まとめ
CloudWatch Syntheticsを使うことで、アプリケーションやウェブサイトの模擬モニタリングを行い、**問題の早期発見とユーザーエクスペリエンスの向上を実現**できます。Canaryを適切に設定し、監視することで、アプリケーションの信頼性を高めていきましょう。

# 参考
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries.html
【AWS】CloudWatchメトリクスの基本と活用方法

# はじめに
AWSのモニタリングサービスである**CloudWatch**では、さまざまなメトリクスを収集し、システムのパフォーマンスを可視化することができます。本記事では、CloudWatchメトリクスの基本的な概念と、その活用方法について解説します。

# メトリクスとは
メトリクスとは、**システムのパフォーマンスに関するデータ**のことです。AWSのサービスの多くは、EC2インスタンスやEBSボリューム、RDSインスタンスなどのリソースに対して、無料のメトリクスを提供しています。また、EC2インスタンスなどの一部のリソースでは、詳細モニタリングを有効にすることで、より詳細なメトリクスを取得できます。
CloudWatchは、AWSリソースのメトリクスだけでなく、**ユーザー独自のアプリケーションメトリクスも収集**することができます。収集されたメトリクスは、検索、グラフ表示、アラームの設定などに利用できます。

# 基本モニタリングと詳細モニタリング
CloudWatchが提供するメトリクスには、**基本モニタリング**と**詳細モニタリング**の2種類があります。**基本モニタリングは無料で提供され、5分間隔でメトリクスが収集**されます。一方、**詳細モニタリングは有料オプションで、1分間隔でメトリクスが収集**されます。
詳細モニタリングを有効にすることで、より細かい粒度でシステムの状態を監視できるようになります。ただし、コストが発生するため、必要に応じて有効化するようにしましょう。

# メトリクスの活用方法
CloudWatchメトリクスは、以下のような方法で活用できます。

- **メトリクスエクスプローラーを使ったリソースのモニタリング**
- **CloudWatch Metrics Insightsを使ったメトリクスのクエリ**
- **メトリクスストリームを使ったメトリクスの外部システムへの送信**
- **カスタムメトリクスのパブリッシュ**
- **異常検出機能を使ったメトリクスの異常値の検出**
- **Metric Mathを使った複数のメトリクスの計算**

これらの機能を適切に使い分けることで、システムの状態を詳細に把握し、**問題の早期発見や性能の最適化につなげる**ことができます。

# メトリクスデータの保持期間
CloudWatchに収集されたメトリクスデータは、**15か月間保持**されます。つまり、現在のデータだけでなく、過去のデータも参照できるため、**長期的なトレンドの分析やシステムの変化の把握**に役立ちます。
ただし、大量のメトリクスデータを長期間保持すると、ストレージのコストが発生するため、**不要なメトリクスは定期的に削除する**ようにしましょう。

# まとめ
CloudWatchメトリクスは、**AWSのリソースやアプリケーションの状態を監視するための強力な機能**です。基本モニタリングと詳細モニタリングを使い分け、メトリクスエクスプローラーやMetrics Insightsなどの機能を活用することで、システムの性能を最適化し、問題の早期発見につなげましょう。

# 参考
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/working_with_metrics.html
【AWS CloudWatch】複合アラームを使って効果的にアプリケーションの監視を行おう

# はじめに
**CloudWatchは、AWSのサービスやアプリケーションのモニタリングを行うためのサービス**です。複数のアラームを組み合わせて、アプリケーション全体の状態を監視することができます。本記事では、CloudWatchの複合アラームについて解説します。

# 複合アラームとは
複合アラームとは、**他のアラームの状態を監視して、自身の状態を判断するアラーム**のことです。例えば、CPUの使用率が高いアラームとディスクの読み取り量が多いアラームを組み合わせて、**両方の条件が満たされた時に通知を送信するような複合アラーム**を作成できます。

複合アラームを使うメリットは以下の2つです。

- **アラームのノイズを減らすことができる**
- **複雑なアラーム条件を作成できる**

# 複合アラームの作成方法
複合アラームを作成するには、以下の2つの方法があります。

- **複合アラームレベルでのみアクションを設定し、基礎となるアラームはアクションなしで作成する**
- **複合アラームと基礎となるアラームで異なるアクションを設定する**

複合アラームでは、 **Amazon SNSトピックへの通知、Lambda関数の呼び出し、Systems Manager OpsItemsの作成、Systems Manager Incident Managerでのインシデント作成**のみ実行できます。

# 複合アラームのルール式
複合アラームを作成する際には、ルール式を定義する必要があります。ルール式では、監視対象のアラームが、 **ALARM、OK、INSUFFICIENT_DATAのどの状態になるかを判定**します。
ルール式では、AND、OR、NOTの論理演算子を使って、複数の条件を組み合わせることができます。例えば、「CPUの使用率が高い かつ ディスクの読み取り量が多い」という条件を設定することができます。

# 複合アラームのアクション抑制
**複合アラームでは、基礎となるアラームのアクションを抑制することができ**ます。これにより、アラームのノイズを減らすことができます。
例えば、CPUの使用率が高いアラームとメモリ使用率が高いアラームを組み合わせた複合アラームを作成し、両方の条件が満たされた場合にのみ通知を送信するように設定できます。この場合、**個々のアラームが発生しても通知は送信されません。**

# まとめ
CloudWatchの複合アラームを使うことで、**アプリケーション全体の状態を効果的に監視でき**ます。複合アラームを作成する際は、**ルール式を適切に定義**し、**アラームのノイズを減らすようにアクションを設定**しましょう。複合アラームを活用して、アプリケーションの安定運用を実現しましょう。

# 参考

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/Create_Composite_Alarm.html
Node.js の fs でフォルダ内の内容を列挙する

## 環境
bun 1.1.3

## 方法
[fs.readdirSync()](https://nodejs.org/api/fs.html#fsreaddirsyncpath-options) を使います。

## コード例
### ファイル構成
```
|--files
| |--fuga.txt
| |--hoge.txt
| |--piyo.txt
|--index.ts
```

```fuga.txt
渚の砂は、崩しても、積る、くぼめば、たまる、音もせぬ。
```

```hoge.txt
ただ美しい骨が出る。
```

```piyo.txt
貝の色は、日の紅、渚の雪、浪の緑。
```

### 例1: シンプルにファイル名のリストを取得
`fs.readdirSync()` はディレクトリ内のファイル名のリストを返します。
厳密にはファイルだけでなくディレクトリもリストに含まれます。
ここでは `.forEach()` で全件ループしています。

```js:index.ts
import fs from 'fs';

const dirPath = 'files';
const fileNames = fs.readdirSync(dirPath);

fileNames.forEach((fileName) => console.log(fileName));
```
**実行結果**
```
fuga.txt
hoge.txt
piyo.txt
```

### 例2: 取得したファイル名を使ってファイルの中身を読み出し
以下はファイルの内容を読み出して出力する例です。
同じく `fs` の `fs.readFileSync()` を使っています。
```js:index.ts
import fs from 'fs';

const dirPath = 'files';
const fileNames = fs.readdirSync(dirPath);

fileNames.forEach(fileName => {
  const file = fs.readFileSync([dirPath, fileName].join('/'), 'utf8');
  console.log(file.trim());
});
```
**実行結果**
```
渚の砂は、崩しても、積る、くぼめば、たまる、音もせぬ。
ただ美しい骨が出る。
貝の色は、日の紅、渚の雪、浪の緑。
```

### 例3: ファイル名でファイルをフィルターして中身を読み出し
以下は拡張子を検査することで、テキストファイルだけを取り出す例です。
今回のファイル構成では実行結果は例2と変わりませんが、ファイル名を拡張子なり正規表現なりでフィルターして取り出したい場合や、当該ディレクトリ内に別のディレクトリが存在する場合は、以下のように `for...of` と `continue` を使って、欲しくないファイルをスキップするといいと思います。

```js:index.ts
import fs from 'fs';

const dirPath = 'files';
const fileNames = fs.readdirSync(dirPath);

for (const fileName of fileNames) {
  if (!fileName.endsWith('.txt')) continue;

  const file = fs.readFileSync([dirPath, fileName].join('/'), 'utf8');
  console.log(file.trim());
}
```
**実行結果**
```
渚の砂は、崩しても、積る、くぼめば、たまる、音もせぬ。
ただ美しい骨が出る。
貝の色は、日の紅、渚の雪、浪の緑。
```
SQLインジェクション

## はじめに

SQLインジェクションについてまとめる。

### SQLインジェクションとは

SQL命令に不正なパラメータを引き渡すことで、本来開発者が意図していなかったはずのSQL命令が生成/実行されてしまうこと。
結果として、公開されるはずでなかった機密情報が漏洩したり、需要なデータが削除されてしまう可能性がある。


### 例

以下のようなコードがあったとして

```php
$stt = $db->prepare("INSERT INTO book(isbn, title, price, publish, published)
VALUES('".$_POST['isbn']."', '".$_POST['title']."', '".$_POST['price']."', '".$_POST['publish']."', '".$_POST['published']."')");
```

`$_POST['isbn']`に以下の入力がされたとき

```text
9-999-99999', '', '', '', '');DELETE FROM book; --
```

以下のようなクエリが生成されてしまう。

```php
$stt = $db->prepare("INSERT INTO book(isbn, title, price, publish, published)
VALUES('9-999-99999', '', '', '', '');DELETE FROM book; --', '', '', '', '')");
```
「--」はコメントを表す記号のため、「--」以降は無視されてしまう。
データを一件挿入した後、bookて０ブルの全てので０田を削除する、という命令が生成されている。

### 対策

SQLエスケープをする。または、PDOを使っているならプレイスホルダーを使う。
[Google Cloud Speech-to-Text API(V2)] Javaでコンフィグレーションを取得する

Cloud Speech-to-Text API V2(Java)を使用して、
Speech-to-Textのコンフィグレーションを取得する方法についてご紹介します。

:::note info
APIを利用する環境の準備から始める場合や、コードを実行する際は、
[⧉[Google Cloud Speech-to-Text API(V2)] JavaでSpeech-to-Text APIを使ってみる](https://qiita.com/doran/items/8e4ef896588229c4fed3)
を参照ください。
:::

|No||目次|
|---|---|---|
|1||[コンフィグを取得](#1-コンフィグを取得)|
||1|[スコープ](#11-スコープ)|
||2|[実行](#12-実行)|
||3|[レスポンスの内容](#13-レスポンスの内容)|

## 1. コンフィグを取得
Speech-to-Textのコンフィグレーションを取得します。

### 1.1. スコープ
OAuth2.0でこのAPIを実行するには、以下のスコープを指定してください。
サービスアカウントで実行する場合はスコープの指定は不要です。
```
https://www.googleapis.com/auth/cloud-platform
```

### 1.2. 実行

```java
public static void main(String[] args) throws Exception{
    try(SpeechClient client = getSpeechClient()){
        GetConfigRequest.Builder builder = GetConfigRequest.newBuilder();
        builder.setName(String.format(
                    "projects/%s/locations/%s/config", 
                    "プロジェクトID","ロケーションID"));
        
        Config response = client.getConfig(builder.build());
        System.out.println(response);
    }
}
```

#### 1.2.1. HTTPリクエスト
GET:　https:\//speech.googleapis.com/v2/projects/{プロジェクトID}/locations/{ロケーションID}/config
が実行されます。

#### 1.2.2. クエリパラメータ
GetConfigRequest.Builderのsetメソッドにより、クエリパラメータを追加できます。
build()メソッドでGetConfigRequestインスタンスを取得し、
getConfig()に渡します。

|メソッド|引数|説明|
|---|---|---|
|setName|String|【必須】リソース名<br>形式："projects/{プロジェクトID}/locations/{ロケーションID}/config"|

### 1.3. レスポンスの内容
#### Config
|メソッド|戻り値|説明|
|---|---|---|
|getName|String|構成リソースの名前<br>形式："projects/{プロジェクトID}/locations/{ロケーションID}/config"|
|getKmsKeyName|String|オプションのKMSキー名<br>形式："projects/{プロジェクトID}/locations/{ロケーションID}/keyRings/{key_ring}/cryptoKeys/{crypto_key}|
|getUpdateTime|Timestamp|このリソースが最後に変更された時刻|

<br>
<br>
おしまい。。
GPT-4とGPT-4oの性能比較と変更点

今回は最新のAI言語モデルであるGPT-4と、その最適化バージョンであるGPT-4o（GPT-4 Optimized）について詳しくご紹介します。
どちらのモデルも自然言語処理の分野で重要な役割を果たしていますが、それぞれ異なる特徴や強みを持っています。

### GPT-4とは
まず、GPT-4について説明します。GPT-4はOpenAIが開発した次世代の言語モデルで、GPT-3の後継機です。
強力な言語理解と生成能力を備えており、多くのタスクで優れた性能を発揮します。

**主な特徴:**
- **高度な言語理解:** より複雑な文脈やニュアンスを理解し、自然な応答を生成します。
- **多言語対応:** 多くの言語で高精度な翻訳やテキスト生成が可能です。
- **応用範囲の広さ:** カスタマーサポート、クリエイティブライティング、データ分析など、多岐にわたる用途で活用されています。

### GPT-4oとは
GPT-4oは、GPT-4をベースに性能と効率をさらに向上させたモデルです。
特にリアルタイムアプリケーションやリソース制約のある環境での利用を想定しています。

**主な改善点:**
- **速度向上:** モデルの計算効率が改善され、応答速度が向上しました。これにより、リアルタイムアプリケーションでの使用がよりスムーズになります。
- **リソース効率:** モデルのメモリ使用量が削減され、リソースが限られた環境でも高性能を維持します。
- **応答精度:** 特定のタスクにおいて、より高い精度で応答を生成するための調整が施されています。

### 性能比較
以下の表でGPT-4とGPT-4oの性能を比較します。

| 特徴            | GPT-4              | GPT-4o             |
|-----------------|--------------------|--------------------|
| 応答速度        | 通常               | 高速               |
| メモリ使用量    | 高い               | 低い               |
| 応答精度        | 高い               | 特定タスクでさらに高い |
| 多言語対応      | 優れている         | 優れている         |
| 利用用途        | 幅広い             | リアルタイム、リソース制約環境 |

### 使用シーンの違い
GPT-4は、クリエイティブなライティングや複雑なデータ分析、カスタマーサポートの自動化など、幅広い用途で使用されています。
特に応答精度が求められるシーンで力を発揮します。

一方、GPT-4oは、リアルタイム性が求められるチャットボットやインタラクティブなアプリケーション、リソースが限られているIoTデバイスなどでの使用に最適です。

### まとめ
GPT-4とGPT-4oは、それぞれ異なる強みを持つ優れたAIモデルです。
用途に応じて適切なモデルを選ぶことで、AIの性能を最大限に引き出すことができます。
【Rust】小数点以下の位を指定して四捨五入する時の実装

## 概要
Rustで小数点以下の位を指定して四捨五入する時、どのような実装があるかのメモ書きです。
実装方針として[Floating-point cheat sheet for Rust](https://floating-point-gui.de/languages/rust/)の記事にある通り、`format`を使う方針と`rust_decimal`のライブラリを使うやり方が取り急ぎ考えられそうです。今回は`rust_decimal`を使ってみましたので、そのメモ書きです。

## 前提
* 使用したrustcのバージョンは`1.78.0`です。
* 使用したrust_decimalのバージョンは`1.35.0`です。

## 実装サンプル
今回はfloatの変数からDecimal型のインスタンスを生成して四捨五入し、小数点第二位まで取得するものを実装してみました。
[FromPrimitive](https://docs.rs/rust_decimal/latest/rust_decimal/prelude/trait.FromPrimitive.html)のドキュメントにある通りDecimal型を取得する際にOptionで包まれるので、mapで四捨五入をする形が以下になります。

```rust
Decimal::from_f32(value_float).map(|d| d.round_dp(2))
```
Time CapsuleをLANで直接繋ぐときの設定をめちゃくちゃ詳しく説明する

# はじめに
この記事には以下の内容が含まれています。
- 本記事の推定する読者層
- テスト環境
- 最低限必要な物
- 配線
- AirMac Time Capsule(以下Time Capsule)の設定
- 終わり

# 本記事の推定する読者層
- Time Capsuleを使ってTime Machineバックアップをしたことがある方
- 用途をNAS限定にしている方
- 最低限の知識のある方
- バックアップに時間がかかっている方

# テスト環境
- iMac Retina 5K 27-inch Late 2020 MacOS Sonoma 14.5
-  AirMac Time Capsule 2TB
-  Cat6A 有線LANケーブル

# 最低限必要な物
- LANケーブル
- Time Capsule
- Mac

# 配線
Time CapsuleはMacとLANポート(WANポートではない)で直接接続

# Time Capsuleの設定
1. まず、AirMacユーティリティを開く
![スクリーンショット 2024-05-15 18.22.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3200440/95037057-f46b-937c-abf6-fa569d6ab7eb.png)
このように、Time Capsuleが出てこない方は、「その他のWi-Fiデバイス」から、「Ethernet」
を選択します。
![スクリーンショット 2024-05-15 18.24.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3200440/bec5263a-37c2-38c1-1fb7-d04fd958b521.png)
このようになったら、次のステップへ進んでください。
2. 設定編集画面を開く
設定したいTime Capsuleをクリックし、
![スクリーンショット 2024-05-15 18.29.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3200440/74654eca-0d0b-754e-4758-32693d4e94a2.png)
上の様になったら、「編集」をクリックします。
3. 設定
上のタブから「ワイヤレス」をクリックし、ネットワークモードを「オフ」に設定します。
続いて、「ネットワーク」からルーターモードを「オフ（ブリッジモード）」に設定します。
AirMacユーティリティは閉じて、システム設定でTime Machineの設定を開きます。
何かエラーが発生していたら、Time Machineの設定を消して、もう一回設定してください。

# 終わり
ここまで見てくださり、有り難うございます。
もしよければ、ハートを押していただけると、今後の活動の助けになります。
また、何かトラブルがございましたら、この記事のコメントで教えていただければ、
順次返信していきますので、よろしくお願いします。
【TypeScript】unknown型ってなに？any型との違いは？

# **unknown型ってなに？**

簡単に言うと制約の強いany型です。

any型のように何でも代入できます。

```tsx
let a: unknown;
a = 0; // OK
a = "あいうえお"; // OK
a= { key: "オブジェクト" }; // OK
```

しかしany型とは違いそのままでは型が明示された他変数への代入やメソッド呼び出しができません。

また型アサーションで型推論を上書きすることもできません。

```tsx
const a: unknown = "abc";
// Type 'unknown' is not assignable to type 'string'.でエラーになる
const b: string = a;
// 'a' is of type 'unknown'.でエラーになる
a.toUpperCase();

a as string;
// 'a' is of type 'unknown'.で型アサーションでstringとして型推論を上書きできない
a.toUpperCase();
```

## 型が明示された他変数への代入やメソッド呼び出し方法

型を絞り込むと代入できるようになります。

```tsx
const a: unknown = "abc";
if (typeof a === "string") {
  // 型を絞り込んだif内ではstring型として扱えるようになる。
  const b: string = a;
  a.toUpperCase();
}

// プロパティも同じようにできる
type E = {
  name: unknown;
};
const e: E  = {name: ""};
if (typeof e.name === "string") {
  const b: string = e.name;
  e.name.toUpperCase();
}

// 連想配列も同じようにできる
const d: Record<string, unknown> = {"test": "test"};
const test = "test";
if (typeof d[test] === "string") {
  const b: string = d[test];
  d[test].toUpperCase();
}
```

しかし配列は型を絞り込む前にisArrayで配列であるか確認しないといけません。

```tsx
const c: [unknown] = [""];
if (Array.isArray(c) && typeof c[0] === "string") {
  const b: string = c[0];
  c[0].toUpperCase();
}
```

また連想配列は変数でKeyを指定して型や引数を絞り込むことができません。
(定数は絞り込みできます。)

```tsx
const d: Record<string, unknown> = {"test": "test"};
let test = "test";
if (typeof d[test] === "string") {
  // Type 'unknown' is not assignable to type 'string'.
  const b: string = d[test];
  // Object is of type 'unknown'.
  d[test].toUpperCase();
}
```

# any型との違いをまとめ

|  | any型 | unknown型 |
| --- | --- | --- |
| 代入できる値 | なんでもOK | なんでもOK |
| 他変数への代入 | できる | 型を絞り込まないといけない |
| アサーションによる型推論を上書き | できる | 型を絞り込まないといけない |
| メソッドやプロパティの呼び出し | 存在したら呼び出せる | 存在しても型を絞り込まないといけない |

**尾張！平定！…以上！皆解散！**

[記事書くの疲れたからunknown型の使い方はこれを見てくれ](https://typescriptbook.jp/reference/statements/unknown#unknown%E3%81%AE%E7%94%A8%E9%80%94)
【Python】python-dotenvはもともとOSに設定されている環境変数と同名の環境変数を上書きしない（override=Trueが必要）

タイトルの通りなのだが、ちょっと詰まったのでメモしておく。

`.env`ファイルに`AWS_ACCESS_KEY_ID`と`AWS_SECRET_ACCESS_KEY`を指定して`load_dotenv()`を実行したのだが、処理内で`print('AWS_SECRET_ACCESS_KEY=' + os.getenv(KEY_AWS_SECRET_ACCESS_KEY))`とかやってみても反映されていない。なんで？？と思ったら、もともとOSに同じ名前で環境変数が設定されていると、`load_dotenv()`はデフォルトではそれを上書きしてくれないのだそうだ。
参考:
https://pypi.org/project/python-dotenv/

この場合は`load_dotenv`の引数に`override=True`を指定する必要がある→`load_dotenv(override=True)`。

はい。お疲れさまでした。
【Next.js】はじめの一歩（１）

# はじめに
このページは、これまでPythonで飯を食ってきた筆者が、春から新しく関わることになったプロジェクトで初めてNext.jsを触ることになったため、最低限使えるようになるまでの学習の軌跡を記したものである。

したがって想定する読者は

- プログラミング初心者**ではなく**（Next.jsの作法や文法を知らないだけ）
- 筆者と同じく初めてNext.jsに触れる**Next.js初心者**

となっているため、プログラミングそのものが初めての人にはお勧めしないことに注意してほしい。

# Next.jsとは
「ReactベースのフルスタックWebアプリケーションフレームワーク」[[参考1][ref_1]]らしい。MITライセンスで開発されており、商用・私用を問わず無償で利用可能なようだ。

また、[こちら][ref_3]には

> Next.jsはサーバーサイドレンダリング(SSR)やファイルベースルーティングなど多くの機能をゼロコンフィグで提供してくれます。また、開発会社Vercelが同名のプラットフォームVercelを展開しており、デプロイ/ビルド/配信までを一気通貫に提供しています。

とあり、これだけだとまだ実感は湧かないが、なんだかすごそうな気がしてきた。

サーバサイドレンダリング（SSR）とは、クライアントサイドレンダリング（CSR）と対になるWebページの描画方法で、その名の通り、HTMLの生成をサーバ側で行うため、CSRと比較するとブラウザ側が低コストで済むのが大きなメリット。すなわちページを表示するデバイスのスペックをあまり考慮せずに、安定した配信が可能となる。またページ遷移ごとにサーバ側でレンダリングを行うため、表示速度には若干の遅延があるが、すべてのページに固有のURLが割り当てられるためSEOに強い（らしい）。

もちろんCSRにもそれなりのメリットは存在するため、作りたいものに合った描画方法を選択することが重要なのは言うまでもない。

# Next.jsのインストールから初期画面表示まで
以下、Windows + VSCode で作業していることを前提とする。MacやLinuxの場合は適宜読み替えてほしい。

### Node.jsのインストール
どうやらNext.jsをインストールするために、まずはNode.jsをインストールする必要があるようだ。[[参考2][ref_2]]

まずはNode.jsの[ダウンロードサイト](https://nodejs.org/en/download)を開いて、LTS版のインストーラをダウンロードする。その後ダウンロードしたインストーラを実行し、画面の指示に従ってインストールを完了したら、以下のコマンドで動作確認をしよう。インストールしたNode.jsのバージョンが表示されれば大丈夫だ。

```shell
node -v
# v20.13.1

npm -v
# 10.5.2
```

### プロジェクトの作成
作業ディレクトリまで移動して、以下のコマンドを実行すると、プロジェクトが自動作成される。

```shell
npx create-next-app sample_app
```

コマンドを実行すると、プロジェクトの設定についていろいろと質問されるが、今回は以下のように回答した。基本的にはEnterを押していくだけで良いはずだ。

```shell
√ Would you like to use TypeScript? ... Yes
√ Would you like to use ESLint? ... Yes
√ Would you like to use Tailwind CSS? ... Yes
√ Would you like to use `src/` directory? ... No
√ Would you like to use App Router? (recommended) ... Yes
√ Would you like to customize the default import alias (@/*)? ... No
```

プロジェクトの作成に成功すると、`./sample_app/` に必要なファイル群がひと通り生成されている。あとは生成されたREADME.mdにもある通り、プロジェクトルートで

```shell
npm run dev
```

すれば開発用サーバが立ち上がるので、[http://localhost:3000](http://localhost:3000)にブラウザでアクセスして、初期画面が表示されることを確認しよう。

記事が長くなりそうなのと、リアルタイムで学習している真っ最中なので、この続きは次の投稿で書くこととする。

# 参考文献
1. [とほほのNext.js入門][ref_1]
1. [Windows 10へNode.jsをインストールする][ref_2]
1. [Next.jsを使うべき5つの理由 + 実装Tips][ref_3]

[ref_1]: https://www.tohoho-web.com/ex/nextjs.html
[ref_2]: https://qiita.com/echolimitless/items/83f8658cf855de04b9ce
[ref_3]: https://qiita.com/Yuki_Oshima/items/5c0dfd8f7af8fb76af8f