OmniAICreator/Qiita-1.07M huggingface dataset:
if __name__ == "__main__":

#### モジュールとスクリプト
- スクリプト: プログラムとして直接実行されるPythonファイル。

- モジュール: 他のPythonファイルからインポートされるライブラリやユーティリティを含むファイル。

#### `__name__`変数
- Pythonファイルが実行されると、特別な変数 `__name__` が設定される。

- 直接スクリプトとして実行された場合、`__name__` の値は `"__main__"` になる。

- インポートされたモジュールとして実行された場合、`__name__` の値はそのモジュール名になる。

#### `if __name__ == "__main__":` の使い方
この条件文は、スクリプトが直接実行された場合にのみ特定のコードを実行するためのものです。これにより、モジュールとしてインポートされた場合に実行されないようにすることができる。
#### **例**
例えば、以下のようなPythonファイル `example.py` があるとする：
~~~
def main():
    print("This is the main function.")

if __name__ == "__main__":
    main()
~~~

#### - 直接実行:
~~~
python example.py
~~~
出力：
~~~
This is the main function.
~~~
#### - インポート:
~~~
import example
~~~
この場合、`main` 関数は実行されません。`if __name__ == "__main__":` のブロック内のコードはスキップされる。
（業務デモ・体験）ITパスポート研修～エンジニアが言う「覚えなくてよい」の意味と程度の例～

「情報系に進路希望されている方向け：IT講師の「覚えなくていい」の本当の意味を知ろう」というタイトルだったが、学生色が強かったのでリスキリングリスキリング者も想定に含んでいる。
なお、実際に研修で使った資料だが、公開できる状態に変更している
というのも、本資料は別途スライドを併用しており、資料の補足教材としての位置づけであるため、本資料だけで研修を実施していない事に留意してほしい。
あくまで「覚えなくてよい」とはどういう状態であるか、に注目している。

---

:::note warn
## キーワード
- 覚える
  - レベル１：その場で話ができればOK。すぐ忘れよう（＝理解したレベルに落とそう）
  - レベル２：忘れてもいいようにするが、できればレベル3にしたい。後で見直ししやすくしよう
  - レベル３：忘れないようにしよう
- 理解する
  - 後で見て思い出せるレベルを目指す
  - 覚える（に越したことはない）必要はないが、忘れたとしても何を言っているかは分かっている状態
- 知る
  - 「よくわからないけど、なにか言ってたな」程度を目指す
  - 【知らない】からの卒業が目的
:::

## 覚えておくと良いもの
:::note
## 努力目標
なるべく覚えない（＝脳みそを疲れさせない）、覚える量を減らす努力をする
:::

脳のキャパシティ（＝学習疲れ）をなるべく回避するための道標として使って欲しい

## 理解しておきたいもの
:::note warn
めちゃくちゃ多いので、読んですぐ理解できなければ聞いてしまおう
今日学んで明日までに忘れることが目標
:::

### 「はじめに」の目次（学習予定表）
- なぜこの作り（構成）になっているのか
- ITパスポート試験勉強をすること（受かることではない）が自身の今後にとってどのように活用できそうかイメージする

### 情報に関する理論
- アナログとデジタル
  - デジタルが0/1で表現される理由と、デジタルでアナログを表現する方法
- ビットをバイトに変換する理由

### コンピュータの構成とCPU
データの流れを追いかけよう

- 入力装置：ハードウェア→ソフトウェア
- 出力装置：ソフトウェア→ハードウェア
  - 入出力の制御にはハードウェア起因の問題とソフトウェア起因の問題があるため「動かない」トラブルへの対応は慎重に切り分け作業を行うこと
- 制御演算装置：処理するもの。1秒間にどれだけ処理できるか（クロック周波数が多いか）が重要
  - CPU: 汎用
  - GPU: 画像処理（AI・ブロックチェーン）
- 主記憶装置：覚えておくもの。寝たら忘れて良い（揮発性）
- 補助記憶装置

読み書きの権限としてそれぞれにRAM/ROMがあり、目的に応じて使い分ける
なお、主記憶装置にも補助記憶装置にもRAM/ROMがあるため、混同しないように（DVD-RAM/ROM。電気屋を見てみよう)

### AI：日進月歩の技術のため試験の出題傾向が読めないが、全部重要
- 機械学習
  - 教師あり：予測：分類
  - 教師なし：クラスタリング
  - 強化学習：最適化
- ディープラーニングとニューラルネットワーク
- AIの問題点
  - 過学習
  - ハルシネーション
  - 不適切な表現など
  - ディープフェイク

## 知っておくぐらいで良いもの
テキストに書いているが、ここに書いてないもの全部
ただし、試験前に詰め込んだほうがいいものを以下に置く

### 試験対策で頑張って覚えよう編
:::note warn
特に言及しない限り、覚えるレベル１で良い
:::

- 情報量の単位
  - 10^3 = 1000ずつとしているが、厳密には2^10=1024であること
- 文字コードの種類と、日本語は2バイトで1文字
  - テキストにマークしておこう！ UTF8
- コンピュータの構成とCPU
  - DRAM/SRAM
  - 補助記憶装置
    - ディスク装置
      - RAID(0/1/5)
    - 光ディスク
    - フラッシュメモリ
- 確率と統計
  - 順列と組み合わせ
  - 平均
  - 中央値・最頻値・範囲・分散・標準偏差
  - 正規分布
    - データの取り方が良くないケースだったり、データ自体が不正なケースなどもある
- 基数変換: 2 <-> 10 <-> 16進数
CSVファイルのファイル名と行番号の文字列を取得する

```python:test.py
import csv

EXTRACT_LINENO_BEFORE = 1
EXTRACT_LINENO_AFTER = 1

def get_code_line(src_lines, lineno):
    if 0 < lineno <= len(src_lines):
        start_line = max(0, lineno - (EXTRACT_LINENO_BEFORE+1))
        end_line = min(len(src_lines), lineno + EXTRACT_LINENO_AFTER)
        result_lines = src_lines[start_line:end_line]
        code_lines = ''
        for i in range(len(result_lines)):
            code_lines += str((lineno - EXTRACT_LINENO_BEFORE)+i) + " : " + result_lines[i]
        return code_lines
    else:
        return "-"

def qac_result_extract_sourcecode(csv_reader_filepath, csv_writer_filepath):
    try:
        with open(csv_writer_filepath, 'w', newline='') as writerfile:
            writer = csv.writer(writerfile)

            try:
                #with open(csv_reader_filepath, 'r', encoding='utf-8') as csvfile:
                with open(csv_reader_filepath, 'r') as readerfile:
                    reader = csv.reader(readerfile)
                    next(reader)  # 1行目スキップ

                    prev_src_filepath = ""
                    prev_src_lineno = 0
                    code_lines = ""
                    src_lines = []
                    for row in reader:
                        if len(row) >= 2:
                            src_filepath = row[0]
                            src_lineno = int(row[1])

                            if prev_src_filepath == src_filepath and prev_src_lineno == src_lineno:
                                #print(code_lines)
                                print("**")

                            elif prev_src_filepath == src_filepath:
                                code_lines = get_code_line(src_lines, src_lineno)

                            elif prev_src_filepath != src_filepath:
                                with open(src_filepath, 'r', encoding='utf-8') as file:
                                    src_lines = file.readlines()
                                    code_lines = get_code_line(src_lines, src_lineno)
                            
                            prev_src_filepath = src_filepath
                            prev_src_lineno = src_lineno

                            row.append(code_lines)
                            writer.writerow(row)
                            
                            print(f"ファイルパス: {src_filepath}, 行番号: {src_lineno}, 結果：{code_lines}")
                        else:
                            print("不完全なデータ行が検出されました。")
            except FileNotFoundError:
                print("CSVファイルが見つかりません。")
            except Exception as e:
                print(f"エラーが発生しました: {e}")

    except Exception as e:
        print(f"エラーが発生しました: {e}")

if __name__ == "__main__":
    csv_reader_filepath = "C:\\Users\\EijiA\\OneDrive\\デスクトップ\\tools\\test.csv"
    csv_writer_filepath = "C:\\Users\\EijiA\\OneDrive\\デスクトップ\\tools\\test2.csv"
    qac_result_extract_sourcecode(csv_reader_filepath, csv_writer_filepath)

```
LeetCodeを1日1題解いてみる (day8)

8日目に取り組んだ問題はこちら！

# 58. Length of Last Word

https://leetcode.com/problems/length-of-last-word/description/

## 問題文
Given a string s consisting of words and spaces, return the length of the last word in the string.

A word is a maximal substring consisting of non-space characters only.


## 僕の回答

```py
class Solution:
    def lengthOfLastWord(self, s: str) -> int:
        s_arr = s.split()
        last_word = list(s_arr[len(s_arr)-1])
        return len(last_word)
```


## より効率の良い回答例
```py
class Solution:
    def lengthOfLastWord(self, s: str) -> int:
        s_arr = s.split()
        last_word = s_arr[-1]
        return len(last_word) if s_arr else 0
```

### コメント
配列の要素にアクセスする際、「後ろからi番目」 には、`[-i]`を使用してアクセスできる。

### 次回はこちら!
https://qiita.com/h_y_s_d/items/3d0a486512f953184853
OIDC認証における「Federated logout 」の目的と特徴

