OmniAICreator/Qiita-1.07M huggingface dataset:
ChatGPT を使って、Rust言語を勉強します。データ型→プリミティブ型 篇

#### 質問1: Rust言語のプリミティブ型を教えてください。

#### 回答1:

---
Rust言語のプリミティブ型は、以下の8つです。

1. bool: 真偽値 (trueまたはfalse) を表す型。
2. char: 1文字を表す型。
3. i8, i16, i32, i64, i128, isize: 符号付き整数型。ビット数が異なり、それぞれ-128から127、-32768から32767、-2147483648から2147483647、などの範囲を表現できます。
4. u8, u16, u32, u64, u128, usize: 符号なし整数型。ビット数が異なり、それぞれ0から255、0から65535、0から4294967295、などの範囲を表現できます。
5. f32, f64: 浮動小数点数型。精度が異なり、それぞれ32ビット、64ビットの精度を持ちます。
6. str: 文字列型。可変長のUTF-8エンコード文字列を表現できます。
6. 
これらの型は、Rustのプログラミングにおいて基本的なデータ型となっています。

---

#### 質問2: Rust言語のプリミティブ型の使い方を教えてください。

#### 回答2:

---
Rust言語のプリミティブ型を使うには、まず変数を宣言する必要があります。変数の宣言は、letキーワードを使用します。

以下は、各プリミティブ型の変数宣言の例です。

```rust
// bool型の変数を宣言する
let is_rust_cool = true;

// char型の変数を宣言する
let first_letter = 'R';

// i32型の変数を宣言する
let number_of_users = 1000;

// u64型の変数を宣言する
let max_file_size: u64 = 1_000_000_000;

// f64型の変数を宣言する
let pi: f64 = 3.14159265359;

// str型の変数を宣言する
let message = "Hello, world!";
```

各変数の後に、コロン（:）を使用して型を指定することもできます。特に、整数や浮動小数点数のような数値型では、変数の型を指定することで、変数の範囲や精度を制限することができます。

また、文字列型の場合、ダブルクオートで囲むことで文字列を定義できます。Rustの文字列型はUTF-8でエンコードされるため、UTF-8に対応した文字列を扱うことができます。

これらの変数は、通常の変数と同様に、値を代入することで更新することができます。

```rust
let mut message = "Hello, world!";
message = "Hello, Rust!"; // メッセージを更新する
```

ただし、変数の型を指定した場合、型が一致しない場合はエラーが発生するため、適切な型を選択する必要があります。また、変数の値は通常の変数と同様にスコープによって制限されます。

---

#### 質問3: Rust言語のプリミティブ型のメソッドを教えてください。

#### 回答3:

---
Rustのプリミティブ型には、それぞれに固有のメソッドはありませんが、各型に対して使用できる共通のトレイトや関数がいくつかあります。

以下に、プリミティブ型に使用できるトレイトと関数の一部を示します。

・　Copyトレイト：複数の所有権を持つことができる型を、所有権を持たない型のようにコピーすることができるようにします。これにより、値を引数として渡す際に、所有権を移動させる代わりに値をコピーすることができます。

・　Cloneトレイト：Copyトレイトと同様に、複数の所有権を持つことができる型をクローンすることができるようにします。ただし、Cloneトレイトは、所有権を持つ型に対してのみ実装されます。

・　Defaultトレイト：値を初期化するために使用されるデフォルトの値を提供します。例えば、i32型のデフォルト値は0です。

・　Fromトレイト：別の型から現在の型に変換するための関数を提供します。

・　Intoトレイト：現在の型から別の型に変換するための関数を提供します。

・　PartialEqトレイト：等価性をテストするための関数を提供します。==演算子は、PartialEqトレイトの実装を必要とします。

・　PartialOrdトレイト：大小関係を比較するための関数を提供します。<や>演算子は、PartialOrdトレイトの実装を必要とします。

・　ToStringトレイト：値を文字列に変換するための関数を提供します。

・　as関数：型の変換を行います。例えば、u32型の値をi32型に変換する場合は、u32値に対してas i32と書きます。

これらのトレイトや関数は、プリミティブ型に限らず、Rustのすべての型で使用できます。

---
【5秒でわからせぇ！】 スマホでlocalhostで開発しているサイトを確認する方法【1選】

みなさん、おはようございます:runner:！
@f0lstです！
今日は、**スマホでlocalhostで開発しているサイトを確認する方法**をお伝えします:airplane:！

## :fist_tone1: 結論から言わんかい

さて、結論から言いましょう！(**仕事できる〜**)

### :star: 結論
`http://{自身のIP}:{ポート番号}`

**です！！！**

では、少し寂しいので...
ここからは詳細お話しします:open_hands::open_hands::open_hands:

## :computer: IPの確認方法 (Macの場合)

### 1. Macの**メニューバー**にある**Wi-Fiのマーク**から**Wi-Fi設定**をクリック
![localhost01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3003760/8f100c21-1bbd-44c9-27ea-6ae3327bb6a9.png)

:::note warn
OSによって表示が違う場合がありますが、**おそらく一番下**に出てるやつです(適当)
:::

### 2. 接続しているWi-Fiの**詳細**をクリック
![localhost02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3003760/389b70bc-305e-b0fe-a79e-67d19a2977c1.png)

:::note warn
この辺りもOSによって表示が違う場合があります。
スクショは**Ventura**のものです。
:::

### 3. 表示されるIPを確認
![localhost03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3003760/42a9f092-b1b0-19d8-e092-2f722c7717fc.png)


### 4. アクセスするURLを作る
- `http://{確認したIP}:{ポート番号}`

:::note
実機での確認は以下の手順が**おすすめ**！
1. 👆の**4**で作成したURLを**PCのChrome等のブラウザで開く**
2. **QRコードを作成**
    - Chromeなどは拡張機能なしでQRコードを作成できるのでおすすめです！
:::

## :santa: まとめ
開発はやはり**実機検証**がとても大事です！

**DevToolsを使った検証では起きなかった問題が、実機で起こる**...
なんて**あるある中のあるある**ですからねえ〜:head_bandage:

個人開発では特にlocalでの開発が多いと思いますので、ぜひお役立てください〜！！


