OmniAICreator/Qiita-1.07M huggingface dataset:
dotnetのカウンター説明（一）



dotnetでは、一般的に使用される指標の収集は以下の通りです：

System.Runtime カウンター

Microsoft.AspNetCore.Hostingカウンター

Microsoft.AspNetCore.Http.Connectionsカウンター

Microsoft-AspNetCore-Server-Kestrelカウンター

System.Net.Httpカウンター(.NET5より利用可能)

System.Net.NameResolutionカウンター(.NET5より利用可能)

System.Net.Securityカウンター(.NET5より利用可能)

System.Net.Socketsカウンター(.NET5より利用可能)

以下のコマンドで、希望する指標を監視することができます。例えば、Microsoft.AspNetCore.Hostingの場合：

```

dotnet-counters monitor -n websample --refresh-interval 1 --counters Microsoft.AspNetCore.Hosting

```

また、より小規模な監視も可能で、--counters パラメーター[]内の項目は、後で各指標()内の項目であり、複数の指標をカンマで分割して指定できます：

```

dotnet-counters monitor -n websample --refresh-interval 1 --counters Microsoft.AspNetCore.Hosting[total-requests,requests-per-second]

```

System.Runtimeは非常に重要なカウンターです。

これはアプリケーションの実行環境のリソース収集を担当し、CPU指標、メモリヒープ指標、スレッド指標などを含みます。続いて、具体的な指標の意味を見ていきましょう。一部の指標を除き、全て.net core 3.1です。

コマンド：

```

dotnet-counters monitor -n websample --refresh-interval 1

```

ビュー：

![alt 画像](https://mmbiz.qpic.cn/mmbiz_png/4CAA63nvHRAAZjMQicCNAjEImXkZ0vsdXDYd8lWWBuIAd6n2zUbuzAT3wcjiasp1Cc9LagDhmGh9rFG3KG215j1w/640?wx_fmt=png)

指標：

% Time in GC since last GC (time-in-gc)	

前回のGCが終了してからのこの期間における現在のGC時間の割合

Allocation Rate (alloc-rate)	

秒ごとのマネージヒープ割り当て量(B)

CPU Usage (cpu-usage)	

 CPU 使用率

Exception Count (exception-count)	

秒ごとの例外数

GC Heap Size (gc-heap-size)	

GC ヒープ割り当て量(MB)

Gen 0 GC Count (gen-0-gc-count)	

 秒ごとの0 世代 GC 回数

Gen 0 Size (gen-0-size)	

0 世代 GC のバイト数

Gen 1 GC Count (gen-1-gc-count)	

秒ごとの1 世代 GC 回数

Gen 1 Size (gen-1-size)	

 GC のバイト数

Gen 2 GC Count (gen-2-gc-count)	

秒ごとの2 世代 GC 回数

Gen 2 Size (gen-2-size)	

2 世代 GC のバイト数

LOH Size (loh-size)	

ラージオブジェクトヒープのバイト数

POH Size (poh-size)	

ピンされたオブジェクトヒープのバイト数

GC Fragmentation (gc-fragmentation)

GCヒープの断片化率

Monitor Lock Contention Count (monitor-lock-contention-count)

秒ごとのロック競合回数

Number of Active Timers (active-timer-count)	

アクティブなタイマーの数

Number of Assemblies Loaded (assembly-count)	

ロードされたアセンブリの数

ThreadPool Completed Work Item Count (threadpool-completed-items-count)	

 秒ごとのThreadPool完了タスク数

ThreadPool Queue Length (threadpool-queue-length)	

現在ThreadPool内のタスク数

ThreadPool Thread Count (threadpool-thread-count)

現在ThreadPool内のスレッド数

Working Set (working-set)	

現在のプロセスが使用するメモリ(MB)

IL Bytes Jitted (il-bytes-jitted)	

JIT コンパイルされた IL の総バイト数(.net5より)

Method Jitted Count (method-jitted-count)	

JIT コンパイルされたメソッドの総数(実際にはこの指標を見ていない)(.net5より)

GC Committed Bytes (gc-committed-bytes)	

GCのデータ量(MB)(.net6より)

（注：以上は個人の理解に基づいて翻訳されたもので、不正確な部分については訂正をお願いします）

(Translated by GPT)

元のリンク：https://mp.weixin.qq.com/s?__biz=MzA3NDM1MzIyMQ==&mid=2247484472&idx=1&sn=4a96b9bad9e9d2c6a66610ae5d42eb90&chksm=9f005b12a877d2046f12ad48f9a139089b022d12163e8880da6c26a8234a63f7522142fffa60&token=418912929&lang=zh_CN#rd
MacでFlutterのビルド時に"Error (Xcode): Target debug_unpack_ios failed: ..."が発生する

## 状況
MacでFlutterの新規プロジェクトを作成し、iOSシミュレータで実行しようとしたところ以下のエラーが発生しました。
<pre>Failed to build iOS app
Error (Xcode): Target debug_unpack_ios failed: Exception: Failed to codesign /Users/(中略)/build/ios/Debug-iphonesimulator/Flutter.framework/Flutter with identity -.

Could not build the application for the simulator.
Error launching application on iPhone 15 Pro.

Exited (1).</pre>

## 環境
* macOS Sonoma 14.2.1
* Flutter 3.16.9

## 原因と対策
プロジェクトを「書類」ディレクトリに作成しており「書類」をiCloud同期する設定にしていることが原因でした。同期設定したディレクトリはビルド用ディレクトリとして適さないようです。

### 対処法1
プロジェクトディレクトリを「デスクトップ」「書類」以外のローカルな場所に作成します。

### 対処法2
システム設定アプリ→自分の名前(Apple ID)→iCloud→iCloudドライブ→"デスクトップ"フォルダと"書類"フォルダをオフにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632965/8b8bfc16-a265-faff-3a9a-2db6cb40bec8.png)

## 補足
一般的に開発用ディレクトリはホームディレクトリ直下などに作成することが多いと思います。

クラウドストレージやネットワーク上のディスクは、日本語のディレクトリ/ファイル名などと同様意図しない不具合が発生することがあるので避けるのが無難です。

今回はバックアップの目的も兼ねてあえてiCloud同期の「書類」フォルダを使ってみましたがやはり良くないようです。（ビルドディレクトリのように頻繁に書き換わるデータを置くことにそもそも無理がありそうですが）

開発ディレクトリはローカルに置いて、バックアップはTime MachineやGit等他の手段を組み合わせて行いましょう。
asp.net core監視—Prometheusの導入（六）

このシリーズの以前のブログ記事では、カスタムビジネスカウンタのステップについて説明してきました：
1. ビジネスを分析し、モニタリングとトラッキングの指標を計画する
2. 指標コレクターを定義する
3. プログラミングに侵入する（開発時にビジネスの実装とモニタリング認証の収集コードを可能な限り分離する）指標を収集する
4. Grafana展示テンプレートを開発し、表示を完了する
「asp.net coreモニタリング—Prometheusの導入」の2、3、4、5の4つのテンプレートのデモを合わせて、これらのステップをより深く分析、理解します。
このシリーズはPrometheusとGrafanの組み合わせで、この組み合わせはシステムのリアルタイムトラッキングデータの表示に長けていますが、統計データの場合、必ずしも最適な選択とは限りません。
1. ビジネスを分析し、モニタリングとトラッキングの指標を計画する
これは最も難しい部分で、まず自分のプロジェクトが解決する主要な問題が何であるかを理解する必要があります。例えば、オンラインショップの最優先事項は商品を売ることで、ある期間内に何をどれだけ売り、どれだけのお金を稼いだかは非常に重要です。それから、ある期間内に何の商品がよく売れたか、ある期間内にユーザー数がどれだけ増えたかなど、比較的次に重要な問題を考えます。ローマは一日にして成らず、重要なことから始めて徐々に自分のモニタリングトラッキングシステムの構築を進めることをお勧めします。
2. 指標コレクターを定義する
このシリーズの記事で述べられたPrometheusの4種類のコレクターについて、計画されたモニタリング指標に基づいて適切なものを選択します。一般的に、Counter（カウンタ）とGauge（ゲージ）は直感的で分かりやすく、Histogram（ヒストグラム）とSummary（サマリー）は抽象的ですが、ビジネス状況をマクロから示し、統計学的により科学的です。
3. プログラミングに侵入する（開発時にビジネスの実装とモニタリング認証の収集コードを可能な限り分離する）指標を収集する
この部分では、デモで共有している事例がありますが、最適な解決策ではないかもしれません。この部分は、プロジェクトのアーキテクチャに応じて処理する必要があります。モニタリング、ログ、トラッキングなどのビジネス以外の機能をビジネスコードから分離し、カップリングを減少させるように努力します。一方で、一部のモニタリングデータはビジネスシステムと密接に結合している場合があります。例えば「asp.net coreモニタリング—Prometheusの導入（三）」のGauge（ゲージ）では、注文の各段階の数量を表示していますが、これは正確ではありません。なぜなら、システムが再起動すると、これらの値はゼロにリセットされるからです。コードを変更し、システムを起動するたびにデータベースから注文の各段階の数量を検索してゲージを初期化することは表面的に可能ですが、システムが分散配置されている場合、各ノードまたはPodがデータのコピーを持つという問題が生じます。Grafanaで集中的に表示する際には、ノードを加算してデータが重複することになります。システムが稼働した後、各注文、支払い、出荷がトリガされるのは、ノードごとのゲージ上の数値の変化であり、このようにして、ある期間稼働した後は、データが倍数関係でも増量関係でもなくなります。しかし、よく分析すると、各注文のリアルタイムの量は、アプリケーション内で加減算を行って値を外部に出すことには適していません。データベースやキャッシュのデータソースを別にして検索して表示することができます。俗に言えば、一本の木にしがみついてはいけません。私たちは、Grafanaの異なるパネルのデータソースが独立しているという特徴を利用し、それぞれを区別して扱う必要があります。
4. Grafana展示テンプレートを開発し、表示を完了する
これは技術的な作業です。まず、Grafanaの使用方法に慣れる必要があります。Grafanaに関する記事はまだたくさんあります。Grafanaでは、異なるデータソースからのデータの取得方法が一致しない場合があります。これは学習のポイントです。また、Grafanaのいくつかの関数も良い選択肢で、関数の自動提示機能を使えば、設定がより簡単になります。さらに、異なるパネルタイプには多くの属性があり、私たちのグラフに彩りを添えることができます。より多くの探求と研究が必要です。
「asp.net coreモニタリング—Prometheusの導入」シリーズはこの記事で終わります。私の粗い理解をみなさんと共有するに過ぎません。指摘を歓迎します！

