OmniAICreator/Qiita-1.07M huggingface dataset:
12日目

開発環境構築からStreamlitアプリ開発、そしてエラー解決まで：詳細まとめ
このまとめでは、開発環境の構築からStreamlitアプリ開発、OpenAI APIの利用、そしてプログラミングの基礎、ユーザー管理、エラー解決まで、幅広いトピックを網羅しています。

1. 開発環境の構築
Homebrewのインストール
macOSでパッケージ管理ツールHomebrewをインストール。
brew installコマンドでソフトウェアを管理。
Python環境のセットアップ
pyenvでPythonのバージョンを管理。
.zshrcにpyenvの初期化スクリプトを追加し、source ~/.zshrcで設定を反映。
Ryeのインストールと使用
Ryeをインストールし、Pythonプロジェクトの依存関係を管理。
.zshrcにRyeの環境設定を追加し、source ~/.zshrcで設定を反映。
rye installで依存関係をインストールし、rye runでスクリプトを実行。
2. アプリケーション開発
Streamlitアプリケーションの開発
Streamlitでチャットボットアプリケーションを構築。
st.session_stateでユーザーのチャット履歴を保持し、ページの再読み込みをまたいでデータを保存。
OpenAI APIの利用
OpenAI APIを使用して、ユーザーの入力に対するAIの応答を生成。
clientオブジェクトを使用してAPIにリクエストを送信し、応答を取得。
3. プログラミングの基礎
f文字列の使用
Pythonのf文字列を用いて、文字列内に変数や式を埋め込む方法を学習。
文字列のフォーマットを簡潔に記述。
4. ユーザー管理と識別
ユーザー識別の方法
Streamlitではユーザー識別の機能は提供されていないため、クッキーやセッションID、ユーザー認証などの方法を検討。
uuidライブラリを使用して一意のユーザーIDを生成し、st.session_stateに保存する例を紹介。
5. エラーの解決
エラーメッセージの理解と修正
TypeError: title() got an unexpected keyword argument 'height'のエラーを修正し、st.title()の正しい使い方を確認。
まとめ
このまとめは、開発環境の構築からアプリケーション開発、そしてエラー解決まで、Pythonプログラミングに必要な知識とスキルを網羅的に提供しています。これらの情報を活用することで、より効率的にPythonプロジェクトを進めることができるでしょう。

補足
各項目は必要に応じてさらに詳細な情報を参照してください。
エラー解決では、エラーメッセージを理解し、適切な対処法を検討することが重要です。
ユーザー管理と識別は、アプリケーションのセキュリティとユーザーエクスペリエンスに大きく関わるため、慎重に検討する必要があります。
この情報が、あなたのPython開発の一助となれば幸いです。
プリザンターの新規作成画面にURLで既定値を設定する方法

## はじめに
プリザンターの新規作成画面、管理画面で固定的な既定値を設定することが出来ます。ただし、これは決め打ちになってしまいます。
サーバスクリプトを使えば、modelに値をセットすることで動的に既定値を変更することが出来ます。今回は、サーバスクリプトとURLのクエリを使用して、URLにセットしたデータを既定値として使用する方法を紹介します。

## 実装方法
プリザンターの新規作成画面のURLは`http(s)://{IPアドレス or ドメイン}/items/{サイトID}/new`となっています。これにクエリパラメータを連結することで、プリザンターにデータを渡すことが出来ます。これを実現するには、サーバスクリプトの`context.QueryStrings`を使用します。

実際に新規作成画面に対して、データを渡すことを想定して、サーバスクリプトを書いてみます。
```
//使用するURL
http(s)://{IPアドレス or ドメイン}/items/{サイトID}/new?ClassA=hogehoge
```

```javascript
if (context.Action === 'new') {
    var data = context.QueryStrings.Data('ClassA');
    logs.LogInfo(data);
}
```
これを画面表示の前を条件にして、実際に実行してみるとデバッグウインドウにはこのように表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3555395/0f8f726e-2481-40c6-77b3-417559a829c6.png)
きちんとデータを取得出来ることが確認出来ました。
URLエンコードが必要な文字を使用する場合は、渡す時にエンコード、渡されたものを受け取った時にデコードが必要になるので、注意してください。（今回、そこは割愛します）

では、実際に取得したデータを既定値としてセットしてみます。
```javascript
if (context.Action === 'new') {
    var data = context.QueryStrings.Data('ClassA');
    if(data) {//クエリの中身があるときだけセットする（＝クエリがなければ管理画面でセットした既定値が生きる）
        model.ClassA = data;
    }
}
```
実行条件は先ほどと同じ画面表示の前です。
![レコーディング-2025-01-31-175636.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3555395/655de91c-c69c-18bf-c80f-3fe842a0cf52.gif)
分類A(ClassA)にきちんと渡した値がセットされていますね。

### 非ログイン状態だとどうなるの？
上のデモはログイン状態で行っていますが、非ログイン状態でも問題無く動作します。
追加したクエリは変更されずにリダイレクト処理が行われるので、ログイン画面を間に挟むだけで既定値を持った状態で新規作成画面が開かれます。

## まとめ
今回はURLから新規作成画面に既定値を渡す方法を紹介しました。この方法を使うと、外部システムからプリザンターの画面をポップアップした時に既定値を持たせることが簡単にできるようになります。
外部のCTIシステムから電話番号を渡した状態で、プリザンターの新規作成画面をポップアップさせることが出来るようになるなど、いろいろと活用シーンがありますので、是非活用してみてください。
Pythonのlist.append()とlist.extend()の違い

Pythonでリストに要素を追加する方法として、`append()`と`extend()`があります。本記事では、それぞれの違いについて詳しく解説します。

## `append()`メソッド

`append()`はリストの末尾に1つの要素を追加するメソッドです。このメソッドはリスト自体を変更しますが、**返り値は`None`** なので注意が必要です。

### 使用例

```python
a = [1, 2, 3]
print(a)  # [1, 2, 3]

b = a.append(4)  # `append()` は `None` を返す
print(a)  # [1, 2, 3, 4]
print(b)  # None
```

`append()`を使うとリスト`a`自体が変更されるため、新しい変数`b`には`None`が入ります。

## `extend()`メソッド

`extend()`はリストに **別のiterable（イテラブル）** の要素を追加するメソッドです。こちらもリスト自体を変更し、**返り値は`None`** です。

### `extend()`の引数に関する注意点

`extend()`の引数は**iterable（イテラブル）** である必要があります。iterableとは、`for`ループなどで要素を1つずつ取り出せるオブジェクトのことです。例えば、`list`、`tuple`、`str`などが該当します。

### 使用例

```python
x = [1, 2, 3]
print(x)  # [1, 2, 3]

# x.extend(4)  # TypeError: 'int' object is not iterable

y = x.extend([4])  # `extend()` は `None` を返す
print(x)  # [1, 2, 3, 4]
print(y)  # None
```

`extend()`の引数には **リストのようなiterable** を渡す必要があり、整数を渡すとエラーになります。

## （番外編）新しい変数に反映したい場合

`append()`や`extend()`はリストを直接変更するため、新しい変数に代入しても`None`が入ります。新しい変数に変更後のリストを代入したい場合は、`+` 演算子を使います。

### 使用例

```python
s = [1, 2, 3]
print(s)  # [1, 2, 3]

t = s + [4]  # `s` は変更されず、新しいリストが `t` に代入される
print(s)  # [1, 2, 3]
print(t)  # [1, 2, 3, 4]
```

`+` を使うと元のリスト`s`を変更せずに、新しいリストを作成できます。

## まとめ

| メソッド | 動作 | 返り値 |
|----------|------------------------------------------------------|--------|
| `append(x)` | リストの末尾に `x` を追加 | `None` |
| `extend(iterable)` | リストの末尾に `iterable` の要素を追加 | `None` |
| `+` | 新しいリストを作成 | 新しいリスト |

- `append()` は1つの要素を追加するが、返り値は`None`。
- `extend()` はiterableの要素を展開して追加するが、返り値は`None`。
- 新しいリストとして扱いたい場合は `+` を使う。
RaspberryPI pico HID