## :tv: ちょっと宣伝
普段はQiitaで、**しんちゃん構文**を使った記事を書いてます:flag_de:！
よければそちらもご覧くださいませ〜！
:point_down::point_down::point_down:
- [👹「しんのすけ〜！あんた、CSSの`:focus-visible`もうお勉強したんでしょうね〜！？」](https://qiita.com/f0lst/items/7b89295db5a101b48710)
- [【ドイツ】< ChatGPTのAIを野原しんのすけに教育したゾ！](https://qiita.com/f0lst/items/628c4444649c97d7c5c2)
- [【10選あるゾ】 🍑 < みさえ！！！youtubeじゃなくて`YouTube`だゾ！！！](https://qiita.com/f0lst/items/3dbce7af6133d85cf12f)
Unity 1マス移動の実装

### この記事の動機
Unity勉強がてら、初めて2Dゲーム制作にチャレンジしていた時に、プレイヤーの1マス移動の実装が単純なものではなかったので忘れないように備忘録としてメモと共有。
（ゲーム開発者にとっては常識かもしれませんが。。）

※タイルマップやプレイヤーの配置などは割愛
※実際の動作は映像を添付できないので割愛

### 最初につまづいたこと
単純にプレイヤーが移動するためには、移動速度を持たせて入力があった方向にプレイヤーの場所を変えてあげれば良いのかと思い、プレイヤーに紐づくコードを以下のように書いてみた。
```c#:PlayerController
public class PlayerController : MonoBehaviour
{
    // Playerの移動
    
    // Playerから移動速度を取得できるように設定
    [SerializeFiled] float moveSpeed;

    // 外部で入力内容を保持する用の変数
    Vector2 input;
    
    void Update()
    {
        // キーボードの入力情報をinputに格納
        input.x = Input.GetAxisRaw("Horizontal"); // 横方向
        input.y = Input.GetAxisRaw("Vertical");  // 縦方向
        
        // 入力があったら（inputに値が入っていたら）
        if (input != Vector2.zero) 
        {
            // 入力内容をもとにプレイヤーを移動させる
            transform.position += (Vector3)input;
        }
    }
}
```

Unityに戻って、プレイヤーの移動速度を"5"に設定して実行してみると。。

プレイヤーがビュンビュン移動するではありませんか！(映像で見せれないのが悔しい)

原因はこのコードだと、入力がある限りどこまでも移動してしまうからです。

### どのように1マス移動を実装させるか
どのように1マス移動を実装するかですが以下のような考え方で実装します。
・入力があった分を一旦目的地として保持し、その目的地に徐々に近づけるような処理をかく（すぐに移動させない）
・入力中（移動中）は入力を受け付けないようにする

入力されている間、プレイヤー徐々に近づけるように動かすにはコルーチンを使います。

https://docs.unity3d.com/ja/2018.4/Manual/Coroutines.html

```c#
    bool isMoving; // 移動中判定
    void Update()
    {
        // 移動中だと入力を受け付けない
        if (!isMoving)
        {
            // キーボードの入力情報をinputに格納
            input.x = Input.GetAxisRaw("Horizontal"); // 横方向
            input.y = Input.GetAxisRaw("Vertical");  // 縦方向

            // 入力があった時
            if (input != Vector2.zero)
            {
                // 入力があった分を目的地にする
                Vector2 targetPos = transform.position;
                targetPos += input;
                StartCoroutine(Move(targetPos));
            }
        }
    }

    //　コルーチンを使って徐々に目的地に近づける
    IEnumerator Move(Vector3 targetPos)
    {
        // 移動中は入力を受け付けない
        isMoving = true;

        // targetposとの差があるなら繰り返す:目的地に辿り着くまで繰り返す
        while ((targetPos - transform.position).sqrMagnitude > Mathf.Epsilon)
        {
            // targetPosに近づける
            transform.position = Vector3.MoveTowards(transform.position, targetPos, moveSpeed * Time.deltaTime);
            // 徐々に近づけるため
            yield return null;
        }
        
        // 移動処理が完了したら目的地に到着させる
        transform.position = targetPos;
        isMoving = false;
    }
```

Vector3のMoveTowardsを使えば、現在地を目的地に向かって任意のスピードで移動させることが出来ます。
これを徐々に近づけさせながら繰り返したいのでコルーチンの中に書きます。

MoveTowardsには
引数1：現在地
引数2：目的地
引数3：速さ
を渡してあげると移動先を返してくれます。

https://docs.unity3d.com/ja/current/ScriptReference/Vector3.MoveTowards.html


さらに、コルーチンの最初で移動中フラグを立てて、移動処理中に入力を受け付けないようにします。
コルーチンの最後（移動完了時）にfalseにしてあげることで、次の入力を受け付けるようになります。

上記のコードを動かしてみると、見事1マス移動を実現することが出来ました！

この技術はゲーム制作において必須スキルになっているのかもと感じました。
ゲームを作るうえでテンプレのように覚えていて損はないですね！
【SwiftUI】Widgetからタップでアクションを実行する

# はじめに
現在、Widgetのアプリを開発しています。
Widgetにボタンを配置してタップアクションを実装しようと思ったのですが、うまく動きませんでした。
どうやら、Widgetではボタンは機能しないみたいです。

別の方法がないか調べたところ、それらしき方法を見つけたので記録しておきます。

# URLSchemeを設定する
こちらは割愛します
以下の記事がわかりやすかったです。

https://dev.classmethod.jp/articles/ios-custom-url-scheme/

今回は、`sample`と設定したことにします。

# 実装
### メイン
```swift:SampleApp
import SwiftUI

@main
struct SampleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView().onOpenURL { url in
                // ここで処理を実行する
            }
        }
    }
}
```

### ウィジェット
```swift:SampleEntryView
struct ZennWidgetExtensionEntryView : View {
    var entry: Provider.Entry
    var body: some View {
        Link(destination: URL(string: "sample://")!) {
            Text("ボタン")
        }
    }
}
```

# おわり
URLSchemeでアプリを開いた時だけ、特定の動作を実現すれば良いみたいです。
```
sample://test/scheme?q=food
```

こんな感じでURLにパスやパラメータを追加することもできます。
アプリ側でパスやパラメータに応じて処理を変更することができます。

URLの部分抽出は以下の記事が参考になると思います。

https://qiita.com/SNQ-2001/items/a5f7bce8854a2c19bf72

# 参考記事
https://stackoverflow.com/questions/65556274/ios-add-button-to-widget-extension
【EC2料金削減】EIP非付与のEC2インスタンスを自動起動・SSH接続するスクリプトを作成してみた

# はじめに

AWSのEC2の料金削減を目的としたスクリプトです。業務利用よりも個人での利用を想定しています。

多くの方が、料金削減のためにEC2を必要なタイミングでのみ起動し、不要なタイミングではシャットダウンするということをされているかと思いますが、
その場合ssh接続する際にAWSコンソール画面などから手動で起動する作業が必要となるかと思います。

また、local環境からssh接続するためには、Global IPを指定する必要があります。Elastic IP(EIP)を付与することで、毎回同じGlobal IPを指定してssh接続が可能となりますが、AWSではEIPはインスタンス停止中にも料金が発生するという課題があります。

この問題を解決するために、EIPを付与せずに動的にGlobal IPが付与されるEC2インスタンスに対して、
AWSコンソール画面を使わずにCLIで起動→ssh接続まで一貫して行うスクリプトを作成しました。

# 前提

* EC2にEIPが付与されていないこと
    * ※付与されていてもこのスクリプトは動作しますが、冗長です
* AWS CLIが導入済みであること
* EC2にssh接続するためのキーペア（秘密鍵、pemファイルなど）が用意されていること

# 解決方法

以下の処理の流れのスクリプトを作成しました。
1. インスタンスIDを指定して、現在のインスタンス起動状態を取得し、未起動であればEC2を起動する。
1. 起動状態になったらグローバルIPを取得する
1. 取得したグローバルIPとキーペアを用いて、ssh接続する。

## 作成したBashのスクリプト

```start-and-ssh-ec2.sh
#!/bin/bash

set -euxo pipefail

# コマンドライン引数からインスタンスID、キーペアを取得
INSTANCE_ID="$1"
KEY_PAIR="$2"

# インスタンスの状態を取得
state=$(aws ec2 describe-instances \
  --instance-ids "${INSTANCE_ID}" \
  --query 'Reservations[0].Instances[0].State.Name' \
  --output text)

# インスタンスが起動していない場合は起動する
if [[ "${state}" != "running" ]]; then
  echo "Starting EC2 instance..."
  aws ec2 start-instances --instance-ids "${INSTANCE_ID}" >/dev/null
fi

# インスタンスが起動するまで待機する
echo "Waiting for EC2 instance to start..."
aws ec2 wait instance-running --instance-ids "${INSTANCE_ID}"

# グローバルIPアドレスを取得する
GLOBAL_IP=$(aws ec2 describe-instances \
  --instance-ids "${INSTANCE_ID}" \
  --query 'Reservations[0].Instances[0].PublicIpAddress' \
  --output text)

# ssh接続を試行する
echo "Connecting to EC2 instance..."
ssh -i "${KEY_PAIR}" ec2-user@"${GLOBAL_IP}"
```

## 使い方

以下のように引数を指定します。
* 第一引数：EC2のインスタンスID (ex. `i-1234567890abcd`)
* 第二引数：キーペア(pemファイルなど)のパス (ex. `~/.ssh/hogehoge.pem`)

### 実行コマンドサンプル
```sh
./start-and-ssh-ec2.sh i-1234567890abcd ~/.ssh/hogehoge.pem
```

# 結論

以上のようなスクリプトを作成することで、EC2インスタンスの起動とssh接続を自動化し、コンソール画面からの操作を省略することができます。
特にEIPを付与せずにGIPを動的に付与する場合には、インスタンス停止中の料金課題も回避することができます。
（実際にいくら削減できるか？というところまでは未計算ですが...）

また、本スクリプトをaliasに登録するなどして、利用の手間を更に軽減させることができます。
最終行の `ssh -i "${KEY_PAIR}" ec2-user@"${GLOBAL_IP}"` はログインユーザー名をハードコードしていますが、必要に応じて書き換えたり、こちらもコマンドライン引数として扱っても良いかもしれません。

実際に利用する際は、EC2インスタンスをシャットダウンするためのスクリプトを作成し、併せて利用するのが便利そうですね。
QueryExpression Condition or

SQL

select * from A ,B inner join A.field1 = B.field11
where B.name1 ="aaa" or B.name2 ="aaa"

QueryExpression

#
var query = new QueryExpression("A");
query.ColumnSet.AllColumns = true;

var linkEntity = new LinkEntity("A", "B", "field11", "field11", JoinOperator.Inner);
linkEntity.LinkCriteria.AddCondition(new ConditionExpression("name1", ConditionOperator.Equal, "aaa"));
linkEntity.LinkCriteria.AddCondition(new ConditionExpression("name2", ConditionOperator.Equal, "aaa"));
query.LinkEntities.Add(linkEntity);

var result = service.RetrieveMultiple(query);

var result = service.RetrieveMultiple(query);
#
【Git】コミット履歴を編集

## 直近のコミットメッセージを変更

```sh
$ git commit --amend -m 'メッセージ内容'
```

上記コマンドで、直近のコミットメッセージを変更できます。

## 複数のコミットメッセージを変更

```sh
$ git rebase -i HEAD~n
```

上記のコマンドで、複数のコミットメッセージを変更することもできます。

* 修正したコミット先頭の**pick**を**edit**を変更する
* `Esc`を押下し、`:wq`で修正後のメッセージを保存する


## Githubの関連記事
https://docs.github.com/ja/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/changing-a-commit-message

## その他Gitの操作

https://seiri-blog.github.io/posts/git-advanced-operation-part1/
CloudFrontのカスタムエラーレスポンスとWAFの組み合わせでメンテナンスページを設定

# これはなに
AWS ClouFrontで公開されるサイトのメンテナンスページの表示方法について検討する際に迷ったことがあったので、実装方法や疑問点など紹介します。

## 背景
・CloudFrontの前段にはAWSWAFが配置されており、IP制限等で接続ユーザーを管理できるようにしてある。
・404エラーなどはカスタムエラーレスポンスでページを表示したい。
・不定期なメンテナンスに備え、任意のタイミングでメンテナンスページへ移行できるようにしておきたい。
### 構成図
構成のざっくりとした全体像は以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435702/9b641937-ca21-66a3-924c-d76d403063a1.png)

## 疑問点
調べてみると以下のような構成にすることで、メンテナンスページを簡単に作れると複数発見。
仕組みとしては以下のようになる。

1. AWS WAF側でIPアドレス制限をかける
2. 許可されてないユーザーがアクセスする
2. 許可されていないので403エラーが発生する
2. エラーコードに基づいてカスタムエラーレスポンスでメンテナンスページを返す

しかし、ん？でも**CloudFrontの前段にWAFがある**から無理じゃない？？と思いました。
そもそも**WAFでブロックされるんだからCloudFrontには到達しない**よね？と。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435702/59a3a13c-1a94-aa6c-04ab-6910f7e5a42d.png)

なので、以下の図のような状態を私の中では想定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435702/3ba4193b-37c1-11b8-1b6a-60da84dc3eb2.png)