「Federated Logout」は、OIDC（OpenID Connect）認証において複数の認証システムやプロバイダが連携している環境で、統一的にログアウト処理を行うための仕組みです。このログアウト方式は、シングルサインオン（SSO）環境において特に重要です。

### 目的

1. **統一的なセッション終了**: Federated Logoutの主な目的は、ユーザーがIdP（アイデンティティプロバイダ）でログアウトした際に、他の連携しているクライアントや認証システムのセッションも同時に終了することです。これにより、セキュリティとユーザー体験が向上します。
2. **SSO環境の一貫性**: SSO環境で複数のアプリケーションやサービスにログインしているユーザーが、あるサービスでログアウトすると、すべてのサービスで一貫してログアウトが実施されることで、セッション管理が一元化されます。
3. **セキュリティ向上**: 連携するすべてのサービスでセッションを終了することで、意図しないセッションの残存や不正アクセスのリスクを低減します。

### 特徴

1. **連携したログアウト処理**: Federated Logoutは、IdPがログアウトリクエストを受けると、そのIdPに連携している他の認証システムやサービスに対してもログアウト通知を送信します。これにより、ユーザーが1つのシステムでログアウトした際に、他のサービスも同時にセッションを終了します。
2. **複数方式の組み合わせ**:
   - **Front-Channel Logout**: ブラウザを介したログアウト通知を組み合わせることが多いです。
   - **Back-Channel Logout**: よりセキュアなサーバー間通信を使った通知が行われることもあります。
3. **ログアウトリクエストの伝播**: ログアウトは、IdPが受けたログアウトリクエストを起点として連携するクライアントやシステムに伝播します。これにより、連携した全てのクライアントがセッション終了を実施します。
4. **ユーザー体験の向上**: ユーザーは一度のログアウト操作で、全ての関連するサービスからログアウトできるため、ログアウト操作を繰り返す必要がなく利便性が高いです。

### 実装の流れ

1. **ログアウトリクエスト**: ユーザーがOIDCプロバイダでログアウト操作を行います。
2. **通知の送信**: IdPは、連携しているクライアントや他のプロバイダに対してログアウトリクエストを送信します。これは、iframeを介したFront-Channel方式や、サーバー間通信を使用するBack-Channel方式で行われます。
3. **セッションの無効化**: 各クライアントやシステムは、通知を受けて該当するユーザーのセッションを無効化します。
4. **リダイレクト**: ログアウト完了後、指定されたURLにユーザーをリダイレクトすることが一般的です。

### 利点と課題

**利点**:

- **セキュリティの強化**: 意図しないセッションの残存を防ぎ、セッション管理を一元化できる。
- **SSOの一貫性**: すべての連携サービスでログアウト状態が保持される。
- **利便性向上**: ユーザーは一度の操作で、すべての連携サービスからログアウトできる。

**課題**:

- **実装の複雑さ**: 各クライアントやシステムがFederated Logoutに対応している必要があり、実装が複雑になることがある。
- **通信の信頼性**: Front-Channel方式ではブラウザを介した通知の信頼性やネットワーク状態に依存する。
- **セキュリティ対応**: ログアウト処理に関してCSRFなどの攻撃に対する対策を考慮する必要がある。

Federated Logoutは、特にSSO環境において一貫性とセキュリティを高め、ユーザー体験を向上させるための重要な仕組みです。
PowerAppsで作成したCSVファイルをローカルにダウンロードする方法