Raspberry PI pico(W)用のプログラムです
ボードは[Raspberry Pi Pico Arduino core, for all RP2040 and RP2350 boards](https://github.com/earlephilhower/arduino-pico8)を使用しました。

ファイル/使用例/09.USB
より、マウスとキーボードのサンプルプログラムを参考に制作しました。



### プログラム

```cpp
#include "Mouse.h"
#include "Keyboard.h"

int Xajst =4095; //マウスのX軸調整
int Yajst =3150; //マウスのX軸調整
int MouseSpeed =100; //マウススピード(小さいほど早い)

void setup() {
  
  Serial.begin(115200); //シリアル通信用
  Keyboard.begin();

  analogReadResolution(12);
  pinMode(26, INPUT);
  pinMode(27, INPUT);
  Mouse.begin();
  
  for( int i=0; i >=15 ; i = i+1 ){ //0~4:切り替えスイッチ 5:空 6~15:ボタン
    pinMode(i,INPUT);
  }
}

void loop() {
  int Y = analogRead(26); //値の読み取り
  int X = analogRead(27);
  Serial.println(Y); //数値確認用
  Serial.println(X);
  delay(5);

  int Xmove = (-X-1200+Xajst)/MouseSpeed; //マウスの移動量調整
  int Ymove = (Y-Yajst)/MouseSpeed;

  Mouse.move(Xmove, Ymove, 0); //マウス入力

  if (digitalRead(0)==LOW && digitalRead(1)==LOW && digitalRead(2)==LOW) { //切り替えスイッチ000xxの時

    int X[9];

    if (digitalRead(3)==LOW && digitalRead(4)==LOW){        //切り替えスイッチxxx00の時
      X[0]={0x61}; X[1]={0x62}; X[2]={0x63}; X[3]={0x64}; X[4]={0x65}; X[5]={0x66}; X[6]={0x67}; X[7]={0x68}; X[8]={0x69};    
    }if (digitalRead(3)==LOW && digitalRead(4)==HIGH){        //切り替えスイッチxxx01の時
      X[0]={0x71}; X[1]={0x72}; X[2]={0x73}; X[3]={0x74}; X[4]={0x75}; X[4]={0x75}; X[5]={0x76}; X[6]={0x77}; X[7]={0x78}; X[8]={0x79};      
    }

    for( int i=0; i <=8 ; i++ ){
      if (digitalRead(i+6)==HIGH){
        Keyboard.press(X[i]);
      }else{
        Keyboard.release(X[i]);
      }
    }
  }
    
  if (digitalRead(0)==LOW && digitalRead(1)==LOW && digitalRead(2)==HIGH) { //切り替えスイッチ001xxの時

  if (digitalRead(6)==HIGH) {
    Keyboard.press(KEY_LEFT_SHIFT);
  }else{
    Keyboard.release(KEY_LEFT_SHIFT);
  }

  if (digitalRead(7)==HIGH) {
    Keyboard.press(KEY_LEFT_ALT);
  }else{
    Keyboard.release(KEY_LEFT_ALT);
  }

  if (digitalRead(8)==HIGH) {
    Keyboard.press(KEY_LEFT_CTRL);
  }else{
    Keyboard.release(KEY_LEFT_CTRL);
  }

  if (digitalRead(9)==HIGH) {
    Keyboard.press(KEY_ESC );
  }else{
    Keyboard.release(KEY_ESC );
  }

  if (digitalRead(10)==HIGH) {
    Keyboard.press(0x61);
  }else{
    Keyboard.release(0x61);
  }
  
  if (digitalRead(11)==HIGH) {
    Keyboard.press(0x61);
  }else{
    Keyboard.release(0x61);
  }

  if (digitalRead(12)==HIGH) {
    Keyboard.press(0x62);
  }else{
    Keyboard.release(0x62);
  }

  if (digitalRead(13)==HIGH) {
    Keyboard.press(0x63);
  }else{
    Keyboard.release(0x63);
  }

  if (digitalRead(14)==HIGH) {
    Keyboard.press(0x64);
  }else{
    Keyboard.release(0x64);
  }

  if (digitalRead(15)==HIGH) {
    Keyboard.press(0x65);
  }else{
    Keyboard.release(0x65);
  }
  }
  //長すぎる


  if (digitalRead(0)==LOW && digitalRead(1)==HIGH && digitalRead(2)==LOW) { //切り替えスイッチ010xxの時
    if (digitalRead(6)==HIGH) {
      Keyboard.println("thank you"); //入力して改行
    }
    if (digitalRead(7)==HIGH) {
      Keyboard.println("good job");
    }
    if (digitalRead(8)==HIGH) {
      Keyboard.println("OMG");
    }
  }  
}
```
最終変更2025/02/10
(yyyy/mm/ddこそ至高)
ご自由にお使いください(多分使えん)
PythonからのChatgpt APIへのリクエストを改善する

# はじめに
皆様お疲れ様です！
TechoesインフラチームのTです。
今回は以前公開したChatgpt APIを利用してCFNテンプレートを生成する記事で使用したPythonコードを久しぶりに実行したところエラーを吐いていたので解消と解決方法の共有ができればと思います。
よろしければ以前の記事にも目を通していただけてたらと思います。

https://qiita.com/y-tomaru-techoes/items/4988aaae1527a033faa2
# 実行環境
- Windows: 11 Home 24H2
- Python: 3.13.1
- モデル: gpt-4o
- openai: 1.60.1

# 現状
まず、現状を把握するために現在のコードと実際に吐いているエラーを見てみましょう。

### 現在のコード

~~~python:test.py
from openai import OpenAI

client = OpenAI(
    api_key="xxxxx",
)
chat_completion = client.chat.completions.create(
    messages=[
        {
            "role": "user",
            "content": "Hello！",
        }
    ],
    model="gpt-4o",
)

print(chat_completion.choices[0].message.content)
print(chat_completion.usage.completion_tokens)
print(chat_completion.usage.prompt_tokens)
print(chat_completion.usage.total_tokens)
~~~

### エラー文

```:<font color='salmon'>Error</font>
Traceback (most recent call last):
  File "C:\xxx\xxx\xxx\test.py", line 1, in <module>
    from openai import OpenAI
ModuleNotFoundError: No module named 'openai'
```
# エラーについてひも解く
注目していただきたいのはエラーのこの部分です。
```:<font color='salmon'>Error</font>
ModuleNotFoundError: No module named 'openai'
```
検索をかけてみたところ、下記の結果になりました。
`no module named`エラーは、Pythonが指定されたモジュールを見つけられない場合に発生します。

トラブルシューティングの方法としてエラー文を検索することで解決に向かう場合が経験上多いのでエラー文は重要な手掛かりになります。
# 修正
最初エラーを見たときになんで`no module named`が出るんだと戸惑いましたがpythonのバージョンを確認したところ`3.11.4`から`3.13.1`に自分で上げていたことを忘れていました。
ということでopenaiを改めてインストールしていきます。
```:Command
pip install
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3492991/f0068393-8c2f-27b5-af1f-c8f2ff668ddc.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3492991/22e9fb7a-edd8-08f2-5d3c-90935c4f663e.png)
インストールが完了したので早速実行してみましょう。
`py test.py`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3492991/46722870-d1e5-8f4c-1f27-c9057b39f010.png)
# 所感
今回はエラーのトラブルシューティング方法の一例をあげてみました。
これからの時期、新卒などで新しくこの業界に携わる方が多いかと思いますので参考になれば幸いです。
# 参考文献

https://dtnavi.tcdigital.jp/cat_system/language_219/
ubuntuベースのプライベートEC2にSystems Manager(Session manager)でアクセスしようとしたらハマった

※設定方法や接続方法は他の記事で詳しく書いてあるので事象だけ書きます。

## やりたいこと
aws cli を使用して local から private subnetにある EC2(ubuntu)にインターネットを使用せずアクセスしたい
`aws ssm start-session --target i-xxx`

## エラー
[記事](https://repost.aws/knowledge-center/ec2-systems-manager-vpc-endpoints)を参考に構成したが `An error occurred (TargetNotConnected) when calling the StartSession operation: i-xxxxx is not connected.` になる

## 結論
ubuntuにRoute 53 Resolverである`169.254.169.253`(AWS DNS IPv4)を読むようにセットしアクセスすることで解決した。

## 構成
[この記事](https://repost.aws/knowledge-center/ec2-systems-manager-vpc-endpoints)を参考にして

- VPC
- IAM
- Security Group
    - VPC
    - EC2
- EC2 (ubuntu)
    - policy(`AmazonSSMManagedInstanceCore`)
    - ssm-agent install
- VPC endpoint
    - com.amazonaws.[region].ssm
    - com.amazonaws.[region].ssmmessages
    - com.amazonaws.[region].ec2messages
        - ※ ssm-agentのversionが3.3.40.0以降では ssmmessagesを使用する場合、[ec2messagesは必要ない](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/systems-manager-setting-up-messageAPIs.html#message-services)らしい

の構成で組んでアクセスしたが上記エラーが発生

## 原因特定
- EC2, VPCにアタッチされている policy, roleが正しいか
    - roleが古い文法になっていたので修正したが解決せず（公式の最新を確認）
- 各所のインバウンド/アウトバウンドの設定に不備がないか
    - 問題なかった
- ssm-agentが最新versionであるか
    - なっていなかったのでinstanceに接続しアップデートしたが解決しなかった
    - `sudo snap refresh amazon-ssm-agent`を実行
- ssm-agentが起動しているか確認
    - `sudo systemctl status snap.amazon-ssm-agent.amazon-ssm-agent.service`を実行
    - runningであることを確認
- `sudo cat /var/log/amazon/ssm/amazon-ssm-agent.log` を実行し ssm-agentのログを確認する
    - ssm-agent立ち上げの段階でerrorを確認
    - `Entering SSM Agent hibernate - RequestError: send request failed
caused by: Post "https://ssm.[region].amazonaws.com/": dial tcp: lookup ssm.[region].amazonaws.com on 8.8.8.8:53: read udp xx.xx.xx.xx:xxxx->8.8.8.8:53: i/o timeout`

### DNSで接続エラーが出ているので修正
private subnetなのにpublicにあるGoogle Public DNS(8.8.8.8)にアクセスしようとしている。

#### 現状把握
instance内で `sudo cat /etc/resolv.conf` 
```
nameserver xxx.xxx.xxx.xxx
nameserver 8.8.8.8
```

#### 修正
[ここを参考](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/AmazonDNS-concepts.html#AmazonDNS)にして`169.254.169.253`をとりあえず `/etc/resolv.conf` に追加 (`tee` or `vi`などで行う）

```
nameserver 169.254.169.253
nameserver xxx.xxx.xxx.xxx
nameserver 8.8.8.8
```

#### 接続確認
1. ssm-agentを再起動
`sudo systemctl restart snap.amazon-ssm-agent.amazon-ssm-agent.service`

2. localから確認
`aws ssm start-session --target i-xxx`

アクセスできた！

#### 永続化
instanceの停止なので設定が消える場合があるので`netplan` で設定しておく
DeepSeek-R1 を LLaMA-Factory でファインチューニングする完全ガイド

## **DeepSeek-R1 を LLaMA-Factory でファインチューニングする完全ガイド**  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917980/571227ae-8cfb-2894-6b43-9eadd0d5bb6b.png)

**DeepSeek-R1** をファインチューニングすると、その応答をカスタマイズでき、特定のタスクにより適したモデルにすることができます。本ガイドでは、強力なファインチューニングツールである **LLaMA-Factory** を使用して **DeepSeek-R1** を調整する方法を説明します。LLaMA-Factory は **LoRA**, **QLoRA**, **SFT** などのファインチューニングをサポートしています。  

---

## **🔹 なぜ DeepSeek-R1 をファインチューニングするのか？**
以下のような場合にファインチューニングが必要です：
- **専門的な知識** を必要とする場合（例：金融、医療、カスタマーサポート）
- モデルを **組織のトーンや文章スタイル** に適合させたい場合
- **特定のタスク** において高いパフォーマンスが求められる場合（例：コード生成、翻訳、チャットボットの応答）

---

## **🔹 ステップ 1: LLaMA-Factory と依存関係のインストール**

ファインチューニングを始める前に、**CUDA 対応の NVIDIA GPU**（推奨：VRAM 24GB 以上）が搭載されたシステムを用意してください。

### **1️⃣ LLaMA-Factory リポジトリをクローン**
まず、GitHub から LLaMA-Factory のリポジトリをダウンロードします：
```bash
git clone https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
```

### **2️⃣ Python 仮想環境を作成**
仮想環境を設定することで、依存関係の競合を防ぎます：
```bash
python3 -m venv venv
source venv/bin/activate  # Linux/Mac
venv\Scripts\activate  # Windows
```

### **3️⃣ 必要なパッケージをインストール**
LLaMA-Factory ディレクトリ内で以下のコマンドを実行してください：
```bash
pip install --upgrade pip
pip install -r requirements.txt
```

---

## **🔹 ステップ 2: ファインチューニング用のデータセットを準備**
DeepSeek-R1 のファインチューニングには、**SFT（Supervised Fine-Tuning）**, **LoRA（Low-Rank Adaptation）**, **QLoRA** などが使用できます。

### **1️⃣ JSONL 形式のデータセットを作成**
データセットは以下のような構造にします：
```json
{"instruction": "今日の天気を教えて", "input": "", "output": "今日は晴れです！"}
{"instruction": "プログラミングについて説明してください", "input": "", "output": "プログラミングとは、コンピューターに指示を与えることです。"}
{"instruction": "好きな食べ物は？", "input": "", "output": "私は寿司が好きです！"}
```
このファイルを `data/custom_train.jsonl` として保存：
```bash
mkdir -p data
nano data/custom_train.jsonl
```

---

## **🔹 ステップ 3: DeepSeek-R1 をファインチューニング**
データセットが準備できたら、**LoRA** を使って **DeepSeek-R1** をファインチューニングしましょう。

### **1️⃣ ファインチューニングスクリプトを実行**
以下のコマンドでトレーニングを開始：
```bash
CUDA_VISIBLE_DEVICES=0 python src/train.py \
    --model_name_or_path deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B \
    --dataset data/custom_train.jsonl \
    --template deepseek \
    --cutoff_len 512 \
    --output_dir output \
    --num_train_epochs 3 \
    --per_device_train_batch_size 4 \
    --gradient_accumulation_steps 4 \
    --learning_rate 2e-4 \
    --logging_steps 10 \
    --save_steps 100 \
    --save_total_limit 2 \
    --bf16 True \
    --do_train \
    --finetuning_type lora \
    --lora_rank 8 \
    --lora_alpha 32 \
    --evaluation_strategy "no" \
    --cache_dir /mnt/data/huggingface_cache \
    --overwrite_output_dir
```

---

## **🔹 ステップ 4: ファインチューニングしたモデルをテスト**
ファインチューニング完了後、以下のコマンドでモデルをテスト：
```bash
python src/test_model.py --model_dir output --test_prompt "おすすめの本を教えて"
```
モデルが適切にファインチューニングされていれば、データセットに基づいた応答が返ってきます。

---

## **🔹 ステップ 5: ファインチューニングしたモデルをデプロイ**
**Ollama** でファインチューニング済みモデルを使用する場合：
```bash
ollama create deepseek-custom output
```
その後、以下のコマンドで実行：
```bash
ollama run deepseek-custom
```
これでファインチューニング済みのモデルが動作するようになります！ 🎉

---
LLVM-ET-Arm-19.1.5-Darwin-universalをmacOSで使う

LLVM Embedded Toolchain for ArmをMacbook Pro (Apple M3 Pro)にインストールしたメモ。

## インストール
ここからリリース版をダウンロードする。
https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases

ダウンロードしたファイル
LLVM-ET-Arm-19.1.5-Darwin-universal.dmg

ダブルクリックすると、以下のようなウィンドウが出来るので、Applicationsフォルダにコピーする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75582/7cdd0fe1-2698-16f9-0c83-ad1d58beddbb.png)

### ターミナルを開く
PATHを通して、バージョンを確認する。

```bash
$ export PATH=/Applications/LLVM-ET-Arm-19.1.5-Darwin-universal/bin:$PATH
$ clang --version
clang version 19.1.5
Target: aarch64-unknown-linux-gnu
Thread model: posix
InstalledDir: /Applications/LLVM-ET-Arm-19.1.5-Darwin-universal/bin
```

QEMUをインストールする
```bash
$ brew install qemu
```

## サンプルプログラムのビルドと実行

サンプルプログラム（baremetal-semihosting）をビルドする
```bash
$ cd /Applications/LLVM-ET-Arm-19.1.5-Darwin-universal/samples/src/baremetal-semihosting
$ make
../../../bin/clang --target=armv6m-none-eabi -march=armv6m -mfpu=none -mfloat-abi=soft -lcrt0-semihost -lsemihost -g -T ../../ldscripts/microbit.ld -o hello.elf hello.c
```

ファイルを確認する。
```bash
$ file hello.elf
hello.elf: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, with debug_info, not stripped
```

プログラムを実行する
```bash
$ make run
qemu-system-arm -M microbit -semihosting -nographic -device loader,file=hello.hex
Hello World!
```

以上です。
AWSでサーバー構築②　～DBサーバー構築～


# AWSでサーバーを構築するには　～DBサーバー構築～

前回の記事はこちら→[AWSでサーバーを構築するには](https://qiita.com/futeiki_kcm/items/ed15a6456c3b99e90f54)

上記記事ではWebサーバーを作っている状態なため、その手順を踏んでると仮定してDBサーバーの作り方についての手順について記載していきます。

## ①プライベートサブネットを作成

パブリックサブネットと同じVPCに、DBサーバー専用のプライベートサブネットを作成する。

## ②セキュリティグループの設定

セキュリティグループを作成より、Webサーバーのグループとは別にDBサーバー用のグループを作成する。
インバウンドルールでタイプをmysqlなど作成したいDBのエンジンを作成する。
その際ソースとして、Webサーバーのセキュリティグループを指定するようにする。

## ③RDSでデータベースの作成

作成したいエンジンのタイプを選択し、認証情報のマスターユーザーはrootで行う。（勉強用の場合）

パスワードを自分で作成しても自動生成しても問題ないが、自動生成した場合はデータベース作成後詳細情報よりマスターパスワードを確認して何かに控えておくこと。

:::note warn
控え忘れた場合は、データベースを選択し、変更から再度自動生成にチェックをつけ、続行したあとマスターパスワードの新しい値を確認する必要あり
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3763202/7a4a22f3-394e-e7eb-2213-89b2c3b9f2b7.png)

## ④EC2インスタンスからDB接続

インスタンスを起動したあとに下記のように接続。

```
ssh -i ~/.ssh/作成したキー.pem ec2-user@パブリックIPアドレス
```

EC2インスタンスにSSH接続後、DBのインストールを行う。（例ではmysql）

```
sudo yum -y install mysql
```

インストール完了したら、RDSの接続したい識別子のエンドポイントと、マスターユーザーで設定したrootをもってmysqlにログインする。

```
mysql -h [データベースのエンドポイント] -u root -p
```

正しいPWを入力し、下記のような表示になると問題なく入れている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3763202/7184514d-ae76-9f52-eb06-89fdaeb2bb3e.png)

:::note warn
もし入れなかった場合は、下記のような観点でもう一度確認しなおすこと
- DBが利用可能になっているか
- セキュリティグループの設定が正しいか
- mysqlからの接続が許可されているか
:::

## まとめ

__①プライベートサブネットを作成__
パブリックサブネットと同じVPCに、DBサーバー専用のプライベートサブネットを作成し、セキュリティ強化のためネットワークを分離する。

__②セキュリティグループの設定__
Webサーバーのグループとは別にDBサーバー用のグループを作成する。
ソースとしてはWebサーバーのセキュリティグループを指定。

__③RDSでデータベースの作成__
RDSで作成したいエンジンのデータベースを作成する。
パスワードの控え忘れに注意。

__④EC2インスタンスからDB接続__
Webサーバーに接続してから必要なDBのインストールを行う。
RDSエンドポイントを使用してDBサーバーにログインして接続確認。
MicrosoftホステッドエージェントからManaged DevOps Pool(MDP)へ乗り換える

## MDP(Managed DevOps Pool)とは？
MDPはAzure DevOpsのエージェントプールの管理を簡単にするフルマネージドサービスです。
特徴として以下のような点が挙げられます。
- 簡単なセットアップ
Azure Portalでリソースを作成することができます。
- 高いスケーラビリティ
スケーリングポリシーやスタンバイポリシーを柔軟に設定することができ、開発時の時間短縮、コスト削減を図ることができます。
- 仮想ネットワークとの統合
ホステッドエージェントではこれまでできなかった仮想ネットワークとの接続ができます。これにより、他のAzureリソースとの接続が柔軟になります。
- キャッシュ利用
エージェントが立ち上がっている間はキャッシュの利用が可能です。これにより二回目以降のDevOpsパイプラインの動作が高速になります。

## なぜMDPに乗り換えるのか
これまでホステッドエージェント一台を契約してAzure DevOpsを利用していました。
ところがエージェント一台では、順番待ちが発生することもあり開発効率が悪い状況でした。
そこでエージェントを追加しようという話になったのですが、ちょうどMDPがGAになったということで、こちらのほうがお安く済むかも？となり採用に至りました。

## MDPを作成する
手順は以下のような流れでした。
1. リソースグループを作成（既存のものでもOK）
1. Dev Centerを作成（既存の物でもOK）
1. 仮想ネットワークを作成（既存のものでもOK）
1. MDPを作成する
[公式ドキュメント](https://learn.microsoft.com/ja-jp/azure/devops/managed-devops-pools/configure-pool-settings?view=azure-devops&tabs=azure-portal)通りにやりました。MSにしては丁寧な説明があり、特に迷うことはありませんでした。
1. DevOpsパイプライン(yaml)を修正する

## 見落としがちなところ
### 仮想ネットワークの設定
MDPに対してサブネットの委任をする必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634883/7357ec36-4283-5a2c-e8e8-0bdfd2657549.png)
Azure Portal上ではサブネットの設定欄に当該項目があるので、「**Microsoft.DevOpsInfrastructure/pools**」を選択します。

### 既存パイプラインの修正
既存のパイプラインにてMDPを使用する際はvmイメージの指定方法に注意して下さい。
MDPではvmイメージの指定をしない場合、その時立ち上がっているエージェントのイメージでパイプラインが稼働します。
使用したいイメージ(OS)が決まっている場合は明示的に書く必要があります。
```yaml
# ホステッドエージェントの場合
pool:
    vmImage: 'windows-latest'

# MDPの場合
pool:
    name: 'MDP-001' # MDPのリソース名です
    demands:
      - ImageOverride -equals windows-2022 #イメージ名はエイリアスの使用ができます
```
VMイメージのエイリアスはAzure PortalのMDPの画面から設定できます。

## コスト予想
ホステッドエージェントを二台契約したときと、MDPで並列ジョブを4つ購入した時の机上コストを以下に掲載します。MDPのVM料金は従量課金制です。サイズはD2ads-v5で、月に100時間の稼働をしたと仮定しています。
|エージェント|並列ジョブ数|並列ジョブ料金（円）|VM料金（円）|合計|
|----|----|----|----|----|
|ホステッド|2|12,604|0|12,604|
|MDP|4|7,090|3560|10,650|

MDPはスタンバイ中も課金が発生しますが、スタンバイ時間を開発が盛んな曜日や時間帯に絞ることで大幅に料金を節約できそうです。
もともとエージェントを1台追加する予定でしたが、並列ジョブを4にしてもエージェント2台よりも安くなりそうなので期待大です。
(ジョブを並列で動かすことにお金がかかる仕組みなんとかならんかなぁ……二重課税みたい……）
AIで360度動画編集を簡単に！VR動画制作の新時代！

はじめに
VR（バーチャルリアリティ）技術の発展により、360度動画の需要が急速に高まっています。
観光業、不動産、教育、エンターテインメントなど、さまざまな分野で没入感のある映像体験が求められるようになりました。
しかし、360度動画の編集には高い技術が必要であり、映像のスティッチング（複数カメラの映像を合成する作業）や手ぶれ補正、適切な視点調整など、多くの時間と労力がかかるのが課題でした。
そこで注目されているのが、AIを活用した360度動画編集です。
AI技術を活用すれば、スティッチングや手ぶれ補正、エフェクト追加などの複雑な作業を短時間で自動化できるため、初心者でも高品質なVR映像を簡単に制作できます。
本記事では、AIを活用した360度動画編集の方法や、おすすめの編集ツールについて詳しく解説します。

360度動画編集におけるAIのメリット
①	 自動スティッチングで編集時間を大幅短縮
360度カメラは複数のレンズを使用するため、撮影後にそれぞれの映像をつなぎ合わせるスティッチングが必要になります。
これを手作業で行うと、映像の継ぎ目を目立たなくするための微調整に膨大な時間がかかります。
しかし、AIを活用したスティッチングツールを使えば、映像のズレや歪みを自動で補正し、自然な360度映像を簡単に作成できます。
✅ おすすめツール
	Mistika VR（高精度なAIスティッチング機能）
	Insta360 Studio（AIによる自動補正機能付き）

②	 AI手ブレ補正でスムーズな映像に
360度動画は、視聴者が好きな方向を見られるため、少しの手ブレでも映像酔いの原因になります。
そのため、滑らかで安定した映像が重要です。
そこでAIを活用した手ブレ補正機能を使えば、カメラの動きを自動で解析し、スムーズな映像に変換できます。
特にアクションカメラで撮影した360度動画では、AI手ブレ補正が必須です。
✅ おすすめツール
	Adobe Premiere Pro（ワープスタビライザー搭載）
	DaVinci Resolve（Neural EngineによるAI手ブレ補正）

③ AIで視点移動を最適化し、自然な映像を作成
360度動画では、視点の移動（パンやティルト）を適切に調整しないと、映像が不自然な動きになり、視聴者にストレスを与える可能性があります。
そこでAIを活用すれば、視点の移動を自動で最適化し、自然で見やすい360度映像に仕上げることができます。
✅ おすすめツール
	GoPro Player（AIが自動で最適な視点移動を調整）
	Insta360 FlowState（AIによるスムーズな視点制御）

AIを活用した360度動画編集の手順
①	360度カメラで撮影する
まず、適切な360度カメラを選び、高解像度（4K以上）で撮影します。
✅ おすすめカメラ：Insta360 ONE X2、GoPro MAX
②	AIスティッチングで映像を結合
撮影した映像をAIスティッチングツールに取り込み、カメラ間の継ぎ目を自動補正します。
③	AI手ブレ補正＆色補正
ワープスタビライザーやAIカラーマッチングを活用し、プロフェッショナルな仕上がりにしましょう。
④	AIエフェクト＆字幕追加
VR用のエフェクトを適用し、視聴者にとって魅力的な映像に仕上げていきます。
字幕も360度動画に適した配置で追加しましょう。
⑤	書き出し＆プラットフォームアップロード
YouTube VRやMeta Questに最適なフォーマットで書き出し、編集した動画を視聴者に届けましょう。

AIを活用したおすすめの360度動画編集ツール
ツール名	主な機能	対応OS
Adobe Premiere Pro	AI手ブレ補正、360度動画編集ツール搭載	Windows/Mac
DaVinci Resolve	AIカラー補正、高精度スタビライザー	Windows/Mac
Insta360 Studio	AIスティッチング＆視点補正機能	Windows/Mac
Mistika VR	高精度なAIスティッチング機能	Windows/Mac

360度動画の活用例
①	YouTube VRコンテンツ
YouTubeはVR動画をサポートしており、360度動画をアップロードすると、視聴者が自由に視点を変更できます。
没入感のあるコンテンツを提供できるため、エンタメ業界や教育分野での活用が増えています。
②	不動産＆観光業のバーチャルツアー
また、不動産の内覧や観光地のバーチャルツアーに360度動画を活用する企業も増えています。
AI編集を活用することで、短時間で高品質なプロモーション動画を作成できます。
③	eラーニング＆教育コンテンツ
360度動画は教育分野でも活用されており、歴史的な遺跡のバーチャルツアーや科学実験のシミュレーションなど、インタラクティブな学習体験を提供できます。

まとめ
AIを活用すれば、360度動画のスティッチング・手ぶれ補正・視点調整を自動化することができます。
また、従来の編集よりも圧倒的に短時間でプロレベルの仕上がりにすることも可能です。
また、VR動画市場の拡大に伴い、360度動画は今後さらに需要が増える分野でもあります。
これから360度動画の編集に挑戦したい方は、AI編集ツールを活用して、手軽に高品質なVR映像を作成してみてください！
スマホアプリ基礎知識（開発者向け）

【プッシュプロビジョニングプロファイル】
スマホアプリの開発に必要な証明書とキーが1セット入っているもの
【開発者証明書】
スマホアプリの開発に必要なアップルから発行された証明書が入っている
【UDID】
アップルの端末を識別するための、コードが格納されている証明書の一覧のようなもの
【p12ファイル】
証明書を作成するもととなるファイルを指している
※上記ファイルは全て有効期限があり、基本的には一年間となっている
Autonomous DatabaseのインスタンスをUndelete Database(削除取消)してみる

# はじめに
この記事では、Autonomous Databaseの2024/9に発表された機能「Undelete Database」をご紹介します。
ECPUコンピュートモデルにおいて、終了したAutonomous Databaseインスタンスの削除を取り消すオプションが追加されました。
データベースの削除を解除できるのは、データベースが終了してから72時間後まで、およびバックアップ保持期間のいずれか短い方までとなります。 データベースを終了してから3日（72時間）以上経過すると、削除を取り消すことはできません。

マニュアルは[こちら](https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/autonomous-undelete.html#GUID-456A0AAD-F841-4983-BF6A-980C4BF8A4B6)です。


# Undelete Databaseを試す

*  まず、使用可能なADBインスタンスの詳細画面内の「More Actions」から、「終了」を選択して、インスタンスを削除します。
 ![画像1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3058002/5e5d8148-38d9-fbe1-1392-ff5d32fa7e36.png)
* 終了の作業が完了するのを待ちます。
    ![画像1.5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3058002/af155e98-a4d0-5921-6a72-917f98047f58.png)

* 終了ができたら、コンソール画面上に「データベースの削除取消」をするかどうかの表示が出てきます。
![画像2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3058002/98f9fabf-20c8-4f19-c762-09e702b8f86b.png)

* データベースの削除取消をクリックします。
* インスタンスのステータスが「プロビジョニング中」となり、削除取り消しを実行しています。
    ![画像4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3058002/2de262f9-21a7-ba10-f664-566e73ff5113.png)

* しばらくすると、削除取消の作業が完了します。ステータスが「使用可能」に戻ります。
    ![画像5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3058002/3fc4a983-aaf0-6e1f-2518-15a523e2be94.png)

* 削除取消を実行することで、誤ってインスタンスを終了してしまったとしても、72時間以内であればインスタンスを使用可能に戻すことができます。

:::note warn
注意
インスタンスを一時的に使用しない場合には、稼働しない時間帯はインスタンスを``終了``ではなく、``停止``するようにしてください。インスタンスが停止している場合は、インスタンスが稼働している時と同様、データベースに格納されているストレージの料金は課金されます。
:::
個人開発を始めてみる

# 個人開発を始めてみる

## はじめに

こんにちは！最近、個人開発に挑戦しようと思い立ち、夢を形にするために「DreamTracker」というアプリを開発しています。このアプリは、人生のやりたいことリスト（バケットリスト）を作成・管理できるサービスです。今回は、この個人開発を始めるにあたっての過程や、開発のスタート地点を紹介しようと思います。

---

## 目標

DreamTrackerの目標は、「人生のやりたいことを可視化し、進捗を管理する」というシンプルなものです。ユーザーは自分の目標をリストにして、その進捗を可視化できます。さらに、他のユーザーと目標を共有したり、AIが提案してくれる機能も実装予定です。

---

## 開発のきっかけ

私は、普段から自分の目標をリスト化することが好きですが、いざ実行に移すとなるとどうしても時間が経つにつれてそのリストは放置されがちです。そこで、「自分の目標をもっと楽しく管理できる方法はないか？」と考えたのが、DreamTrackerのアイデアのきっかけです。

また、最近AI技術が注目されている中で、やりたいことを思い付かないユーザーに対してAIによる目標提案機能を実装することで、さらに魅力的なサービスにできると感じました。

---

## 使う技術スタック

- **フロントエンド**: React
- **バックエンド**: Laravel（API） + Firebase（認証）
- **データベース**: PostgreSQL（Supabase）
- **使用するAPI / ライブラリ**:
    - Firebase Authentication（ユーザー認証）
    - OpenAI API（AIによる目標提案）
    - Heroicons（UIアイコン）

Reactでフロントエンドを作り、バックエンドはLaravelを使ってAPIを提供します。認証はFirebaseで簡単に実装し、データベースにはPostgreSQLを使用しています。AIの提案機能にはOpenAIのAPIを利用予定です。

---

## MVP（最小限の実用的な製品）として実装する機能

最初にリリースするMVPは、以下の機能を中心に構築していきます。

1. **ユーザー認証**: Firebase Authenticationを使用して、簡単にログイン・サインアップ機能を実装
2. **バケットリスト管理**: やりたいことリストを作成し、進捗を管理
3. **AI提案機能**: OpenAIを使って、やりたいことを思い付かないユーザーに対して目標提案
4. **他ユーザーとの共有機能**: ユーザー同士で目標をシェアして、互いに刺激し合える機能

---

## 開発の進捗

現在、プロジェクトの準備段階として、GitHubでリポジトリを作成し、開発環境を整えました。フロントエンドはReactで、バックエンドはLaravelを使う予定ですが、まだ初期設定が完了した段階です。

---

## 今後の展望

DreamTrackerのMVPが完成したら、さらに多機能を追加していく予定です。例えば、タイムライン機能や、リストアイテムに対する「いいね」機能などを実装することで、より多くのユーザーが使いやすいサービスにしたいと考えています。

---

## 最後に

個人開発は本当に大変ですが、やりがいも非常に大きいです。自分のアイデアを形にする過程で得られる学びや経験は、今後のキャリアにも大きな影響を与えると思っています。DreamTrackerの開発が順調に進めば、ぜひ多くの人に使ってもらいたいと思います。

この記事が、これから個人開発を始める方にとって参考になれば嬉しいです！
python演習問題

## はじめに
この記事は[こちら](https://qiita.com/itijuku/items/b2b86ad8ff0fdaf1c04f)の記事と一緒に使うようです。

### 用語の意味一覧
【出力】printでデータを表示させること

## 1-1(print)
### catという文字を出力

目標とする出力結果
```
cat
```

## 2-1(演算)
### 5+5*5の計算を出力
目標とする出力結果
```
30
```

## 3-1(変数)
### varという変数に10を入れ、それに5を足したものを出力
目標とする出力結果
```
15
```

## 3-2(変数)
### var1という変数に5を入れ、var2という変数に15を入れ、var1とvar2を掛け算した結果を出力
目標とする出力結果
```
75
```

## 4-1(入力)
### 入力したデータを取得して表示
目標とする出力結果
```
入力したデータ
```
Databricks認定資格 Databricks Certified Data Analyst Associate 受験感想/合格体験記

:::note info
何か知りたいことがあれば、コメントいただければ、可能な範囲でお答えいたします。
ぜひお声がけください。
:::

### 試験に使えそうな資材
- 公式のAcademyTraining
- UdemyでもYoutubeでも、自分に合ったものであればOK
- Qitta記事（下記おすすめ）

https://qiita.com/nttd-saitouyun/items/b056f5f98bd1a705a7b2

https://qiita.com/nakazax/items/1bef5af7a53220d09b20

### オンライン受験について　→　テストセンターで受験した
- テストセンターでの受験が可能になったので（BIG THANKS:sunny:）、テストセンターで受験した
    - 身分証明書が２点必要
    - 予約メールで案内された認証コードが必要（メールに重要事項として記載あり）
    - 試験中にメモ用具の提供はなかった
- 現時点（25.01）では、公式ページにはオンライン受験のみと記載されているが、予約サイトではテストセンター受験の選択が可能となっている

### 受験感想
- 受験時点では試験言語は英語のみだったので、英語で受験した
- 試験時間については、慣れない外国語で受験しても十分な余裕があった
    - 言語の壁がある分、じっくり問題を読むことができた
    - 受験画面右下に言語切り替えの選択肢のようなものが表示されていたが、機能していなかった
- 試験内容については、Qittaの記事がかなり参考になった
- １ヶ月もあれば、合格するための勉強が十分にできるでしょう

### 参考情報
https://qiita.com/nttd-saitouyun/items/e7d1ca77e23b8e635518

https://qiita.com/ikejiri-makoto2/items/093dfb52d4d19904d1de#data-analyst-associate
MySQLが文字化けするときの対処

MySQLで文字化けしてしまったときの対処方です。
1. クライアント側、サーバー側（mysqlサーバー）、及びそれらの接続の文字コード
2. データベース/テーブル/カラムの文字コード
の設定が必要です。

まずは現状を確認です。
```
show variables like "chara%";
```

```
[client]
default-character-set=cp932
・・・

[mysql]
default-character-set=utf8
・・・

[mysqldump]
default-character-set=utf8
・・・

[mysqld]
character-set-server=utf8
・・・
```

- **character_set_client**：クライアント側で発行したsql文はこの文字コードになる
- **character_set_connection**：クライアントから受け取った文字をこの文字コードへ変換する
- **character_set_database**：現在参照しているDBの文字コード
- **character_set_results**：クライアントへ送信する検索結果はこの文字コードになる
- **character_set_server**：DB作成時のデフォルトの文字コード
- **character_set_system**：システムの使用する文字セットで常にutf8が使用されている

基本的にはこれを全部（character_set_filesystem, character_sets_dir以外）utf-8にすれば大丈夫です。

```/etc/my.cnf
[mysqld]
...
character-set-server=utf8 #mysqldセクションの末尾に追加

[client]
default-character-set=utf8 #clientセクションを追加
```

設定が終わったら、再起動。
```
/etc/init.d/mysqld restart
```

確認します。
```
show variables like "chara%";
```
```
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       | #utf8にok!
| character_set_connection | utf8                       | #utf8にok!
| character_set_database   | utf8                       | #utf8にok!
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
```
LINE Messaging API

# LINE Messaging APIを使用したPythonメッセージ送信スクリプト

## 概要
このスクリプトは、LINE Messaging APIを使用してPythonからLINEにメッセージを送信する方法を示します。

## コード

```python
import requests
import json

##############
###LINE BOT###
##############

line_access_token = 'YOUR_ACCESS_TOKEN_HERE'
line_id = 'YOUR_LINE_ID_HERE'  # ユーザーIDまたはグループID

def send_line_message(access_token, line_id, message):
    """
    LINE Messaging APIを使用してメッセージを送信する関数

    Parameters:
        access_token (str): LINE Botのアクセストークン
        line_id (str): 送信先のユーザーIDまたはグループID
        message (str): 送信するメッセージ
    """
    url = 'https://api.line.me/v2/bot/message/push'

    # ヘッダーにアクセストークンを設定
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {access_token}'
    }

    # 送信するデータ（メッセージ内容と送信先ID）
    payload = {
        'to': line_id,
        'messages': [
            {
                'type': 'text',
                'text': message
            }
        ]
    }

    # POSTリクエストを送信
    response = requests.post(url, headers=headers, data=json.dumps(payload))

    # 結果を表示
    if response.status_code == 200:
        print("メッセージが正常に送信されました。")
    else:
        print(f"メッセージ送信に失敗しました。ステータスコード: {response.status_code}, 内容: {response.text}")