(Translated by GPT)

元のリンク：https://mp.weixin.qq.com/s?__biz=MzA3NDM1MzIyMQ==&mid=2247483789&idx=1&sn=a2cb5bf097f1804fd980652042e42fc5&chksm=9f005ea7a877d7b102f6cbdb46a7ab272bbf9ae1a2fe6ae3bde93a707400bc2d8f9f23b68516&token=418912929&lang=zh_CN#rd
値の最頻値を残して重複を削除する(SPSS Modeler データ加工逆引き7-20)

# 値の最頻値を残して重複を削除する（代表価格の算出）

![スクリーンショット 2024-02-12 14.58.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/d668099e-29fa-fbb2-6761-09c495dcc1d5.png)

## 1.想定される利用目的

・事実上の定価（代表価格）の算出

## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/raw/main/most_freq.str

## 3.サンプルストリームの説明

![スクリーンショット 2024-02-15 14.46.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/ff273a73-eef1-394f-7e70-3f1d69cf674b.png)

a.入力するデータは以下の通りです。　顧客の商品購入履歴情報の一部です。

![スクリーンショット 2024-02-12 14.58.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/a514e994-998e-d7a9-cdb6-649132a1132a.png)

b.[重複]ノードを編集します。[グループ化のキーフィールド]は[商品]を選択します。

![スクリーンショット 2024-02-12 14.59.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/477a5964-9a7b-44bd-2afd-a50638dfb3ce.png)

[複合]タブで[次を基準とする値を入れる]に[カスタム...]を選択します。
![スクリーンショット 2024-02-12 14.59.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/b18180b8-14cf-fe6d-7cb0-bab5399e7a73.png)

[出現頻度で選択]を選びます。[使用]に　[最も高い頻度]を　[結合基準]には[最後を使用]を選びます。

![スクリーンショット 2024-02-12 15.00.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/d34cf9c6-1fcb-f36d-bdd0-90c99ada1602.png)

以下のように設定されます。

![スクリーンショット 2024-02-12 15.00.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/53dc77c0-df5e-d2d8-5bbc-14544832cc14.png)

[テーブル]を実行します。

![スクリーンショット 2024-02-12 15.01.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/6c080485-360b-cccb-3ce0-868e409ff91b.png)

#### 注意事項

最大値を定価とする場合もありますが、誤った値が偶発的に含まれることを想定して最頻値をを紹介しました。

[価格]を連続値にしておくとカスタムで最頻値選択ができません。入力時に[順序尺度]のようなセット値（カテゴリデータ）　にしておく必要があります。

![スクリーンショット 2024-02-12 15.01.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/b02f24aa-6897-9a66-c425-daa87f7e4b75.png)


## 4.参考情報

#### 重複する不要なレコード（行）を削除する

https://qiita.com/416nishimaki/items/99ab1340079275fdeb61

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/private/4bf813e6cba84b2a1008
本番へ新規項目をリリース時、Limit Exceededエラーが発生

## エラー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634241/cbeb0957-3409-82b1-7ad6-90d8632417f4.png)

## 原因
管理者が不要な項目をUIから（論理）削除したが、組織のバックグラウンドに「削除済み項目」のメタデータが残っていて、十分な領域がないため、新たなカスタム項目の作成時にエラーが発生しています。

## 対策
１． 物理削除処理で領域が開放されるまで待つ
２． お急ぎの場合は手動で領域解放処理（物理削除処理）をSalesforce社に実施してもらう

## Salesforce社からの回答
本エラーはすでにご認識の通り、組織のバックグラウンドに削除済み項目のメタデータが残っており、カスタム項目を作成するのに十分な領域がないために、パッケージのインストールなどによるカスタム項目の作成時にエラーが発生しているとお見受けします。

早期の解決をご希望とのことですので、当サポートにて物理削除の対応をいたします。

サポートでの物理削除の実行時に必要な情報として、以下ヘルプの抜粋部分がございますが、お客様より現時点で以下情報いただいておりますので、お間違い無いかご確認のうえ、以下情報を合わせてご教示いただけますでしょうか。

エラーメッセージ：Limit Exceeded
対象の組織ID：xxxxxxxxxx
対象オブジェクト：「⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎」

物理削除の実施を許可いただけるユーザーのユーザー名：
※「システム管理者」からのご許可を明示いただくために必要な情報となります。「システム管理者」ユーザーのユーザー名をご教示ください。

なお物理削除の実施にはお時間を頂戴する場合がございますので、ご理解いただければ幸いです。

## 結局
依頼後、該当組織のバックグラウンドジョブを確認したところ、下記のジョブが実行されていることを確認しました。
>Cleanup of custom field data when a custom field definition is hard deleted

上記処理は物理削除によるカスタム項目の領域開放の処理です。

そのジョブ実行完了後、新規項目はうまくリリースできるようになっています。

## 関連記事
https://help.salesforce.com/s/articleView?id=000382649&type=1
Adobe Acrobat Signのまとめ

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめA～M](https://qiita.com/Keiji_otsubo/items/f3ddedee6793bf1576f8)


+ [Getting an error 'Invalid user ID or email provided in x-api-user header' while sending agreement from Salesforce. | Adobe Sign](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000JfyzTSAR)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/7429ebfc-dbf4-1391-430c-47102526fb82.png)


:::note
Salesforce の apex からの契約送信: x-api-user ヘッダーに指定されたユーザー ID または電子メールが無効です。

Salesforce sending agreement from apex : Invalid user ID or email provided in x-api-user header.

https://community.adobe.com/t5/adobe-acrobat-sign-discussions/salesforce-sending-agreement-from-apex-invalid-user-id-or-email-provided-in-x-api-user-header/td-p/10363851
:::

+ [Ending position out of bounds: 0](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000SXIuv)

:::note
Update - the error was caused because one of the SF fields I was trying to map was not a string, but instead a formula (string). It appears that all SF fields used in merge mapping must be of the string data type. 

追記 - マッピングしようとしたSFフィールドの1つが文字列ではなく、数式（文字列）だったため、エラーが発生していました。マージマッピングで使用するSFフィールドはすべて文字列データ型である必要があるようです。
:::


# 未解決

+ [Adobe Sign カスタムオブジェクトからのマッピングの結合](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000HmOO1)
Pandasによるデータ整理の基本



## はじめに
Pandasによるデータ整理の基本に関しての備忘録です。
コードを書き始めて1年以内の若輩者です😅
もし間違いがあれば、ご指摘いただけると助かります🙇
<br>
## 🦁<INS>**結論**</INS>🦁
データ操作の基本のきの字になるもの。
整理することで正しく行う事で分析につながる。

:::note info
押さえておくべき点
* 列や行の操作時のinplaceパラメータの意識的な使用が必要。
:::  
***

:::note alert
注意点
*  データを変更する操作を行う前には必ずバックアップを取る必要がある。
:::  

***

## <INS>**基本のデータ整理コード一覧**</INS>


## <INS>**.rename()**</INS>
列名を変更することができる。
辞書型で古い名前をキー、新しい名前を値として指定できる。

inplace=True を指定すると、元のDataFrameが直接変更される。
列だけでなく、インデックス名の変更にも使用できる。
```py
df.rename(columns={'old_name': 'new_name'})
```
***  

## <INS>**.astype()**</INS>
列のデータ型を変更できる
文字列型の列を数値型に変換したい場合などに使う
変換先のデータ型を正確に指定する必要がある（例: 'int64', 'float', 'category'）
```py
df['column_name'] = df['column_name'].astype('desired_type')
```
***  