今回の記事は先日投降した[「PowerAppsのギャラリーをCSVでエクスポートする方法【PowerAutomate】」](https://qiita.com/hedaozhenye/items/f86136bd99631ed2f405)の続きの内容となります。
CSVファイルを作成している前提での話となりますのでもし理解できないところがあれば併せて読んでいただければと思います。

# SharePointに作成する場合との相違点
まず最初に、SharePointにファイルを作成するだけの状態をローカルフォルダにダウンロードするように変更するために必要な変更箇所を先に明示します。
<dl>
  <dt>PowerAutomate</dt>
  <dd>作成したファイルのリンクではなくダウンロードリンクを取得するように変更</dd>
  <dt>PowerApps</dt>
  <dd>ダウンロードするボタンにダウンロードリンクを返すような関数の追加</dd>
</dl>

# PowerAutomateの変更
まずはSharePointに作成したファイルのダウンロードリンクを作成します。こちらはSharPoint上に存在するファイルのパスからダウンロードURLを作成することができます。
ファイルのパスを使用したダウンロードURLは次のような形になります。
```
[サイトURL]/_layouts/download.aspx?SourceUrl=[ファイルのパス]
```
PowerAutomateで作成する場合には、ファイルの作成前に「変数の初期化」のアクションを使って先に定義することで日付と日時を利用したオリジナルなファイル名を使用しつつ、ダウンロードURLの作成が可能です。

作成したダウンロードURLは「PowerAppsまたはフローに応答する」のアクションを使用することで、PowerAppsにURLを返却することができます。
PowerAppsから入力を受け取ったときと操作が似ていますが、こちらではテキストで出力の追加をしてタイトル（PowerAppsでURLを受け取るときに指定する値）を設定し値の部分には先程作成したダウンロードURLを設定してください。

:::note info
このページでの説明はタイトルにExportURLとして説明していきます
:::

```mermaid
graph TD;
実装イメージ
    変数の初期化:ファイル名の指定-->SharePointにファイルの作成;
    SharePointにファイルの作成-->変数の初期化:Concat関数を使用してURLの作成;
    変数の初期化:Concat関数を使用してURLの作成-->PowerAppsまたはフローに応答する:タイトルとURLの設定;
```

# PowerAppsの変更
こちらではAutomateで作成したURLを受け取り、Download関数に設定することでファイルのダウンロードを実装することができます。
まずは受け取ったURLを変数として保持できるようにフローの実行の部分の関数を修正します。フローの実行はこちらのような関数で実行していました。
```
Flow.Run(Flow_json)
※ここではフローに渡す値をFlow_Jsonとしています
```
このフローを実行して返却された値を変数に格納したいため次のように修正します。
```
Set(ExportURL,Flow.Run(Flow_json))
```

最後にフローから受け取ったURLをダウンロード関数に渡すような関数を記載します。

```
Download(ExportURL.exporturl)
```
# 最後に
このように修正することでアプリの再生でダウンロードボタンを押してファイルをローカル環境に保存することができるようになります。その後の処理として、ファイルのダウンロード後はSharePointからデータを削除しても手元の端末には残るので、作成したファイルを削除するようなフローを追加したりしてもいいと思います。この辺りの追加実装も必要に応じてぜひやってみてください。
ここまで読んでいただきありがとうございました。
Python開発: ブラウザ操作処理をPlaywrightで効率的に開発しよう！

# Playwrightとは

Playwrightは**マイクロソフト**が提供するオープンソースの**エンドツーエンドテスト自動化フレームワーク**です。ブラウザの操作をプログラムで記述することで、テストやスクレイピングなどを効率的に実現できます。
今回はエンドツーエンドテスト自動化フレームワークの中でPlaywrightを選ぶ利点や導入方法、便利なコード自動生成機能について解説します。

:::note
対応言語はTypeScript、JavaScript、Python、Javaといった複数の言語で使用でき、Chromium、Firefox、WebKitといった複数のブラウザエンジンに対応しています。
:::

### Playwrightの利点

- **自動待機機能**
Playwrightは要素の読み込みや表示を自動的に待機する機能が備わっています。
そのため他のスクレイピングツールで実装が必要だった明示的な待機処理を省略して実装できるため、シンプルな記述で高度なブラウザ操作が可能になります。
- **高速な操作**
Playwrithの他にエンドツーエンドテスト自動化フレームワークとして代表的な**Selenium**がありますが、SeleniumはWebDriverプロトコルを使用してブラウザと通信するため、プロトコルとブラウザとのやりとりのHTTPリクエストで若干の遅延が生じることがあります。
対してPlaywrightはブラウザと直接通信するため、低レイテンシーな操作が可能です。
- **非同期処理の活用**
Playwrightは非同期APIをフル活用しており、並行処理による効率的な操作が可能です。一方、Seleniumは基本的に同期的な操作が中心です。

- **コード自動生成機能**
Playwrightはコード自動生成機能を提供しており、手作業で行ったブラウザ操作を自動的にコードとして記録します。これにより、効率的にテストやスクレイピング用のコードを生成できます。


---

Playwrightの公式ドキュメントはこちら

https://playwright.dev/python/

## Playwrightの使用方法

### Playwrightのインストール
```bash
pip install pytest-playwright
```

必要なブラウザのインストール
```bash
playwright install
```
これでPlaywrightのコードが実行できるようになりました。


## コード自動生成機能
以下コマンドで[Playwright Inspector](https://playwright.dev/python/docs/debug#playwright-inspector)が立ち上がり、表示されたブラウザに対して実装したいスクレイピング操作をすることで、Playwrightのコードを生成してくれます。
```bash
playwright codegen <サイトURL>
```

:::note info
サイトURLはオプションで`playwright codegen`を実行後、開いたブラウザに直接サイトリンクを入力する方法でもコード生成可能です。
:::

## 実際にコード生成してみる

スクレイピング練習用のサイトがあったのでこちらを使用してコード生成してみました。
サイト↓

https://quotes.toscrape.com/

以下コマンドでジェネレータを起動しブラウザを操作することでコードが自動生成されていることが確認できました。
```bash
playwright codegen https://quotes.toscrape.com/
```
![2024-12-031.32.32-ezgif.com-video-to-gif-converter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3314085/a94547f0-21b4-30d5-b314-ebb137636b88.gif)

**Playwright Inspector**のTargetドロップダウンからテストコード、同期処理、非同期処理に切り替えることができます。

![2024-12-031.35.49-ezgif.com-video-to-gif-converter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3314085/35297a83-9cce-5b4d-1033-c14352f4bcf4.gif)


### Playwright Inspectorについて解説
![Playwright Inspector.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3314085/0e212e0a-8deb-c0fb-d0a4-5e64efda1d18.png)

- Pick locator
選択した要素を取得するコードを作成
- Assert Visibility
表示されていることを期待するテストコードを作成
- Assert Text
テキスト文字をassertするコードを生成
- Pick locator
選択した要素を取得するコードを作成
- Target
ドロップダウンから様々な言語, 同期・非同期処理のコードへ変換

:::note
Playwright Inspectorには**debugモード**が用意されており、実装したテストコードを`PWDEBUG=1`をつけて`pytest`の実行をするとdebugモードで起動できます。
breakpointを入れたい場合は実装コードに`page.pause()`を入れることで`page.pause()`の前で止めることができるようです。
```bash
PWDEBUG=1 pytest
```
:::

## まとめ
今回はPlaywrightについてまとめてみました。
セットアップが簡単で実装コードもシンプルな記述な上にコード自動生成機能があるので個人的に大好きなE2Eテストフレームワークです。
Playwrightには今回記載したコード自動生成機能以外にも様々な便利機能があるのでぜひ使ってみてはいかがでしょうか。
続)(SSD1327)M5StampS3、時計で遊ぶ。



x 過去ログ見よ!!
x 3.0.7
x 時間合わせは、別
x 業務連絡　理系フリマあるよ(絶滅メディア博物館)　なんのこと?



結果


![o_coq606.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/d31da2df-22bb-5900-2b26-9078803083bd.jpeg)


プログラム


```c++



//SSD1327_DS1307_M5NanoC6_1


//ヘッダーファイル
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1327.h>

//定義
#define SCREEN_WIDTH  128    // OLED display width, in pixels
#define SCREEN_HEIGHT 96    // OLED display height, in pixels
#define OLED_RESET     -1   // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1327 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define setCursorAA(AA,BB) setCursor(AA+16,BB)

// デバイスアドレス(スレーブ) DS1307
#define ADDR    0x68    // 2進数 1101000


//初期化
void setup() {

  // I2Cアドレスは使用するディスプレイに合わせて変更する
  display.begin(SCREEN_ADDRESS);

}//setup


//メインループ
void loop() {

  // 画面表示をクリア
  display.clearDisplay();

  // テキストサイズを設定
  display.setTextSize(2);
  // テキスト色を設定
  display.setTextColor(SSD1327_WHITE);
  // テキストの開始位置を設定
  display.setCursorAA(0, 16);

  //時計の処理 ↓ここから
  // レジスタのアドレスを先頭にする
  Wire.beginTransmission(ADDR);
  Wire.write(0x00);
  Wire.endTransmission();
  delay(1);

  // I2Cスレーブに8byteのレジスタデータを要求する
  Wire.requestFrom(ADDR, 8);

  // 8byteのデータを取得する
  char data_read[16] = {0x88, 0x88, 0x88}; //データバッファー
  int ii = 0;
  while (Wire.available())  {   // 要求より短いデータが来る可能性あり
    data_read[ii++] = Wire.read();       // 1バイトを受信
  }//while
  delay(1);

  //表示変換する パック二進化十進を文字列にする
  char cn1[16];  //桁
  cn1[0] = '0' + (data_read[2] >> 4);  //0 時 上位
  cn1[1] = '0' + (data_read[2] & 0xf); //1 時 下位
  cn1[2] = ':';
  cn1[3] = '0' + (data_read[1] >> 4);  //2 分 上位
  cn1[4] = '0' + (data_read[1] & 0xf); //3 分 下位
  cn1[5] = ':';
  cn1[6] = '0' + (data_read[0] >> 4);  //4 秒 上位
  cn1[7] = '0' + (data_read[0] & 0xf); //5 秒 下位
  cn1[8] = 0;
  //時計の処理　↑ここまで
  
  display.println(cn1); //時刻を表示する

  // 描画バッファの内容を画面に表示
  display.display();

  delay(1000); //1秒待つ

}//loop



```
「OIDC Front-Channel Logout」のけるiframeの実装方法（サンプルコードあり）

以下に、OIDC Front-Channel Logoutにおいてiframe技術を活用し、複数クライアントのログアウトを実現するためのサンプルコードを示します。このコードは、OIDCプロバイダ（IdP）のログアウトエンドポイントにユーザーがアクセスした際に、iframeを利用して複数クライアントにログアウト通知を送信する方法を示しています。

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>OIDC Front-Channel Logout</title>
</head>
<body>
  <h1>Logging out...</h1>
  <p>You will be logged out from all associated applications.</p>

  <!-- Main logout process -->
  <script>
    // クライアントのログアウトエンドポイントリスト
    const logoutEndpoints = [
      'https://client1.example.com/logout',
      'https://client2.example.com/logout',
      'https://client3.example.com/logout'
    ];

    // iframeを作成して各クライアントのログアウトエンドポイントにアクセス
    logoutEndpoints.forEach((endpoint) => {
      const iframe = document.createElement('iframe');
      iframe.src = endpoint;
      iframe.style.display = 'none'; // 表示されないように隠す
      document.body.appendChild(iframe);
    });

    // すべてのiframeにログアウト通知が送信された後のリダイレクト
    setTimeout(() => {
      window.location.href = 'https://idp.example.com/post-logout-redirect';
    }, 3000); // 必要に応じて遅延時間を調整
  </script>
</body>
</html>
```

### 説明

- **iframeの生成**: `logoutEndpoints`配列に格納されたクライアントのログアウトエンドポイントに対して、iframeを生成してアクセスします。
- **iframeの非表示**: iframeは`style.display = 'none'`で非表示に設定され、ユーザーに見えない形でログアウトリクエストが送信されます。
- **リダイレクト**: すべてのログアウトリクエストが送信された後、指定されたURL（OIDCプロバイダが定義する`post-logout-redirect`）にリダイレクトされ、ユーザーはログアウト完了後のページに誘導されます。
- **時間設定**: `setTimeout()`関数で遅延を設定し、すべてのログアウトリクエストが処理される時間を確保します。

このサンプルコードにより、OIDC Front-Channel Logoutの実装イメージを掴むことができるでしょう。複数クライアントのセッション終了をブラウザを介して同時に行う方法が実現されます。
【JavaScript】Unix Timestampを日時に変更する方法

以下のように記述することでUnix Timestampを日時に変更できます。

```js
const unixTimestamp = 1732019850

const date = new Date(unixTimestamp * 1000)

console.log(date) // Tue Nov 19 2024 21:37:30 GMT+0900 (日本標準時)
```
【超入門】Pythonで動くAWS LambdaのHelloWorld API

## はじめに
個人開発始めたての方やAWS、webアプリの勉強してる方向けに、まず挫折しない超シンプルなAPIをAWS環境にPythonで作ってみました。PostmanでHTTPリクエストを送ると'helloworld'が返ってくるというだけのものです。
ぜひ参考になれば。

## インフラ構成
まずさっくりしたインフラ構成図はこちらです。
私はmacを使っていますがPostmanのインストール手順が少し変わるだけで環境差分はほぼないです。
AWSのいいところですね。

![インフラ構成図.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762025/f073bf00-89f5-4ded-0a66-33bfcb9bb1e9.png)


## 事前準備
- AWSアカウントを発行済みであること
- Postmanがインストール済であること
⇨DLサイトhttps://www.postman.com/downloads/

## 構築の流れ
次にStep by StepでAPI構築の流れを追っていきます。
難しいところはほとんどなくサクサクと進めちゃいます。(30分くらいでできました。）

### 1. Lambda関数の作成
1. **AWS Lambdaコンソール**で「関数の作成」をクリック
![Lambda_function1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762025/bc489d5f-bb6a-c614-94a1-aad9a318a47e.png)

2. 「一から作成」を選び、以下のように設定する
3. IAMロールは、既存のものを使用する
![lambda_function2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762025/3f2b3e4e-7ccb-4ded-648f-a77e484dd535.png)
4. 関数が作成されたら、コードエディタで「helloworld.py」というファイルを新規作成する
5. 新規作成したファイルに以下のPythonコードを入力して「デプロイ」をクリックする

    ```python
    def lambda_handler(event, context):
        return {
            'statusCode': 200,
            'body': 'Hello, World!'
        }
    ```
6. ランタイム設定のハンドラが今回作ったファイル名.lamnbda_functionであることを確認する
![lambda_function3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762025/0abb6a9d-6061-2242-41bf-cad8f0b7ef0f.png)


### 2. API Gatewayの設定
1. **API Gatewayコンソール**で「REST API」を選択し、新しいAPIを作成します
   - **API名**：HelloWorldAPI（任意）
2. 作成したAPIで、「アクション」メニューから「リソースの作成」を選択し、以下のように設定する
   - **リソース名**：`/helloworld`
3. リソースを選択した状態で「アクション」→「メソッドの作成」→ **POST** を選択する
4. **統合タイプ**で「Lambda関数」を選び、先ほど作成したLambda関数（HelloWorldFunction）を指定する
![apigateway1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762025/5efbabb4-0e58-0e4c-82df-af5d8d86f187.png)

5. **API Gateway**で「アクション」→「APIのデプロイ」を選択する
6. 新しいステージ（例：「dev」）を作成し、デプロイを完了させる
7. デプロイ後、API > ステージでAPIの**エンドポイントURL**が表示されるのでコピー
![apigateway2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762025/74333b25-26e1-e890-e7ec-53294b480dc5.png)

### 4. Postmanで動作確認
1. **Postman**を開き、**POST**リクエストを作成する
2. URLに、API GatewayでコピーしたエンドポイントURLを入力する
3. 「Send」をクリックし、以下のようなレスポンスが返ってくることを確認する

![postman.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762025/c7de25b5-f9bd-d316-35c7-f715d463bbba.png)


    ```json
    {
        "statusCode": 200,
        "body": "\"Hello from Lambda!\""
    }
    ```

## おわりに
今回作ったwebAPIをベースに、DBにレコードを新規登録するAPIや何かしらの値を返却するAPIを作ってもう少し拡張して行くと面白いかもと思います。
ちなみに私は、kintoneがデータを更新するたびにawsのRDSにレコードを登録・更新してくれるAPIを作る予定です。
LangChainを使用してYouTube字幕を取得する方法

## はじめに

このノートブックでは、LangChainを使用してYouTube動画から字幕を取得する方法を説明します。LangChainのYouTubeLoaderを使用することで、簡単に字幕データを取得することができます。

<blockquote class="twitter-tweet" data-media-max-width="800"><p lang="ja" dir="ltr">Youtubeの字幕取得もlangchainで数行でやってみた<br>タイムスタンプの表示も可能！！ <a href="https://t.co/cZdpgmMumY">https://t.co/cZdpgmMumY</a> <a href="https://t.co/JZNZMi3wGi">pic.twitter.com/JZNZMi3wGi</a></p>&mdash; Maki@Sunwood AI Labs. (@hAru_mAki_ch) <a href="https://twitter.com/hAru_mAki_ch/status/1853811968358117624?ref_src=twsrc%5Etfw">November 5, 2024</a></blockquote> 

## 必要なライブラリのインストール

まず、必要なライブラリをインストールします。

```python
!pip install langchain-community
```

このコマンドでLangChainのコミュニティバージョンがインストールされます。

## YouTubeLoader のインポート

次に、LangChainからYouTubeLoaderをインポートします。

```python
from langchain_community.document_loaders import YoutubeLoader
```

## YouTube Transcript API のインストール

YouTubeの字幕を取得するために必要なライブラリをインストールします。

```python
%pip install --upgrade --quiet youtube-transcript-api
```

## 基本的な字幕の取得

### 4.1 日本語字幕の取得

```python
loader = YoutubeLoader.from_youtube_url(
    "https://www.youtube.com/watch?v=Tzu2onb2yYk",
    add_video_info=False,
    language=['ja']  # 日本語字幕を指定
)

# 字幕を取得
documents = loader.load()
```

### 4.2 字幕と動画情報の取得

動画のタイトルや説明などの追加情報も取得したい場合は、`add_video_info=True`を指定します。

```python
# pytubeのインストールが必要です
%pip install --upgrade --quiet pytube

loader = YoutubeLoader.from_youtube_url(
    "https://www.youtube.com/watch?v=Tzu2onb2yYk",
    add_video_info=True,
    language=['ja']
)

# 字幕と動画情報を取得
documents_with_info = loader.load()
```

## 高度な使用方法

### 5.1 複数言語の指定と翻訳

特定の言語が利用できない場合のフォールバック言語を指定したり、翻訳を設定することができます。

```python
loader = YoutubeLoader.from_youtube_url(
    "https://www.youtube.com/watch?v=Tzu2onb2yYk",
    add_video_info=True,
    language=["ja", "en"],  # 日本語を優先、なければ英語
    translation="en"        # 英語に翻訳
)
```

### 5.2 タイムスタンプ付きチャンク分割

字幕を一定時間ごとのチャンクに分割して取得することもできます。

```python
from langchain_community.document_loaders.youtube import TranscriptFormat

loader = YoutubeLoader.from_youtube_url(
    "https://www.youtube.com/watch?v=Tzu2onb2yYk",
    add_video_info=True,
    transcript_format=TranscriptFormat.CHUNKS,
    chunk_size_seconds=30  # 30秒ごとにチャンク分割
)

# チャンク分割された字幕を取得
chunked_documents = loader.load()
```

## エラーハンドリング

字幕取得時の一般的なエラーとその対処方法：

```python
try:
    loader = YoutubeLoader.from_youtube_url(
        "https://www.youtube.com/watch?v=Tzu2onb2yYk",
        language=['ja']
    )
    documents = loader.load()
except Exception as e:
    if "No transcript found" in str(e):
        print("指定された言語の字幕が見つかりませんでした")
    elif "Video unavailable" in str(e):
        print("動画が利用できません")
    else:
        print(f"エラーが発生しました: {e}")
```

## 注意点

- 字幕が設定されていない動画からは取得できません
- 自動生成字幕の品質は動画によって異なります
- 一部の動画では字幕が無効化されている場合があります
- APIの利用制限に注意が必要です

## まとめ

LangChainのYouTubeLoaderを使用することで、以下のことが可能になります：

- 複数言語の字幕取得
- 動画情報の取得
- 字幕の翻訳
- タイムスタンプ付きのチャンク分割
- エラーハンドリング

これらの機能を組み合わせることで、YouTubeコンテンツの分析や処理を効率的に行うことができます。


## 📒ノートブック

https://colab.research.google.com/drive/1VMiSULrT_md-C83Vy5YtAa5J0edQ5dfz?usp=sharing

<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
変数・クラスの初期化前の参照（JavaScript）

こんにちは。
JavaScript では変数・クラスの初期化前の参照は許されません。

下記を実行させると、エラーとみなされますので（```Cannot access ... before initialization```）、class 文を前置する必要があります。ただし ```bun run ./color.js``` ではエラーは生じません。

なお、```function``` 文は後置記述が許されます。

```color.js
const color = generate_color();
console.log(color);

class Color{
  constructor() {
    this.R = getRandomInt(255);
    this.G = getRandomInt(255);
    this.B = getRandomInt(255);
  }
}

function generate_color() {
  return new Color();
}

function getRandomInt(max) {
  return Math.floor(Math.random() * max);
}
```
続)時計ICの時間合わせプログラム簡易型(DS1307)(M5StampS3)



x 過去ログを見よ!!!
x 3.0.7



HHとMMに適切な値を書いて実行して終了
戻りは、なし

いろいろ
最初は、立派な入力システムを書いていたが
だんだん、めんどくさくなり、スクリプト的に
実行したら終わりに落ち着いた。

プログラム


```c++


//I2C_DS1307_SET_TIME_M5NanoC6_1

#include <Wire.h> //I2C library

#define ADDR    0x68  // 2進数 1101000

char    data_read[8]; //i2cバッファー

#define HH  23
#define MM  12

void setup()
{
  Wire.begin(); //uno

//i2c書き込み
  Wire.beginTransmission(ADDR);

  Wire.write((char) 0    ); //0 レジスターの位置は0
  Wire.write((char) 0    ); //1 秒
  Wire.write((char) ( MM /10)*16+( MM %10) ); //2 分
  Wire.write((char) ( HH /10)*16+( HH %10) ); //3 時

  Wire.write((char) 3    ); //4 曜日
  Wire.write((char) 1    ); //5 日
  Wire.write((char) 1    ); //6 月
  Wire.write((char) 0x20 ); //7 年

  Wire.endTransmission();

} //end setup

void loop()
{

} //loop


```
データベースのJOINと直積の関係について

直積とはAとBというテーブルがあったすると2つの表におけるすべての行を組み合わせて新しい表を作る演算です。
直積行の列数は両方の列数を足した数になり、行数は両方の行数を掛けた数になります。
![スクリーンショット 2024-11-05 231236.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3921010/15ee7d67-1ea1-2dc5-21b4-444248c5863b.png)
FROM 句で二つの表を書くことにより直積表が得られます。
![スクリーンショット 2024-11-05 231332.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3921010/397d6f90-19eb-14a2-1661-3ec90c7d5fbb.png)
そして、WHERE句で条件を指定することにより結合表の中でその条件にマッチしたレコードのみを取得することができます。
![スクリーンショット 2024-11-05 231401.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3921010/369d3697-5c56-77bb-6f81-e2e370cb7c8e.png)
また、FROM句でINNERJOINを使うことによりWHERE句で条件指定をしなくてもFROM句で指定することにより、よりシンプルな書き方で同じレコードを抽出することができます。
続)(SSD1306)M5StampS3、時計で遊ぶ。



x 過去ログを見よ!!
x 3.0.7
x 時間合わせは、別
x 業務連絡　理系フリマあるよ(絶滅メディア博物館)　なんのこと?

結果

![o_coq605.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/ed9d445f-34ba-24d9-5eea-bad2331a5ef8.jpeg)



プログラム


```c++



//SSD1306_DS1307_M5NanoC6_1


//ヘッダーファイル
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>


//定義
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// デバイスアドレス(スレーブ) DS1307
#define ADDR    0x68    // 2進数 1101000


//初期化
void setup() {

  // I2Cアドレスは使用するディスプレイに合わせて変更する
  display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);

}//setup