# 関数を呼び出してメッセージを送信
send_line_message(access_token=line_access_token, line_id=line_id, message="テストメッセージ")
```

## 解説

### 必要な準備
1. `requests`と`json`ライブラリをインストールする必要があります
2. LINE Developersコンソールからアクセストークンを取得

### 主な機能
- LINE Messaging APIを使用したメッセージ送信
- エラーハンドリング付きのメッセージ送信関数

### 注意点
- `line_access_token`は必ず非公開にしてください
- 送信先の`line_id`は正確に設定してください

## 使用上の注意
- LINE Messaging APIの利用規約を遵守してください
- 個人情報の取り扱いには十分注意してください
プリザンターにTOTP（Time-based One-Time Password）認証機能を実装いたしました

# はじめに
2024年、3/12 リリース(ver.1.4.2.0)にて、当社でTOTP（Time-based One-Time Password）認証機能を実装いたしました。今更ではありますが、簡単に機能のご紹介をさせていただこうと思います。

# TOTPとは？
TOTPはワンタイムパスワードの一種で、最初にサービス側とユーザ側の専用のアプリなどで暗号生成用のコードを共有しておき、そのコードを元に時間から共通のコードを生成し、認証します。
代表的なアプリにはGoole Authenticatorや、Microsoft. Authenticatorがあります。

# 何のために追加したか
プリザンター旧来の2段階認証では、メール認証しか使えませんでした。
これはネットワークに繋がっていないローカル環境などでは使用できません。対してTOTPでは、認証に別のアプリかデバイスが必要になりますが、性質上通信を必要としないため、多くの環境で利用することができます。
また、TOTPではワンタイムパスワードの発行に通信が発生しないため、(生成用のコードが漏洩しない限り)通信の傍受などで盗み取られる危険性は低くなります。
最近ではTOTP認証を採用しているサービスも多いので、ユーザーにとってもなじみがあり、導入もしやすいのではないかと思います。

# 実装について
Totpが有効化されている場合は既存の2段階認証と分岐する形で、MIT Licenseで公開されているOtp.NETプラグインを利用して認証するように実装いたしました。

# 使い方と各種パラメータ
#### 有効化手順
- Security.jsonのSecondaryAuthenticationパラメータを以下の通り変更
    - ModeをDefaultEnableに設定
    - NotificationTypeをTotpに設定
```
"SecondaryAuthentication": {
    "Mode": "DefaultEnable",
    "NotificationType": "Totp",
    "CountTolerances": 1,
    "NotificationMailBcc": false,
    "AuthenticationCodeCharacterType": "Number",
    "AuthenticationCodeLength": 8,
    "AuthenticationCodeExpirationPeriod": 300
},
```
#### 初回登録
- TOTP有効化後の初回ログイン時に表示されるQRコードを読み取り、認証アプリに登録する
- 表示されるコードを入力してログインする
    - 初回は認証アプリに登録後、ログインするとコードが登録されます
    - ログインせずアプリに登録だけ行った場合、暗号コードが保存されないため再度登録し直す必要があります

#### 登録解除(コードリセット)
- ユーザ管理から、解除したいユーザの「秘密鍵有効」チェックを外す
    - 現在登録されている暗号コードが無効化され、再度初回登録画面が表示されるようになります

#### 変更できるオプション
- 上記パラメータのCountTolerancesを変更すると、指定した回数分古いコードで認証できるようになります
    - デフォルトの1では、現在表示されているパスワードと1つ前のパスワードでログインができます
    - たとえば2に設定すると、現在表示されているパスワードから2つ前までのパスワードログインできるようになります
    - 0に設定した場合、現在表示されているパスワードのみでログインできます

# まとめ
2段階認証にTotpを追加したことで、手軽にセキュリティの強化ができるようになりました。
Githubなどにも採用されている認証方法なので、普段から利用されている方は特に始めやすく、ローカルでご利用の方や個人など、どのような環境でも使いやすくなっていると思いますので、ぜひ使ってみて頂きたいと思います。
【テスト技法】ディシジョンテーブル

# はじめに
こんにちは。アメリカで独学でエンジニアを目指している者です。
現在はRailsを勉強しているのですが、並行してソフトウェアテスト技法も学ぶことで、Railsチュートリアルの理解が深まるのではないかと考え、テスト技法の勉強を始めました。
今回学んだディシジョンテーブルについて、記憶が薄れないうちに簡単にまとめておきたいと思います。
ちなみに、テスト技法はUdemyで勉強しています。とても分かりやすいので、テスト技法を勉強したいと思う方はぜひ見てみてください。

https://www.udemy.com/share/102NaE3@Klm5Y802jzOOWemmUmgcZKwsmg5ZeKSLdssOdLltCQUeMwrYsLoBehQBwhoefOb3yw==/

## ディシジョンテーブル
ディシジョンテーブルとは、条件同士は独立していて、込み入った論理関係を整理する場合に使用されます。
ドメイン分析テストは複数の条件が**数式で結ばれている**場合に有効だったのに対し、ディシジョンテーブルは複数の条件が**論理式で結ばれている**場合に使用します。

例えば、ネットショッピングの注文処理を考えてみましょう。

### 例: ネットショッピングの注文処理

以下の条件があるとします。

1. ユーザーが会員である
2. クーポンを持っている
3. 在庫がある

この場合、注文が確定するかどうかは、これらの条件の組み合わせによって決まります。
ディシジョンテーブルを使うことで、すべての条件の組み合わせとその結果を明確に整理できます。

| 条件           | ルール1 | ルール2 | ルール3 | ルール4 | ルール5 | ルール6 | ルール7 | ルール8 |
|--------------|-------|-------|-------|-------|-------|-------|-------|-------|
| 会員か？      | ○     | ○     | ○     | ○     | ×     | ×     | ×     | ×     |
| クーポンあり？ | ○     | ○     | ×     | ×     | ○     | ○     | ×     | ×     |
| 在庫あり？     | ○     | ×     | ○     | ×     | ○     | ×     | ○     | ×     |
| 結果（注文可否） | ○     | ×     | ○     | ×     | ○     | ×     | ×     | ×     |

この表を見ると、
- 在庫がない場合は、会員やクーポンの有無に関係なく注文できない
- 在庫がある場合は、非会員の場合はクーポンの有無に関係なく注文できない
- 在庫があり、かつ会員ならばクーポンの有無に関係なく注文できる

というルールが明確になります。

また、注文の可否についてだけ見ればよいのであれば在庫の有無が関係してきているので以下のように、テストケースを圧縮することができます

| 条件           | ルール1 | ルール2 | ルール3 | ルール4 | ルール5 | 
| -------------- | ------- | ------- | ------- | ------- | ------- | 
| 在庫あり？     | 〇      | 〇      | 〇      | 〇      | ×       | 
| 会員か？       | 〇      | 〇      | ×       | ×       | ー      | 
| クーポンあり？ | 〇      | ×       | 〇      | ×       | ー      | 
| 結果(注文可否) | 〇      | 〇      | 〇      | 〇      | ー      | 

在庫がなければ、注文はできないので在庫がある場合でそれぞれテストすることで網羅することが可能です。


## ディシジョンテーブルの作成手順

ディシジョンテーブルを作成する際の基本的な手順は以下の通りです。

1. **条件をリストアップする**
   - システムの動作に影響を与えるすべての条件を洗い出します。
   
2. **条件の組み合わせを網羅する**
   - すべての条件の真（○）と偽（×）の組み合わせを列挙します。
   
3. **結果を定義する**
   - 各条件の組み合わせに対するシステムの挙動（結果）を定義します。
   
4. **冗長なルールを統合する（必要に応じて）**
   - 明らかに不要なルールを統合することで、テーブルを簡潔にできます。

## ディシジョンテーブルのメリット

ディシジョンテーブルを活用することで、以下のようなメリットがあります。

- **条件の組み合わせを網羅できる**: 人間が見落としやすい組み合わせも明確にできる。
- **仕様の整理がしやすい**: システムの動作を視覚的に整理できるため、仕様の矛盾を発見しやすくなる。
- **テストケースの設計がしやすい**: 条件ごとのテストパターンを明確にできるため、漏れのないテスト設計が可能。

## まとめ

ディシジョンテーブルは、複数の条件が論理式で結ばれている場合に有効なテスト技法です。
特に、条件が複雑で人間の頭では整理しにくい場面において、テストケースの抜け漏れを防ぐのに役立ちます。
【HTML】HTMLの基本構造について改めて勉強してみた①～DOCTYPE宣言~

# 目的
HTMLの骨組みについて、その役割や意味・背景などの基礎知識を理解すること。
# 基本構造
※VSCode（コードエディタ）であれば、```!```キー＋```Enter```キー押下で下記の最低限の骨組みが
　 補完されます。
```HTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>
```
１行目の```<!DOCTYPE html>```から順に確認してきます。
# １行目：DOCTYPE宣言
## DOCTYPEとは
HTML文書の先頭に記述する文書型宣言のことです。
これを記述することで、ブラウザに対し、このHTMLファイルが古いHTML文書でないことを
示します。小文字で記載しても問題なく動作します。
### 古いHTML文書とは
古いHTML（バージョン4.01以前）はSGML（HTMLの元にである言語）が利用されており、
以下のように文書の先頭でDTD（文書のルール）を参照する記述が必要でした。
```HTML
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01//EN” “http://www.w3.org/TR/html4/strict.dtd”>
```
HTML5以降はSGMLを利用していないため、上記宣言は不要となりました。
しかし、ブラウザは互換性モードかどうかをこの宣言内容により判定しています。
文書型宣言の記述がないと互換性モードと解釈されますが、これを避けるために
DOCTYPE宣言が必要となりました。
### ブラウザの解釈モード（レンダリングモード）について
以下の３種類があります。
現在ほとんどのブラウザが③完全標準準拠モードの利用を推奨しています。
**① 後方互換 (Quirks) モード**
　古いHTMLを正しく表示するモード。現在の標準的なHTML・CSSルールを無視して、
　古いブラウザの挙動を再現する。
**② 準標準 (Almost Standards) モード**
　基本的には標準ルールで表示するが、古いブラウザとの互換性のため
　一部例外があるモード。
**③ 完全標準準拠 (Full Standards) モード ◀推奨**
　最新の標準的なHTML・CSSの仕様通りに解釈・動作するモード。

※ブラウザの表示方法（レンダリングモード）では、以下のような内容が
　切り替えられます。
　・レイアウトの計算方法（ボックスモデル・table・imgのサイズの計算方法）
　・適用するCSSルール（最新仕様または古いブラウザ向けのルールか）
　・ブラウザ互換性の確保（古いWebページ表示のために昔のブラウザの挙動を再現）

# 参考
https://www.borndigital.co.jp/book/25999/

https://www.tohoho-web.com/html/doctype.htm

https://www.tohoho-web.com/ex/dtd.htm

https://note.com/mitts543/n/naa91f5d0b46d

https://developer.mozilla.org/ja/docs/Web/HTML/Quirks_Mode_and_Standards_Mode

https://www.dspt.net/html_tag/mode.html
VBAでメール情報を取得する

Outlookにて、メールの新規作成 or 下書きをポップアップで開いるときに、
情報をチェックしたい。


```vb
Sub GetOpenMailInfo()
    Dim objInspector As Outlook.Inspector
    Dim objMail As Outlook.MailItem
    Dim recipients As Outlook.Recipients
    Dim recipient As Outlook.Recipient
    Dim attachment As Outlook.Attachment
    Dim recipientList As String
    Dim hasVoteButtons As Boolean
    Dim hasEncryption As Boolean

    ' 開いているメールアイテムを取得
    On Error Resume Next
    Set objInspector = Application.ActiveInspector
    If objInspector Is Nothing Then
        MsgBox "開いているメールがありません。"
        Exit Sub
    End If
    
    If objInspector.CurrentItem.Class = olMail Then
        Set objMail = objInspector.CurrentItem
    Else
        MsgBox "メールアイテムではありません。"
        Exit Sub
    End If
    On Error GoTo 0
    
    ' 差出人
    Dim sender As String
    If Not objMail.Sender Is Nothing Then
        sender = objMail.Sender.DisplayName
    Else
        sender = "情報なし"
    End If
    
    ' To, CC, BCC
    Set recipients = objMail.Recipients
    Dim toList As String, ccList As String, bccList As String
    toList = ""
    ccList = ""
    bccList = ""
    
    For Each recipient In recipients
        Select Case recipient.Type
            Case olTo
                toList = toList & recipient.Name & "; "
            Case olCC
                ccList = ccList & recipient.Name & "; "
            Case olBCC
                bccList = bccList & recipient.Name & "; "
        End Select
    Next recipient
    
    ' メール形式
    Dim format As String
    Select Case objMail.BodyFormat
        Case olFormatHTML
            format = "HTML"
        Case olFormatPlain
            format = "Plain Text"
        Case olFormatRichText
            format = "Rich Text"
        Case Else
            format = "Unknown"
    End Select
    
    ' 投票ボタンの有無
    hasVoteButtons = Not IsEmpty(objMail.VotingOptions)
    
    ' 暗号化の有無
    hasEncryption = objMail.Sensitivity = olConfidential
    
    ' 返信先設定
    Dim replyTo As String
    replyTo = objMail.ReplyRecipientNames
    
    ' 添付ファイルの有無
    Dim hasAttachments As Boolean
    hasAttachments = objMail.Attachments.Count > 0
    
    ' 結果を表示
    MsgBox "差出人: " & sender & vbCrLf & _
           "TO: " & toList & vbCrLf & _
           "CC: " & ccList & vbCrLf & _
           "BCC: " & bccList & vbCrLf & _
           "形式: " & format & vbCrLf & _
           "投票ボタン: " & IIf(hasVoteButtons, "あり", "なし") & vbCrLf & _
           "暗号化: " & IIf(hasEncryption, "あり", "なし") & vbCrLf & _
           "返信先: " & replyTo & vbCrLf & _
           "添付ファイル: " & IIf(hasAttachments, "あり", "なし")