## 試してみた
### 許可IPでの接続時
許可されたIPアドレスなので、そうていのコンテンツが表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435702/d0c5e378-6de1-836b-c86b-c2ad0010dce0.png)
### 非許可IPでの接続時
WAFでブロックされているはずなのに設定したカスタムエラーレスポンスがちゃんと返ってくる。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435702/a5ca0e8c-6455-3482-5952-7b8769d5151b.png)

### 調べてみた
つまり、403エラーはWAFが返してるのではなく、
<font color="Red">**CloudFrontから返ってきていたのだ**</font>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435702/f12bd4a9-750b-8ce0-1349-90c5a15caa41.png)

https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/cloudfront-features.html

## 実際の動き
上記の調べてみた前提をもとにAWS WAFでブロックされた際の処理フローを図解してみると以下のようになります。
1. AWS WAFがCloudFrontに403エラーを返却する
1. S3からカスタムエラーレスポンスに設定のコンテンツを取得する
1. 取得したコンテンツをユーザーに返す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435702/72bacfc7-4699-7d81-21f8-6f818c7ae876.png)

## まとめ
- CloudFrontのカスタムエラーレスポンスを使うと簡単にメンテナンスページが実現できるの皆さんもぜひ！！
- **WAFでブロックされたときにはWAFからレスポンスを返すのではなく、CloudFrontに403を返している**。

## 最後に注意点
①AWS WAF ルールを使用してカスタマイズした応答は、
CloudFront カスタムエラーページで定義した応答よりも優先されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435702/6b27cba4-94d4-3f62-90c0-e8ba61b86bc2.png)

②CloudFrontはオリジンによって返された403と、
AWS WAFによってブロック時に返された403を区別できないです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435702/9aad0005-1990-b87f-a29d-2dddc32b1356.png)

https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/cloudfront-features.html#cloudfront-features-custom-error-pages
Chrome View Transitions API

# Chrome View Transitions APIについて

Chrome View Transitions APIは、**Chrome 111**で新たに追加されたAPIで、ウェブアプリケーションでの画面遷移時に簡単かつスムーズなアニメーションを実現することが可能
これにより、ウェブアプリケーションのユーザーエクスペリエンスが向上ができる

## 目次