//メインループ
void loop() {

  // 画面表示をクリア
  display.clearDisplay();

  // テキストサイズを設定
  display.setTextSize(2);
  // テキスト色を設定
  display.setTextColor(WHITE);
  // テキストの開始位置を設定
  display.setCursor(0, 10);

  //時計の処理 ↓ここから
  // レジスタのアドレスを先頭にする
  Wire.beginTransmission(ADDR);
  Wire.write(0x00);
  Wire.endTransmission();
  delay(1);

  // I2Cスレーブに8byteのレジスタデータを要求する
  Wire.requestFrom(ADDR, 8);

  // 8byteのデータを取得する
  char data_read[16] = {0x88, 0x88, 0x88}; //データバッファー
  int ii = 0;
  while (Wire.available())  {   // 要求より短いデータが来る可能性あり
    data_read[ii++] = Wire.read();       // 1バイトを受信
  }//while
  delay(1);

  //表示変換する パック二進化十進を文字列にする
  char cn1[16];  //桁
  cn1[0] = '0' + (data_read[2] >> 4);  //0 時 上位
  cn1[1] = '0' + (data_read[2] & 0xf); //1 時 下位
  cn1[2] = ':';
  cn1[3] = '0' + (data_read[1] >> 4);  //2 分 上位
  cn1[4] = '0' + (data_read[1] & 0xf); //3 分 下位
  cn1[5] = ':';
  cn1[6] = '0' + (data_read[0] >> 4);  //4 秒 上位
  cn1[7] = '0' + (data_read[0] & 0xf); //5 秒 下位
  cn1[8] = 0;
  //時計の処理　↑ここまで
  
  display.println(cn1); //時刻を表示する

  // 描画バッファの内容を画面に表示
  display.display();

  delay(1000); //1秒待つ

}//loop