End Sub

```
OutSystemsでDataGrid、Tableどちらを使うか

# はじめに
OutSystemsでのデータの一覧表示といえば、Table Widget(TraditionalでのTable Records)またはForgeコンポーネントのOutSystems Data Gridかと思います。
どちらを使うのが無難なのか、両方の開発を経験してみて感じたことをまとめてみようと思います。

## 前提
- OutSystems 11
- Reactive Web
- OutSystems Data Grid (version 2.18.1)

## Table Widget
OutSystems標準のUI。基本は表示のみでTableだけでは一覧形式の入力には対応していませんが、他のInput Widget等と組み合わせることで実現可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239988/f4c38e48-2c1a-6e72-ebcc-953e2e881def.png)

他のシステムUIと組み合わせることできるのが、実はこのTable Widgetの強みではないかと思います。

### メリット
- デザインの調整は基本的にCSSで対応可能
- WebBlockをTableのセル内に埋め込むことでわりと自由にカスタマイズできる
- JavaScriptが必要になるケースはあまりない
### デメリット
- ソート機能は自前で実装する必要あり(ただし、Aggregateへのソートキーの受け渡し程度)
- セル結合、ヘッダセル結合はできない
- 各セルの幅はパーセンテージやpxによる固定なので、操作しているユーザーが自由にいじることはできない

## DataGrid
OutSystemsチームが開発しているForgeであり、多くの現場で使用されているEXCELライクな入力ツールです。

https://www.outsystems.com/forge/component-overview/9764/outsystems-data-grid-o11

そして、DataGridのベースとなっているのは、Javascript開発ライブラリのWijmo(ウィジモ)に含まれているFlexGridというコンポーネントです。

こちらの記事でDataGridについて詳しく書かれているので是非ご覧ください。

https://qiita.com/sayamaguchi/items/997bcd2b4c8d24636296

### メリット
- 厳密なルールが不要であれば、ほぼお任せでソート機能がつけられる
- セル結合、ヘッダセル結合が可能
- 各列幅をユーザーが自由にいじることができる
- カスタマイズをあまりせずデータを一覧表示したいだけであれば、取得したデータをJSON化してDataGridに受け渡すだけなので実装スピードも速い
### デメリット
- カスタマイズをしたい場合、DataGridの標準機能にないものはJavaScriptで実装する必要がある
- 意外とDataGridの標準機能でできないことも多い(行の下に追加する動きとか)
- DataGridの情報が少ない

## DataGrid、正直情報が少ない
見栄えもいいし、よくできたツールなのですが如何せん情報が少ない・・・
以下が公開されているサンプルです。(このForgeもインストールすれば実装が確認できます)

https://outsystemsui.outsystems.com/OutSystemsDataGridSample/Overview

カスタマイズが必要になったら、Wijmoのオンラインドキュメントを参考にDataGridの標準機能にない機能を実装してみましょう。

https://docapp.mescius.jp/wijmo/api/Index.html

# 結論
特にDataGridを使う理由がないなら、Table Widget使っておいたほうが無難。
OutSystemsのローコードという性質上、コードが増えるのは好ましくないからです。
カスタマイズにJavaScriptが必須となるDataGridを採用するのは、それなりのリスクかなと考えます。
(JavaScript使わない範囲でやります！でもいいかなと思うけど、時折痒い所に手が届かない・・・)
採用するなら、要件上「DataGridでないと実現できない」機能に絞るのがベスト。
AWS MLA合格体験記

## はじめに
AWS Certified Machine Learning Engineer - Associate認定試験を受験してきました。
ALL Certs2025の申請条件が残りMLAのみでしたので、期限ギリギリになって焦ることがないように早めに受けておきました。(最悪落ちても何回か挑戦できる余裕をもちたい。。。)

## 前提
- 業務でAWS利用経験あり(2年いかないくらい)
- AIや機械学習の知識はほとんどない
- AWS認定試験は「MLA」以外はすべて取得済(詳細は[こちら](https://qiita.com/num-bx77/items/f629cc2e9f7616a62ccb))

## 使用教材・参考サイト

今回も新しい試験でしたので、教材選びが少し大変でした。

### 使用教材

[AWS Certified Machine Learning Engineer - Associate (MLA-C01)](https://d1.awsstatic.com/ja_JP/training-and-certification/docs-machine-learning-engineer-associate/AWS-Certified-Machine-Learning-Engineer-Associate_Exam-Guide.pdf)
➡試験ガイド

[Exam Prep Official Practice Question Set: AWS Certified Machine Learning Engineer - Associate (MLA-C01 - 日本語)](https://explore.skillbuilder.aws/learn/courses/19689/exam-prep-official-practice-question-set-aws-certified-machine-learning-engineer-associate-mla-c01-japanese)
➡公式サンプル問題

[Practice Exams: AWS Machine Learning Engineer Associate Cert](https://www.udemy.com/course/practice-exams-aws-certified-machine-learning-engineer-associate/?couponCode=V2JPLETSLEARN)
➡UdemyWeb問題集

### 参考サイト
[]()

[AWSの3つのAI・機械学習認定試験をこれから受ける人のためのガイド - プラクティショナー(AIF)/アソシエイト(MLA)/スペシャルティ(MLS)](https://dev.classmethod.jp/articles/how-to-pass-aws-certified-ai-ml/)

## 結果

無事合格できました！

![スクリーンショット 2025-01-31 152304.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3904291/27f44114-0813-2d7a-2354-51217b905f3f.png)



## 感想
機械学習系はAWS MLSを持ってはいたものの去年のはじめくらいに取ったのでほとんど記憶に残っていませんでした。そのため一から勉強するつもりでUdemy問題集を何回か周回して勉強していました。業務では扱うことがないサービスばかりが試験対象なので、どうしてもわかりづらい部分がありましたが、都度ChatGPTさんにも聞きながら勉強を進めていきました。
今回無事合格できたので[公式からお知らせ](https://aws.amazon.com/jp/blogs/psa/2025-japan-aws-all-certifications-engineers-criteria/)が出たら忘れずに申請を出したいと思います。

MLA試験自体とは無関係になりますが、今回初めて試験を受ける前に受付で「スマホの電源を落としたことを確認させください」と言われました。試験中にロッカーでスマホが鳴ることが多いんですかね。。。
dockerコマンドを叩いた時にCannot connect to the Docker daemon at unix:///Users/hoge/.docker/run/docker.sock. Is the docker daemon running?というエラーが出た時

## エラーの内容
例えば`docker compose up`などのコマンドを叩いた時に
`Cannot connect to the Docker daemon at unix:///Users/hoge/.docker/run/docker.sock. Is the docker daemon running?`
このエラーは、Dockerクライアント（コマンドラインツール）がDockerデーモン（バックグラウンドで動作するサービス）に接続できない時に発生することがあります。