1. [主な機能](#主な機能)
2. [使用例](#使用例)
3. [詳細な情報](#詳細な情報)
3. [注意点](#注意点)

## 主な機能

### 簡単な画面遷移アニメーションの実装

View Transitions APIを使用することで、ウェブ開発者は簡単に画面遷移アニメーションを実装し、ユーザーエクスペリエンスを向上が可能

### カスタマイズ可能なアニメーション設定

APIは、遷移アニメーションの方法、時間、イージングなどを簡単に設定できるように設計されている

## 使用例

以下は、View Transitions APIを使用して画面遷移アニメーションを実装する例

```javascript
// 新しいページへの遷移時にフェードインアニメーションを実行する
const viewTransition = new ViewTransition({
  type: 'fade',
  duration: 300,
  easing: 'ease-out'
});

// 遷移を開始する
viewTransition.start().then(() => {
  // 遷移が完了した後の処理をここに記述
});
```

以下に、Reactでの詳細なサンプルを記載
```javascript
// src/App.js
import React, { useCallback } from 'react';
import { BrowserRouter as Router, Route, Switch, useHistory } from 'react-router-dom';
import NewPage from './NewPage';

const Home = () => {
  const history = useHistory();

  const handleNavigate = useCallback(async () => {
    // 新しいページへの遷移時にフェードインアニメーションを実行する
    const viewTransition = new ViewTransition({
      type: 'fade',
      duration: 300,
      easing: 'ease-out',
    });

    // 遷移を開始する
    await viewTransition.start();

    // React Routerで遷移する
    history.push('/new-page');
  }, [history]);

  return (
    <div>
      <button onClick={handleNavigate}>Navigate to New Page</button>
    </div>
  );
};

const App = () => {
  return (
    <Router>
      <Switch>
        <Route exact path="/" component={Home} />
        <Route path="/new-page" component={NewPage} />
      </Switch>
    </Router>
  );
};

export default App;

```

### 詳細な情報
詳細な情報やドキュメントについては、以下のリンクを参照

[New in Chrome 111: View Transitions API](https://developer.chrome.com/en/blog/new-in-chrome-111/#view-transitions-api)


## 注意点

- View Transitions APIは、Chrome 111以降でのみ利用可能です。そのため、対応していないブラウザでは、適切なフォールバック方法が必要
- 現時点では、APIはまだ実験的な段階にあり、仕様が変更される可能性があるため、注意が必要
NxでReact製のwebアプリとReact Native製のmobileアプリをモノレポ管理するメモ（開発サーバーの起動まで）

## これは

初めてNxを使ってモノレポ管理を実践した時の雑な作業メモ。

バージョンは以下の通り。
```
"nx": "15.8.7"
"react": "18.2.0",
"react-native": "0.71.2",
"typescript": "^5.0.2"
```

基本的にはnxの公式の手順に従って進める。
- [@nrwl/react](https://nx.dev/packages/react)
- [@nrwl/react-native](https://nx.dev/packages/react-native)

## メモ

まずはnxのワークスペースを作成。名前は仮。
`npx create-nx-workspace nx-sample`

オプションは`Package-based monorepo`を選択。

作成完了後、`nx-sample`に移動して
`typescript`を入れて`tsconfig.json`作成。

次にnxのreactとreact native用のパッケージを入れる。

`npm i -D @nrwl/react @nrwl/react-native`

オプションは以下の通り選択。
- ✔ Which stylesheet format would you like to use? · css
- ✔ Would you like to add React Router to this application? (y/N) · false
- ✔ Which bundler do you want to use to build the application? · vite

rootの`package.json`のscriptsに追加。

```
"dev:web" : "nx serve web"
```

`npm run dev:web`で開発サーバーの起動に成功。

次にmobile版のアプリケーション作成。
`nx g @nrwl/react-native:app mobile`

下記エラーが発生。
```
 >  NX   Command failed: pod install
/bin/sh: pod: command not found
Pass --verbose to see the stacktrace.
```

cocoapodsがなかったので手動で入れる。

```
sudo gem install cocoapods
```

再度`nx g`コマンド実行。
ここでかなり時間がかかる。
結果別のエラーが発生。
```
 >  NX   Command failed: pod install

   
   [!] Do not use "pod install" from inside Rosetta2 (x86_64 emulation on arm64).
   
   [!]  - Emulated x86_64 is slower than native arm64
   
   [!]  - May result in mixed architectures in rubygems (eg: ffi_c.bundle files may be x86_64 with an arm64 interpreter)
   
   [!] Run "env /usr/bin/arch -arm64 /bin/bash --login" then try again.
   
   Pass --verbose to see the stacktrace.
```

一旦削除してbrewで再度インストール。
```
sudo gem uninstall cocoapods

arch -arm64 brew install cocoapods
```

そして`npx nx start mobile`でmetroサーバーの起動に成功。

簡単すぎるが一旦今回はここまで。
Azure Administrator(AZ-104)：Azure でのストレージの実装と管理「Azure Storageセキュリティのベストプラクティス」

Microsoft Learnを用いたMicrosoft Azure Administrator(AZ-104)の試験内容をまとめる投稿です。
この投稿ではMicrosoft Learnで学ぶ内容をできるだけ簡潔にまとめております。
Azureの勉強を一から始め、AZ-900取得後の資格としてAZ-104取得を目指している方の参考になれば幸いです。
※AZ-900の内容は本投稿では省略しております。再度復習したい方は下記をご参照ください。
[Azure Fundamentals(AZ-900)：試験合格に向けた学習内容のまとめ](https://qiita.com/fsd-jume/items/e4ec76959adb547ac5e8)

## 今回の学習内容
**◆「Azure Storageセキュリティのベストプラクティス」**
◇対応するMicrosoft Learn ラーニングパス
[AZ-104:Azure でのストレージの実装と管理](https://learn.microsoft.com/ja-jp/training/paths/az-104-manage-storage/)
◇対応するモジュール
[Azure Storage セキュリティのベスト プラクティスを適用する](https://learn.microsoft.com/ja-jp/training/modules/configure-storage-security/7-apply-best-practices)

※前回の投稿は下記から確認できます。
[Azure Administrator(AZ-104)：Azure でのストレージの実装と管理「Azure Storageの暗号化」](https://qiita.com/fsd-jume/items/21f5da17db39d78481b1)

## Azure Storageセキュリティのベストプラクティス
### アプリでSASを使用した際の潜在的なリスク
・SASが侵害された場合
⇒悪意あるユーザも含めて、取得した人はだれでも使用可能
・クライアントアプリに提供されたSASの有効期限が切れた場合
⇒アプリがサービスから新しいSASを取得できない場合はアプリの機能停止の可能性

### SASを使用する際の推奨事項
**◆作成と配布には常にHTTPSを使用**
・SASがHTTP経由で渡されて傍受された場合
⇒中間者攻撃の実行者はSASを使用可能
⇒機密データの漏洩/データを破損される恐れがある

**◆サービスSASの保存されているアクセスポリシーを使用**
・ストレージアカウントキーを再生成せずに、SASのアクセス許可を失効可能
・ストレージアカウントキーの有効期限を遠い将来(または無期限)に設定を推奨

**◆計画外のSASには短い有効期間を設定**
・SASが侵害された場合の攻撃を軽減可能
・保存されているアクセスポリシーを参照できない時に重要
・短期間の有効期間はBLOBにアップロード可能な時間が制限
⇒BLOBに書き込むことのできるデータ量も制限

**◆クライアントにSASの自動更新を要求**
・クライアントに有効期限が切れるかなり前にSASを更新するよう要求
・早く更新した場合
⇒SASを提供するサービスが使用不可の時に再試行する時間が発生

**◆SASの開始時刻を慎重に計画**
・SASの開始時刻を現在時刻に設定した場合
⇒最初の数分間に断続的なエラーが発生する可能性あり
⇒コンピュータごとに現在時刻が若干異なるため(クロックスキュー)
・一般に、開始時刻は15分以上前になるよう設定
※または特定の開始時刻を設定しない
・一般的には有効期限も同様
⇒どの要求でも、前後に最大15分のクロックスキュー発生の可能性あり
・2012年2月12日より前のREST APIバージョン使用クライアントの場合
⇒保存されているアクセスポリシーを参照しないSASの最長期間は1時間
⇒1時間より長い期間を指定するポリシーはいずれも失敗

**◆リソースの最小限のアクセス許可を定義**
・セキュリティのベストプラクティス
⇒可能な限り少ないリソースへの必要最小限の権限をユーザに付与
・下記の場合に役立つ
　-攻撃者の管理下でのSASの機能低下
　-SASが侵害された場合の損害抑止

**◆SASを含む使用量に対するアカウントの課金について理解**
・BLOBへの読み取り/書き込みアクセスを許可した場合
　-ユーザが200GBのBLOBをアップロードする可能性あり
　-200GBのBLOBを10回ダウンロードする可能性あり
⇒2TBの送信料金が発生
・悪意あるユーザによるリスク軽減のため、制限付きアクセス許可を付与
・短期間のSASを使用(終了時刻のクロックスキューに注意)

**◆SASを使って書き込まれたデータを検証**
・クライアントアプリがストレージアカウントにデータを書き込む場合
⇒そのデータに問題がある可能性に注意
・アプリで検証済み/認可済みのデータが必要な場合
⇒データが書き込まれてからアプリで使用されるまでに検証を実施
・検証により下記の場合でも破損/悪意あるデータの書き込みからアカウントを保護
　-ユーザがSASを正当に入手している場合
　-漏洩したSASを利用している場合

**◆SASを使用しない場合を認識**
・ストレージアカウントに対する特定の操作に関連するリスク
⇒SASを利用する利点より重大である場合もあり
⇒下記の後にストレージアカウントに書き込む中間層サービスを作成
　-ビジネスルールの検証/認証/監査
・別の方法でアクセスを管理する方が容易な場合もあり
　-例：コンテナ内のすべてのBLOBが一般ユーザに読み取り可能な場合
　⇒SASの提供ではなく、コンテナをパブリックにする

**◆Azure Storage Analyticsでアプリを監視**
・ログ/メトリックを使用して認証エラーの急増を観察可能
⇒下記により発生している可能性あり
　-利用中のSASプロバイダーサービスの停止
　-保存されているアクセスポリシーの誤削除

## 次の学習内容
**◆ファイル共有やBLOBデータのためのストレージ比較**

https://qiita.com/fsd-jume/items/e272f42e72629f1cba72

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/6eda24728c9c03c36bc3
シングルページアプリケーションのサイトでgoogleアナリティクスを実装

## はじめに

こちらはユニバーサルアナリティクスの設定を行った時のメモになります。
現状GA4とはまた仕様が異なります。

## シングルページアプリケーションとは

シングルページアプリケーション（SPA）とは、サイトを作成する方法のひとつ、
ブラウザではページの移動を行わずにはじめに到達したページの上で画面遷移が行われる構成のことを指します。
Googleアナリティクスにとっては画面遷移が行われていないと認識されてしまい、最初のページ以降、ページビュー数が計測できないという事態に陥ってしまうため、別途gtmページビュータグの設定が必要になります。


## 設定手順

# 実装ずみのGTM上でカスタムトリガーを作成する

nuxtRouteイベントをトリガーとするカスタムイベント
トリガータイプ：カスタムイベント
イベント名：nuxtRoute
このトリガーの発生場所‘：「すべてのカスタムイベント」にチェックを入れる




# ふたつのデータレイヤー変数を作成する

①データレイヤー変数名：pageURL
変数のタイプ；データレイヤー
データレイヤーのバージョン：バージョン2

②データレイヤー変数名：route Name
変数のタイプ；データレイヤー
データレイヤーのバージョン：バージョン2



# GTMでアナリティクスタグを作成する
トラッキングタイプ；ページビュー
Googleアナリティクス設定変数：このタグでオーバーライド設定を有効にする
トラッキングID：GAのIDを入力
pageの値page：URL変数に設定
titleの値：route Name
トリガー：nuxtRouteトリガー






# プレビューで確認し公開する

全ての設定が終わったらプレビュー画面で正常にタグが動いているか確認し、
最後に公開をして終了です。
Cloud Telephony Providers

In today's digital age, businesses are increasingly moving away from traditional phone systems and adopting cloud telephony solutions. Cloud telephony is a service that allows businesses to make and receive calls over the internet using a cloud-based system. It offers many benefits over traditional phone systems, such as cost savings, scalability, and advanced features. In this article, we'll take a look at some of the top cloud telephony providers and what they have to offer.

https://www.telecmi.com/solutions/cloud-telephony/
ixp425のredboot

いろいろ試して結局、githubのnslu2のredbootではなく、sfにあったアーカイブファイルからビルドすることにしました。これはnslu2の方のredbootはpciにつながったGigaなifを使っていて、内蔵のifのコードを入れていなかったからです。

GitHubにレポジトリ作りました。

https://github.com/yamori813/IOP_Redboot_Mar_19_2007

IOPはおそらくIntel Open Platformとかの略ではないでしょうか。

無いファイルを探して入れたり、定義のエラーなどいくつか直してビルドは通るようになっています。intelが配布していたもののようですが、かなりいい加減です。

```
+**Warning** FLASH configuration checksum error or invalid key
Use 'fconfig -i' to [re]initialize database
... Waiting for BOOTP information, press Ctrl-C to skip
DHCP reply: 2, not 5
DHCP reply: 2, not 5
Ethernet eth1: MAC address 00:01:69:bc:00:06
Can't get BOOTP info for device!

RedBoot(tm) bootstrap and debug environment [ROM]
Intel IOP Redboot release
         version 2.3-IOP-RedBoot
         built 16:31:00, Mar 30 2023

Platform: IXDP425 Development Platform (XScale) 
Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
Copyright (C) 2003, 2004, 2005, 2006 eCosCentric Limited

RAM: 0x00000000-0x04000000, [0x0006a880-0x03fd1000] available
FLASH: 0x50000000 - 0x51000000, 128 blocks of 0x00020000 bytes each.
RedBoot> 
```

Todo:

~~Flashの書き込みが出来ません。~~ 修正済み

~~メモリサイズの設定が分からないので、無理やりパッチ当ててます。~~ 修正済み

SwitchにつながっているMACが使えません。PHYの方のMAC(WAN)は使えるので制限事項

fis initしてfconfig -iして設定を保存した状態。

```
+Ethernet eth1: MAC address 00:01:69:bc:00:06
IP: 10.0.1.99/255.255.255.0, Gateway: 0.0.0.0
Default server: 10.0.1.38

RedBoot(tm) bootstrap and debug environment [ROM]
Intel IOP Redboot release
         version 2.3-IOP-RedBoot
         built 06:50:48, Mar 31 2023

Platform: IXDP425 Development Platform (XScale) 
Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
Copyright (C) 2003, 2004, 2005, 2006 eCosCentric Limited

RAM: 0x00000000-0x04000000, [0x0006a880-0x03fd1000] available
FLASH: 0x50000000 - 0x51000000, 128 blocks of 0x00020000 bytes each.
RedBoot> 
```
（朗報）ChatGPTに宇宙人診断メーカーを作成してもらった結果

私は宇宙が好きだ。昔から自分が宇宙人じゃないか？と疑うくらい
宇宙が好きだ。

そこで宇宙人かどうか確かめるために

ChatGPTの力を借りて宇宙人診断メーカーを作成することにした！！

まず診断アプリを作る方法を質問してみる

![診断.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291317/5c3231ff-bcfb-fb97-1d1d-36938e011d4f.png)

なるほど！！よく分かった気がする

そこで私は各宇宙人の特徴を調べてみて質問リストを作成した。
これを元にしてChatGPTにgoogle colab上で動くようコーディングを依頼してみることに

以下のコードが出来上がった！！

![宇宙人診断.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291317/a79d3922-c489-0706-ce5d-4d821207d400.png)

なんか質問と答えがおかしくない？っていうツッコミはご指摘の通りだ

この診断メーカー”宇宙人”かどうかを測るためなので気づいたあなたは地球人として優秀である。というのは冗談として

このコードをgoogle colabで動かしてみることに

その結果！！

![アスターラ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291317/665dbecb-cddc-8505-2dbe-b93a2dd23f8c.png)

私はアスターラ星人らしい(笑)
Azure Administrator(AZ-104)：Azure でのストレージの実装と管理「Azure Storageの暗号化」

Microsoft Learnを用いたMicrosoft Azure Administrator(AZ-104)の試験内容をまとめる投稿です。
この投稿ではMicrosoft Learnで学ぶ内容をできるだけ簡潔にまとめております。
Azureの勉強を一から始め、AZ-900取得後の資格としてAZ-104取得を目指している方の参考になれば幸いです。
※AZ-900の内容は本投稿では省略しております。再度復習したい方は下記をご参照ください。
[Azure Fundamentals(AZ-900)：試験合格に向けた学習内容のまとめ](https://qiita.com/fsd-jume/items/e4ec76959adb547ac5e8)

## 今回の学習内容
**◆「Azure Storageの暗号化」**
◇対応するMicrosoft Learn ラーニングパス
[AZ-104:Azure でのストレージの実装と管理](https://learn.microsoft.com/ja-jp/training/paths/az-104-manage-storage/)
◇対応するモジュール
[Azure Storage の暗号化を決定する](https://learn.microsoft.com/ja-jp/training/modules/configure-storage-security/5-determine-storage-service-encryption)
[カスタマー マネージド キーを作成する](https://learn.microsoft.com/ja-jp/training/modules/configure-storage-security/6-create-customer-managed-keys)

※前回の投稿は下記から確認できます。
[Azure Administrator(AZ-104)：Azure でのストレージの実装と管理「URIパラメーターとSASパラメーター」](https://qiita.com/fsd-jume/items/423509eafb3f7a661537)

## Azure Storageの暗号化
### Azure Storageの暗号化の特徴
・Azure Storageの暗号化で保存データを保護
⇒組織のセキュリティ/コンプライアンスコミットメントを満たすのに役立つ
・データは下記に永続化される前に自動的に暗号化
　-Azure Managed Disks
　-Azure Blob Storage
　-Azure Queue Storage
　-Azure Cosmos DB
　-Azure Files
・データは取得前に自動的に暗号化が解除
・暗号化はすべてのストレージアカウントで既定で有効化され、無効にできない
⇒暗号化利用のためにコード/アプリの変更は不要
・下記はユーザに対して透過的に実施
　-Azure Storageの暗号化
　-保存時の暗号化
　-複合化
　-キー管理
・Azure Storage内のデータは256ビットAES暗号化を使って暗号化
⇒利用可能な最強のブロック暗号の1つ
・Azure Storage暗号化はWindowsでのBitLocker暗号化と類似

### Azure Storageの暗号化の種類
・データの暗号化は暗号化キーを使用
⇒暗号化キーの管理方法は2種類

**◆Microsoftマネージドキー**
・Microsoftが暗号化キーを管理
・既定で使用

**◆カスタマーマネージドキー**
・Azure Key Vaultを使用して管理
⇒Azure Key Vault APIで暗号化キーの生成も可能
・独自のキーを作成し、キーコンテナへの格納も可能
⇒柔軟性と制御性が向上
・暗号化には既存のキーコンテナとキーも使用可能
・ストレージアカウントとキーコンテナは下記が異なっていても問題なし
　-Azure ADテナント
　-リージョン
　-サブスクリプション

## 次の学習内容
**◆Azure Storageセキュリティのベストプラクティス**

https://qiita.com/fsd-jume/items/efec36da3babac40bdae

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/6eda24728c9c03c36bc3
ChatGPT を使って、Rust言語を勉強します。データ型→コンパウンド型 篇

##### 質問1: Rust言語のコンパウンド型を教えてください。

##### 回答1:

---
Rust言語には、複数の値をひとつの変数にまとめることができるコンパウンド型がいくつかあります。代表的なものを以下に示します。

1. タプル (tuple)
・　複数の異なる型の値を、カンマで区切って並べたもの
・　例: (i32, f64, &str)

2. 構造体 (struct)
複数のフィールドを持つ、名前付きの型
例:
```rust
struct Person {
    name: String,
    age: u32,
    address: String,
}
```

3. 列挙型 (enum)
・　複数の種類の値を持つ、ヴァリアントを定義できる型
・　例:
```rust
enum TrafficLight {
    Red,
    Yellow,
    Green,
}
```

これらのコンパウンド型は、それぞれ異なる使い方がありますが、一般的にはデータをより複雑な形式で表現するために用いられます。また、これらの型はジェネリックなコードの実装にも役立ちます。詳細は公式ドキュメントを参照してください。

---

##### 質問2: Rust言語のコンパウンド型の使い方を教えてください。

##### 回答2:

---
Rust言語のコンパウンド型は、複数の値をひとつの変数にまとめるために使われます。以下に、それぞれのコンパウンド型の使い方の例を示します。

1. タプル (tuple)
タプルは、異なる型の複数の値をまとめたものです。タプルを作成するには、値をカンマで区切って並べ、それを丸括弧で囲みます。例えば、(1, 2.5, "hello")は、i32型の1、f64型の2.5、&str型の"hello"を持つタプルです。タプルの要素には、インデックスを使ってアクセスできます。例えば、以下のように書くことで、タプルの要素にアクセスできます。

```rust
let t = (1, 2.5, "hello");
let first = t.0;
let second = t.1;
let third = t.2;
``` 

2. 構造体 (struct)
構造体は、複数の名前付きフィールドを持つ型です。構造体を作成するには、structキーワードを使い、構造体名とフィールドを定義します。例えば、以下のようなPerson構造体を定義できます。

```rust
struct Person {
    name: String,
    age: u32,
    address: String,
}
```

この構造体を使って、値を作成するには、以下のように書きます。

```rust
let person = Person {
    name: String::from("Alice"),
    age: 30,
    address: String::from("Tokyo"),
};
```

また、構造体のフィールドには、ドット記法を使ってアクセスできます。

```rust
println!("{} is {} years old and lives in {}.", person.name, person.age, person.address);
```

3. 列挙型 (enum)
列挙型は、複数のヴァリアントを持つ型です。例えば、以下のようなTrafficLight列挙型を定義できます。

```rust
enum TrafficLight {
    Red,
    Yellow,
    Green,
}
```

この列挙型を使って、値を作成するには、以下のように書きます。

```rust
let light = TrafficLight::Red;
```

また、列挙型の各ヴァリアントには、関連するデータを持たせることもできます。例えば、以下のように書くことで、TrafficLight列挙型のYellowヴァリアントに、持続時間を表すデータを持たせます。

```rust
enum TrafficLight {
    Red,
    Yellow(u32),
    Green,
}

let light = TrafficLight::
```

---

##### 質問3: Rust言語のコンパウンド型のメソッドを教えてください。

##### 回答3:

---
Rust言語のコンパウンド型には、それぞれに特有のメソッドがあります。以下に、それぞれのコンパウンド型のメソッドの例を示します。

1. タプル (tuple)
タプルは、標準ライブラリに特別なメソッドを持っていません。しかし、タプルの要素にアクセスするためのメソッドとして、.0、.1などがあります。また、std::mem::swap関数を使うことで、2つのタプルを入れ替えることができます。

2. 構造体 (struct)
構造体は、implブロックを使って、独自のメソッドを定義することができます。例えば、以下のようなRectangle構造体を定義し、areaメソッドを定義することができます。

```rust
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}
```

このメソッドを使って、面積を計算するには、以下のように書きます。

```rust
let rect = Rectangle { width: 30, height: 50 };
let area = rect.area();
println!("The area of the rectangle is {} square pixels.", area);
```

3. 列挙型 (enum)
列挙型は、各ヴァリアントに独自のメソッドを定義することができます。例えば、以下のようなOption列挙型を定義し、unwrapメソッドを定義することができます。

```rust
enum Option<T> {
    Some(T),
    None,
}

impl<T> Option<T> {
    fn unwrap(self) -> T {
        match self {
            Option::Some(val) => val,
            Option::None => panic!("called `Option::unwrap()` on a `None` value"),
        }
    }
}
```

このメソッドを使って、Option型から値を取り出すには、以下のように書きます。

```rust
let x = Some("hello").unwrap();
println!("{}", x);  // "hello"を表示
```

---
VB6からc#への変換について

# 目的

「VBマイグレーション」と呼ばれる、旧世代の`VB6`で作成された業務アプリケーションを`VB.net`や`c#`といった現役の環境に移行するソリューション.

`VB6`がサポート終了して10年以上たったです。

`VB6`の「開発環境」はすでにサポートが終了しておりリスキーです。

# VB6のころのチャート？

`VB6`がバリバリ現役だった頃は、有料のソフトをかうっていうことにあまり抵抗感なかったので、NI
のコンポネントワークス（いまはメジャメントスタジオ？）っていうのを買ってました。そのなかに
`CWGraph`っていうのがあり、これをフォームに貼り付けると、ハッピーでした。

# どうせなら`c#`にしたら？

`VB.net`へのマイグレーションがすぐに思いつくことです。わたくしも、

- `WinXP-OS`
- `vs2005`
- `VB.net`
- `ZedGraph`

という環境で、マイグレーション
（リファクタリング）していたこともあります。このころには、なるべく`OSS`でいろいろなことをやりたい。そう思うようになりまして、その中で白羽の矢が立ったのが、`ZedGraph`というチャート機能です。

マイグレーションができたコードと、まだ着手できてないコードがあります。

# いつまでもXPじゃなかろ？

いつまで`XP`使ってるの？ネットに接続しないから、いい？そんなかんじで最近目覚めてきまして、以下のような環境で、コーディングしなおそうか？そのように思っております。

- `c#`
- `vscode`
- `.net6`
- `visual studio 2022`

という組み合わせです。

`ZedGraph`がいまでも使えるかどうか不明です。`MSChart`ってdeprecateされたのですか？
いろいろとネット検索していると、
[`ScottPlot`](https://github.com/ScottPlot/ScottPlot)ってのがのっていました。

`vs2022`を起動しました。そのあと、`nuget`で`ScottPlot`ってのを`add package`しました。ver.5もあるみたいですが、ここではver. 4しか選べません。そのあと、

新規に `winforms`つくって、`ScottPlotWinForms`を`nuget`してからフォームにグラフをはりつけた上で、`Form1.cs`に下のようなコードをかいたら, うごくようになりました。
(この場合、versionが4なので、命令系統がver.5と異なる)

```
namespace WinFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            double[] dataX = new double[] { 1, 2, 3, 4, 5 };
            double[] dataY = new double[] { 1, 4, 9, 16, 25 };
            formsPlot1.Plot.AddScatter(dataX, dataY);
            formsPlot1.Refresh();

        }
    }
}
```

`VS2022`は、ツールボックスをだしてくるのに苦労しますね。私は、control+Alt+Xでおこないました。

結果について： 下のようなスクショです。

![screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/422525/9ecf8655-85c2-fc07-488e-74932a2343db.jpeg)

# こんなかんじで今後も変換したい

こんなかんじで今後も変換したいです。つぎの大きな障壁は、外部機器との通信ですね。`SerialPort`は`.net6`でも現役なので、ここは一安心ですね

# 備忘録

ちなみに、[`vscode`で`nuget`](https://qiita.com/Kosen-amai/items/9951e41800b8fe39745e). これは備忘録です。
VPCのApplication Load Balancerの名前解決をプライベートNWからのみ許可する

# はじめに
VPCのApplication Load Balancer(ALB)は、これまで、プライベートタイプであっても`lb.appdomain.cloud`ドメイン配下にFQDNで作られ、インターネットからも名前解決できる仕様でした（名前解決先がプライベートIPなので外からは繋がりませんが。）
　
今回、ALBがDNS Servicesと連携することにより、ユーザーがDNS Services上に作成したドメインでALBのFQDNが作られ、VPC内からのみ名前解決できる構成にすることが可能になりました。
https://cloud.ibm.com/docs/vpc?topic=vpc-lb-dns&interface=ui

実際に試してみます。

# サービス間の権限を許可する
今回の機能を使うために、ALBからDNS Servicesを操作できる必要があります。（ALBのFQDNに対応したAレコードがDNS Services上に作成され、ALBのメンテナンス等で実IPが変わったら都度更新されるため。）
そのため、IAMのAuthorizationの画面で、ALBからDNS Servicesに対する権限を付与します。

https://cloud.ibm.com/iam/authorizations
ソースとなるサービスに、`VPC Infrastructure Service`の中から、`Resource type`として`Load Balancer for VPC`を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/bcf49142-7e5d-4bcd-3de5-bcaae646b2fc.png)

ターゲットとなるサービスにDNS Servicesを選択し、Service accessにManager権限を付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/8438c513-39cb-f0df-92da-6ac5f226353e.png)

下記の権限が追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/021dde9e-e4b9-b2f4-c78e-0733cdbffd05.png)

# DNS Services

DNS Servicesにゾーンを作成します。レコードの作成は不要です（後ほどALBにより自動的にAレコードが作成されます）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/f4ad9929-55aa-f930-d53d-bcc1da27023e.png)

# ALB作成

ALBのオーダー画面で、`DNS type`=`Private`を選択すると、DNS ServicesにこのALBのレコードが作られることになります。
DNS typeにPrivateを選択すると、DNS ServicesをBindできるUIが出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/42c48ddf-aadc-b5f3-8b5c-1bb0871c431b.png)

DNS Servicesのインスタンス名とゾーンを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/d1f7deef-6b2e-170b-6f35-634d27378e00.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/42291664-f255-f1e3-834e-ec68a891e930.png)

その他、いつも通り、ALBを配置するVPCやサブネットを選択し、ALBをオーダーすると、ALBの作成中に、DNS Servicesの該当ゾーンにALB用のAレコードが追加されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/7d5dd4ce-c389-6d18-4b1e-78e2a00f342b.png)

ALBの管理画面上も、いつもの`lb.appdomain.cloud`ドメインでなく、独自ドメインで作成されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/0808cdc0-c3da-24db-ef40-767607df3148.png)

# 動作確認

プライベートDNSに作成したドメインなので、インターネット上のDNSでは名前解決できません。
```:PCからnslookup
% nslookup 7b4f004d-jp-tok.tmgw.local
Server:		192.168.3.1
Address:	192.168.3.1#53

** server can't find 7b4f004d-jp-tok.tmgw.local: NXDOMAIN

% 
```

DNS Servicesで許可したVPC内のVSIからは、名前解決できます。
```:VPC内のVSI
# nslookup 7b4f004d-jp-tok.tmgw.local
Server:		161.26.0.7
Address:	161.26.0.7#53

Non-authoritative answer:
Name:	7b4f004d-jp-tok.tmgw.local
Address: 172.16.50.4
Name:	7b4f004d-jp-tok.tmgw.local
Address: 172.16.60.4

# 
```

Custom Resolverを作成し、それを参照すれば、Direct Link越しにも名前解決できます。
```:Direct Link越しにCustom Resolverを参照
# nslookup 7b4f004d-jp-tok.tmgw.local
Server:         172.16.50.12
Address:        172.16.50.12#53

Name:   7b4f004d-jp-tok.tmgw.local
Address: 172.16.60.4
Name:   7b4f004d-jp-tok.tmgw.local
Address: 172.16.50.4

# 
```

以上
RailsでのN+1問題と向き会ってみる

## N+1問題とは
RailsのN+1問題とは、データベースから取得した1つのレコードに対して、関連するデータを取得するために、関連するテーブルに対して複数のSQLクエリを発行してしまう問題のことを指します。

例えばユーザー情報を取得する際に、そのユーザーが投稿した全ての記事の情報も取得する場合を考えてみましょう。
この場合、ユーザー情報を取得するための1つのSQLクエリを発行した後、全ての記事情報を取得するために、別途SQLクエリを発行する必要があります。
このため、ユーザーの数だけSQLクエリが発行されてしまい、処理時間が大幅に遅くなることがあります。

```
# app/controllers/users_controller.rb

class UsersController < ApplicationController
  def index
    @users = User.all
    @users.each do |user|
      @post_count = user.posts.count
    end
  end
end
```

N+1問題は、Railsでよくある問題であり、性能劣化の原因となります。解決策として、Active Recordの`includes`メソッドや`eager_load`メソッドを使用して、予め関連するデータを取得することが挙げられます。また、gemである`bullet`を使うことで、N+1問題を検出することもできます。

# 解消方法
このままではパフォーマンスが悪いアプリケーションのままです…
解消方法がいくつかあるので挙げていきます。


## eager_loadを使用した場合
```
@users = User.eager_load(:posts)
```
LEFT_OUTER_JOINで指定したデータを結合して関連テーブルのデータを取得してきます。
引数として渡した関連先の要素で絞り込みを行うことが

## preloadを使用した場合
```
@users = User.preload(:posts)

# 特定のタイトルというカラムのみを読み込みたい場合
@users = User.preload(posts: :title)
```
usersテーブルから必要なデータを一度に読み込み、さらにそれに紐付く投稿のタイトルのみを一度に読み込むことができます。
これにより、必要なデータだけを読み込むことができ、メモリ使用量を削減することができます。

## includesメソッドを使用した場合
```
# app/controllers/users_controller.rb

class UsersController < ApplicationController
  def index
    @users = User.includes(:posts)
  end
end
```
デフォルトではpreloadと同じ動きをし、関連先のテーブルの要素で絞り込みを行った場合などはeager_loadと同じ動きをします。

# eager_load, preload, includesの使い分け
## eager_load
`has_one`、`belongs_to`関連など1クエリでデータを取得した方が効率が良いと考えられる場合

## preload
`has_many`の関連を持つデータの事前読み込みを行う場合

## includes
他テーブルを結合処理しているか、関連先のテーブルを絞り込みしている場合は挙動(`eager_load`)が変わるため、リーダブルなコードを書くことを意識すると基本的に使うことは少なそう。

# N＋1問題の検出方法
解消方法は理解できたので、原因箇所の検出が必要です。
その際に使用できるのが`bullet`というgemになります。
## <a href="https://github.com/flyerhzm/bullet">bullet</a>
Bulletは、アプリケーションの動作中にN+1問題を検出し、警告を出力してくれます。
### Gemfileへの追加
```
gem 'bullet', group: 'development'
```
### generate コマンドで Bullet gem を有効にします 
```
bundle exec rails g bullet:install
```
### 設定
明示的に指示を出す必要があるため、`config/environments/development.rb`に下記コードを追加します。
設定は自身で変更可能です。Slackへの通知やN+1を検出した際にエラーを発生させることも可能です。
```
# config/environments/development.rb

config.after_initialize do
  Bullet.enable = true          # Bullet gemの有効化
  Bullet.alert = true           # ブラウザ上でJavaScriptによるアラートをポップアップで表示
  Bullet.bullet_logger = true   # Bullet ログ ファイル (Rails.root/log/bullet.log) にログを記録
  Bullet.console = true         # ブラウザの console.log に警告を記録
  Bullet.rails_logger = true    # Rails ログに警告を直接追加
```
### ブラウザにてコンソールログを確認
Bulletは、アプリケーションの動作中にN+1問題を検出し、コンソールログに警告を出力します。例えば、以下のようなログが出力されます。
```
N+1 Query detected
  User => [:posts]
  Add to your finder: :includes => [:posts]
```
ログに出力されたアドバイスに従い、includesメソッドを使ってN+1問題を解消することができます。

# まとめ
N＋1問題と向き合ってみました。
パフォーマンスの問題はアプリケーションが大きくなればなるほど向き合う数は増えていきます。
常日頃からパフォーマンスを低下させないリーダブルなコードを書けるよう意識していきます。
Arduinoのfloatをbyte配列へ格納

これまた単に備忘録です。

しかも今回はネット引用ではなく、色々調べたり試した挙句、ChatGPTに質問投げたら素晴らしくシンプルなやり方で解決したので、これは残しておこうというものです。

通常、浮動小数点なデータをわざわざByte型に変えるなんてもう、通信でデータ転送するくらいしかないわけです。
勿論今回悩むに至った経緯も、通信に乗せるにあたって。

しかし、共同体UNITなどを使ってArduinoのSerialライブラリでそのデータ自体を送信する方法はあるあるとして、
今回は、少しまとまったデータの一部分に、Arduinoボード上で取得したFloatデータ（具体的には温度データなんですけど）を乗せたいとおもった次第です。

## まずは結論から
to ChatGPT : Arduinoで、floatをbyte配列に分割格納するには?
```cpp
float value = 3.14159; // 分割するfloat値

byte* bytes = (byte*)&value; // float値の先頭アドレスをbyteポインタにキャストする

for (int i = 0; i < sizeof(value); i++) {
  byte b = bytes[i]; // ポインタからbyte値を取得する
  // 取得したbyte値を何らかの方法で格納する
}
```

素晴らしい！
もうなんてシンプルなんでしょ！！

付け加えてエンディアンの注意事項まで回答してきてくれるので、もうそりゃ人類はAIがかわいく見えて仕方なくなるわけですｗｗｗ
（たとえその様に仕組まれているとわかっていようとも・・・）



ちなみに後述のため、失敗談も載せておきます。
## すぐに思いついた方法「1byte毎シフトして格納」
ArduinoのFloatが4byteデータなので・・・
```cpp
float value = 3.14159;
byte Data[] = {0,0,0,0};
Data[0] = (byte)((value & 0xff000000) >> 24);
Data[1] = (byte)((value & 0x00f00000) >> 16);
Data[2] = (byte)((value & 0x0000ff00) >> 8);
Data[3] = (byte)((value & 0x000000ff) >> 0);
```
はい、これだとArduino IDEのコンパイラがFloat、intのデータキャストできんと文句言ってきます。

もしかすると、配列にしなければ上手くいくのか？？？
今度試してみようか・・・

勿論、単に取得したFloatデータをそのままSerialライブラリ使って送信したいなら、
## floatを共同体で宣言すして利用する方法
```cpp
typedef union {
  float value;
  byte bytes[4];
} uf;

uf uf1;
uf1.value = 3.14159;
Serial.write(uf1.bytes, 4);
```
というものありますかね。

でもAIが出したのがシンプル過ぎてね。
wemosでalexaデバイス その8

# 概要
wemos d1で、alexaデバイスを作ってみる。
amazonでsmart ir リモコン買ってみた。
bluetoothは、無いタイプ。

# セットアップ手順

# tuya smart アプリ

- Google Playで「Tuya Smart」アプリを検索し、インストールしてください。
- アプリを起動して、新しいアカウントを作成してください。
- デバイスのリセットボタンを押します。
- アプリの＋をクリックして、デバイスを追加します。
- wifiのssid,pass要求される。
- Smart IRとなる。
- リモートコントロールを追加 -> テレビ -> パナソニック
- プロフィールをクリック -> サードパーティー音声サービス -> alexa

# Alexaアプリを開く
- スマートホームスキルに「Tuya Smart」を追加

# アレクサで実行

「アレクサ、テレビを点けて」
「アレクサ、テレビのチャンネル、４にして」
「アレクサ、テレビのボリューム、一つ上げて」

以上。
[GAS] clasp push による上書きを安全にする方法

## 概要
Google Apps Script（GAS）を開発する際には、クライアント側にある GAS エディタ上で作業を行い、clasp コマンドでサーバー側にアップロードします。clasp push コマンドを使うことで、サーバー側のスクリプトを更新することができます。しかし、誤って重要なスクリプトを上書きしてしまうことがあるため、注意が必要です。
そこで、今回は clasp push による上書きを安全にする方法を紹介します。

## 手順
具体的には、以下のような手順を踏みます。

1. ローカルのリポジトリに変更を一時保存するために、一時的なコミットを行います。
2. バックアップ用のブランチを作成し、現在のHEAD^（1つ前のコミット）をリセットします。
3. clasp pull コマンドで、サーバー側のスクリプトをローカルにダウンロードします。
4. 変更を追加して、バックアップ用のブランチにコミットします。
5. 変更を GitHub に push して、バックアップ用のブランチに保存します。
6. main ブランチに戻り、先ほどの一時的なコミットを取り消します。
7. clasp push コマンドで、変更をサーバー側にアップロードします。
8. 以下は、シェルスクリプトの例です。上記の手順を自動化しているため、手動で行う必要はありません。


```shell:backup_and_push.sh
#!/bin/bash

set -eu

function error_exit() {
  echo "[ERROR] $1"
  exit 1
}

# clasp push バックアップ用
git add .
git commit -m "仮コミット" || error_exit "failed to commit changes"

# backupブランチにGASエディタのデータバックアップ
if git checkout -b "backup"; then
  git reset --hard HEAD^ || error_exit "failed to reset HEAD"
  clasp pull || error_exit "failed to pull scripts from the Clasp server"
  git add . || error_exit "failed to add changes"
  git commit -m "push時のバックアップ" || error_exit "failed to commit changes"
  git push origin HEAD || error_exit "failed to push changes"
else
  error_exit "failed to create backup branch"
fi

# 元に戻してclasp push
if git checkout main; then
  git reset --soft HEAD^ || error_exit "failed to reset HEAD"
  clasp push || error_exit "failed to push scripts to the Clasp server"
else
  error_exit "failed to switch to main branch"
fi

# 全て成功したらbackupブランチを削除する
git branch -D backup || true

```


## 最後に
上記のシェルファイルを下記のようにpackage.jsonで独自のコマンドにしてあげてpushする時は、`npm run push`などをしてあげたら、誤ってスクリプトエディタ上のコードを消してしまうことがなくなります！
余談ですが、.clasp.jsonファイルなどを別で管理することで既存の`clasp push`を実行できないにしてより安全性を保つとかが良いのかなと思いました。

```json:package.json
{
	"scripts": {
		"push": "bash backup_and_push.sh"
	},
}
```

ローカル環境下での、よきGAS開発を！！
idで指定する

# idで指定する
IDセレクタ
ID（固有の識別名）を使った指定では、1つの要素にだけスタイルを適用させることができます。

要素のIDは、id属性で指定することができます。
```css
#example { color: red; }
```
上記の例では、example というIDが付けられた要素にだけ、このスタイルが適用されることになります。

1つのIDは、同じ文書内で1ヵ所にだけ使用できます。（重複させてはならない）
指定方法
要素名に続けてID名を指定する方法と、ID名だけで指定する方法があります。どちらの場合も、ID名はハッシュ（ # ）に続けて記述します。

```css
h1#example1 { color: red; }
#example2 { color: blue; }
```

example1 と example2 の部分がIDになります。

# 出典
https://www.tagindex.com/stylesheet/basic/format3.html#:~:text=ID%E3%82%BB%E3%83%AC%E3%82%AF%E3%82%BF,%E3%81%AB%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82

# CSSでidは使わない方が良い？
```前述した詳細度の仕組み的に、idは基本使いません。```

有名なCSS設計で、特定条件では使っても良いとしているものもありますが、使うことのメリットは特にありません。

もちろんページ内リンクの飛び先になるタグにはidが必要です。それでもidにはスタイリングしな方が良いです。

<header id="header" class="header">...</header>
スタイリングが必要な場合、このようにして.headerに書きます。

IdをJavaScriptのフックに使う方もいます。

<div id="js-kv-slider">...</div>
JavaScriptを書く際にはこのidを指定します。この使い方は特に問題ないです。ただし、#js-kv-sliderにスタイリングをするのはNGです。あくまでJavaScriptのフックのためのidです。

JavaScriptのフックでもclass=”js-kv-slider”のようにclassで指定しても良いです。

# 出典
https://moshashugyo.com/media/css-naming-rules#:~:text=specificity-,CSS%E3%81%A7id%E3%81%AF%E4%BD%BF%E3%82%8F%E3%81%AA%E3%81%84%E6%96%B9%E3%81%8C%E8%89%AF%E3%81%84%EF%BC%9F,%E3%81%AE%E3%82%88%E3%81%86%E3%81%ABclass%E3%81%A7%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%A6%E3%82%82%E8%89%AF%E3%81%84%E3%81%A7%E3%81%99%E3%80%82,-CSS%E3%81%AE%E5%91%BD%E5%90%8D

# 感想
まだまだ知らないことばかりだ。
cssの参考書があった方がいいな。
マルチスレディングによるglue並列処理

はじめに
-
AWS GlueはETLに特化したサーバレスサービスです。
データの検出・変換・移動など、様々なコンポーネントが存在しますので、ETLパイプラインの構築をより容易にします。

この記事では、マルチスレディングによるGlue処理（pyspark）の高速化について説明します。

Glue内でETL処理を実装する時、同じデータソースから複数の異なるデータの出力が必要になるケースがあります。
これはパフォーマンスのボトルネックを引き起こす場合が多いです。

ボトルネックを解消するため、各出力データに対してGlue jobを作成すれば作業を並列に実行することは可能です。
但し、時には非効率的になる可能性があり、出力対象を定義できない場合は作成が難しいです。

この場合、単一のGlue job内部にマルチスレッドを使用して、Sparkのスケジューラを設定することで、
多数のジョブをSparkに並列に提出します。

Spark Job
-
Spark Applicationは、複数のjobを実行して目標を達成します。
jobはstageを経てtaskというより小さい実行単位に分けられます。
このtaskは複数のexcutorに実行を要請することでtaskが並列に処理されます。

基本的に、SparkのスケジューラーはFIFO方式でjobを処理します。
つまり、1つのjobで生成された多数のtaskをexecutorに実行を頼んで結果を受け取りながら、jobのすべてのtaskが完了するまで繰り返します。

pyspark実装
-
jobを並列に処理するためにはSparkのスケジューラをFAIR方式に設定する必要があります。
`spark.scheduler.mode`を`FAIR`に設定し、pool環境の構成ファイル(`fairscheduler.xml`)を提供する必要があります。
> fairscheduler.xmlを提供しないと、Glueコンテナがスケジューラ設定をスキップしますのでご注意ください
```python
from pyspark.context import SparkConf, SparkContext

...

self.conf = SparkConf()
self.conf.set('spark.scheduler.mode', 'FAIR') \
         .set('spark.scheduler.allocation.file', 'fairscheduler.xml')
self.sc = SparkContext(self.conf)
self.glue_context = GlueContext(self.sc)
```
この後、マルチスレッド環境で各jobをスケジューラのpoolに提出することで、jobを並列に処理できます。
```python
from concurrent.futures import ThreadPoolExecutor

def first_pool(self, df):
    self.sc.setLocalProperty('spark.scheduler.pool', 'first')

    # データ処理
    ...

    self.sc.setLocalProperty('spark.scheduler.pool', None)
def second_pool(self, df):
    self.sc.setLocalProperty('spark.scheduler.pool', 'second')

    # データ処理
    ...

    self.sc.setLocalProperty("spark.scheduler.pool", None)

...

with ThreadPoolExecutor(max_workers=2) as executor:
    executor.submit(self.first_pool, df=df)
    executor.submit(self.second_pool, df=df)
```
下記は`fairscheduler.xml`の中身の例です。
```xml
<?xml version="1.0"?>
<allocations>
    <poolname="first">
        <schedulingMode>FIFO</schedulingMode>
        <weight>1</weight>
        <minShare>2</minShare>
    </pool>
    <poolname="second">
        <schedulingMode>FIFO</schedulingMode>
        <weight>2</weight>
        <minShare>3</minShare>
    </pool>
</allocations>
```
* schedulingMode:
    * poolにあるjobの処理方式です
* weight:
    * poolに割り当てられるリソースの重み付けです。
    * 高く設定することで、該当のpoolを優先的に処理できます。
* minShare：
    * weightとは別で、各poolに割り当てられる最小CPUコア数です。
    * スケジューラは重み付けに基づいて追加のリソースを配布しますが、その前、常にすべてのminShareを満たそうとします。

pool環境を調整することで、作業を効率的に処理できます。

おわりに
-
GlueでSparkのスケジューラを設定して、各jobを並列に処理することを調べました。

但し、一般的な状況だと、各jobを効率的にパーティショニングすることで十分FIFO方式でも処理効率を高めることができます。
多数のjobを処理し、パーティショニングに困難がある場合に限り、jobの並列処理を検討することができそうです。

参考
-
https://spark.apache.org/docs/latest/job-scheduling.html
UiPath StudioWeb(Integration Service)を使ってTeamsにメッセージを送る

前提として2023年3月末時点の検証結果。機能改修によって最新版では変わっているかもしれません。
# 背景
業務の中でTeamsの利用が増えてきた。同僚とのやりとりもメールからTeamsに変化してきた。
ロボットの動作も、以前はメール中心に通知をしていたが、Teams通知したくなった。

# TeamsのID
TeamsのID取得を苦労したので備忘録として記載。
私は今回個人のチャット宛にメッセージを送ろうとしたが情報が少ない。チームIDやチャネルIDのは容易に見つかった。

https://qiita.com/yamad365/items/e480f77e9102b132d258

# チャットIDの取得方法
TeamsのWebから確認可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707463/d5fcdebd-0afe-16b4-1c68-bf292eec5b70.png)
この画面からサインインする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707463/f6b647a2-bafa-c87a-0045-ef1696062b3d.png)
当該のチャットに移動してURLを確認
conversationsの後のZZZがチャットID
```
* https://teams.microsoft.com/_?culture=XX&country=XX#/conversations/ZZZ?ctx=chat
```

# 実装イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707463/ddd5b733-1832-de56-f0f5-4ded253ce224.png)
UiPath Studio WebでTeamsのSend chat messageを選択
たぶんStudioだとActivityをダウンロードするやり方になると思う（未検証）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707463/ce12f7d6-3a56-c04d-2fd8-9904f681afcc.png)
Chat IDに先ほどのURLからとってきた値を入れる。

仮に以下のURLだった場合に、Chat IDは123:abcdefghijklmnとなる。
/conversations/123:abcdefghijklmn?ctx=chat

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707463/38da739d-b21d-3059-f936-9f5d5d7e4921.png)
正しくメッセージを送付出来た。
AndroidStudio ボタンで画面遷移

 
初学者です。Android studioでボタンを押すと次の画面へ切り替わる方法を学習しました。

#### ◇xml
xmlにButtonをいれ、onClickにメソッド名を決めます。
```
 <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/btn_next"
        android:layout_marginTop="80dp"
        android:onClick="toNext"/>
```

#### ◇Activity
Activityはintentで画面遷移をします。xmlのonClickで決めたメソッドの中にintentを入れます。
```
public void toNext(View view) { 
Intent intent = new Intent({今の画面Activity名}.this, {次の画面Activity名}.class);
        startActivity(intent);
}
```
#### ◇AndroidManifest
1番目の画面がtrue、 2番目の画面以降はfalseにします。

```
        <activity
            android:name=".{2番目以降の画面Activity名}"
            android:exported="false" />
        <activity
            android:name=".{最初の画面Activity名}"
            android:exported="true" >
```

#### ◇動きました！

![2023-03-30-17-05-28.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/842570/6cc689cd-0f2a-5282-3f02-ef3433f1c01c.gif)

参考にさせていただきました：
https://codeforfun.jp/android-studio-how-to-set-button-click-event-with-java/
https://zenn.dev/yass97/articles/26e3f92a0d7d0d
https://akira-watson.com/android/activity-1.html
https://codeforfun.jp/android-studio-quiz-game-7/
cursor

# cursor
cursor は CSS のプロパティで、マウスポインターが要素の上にいるときに表示されるマウスカーソルの種類を設定します。

```css
  .open {
      cursor:pointer;
  }
```
# 出典
https://developer.mozilla.org/ja/docs/Web/CSS/cursor

# 感想
すごい。