```
Webデザインに高校数学が役立つ実例 - 微分で作るドロップダウンメニュー

(1年前からずっと下書きだったらしい。そのまま投稿してみる）

----

数学がわからなくてもプログラムは書けるので、数学なんていらないぜ！という意見をたまに目にします。私もいらないと思います。でも、数学の知識があると、こういう時に役立つよっていう実例を一つ紹介しましょう。すんごいアルゴリズムの話ではないです。誰でもわかる Web デザインの話です。

Web サイトのメニューで、使いづらいやつがよくあります。斜めにマウスを持ってくと閉じちゃうサブメニュー、ありますよね。このツイートを見て思い出しました。

https://twitter.com/needle/status/1685868373564170240?s=20

緑の矢印の方にマウスを動かしても大丈夫だけど、赤の矢印の方はサブメニューが閉じる、という実装ですね。下手な実装をすると、緑の方向でもサブメニューが閉じちゃうんですよね。

確かこの記事で後述のライブラリを知った気がします。

[なぜAmazonのメガドロップダウンメニューはスムーズに操作できるのかという秘密](https://gigazine.net/news/20130307-amazon-mega-dropdown/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24737/eee19ac5-85a0-c3f5-8472-8c58f9898cb1.png)

その昔、これを解決する方法を自分で考えた私は、２秒でマウスの座標をwatchするという天才的なアイデアを思いつきました。サブメニューに向かう薄い緑の三角形の中に、マウスの座標があるかどうかを判定すればいいですよね。しかし天才の上には天才がいるものです。

jQuery-menu-aim がその問題をクリアしていたので実装を見た時の話です。

https://github.com/kamens/jQuery-menu-aim/blob/master/jquery.menu-aim.js#L267

私は、そのシンプルな構造に驚きました。

```Js
                function slope(a, b) {
                    return (b.y - a.y) / (b.x - a.x);
                };
```

これは微分で接線の傾きを求める公式そのままで、みなさん教科書で見たことがあるであろうものです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24737/0e0b7f3f-610c-2915-0092-583c1c734a40.png)

bは今マウスがいる座標で、aはさっき(0.1ms前とかに)マウスがいた座標です。それぞれのx, yの差異を割ることで２つの座標の接線の傾きを求めています。


[smart-dropdown-menu](https://yami-beta.hateblo.jp/entry/2016/11/26/022732) さんの gif が三角形がどう動いているのか分かりやすいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24737/aed830d9-8112-acd7-c2fa-dd6eef880079.png)



そして、それがサブメニューに向かう傾きなのかどうかを調べているだけなのです。座標で判定すると 2次元の判定がいるのでコードはゴミゴミするのですが、傾きは一次元のただの数字なので、 `if 傾き in (上の角に向かう傾き, 下の角に向かう傾き)` と、たった３つの数字だけで、美しく判定できてしまうのです。

数学が Web デザインにも役立つんだと実感した初めての瞬間でした。
実践DDD-イベントストーミング

## はじめに
システムのリアーキテクチャや新規サービスを開発するときに、業務知識の俗人化や人が入れ替わる度にキャッチアップのために多くの時間を割くの嫌ですよね。
今回はイベントストーミングによるモデリングとDDDで設計して、コードに落とすとこまで、紹介したいと思います。

## イベントストーミングとは

複雑なビジネスプロセスやドメインの全体像をチームで視覚的に理解し、システム設計に活かすための手法です。
従来の手法と違って、ドメインに詳しい人とエンジニアが集まって、行うことで、要件の漏れを防ぎやすくなったり、チーム全員に理解を促すことができます。
また、モデルとソースをマッピングすることで、仕様変更時や数年後アーキテクチャを変更する場合も影響範囲を把握しやすくなります。

## イベントストーミング要素

![スクリーンショット 2024-11-03 15.54.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900459/b1a966c3-22be-271a-fc59-0d7b0cdc60ba.png)


・アクター
コマンドを実行する人やシステム

・コマンド
ユーザやシステムが実行するリクエスト
以下のことをルールとして決めるとよい。

1. 過去形動詞を使用する。
2. 専門用語を使用しない

・集約
関連するデータやエンティティの集合体

・外部システム
S3、SendGridなど利用する外部システム

・イベント
発生した事象やアクション

・ポリシー
イベント発生の条件やルール

・ビュー/リードモデル
ユーザへ返却するデータを表現

・ホットスポット
注意が必要な事柄

各要素の概要は以上のとおり。

## イベントストーミングフロー

### ビッグピクチャ

目的: システムやドメイン全体の理解を深め、チーム間の共通認識を作る。

範囲: 全体のプロセスの流れ、エンドツーエンドの視点

実施内容: 

・イベントを思いつく限り列挙する
・イベントをカテゴライズする
・イベントを時系列に並べる

### プロセスモデリング

目的: ビジネスプロセスや業務フローの詳細な理解と設計

範囲: 特定のビジネスプロセスや機能に絞り込み、その詳細な流れを把握

実施内容: 

・アクターとコマンドを追加する
・外部システムを追加する
・アクターから実行されないコマンドはポリシーとして出す
・アクターへ返却するデータをリードモデルとして出す

### ソフトウェアモデリング

目的: システム内でのイベント処理フローの詳細化

範囲: データの流れやイベントの発生から処理までの流れ

実施内容:

・集約の特定
・境界の定義

集約は整合性を保つための単位です。
境界とは特定のモデルが定義される粒度

この辺は言葉での表現だと分かりづらいので、モデリングの例を見ていただけるとイメージつくかなと思います。

## 実践

お題は出前サービスとします。

**私自身はドメイン詳しいわけではないので、業務が間違っている可能性があります。**
**また例題のため、細かく業務を洗い出しません**

1. 思いつくイベントを挙げていく

![スクリーンショット 2024-11-05 21.49.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900459/0432bb75-4c3c-3553-9230-e59a840436d8.png)

2.イベントをカテゴライズしながら時系列で並べていく

![スクリーンショット 2024-11-05 21.57.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900459/fffef3cd-73bb-08e5-0bae-65c6fdcea984.png)

3.プロセスを詳細化しつつ、不足しているプロセスを追加する

![スクリーンショット 2024-11-05 22.37.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900459/2b1171e7-58b3-fc2c-71ca-37949697cb5b.png)

4.コメントや懸念事項があれば追加（すみません、先に集約入れてしまってます）

![スクリーンショット 2024-11-05 22.56.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900459/33580753-8744-b154-347d-9d850651e1ab.png)

5.集約を特定

![スクリーンショット 2024-11-05 22.56.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900459/33580753-8744-b154-347d-9d850651e1ab.png)


6.境界の定義

![スクリーンショット 2024-11-05 23.04.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900459/696751e5-9ebe-b771-0af6-8d09d656fbbe.png)


## さいごに

一連の流れを掴めたかなと。
ただ、何回やっても集約と境界の定義が難しいなと感じます。
いきなりベストな解は出ないかなと思うので、コード書きつつ修正の繰り返しになると思うので、ひとまず参加者の半数の承諾得られたら仮決めという形で次へ進んでいいと思います。
次はこの図からドメインモデルを作成していきます。
初学者の登竜門のひとつ「Xdebugの導入」sailを使用したプロジェクト

## はじめに

Xdebugって導入難しすぎません？
初学者の皆さんどうですか？　自力でできました？
記事通りにやってもうまくいかないし、、、

やっとできたので備忘録で取っておきます。


※laravel sailを使用をしようしてdockerを使ったデバックの記事になります。
※vscodeの拡張「php debug」のインストールは済ませること。
※Xdebugのバージョンは3になります。2だと設定が違います。確認はphpinfo関数を使用してください。

## .envファイルに以下2行追加

```
SAIL_XDEBUG_MODE=develop,debug,
SAIL_XDEBUG_CONFIG="client_host=host.docker.internal"
```

## xdebug.iniファイルを作成

/自分のプロジェクト/vendor/laravel/sail/runtimes/今回のPHPのバージョン/ここに作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832683/a170d3b1-f154-e12d-3ad9-6d275a356851.png)

※vendorフォルダがない場合は以下のコマンドを実行
```
composer install
```
※バージョンがわからない場合は、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832683/c4c5fa10-bd82-5671-4258-e751fb92f99f.png)
プロジェクト直下にあるdocker-compose.ymlのcontext:の右に書かれている最後の8.3がバージョンになる。
 　
/自分のプロジェクト/vendor/laravel/sail/runtimes/今回のPHPのバージョン/ここに

xdebug.iniを作成し、ファイル内に以下を貼り付ける
```
zend_extension=/usr/lib/php/20220829/xdebug.so
xdebug.mode=debug
xdebug.start_with_request=yes
```
## php.iniの編集
先ほど確認したPHPのバージョン配下にあるphp.iniを編集する
/自分のプロジェクト/vendor/laravel/sail/runtimes/今回のPHPのバージョン/php.ini←これ

以下を貼り付ける
```
xdebug.client_host = host.docker.internal
xdebug.mode = debug
xdebug.start_with_request = yes
xdebug.discover_client_host = 0
xdebug.remote_handler = "dbgp"
xdebug.client_port = 9003
zend_extension=/usr/lib/php/20230831/xdebug.so
```
:::note warn
client_port の値についてはポートを変えてもいいが、launch.jsonで合わせる必要があるので注意
:::


## Dockerファイルの編集

先ほど確認したPHPのバージョン配下にあるdockerfileを編集する
/自分のプロジェクト/vendor/laravel/sail/runtimes/今回のPHPのバージョン/Dockerfile←これ

```
# peclのインストール
RUN apt-get install -y php-pear