## <INS>**列の追加**</INS>
単純に新しい列名を指定して値を代入。
条件に基づいて新しい列を作成する場合は、.apply() や .map() メソッドが便利。
```py
df['new_column_name'] = value_or_array
```
***  

## <INS>**drop()**</INS>
列を削除することができる。
axis=1 を指定することで列の削除を示せる。
※axis=0は行
行を削除する場合は、ラベル（インデックス）を指定する必要がある。
```py
df.drop('column_name', axis=1, inplace=True)
```

## まとめ✍️
基本だが、データが消してしまったり、データを崩したりすることには注意を払わないといけないなと感じた。
EKS on FargateにおいてPodを明示的に（確実に）AZを跨ぎ実装する方法

FargateにおけるPodの配置計画は `Fargate Profile` を用いて管理する。

掲題の問題は2つの問題を分離して考える必要がある。
- Fargate(Node)がどのAZ（Fargate profileで指定するのはsubentだから、実際はsubnet)に配置されるか
- PodがどのNodeで構築されるか


# 前提知識

## k8s スケジューリング(どのNodeにPodを配置させるか
- nodeSelector
- Node Affinity, Node Anti-Affinity
- Inter-Pod Affinity, Inter-Pod Anti-Affinity


## AWS
<details><summary>Fargate profile</summary>
目的: Selector（namespace, tag)を指定して、該当PodをFargate上で起動させる
FargateをどのAZに配置するかは管理してないのでは？


</details>

<details><summary>妄想</summary>
Stateful setでPodを実行させ、Pod名をtagにいれる。(Statefule setではpod名の末尾に連番が振られる
→ selectorにtagとして、`pod名-0`, `pod名-1`を指定したprofileを作成する。このprofileではAZを一つだけ指定する。
</details>
AWSぜみ内容

現状のデータ分析の基盤について
ほかの顧客データなどを実際に活用するハードルは結構高いのでは
→実際にTableau（タブロー）を導入したばかりであり、すぐにQuicksightが使われるわけではない　　
実際にサービス評価も行われている、まだ確認できていないが

最初に今回あまり調査実施できませんでした、、
AWS CLIでログデータのデータレイク作ろうとしたらうまく行かなくて、、あまり他の調べができませんでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3688241/cce7121f-0ca3-fc29-9830-e5b807bd4aad.png)






一方でAWS内のサービスにおいて分析を行うサービスであれば使いやすいのでは？aws
ログ分析を行う基盤など
→Amazon Detective、Security Lakeなどあるが、、

AWS上のアプリケーションでのセキュリティ問題や不審なアクティビティなどがあった際に原因を分析・調査することを支援するサービス

Amazon Security Lake は、AWS 環境、SaaS プロバイダー、オンプレミス、およびクラウドソースからのセキュリティデータを、アカウントに保存されている専用データレイクに自動的に一元化します


security lake 
データアクセス

クエリアクセス


athena + quicksigtの使用例

S3からとってきていたが今回顧客のデータを使うなどは難しい
ログやセキュリティの情報を分析するのについては顧客データよりハードルが下がるのでは？
企業規模のセキュリティデータ分析における課題
を解決するためのセキュリティに特化したデータレイクサービス
であるSecurity lakeがある、しかもこれはAthenaで分析かのうである、またGlueも使用可能であり

glue+athena+quicksightでのセキュリティの分析がすぐに可視化できるようになる
QuickSight でデータを視覚化するために Security Lake からクロスアカウント共有を設定する方法と、使用される関連する Athena クエリについて説明します。ログデータを視覚化ワークロードから分離することがベストプラクティスであり、QuickSight 視覚化には別の AWS アカウントを使用することをお勧めします。アーキテクチャの高レベルの概要を図 1 に示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3688241/5fb796f5-8844-d21e-d2a8-86e6f8399694.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3688241/3733528f-91f9-9046-abcf-65b001e3be53.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3688241/da653da9-2b17-b692-dcc8-84a57e663c77.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3688241/e65e7c50-1313-b299-4fb6-ebeb0d824e1d.png)

そのあとAthenaでデータベースの作成を行ってその後リソースのリンクを作成し、Athenaでクリエがじっこうできるようになる、またクリエ結果を保存するためにＳ３の指定も必要である。

その後
CREATE VIEW security_hub_new_failed_findings_by_created_time AS
SELECT
finding.title, cloud.account_uid, compliance.status, metadata.product.name
FROM "security_lake_visualization"."amazon_security_lake_table_ap_southeast_2_sh_findings_1_0"
WHERE compliance.status = 'FAILED'
ORDER BY finding.created_time
limit 100;
失敗したチェックを含む 100 件の検出結果を、検出結果の作成時刻で並べ替えてリストするビューの例です。
そのあとQuicksightでの使用がかのうである

うまくいくと以下のようなダッシュボードが作成できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3688241/7bf79b00-ec2f-5785-1509-89451236e2ba.png)

感想、Athena＋quicksightでのデータビジュアル化のことはかなり幅広く有用性があるものだといえると感じた。


https://aws.amazon.com/jp/blogs/security/how-to-visualize-amazon-security-lake-findings-with-amazon-quicksight/
【AWS】ssh接続にて「Permission denied (publickey,gssapi-keyex,gssapi-with-mic).」エラーと戦った日

こんにちは！
転職成功してからすごーく久々の投稿となります。
インフラエンジニアデビューしてからというもの業務（作業）に追われることばかりになり学習が全くできていませんでした。
本当に良くないとわかっていつつ時間の浪費に追われてしまっていました。
自分の人生なのでやりたいことをやるためにまずSAA取得から頑張ります！

話せば長くなるので本題に。


最近AWSと戦っておりましてudemyの講座で学習中。
EC2インスタンス立ち上げてパブリックサブネットにてWebサーバー構築し、プライベートサブネットにDBサーバー作成、さあsshでアクセスするぞというところでつまずきました。
秘密鍵をコピペしてログインしようと試みるも繋がらない。
エラーメッセージは以下のとおり。

<h3>Permission denied (publickey,gssapi-keyex,gssapi-with-mic).</h3>

権限つけたはずなのになにかがおかしいい。
コピペ元のpemファイルを確認すると以下のように記述されていた。


<h3>
-----BEGIN RSA PRIVATE KEY-----
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx（鍵部分）<br>
-----END RSA PRIVATE KEY-----
</h3>


コピーしたところを確認するとxxxx～の部分だけ。
もしかしてと思ってヘッダーとフッターのところも入れてみる。

すると成功。
BEGINて書いてあるところからBEGINということだったらしく、くだらないことで1時間ぐらいハマりました。

まだまだ道のりは険しい。
明日も頑張るぞ。
GitHub Actions で一つのシークレットに複数の環境変数を定義して利用する

# 背景
- GitHub Actions で複数の環境変数を参照するスクリプトを実行したい
- リポジトリシークレットで変数を定義し、ワークフローからも参照して利用可能だが量が増えると手間になる
- できるだけ楽に管理したい

# 想定環境
- pipenv を使って python スクリプトを実行する
- 環境変数は `.env` ファイルで定義

# 手順
1. リポジトリシークレットで一つの変数に複数の環境変数を定義
    ```
    VAR1=value1
    VAR2=value2
    VAR3=value3
    VAR4=value4
    VAR5=value5
    VAR6=value6
    VAR7=value7
    VAR8=value8
    VAR9=value9
    ```
1. ワークフローでシークレットを `.env` ファイルに書き出す
    ```yaml
      - name: setup environments
        run: |
          echo "${{ secrets.ENVIRONMENTS }}" > .env
    ```
1. スクリプト内で環境変数を参照する処理を記述する
    ```python
    import os
    print(os.getenv("VAR3")
    ```

# ワークフローサンプル
```yaml
name: PIPENV

on:
  workflow_dispatch:
  
jobs:
  build:
    runs-on: 任意の実行環境

    steps:
      - uses: actions/checkout@v3
       
      - name: install python
        uses: actions/setup-python@v5
        with:
          python-version: "v3.11.1"

      - name: install pipenv
        run: |
          python -m pip install --upgrade pip
          python -m pip install pipenv=="2023.4.29"

      - name: setup environments
        run: |
          echo "${{ secrets.ENVIRONMENTS }}" > .env
          cat .env

      - name: pipenv
        run: |
          pipenv run python -c "import os; print(os.getenv('VAR3'))"
```

```:実行結果(直接の出力はマスクされる)
Run echo "***
  echo "***
  ***
  ***
  ***
  ***
  ***
  ***
  ***
  ***" > .env
  cat .env
  shell: /usr/bin/bash -e {0}
  env:
    pythonLocation: /opt/hostedtoolcache/Python/3.11.1/x64
    PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.11.1/x64/lib/pkgconfig
    Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.1/x64
    Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.1/x64
    Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.1/x64
    LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.11.1/x64/lib
***
***
***
***
***
***
***
***
***
```

```:実行結果(スクリプトから参照しての出力は表示されてしまう)
Run pipenv run python -c "import os; print(os.getenv('VAR3'))"
Loading .env environment variables...
(略)
value3
```

# まとめ・注意点
- 一つのシークレットに対して複数の環境変数を定義できた
- 基本的にはマスクしてくれるが、プログラムからの出力までには対応できないので、スクリプトからの出力処理には気をつける
web系開発とiOSアプリ開発の違い

