OmniAICreator/Qiita-1.07M huggingface dataset:
AWS 認定 AI Practitioner に合格しました

## はじめに

AI Practitioner は AWS 認定の一つで、 AI や機械学習の知識と AI を AWS 上で活用するための知識が証明できます

https://aws.amazon.com/jp/certification/certified-ai-practitioner/

大昔、 ソリューションアーキテクト アソシエイト に合格して、そのまま更新せずに失効してしまいました

今回、久しぶりに AWS 認定を受けようと思い、確実に合格できそうなものとして AI Practitioner を受験しました

目論見通り一発合格できたので、勉強内容等を残しておきます

[![AI Practitioner badge](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/27c8661a-aec0-ee6e-6cbf-56972517091f.png)](https://www.credly.com/badges/a8d4288b-1a87-4ba0-ba71-1cb52e735b1f/public_url)

2024年8月に新設された認定なので、早期取得のバッジもゲットしました

[![Early adopter badge](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/d2648e12-5ea0-9120-68a0-8cae17b704a3.png)](https://www.credly.com/badges/ecb8e84f-72e1-462d-9319-7410ad46e103/public_url)

## 受験をオススメする対象者

AI Practitioner 公式サイトの「対象者」には以下のように書かれています

> AWS の AI/ML テクノロジーを使用するソリューションを熟知してはいるが、必ずしも構築するわけではないという個人

実際、 Python を読み書きしたり、具体的な AI フレームワークに関する知識を問われたりはしません

あくまでも AI 、機械学習に関する一般的な知識があれば十分です

日本ディープラーニング協会の「G検定」を持っていれば、 AI 知識の要件としては満たしているのではないでしょうか

https://www.jdla.org/certificate/general/

ちなみに私は「G検定」は受験したことがなくて、「E資格」を持っています

https://www.jdla.org/certificate/engineer/

業務で AI を扱っていれば AI Practitioner 受験に問題はないと思います

AWS の資格は取りたいけど Cloud Practitoner は範囲が広すぎる、でも G 検定や E 資格は持っている、という人にはオススメです

## 勉強方法

AWS Skill Builder で勉強しました

https://skillbuilder.aws/jp

思った以上にコンテンツが豊富で、一通り見ておけば「何を知っておかないといけないのか」が分かります

一般的な AI 知識のコンテンツもあるので、受験しなくても AI 入門学習に使えます

## 受験結果

無事合格はしたものの、私は AWS の AI サービス周りで得点が低くなっていました

AWS の AI サービスは近年で大幅に増加、機能強化しているため、昔使っていたサービスもかなり変わっており、「SageMaker でそんなことまでできるようになっているの!?」というようなものが多いです

https://aws.amazon.com/jp/ai/services/

また、ガバナンスやコンプライアンス関係のサービスも増えていて、 AI を **使っているだけ** だと関わらないようなものもかなりあります

https://aws.amazon.com/jp/ai/responsible-ai/

## まとめ

何はともあれ合格できて良かったです

単純にテストセンター自体 E 資格ぶりだったので緊張しましたが、ここから波に乗っていきたいなあ
アンケートへの回答データをケースとリンクする



+ [Link SurveyResponses with Cases](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007erEuaSAE)

>SurveySubject を SurveyResponse レコードにリンクして、回答を適切にレポートし、関連するケースまで追跡できるようにする方法を探しています。ドキュメントによると、SurveySubject.SurveyResponseId フィールドは作成/更新できないようです。

アンケート対象レコードには、アンケート招待、関連オブジェクトの開発者名、および関連オブジェクトのレコード ID である件名 ID にリンクするフィールドがあります。

 

手順は次のようになります。

1. 調査招待にケース レコードにリンクするカスタム参照フィールドを作成します。
2. アンケート対象レコードが作成された後に起動するフロー トリガーを作成します。オブジェクト名がケース オブジェクトと一致する場合は、手順 1 で作成したフィールドに件名 ID をコピーして、識別されたアンケート招待を更新します。

アンケート招待のカスタム ルックアップ フィールドを使用すると、ケース レコードのすべてのフィールドにアクセスできます。実際にフィールドを表示するには、カスタム レポート タイプを作成する必要がある場合があります。

この手法は、アンケートの回答にリンクするすべてのオブジェクトに適用されます。

------
長い間 Surveys に使用しているテスト組織を確認しました。2022 年初頭まで遡って、166 件の SurveyResponse レコードが作成されていました。どのレコードにも SurveyResponseId 値がありません。

アンケート件名オブジェクトは、Salesforce アンケートが Spring 18 リリースで開始されてから 1 年後の Spring 19 リリースで追加されました。これは、フィードバック管理と合わせて Summer 20 リリースで「発表」されました。また、アンケートへの招待と関連オブジェクト レコード (ラテン語のexempli gratiaは「たとえば」または「例として」を意味します) 間のリンクが初めて提供されました。ケース、商談、または任意のカスタム オブジェクトなどです。

どうやら、SurveyResponseId は「当時は良いアイデアだった」ものの、使用されたことも接続されたこともなかったようです。 

これは、Summer 20 リリースで導入されたフィードバック管理の一部である可能性があります。ただし、フィードバック管理を使用して確認するために年間 50 万ドルを費やす余裕はありません。

+ [アンケート招待オブジェクトを使用しており、メール、SMS、Whatsapp などの多くのチャネルを使用してそれを送信しています。クライアントが回答するために使用したチャネルを何らかの方法で検出することは可能ですか? SurveyInvitation リンクで UTM を使用して、それに基づいてフィールドに入力することを考えました。 ](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000JzDmJSAV)

:::note
おそらく、箱から出してすぐに使えるものは何もありません。

1 つの提案は、アンケートの招待にカスタム フィールドとして「チャネル」の選択リスト フィールドを追加することです。 

また、デジタルエンゲージメントチャネルとフィードバック管理がある場合は、これらを使用してアンケートの招待状を送信できます。[ヘルプリンク](https://help.salesforce.com/s/articleView?id=sf.task_distribute_surveys_using_digital_engagement_channels.htm&type=5)。
:::
REST API advancements2

PythonでWebexの部屋一覧を表示してみる。

必要なドキュメントは
https://developer.webex.com/
＞Documentaion
＞Full API Reference
＞Rooms
にある。

https://developer.webex.com/docs/api/v1/rooms

ドキュメントは簡単なAPIテストツールにもなっており、
Create a RoomにアクセスしTitleをいれRunをクリックするとRoomが作成される。
![Screenshot_2024-11-24_06-26-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943132/542b7bd9-6692-928b-62f4-cd1f06482bdd.png)

次にList RoomsからOKを押すとつくったRoom一覧が作成される。これをPythonで取得するのが今回の目的だ。まず右上のBearerをコピペしよう。これがPythonからCISCOのAPIにアクセスするキーになっている。
![Screenshot_2024-11-24_06-38-32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943132/bb0c2150-d332-07ee-029e-5e79cc0e7ef6.png)

input token hereのところにBearerを入れて実行しよう。
```python
#PythonでHTTPリクエストを簡単に行うためのライブラリ
import requests

rooms_url = "https://webexapis.com/v1/rooms"
access_token = 'input token here'

query_headers = {
#サーバーに対してこのリクエストのレスポンスとして、JSON形式のデータを希望
    "Accept":"application/json",
    'Authorization': f'Bearer {access_token}'
}

#CISCOのDocumentの要求形式
query_params = {
    "sortBy":"lastactivity",
    "max":"5"
}

response = requests.get(url = rooms_url,headers=query_headers, params=query_params)

print(response.status_code)
print(response.text)

```

うまくいくとステータスコードの200と詳細情報が帰ってくる
```shell
200
{"items":[{"id":"Y2lzY29zcGFyazovL3VybjpURUFNOnVzLXdlc3QtMl9yL1JPT00vM2EyNTNmMzAtYTllMS0xMWVmLTgxZmMtODM2YWRmZjZkMjNm","title":"Test","type":"group","isLocked":false,"lastActivity":"2024-11-23T21:23:48.004Z","creatorId":"Y2lzY29zcGFyazovL3VzL1BFT1BMRS9lYWIwYjZkOS1kMjM4LTQwOTctYTE4ZS1iZDZmODIwZDYwMGY","created":"2024-11-23T21:23:48.004Z","ownerId":"Y2lzY29zcGFyazovL3VzL09SR0FOSVpBVElPTi81NWY0YmRjYS05MmVlLTQ1NWQtOTRmYy0zZGY5ZjZiNTIyMWI","isPublic":false,"isReadOnly":false},{"id":"Y2lzY29zcGFyazovL3VybjpURUFNOnVzLXdlc3QtMl9yL1JPT00vOWQ0NjljZjAtYTlkYS0xMWVmLTk3OGYtYzk0M2JmYzBjMWMz","title":"testtest2","type":"group","isLocked":false,"lastActivity":"2024-11-23T21:11:39.143Z","creatorId":"Y2lzY29zcGFyazovL3VzL1BFT1BMRS9lYWIwYjZkOS1kMjM4LTQwOTctYTE4ZS1iZDZmODIwZDYwMGY","created":"2024-11-23T20:36:27.839Z","ownerId":"Y2lzY29zcGFyazovL3VzL09SR0FOSVpBVElPTi81NWY0YmRjYS05MmVlLTQ1NWQtOTRmYy0zZGY5ZjZiNTIyMWI","isPublic":false,"isReadOnly":false},{"id":"Y2lzY29zcGFyazovL3VybjpURUFNOnVzLXdlc3QtMl9yL1JPT00vOThhMTA5YjAtYTlkYS0xMWVmLWExZDUtNGIxYWZkZGNlYjYw","title":"testtest","type":"group","isLocked":false,"lastActivity":"2024-11-23T20:36:20.043Z","creatorId":"Y2lzY29zcGFyazovL3VzL1BFT1BMRS9lYWIwYjZkOS1kMjM4LTQwOTctYTE4ZS1iZDZmODIwZDYwMGY","created":"2024-11-23T20:36:20.043Z","ownerId":"Y2lzY29zcGFyazovL3VzL09SR0FOSVpBVElPTi81NWY0YmRjYS05MmVlLTQ1NWQtOTRmYy0zZGY5ZjZiNTIyMWI","isPublic":false,"isReadOnly":false}]}
```

:::note info
今日の課題とまとめ
・APIのドキュメントとAPIテスターは一緒になっている。
・Tokenがうまく認証されなかったがCHAT　GPTににたプログラムをつくってコピペしたら動いたが問題の原因は不明である。Pythonはエラーが不明確な事が多い。
REST API advancements

# REST API advancements

POSTMANやWEBブラウザで生成したHTTPクエリをサーバーに
送信し、サーバー側でHTTPレスポンスを返す。

## HTTPクエリは以下の要素がある。
```
0 メソッド
1 URL
2 ヘッダー
3 ボディ/ペイロード (オプション)
```
## HTTPレスポンスは以下の要素がある。
```
0 ステータスコード
1 ボディ/ペイロード
```
## Rest APIページ化
レスポンスが大きいときに複数ページに分割する
### ページ化の方法
```
ページベースページ化
特定のページを直接指定する
例)events?page=3&page-size=30
```
```
カソールベースページ化
カソールをつくってその範囲を指定する
例）beforeID=6&max=3
```
カソールベースの方がデータ変動に強い。ページベースは
わかりやすいがデータ変動に弱い。


## Cisco SDN製品
```
Enterprie分野：SD-WAN、SD-ACCESS、MERAKI
ServiceProvider分野：Cisco　NSO、Cisco　Crossworks
Datacenter分野：ACI、NDFC、IPFM、InterSight、UCS　Director
Collaboration分野：Webex、Cucm、UCCX
```

いろいろなCISCO製品があるがすべて独自のAPIがありHTTPで通信する。
https://devnetsandbox.cisco.com
で挙動が確認ができる。サーバー使用率の高いAPIは予約が必要。
GitHubのパスキーをiPhoneを使って1passwordに登録する手順

# はじめに

パスキーの設定方法で大いに迷ったので、手順を書き留めておきます。この手順は、パスキーを何度も設定している経験者には当たり前かもしれませんが、初心者にはかなり戸惑う部分があると思います。

ところで、なぜ1Passwordにパスキーを設定したいかというと、1Passwordは同期できる認証器であり、複数のデバイスで同じパスキーを使用できるからです。さらに、Appleのキーチェーンとは異なり、複数のプラットフォームで使えるので便利です（ただし、これは便利さと安全性を天秤にかけているため、必ずしも正しいアプローチとは限りません）。

# 結論

**QRコードはiPhoneのカメラで読み取る**

# 前提

* iPhoneのカメラ設定で「QRコードを読み取る」がオンになっている
* iPhoneの「認証コードを設定するアプリ」で「1Password」が選択されている（これが設定されていないと、1Password以外の認証アプリが開いてしまいます）

![20241123_210813000_iOS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/a636bb5e-2e40-35e7-01c4-043ed9bf4870.png)

# 手順

1. GitHubにサインインする（既存のパスワード＆2FAなどでサインインします。これでワンタイムパスワードなどの煩雑な手順は最後になるかもしれません！）
2. GitHubの設定ページで「Password & Authentication」（日本語だと「パスワードと認証」など）に移動する
3. 「Passkeys」のセクションで「Add a passkey」というボタンをクリックする
4. ブラウザのダイアログが表示され、さらに「Add passkey」というボタンが出るので、それをクリックする
5. パスキーの保存場所として「iPhone、iPad、Android」を選択する（他にはUSBデバイスなどの選択肢があります）
6. QRコードが表示される
7. iPhoneのカメラでQRコードを読み取る（1Passwordに「パスキーのQRコードを読み込む」機能を探していましたが、見つかりませんでした）
8. カメラがQRコードを読み取ると、「1Passwordにパスキーを保存しますか？」と表示されるので、続行する
9. 1PasswordとGitHubの両方に新しいパスキーが保存され、「完了しました」となります。これで、1PasswordにGitHubアカウントのパスキーを追加することが完了します

# バリエーション

私はiPhoneでのメインのAuthenticatorとして1Passwordを使用しています。他にもMicrosoftやGoogleのAuthenticatorアプリ、Apple純正のパスワードアプリなどがあります。どれを使うかは個人の選択です。

パスキーはデバイスごとに設定できるので、GitHub側でも複数のパスキーを設定できます。GitHubに保存する際、ニックネームを付けるよう求められるので、「デバイス名」を入力すると良いでしょう。複数のデバイスにそれぞれ設定する方が、1Passwordなどで複数のデバイスに同期するより安全性が高くなります。もしデバイスを紛失した場合、該当するパスキーをGitHub側で削除すれば、その紛失したデバイスからGitHubへのサインインは不可能になります（これはGitHubに限らず、パスキーの特徴です）。
JavaScript: readAsBinaryStringは2度死ぬのか

歴史的背景として`ArrayBuffer`が標準化される前から`readAsBinaryString`は実装されているが、`readAsArrayBuffer`の登場によりその利用価値はほぼ皆無となり、**File APIの仕様から削除された**とかいう噂が飛び交っている。
しかし後方互換の為に再び仲間として生暖かく迎えられたとかいう噂が飛び交っている。そんな理由で仲間入りした所で、果たして最後まで冒険を共にする事ができるだろうか? 2度死ぬ未来が訪れないとも言い切れない。

## 使い所さん
などといった下らない前置きはこのくらいにして、本題に話をすり替えていこう。個人的にはこの役に立たない便利な`readAsBinaryString`はまだ使い所さんがあると思い込んでいる。例えば以下のような処理である。
```html:Base64encode
<input type=file oninput="with(new FileReader)readAsBinaryString(files[0]),onload=b=>a.href=self.URL.createObjectURL(new Blob([btoa(result)]))"><a download id=a>DL</a>
```
上記の処理を`readAsArrayBuffer`でやろうとするとクソ面倒な事になる。`btoa`は文字列しか受け入れやがらない体質だからだ。代替しようとすると`btoa`への渡し方は以下のようになる。
```js
btoa(String.fromCharCode.apply(0,result))
```
ただしこれだと引数の個数の限界に引っ掛かると動作しなくなる。`apply`に代わりspread構文にしても同じ事である(現時点では)。限界突破したいなら以下のような処理になる。
```js
btoa(Array.from(new Uint8Array(result),a=>String.fromCharCode(a)).join(""))
```
言うまでもなく低速化は免れられない。Unicode番号127以下の文字しか含まれない文字列であれば以下のようにできる。
```js
btoa(new TextDecoder().decode(result))
```
## 余談
さて、他にも使い所は山盛りてんこ盛りであるが、そんな事はもはやどうでも良い。`atob`といい`btoa`といい、その変態的な仕様にはうんざりだ。`atob = ascii to binary`、`btoa = binary to ascii`という解釈ではないのか。
それにもかかわらず`atob`の返り値は文字列、`btoa`の引数は文字列、これでは両方とも`ascii to ascii`だろうと突っ込まざるを得ない
PythonコードにJSONを書く方法(本当の意味で)

## 概要

JSONは本来JavaScript実行環境でJavaScriptとしてそのまま実行できることが特徴のデータ形式ですが、同じことをPythonでやる方法を思いついたのでメモ。

## やり方

Pythonではbool値は`True`,`False`(先頭が大文字)、nullに相当する値は`None`ですが、幸いなことにJSONで使う`ture`,`false`,`null`はPythonにおいては予約語ではなく変数として定義できるので、これらにそれぞれ`True`,`False`,`None`を代入して定義すれば、Pythonの辞書リテラルをJSONと全く同じ表記で書くことができます。

JavaScriptとは違い、Pythonの辞書リテラルはキー名をクォーテーションで囲む必要があるのでよりJSONっぽいです。

```python
true = True
false = False
null = None

print(
{
    "name": "John",
    "age": 30,
    "married": true,
    "divorced": false,
    "children": [
        {
            "name": "Ann",
            "age": 5
        },
        {
            "name": "Sally",
            "age": 7
        }
    ],
    "nulldata": null
}
)

# -> {'name': 'John', 'age': 30, 'married': True, 'divorced': False, 'children': [{'name': 'Ann', 'age': 5}, {'name': 'Sally', 'age': 7}], 'nulldata': None}

# 上記の表記が正当なJSONであることを確認するために同じ内容をjson.loadsでロードしてみる

import json

print(json.loads("""
{
    "name": "John",
    "age": 30,
    "married": true,
    "divorced": false,
    "children": [
        {
            "name": "Ann",
            "age": 5
        },
        {
            "name": "Sally",
            "age": 7
        }
    ],
    "nulldata": null
}
"""))

# -> {'name': 'John', 'age': 30, 'married': True, 'divorced': False, 'children': [{'name': 'Ann', 'age': 5}, {'name': 'Sally', 'age': 7}], 'nulldata': None}
```

## 使い道

あるの…？思いついたのはPythonコードを別のプログラムで生成しそこにJSONを埋め込むような時にプログラムや生成するPythonコード上でJSONをパースする処理を書く必要がなくなるくらい？
Module-LLMからPCのブラウザへ動画データを送る


## 目的

Module-LLMでmp4を再生してhttp経由でPCのブラウザに送ってみました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">LLM Moduleでmp4を再生してhttp経由でPCのブラウザに送ってみました。<br>UART転送を見慣れた後には普通に早い… <a href="https://t.co/WSXlLlgvsw">pic.twitter.com/WSXlLlgvsw</a></p>&mdash; nnn (@nnn112358) <a href="https://twitter.com/nnn112358/status/1860311663888728276?ref_src=twsrc%5Etfw">November 23, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

## PCのブラウザに画像を送る

Module-LLMのrootアカウントにログインし、pipでOpenCVとFastAPIをインストールします。

```
# apt install libopencv-dev
# pip install opencv-python fastapi
# python3 send_http_mp4.py
```

　このプログラムはFastAPIフレームワークを利用してビデオストリーミングサーバーを実装したものです。指定されたビデオファイルを読み込み、フレームごとにリサイズしてブラウザにストリーミング配信します。
　処理の流れとしては、まずFastAPIのアプリケーションインスタンスを作成し、ビデオ処理のための補助関数として、入力フレームを320x240ピクセルにリサイズする`resize_frame`関数を定義します。続いて、ビデオストリーミングの核となる`get_video_stream`関数では、OpenCVを使用してビデオファイルを読み込み、フレームごとに処理を行います。各フレームはリサイズされ、JPEGフォーマットにエンコードされ、マルチパート形式でストリームデータとして生成されます。
 　ウェブブラウザで http://localhost:8888/video にアクセスすることで、ストリーミングされるビデオを視聴することができます。

```send_http_mp4.py
from fastapi import FastAPI, Response
from fastapi.responses import StreamingResponse
import cv2
import numpy as np
from typing import Generator
import time

app = FastAPI()

def resize_frame(frame: np.ndarray, width: int = 320, height: int = 240) -> np.ndarray:
    return cv2.resize(frame, (width, height), interpolation=cv2.INTER_AREA)

def get_video_stream(video_path: str) -> Generator[bytes, None, None]:
    video = cv2.VideoCapture(video_path)
    try:
        while True:
            success, frame = video.read()
            if not success:
                break
            frame = resize_frame(frame)
            time.sleep(0.01)
            _, buffer = cv2.imencode('.jpg', frame)
            yield (b'--frame\r\n'
                  b'Content-Type: image/jpeg\r\n\r\n' + buffer.tobytes() + b'\r\n')
    finally:
        video.release()
@app.get("/video")
async def video_endpoint():
    video_path = "./video.mp4"
    return StreamingResponse(
        get_video_stream(video_path),
        media_type='multipart/x-mixed-replace; boundary=frame'
    )
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8888)
```
今回は「新入社員のエンジニアが1年目に読むべき本」をご紹介します。 

はじめに
今回は「新入社員のエンジニアが1年目に読むべき本」をご紹介します。

私は2021年4月に新卒としてWebエンジニアとして働き始め、2022年は2年目になります。
1年前のスキルレベルについては以下の通りです：

HTMLとCSSを使った静的コーディングが可能
jQueryを使った動的Webサイトの作成が可能
ReactやTypeScriptの基礎知識がある
PHPを使って簡単なブログを作成可能
これが私のスキルセットでした（会社に入社する前に、独学や研修を通じて学んだレベルです）。

1年前の自分に向けて、「この本を読んでほしい」と思う本をご紹介します。
自分自身の経験を踏まえて、なぜこれらの本を読むべきなのかも解説します。

このブログはこんな人におすすめ
エンジニアを目指して勉強中の人
エンジニア1年目の人
技術書をあまり読んでいない人
全エンジニアに
リーダブルコード
![本の画像](スクリーンショット 12-08-2022 10.47.48.jpg)

まずご紹介するのは、名著「リーダブルコード」です。

「リーダブルコード」は、コードを書く人すべてが読むべき本と言われる傑作です。
この本を読むことで、他人が読んでも理解しやすいコードを書く方法を学べます。

具体的には以下の内容を学ぶことができます：

読みやすいコードとは何か
変数名の付け方
コメントの書き方
理解しやすいロジックの書き方
SQLパズル20　テスト結果 解法１ 学習メモ

# 概要
SQL パズル20　テスト結果 解法１の学習メモです。
Exists述語を使った解法です。

# 要件
全てのcomp_dateに値が入っている科目の情報のみを取得する。
→comp_dateに対して、nullが一つも存在しない科目を取得する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/804c6c95-e4f0-dccf-f60f-63ccd3f5d043.png)

# DDL
```sql
drop table if EXISTS TestResults;
create table TestResults(
    test_name CHAR(20) not null,
    test_step integer not null,
    comp_date Date,
    primary key(test_name,test_step)
);

INSERT INTO TestResults VALUES('読解', 1, '2006-03-10');
INSERT INTO TestResults VALUES('読解', 2, '2006-03-12');
INSERT INTO TestResults VALUES('数学', 1, NULL);
INSERT INTO TestResults VALUES('数学', 2, '2006-03-12');
INSERT INTO TestResults VALUES('化学', 1, '2006-03-08');
INSERT INTO TestResults VALUES('化学', 2, '2006-03-12');
INSERT INTO TestResults VALUES('化学', 3, '2006-03-15');

```

# 答え
```sql
-- テスト結果 その１　EXISTS 全量化
SELECT DISTINCT test_name
FROM TestResults AS T1
WHERE NOT EXISTS (SELECT *
                    FROM TestResults AS T2
                    WHERE T1.test_name = T2.test_name
                    AND T2.comp_date IS NULL);


-- サブクエリ内
-- 科目同士の組み合わせ（自己結合）でcomp_date=nullのレコードを取得
SELECT T1.*
FROM TestResults AS T2,TestResults AS T1
WHERE T1.test_name = T2.test_name
AND T2.comp_date IS NULL
;


--  comp_date != nullが一つも存在しない科目のレコードを取得
-- 全称量化の二重否定
SELECT *
FROM TestResults AS T1
WHERE NOT EXISTS (SELECT *
                    FROM TestResults AS T2
                    WHERE T1.test_name = T2.test_name
                    AND T2.comp_date IS NULL);
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/12284f3c-f47b-95f7-56f5-9e64a3368dde.png)


# 参考
SQLパズル　p88

SQLパズル　サポートページ
https://mickindex.sakura.ne.jp/database/db_support_sqlpuzzle.html#LocalLink-p20

達人に学ぶSQL徹底指南書第２版 p90 Exists述語の使い方　肯定↔️二重否定の変換に慣れる

Distinct
https://www.postgresql.jp/docs/9.5/queries-select-lists.html

EXISTS述語
https://www.postgresql.jp/document/7.3/user/functions-subquery.html

github 差分

https://github.com/RYA234/SQL_Puzzle_Learning/commit/998b3f058e331c861289d21ff1971fbfd6713d4e
僕の愛する HHKB カスタマイズ

# はじめに

Qiita Advent Calendar 2024 の「⌨ ぼくのかんがえたさいきょうのきーぼーど ⌨」の6日目の投稿です！

HHKB の構成を晒します(^^)/

HHKB の利用は3年くらい。その前は Realforce を5年くらい使ってました。
愛用の Logicool トラックボールマウスの「MX ERGO」とセットで、プライベートも仕事でも使ってます。
（「MX ERGO S」欲しい… :yum: サンタさん… :santa_tone1: 

HHKB を使い始めてから、Vim/NeoVim とのコンパクトな操作ともマッチして、とにかくキータイプが楽しい、コーディングが楽しい:exclamation:
イイモノはやっぱり QoL を上げますね:exclamation: 

# HHKB グラビア

## プライベート用

ベースは **「HYBRID Type-S」**。
普段、PC とは別に iPhone や iPad、さらに +αで切り替えて使う事もあるので、Bluetooth のチャンネルが4つもあるのはとても嬉しい。
さらに、Bluetooth が使えない環境 (BIOS 操作してる時や Rasberry Pi に直接書き込んでる時など) は有線接続も可能なので、**実質5チャンネル使える**構成です。万能すぎる:exclamation:

キーキャプは、「EC HHKB D&G REV2 DYE SUB KEYCAPS」。
色んなネットの海を多大酔いながら、行きつき、[KBDfans](https://kbdfans.com) で購入しました。
（今はこのショップでは買えないのかな？

色構成がこの HHKB のブラックに映えるのと、特にこのグレーと赤の色味がとても好みです。
さらにはフォントがオシャレ:exclamation:
小さいファンクション用の印字も赤色が生えてオシャレ:exclamation:
とてもセクシーですね～:blush:

![IMG_8063.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/bd4a8a6a-2eb4-cf6f-5959-8982818bce26.jpeg)

木材っぽい机の上でもｲｲｶﾝｼﾞの存在感。

![IMG_8056.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/7d694431-0dba-2498-323c-05bf5fe631a8.jpeg)

この配色と、~ キー、Del キー、エンターキー、Shift + Fn キーの長さのコントラストがカッコイイ。
さらにそこから下に目線を流すと存在感のある赤色のスペースばー。
思わずタイプしたくなる。
「　　　　　　　　　　　　　　」

![IMG_8061.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/63be3dd2-7fc5-6d90-6235-817474c212be.jpeg)

この近寄ったショットは特にセクシー。

![IMG_8068.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/90c41e12-195e-9699-4ca2-aca2ae89bde1.jpeg)

## 仕事用

仕事用の HHKB はオフィスにあり、写真は撮れないので軽く文字列だけ。

ベースの繁体は、プライベートのと同様に **「HYBRID Type-S」** を使用。
内側の文字・数字列キーは「HHKB のホワイトのスペアキーキャップ」を別途購入してつけている。
Esc と Enter は、「カラーキートップセット（HHKB Professionalシリーズ専用）」をこれまた別途購入して付けている。

# スイッチ構成

スイッチは、プライベート用・仕事用共に1と3だけ**ON**。
BS 利用だけはしたいので。

https://happyhackingkb.com/jp/products/discontinued/hhkb_backview.html

# キーマップ

特に変更なし！デフォルト最強:exclamation::exclamation::metal:

# さいごに

年末なので、分解してキーキャップやフレームを洗浄しつつさっぱりさせました。

来年もよろしくネ:exclamation::exclamation::raised_hands:
四旬節第二金曜日、またはクリスマスのミサ開始まであとどれくらいか、カウントダウンするスクリプト [Python]


タイトル通りです。待ってます。

他の年のを求めたければ、スクリプト内の`y=2025`を変えてください。

Pythonはなんでこんなに日付と時間の扱いが複雑なんだろう。unix時間を使ってシリアルにしたら良いのに。他のやり方があるみたい。
機械と人間のインターフェースは大変だ。

```countdown.py
#!/usr/bin/python
import datetime
import time
from datetime import timedelta

def lent_second_friday(year):
    # イースターの日付を計算（アルゴリズムは「メートンのアルゴリズム」を使用）
    easter = calculate_easter_date(year)
    
    # イースターの46日前がレントの開始日（灰の水曜日）
    lent_start = easter - timedelta(days=46)
    
    # レント開始日（灰の水曜日）から、最初の金曜日を探す
    first_friday = lent_start + timedelta(days=(4 - lent_start.weekday() + 7) % 7)
    
    # 第二金曜日は四旬節が始まってから3番めの金曜日とされているので、
    # 14(二週間)を足して計算する
    second_friday = first_friday+timedelta(days=14)

    # 8:30時(ミサ開始時)のdatetimeを返す
    return second_friday.replace(hour=8, minute=30, second=0, microsecond=0)

def calculate_easter_date(year):
    """ イースターの日付を計算する関数（メートンのアルゴリズム） """
    a = year % 19
    b = year // 100
    c = year % 100
    d = b // 4
    e = b % 4
    f = (b + 8) // 25
    g = (b - f + 1) // 3
    h = (19 * a + b - d - g + 15) % 30
    i = c // 4
    k = c % 4
    l = (32 + 2 * e + 2 * i - h - k) % 7
    m = (a + 11 * h + 22 * l) // 451
    month = (h + l - 7 * m + 114) // 31
    day = ((h + l - 7 * m + 114) % 31) + 1
    return datetime.datetime(year, month, day)

def main():

    y=2025

    tt1=lent_second_friday(y)
    t1=int(time.mktime(tt1.timetuple()))
    print(f"{y}年四旬節第2金曜日 {tt1}")
    while True:
        tt2=datetime.datetime.now()
        t2=int(time.mktime(tt2.timetuple()))
        if t1>=t2:
            print (chr(13)+"Rest is :",tt1-tt2,"   ",end='')
        else:
            return

if __name__=='__main__':
    main()
    print("Reached.")
    exit(0)


```

2024年のクリスマスまで。

```cdc.py
#!/usr/bin/python
import datetime
import time
from datetime import timedelta

def calculate_easter_date(year):
    return datetime.datetime(year, 12, 25)

def main():

    y=2024

    tt1=datetime.datetime(y,12,25)+timedelta(hours=8,minutes=30)
    t1=int(time.mktime(tt1.timetuple()))
    print(f"{y}年クリスマス {tt1}")
    while True:
        tt2=datetime.datetime.now()
        t2=int(time.mktime(tt2.timetuple()))
        if t1>=t2:
            print (chr(13)+"Rest is :",tt1-tt2,"   ",end='')
        else:
            return

if __name__=='__main__':
    main()
    print("Reached.")
    exit(0)
```
Hono + Cloudflare で Twemoji を返却するAPIを作成した！


## はじめに

今回は、Hono、Cloudflare Pages を使って、簡単に Twemoji を返却する API を作ってみた話をまとめました！

この記事では、その作成過程や使った技術について紹介します
なお、Hono などの詳細な解説は省略しますので、詳しく知りたい方は公式ドキュメントを参照してください

このプロジェクトは以前の記事で作成した [Hono + Satori + Cloudflare でアバター生成 API を作った！](https://qiita.com/minagishl/items/0874a71924ae6526abdf) をベースに、Twemoji を返却する API を作成しました

## プロジェクトの概要

このプロジェクトでは、ユーザーが指定した絵文字をもとに、Twemoji を返却する API を作りました
どんな技術を使って、どうやって実現したのかを紹介します

### 1. Hono で API ポイントを作成

Hono は非常に軽量で高速なウェブフレームワークです
このプロジェクトでは、API のエンドポイントを作成し、ユーザーが入力した絵文字を受け取り、変数に格納しました

（今回は以前のコードよりも綺麗に描けたと思います）

https://github.com/minagishl/hono-twemoji/blob/a0da4d534900bd84f0b1d5a7492b173798419d52/src/index.ts#L48-L80

### 2. 独自関数で ID に変換

個人的には、絵文字を ID に変換する関数が一番難しかったです
絵文字を ID に変換するために、絵文字の Unicode を取得し、それを元に ID を生成しました

https://github.com/minagishl/hono-twemoji/blob/a0da4d534900bd84f0b1d5a7492b173798419d52/src/index.ts#L6-L42

### 3. Cloudflare Pages にデプロイ

Cloudflare Pages は、静的サイトや Next.js などを簡単にデプロイできるサービスです。このプロジェクトでは、Cloudflare Pages を使って、Twemoji を返却する API をデプロイしました

個人的に Cloudflare Workers よりも Pages の方が `{appname}.{username}.workers.dev` という URL が `{appname}.pages.dev` になるので、敷居が低いと感じています

### 4. 使い方

この API は、以下の URL にアクセスすることで利用できます

```
https://hono-twemoji.pages.dev/emoji/👍.png
```

## まとめ

今回は Hono、Cloudflare Pages を使って、Twemoji を返却する API を作成しました
興味がある方は、ぜひ [GitHub のリポジトリ](https://github.com/minagishl/hono-twemoji) をご覧ください

またもしよろしければ、以前の記事もご覧いただけると幸いです

https://qiita.com/minagishl/items/0874a71924ae6526abdf

コードに関するレビューやフィードバックがあれば、大歓迎です！どんな意見でもお待ちしています
アクセストークンをどこに保存するか

## 概要

この記事は、ID Token(IDT)、Access Token(AT)、Refresh Token(RT)をどこに保存すべきか迷っている方向けです。タイトルにはアクセストークンと書きましたが他のトークンも扱います。

https://qiita.com/yngwie6120/items/e481a8a174c6d4f7fc02

以下が結論です。

| Client | 説明 |
|:-:|:-:|
| SPA | AT/IDT：メモリ上 、RT：①発行しない or ②安全性が許容範囲内ならLocal Storage（ローテーション機能等をID Provider側で実装）。認証処理はサーバサイドCookieで省略可能 |
| ネイティブアプリ | SPAと同様 |
| バックエンドシステム | サーバサイドの安全な永続化ストレージに保存|
| バックエンドを持つWebシステム(クラシックWeb) | バックエンドシステムと同様 |

## まず理解しなければいけないこと：Client Type

OAuthの考え方では、アプリケーションにはConfidentialとPublicの2種類があります。


| Client Type | 説明 | 例 |
|:-:|:-:|:-:|
| Confidential | 鍵を安全に管理可能 | バックエンドシステム、クラシックWeb |
| Public | 鍵を安全に管理不可能 | SPA、ネイティブアプリ |

Publicクライアントでは、秘密鍵を安全に保持できないためクライアントの正当性やトークン流出時のケアなどができなくなります。

https://zenn.dev/ritou/articles/d26c7861047a2d


## SPA・ネイティブアプリの保存場所

本記事ではAPIからデータを取得して利用する程度のアプリケーション(SPA)を想定します。金融システムなどのことは考えません。

SPA構成のWebを想定してみると、使えるのはブラウザ側の機能もしくはSPAのコードとなりますので、保存できる領域はCookie、Session Storage、LocalStorage、オンメモリなどの選択肢となります。


ID Token/Access Token

- 保存推奨：オンメモリ（XSS対策）
- 注意点：リロードで消えるため短い有効期限を推奨


Refresh Token

- 保存先候補：Local Storage or Session Storage or 発行しない
- 注意点：発行する場合にはID Providerでローテーション・多重利用検知を実装


cookieに保存するとサブドメイン全体に該当のトークンが送信され危険ですのでやめましょう。Session StorageおよびLocal Storageはトークンが流出した場合の懸念がビジネス的に少ないのであれば選択してもいいかと思います。

Refresh TokenはAT/IDTの再発行を省略するために利用します。

https://datatracker.ietf.org/doc/html/rfc6749#section-1.5

メモリに保存する場合はブラウザのリロードでトークンが失われてしまうため、メモリに保存するくらいならば特別な要件がない限りRefresh Tokenを発行しない方が適切です。

AT/IDTと同様に流出リスクが低いケースでは、Local StorageやSession Storageの使用も選択肢となります。

Refresh Tokenは、ID Provider側で検証するものなので、使用時にローテーションを実装し、多重利用が検知された場合に失効させるなどの実装をID Provider側に盛り込むことで流出への一定の対応が可能です。

ネイティブアプリはSPAと構成が一緒なので割愛します。

## ID Providerによる認証セッション管理

OAuth2.0の中で、ユーザの情報を打ち込んでログインしてもらう工程、3rdパーティーアプリケーションとリソースサーバの連携に対して同意を行う工程が存在します。この工程はリソースオーナーとなるユーザ（利用者）が手入力により行う必要があります。

この手入力箇所で認証セッション(Session Cookie) をブラウザに発行して次回から処理をスキップするID Providerの実装があります。確認したところ、Auth0も同様の実装をしているようで、発行したトークンを削除した場合2回目以降は入力なしで再びIDT/AT/RTを発行してもらうことができました。

https://auth0.com/jp/intro-to-iam/what-is-single-sign-on-sso


## トークン流出について

流出リスクを考える場合にはトークン使用時にクライアントの正当性を確認するProof of Possessionが推奨されます

https://datatracker.ietf.org/doc/html/rfc9449

ただしパブリッククライアントでは最終的には鍵の管理ができないという課題が残ります。

## バックエンドシステムがクライアントとなる場合

ここまでSPAの場合の話をしました。バックエンドがID Providerやリソースサーバと通信を行う構成の場合、各種トークンはバックエンド側のサーバで安全に保持できます。

Publicクライアントの問題を解決するため、バックエンドが鍵を保持してID Providerとやり取りする仕組みも存在します(Backend for Frontend)。この方式の場合にはバックエンドをConfidential Clientとして扱います。

https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps#name-application-architecture-pa
ABC373Dを解いた


以前ABCで解けなかった以下の問題を解いていく

https://atcoder.jp/contests/abc373/tasks/abc373_d

# 実装コード

まず適当な値を最初のノードに入れ
そこから深さ優先探索をして、エッジの重みから
次のノードの値を計算する。

どうやら入力で与えられる
u→vの重みがwのエッジの他に
v→uで重みが-wのエッジを追加しても良いらしい

```python
import sys
from collections import deque,defaultdict
def rI(): return int(sys.stdin.readline().rstrip())
def rLI(): return list(map(int,sys.stdin.readline().rstrip().split()))
def rI1(): return (int(sys.stdin.readline().rstrip())-1)
def rLI1(): return list(map(lambda a:int(a)-1,sys.stdin.readline().rstrip().split()))
def rS(): return sys.stdin.readline().rstrip()
def rLS(): return list(sys.stdin.readline().rstrip().split())
def err(*args): print(*args, file=sys.stderr)

class Node:
    def __init__(self, val):
        self.val = val
        self.links = []

class Edge:
    def __init__(self, src, dest, wt):
        self.src = src
        self.dest = dest
        self.wt = wt

class Graph:
    def __init__(self, directed=False):
        self.nodes = {}
        self.directed = directed

    def __getitem__(self, k):
        return self.nodes[k]
    
    def __len__(self):
        return len(self.nodes)
    
    def add_node(self, val):
        node = Node(val)
        self.nodes[val] = node
    
    def add_edge(self, src, dest, wt):
        edge = Edge(src, dest, wt)
        if src not in self.nodes:
            self.add_node(src)
        if dest not in self.nodes:
            self.add_node(dest)
        self.nodes[src].links.append(edge)
        if not self.directed:
            reverse_edge = Edge(dest, src, -wt)
            self.nodes[dest].links.append(reverse_edge)
               
def main():
    N, M = rLI()
    G = Graph()

    for i in range(N):
        G.add_node(i+1)
    for _ in range(M):
        u, v, w = rLI()
        G.add_edge(u,v,w)    
    visited = set()
    result = defaultdict(lambda:None)
    # result[1] = {3:3,4:5,5:200401298}.get(len(G),0)

    for k in range(1,N+1):
        if k in visited: continue
        st = deque([G.nodes[k]])
        while st:
            node = st.pop()
            i = node.val
            visited.add(i)
            if result[i] is None:
                result[i] = 0
                # result[i] = (x:={4:6,5:278499365}.get(len(G),0))
                # err(i,x)
            for edge in node.links:
                d = G[edge.dest]
                if (j:=d.val) not in visited:
                    visited.add(j)
                    st.append(d)
                    if result[j] is None:
                        w = edge.wt + result[i]
                        result[j] = w
                        # err(j, w, edge.wt, result[i])
    
    ans = [result[i+1] for i in range(N)]
    print(*ans)
    
if __name__ == '__main__':
    main()
```


# まとめ

ABC373Dを解いた、実装には深さ優先探索を使用した

# 感想

グラフの拒絶反応を克服するために問題を解いた、
なかなか難しいが、鉄則本を読みながらコーディングして、
グラフについて少し理解を進められた。
Waitress+FlaskをAWS ECS Fargateで動かして詰まった話

<h1>経緯</h1>
Waitress+Flaskで作成したWebAPIをFargateで動かしたが、1,2件は8sで処理が終わるが10件の同時リクエスト時に1mを超えてしまった。<br>
根気強く試行錯誤し解決しましたが同様の情報がネット上に確認できなかったので、<br>
同じ状態で悩む人の為に記事にしたいと思います。

<h1>使用環境</h1>
AWS ECS Fargate<br>
Docker<br>
Waitress<br>
Flask<br>
その他WebAPIに必要なサービス(本件に関係ないため省略)

<h1>試したこと</h1>
Waitressのthreadsやconnection_limitの調整とFargateのvCPU、メモリの調整。

<h1>解決方法</h1>
FargateのvCPU、メモリの調整をするのではなくタスクの数を調整する。

<h1>問題の発生から解決までの過程</h1>
まずWaitressのthreadsを100、connection_limitを500に設定した。
2vCPU 6GBで1件の処理がうまくいったため同時リクエスト(10件)の時間を計測した。
その際に時間が１mを超えてしまったためvCPUとメモリを増やすことにした。

16vCPU 32GBで処理を行ったが時間があまり変わらなかった。
メトリクスで負荷を確認すると特段負荷はかかっていなかった。
そこで思い至ったのが2vCPUでも16vCPU使用されているスレッドが少ないのではないかということです。
実際1vCPUと2vCPUでは差が出ましたがvCPUを2より大きくしても処理時間に大きな変化はなく、むしろ時間が多くなっていました。

解決策としてまずどのvCPUとメモリの組み合わせが処理に最適化を調整し、
リクエスト数に応じてタスクを増やすといった結論に至りました。

以上になります。
<h1>所感</h1>
Javaの開発エンジニアのつもりなのですがいきなりサーバの調整を任されたのでやることになりました。<br>
vCPUを増やせば使えるスレッドも増えるだろうと勝手に思っていたのですがそうでもないんですかね。<br>
もしもっと良い解決方法などがあればコメントにてご教示いただけますと幸いです。<br>
インフラエンジニアの方からしたら常識的な内容だったのかなと勝手に思いつつ終わります。<br>
3.スクリプト作成


**3.スクリプト作成**

自動テストを行うためのスクリプトの作成や、スクリプトを作成するための環境作りをまとめます。


・目次
3.1.スクリプト環境
3.2.環境構築
　3.2.1.pyenvインストール
　3.2.2.Pythonインストール
　3.2.3.Appium-Python-Clientインストール

3.3.スクリプト作成
　3.3.1.直接コーディングする方法
　3.3.2.AppiumInspectorを使用する方法


<br>
<br>
<br>



3.1.スクリプト環境
---



<br>
<br>
<br>

3.2.環境構築
---

<br>




3.2.1.pyenvインストール
---

Python のバージョン管理が可能な仮想環境

<br>
以下コマンドでインストール

```ターミナル.
brew install pyenv
```

<br>
以下コマンドでバージョンを確認

```ターミナル.
pyenv -v 
```

以下コマンドでバージョンを更新
```ターミナル.
brew upgrade pyenv
```


# pyenv の初期化
```
echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.zprofile
```

```
echo 'eval "$(pyenv init --path)"' >> ~/.zprofile
```

```
echo 'eval "$(pyenv init -)"' >> ~/.zprofile
```

<br>
<br>
<br>

3.2.2.Pythonインストール
---

以下コマンドでxz ライブラリをインストール

```ターミナル.
brew install xz
```



以下コマンドでインストール可能なPythonのバージョンを確認

```ターミナル.
pyenv install --list
```

<br>
以下コマンドでPythonインストール

※バージョン数は上記で表示されたバージョンの最新を記載

```ターミナル.
pyenv install 3.13.3
```

<br>
以下コマンドで使用されるバージョンを指定

```ターミナル.
pyenv global 3.13.3
```

<br>
以下コマンドでバージョンを確認

```ターミナル.
pyenv versions
```

```ターミナル.
python3 --version
```

```ターミナル.
pip3 --version
```

→pyenv/versions/3.XX.X
×部分が一致していればOK


<br>
<br>
<br>

3.2.3.Appium-Python-Clientインストール
---

以下コマンドでインストール

```ターミナル.
pip3 install Appium-Python-Client
```
<br>
以下コマンドでバージョンを確認

```ターミナル.
pip3 show Appium-Python-Client
```

<br>
<br>

3.3.スクリプト作成
---
テストコードの作成方法をまとめます。
Appiumでは複数の言語を選択することができ、自身に合った言語でテストコードを記載することができます。

サポートされている言語は以下になります。


|言語 |フレームワーク|特徴|おすすめ度|
|--|--|--|--|
|NUnit|.NET(C#) |ユニットテスト向け　|★ |
|JavaScript|Webdriver.io |E2Eテスト向け　<br>Webアプリ向け　|★★★★★ |
|JavaScript|Oxygen HQ |Appiumに統合可能　|★★★ |
|Java|JUnit4 |ユニットからシステムテストまで可能|★★|
|Java|JUnit5 |JUnit4の進化版　|★★★ |
|Python |--|ユニットからシステムテストまで可能<br>簡潔に記載可能　|★★★★ |
|Ruby |--|簡潔に記載可能　|★★★★ |
|Pythonなど|Robot Framework |Appiumに統合可能　<br>テキスト形式で非技術者でも理解可能|★★★★★ |


3.3.1.直接コーディングする方法
---

3.3.2.AppiumInspectorを使用する方法
---

・AppiumInspectorを起動

・ウィンドウ上部の「記録を開始する」をクリック
・ウィンドウ上部の「レコーダー」タブをクリック
・ウィンドウ右部の「.NET」と記載されている部分をクリックし、任意の言語を選択

<br>

　座標で操作する場合
　・ウィンドウ左部の「座標でタップ/スワイプする」をクリック
　・ウィンドウ左部のスマホ画面をクリック
　・ウィンドウ上部の「レコーダー」タブをクリック
　・指定した言語でコードが記載されている

　ACCESSIBILITY_IDで操作する場合
　・ウィンドウ左部のスマホ画面をクリック
　・ウィンドウ上部の「ソース」タブをクリック
　・ウィンドウ右部の「選択された要素」内のタップボタンをクリック
　・ウィンドウ上部の「レコーダー」タブをクリック
　・指定した言語でコードが記載されている

<br>
・ウィンドウ上部の「レコーダー」タブ内、「定型コードの表示/非表示」をクリックで定型文が表示される

・生成されたコードをファイルに追記する

<br>
<br>
<br>

以下記事を参考いたしました。
https://qiita.com/beliefarrow/items/211ca23edbb5f2776771
https://qiita.com/k5n/items/6e81b5986361bd1e3cd0
https://qiita.com/kunichiko/items/5a6114bc4b8b91d266f7
https://qiita.com/ys-sgn/items/a512ac5d99db35bbde0d
https://qiita.com/Jun96427231/items/16acecb85de094ee9736
https://www.slideshare.net/MasayukiWakizaka/appium-20
https://qiita.com/k5n/items/899cf40a0021a6a92efd
https://qiita.com/5enxia/items/13cafabc8a82a21700bf


<br>
<br>
<br>

以上！
【selenium】pythonでChromeドライバーを使ってブラウザを操作　入門編

## はじめに
今回はずっとやりたいなと思っていたChromeドライバーを使用してseleniumでブラウザ操作をするということを行った。
その時の備忘録としてここにまとめておく。

## 共通インポート
``` sample.py
from selenium import webdriver
from selenium.webdriver.common.by import By
```


## クラス要素の取得　.find_element(By.CLASS_NAME, '')
```sample.py
driver.find_element(By.CLASS_NAME, "login-btn")
```


## ID要素の取得　.find_element(By.ID, '')
``` sample.py
driver.find_element(By.ID, "login-email")
```


## 要素の取得　.find_element(By.XPATH, '')
``` sample.py
driver.find_element(By.XPATH, 'XPATH値')
```



## 要素の取得　.find_element(By.TAG_NAME, '')
``` sample.py
driver.find_element(By.TAG_NAME, "option")
```


## 要素の取得　.find_element(By.NAME, '')
``` sample.py
driver.find_element(By.NAME, "email")
```


## クリック操作　.click()
``` sample.py
loginBtn = driver.find_element(By.CLASS_NAME, "login-btn")
loginBtn.click()
```


## まとめ
やはりpythonの技術に個人的には癖があるなぁと思った。が、pythonは意外と簡単に作れてしまうので、便利やなぁと感じた。
.envファイルに環境変数を設定する

### .envファイルとは

Goの設定ファイル。環境変数の設定や管理を行うことで
環境ごとに異なる環境変数を設定したりセキュリティを向上させることができる。通常はGitなどのバージョン管理システムに含めないファイルである

### .envファイルに環境変数を作る

「環境変数名=値」で設定できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3926100/d554a8af-830c-64c2-cb6e-64c0e5a57573.png)

### 環境変数の値をGoのソースで呼び出す

外部パッケージをLoadすることで呼び出すことができる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3926100/a641541f-2fc4-3f71-4063-d8cd0be29bd6.png)

<実行結果>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3926100/36bbe1df-54cd-77bb-ac91-ff0ba82d68bb.png)


### 外部パッケージをダウンロードする方法

ターミナルで「go mod tidy」コマンドを実行すると、importしようとしている外部パッケージをダウンロードできる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3926100/3a0e62c2-038c-2f62-0028-5329b2d91098.png)

### go.sumファイルについて
外部パッケージをダウンロードするとgo.sumファイルが作成される。
このファイルの役割は、依存関係の整合性を保ったりバージョン管理を行うこと。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3926100/435945b3-40f3-39d5-7a9f-b209a15a3da7.png)
[Next.js App Router] Server Components と SSR の概念理解・違いについて

# はじめに

今回は、業務で Next.js 14 (App Router)を用いた実装で、Server Componet の概念、SSR との違いなどについて理解が曖昧だったので簡潔に整理してみました

# 対象読者

- Server Compoent の挙動についてイマイチわかっていない
- Server Component と Client Component の違いについて知りたい
- Server Component と SSR の違いについて腑に落ちていない

# レンダリング環境について

- クライアント
  - ブラウザを指し、サーバーにアプリケーションコードのリクエストを送信する。その後、サーバーからのレスポンスを UI に変換する
- サーバー
  - データセンター内のコンピュータを指し、アプリケーションコードを保存し、クライアントからのリクエストを受信して適切なレスポンスを返す

# Server Compornents とは？

- JS コードをクライアントで実行しなくてもいいコンポーネントをマーキングするだけの機能
- サーバーだけで完結できるコンポーネントは、サーバーで効率よく処理を済ます
- いつから導入されたの？
  - 2023 年 5 月にリリースされた [Next.js 13.4](https://nextjs.org/blog/next-13-4) で使えるようになった新たな機能
- 使用する目的
  - UX の向上
  - サービスの安全性向上
- サーバーレンダリングの利点
  - データ取得
    - データ取得をサーバーに移行できるので、レンダリングに必要なデータを取得する時間を短縮し、クライアントのリクエスト数を減らすことでパフォーマンスの向上が見込める
  - セキュリティ
    - トークンや API キーなどの機密データとロジックをクライアントに公開せずサーバーに保持できる
  - キャッシング
    - サーバー側で取得したデータはキャッシュされ、後続のリクエストやユーザー間で再利用できる
    - キャッシュの設定についてもカスタマイズできる
  - パフォーマンス
    - クライアント側のJSコードの実行量を削減できるので速度アップが見込める
- どのようにレンダリングされるのか？
  - サーバー側で行われていること
    1. サーバーコンポーネントを特殊なデータ形式 (RSC Payload) に変換
       1. RSC Payload (React Server Component Payload) は、レンダリングされた React Server Components tree のコンパクトなバイナリ表現のこと
       2. クライアント上の React によって、ブラウザの DOM を更新するために使用される
    2. 上記を HTML としてレンダリングする

# SSR (Server Side Rendering) とは？

- 「どのようにページ全体を最初にレンダリングするか？」というレンダリング手法
- サーバー側でリクエストがある度にレンダリングをおこなう
- ページ全体の HTML を事前に生成 (プリレンダリング) し、それを高速でクライアント(ブラウザ)に返す
- 使用する目的
  - コンテンツの初回描画速度の向上
  - SEO の向上

# Server Component と SSR の違い

- 従来の SSR (Pages Router) では、サーバー側でプリレンダリングする際に実行される JS コードが、クライアント側でも再度ハイドレーション時に JS コードが実行されてしまっていた
- Server Component は、サーバー側でプリレンダリング時に JS コードを実行してクライアントにはレンダリングした HTML と RSC Payload の JSON データを返却するので、クライアントで JS コードのバンドル (ハイドレーション) が行われない
- なので、「SSR の中に Server Component が組み込まれて共存している」というのが現状での認識

# おわりに

今回は、Next13.4 からデフォルトになった Server Component について曖昧なところを少し深掘りして理解できたので、今後の実務や個人開発でのコンポーネント設計に活かせれたらと思います。

また、SSR と Server Components の定義の違いも曖昧だったので整理できて良かったです

# 参考文献

[Next.js 日本語ドキュメント - Server components](https://ja.next-community-docs.dev/docs/app/building-your-application/rendering/server-components)
CCIE　DEVNET　学習　目次

CCIE　DEVNET　学習　目次

Using IOS-Automation with Netmiko via OOP approach
Model driven programability advancement
Model driven telemetry using Yang suite
Application development using click framework
API development using Flask Framework
Performing networ tests using pyATS
Advancements of CICD pipelines using gitlab
Understanding & implementing Infra as code using hashicorp teraform
Implementing centralized credential management using Hashicorp Vault
Orchastrating Network infra using Cisco NSO
Docker & Kubernates
Monitoring application performance using AppDynamics & Thousandeyes
Implmenting Advancements RestAPI & Graph API
[備忘録]Zorin OS 仮想デスクトップの切り替え方法

# Zorin os 17.2の仮想デスクトップ切り替え方法

### 仮想デスクトップの切り替え方法で、迷ったので備忘録として記載します。
なぜかわからないけど下記のように上矢印と下矢印で仮想デスクトップ画面が切り替わりました。普通は左右じゃないのかな？

1. Ctrl + Alt + ↑
1. Ctrl + Alt + ↓
【Amazon】Fulfillment Inbound API新バージョン移行についての注意点【SPAPI】

# SPAPIとは
SPAPI(Selling Partner API)とはAmazonが提供するAPIで、Amazonマーケットプレイスでビジネスを行う販売者（Selling Partner）が、自身のビジネスプロセスを効率化し、販売活動をサポートするためのAPIです。
RESTfulアーキテクチャを採用しており、以下のように用途ごとに多岐にわたるエンドポイントが提供されています。

・商品管理（Product APIs）
・注文管理（Orders API）
・FBA（Fulfillment By Amazon）に関する機能
・レポート（Reports API）
・在庫・納品（Inventory APIs）など

# Fulfillment Inbound APIとは
SPAPIで提供される、FBA納品作業ににかかる、出荷作成、管理、送信するためのワークフローを構築できます。

# 新バージョンへの移行
## 概要
Fulfillment Inbound APIは2024年3月にv2024-03-20をリリースしており、従来使用されていたv0の一部の機能が2024年12月20日を以て廃止になるそうです。
※[v0公式ドキュメント](https://developer-docs.amazon.com/sp-api/docs/fulfillment-inbound-api-v0-reference)で確認できますが、**廃止にならない**ものが赤文字でwarningと表示されているのでぱっと見間違えそうですね。。

今回、v0で実装している部分をv2024-03-20に移行するわけですが、v0のエンドポイントが16個であったのに対して、v2024-03-20のエンドポイントはなんと45個(多すぎだろ)。

一応[移行用のドキュメント](https://developer-docs.amazon.com/sp-api/docs/migrating-fulfillment-inbound-workflows)もあるようで、新旧で対応するエンドポイントを見ることができます(おそらく全てではなく主要なものだけと思われます)。
以下の画像を見る限りv2024-03-20ではかなり処理が細分化されているようですね。
![createInboundShipment.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083940/de9f9fff-3b5f-78a2-6549-c6854d2b7c6e.jpeg)

## 実際にやってみる
詳しい作業内容は社内ノウハウも含みますので、今回はざっくり作業内容を記載しその中での注意点を記載させていただきます。

今回自分が行った作業としては発送後の荷物に対する追跡番号を更新するというフローについての移行です。

追跡番号更新エンドポイントの新旧表は以下の通り。
![updateTransportDetail.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083940/0e605292-f224-58da-96ff-ba3ede1e8571.jpeg)

おや？createInboundShipmentPlanと比べると新旧が1 : 1となっておりかなり簡単そうですね！
ところがどっこい、そんな甘いものではありませんでした。

## 注意点
### その1
v0で使用していたPutTransportDetailsではshipmentIdを指定してリクエストしていたのですが、updateShipmentTrackingDetailsではinboundPlanId, shipmentId, boxIdがリクエストに必要となります。
ここで重大発表です。v0で使用していたshipmentIdとv2024-03-20のshipmentIdは別物です(青天の霹靂)。
v0で使用していたshipmentIdはv2024-03-20のshipmentConfirmationIdが対応するらしいです。

「ほなv2024-03-20のshipmentIdを取得する必要があるなぁ」と思いv0のgetShipmentsのようにshipments一覧を取得できる類似のエンドポイントがv2024-03-20にないか確認したところ無いらしい(絶望)。

### その2
その1で述べたv0のgetShipmentsに対応するエンドポイントが用意されていないという点にもつながるのですが、updateShipmentTrackingDetailsにはboxIdが必要です。
そしてboxIdを取得するにはgetShipmentなどのレスポンスが必要であり、そのgetShipmentを呼ぶためにはshipmentIdとinboundPlanIdが必要となります。

という風に必要なリクエストを行うためのIDを揃えるために上位エンティティのID情報を取得する必要があり、新旧表のように単純に旧のエンドポイントを新に変更すればいいというものではなくそれに付随する複数のエンドポイントの実装が必要になります。

### その3
その2で述べた、上位エンティティのID情報を取得するにあたって、すべてのエンティティの原点となる納品プランのリストを取得するlistInboundPlansでの注意点です。

プランのstatusは以下の3種類があり、公式ドキュメントではstatusはoptionalなパラメータとなっておりデフォルト値も設定されていません。
![planStatus.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083940/2b915f97-4003-4e23-2ede-b0426662ecd3.jpeg)

![status.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083940/a79be6d6-91ab-284f-5803-ac94f13a0a62.jpeg)

「ほな指定せんかったら全ステータスが取得できるんかぁ」と思ったそこのあなた、違います！
何も指定しなかった場合はACTIVEのプランリストが取得されます。
※ACTIVEを指定しても、しなくても同じ結果が得られます。

# さいごに
今回はv2024-03-20移行時に発見した注意点を記載させていただきましたが、今後修正される可能性もありますので、あくまで現時点での情報となります！
記載している情報に間違い等あればご指摘いただければ幸いです。
今後実装を進める中で新たな注意点が見つかればまた発信していこうと思います。
【TypeScript】オブジェクトのキーをスネークケースに変換した型を生成する方法

## `snakecase-keys` をインストール
以下のコマンドを実行して `snakecase-keys` をインストールします。

```terminal
npm install snakecase-keys
```

https://github.com/bendrucker/snakecase-keys#readme

## 型を生成する

以下のように記述することで `snakecase-keys` を使用してキーをスネークケースに変換した場合のオブジェクトの型を生成できます。

```typescript
type test1 = snakecaseKeys.SnakeCaseKeys<
  {
    sampleValue: string
    data: {
      sampleValue: string
      data: {
        sampleValue: string
      }
    }
  },
  false
>

// type test1 = {
//    sample_value: string;
//    data: {
//        sampleValue: string;
//        data: {
//            sampleValue: string;
//        };
//    };
// }

type test2 = snakecaseKeys.SnakeCaseKeys<
  {
    sampleValue: string
    data: {
      sampleValue: string
      data: {
        sampleValue: string
      }
    }
  },
  true
>

// type test2 = {
//     sample_value: string;
//     data: {
//         sample_value: string;
//         data: {
//             sample_value: string;
//         };
//     };
// }

```
【超基礎】TypeScript関数の引数まとめ

## 前提
この記事は、初学者の私が、サバイバルTypeScriptで学んだこと+調べたことをまとめたものになります。

従って、経験則に基づいた発言ではないため、一部慣習とは違っていたり、認知にずれがあったりする可能性がありますので、ぜひコメントで指摘していただけると幸いです。

https://typescriptbook.jp/


## TypeScriptにおける引数
- 渡す引数と期待する引数の**数と型の一致**が必須。(JSだと無視)
- 型を引数として渡すこともできる(**ジェネリクス**)
- C言語の様な**ポインタ渡しは存在せず、基本は値渡しのみ**。呼び出し先の関数で書き換えても、呼び出し元では変化しない
::: note
オブジェクトのみ新しい変数に代入すると**値を共有する**ようになるため、呼び出し先で書き換えると、共有された呼び出し元のオブジェクトも更新される。
:::

https://qiita.com/araarara/items/a6cba596ec1bd4850ddc

```typescript:typesciprt
function func(a: number,b: string): void{
    console.log(`num:${a},str:${b}`);
}

func(1,"hello"); //=> num:1,str:hello
```


## オプション引数
- 呼び出し先関数の引数の後ろに`?`を付けたもの
- 関数呼び出し時に引数を省略できる
- **undefindとのユニオン型**になり、引数が省略された場合はundefinedとなる
➡ そのままでは各型のメソッドが使えないので、関数の初めに型ごとの処理をする必要がある。
- **通常の引数と併用できるが必ず最後に置く必要がある**
:::note warn
多くのケースでは[デフォルト引数](#デフォルト引数)を使った方がいい。・
:::
```typescript:オプション引数
function funcOpt(a: number,b?: string){ //引数の後ろに'?'を付ける。
    if(typeof b === "undefined"){ //型について初璃
        b = "undef";
    }
    console.log(`num:${a},str:${b}`);
}

funcOpt(1,"hello") //=> num:1,str:hello
funcOpt(5) //=> num:5,str:undef　省略ok
```

## デフォルト引数
- **オプション引数よりシンプルに書ける**
- 可読性、保守性も高い
- 特に順番に関する制限はない
- 引数の型が`undefined`の時に動作する
:::note warn
引数の型が`null`だとデフォルト引数は適用されない
:::
```typescript:デフォルト引数
function funcOpt(a: number,b: string ="undef"){ //よりシンプルかつ直感的な実装
    console.log(`num:${a},str:${b}`);
}

funcOpt(1,"hello") //=> num:1,str:hello
funcOpt(5) //=> num:5,str:undef　省略ok
```
## 残余引数（可変長引数）
- 引数の前に`...`を付けることで、引数の数が可変になる
- 渡された引数は**配列**として扱われる➡省略すると空の配列が生成される
- **通常の引数と併用できるが必ず最後に置く必要がある**
- 関数呼び出し側では配列を渡すとエラーになるため、スプレッド構文を使う
::: note
スプレッド構文：配列の先頭に`...`を付けたもの、配列を引数に分解できる
:::

```typescript:残余引数
function funcOpt(a: number,...b: number[]){ //number[]型であることに注意
    console.log(`num_1:${a},num_2:${b}`);
}
funcOpt(1) //=> num_1:1,num_2:
funcOpt(1,2) //=> num_1:1,num_2:2
funcOpt(1,2,3,4,5) //=> num_1:1,num_2:2,3,4,5
```
## まとめ
以上になります。ずっと「引数に謎の修飾がされているな」というだけのやんわりとした理解だった部分の解像度が上がりました。

当方初学者なため、認知のずれや、モダンな開発現場ではもう使わない表現などがありましたらコメントで指摘していただけると幸いです。😸
Dockerローカルで触ってみた

## テーマ
ローカルでDockerを触ってみる！

## 前提
Dockerがインストールされていること

## 登場人物
/work/Dockerfile
/work/src/index.html

### Dockerfile（/work/Dockerfile）
```jsx
FROM nginx:latest
COPY ./src /usr/share/nginx/html
```
COPY・・・　./srcディレクトリを、コンテナ内の/usr/share/nginx/htmlにコピーする。

### index.html(/work/src/index.html)
```jsx
HelloWorld!!
```

## 操作
上記2つのファイルを作成したら、コンテナ(Docker)の作成・削除を行う。
下記コマンドはDockerfileが存在するディレクトリ（本投稿では「/work」）で行うこと

### 起動
1. イメージ化
    `docker build . -t {イメージ名}`
    イメージ名はお好きな文字列。
    .(カレントディレクトリ)は、Dockerfileが存在するパスを指定している。

2. コンテナ起動
    `docker run —rm -p 8080:80 {イメージ名}`    
    --rm・・・コンテナ停止時、コンテナを自動的に削除する
    -p・・・ポートの指定
    イメージ名は１で作成したイメージ名。
    
↓

ブラウザで`http://localhost:8080`につなぐと、HelloWorld!!が表示される。

### 停止

1. コンテナIDを確認する
    `docker ps`
    
2. コンテナを停止する
    `docker stop {コンテナID}`
    

### （おまけ）確認系のコマンド
作成したイメージを確認する `docker images`
起動したコンテナを確認する `docker ps`
デバッグに重宝するIceCreamライブラリ

# はじめに
とあるコミュニティに所属しており，その中でふと話題になってからすっかりハマってしまったライブラリ`IceCream`について紹介したいと思います．


# IceCreamって？

https://github.com/gruns/icecream

デバッグに非常に便利なメソッド`ic`を提供するライブラリです．
`print`文でも実装できるがめんどくさい．そんな時に大きな助けになってくれます．


# IceCreamの使いかた
使い方は非常に簡単で，`pip install icecream`を実行し，`from icecream import ic`でインポートするだけです．
サンプルコードを確認してみます．

```python: icecream_sample.py 
from icecream import ic 


ic.enable()
ic()

def foo():
    ic()
    return 42

def bar():
    ic()
    return {'A': 1, 'B': [2, 3]}

hoge = ic(foo())
ic(hoge)

hoge = ic(bar())
ic(hoge)
```

実行結果は以下の通り．（ベースイメージがUbuntuのDockerコンテナ内での実行結果です）

![スクリーンショット 2024-11-23 23.07.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693436/0c112b5f-97c8-d654-186e-18bddc1ff510.png)

`ic`メソッドには大きく2つの使い方があります．1つ目は引数与えずに実行する方法，もう一つが引数を与える方法です．

引数を与えない場合，実行位置（行数・関数名）と時刻が標準出力に投げられます．すなわち，`ic()`と記述するだけでその場所の実行が適切におこなわれているかがわかります．

```python
ic()    # 行数・関数名・時刻が標準出力に
```

次に，引数を与える場合です．
関数や変数を与えることができ，関数を与える場合にはその関数の返り値を受け取ることができます．`print`とf-stringを用いれば同様の実装が可能ですが，面倒です．

```python 
ic(hoge)            # hogeの値を出力
hoge = ic(fuga())   # fuga()の実行結果を出力し，返り値をhogeに格納

# print(f'{hoge = }')    # print文で書くとこんな感じ
```

ここまでであれば，手癖で慣れている人にとっては大きな差にならないかもしれませんが，要素数が大きな返り値・変数の時に威力を発揮します．

```python: icecream_sample_2.py
from icecream import ic 


ic.enable()
ic()


def foo_large():
    ic()
    return {idx: [idx_i for idx_i in range(idx)] for idx in range(10)}


hoge = ic(foo_large())
ic(hoge)
```

実行結果は以下の通りです．
見ていただいてわかるように，ある程度の大きさになると見やすい形に整形してくれます．`pprint`を用いるなどの方法もありますが，それをするなら個人的には`ic`だけで良いのではないかと感じています．

![スクリーンショット 2024-11-23 23.21.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693436/3b543afd-7700-55a6-8ad3-1e828775c072.png)


# 補足
私の環境（ベースイメージがUbuntuのDockerコンテナ）だけかもしれませんが，`ic.enable()`を`ic`メソッド前に付けなければうまく動作しませんでした．

逆のメソッドとして`ic.disinable()`というものもあり，デバッグモードの一括管理も可能です．


# 最後に
IceCreamライブラリを利用し始めてからというもの，どういう訳かIceCreamを使ってみたという記事がよくレコメンドされます．（推薦アルゴリズムの影響か，はたまた流行り始めているのか）
個人的には気に入りました．
AWS 高可用性の基礎：小さな一歩から始める設計のヒント

### **AWS の高可用性 (High Availability, HA) の紹介**

AWS は、信頼性の高いインフラと多様なサービスを活用し、高可用性を実現できるプラットフォームを提供しています。ここでは、AWS の高可用性を支える仕組みと関連サービスを紹介します。

---

### **高可用性の基本概念**
高可用性とは、システムやアプリケーションが障害時でも稼働し続ける能力を指します。AWS は以下の要素を活用して高可用性を実現します。

1. **グローバルなインフラストラクチャ**  
   - **リージョン (Region)**: 地理的に分散されたデータセンターのグループ。
   - **アベイラビリティゾーン (AZ)**: 各リージョン内に独立したデータセンター群が複数存在。
   - **エッジロケーション**: コンテンツ配信とレイテンシ削減のための分散ネットワーク。

2. **冗長性とフォールトトレランス**  
   - データやアプリケーションを複数の AZ やリージョンに配置し、障害時にもシステムが継続可能。

---

### **AWS の高可用性を支える主要サービス**

#### **1. コンピューティング**
- **Amazon EC2 Auto Scaling**
  - 負荷に応じてインスタンスを自動でスケールイン/アウト。
  - インスタンス障害時に自動で新しいインスタンスを起動。
  - **マルチ AZ 配置**により冗長性を確保。

- **Elastic Load Balancing (ELB)**
  - トラフィックを複数の EC2 インスタンスに分散。
  - 健康チェックにより障害があるインスタンスを自動的に除外。
  - **クロス AZ ロードバランシング**で高可用性を強化。

#### **2. データストレージ**
- **Amazon S3**
  - 高耐久性 (99.999999999% の耐久性) を持つオブジェクトストレージ。
  - データは複数の AZ に自動的に複製。
  - バージョニングやレプリケーションでさらに冗長性を強化。

- **Amazon RDS**
  - マルチ AZ 配置オプションにより、自動的にバックアップインスタンスにフェイルオーバー。
  - 自動バックアップとポイントインタイムリカバリでデータ損失を防止。

- **Amazon DynamoDB**
  - マルチリージョンレプリケーションで、データベースの高可用性を実現。
  - サーバーレスな構造でダウンタイムを最小化。

#### **3. ネットワーク**
- **Amazon Route 53**
  - 可用性の高い DNS サービス。
  - 地域間ルーティングやフェイルオーバールーティングをサポート。
  - ヘルスチェックにより障害のあるリソースを動的に回避。

- **AWS Global Accelerator**
  - 複数リージョン間でアプリケーションの高可用性を提供。
  - トラフィックを健康なエンドポイントに自動的にルーティング。

#### **4. バックアップと復元**
- **AWS Backup**
  - 複数の AWS サービスにわたる統合バックアップソリューション。
  - 自動スケジュールでバックアップを取得。
  - バックアップの復元によりシステム停止リスクを軽減。

- **Amazon EBS**
  - スナップショットを使用して永続的なバックアップを取得。
  - EBS ボリュームは AZ 内で冗長化され、高可用性を確保。

#### **5. サーバーレス**
- **AWS Lambda**
  - イベント駆動型でスケーラブルなアーキテクチャ。
  - 障害が発生しても AWS がバックエンドを管理するため、ダウンタイムが発生しにくい。

- **Amazon Aurora (Serverless)**
  - 自動スケーリング機能を備えた高性能なデータベース。
  - マルチ AZ 配置でフォールトトレランスを強化。

---

### **高可用性アーキテクチャの設計例**
#### **マルチ AZ 設計**
- EC2、RDS、ELB をマルチ AZ に配置し、障害時もサービスが継続可能。
  
#### **マルチリージョン設計**
- DynamoDB や S3 を利用して、データを複数リージョンにレプリケーション。
- Route 53 を活用して、ユーザーを最も近いリージョンへルーティング。

#### **サーバーレス設計**
- Lambda、API Gateway、DynamoDB を利用したサーバーレスアーキテクチャでダウンタイムを最小化。

---

### **高可用性のためのベストプラクティス**
1. **マルチ AZ を有効化する**  
   - 主要なサービスでマルチ AZ 配置を有効にする。

2. **自動化を活用する**  
   - Auto Scaling やヘルスチェックで障害を検出し、復旧を自動化。

3. **バックアップを定期的に取得**  
   - AWS Backup や EBS スナップショットでデータ保護を強化。

4. **監視とアラートの設定**  
   - Amazon CloudWatch を使用してシステムの状態を常時監視。

5. **リージョン間レプリケーションを設計する**  
   - 重要なデータやアプリケーションを複数のリージョンで冗長化。

---

AWS の高可用性機能を活用すれば、システムの信頼性と耐障害性を大幅に向上させることができます。設計時に冗長性や自動化の要素を組み込むことが成功の鍵です！