RUN pecl install xdebug \
&& docker-php-ext-enable xdebug	

COPY xdebug.ini /etc/php/8.2/cli/conf.d/20-xdebug.ini
```
どこでもいいとは思うが自分は写真のところに配置した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832683/4655624b-d08f-a92e-04a6-614cbc1ba80d.png)


コマンドを打ってコンテナを再度作り直し
```
./vendor/bin/sail down
./vendor/bin/sail up -d --build
```

## launch.jsonの作成、編集
サイドバーに存在する△と虫のアイコンをクリックし、
launch.jsonを作成する。この後PHPを選択
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832683/fd55d316-fd62-a4b9-8024-70895a462749.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832683/2c8ac898-4b33-d3a4-f9f1-5af08d7404e6.png)

ここのPathMappingsがいろいろ記事によって言い方が違うが
変数を使うのはおすすめしません。
（${workspace}みたいな）

：の左の場所は
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832683/c4c5fa10-bd82-5671-4258-e751fb92f99f.png)
プロジェクト直下のdokcer-compose.ymlファイルのvolumesに書かれています。

：右側の場所はプロジェクトをおいている場所
cドライブ直下にプロジェクトをおいている場合は
```
"c:/プロジェクト名"
```

これで必要な設定は全部です。
ブレイクポイントを打って（行の数字の左をクリック）
デバックを起動！（写真の緑△ボタン）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832683/cf9c689b-7353-eba8-8fa4-6bcdde9fd958.png)


あとは画面を動かす。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832683/6f77b8c6-6fd5-4828-c92c-5ae40601b807.png)

成功するとこのようにブレイクポイントで止まります。
プログラムの処理が行われるところでないと止まらないので
止まらないときブレイクポイントもチェック！

お疲れ様でした！
【入門者向け】繰り返し処理を図解で学ぼう

:::note
私が教材として作る際は、以下内容は必ず網羅してますよ、という話です。要するに宣伝ですが、役に立つ話なので公開します。
:::

一気に見ると大変なので、学習状況によって一つずつ見てくださいね。
一気見すると一瞬ですが、きちんと学習しようとすると、半日＋半日以上かかるつもりで読み進めてください。

## 目次
- [条件分岐編](https://qiita.com/nomurasan/private/4a40feb042bbb71cb650)
- 繰り返し処理編（ここ）
- [配列・連想配列・オブジェクト編](https://qiita.com/nomurasan/private/ec01ba58ba295a4fa80f)

### for文を理解する前に、コードを分解してからフローチャートをみよう
```js
for(i = 1; i <= 10; i++) {
  // ここに繰り返し実行したい処理
}
```

これを理解するためには、まず

```js
i = 1
if(i <= 10){
  // ここに実行したい処理
}
i++(i = i + 1)
```

をそれぞれに理解する必要があります。
分解したコードをフローチャートで書くと

```mermaid
graph TD
    A[i ← 1] --> B{i <= 10}
    B -->|"True"| C[i ← i + 1]
    C --> D[続きの処理]
    B -->|"False"| D
```

となります。
これをfor文にすると

```mermaid
graph TD
    A[i ← 1] --> B{i <= 10}
    B -->|"False"| E[繰り返し処理を抜けた後の処理]
    B -->|"True"| C[ここに実行したい処理]
    C --> D[i ← i + 1]
    D --> B
```

このように変わります。
（mermaidで綺麗に描けなかったので、ちょっと良くない図になってしまいました）

本質的にはif文のフローチャートの流れで、Trueの時にもう一度処理を繰り返すのだ、と理解すればわかりやすいです。

:::note alert
条件や実行処理を間違えると無限ループになる危険性があります。
:::

:::note warn
無限ループになるとシステムが止まったり落ちたりしてしまいますので、繰り返し条件は確実に満たすようにしましょう。
:::

:::note
繰り返し条件は「繰り返し処理をやめる条件」という考え方もできます。
:::

## while文とは？
for文と比較すると、

- 初期化がない
- 繰り返し処理が終了した時に毎度実施する処理がない

というのが大きな変化です。

```mermaid
graph TD
    B{i <= 10}
    C[ここに実行したい処理]
    D[繰り返し処理を抜けた後の処理]
    B -->|"True"| C
    C --> B
    B -->|"False"| D
```

これを念頭に置いて、コードをみます

```js
while(i <= 10) {
  // ここに実行したい処理
}
// 繰り返し処理を抜けた後の処理
```

`let i = 1;`と、`i = i + 1;`がありませんね。
そのため、for文の構造や思想を理解してから、あえてforを使わないという選択肢が持てるようになって初めて使えるものだと認識しましょう。

### do-while
```js
let i = 1;  // 繰り返しをわかりやすくするため、敢えて書きます
do {
  // ここに実行したい処理1
  // わかりやすくするために複数処理を入れます
} while(i <= 10)
```

```mermaid
graph TD
    A[i ← 1]
    B[ここに実行したい処理]
    E[わかりやすくするために複数処理を入れます]
    C{i <= 10}
    D[繰り返し処理を抜けた後の処理]
    A --> B
    B --> E
    E --> C
    C -->|"True"| B
    C -->|"False"| D