## はじめに
初めまして、2月に私はエンジニアへ転身しました。
プログラミングは全くの未経験者で以前は、HTMLやCSS、PHPを扱っておりWEB系に特化してました。
プログラミング未経験と言ってもレベルは様々かと思いますが、「Swift」のスの字すらも知らないレベルからの開始です。
こんなド未経験の人でもプログラミングやっているんだ！と少しでも励みやモチベーションに繋げていただけたらと思います。

## web系開発言語とiOSアプリ開発言語の違い

今回は私が現在扱っている「Swift」と今まで扱っていたWEB系言語の「HTML・CSS」で比較をしてみました。

### 1. 言語の種類と用途

- Swift：

Swiftはプログラミング言語で、iOSアプリケーションやmacOSアプリケーションなどのネイティブアプリケーションの開発に使用されます。

- HTML、CSS：

HTMLとCSSはマークアップ言語とスタイルシート言語で、WEBページの構造とスタイルを定義するために使用されます。

### 2. 構文と文法

- Swift：

Swiftは静的型付け言語で、C系の言語に似た構文を持ちます。関数型プログラミングの概念も取り入れられています。


- HTML、CSS：

HTMLはマークアップ言語で、タグと属性を使用して文書の構造を表現します。CSSはスタイルシート言語で、セレクタとプロパティを使用してスタイルを定義します。

### 3.開発環境

- Swift：

Swiftの開発にはXcodeやSwift Playgroundなどの統合開発環境（IDE）が使用されます。

- HTML、CSS：

Webの開発にはテキストエディタや統合開発環境（IDE）が使用されますが、特に必須ではありません。
私はVScodeを使用しておりました。

### 4.デバッグとテスト

- Swift：

Xcodeを使用してデバッグやテストを行いビルドエラーやランタイムエラーのデバッグが一般的です。

- HTML、CSS：

ブラウザの開発者ツールを使用してHTMLやCSSのエラーをデバッグする。レスポンシブデザインなどのテストも重要です。

### 5. プラットフォームの違い

- Swift：

iOSやmacOSなどのAppleのプラットフォームでのみ動作します。

- HTML、CSS：

ほぼすべてのデバイスとブラウザで動作はしますが、レスポンシブデザインの考慮が必要となります。

## さいごに

今回の記事は以上になります。
エンジニアとしてはまだまだひよっこで
色々と拙い部分があるかと思いますが間違っている点、ご意見等あればご指摘いただけますと幸いです。

弊社では、経験の有無を問わず採用を行っています。
興味のある方は是非カジュアル面談しましょう！

https://jambo-support.com/recruit_engineer/

ではまたっ！
サーバー立ち上げ

1.1レンタルサーバの選定
</h3>
<h4>
費用
</h4>
<h5>
初期費
</h5>
<h5>
月額費用
</h5>
サーバ利用料
<h5>
年間費用
</h5>
SSL維持費
<br>
ドメイン維持費
![uploading...0]()
CloudFormationでEC2のインスタンスタイプをスタック更新時の不安


CloudFormationで構築したEC2インスタンスのインスタンスタイプを変更しようとした際に
少し考えたことがあったのでメモ。

# 背景

既存のEC2スタックを更新して、インスタンスタイプを変更しようとした

![cfn-ec2-instancetype01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/f453b235-8811-788a-d85b-6508df224c6c.png)

インスタンスタイプをスペックアップしていざ更新しようとした。

![cfn-ec2-instancetype02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/f3ef0999-b1fa-c5b3-c41d-befde03b0fa3.png)

チェンジセットのReplacementが`Conditional`になっている。
通常、ただのインスタンスタイプ更新であれば`False`になると思っていたが、置換されてしまうのかどうかが不安になった。

![cfn-ec2-instancetype03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/c82cbd4b-ce36-eacd-3276-afd61ed85c7a.png)

# 結論：インスタンスは基本置き換わらない

Replacementに関して、ドキュメントをあさってみると。以下のようなことが書いてあった

> キー名が変わらない場合は、InstanceType プロパティに対する変更がもっとも大きな更新動作 (Conditionally) になります。したがって、Replacement フィールドは Conditionally です。CloudFormation によってインスタンスが置き換えられる条件を確認するには、InstanceType プロパティの更新動作をご参照ください。
>
> https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-changesets-samples.html

キー名(Logical ID)が変わる場合は必ずReplacementが発生するが、そうでない場合はInstanceTypeプロパティの挙動次第で
インスタンスが置き換わるかどうかが決まるということらしい。
リンクをさらに深ぼると、InstanceTypeリソースについては、以下のような説明がある。

> When you change your EBS-backed instance type, instance restart or replacement behavior depends on the instance type compatibility between the old and new types. An instance with an instance store volume as the root volume is always replaced. For more information, see Change the instance type in the Amazon EC2 User Guide.
>
> ---
>
> EBSでバックアップされたインスタンス・タイプを変更した場合、インスタンスの再起動または置換の動作は、新旧のインスタンス・タイプの互換性に依存します。ルートボリュームとしてインスタンスストアボリュームを持つインスタンスは、常に置き換えられます。詳細については、『Amazon EC2ユーザーガイド』の「インスタンスタイプの変更」を参照してください。
>
> https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-instance.html#cfn-ec2-instance-instancetype


ルートボリュームをインスタンスストアボリュームとして利用していなければ、置換されることはないということらしい。
今時のインスタンスタイプは、全部デフォルトでEBSボリュームで作成されるはずなので、まず気にする必要はないのかなと思う。


# そもそもインスタンスストアとは？

EC2のルートボリュームの生成方法には、`EBS-backed`と`Instance store-Backed`の2タイプがある。

EBS-backedを使用するインスタンスは、EBSボリュームという外部ストレージを使ってルートボリュームを作成し、インスタンス起動時にそのEBSボリュームに自動アタッチしてくれる。
外部ストレージに保管しているので、インスタンスが停止してもデータはそのまま残る。

![cfn-ec2-instancetype04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/acf33a52-1612-97d5-57bf-26f23affaa72.png)
*AWS公式ドキュメントより拝借*

Instance store-Backedを使用するインスタンスは、インスタンス上にルートボリュームを作成し保管する方法。
インスタンス上に保存されるので、インスタンスが止まれば、ルートボリューム上のデータも削除される。

![cfn-ec2-instancetype05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/2f35efdb-2062-b215-2f0c-152744266291.png)
*公式ドキュメントより拝借*

Instance store-Backedインスタンスを使用できるインスタンスタイプは限られている

> インスタンスストアボリュームをルートボリュームとしてサポートするインスタンスタイプは C3、D2、G2、I2、M3、および R3 のみです。

詳細は以下ドキュメント参照

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/RootDeviceStorage.html


今はEBS上でルートボリュームを作成するのがデフォルト動作で、インスタンスストアボリュームを使うメリットはないと思う。
基本気にせずにインスタンスタイプを変更しても問題はなさそう。

# まとめ
Replacement: `Conditional`の際は、Conditionalとなっているプロパティを調べる
IEx.pryでデバッグ

 IEx.pry()を使うと記述した箇所で一時停止できます
 
# Brightの対象
Webアプリ開発 Elixir > クラス1 > Elixirテスト／デバッグ > デバッグ > pry


# 準備

```elixir:サンプル

 defmodule Dymn do
  require IEx # ←ここ


  def hello do
    a = 1..10
    |> Enum.shuffle()
    b = a |> Enum.sum()
    IEx.pry() # ←ここ
    :world
  end

end

```

デバックしたいソースに
・require IExを書く
・一時停止したい箇所にIEx.pry()を書く

# デバッグ実行

iex起動
```
$ iex -S mix
```
iexで操作

```elixir
iex(1)> Dymn.hello
Break reached: Dymn.hello/0 (lib/dymn.ex:9)

    6:     a = 1..10
    7:     |> Enum.shuffle()
    8:     b = a |> Enum.sum()
    9:     IEx.pry()
   10:     :world
   11:   end
   12: 

```

変数を確認
```elixir
iex(2)> a 
[7, 5, 8, 10, 3, 1, 6, 9, 4, 2]
iex(3)> b
55
```

つづきを実行

```elixir
iex(4)> respawn

Interactive Elixir (1.15.4) - press Ctrl+C to exit (type h() ENTER for help)
:world  
```

これでデバッグできました
STM32C011をMbed(Keil)で遊ぶ。なんにも動かない(20240228)(STM32C011J4M7)


目的
テスト

```

Target "DISCO_C0116" is not recognized
Internal error.
Build failed
Build failed

```

![o_cop973.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/873e9e57-61bc-6cee-a63d-f03a6982c797.jpeg)
cscの作法 その459

# 概要
cscの作法、調べてみた。
PictureButton、やってみた。

# 参考にしたページ

https://lets-csharp.com/stylish-button/

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/71980ffc-f008-04aa-4197-b4f4d48d11b9.png)


# サンプルコード