## 結論

大体の場合はDocker Desktopが立ち上がっていない場合なので、
```
$ open -a docker
```
のコマンドを叩いてDocker Desktopを立ち上げると解消されます。
🎭 Playwright 環境構築（Windows）

## **📌 記事の内容**
- Playwright を使って **E2E（エンドツーエンド）テスト** を実行するための環境構築手順
- **Google検索のテスト** をサンプルに Playwright で自動テストの実行をしてみる

## **✅ 1. Playwright 環境構築**
### **1-1. Node.js のインストール**
1. [**Node.js公式サイト**](https://nodejs.org/) から **LTS版** をダウンロード
2. インストール後、バージョン確認**✅ `v18.x.x` や `v16.x.x` などが表示されればOK**
    ```bash
    node -v
    npm -v
    ```
---

### **1-2. Playwright のインストール**
### **① プロジェクトフォルダを作成**
```bash
mkdir my-playwright-project
cd my-playwright-project
npm init -y
```

### **② Playwright をインストール**
```bash
npm install -D @playwright/test
npx playwright install
```

---

## **✅ 2. プロジェクトを初期化**
通常は以下のコマンドでPlaywrightの設定を自動生成できる：
```bash
npx playwright init
```
**✅ これが動けば、そのまま進める！**

**❌ もし `init` が動かない場合は、以下の手動設定を行う。**

---
## **🔹 `npx playwright init` が動かない場合の手動設定**
### **2-1. `playwright.config.ts` を手動作成**
### **① 設定ファイルを作成**
```bash
New-Item -Path . -Name "playwright.config.ts" -ItemType "file"
```
### **② ファイルを開いて以下を記述**
```tsx
import { defineConfig } from '@playwright/test';

export default defineConfig({
  testDir: 'tests',
  timeout: 60000,
  use: {
    headless: true, // 👈 ブラウザを開かずに実行
    screenshot: 'on', // スクリーンショットを保存
    video: 'retain-on-failure', // 失敗時に動画を保存
  },
});
```
---

### **2-2. `tests/` フォルダとテストファイルを作成**
### **① `tests/` フォルダを作成**
```bash
mkdir tests
```
### **② `example.spec.ts` を作成**
```bash
New-Item -Path tests -Name "example.spec.ts" -ItemType "file"
```
📌 **`tests/example.spec.ts` に記述**
```tsx
import { test, expect } from '@playwright/test';

test('Google検索テスト', async ({ page }) => {
  await page.goto('https://www.google.com');

  // 🔹 検索ボックスをクリック
  await page.getByRole('combobox', { name: '検索' }).click();

  // 🔹 検索ワードを入力
  await page.fill('textarea[name="q"]', 'Playwright');

  // 🔹 Enterキーを押して検索
  await page.press('textarea[name="q"]', 'Enter');

  // 🔹 検索結果のタイトルを確認
  await page.waitForTimeout(2000);
  await expect(page).toHaveTitle(/Playwright/);
});
```
---

## **✅ 3. Playwright のテストを実行**
```bash
npx playwright test
```
✅ **成功例**
```scss
✓ 1 passed (4.1s)
```
**スクリーンショット & 動画の確認**

- `test-results/` フォルダ内の **画像（.png）や動画（.webm）** を確認
- 失敗時のスクリーンショットが自動保存される
---

## **✅ 4. Playwright のデバッグ**
### **4-1. `headless: false` でブラウザを開く**
`playwright.config.ts` を修正して、ブラウザを表示しながらテスト実行
```tsx
export default defineConfig({
  use: {
    headless: false, // 👈 ここを false にする
  },
});
```
その後、再度実行：
```bash
npx playwright test
```
---

### **4-2. `npx playwright codegen` で正しいセレクターを取得**
もし `getByRole` や `input[name="q"]` で要素が見つからない場合は、以下を実行
```powershell
npx playwright codegen https://www.google.com
```
- 自動で **ブラウザ + コード生成ツール** が起動
- 検索ボックスをクリックすると、適切な **セレクター** を取得可能
- **取得したセレクターを `example.spec.ts` に反映**
---

## **🎯 5. その他**
### **🔹 スクリーンショットを手動で撮る**
```tsx
await page.screenshot({ path: 'screenshot.png' });
```
### **🔹 複数のブラウザでテスト**
```powershell
npx playwright test --browser=firefox
```
**📝 `chromium`, `firefox`, `webkit` に対応**
Snowflakeのロール階層をデータベースロールも含めて可視化する方法



## ①ロール階層を取得
以下のクエリを使いロール階層構造を取得する


```
SELECT 
    grantee_name role_name
    , name child_role_name
FROM
    SNOWFLAKE.ACCOUNT_USAGE.GRANTS_TO_ROLES
WHERE
    granted_on in ('ROLE', 'DATABASE_ROLE')
    and granted_to in ('ROLE', 'DATABASE_ROLE')
    and privilege = 'USAGE'
    and deleted_on is null
order by
    1,2
;
```

## ②. dotファイル形式にする
クエリ結果を整形し以下のdotファイルを作成する
```
digraph a_tree {
    // グラフ全体の配置を縦方向にする（TB: top to bottom）
    rankdir = TB;

    // 上記のクエリ結果を整形し「"[role_name]" -> "[child_role_name]";」の形式で羅列する
    "ACCOUNTADMIN" -> "SYSADMIN";
    "ACCOUNTADMIN" -> "MY_CUSTOM_ROLE";
    // ...以下省略...
}
```

## ③. 適当なツールを使い可視化する
例えば、VS Codeの[Graphviz (dot) language support for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=Stephanvs.dot)を使い可視化する