```

先ほどのwhile文との違い、繰り返し処理を１回実行してから判定をしています。
do-whileとwhileの違いで比較しやすいですが、for文とdo-whileで比較できるのが理想です。

:::note
専門用語っぽく言うと、
- 前置判定: 条件分岐を「先」に書いて繰り返し処理を実施
- 後置判定: 条件分岐を「後」に書いて繰り返し処理を実施
という違いです
:::

どちらが良いのか？という表現ができるうちはforを使った方がいいです。
forで解決できないものをdo-whileで解決しましょう。

## 次の章へ
- [条件分岐編](https://qiita.com/nomurasan/private/4a40feb042bbb71cb650)
- 繰り返し処理編（ここ）
- [配列・連想配列・オブジェクト編](https://qiita.com/nomurasan/private/ec01ba58ba295a4fa80f)
imgタグをfigureタグなどで囲う理由について

# はじめに
学んだことを忘れないように備忘録として残しています

初学者のうちはimgタグをdivタグで囲うように教わっているかと思います。
しかし実務ではpタグやfigureタグで囲うのが一般的のようです。
その理由やタグの使い分けについて解説していきます。

## そもそもなぜimg単体で使ってはいけないのか？
**結論、レイアウトの調整等がしにくいから。**

imgタグはインライン要素のため、他のブロック要素と並べると想定通りの配置が難しいことがあります。
そこでdivで囲むことで、親のブロック要素に対する位置やサイズを調整しやすくなります。特に、中央揃えや幅・高さの制限が必要な場合に便利です。

## pタグで囲う場合
p（段落）タグで画像を囲うのは、画像がその段落に含まれる内容の一部である場合に適しています。
例えば文章の中で参照される画像を含む場合、つまり文脈上必要になってくる画像の場合pタグで囲うのが良いと言えます。


## figureタグで囲う場合
figureタグは、画像や図、イラストなど、文書中の独立したコンテンツとして扱いたい場合に使用されます。
つまり文脈上必要で無い画像の場合にfigureタグを使うイメージで良いかと思います。

## まとめ
文章中で意味を持つ画像はpタグ、意味を持たない画像はfigureタグで囲むことを推奨します。
「OIDC Back-Channel Logout」と「OIDC Front-Channel Logout」の比較表（共通点、相違点）

以下は、「OIDC Back-Channel Logout」と「OIDC Front-Channel Logout」の共通点と相違点を比較した表です。

| 比較項目	| OIDC Back-Channel Logout	| OIDC Front-Channel Logout|
| --- | --- | --- |
|主な目的|	セキュアなログアウトとセッション終了|	ブラウザを介した複数クライアントのログアウト|
|通信経路|	サーバー間通信|	ユーザーのブラウザを経由|
|セキュリティ|	高いセキュリティ（ブラウザ依存なし）|	ブラウザ依存でCSRFなどの脆弱性リスクあり|
|リアルタイム性|	非リアルタイム（サーバー間通信のため）|	リアルタイム（ブラウザを介した即時通知）|
|通知方式|	HTTP POSTを使用したサーバー間のログアウトリクエスト|	|iframeを使用してブラウザ経由で各クライアントに通知|
|実装の複雑さ|	高い（サーバー間通信の設定が必要）|	低い（iframeを介した通信）|
|信頼性|	高い（ブラウザに依存しない）|	ブラウザ依存のため状況により通知が失敗する可能性|
|クライアントの対応|	サーバー側でのログアウトリクエストの受信処理が必要|	iframeリクエストに対応するだけで簡単|
|使用例|	高セキュリティが求められるシステム|	ユーザー体験を重視し、簡単な実装を求める環境|
|制約|	クライアントが対応していないと通知が届かない|	ブラウザの閉鎖や通信障害で通知が失敗する可能性|

‌

これらの特性を考慮し、環境やセキュリティ要件に応じて適切なログアウト方式を選択することが重要です。
ユークリッドの互除法をプログラムで実装（C言語）

# ユークリッドの互除法とは
### 1. 最大公約数
2つの自然数があったとします。
例えば$a=50$、$b=30$のとき、$a,b$で大きい方は$a=50$の方です。
このとき次のように式を立てられます。

```math
\begin{align}
    a \div b &= c\;あまり\; d\\
    a &= b\cdot c + d\tag{1}
\end{align}
```

今回は(1)式を利用したお話です。
2つの自然数があるとき、「**最大公約数**」を求めたいとします。
<INS>最大公約数は片方の数が小さければ簡単に求められますが、共に大きな数の場合、見つけるのは非常に困難</INS>です。
そこで<font color="red">**ユークリッドの互除法**</font>と呼ばれる計算方法を使います。

初めの例で試してみましょう。
$a=50$、$b=30$なので大きな方から小さな方を割ったときを考えます。

```math
\begin{align}
    a &= b\cdot c + d\tag{1}\\
    50 &= 30\cdot {\color{orange}{1}} + {\color{red}{20}}
\end{align}
```

**このとき、次のように$b$を$a$の位置へ、余りを$b$の位置へ移動します。**
これを繰り返します。
すると、

```math
\begin{align}
    a &= b\cdot c + d\tag{1}\\
    50 &= 30\cdot {\color{orange}{1}} + {\color{red}{20}}\\
    30 &= {\color{red}{20}}\cdot{\color{purple}{1}} + {\color{blue}{10}}\\
    {\color{red}{20}} &= {\color{blue}{10}}\cdot{\color{green}{2}} + 0
\end{align}
```

このようになり、余り（+の後ろ）が「$0$」になったら計算終了です。
このとき、$b$の位置にある数（今回なら「$10$」）が2つの自然数の最大公約数になります。

:::note warn
公式っぽく書くと、2つの自然数$a$ , $b$ $(a>b)$があるとき
```math
\begin{align}
    a &= b\cdot c_1 + d\\
    b &= d\cdot c_2 + e\\
    d &= e\cdot c_3 + f\\
    \vdots\\
    e &= f\cdot c_n + 0
\end{align}
```
と、計算することができ、余りが$0$になったときの$f$の位置にある数が2つの数の最大公約数です。
:::

### 2. 最小公倍数
ユークリッドの互除法が分かったところで、今度は**最小公倍数**を求める方法を紹介します。
例えば、先ほどの例のように$a=50$、$b=30$の場合、最大公約数は「$10$」でした。
ここで、$a$でも$b$でもどちらでも良いのですが、今回は$a$を使うとします。
また、最大公約数を$G=10$として次のように計算します。

```math
\begin{align}
    a \div G &= c\tag{2}\\
    c\times b &= L\tag{3}
\end{align}
```

このときに得られる$L$が最小公倍数です。
実際に値を入れて計算してみると、

```math
\begin{align}
    50 \div 10 &= 5\\
    5\times 30 &= 150
\end{align}
```

よって、「$150$」が2つの自然数の最小公倍数になります。

# C言語で実装
ここまでは数学的な話をしてきましたが、ここからはC言語でユークリッドの互除法を使った計算ができるプログラムを作成していきます。

まず、ここまでの復習として**最大公約数は(1)式を繰り返し同じような計算をすると分かりました。<font color="red"><INS>ただし、1回の計算が終わるたびに2つの数がズレていく**</INS></font>ことも分かりました。

次に、**最小公倍数は計算したい2つの自然数$a$,$b$と先に求めた<INS>最大公約数</INS>を用いて(2)(3)式を計算すれば良い**と分かりました。

これらを元にC言語でコードを書くと以下の通りになります。
```c:Euclid.c
#include <stdio.h>
int main(void)
{
    int a, b, c; // 変数cは仮代入
    printf("整数a,b(a>b)の最大公約数を求めます.\n");
    printf("整数aを入力 > ");
    scanf("%d", &a);
    printf("整数bを入力 > ");
    scanf("%d", &b);
    
    int A=a, B=b;
    
    while(1)
    {
        if(a<b)
        {
            printf("入力し直してください.\nERROR:a<b\n");
            break;
        }
        if(b==0) // b=0だったときは処理を終了する
        {
            printf("0で割ってはいけません.\n");
            return 0;
        }
        if(a%b==0)
        {
            printf("最大公約数 : %d\n", b);
            break;
        }
        else
        {
            c = a % b;
            a = b;
            b = c;
        }
    }
    
    //最小公倍数を求める
    c = A / b;
    c = c * B;
    printf("最小公倍数 : %d\n", c);
    
    return 0;
}
```

GCCコンパイルして、実行すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3925398/9c19a0e5-7b0e-88f1-a64c-f76145c60779.png)

このようになりました！！
答えが合っているか分かりませんが一応動きます。

ここで注意ですが、**あまりにも大きい数を使用するとオーバーフローする可能性があります**のでご注意ください。

挑戦できる方はオーバーフローしにくくなるように改良したり、他の言語でユークリッドの互除法を計算するプログラムを組んでみましょう。
controllerの中の　before_action :set_item

## はじめに
今までスルーしてしまっていた中途半端に理解しているコードを、これを機にひとつひとつ深堀していきたいと思います。

```
lass ItemsController < ApplicationController
  before_action :authenticate_user!, only: [:edit, :update, :destroy, :new] 
  before_action :set_item, only: [:edit, :update, :show, :destroy]
　before_action :move_to_index, only: [:edit, :update, :destroy]
  ```

例えばこんな記述があったとする。

``authenticate_user!``はログインログアウトを分けてくれて、``move_to_index``はトップページに戻してくれて
とわかるんだけど、いまいちわからないのが``set_item``。この子はなにをしてくれるんだろう。

## 解説
``set_item`` メソッドの役割は、``params[:id]`` から該当する商品の情報をデータベースから持って来て、``@item`` に代入する。
``edit`` や ``update`` などのアクションをする前に ``@item`` を使って該当する特定の商品データにアクセスできるようにしてくれている。

```
def set_item
  @item = Item.find(params[:id])
end
```
``params[:id]`` は、リクエストのURL（例えば ``/items/5/edit`` の場合は 5）から取得される商品の ID 。
``Item.find(params[:id])`` は、その ID に対応する商品をデータベースから探してきて、見つかった商品を ``@item`` 変数の中に入れてくれる。

``set_item`` を使う意味とは
同じ商品の情報を ``edit`` ``update`` ``show`` ``destroy`` の各アクションで使用するために、
``set_item``があることでコードをまとめる事が出来て ``before_action`` で一括して呼び出せる。

これにより、各アクション内に同じコードを書く必要がなくなって、コードの重複を減らし、可読性が向上する。

##　おわりに
可読性をあげるため重複をなくす等のテクニックはプログラマーの必須スキルと思うので
これからもアウトプットしてひとつひとつ自分のものにしていきます。
ABC378 C - Repeating

## はじめに
11/2開催のABC378のC問題の復習です。

## 問題文
長さ$N$の正数列$A=(A_1,A_2,…,A_N)$が与えられます。以下で定義される長さ$N$の数列$B=(B_1,B_2,…,B_N)$を求めてください。
$i=1,2,…,N$について、$B_i$を次のように定義する：
- $A_i$と等しい要素が$i$の直前に出現した位置を$B_i$とする。そのような位置が存在しなければ$B_i =−1$とする。より正確には、正整数$j$であって$A_i = A_j$となる$j<i$が存在するならば、そのうち最大の$j$を$B_i$​とする。そのような$j$が存在しなければ$B_i=−1$とする。

## 自分の提出
考え方としては、
「配列内の要素が前回どこで出現したか」を求める問題なので、
辞書を使って各数値の最後の出現位置を記録します

配列を順番に走査しながら、各要素について、
　1. その数値が前に出現していれば、その位置を配列$B$に記録
　2. 出現したことがないのであれば$-1$を配列$B$に記録

各要素を処理した後、配列$B$を出力する


```python:ABC378_C
def find_previous_num(N, A):
  last_seen = {}
  B = []

  for i in range(N):
    current = A[i]
    if current in last_seen:
      B.append(last_seen[current] + 1) # 0-based indexを出力用に+1
    else:
      B.append(-1)
    last_seen[current] = i

  return B