```
class form1: Form {
	form1() {
		Text = "open";
		ClientSize = new Size(200, 200);
		Button btn1 = new Button();
		btn1.Location = new Point(50, 50);
		btn1.Text = "test";
		btn1.Click += btn1_Click;
		PictureButton btn2 = new PictureButton();
		btn2.Location = new Point(40, 100);
		//btn2.BackColor = Color.Red;
		btn2.Image = Image.FromFile("C:\\Users\\User\\csc\\1.png");
		btn2.Click += btn2_Click;
		Controls.AddRange(new Control[] {
			btn1, btn2
		});
	}
	void btn1_Click(object sender, System.EventArgs e) {
		MessageBox.Show("ok");
	}
	void btn2_Click(object sender, System.EventArgs e) {
		MessageBox.Show("ok");
	}
	[STAThread]
	public static void Main() {
		Application.Run(new form1());
	}
}





```

以上。
レポートで問題になる複数選択リスト


+ [複数選択リストの検索条件について](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007XIbq3)

:::note
以下でも複数選択リストでは機能しないことが回答されています。

https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000A8X0GSAV
:::

+ [複数選択リストの値をグラフで適切に表示させるアイデアを考えています。](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007Yw0Oy)

:::note
レポートの作成で一番悩まずに済むのは、複数選択リストの値別に違うオブジェクトに１つ、１つレコードを作ることだと思います。

単に選択リストの値だけでレポートを作るのなら、基のオブジェクトのレコードを参照できるように参照項目を作ります。また、複数選択リストの部分は選択リスト（単数）かテキストの項目で作れば大丈夫と思います。

他にレポートで検索条件に使う項目あれば、それも作る必要があります。
:::
【Docker】Compose: Dockerと別物だった

# はじめに

以下の書籍と、公式のドキュメントをリソースとしております。