N = int(input())
A = list(map(int, input().split()))
result = find_previous_num(N, A)
print(*result)
```

## おわりに
Pythonで辞書が使えて楽でした。

ただ、$A_i$の数がもっと多い場合、
`if current in last_seen:`の部分を少し変えるなど
工夫が必要になったのかもしれません。
CloudWatch アラームの無効について

# はじめに
Amazon EventBridge を使用して、CloudWatch アラームの状態を一時的に変更した場合の動作を確認したくなった。
EventBridge でアラームの状態を変更しても、本来の状態に戻ると思うが念のため確認する。

# ステップ 1: CloudWatch アラームおよび EventBridge の作成

以下の CloudWatch アラームおよび EventBridge を作成

・閾値が StatusCheckFailed_System が 1 以下だと『アラーム状態』になる CloudWatch アラーム
・以下のように状態を『OK』に変更する Amazon EventBridge 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224973/663f8bed-70d2-25d3-8283-df1f0cc1d02f.png)


# ステップ 2: EventBridge の実行後の状態

CloudWatch アラームの状態。
Amazon EventBridge は 22:25 の実行に設定していたため、該当のタイミングで一時的に『OK』になったが、その後に、『アラーム状態』に戻ったことが確認できた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224973/1d19d077-c7cd-117a-9247-665d7ba0707b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224973/c10b2e9f-611a-018f-bc03-0da901e23e76.png)
BlenderとLLMで3Dの文字作成

# 記事の概要

Blenderに限らず3D関連のツール全てに言えるが、Blenderの最大の欠点は、このインターフェースの悪さ。
（ボタン多すぎ、タブ多すぎ、ウィンドウ多すぎ、アイコン多すぎ）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619695/98497d92-d591-4f26-969c-8de65409a1e2.png)

Blenderを初めてインストールした人が、3Dの文字を一文字作成するのに、どれぐらいの調査時間がかかるでしょうか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619695/114c5942-31d8-5916-858a-b7407d15def0.png)


LLMを使えば秒殺です。
そもそもBlenderの操作をLLMで行うためのアドオンを誰かに作ってほしい。

### 環境構築

以下からインストーラをダウンロードして、Blenderをインストールする。

https://www.blender.org/download/

### 手順

以下のようなプロンプトを入力し、Blenderで実行できるpythonのプログラムを作成してもらう。

```
Blenderで「あいうえお」を3Dオブジェクトとして表示するためのスクリプトを作成してください。
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619695/a2657873-a4fd-8f4f-e096-ca0285231f99.png)

今回は以下のスクリプトが作成された。

```python
import bpy

# Blender内の既存オブジェクトを全て削除
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)

# 表示するテキスト
text_content = "あいうえお"

# テキストオブジェクトの作成
text_obj = bpy.data.curves.new(name="JapaneseText", type='FONT')
text_obj.body = text_content  # テキスト内容を設定

# 3Dオブジェクトとして追加
text_object = bpy.data.objects.new(name="JapaneseTextObject", object_data=text_obj)
bpy.context.collection.objects.link(text_object)

# 3Dビュー内の配置とサイズ設定
text_object.location = (0, 0, 0)
text_object.scale = (1, 1, 1)  # サイズ調整

# テキストの押し出し設定（3D化）
text_obj.extrude = 0.1  # 押し出しの深さを設定（数値を大きくすると厚みが増します）

# 表示する視点の調整
for area in bpy.context.screen.areas:
    if area.type == 'VIEW_3D':
        for space in area.spaces:
            if space.type == 'VIEW_3D':
                space.region_3d.view_perspective = 'CAMERA'

# カメラとライトの追加
# カメラ
bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=(2, -2, 2), rotation=(1.1, 0, 0.78))
camera = bpy.context.object
camera.name = "Camera"

# ライト
bpy.ops.object.light_add(type='POINT', location=(3, 3, 3))
light = bpy.context.object
light.name = "Light"

print("3Dテキストオブジェクトの作成が完了しました。")
```

Blenderを起動する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619695/6fd42121-47f6-ab98-8990-7c7241fe4855.png)

①「Scripting」タブをクリックして、②「+ New」をクリックする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619695/75754df0-f87d-9b71-6dbf-95c0c02066b9.png)

テキストエディタになるので、LLMが作成したスクリプトを貼り付ける。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619695/b2528cf9-bc8e-b20c-0fc9-d1e8f8531128.png)

再生ボタンをクリックする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619695/0ecf580d-d3a4-ee4d-8f14-0400becfdc1e.png)

さっきまで、立方体が表示されていたところに文字が表示されている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619695/063ef58c-840e-f47a-81b5-2394fee45e5b.png)

「Layout」タブにクリックすると、文字が出力されていることをわかる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619695/76bad121-c9c5-9c0f-a365-3ae2ad015f10.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619695/1e947c81-71cf-8ef9-011b-bb62449776bd.png)

# 感想

操作方法を知っていれば簡単なのに、調べ方すらわからない分野に、生成AIは非常にシナジーが高い。
今回の手順はその代表例ともいえる。
プログラムが実行できるところであれば、LLMはどこまででも操作できる。
[AWS SAA] AWS初心者がEC2についてまとめた。

# はじめに
私は、エンジニア歴二年目の下っ端エンジニアです。
今後のキャリアと収入を考えてAWS資格は持っておくべきだろうと考えたため、AWS SAAについて学習した内容を日々、ここでまとめていきます。
本日はEC2についてです。

# EC2とは
AWSが提供している仮想のサーバを構築できるサービスのことです。
EC2を利用して構築したサーバをインスタンスと呼ぶ。

# EC2のストレージ
EC2にはインスタンスストアとEBSという二つのストレージがあります。

## インスタンスストア
### 特徴
揮発性のストレージで、インスタンスが停止すると保持していたデータが消える。
### 用途
一時的なデータ保存

## EBS
### 特徴
インスタンスを停止してもデータの永続的な保持が可能なストレージ
### 用途
永続的なデータの保持

# EC2の基盤
インスタンスは実際にあるコンピュータ上で動作しており、運用方法にもパターンがある。
## マルチテナンシー
一つのホストコンピュータに複数のアカウントのインスタンスが配置される
## ハードウェア専有インスタンス
一つのホストコンピュータに同一のアカウントのインスタンスのみを配置できる。
インスタンスを起動するハードウェアの固定は不可能。
## Dedicated hosts
一つのホストコンピュータに同一のアカウントのインスタンスのみを配置できる。
インスタンスを起動するハードウェアの固定が可能。

# セキュリティ
EC2ではセキュリティグループという仮想のファイアウォールを用いてインスタンスへのアクセスを制御します。

#　ネットワーク
EC2のネットワークには三種類のIPアドレスがあります。
## プライベートIPアドレス
AWSのネットワーク内で使用するIPアドレスとなっていて、インスタンスの作成時に付与されます。
インスタンスを再起動しても変わらない
## パブリックIPアドレス
動的なIPアドレスで、インスタンス作成時に付与される。
インスタンスを再起動したら変わってしまう。
## EIP (Elapsed IP Address)
静的なグローバルIPアドレスです。
インスタンスを再起動しても変わりません。

# 運用・監視
CPU使用率やディスク使用率はなどはCloudWatchというサービスで確認できます。
設定した閾値を超えた際にメールで連絡を送るなどすることができます。
AutoRecoveryを使用することで、インスタンスに異常が起きた時に自動で再起動してくれます。

# 利用料金
## オンデマンドインスタンス
利用した時間分の料金がかかります。

## リザーブドインスタンス
1年or3年の契約を行うことで少し安価になります。

## スポットインスタンス
誰も使用していないインスタンスを入札して使用することで、リザーブドインスタンスより安価になります。

# 最後に
AWSはほとんど分かりませんが、継続してSAAは一旦取りたいなと考えています。
また、AWS実際に触ってみたい気持ちと料金でのミスの記事をよくみるので手が出せていません🥺
AWS勉強中の方もいらっしゃると思うので一緒に頑張っていきましょう！
最後まで読んでくださりありがとうございました。気軽にいいね、ストックしてくださるとモチベにつながります。

## 引用
主に動画学習をしており、参考にさせていただいている動画
https://www.youtube.com/watch?v=QA0aHa0qPVk&list=PLPzcoMdqG5npIMyRZ7QmBaZQ-LdMeGXRa