[Docker&仮想サーバー完全入門　Webクリエイター＆エンジニアの作業がはかどる開発環境構築ガイド](https://amzn.asia/d/iaR1hmI)
[History and development of Docker Compose](https://docs.docker.com/compose/intro/history/)

[# Announcing Compose V2 General Availability](https://www.docker.com/blog/announcing-compose-v2-general-availability/)

# Composeは、かつてDockerと別物だった

Docker Composeは、YAMLファイルを元に複数のコンテナを作成・実行できる機能です。

もともと、Dockerとは別のソフトウェアだったようです。
別物であるため、個別のインストールが必要でした。

Docker Compose V2でDokcerのコア機能として再設計され、現在の形になったようです。

# 別物だったころの名残①【docker-compose】

`docker compose up`というコマンドがありますが、
かつては`docker-compose up`と記述したようです。

コンポーズ機能がDockerの内部ではなく、docker-composeという別の仕組みであったことがわかります。

Compose V2でDockerのコア機能に統合され、現在の`docker compose`という記法になったようです。

現在でも`docker-compose`と記述することは可能であり、この記法を廃止する予定はないようです。
`docker-compose`と記述した場合は、内部的に`docker compose`と解釈されます。

なお、`docker-compose`という記法が非推奨であると明示した箇所は見つかりませんでした。
ただ歴史を鑑みると`docker compose`と記述するのが良いでしょう。

# 別物だったころの名残②【マスコットキャラクター】
Dockerには、象徴的なクジラのマスコットがいます（[Moby Dockという名前があります](https://www.docker.com/blog/call-me-moby-dock/)）。

![Moby Dock](https://www.docker.com/wp-content/uploads/2013/08/KuDr42X_ITXghJhSInDZekNEF0jLt3NeVxtRye3tqco.png)

しかし、実はCompose独自のマスコットがいるのです。

![Compose mascot](https://www.docker.com/wp-content/uploads/2022/04/octopus-compose-980x980.jpg.webp)

名前はありません。
[名前決めコミュニティ](https://github.com/docker/compose/issues/9417)は2023/06を最後に投稿がなく、公式からも忘れられているようです🥲。

話が逸れましたが、このマスコットもCompose機能が独立していた名残ですね。
# おわりに

Docker ComposeはもともとDockerに含まれておらず、Dockerをより便利にするために生まれたアディショナルな機能であるという認識はDockerの理解に役立ちそうです。

また、`docker-compose`という記法は現在でもたまに見かけるため、`docker compose`のエイリアスであると知れたことも良かったです。

ではまた。
Colimaでvz+RosettaのVMでx86用Dockerコンテナを実行する場合にはarchにaarch64を指定する

# はじめに

Apple社のMacBookがARMベースのCPU、すなわちApple Siliconへと移行して数年が経過した。現在市場に出回っている新製品のCPUはすべてARMアーキテクチャを採用している。この変化は多くの利点をもたらしたが、開発業務においては依然としてホストマシンのCPUがx86系を前提としているケースも少なくない。このような状況を踏まえ、M1 Mac上でx86用のDockerコンテナを実行し、コンテナ内でビルドを行う方法について調査を進めた。

Docker Desktop for Mac、Orbstack、そしてColimaは、M1 Mac上でDocker環境を簡易に構築できるツールである。特にColimaを使用する際に遭遇した思わぬ落とし穴について、その解決法を含めてメモとして記録する。

# Colimaでx86_64用Dockerコンテナを実行する

具体的にx86_64用のDockerコンテナを実行するプロセスと失敗について確認する。

## Colimaとは

Colimaは、Limaをベースとしたコンテナランタイムである。LimaはLinuxの仮想マシンをmacOS上で簡単に起動できるツールであり、ColimaはこのLimaを利用してDockerコンテナを扱いやすくするための環境を提供する。

- 公式GitHubリポジトリ: [https://github.com/abiosoft/colima](https://github.com/abiosoft/colima)
- Colimaの使い方に関する参考記事: [https://qiita.com/nishikyon/items/ac3eed100eb118c8af22](https://qiita.com/nishikyon/items/ac3eed100eb118c8af22)

## インストール

Homebrewを使用してColimaをインストールすることができる。以下のコマンドを実行することで簡単にインストールできる。

```terminal
$ brew install colima
```

## VMを作成

x86_64用のDockerコンテナを実行するためには、ColimaのVMを適切に設定して作成する必要がある。以下の手順でVMを作成することが推奨される。

### x86_64アーキテクチャのVMを作成

```terminal
$ colima start --cpu 8 --memory 12 --disk 160 --arch x86_64 --vm-type=vz --vz-rosetta --mount-type virtiofs
```

:::note warn
--archにx86_64を指定すると、x86_64用のQEMUを起動し、その結果処理が遅くなる。
:::

このコマンドは、x86_64アーキテクチャ用のVMを作成し、Dockerコンテナの実行環境を準備する。

### aarch64アーキテクチャのVMを作成

```terminal
$ colima start --cpu 8 --memory 12 --disk 160 --arch aarch64 --vm-type=vz --vz-rosetta --mount-type virtiofs
```

:::note info
vzとRosettaを使用してaarch64アーキテクチャ用のVMを作成することで、より高速にx86_64用のDockerコンテナを実行することが可能である。
:::

この方法は、ARMアーキテクチャの性能を最大限に活用しつつ、x86_64用のアプリケーションを動作させることができる。

## x86_64用Dockerコンテナを実行

以下のコマンドを使用して、x86_64のUbuntu 22.04のデスクトップ版のDockerコンテナを起動することができる。

```terminal
$ docker run --rm -it --platform=linux/amd64 ubuntu:22.04
```

このコマンドは、指定されたプラットフォーム（この場合はlinux/amd64）でUbuntu 22.04のコンテナを起動し、対話的なシェルを提供する。これにより、開発者はM1 Mac上でもx86アーキテクチャを必要とするアプリケーションの開発やテストを行うことができるようになる。

```terminal:コンテナ内で実行したコマンド
$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.6  0.0 1196696 6452 pts/0    Ss   22:22   0:00 /mnt/lima-rosetta/rosetta /bin/bash
root          10  0.0  0.0 1198840 4864 pts/0    R+   22:22   0:00 /usr/bin/ps aux
```

コンテナ内でpsコマンドを実行するとbashコマンドがrosettaを経由して実行されていることが確認できる。

---

この記事では、M1 Mac上でx86_64用のDockerコンテナを実行するための方法と、それを実現するためのツールであるColimaの使用方法について説明した。この情報が、同様の環境で開発を行っている方々の参考になれば幸いである。
AWS TokyoリージョンのDatabricksでサーバレスSQLが利用できるようになりました！

こちらに引き続きAWS Tokyoリージョンでも[サーバレスSQL](https://docs.databricks.com/ja/compute/sql-warehouse/serverless.html)がリリースされました。お待ちしておりました。

https://qiita.com/taka_yayoi/items/1f314088d8917387277d

**SQLウェアハウス**にアクセスして、**SQLウェアハウスを作成**をクリックすると、**サーバレス**の文字が！
![Screenshot 2024-02-28 at 7.22.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/0931215d-492c-5f74-fdc4-38dfc6b3c2f6.png)

起動もあっという間です。
![Screenshot 2024-02-28 at 7.22.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/f3b6cf50-deb0-0557-fec6-311f67ca40f7.png)

是非ご活用ください！
![Screenshot 2024-02-28 at 7.23.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/7b5893e5-9bae-91d9-4bea-c5128fa15a77.png)

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
UnityのAwaitableを使った時に非同期で使えないAPIを使いたいときのメモ

# 初めに
Unity 2023.1 から公式で[Awaitable](https://docs.unity3d.com/2023.1/Documentation/ScriptReference/Awaitable.html)という非同期向けのクラスが用意されました。
今回はこれを使うにあたりUnityのAPI使えない問題に遭遇したので対処のメモです。

# 先に結論
`Awaitable.MainThreadAsync`を使ってメインスレッドでUnityのAPIを使い、
`Awaitable.MainThreadAsync`を使ってバックグラウンドスレッドで処理を行う

参考: https://docs.unity3d.com/2023.2/Documentation/Manual/AwaitSupport.html

# 遭遇した事象
例えば以下のコードだと2か所で`その処理、バックグラウンドスレッドで処理できないよ`と怒られます。

```csharp
await Task.Delay(0); // ここでは他の非同期処理 (Delay()で代用)

// 画像を作成して保存したい
var imagePath = Path.Combine(Application.persistentDataPath, fileName); // ここでNG ・・・1
var texture = new Texture2D();
await File.WriteAllBytesAsync(imagePath, texture.EncodeToPNG()); // ここでNG ・・・2
```

なぜ怒られるかというと、1つ目は`Application.persistentDataPath`が、2つ目は`texture.EncodeToPNG()`がそれぞれ怒られてしまいます。
~~文字列の取得だけに怒られるなんて...~~
~~エンコードなんていう重い処理をバックグラウンドスレッドで実行させてくれないなんて...~~

# 対策
さて、ファイル書き込みを含む重めになりそうな処理をするのであれば非同期にはしたいです。
ドキュメントをあさってみると[Unity 2023.2以降のEnglishページ](https://docs.unity3d.com/2023.2/Documentation/Manual/AwaitSupport.html)に解決策が書いてありました。
結論の通りに修正すると以下のコードになります。
```
await Task.Delay(0); // ここでは他の非同期処理 (Delay()で代用)

// 画像を作成して保存したい
await Awaitable.MainThreadAsync(); // UnityのAPIをメインスレッドで実行する
var imagePath = Path.Combine(Application.persistentDataPath, fileName);
var texture = new Texture2D();
var pngData = texture.EncodeToPNG();
await Awaitable.BackgroundThreadAsync(); // ファイル書き込みはバックグラウンドスレッドで実行する
await File.WriteAllBytesAsync(imagePath, pngData);
```

これで問題なく動くようになりました！
ポイントとしては
- バックグラウンドで処理したい場合は`await Awaitable.BackgroundThreadAsync()`する
- メインスレッドで処理したい場合は`await Awaitable.MainThreadAsync()`する
- ~~2024/2/28現在は2023.2以降の英語マニュアルでないとAwaitableの解説がない~~

というところですね。

# 最後に
それメインスレッドでなくても・・・と思うところはありましたが、基本的に非同期は複雑性と危険性が伴うのも事実なのでマニュアルに沿ってメインスレッドとバックグラウンドスレッドを切り替えていけばよさそうですね！
速習 TypeScript#6 Reactの型定義

# はじめに
この記事は下記の講座で学んだ内容をまとめています。

https://www.udemy.com/course/typescript-react-frontend/

## 目次
1.[速習 TypeScript#1](https://qiita.com/warabimochi_26/items/d22215f2241c713fe416)
2.[速習 TypeScript#2](https://qiita.com/warabimochi_26/items/ddfbc4cfbe0065de9fe8)
3.[速習 TypeScript#3](https://qiita.com/warabimochi_26/items/76ad267b89babe2a30ce)
4.[速習 TypeScript#4](https://qiita.com/warabimochi_26/items/7d1a903f519638556dad)
5.[速習 TypeScript#5](https://qiita.com/warabimochi_26/items/37d3de964a8e43424498)
6.速習 TypeScript#6 <- この記事

## ReactのPropsの型定義を行う
`:React.FC` は 関数コンポーネントの型です。

関数コンポーネントの型にジェネリクスを与えることで`Props`の型定義が行えます。

```tsx
interface Props {
    text: string;
}

const TestComponent: React.FC<Props> = (props) => {
  return (
    <div>
        <h1>{ props.text }</h1>
    </div>
  )
}
```

## useStateの型定義を行う
・useStateは関数であり型推論が効くので単一の型だけならジェネリクスで定義しなくても良いです。

stateも更新関数の引数も初期化された値の型しか受け付けないです。
```jsx
const [count, setCount] = useState(0); // count: number setCount(temp: number)
```

・複数の型を許容したいならジェネリクスで定義する

stateも更新関数もジェネリクス通りの型を取ります。
```jsx
  const [ count, setCount ] = useState<number | null>(null);
```

・オブジェクト型を許容したいならジェネリクスで定義します。
```jsx
interface UserData {
  id: number;
  name: string;
}

const [ user, setUser ] = useState<UserData>({
  id: 1,
  name: "rarara"
});

```

## onClickやonChangeなどのイベントの型を定義する
イベントリスナに`callback`関数を渡して型推論させた引数の型を使います。
```jsx
 const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
   setInputData(e.target.value);
} 

<input type="text" value={inputData} onChange={handleInputChange} />
```
速習 TypeScript#5 ジェネリクス

# はじめに
この記事は下記の講座で学んだ内容をまとめています。

https://www.udemy.com/course/typescript-react-frontend/

## 目次
1.[速習 TypeScript#1](https://qiita.com/warabimochi_26/items/d22215f2241c713fe416)
2.[速習 TypeScript#2](https://qiita.com/warabimochi_26/items/ddfbc4cfbe0065de9fe8)
3.[速習 TypeScript#3](https://qiita.com/warabimochi_26/items/76ad267b89babe2a30ce)
4.[速習 TypeScript#4](https://qiita.com/warabimochi_26/items/7d1a903f519638556dad)
5.速習 TypeScript#5 <- この記事
6.[速習 TypeScript#6](https://qiita.com/warabimochi_26/items/f09fdb3968f504867d59)

## ジェネリクス
ジェネリクスは型のテンプレートを用意しておいて使う時にデータ型を与えることで動的にデータ型を変更出来るという物の事です。


### ジェネリクスの定義・使い方
定義側でジェネリクスを使う時は型の右横に&lt;T&gt;をつけます。
ジェネリクスのデータ型を使う時は`T`を使います。

使う時は型の後に`<>`を付けてその中に自分の使いたい型定義を入れます。
```typescript
interface GEN<T> {
 item: T
} 

const gen0: GEN<string> = { item: "hello" }; // OK
const gen1: GEN<string> = { item: 456 };     // NG
```
### ジェネリクスの型にデフォルト型を設定する
デフォルト型を設定すると使う時に型を与えない場合はデフォルト型が設定されます。

```typescript
interface GEN1<T = string> {
  item: T
}

const gen3: GEN1 = { item: "string" }; // OK
const gen3: GEN1 = { item: 100 };      // NG
```

### ジェネリクスで使える型定義に制限をかける
`extends`を使ってジェネリクスで指定する型を制限することが出来ます。

```typescript
interface GEN2<T extends string | number> {
  item: T;
}

const gen4: GEN2<string> = { item: "hello" }; // OK
const gen5: GEN2<number> = { item: 42 };      // OK
const gen6: GEN2<boolean> = { item: true };   // NG
```

## 関数でジェネリクスを使う
引数の左に&lt;T&gt;を付けます。

引数の型推論が働くので実行時にジェネリクスを付けなくても実行できます。

ジェネリクスにはユニオン型も使えます。
```typescript
function funcGen<T>(props: T) {
  return {
    item: props
  }
}

const gen7 = funcGen("test"); // T = string
const gen8 = funcGen<string>("test"); // T = string
const gen9 = funcGen<string | null>(null); // T = string | null
```

### 関数のジェネリクスで使える型を制限する
`extends`を使ってジェネリクスで使える型を制限することが出来ます。

```typescript
function funcGen1<T extends string | null> (props: T) {
  return {
    value: props
  }
}

const gen10 = funcGen1("hello"); // OK
const gen11 = funcGen1(null);    // OK
const gen12 = funcGen1(300);     // NG
```

### アロー関数でジェネリクスを使う
引数の左にジェネリクスを付けて実装します。
```typescript
interface Props {
  price: number;
}

const funcGen4 = <T extends Props>(props: T) => {
  return {
    value: props.price
  }
} 
```
速習 TypeScript#4 enum型・型の互換性

# はじめに
この記事は下記の講座で学んだ内容をまとめています。

https://www.udemy.com/course/typescript-react-frontend/

## 目次
1.[速習 TypeScript#1](https://qiita.com/warabimochi_26/items/d22215f2241c713fe416)
2.[速習 TypeScript#2](https://qiita.com/warabimochi_26/items/ddfbc4cfbe0065de9fe8)
3.[速習 TypeScript#3](https://qiita.com/warabimochi_26/items/76ad267b89babe2a30ce)
4.速習 TypeScript#4 <- この記事
5.[速習 TypeScript#5](https://qiita.com/warabimochi_26/items/37d3de964a8e43424498)
6.[速習 TypeScript#6](https://qiita.com/warabimochi_26/items/f09fdb3968f504867d59)

## enum型
`enum型`は作成したプロパティに対して連番を付ける事が出来る型のことです。

このようにして使います。
```typescript
enum OS {
  Windows, // 0
  Mac,     // 1
  Linux    // 2
}

interface PC {
  id: number;
  OSType: OS;
}

const PC1: PC = {
  id: 0,
  OSType: OS.Windows, // 0
};
```

`enum型`を使ってその値の持つ意味と数値を結びつけることが出来ます。

## 型の互換性
```typescript
const comp1 = "test"; // "test"型
let comp2: string = comp1; // OK

let comp3 = "test";   // string型
let copm4: "test" = comp3; // NG
```
`string型`は文字列の`リテラル型`を包括しているので変数`comp1`は変数`comp2`に代入出来る。
文字列の`リテラル型`は`string型`を包括していないので変数`comp3`は変数`comp4`に代入出来ない。
速習 TypeScript#3 typeof・keyof

# はじめに
この記事は下記の講座で学んだ内容をまとめています。

https://www.udemy.com/course/typescript-react-frontend/

## 目次
1.[速習 TypeScript#1](https://qiita.com/warabimochi_26/items/d22215f2241c713fe416)
2.[速習 TypeScript#2](https://qiita.com/warabimochi_26/items/ddfbc4cfbe0065de9fe8)
3.速習 TypeScript#3 <- この記事
4.[速習 TypeScript#4](https://qiita.com/warabimochi_26/items/7d1a903f519638556dad)
5.[速習 TypeScript#5](https://qiita.com/warabimochi_26/items/37d3de964a8e43424498)
6.[速習 TypeScript#6](https://qiita.com/warabimochi_26/items/f09fdb3968f504867d59)

## typeof
typeofは定義済み変数から型を取得するキーワードです。

このようにして使います。
```typescript
let msg: string = "Hi";
let msg2: typeof msg;
msg2 = "hello";

let animal = { cat: "small cat" };
let newAnimal: typeof animal = { cat: "big cat" };
```
変数`msg`は`string型`なので変数`msg2`も`string型`になります。
変数`animal`は`{ cat: string; }型`なので変数`newAnimal`も`{ cat: string; }型`になります。

## keyof
keyofは定義済みのオブジェクトの型からプロパティ名のリテラル型のユニオン型として取得するキーワード

このようにして使います。
```typescript
type KEYS = {
  primary: string;
  secondary: string;
}

let key: keyof KEYS; // "primary" | "secondary"
key = "primary";   // OK
key = "secondary"; // OK
key = "third";     // NG
```

### keyof + typeof で定義済みのオブジェクト変数のプロパティ名のリテラル型のユニオン型を取得する
```typescript
const SPORTS = {
  soccer: "Soccer",
  baseball: "Baseball"
};

let keySports: keyof typeof SPORTS; // "soccer" | "baseball"
keySports = "soccer";   // OK
keySports = "baseball"; // OK
keySports = "tennis";   // NG
```
typeof で オブジェクト変数をオブジェクト型に
keyof でオブジェクト型のキーのリテラル型をユニオン型にしている。
速習 TypeScript#2 インターセクション・ユニオン・リテラル型

# はじめに
この記事は下記の講座で学んだ内容をまとめています。

https://www.udemy.com/course/typescript-react-frontend/

## 目次
1.[速習 TypeScript#1](https://qiita.com/warabimochi_26/items/d22215f2241c713fe416)
2.速習 TypeScript#2 <- この記事
3.[速習 TypeScript#3](https://qiita.com/warabimochi_26/items/76ad267b89babe2a30ce)
4.[速習 TypeScript#4](https://qiita.com/warabimochi_26/items/7d1a903f519638556dad)
5.[速習 TypeScript#5](https://qiita.com/warabimochi_26/items/37d3de964a8e43424498)
6.[速習 TypeScript#6](https://qiita.com/warabimochi_26/items/f09fdb3968f504867d59)

## インターセクション型
インターセクション型は異なる型を合わせて新しい型を作成出来ます。
&を使います。
```typescript
type PROFILE = {
  age: number;
  city: string;
};

type LOGIN = {
  username: string;
  password: string;
};

type USER = PROFILE & LOGIN;
```

`USER型`は`PROFILE型`と`LOGIN型`の双方を持ち合わせているので代入するオブジェクトはこうなります。

```typescript
let userA: USER = {
  age: 30,
  city: "Tokyo",
  username: "xxx",
  password: "yyy"
}
```

## ユニオン型
ユニオン型では複数の型を許容する型を作成出来ます。
|を使います。

・変数ではこのようにして使います。
```typescript
let value: boolean | number;
value = true; // OK
value =  10;  // OK
value = "a"   // NG
```

・配列ではこのようにして使います。
```typescript
let arrayUni: (number | string)[]
arrayUni = [0, 1, 2, "hello", true];  0, 1, 2, "hello" -> OK. true -> NG
```

## リテラル型
リテラル型は単一の文字や数値等の単一の値を扱った型のことです。
・良くユニオン型と合わせて使う
```typescript
let company: "Facebook" | "Google" | "Amazon";
company = "Amazon";

let memory: 256 | 512;
memory = 512;
```
速習 TypeScript#1 TSの書き方・良く使う型

# はじめに
この記事は下記の講座で学んだ内容をまとめています。

https://www.udemy.com/course/typescript-react-frontend/

## 解決したいこと

TypeScriptで行う事は自分だけが持っていた変数や関数の引数等の値に対する明文化していない感覚を明文化して他人やIDEに伝えるというようなイメージであり、
実行された時にどうであるかは関係なく、個々の値に設定した型の突合せによって矛盾を探してエラーを伝えているという認識が正しいかどうか

## 目次
1.速習 TypeScript#1 <- この記事
2.[速習 TypeScript#2](https://qiita.com/warabimochi_26/items/ddfbc4cfbe0065de9fe8)
3.[速習 TypeScript#3](https://qiita.com/warabimochi_26/items/76ad267b89babe2a30ce)
4.[速習 TypeScript#4](https://qiita.com/warabimochi_26/items/7d1a903f519638556dad)
5.[速習 TypeScript#5](https://qiita.com/warabimochi_26/items/37d3de964a8e43424498)
6.[速習 TypeScript#6](https://qiita.com/warabimochi_26/items/f09fdb3968f504867d59)

## TypeScriptの書き方

```typescript
let username = "hello"
```

変数`username`の型は`string`.
`JavaScript`と同じ記述をした時に変数の型は初期化した値の型になる.
これを型推論と呼ぶ.

```typescript
let username: string = "hello"
```

変数`username`の型は`string`.
`TypeScript`では変数の横に:を付けて型を記述する.
これをアノテーションと呼ぶ.

TSでは型推論かアノテーションによって型が決定される

## TypeScriptでよく使う型
・`string` -> 文字列型
・`number` -> 数値型
・`boolean` -> 真偽値型

・`string[] number[] boolean[]` -> 配列型
左から順に配列の要素が 文字列型のみ.数値型のみ.真偽値型のみ で構成されている。
・`(string | number)[]` -> 配列型
配列の要素が 文字列型と数値型の内どちらかもしくはどちらもで構成されている

・`interface NAME { first: string; last?: string | null; }` -> オブジェクト型
NAMEという名前のオブジェクト型を意味する
プロパティ名の末尾に?をつけるとそのプロパティが変数に代入するオブジェクト内にあってもなくても良いという意味になる
string | null のように型同士に | を繋げてくっつけるとくっつけられた型のどちらでも良いという意味になる

・`const func1 = (x: number, y: number): number => {
  return x + y;
};` -> 関数の型定義
関数の型定義には引数と戻り値に型をつける。
速習App Router#7 ミドルウェア

# はじめに
この記事は下記の講座で学んだ内容をまとめています。
理解が怪しい所があるので教えてくれるととても嬉しいです。

https://www.udemy.com/course/nextjs-supabase-app-directory

# 目次
1.[速習App Router#1](https://qiita.com/warabimochi_26/items/bb3c17f06e07c080504e)
2.[速習App Router#2](https://qiita.com/warabimochi_26/items/ad7a3876d6cd614d0837)
3.[速習App Router#3](https://qiita.com/warabimochi_26/items/163f801647a1bcfa31be) 
4.[速習App Router#4](https://qiita.com/warabimochi_26/items/41714929576c8d0cf297)
5.[速習App Router#5](https://qiita.com/warabimochi_26/items/1192f759c9bec2c793bf)
6.[速習App Router#6](https://qiita.com/warabimochi_26/items/8c0217fbd96276fb9ed8)
7.速習App Router#7 <-この記事

## ミドルウェアについて
ブラウザからのアクセスが`page.tsx`に辿り付くまでに一旦経由される部分のこと。

```typescript:/middleware.ts
export async function middleware(req: NextRequest) {
    const res = NextResponse.next()
    const supabase = createMiddlewareSupabaseClient({ req, res })

    const { data: { session }} = await supabase.auth.getSession()
    
    if (!session && req.nextUrl.pathname.startsWith('/auth/todo-crud')) {
        const redirectUrl = req.nextUrl.clone()
        redirectUrl.pathname = '/auth'
        return NextResponse.redirect(redirectUrl)
    }
    
    return res
}
```
これは `/auth/todo-crud`にアクセスした時にログインしているかどうかによって `/auth/todo-crud`に通すか決めるミドルウェアです。
【初級者向け】 TypeScript と React/Next.js でつくる実践 Web アプリケーション開発

# 【初級者向け】 TypeScript と React/Next.js でつくる実践 Web アプリケーション開発

以下の書籍を読み、現役の自称フルスタックエンジニア（よわ）がレビューさせていただきます。

ちなみに私は、フロントの実務経験は従来が半年、モダンで 1 年未満で、約 1 年半くらいで基礎はわかっているかな程度レベルでの感想になります、ご理解下さい。

## 概要

タイトルにもある通り、「実践 Web アプリケーション開発」と記載されていますが、モダンな技術初学者にとってはとっつきやすい内容でした。
もちろん最低限の HTML,CSS,JavaScript が全く分からない人には厳しいです。。
本書では、前半は React/Next.js と TypeScript を基礎からわかりやすくまとめられていて、後半は実際にアプリケーション開発に進む形になります。
上記の技術を組み合わせた開発を取り入れたいや学習したい方にはバッチリおすすめ本だと思います！

## 扱う内容

- フロントエンド技術についての歴史 なぜ進化していったか
- TypeScript の基礎
- React の基礎
- Next.js の基礎
- コンポーネント概念、設計
- 実際に Web アプリケーションを開発する
- 実装以降のテスト、リリースまで
- Web セキュリティやログ管理など

## 良かったところ

序盤はモダンなフロントエンド技術が生まれた背景が描かれており、なぜ活用した方がいいか紹介されています。
これは技術選定時や社内でモダンフロントを広めたい場合にも活用できる内容だと思いました。

新しい技術が生まれる時って、従来の問題の課題解決のために生まれていることが多いです。
React が生まれた理由はコーディングで抱える問題、保守性の欠如、互換性問題などなどがあります。
TypeScript は Javascript のには型定義(動的型付け言語)がなかったため、可読性も落ち、実行されるまでエラーか判断できない部分を解消しました。
Next.js は React の抱える描画問題、SEO などを解決するために作られました。

こういった背景を理解しておくことによって、より深くまで理解できるかと思います。

Next.js には SPA・SSR・SSG・CSR・ISR というようなレンダリング方式が存在しています。
それぞれアプリケーションの用途によって最適なレンダリングをすることによってパフォーマンスが変わってきます。
ここでは詳しく説明しませんが、この辺についてもしっかり図で説明されていたのがわかりやすかったです。

また、コンポーネントやスタイル、テストについて、推奨化されているものを紹介していて、自分はベストプラクティスを追い求めるので、とても嬉しかったです。
モダンフロントの場合のセキュリティ対策やログ出力も最後の方にまとめられていて、網羅的で良かったです。
あまり意識しなくてもある程度の対策は React がやってたりするらしいです。

さらに。。なんと Youtube でオンラインセミナーの動画が公開されています！
あと[GitHub](https://github.com/gihyo-book/ts-nextbook-app)ソースも公開されています。

[TypeScript と React/Next.js でつくる実践 Web アプリケーション開発](https://www.youtube.com/watch?v=tjQCaWcOqZ8)

## 悪かったところ

実際のアプリケーション開発部分は、画面＋コードの羅列だったので、行ったり来たりで読みづらい部分はあった。が、どの書籍にも言えることなので、ここはいつも同じ感想になる。→ なのでソースコードを見ながらするとより理解できると思います。

最新アップデート版の AppRouter などは記載されていないので、改正版を待った方がいいかも知れません。
（フロントエンド技術のアップデートは本当に早すぎてついていくのが大変）

## 学んだこと

自分が知りたかった、モダンフロントでの、Jest を使ったテスト、セキュリティ対策などが知れました。
特に StoryBook でコンポーネントを管理する方法は使えそうだなと感じました。
また、以下のコンポーネント思想による設計を学ぶことができた。

![スクリーンショット 2024-02-28 5.42.37（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3289261/136faf62-4d8e-0146-59bc-453da264c081.png)

## まとめ

Next.js を少し触ったことがある私からすると、なんて多機能なんだ、扱うの大変。という印象ですが、今回この本を読んで散りばめられた知識がまとまりました笑
それほど網羅的に、簡潔にまとめられていました。
実際の時間とSymbol時間

deadlineは実際の時間から数時間後と設定することが多いですが、Symbolのネットワーク時間は***少し未来***です。

## 実際の時間とSymbol時間を表示するコード

```typescript
import symbolSdk from 'symbol-sdk';

const NODE = 'http://finnel.harvestasya.com:3000';

// /node/time を取得
const nodeTimeResponse = await fetch(new URL('/node/time', NODE), {
  method: 'GET',
  headers: { 'Content-Type': 'application/json' },
});

// 実時間取得
const actualTime = new Date();

// /node/time からネットワーク時間算出
const nodeTimeJson = await nodeTimeResponse.json();
const symbolTime = Number(
  nodeTimeJson.communicationTimestamps.receiveTimestamp
);
const facade = new symbolSdk.facade.SymbolFacade('mainnet');
const networkDate = facade.network.toDatetime(
  new symbolSdk.symbol.NetworkTimestamp(symbolTime)
);

// 表示
console.log(`ActualTime: ${actualTime}`);
console.log(`SymbolTime: ${networkDate}`);
```

### /node/timeとは
`/node/time`は、Symbol時間をこういうJsonを返します。`sendTimestamp`、`receiveTimestamp`が異なる値になっているのは見たことないので、どちらを使用しても良いかと思います。
```json
{
  "communicationTimestamps": {
    "sendTimestamp": "93214047045",
    "receiveTimestamp": "93214047045"
  }
}
```

### 実行
```plaintext
ActualTime: Wed Feb 28 2024 05:42:46 GMT+0900 (日本標準時)
SymbolTime: Wed Feb 28 2024 05:42:50 GMT+0900 (日本標準時)
```

Symbolは3~4秒先を見てる。


## 実際使う場合
使用端末の時間があってるとは限らないので、ネットワーク時間取得してdeadline設定する方が良いかと。
```typescript
import symbolSdk from 'symbol-sdk';

const NODE = 'http://finnel.harvestasya.com:3000';

// /node/time を取得
const nodeTimeResponse = await fetch(new URL('/node/time', NODE), {
  method: 'GET',
  headers: { 'Content-Type': 'application/json' },
});
// /node/time からネットワーク時間算出
const nodeTimeJson = await nodeTimeResponse.json();
const symbolTime = Number(
  nodeTimeJson.communicationTimestamps.receiveTimestamp
);
// deadline 2時間
const networkTimestamp = new symbolSdk.symbol.NetworkTimestamp(symbolTime);
const deadline = networkTimestamp.addHours(2).timestamp;

// 表示
console.log(`SymbolTime: ${symbolTime}`);
console.log(`DeadLine  : ${deadline}`);
```
速習App Router#6 StreamingHTML

# はじめに
この記事は下記の講座で学んだ内容をまとめています。
理解が怪しい所があるので教えてくれるととても嬉しいです。

https://www.udemy.com/course/nextjs-supabase-app-directory

# 目次
1.[速習App Router#1](https://qiita.com/warabimochi_26/items/bb3c17f06e07c080504e)
2.[速習App Router#2](https://qiita.com/warabimochi_26/items/ad7a3876d6cd614d0837)
3.[速習App Router#3](https://qiita.com/warabimochi_26/items/163f801647a1bcfa31be) 
4.[速習App Router#4](https://qiita.com/warabimochi_26/items/41714929576c8d0cf297)
5.[速習App Router#5](https://qiita.com/warabimochi_26/items/1192f759c9bec2c793bf)
6.速習App Router#6 <- この記事
7.[速習App Router#7](https://qiita.com/warabimochi_26/items/85f6a05cf9cd2554e690)

## StreamingHTMLについて
レンダリングにかかる時間が異なる二つのサーバーコンポーネントを用意します。
・`blog-list.tsx` -> 描画に6秒かかるコンポーネント
・`news-list.tsx` -> 描画に2秒かかるコンポーネント

これらのコンポーネントをSuspenseコンポーネントで囲んで同じpage.tsx内で実行します。

```typescript:/page.tsx
import BlogList from '../components/blog-list'
import NewsList from '../components/news-list'
import Spinner from '../components/spinner'

export default function StreamingServerRenderingPage() {
  return (
  <Suspense fallback={<Spinner color="border-green-500" />}>
    <BlogList />
  </Suspense>
  <Suspense fallback={<Spinner />}>
   <NewsList />
  </Suspense>
  )
}
```
`news-list.tsx`の ロード -> 描画 が終わった後に
`blog-list.tsx`の ロード -> 描画 が終わる。

つまり、`loading.tsx`では`page.tsx`という単位でしかローディングを実装出来なかったが、
`Suspense`コンポーネントで描画に時間のかかるコンポーネントを囲むことで
コンポーネント単位でローディングを実装出来るという事です。