OmniAICreator/Qiita-1.07M huggingface dataset:
[初心者向け]テストレベル - 統合テスト

[徹底攻略 JSTQB Foundation教科書&問題集 シラバス2018対応](https://www.amazon.co.jp/%E5%BE%B9%E5%BA%95%E6%94%BB%E7%95%A5-JSTQB-Foundation%E6%95%99%E7%A7%91%E6%9B%B8-%E5%95%8F%E9%A1%8C%E9%9B%86-%E3%82%B7%E3%83%A9%E3%83%90%E3%82%B92018%E5%AF%BE%E5%BF%9C/dp/4295017671/ref=asc_df_4295017671/?tag=jpgo-22&linkCode=df0&hvadid=654833321247&hvpos=&hvnetw=g&hvrand=7317531869461544354&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009293&hvtargid=pla-2199686852302&psc=1&mcid=140f9d5d8ea8321d9cdbe1b981b50a4c&th=1&psc=1)を勉強しているので、自分のメモとしてまとめています。第10弾。

# テストの目的
統合テストの目的は、インターフェース部分の振る舞いが正常かどうかを確認すること。

## 属性
- インターフェースの振る舞いが設計・仕様通りであることの検証
- インターフェースに存在する欠陥の検出
- インターフェースの品質に対する信頼の積み上げ
- 欠陥が上位レベルのテストまで見逃されることの防止
- リスクの低減

## 説明
統合テストは、コンポーネントテストやシステム間の相互処理のテストのこと。
あくまで相互処理やインターフェースに焦点を当ててテストを行う。
ただ、統合テストにおいてコンポーネントやシステムに内在する欠陥が検出されることもよくある。

## 特性
### リグレッションテストの自動化
コンポーネントテストと同様。
自動化しておくことでコードの変更が既存のインターフェースやコンポーネント、システムを破壊しないという信頼性を提供できる。

### コンポーネント統合テストとシステム統合テスト
統合テストではテスト対象が2つある。
コンポーネント間のインターフェースを対象とするものをコンポーネント統合テスト、システム間のインターフェースを対象とするものがシステム統合テストである。
#### コンポーネント統合テスト
- コンポーネント間の相互処理とインターフェースに焦点を当ててテストをする
- コンポーネントテストが終わった後で実施
- 継続的インテグレーションの一環として自動化されることも多い

#### システム統合テスト
- マイクロサービス（小さなサービスを組み合わせてソフトウェアを作る手法における構成要素）間の相互処理とインターフェースに焦点を当ててテストする
- システムテストが終わった後、またはシステムテストと並行して実施
- 外部システムとのインターフェースが正常かどうかを確認する作業も範囲内

# テストベース
- **ソフトウェア設計書**や**システム設計書**
- インターフェース仕様や通信プロトコルの仕様
    - システム間の連携部分に関するもの
- シーケンス図（オブジェクト間のやり取りを時間軸に沿って表現するもの）
- ユースケース図（ユーザー目線でシステムがどのような使われ方をするのかの図）
- ワークフロー（業務の流れを図解したもの）
- コンポーネントレベルやシステムレベルのアーキテクチャー
- 外部とのインターフェース定義

など

# テスト対象
統合テストの対象は、いくつかのコンポーネントのかたまりで、以下のインターフェースやAPIがテスト対象になる。
- サブシステム
- データベース
- [インフラストラクチャー](https://wa3.i-3-i.info/word12114.html)
- パッケージ
- マイクロサービス

# 典型的な欠陥と故障
## コンポーネント統合テスト
以下が主な典型例になる。
- データの欠陥
    - データが正しくない
    - データ不足
    - データエンコーディング（コード変換）が正しくない
- インターフェースの欠陥
    - 呼び出しが正しくない
    - 順序やタイミングが不正
    - 不整合
- コミュニケーションの欠陥
    - コンポーネント間のコミュニケーション故障
    - 処理が不在または不適切
- 仕様不一致の欠陥
    - コンポーネント間で渡されるデータの意味・単位・境界の正しくない思いこみ

## システム統合テスト
以下が主な典型例になる。
- システム間で一貫性のないメッセージ構造
- データの欠陥
    - データが正しくない
    - データ不足
    - データエンコーディング（コード変換）が正しくない
- インターフェースの不整合
- システム間通信の故障
    - 処理が不適切
    - データが合わない　など
- 仕様の不一致
    - システム間で渡されるデータの意味、単位、境界の正しくない思いこみ
- 必須セキュリティ規制への非準拠

# アプローチと責務
統合テストのアプローチと責務に関して、次のような特徴を示す。
## インターフェースに集中
コンポーネント統合テストとシステム統合テストは、相互連携やインターフェースなど、統合部分だけに集中してテストする。

## 機能テスト、非機能テスト、構造テストを行える
統合テストでは、機能テスト（機能要件が正しいことを評価）のほかに非機能テスト（セキュリティや使用性など、機能以外の要件が正しいことを評価）、構造テスト（コンポーネントやシステムの構造、アーキテクチャが仕様通りであることを評価）なども行うことができる。

## テスト担当者がテスト
コンポーネント統合テストは開発担当者自信がテストするが、システム統合テストは通常テスト担当者が実行する。
そのため、テスト担当者はシステムアーキテクチャを理解し、統合テスト計画の作成に関与すべきとされている。

## 開発前にテスト戦略を計画
コンポーネントやシステムを構築する前に統合テストや統合戦略を計画にすると、テスト効率が高いシステムを作ることができる。
統合戦略とは、システムアーキテクチャや機能的タスク、トランザクション処理シーケンスなどがベースになる。

## インクリメンタルにテスト
統合テストはビックバン（すべてのコンポーネントやシステムを一度にテストする）ではなく、ある部分から順番にテスト範囲を広げるインクリメンタルなテストが望ましい。

## 複雑なインターフェースのリスク分析
複雑なインターフェースに対しては、リスク分析を行うことで統合テストのどこに焦点を当てるべきかのあたりをつけることが効果的。

## 継続的インテグレーションで自動化
統合の範囲が大きくなるほど、欠陥の特定が難しくなり、リスクが増えてトラブルシューティングの時間が増大する。
そのため、継続的インテグレーションにより統合テストの自動化を行うことが普及しつつある。

# 次回
テストレベル - システムテスト（記事書いたらリンク貼る）
【Python】再帰でエラーになる人は必見！再帰の深さとsetrecursionlimit

## 記事の内容
先日、競技プログラミングの問題で再帰を使っていたらエラーに遭遇しました。エラーの原因は、再帰の上限です。ここで改めて、再帰の上限についてまとめたく、この記事を公開します。

## Pythonの再帰におけるsetrecursionlimitの解説

再帰呼び出しは、関数が自分自身を呼び出すプロセスです。再帰を使用することで、問題をより小さなサブプロブレムに分割して解決することができます。しかし、再帰には限界があります。それが再帰の深さです。

### 再帰の深さとsetrecursionlimit
再帰の深さは、関数が何回自分自身を呼び出すことができるかを示す指標です。再帰が深くなると、プログラムのスタックメモリを消費します。Pythonには、再帰の深さに制限があり、これを超えるとRecursionErrorが発生します。

```python
RecursionError: maximum recursion depth exceeded in comparison
```

デフォルトでは、Pythonの再帰深さの制限は1000に設定されています。この制限は、無限再帰によるスタックオーバーフローを防ぐために存在します。

### sys.setrecursionlimitの目的と必要性
sys.setrecursionlimitは、この再帰深さの制限を変更するための関数です。以下のように使用します：

```python
import sys
sys.setrecursionlimit(2000)  # 再帰の深さの制限を2000に設定
```
### 目的と必要性

* より深い再帰を許容：特定のアルゴリズム、特に深い再帰が必要なアルゴリズムでは、デフォルトの再帰深さが不十分な場合があります。例えば、深い再帰を使用する分割統治法やグラフ探索などです。
* プログラムの安定性：デフォルトの設定は、多くの一般的なシナリオでの安定性を確保するために設計されていますが、特定の問題解決には調整が必要です。

### 具体例
再帰の深さ制限に直面する例として、深いツリー構造を探索する場合を考えてみましょう。

```python
def deep_recursion(n):
    if n == 0:
        return
    deep_recursion(n - 1)

deep_recursion(1001)  # デフォルトの再帰深さを超えるとエラーが発生する
```

このコードはデフォルトの設定ではエラーになります。sys.setrecursionlimitを使って制限を変更してみましょう。

```python
import sys
sys.setrecursionlimit(2000)

def deep_recursion(n):
    if n == 0:
        return
    deep_recursion(n - 1)

deep_recursion(1001)  # これでエラーが発生しなくなる
```

## 歴史的背景
再帰の深さ制限は、プログラムが無限再帰によってクラッシュするのを防ぐために導入されました。CやC++のような言語でも、スタックオーバーフローを防ぐために再帰深度に実質的な制限があります。Pythonでも同様に、デフォルトで比較的低い再帰深度制限を設けることで、ユーザーが無意識にシステムをクラッシュさせないようにしています。

## 注意点
sys.setrecursionlimitの値を大きく設定しすぎると、スタックオーバーフローを引き起こし、システムがクラッシュする可能性があります。設定する値は、システムのメモリ容量や使用しているアルゴリズムの特性に応じて慎重に決定する必要があります。

## まとめ
* 再帰の深さは、関数が自分自身を呼び出す回数を制限する指標。
* **sys.setrecursionlimit**を使って、この制限を変更できる。
* 目的は、無限再帰を防ぎつつ、必要に応じて深い再帰を許容すること。
* 慎重な設定が求められる。

## 参考資料
[Python公式ドキュメント：sysモジュール](https://docs.python.org/3/library/sys.html#sys.setrecursionlimit)

## おすすめ記事
* [論理学って何を扱うの？論理学入門](https://qiita.com/kyogoku_meta/items/7dc1c17f78bc36d11346)
* [線形代数の「背景と概念」をもっとよく分かりたい【数学弱者・凡人のための線形代数入門】](https://qiita.com/kyogoku_meta/items/077e9972dcd7b08d6473)
* [弱者・凡人のための競技プログラミング入門『競技プログラミングの鉄則』本を使いこなしたい ①二分探索](https://qiita.com/kyogoku_meta/items/91b32773f045d0ef560b)
* [【Python リストの基礎】[ ]とlist() の違いが気になったから調べてみた](https://qiita.com/kyogoku_meta/items/f1a9e0a92a4d89253eb3)
Solana 靓号地址生成器

现实生活中，有人追求手机号“111111”，而在区块链中，大家也追求“靓号地址”。靓号地址（Vanity Address）指的是包含特定字符或字符序列的加密货币地址，这些地址通常具有某种特殊的含义或美观性。

[JPv1rCqrhagNNmJVM5J1he7msQ5ybtvE1nNuHpDHMNU](https://explorer.solana.com/address/JPv1rCqrhagNNmJVM5J1he7msQ5ybtvE1nNuHpDHMNU)是 https://jetprotocol.io/ 的合约地址。 `jpv1` 就是一个靓号地址前缀，表示是 jet protocol v1 版本。

如何生成自己的靓号地址呢？solana 很贴心，已经为我们准备好了工具。

## 安装 Solana Cli

solana cli 安装好后，还会有个 `solana-keygen` 命令

```sh
sh -c "$(curl -sSfL https://release.solana.com/stable/install)"
solana -V
solana-keygen -V
```

## 使用 solana-keygen grind 生成靓号地址

### starts-with

生成已 sos 开头的地址

```sh
solana-keygen grind --starts-with sos:1

# sosqy9REQD9fjFUwa4VQBYAnSHq6nV6PsiKL9ADD9Ng
```

### ends-with

生成以 111 结尾的地址

```sh
solana-keygen grind --ends-with 111:1

# epkcYU58Bj9so3fh9GpV87fzJRtthFm9vLoTZEbb111
```

### starts-and-ends-with

生成以 a 开头，z 结尾的地址

```sh
solana-keygen grind --starts-and-ends-with A:Z:1 --ignore-case

# AfwSyFuGd6dQ39y1T9cpqseZfBSSAV39i8P76tG2bThz
```

还有更复杂的命令

```sh
solana-keygen grind --starts-and-ends-with A:M:1 --ignore-case --use-mnemonic --word-count 12 --language english --no-outfile --no-bip39-passphrase

Searching with 12 threads for:
	1 pubkey that starts with 'a' and ends with 'm'
================================================================================
Found matching key AYgp1PVZ8BavYqQYuKqC6VP44RgHCzeKn2AwTFKpi6Hm

Save this seed phrase to recover your new keypair:
afraid glove catalog lens cattle garbage perfect dignity happy curve flip address
================================================================================
```

## 使用 GPU 生成靓号
如果你的靓号太苛刻，则需要大量的计算时间

```sh
solana-keygen grind --starts-with 1111:1

Searching with 12 threads for:
  1 pubkey that starts with '1111' and ends with ''

Searched 1000000 keypairs in 3s. 0 matches found.
Searched 2000000 keypairs in 7s. 0 matches found.
Searched 3000000 keypairs in 11s. 0 matches found.
Searched 4000000 keypairs in 16s. 0 matches found.
Searched 5000000 keypairs in 20s. 0 matches found.
Searched 6000000 keypairs in 25s. 0 matches found.
Searched 7000000 keypairs in 31s. 0 matches found.
Searched 8000000 keypairs in 36s. 0 matches found.
Searched 9000000 keypairs in 41s. 0 matches found.
Searched 10000000 keypairs in 45s. 0 matches found.
```

这时候需要使用 GPU 来帮你生成地址，可以参考下面的链接

https://smith-mcf.medium.com/solana-vanity-address-using-gpus-5a68ad94d1d4

https://github.com/ChorusOne/solanity/

---

Ref：

https://explorer.solana.com/address/didso1Dpqpm4CsiCjzP766BGY89CAdD6ZBL68cRhFPc

https://www.quicknode.com/guides/solana-development/getting-started/how-to-create-a-custom-vanity-wallet-address-using-solana-cli
【Python】基本的な書き方

Pythonは人間にとって読みやすく、シンプルな構文を持つプログラミング言語です。ここでは、Pythonの基本的な書き方を紹介します。
```Python
# コメント: コメントは#から始まり、その行の終わりまでがコメントになります

# 出力
print("Hello, World!") # コンソールに文字列を出力します

# 変数
x = 5 # 値を変数に代入
y = "Python" # 文字列も変数に代入できます
print(x)      # 変数の値を出力
print(y)

# 数値演算
a = 3
b = 2
print(a + b) # 足し算: 5
print(a - b) # 引き算: 1
print(a * b) # 掛け算: 6 
print(a / b) # 除算: 1.5

# 文字列の操作
s = "Python"
print(s + " is fun!") # 文字列を連結
print(s * 3)          # 文字列の繰り返し

# リスト
list = [1, 2, 3, 4, 5] # リストの作成
print(list[0])        # リストの要素にアクセス: 1
print(list[-1])       # 末尾の要素にアクセス: 5

# IF文
if x > 0:
    print("xは正の数です")
elif x < 0:
    print("xは負の数です") 
else:
    print("xは0です")
    
# for文
for i in range(5):
    print(i) # 0から4まで出力

# 関数
def greet(name):
    print("Hello, " + name) # 引数nameを受け取る

greet("John") # Hello, John
```
これらはPythonの基本的な文法の一部ですが、変数、演算子、制御フロー(if/for)、関数などの基本概念が含まれています。Pythonでは**インデント**が構造を表すため、きれいでわかりやすいコードを書くことができます。
# インデント
インデントとは、コードの構造を視覚的に表すために、スペースや半角スペースを使って字下げすることです。Pythonではインデントが特に重要な役割を果たします。
Pythonではインデントによってブロック構造(コードのまとまり)が定義されます。例えば:
```python
if x > 0:
    print("xは正の値です")
    print("この行もインデントされています")
print("インデントされていない行")
```
上記のようにif文の中身は、インデントされた行が実行されます。インデントは通常4つのスペースか1つのTabで表されますが、どちらを使うかは重要ではありません。重要なのは、同じブロック内のコードで同じインデントのスタイルを使うことです。
```python
# インデントが異なる(NG)
if x > 0:
    print("xは正の値です") 
        print("インデントが深すぎる!")

# インデントが統一されている(OK) 
if x > 0:
    print("xは正の値です")
    print("インデントが同じ")
```
インデントを適切に行うことで、ブロックの範囲がはっきりと視覚化され、コードの読みやすさが高まります。Pythonではインデントがコードの文法的な意味を持つため、インデントの使い方が非常に重要です。
# 命令文
Pythonでは、命令文を使って処理を記述します。主な命令文は以下の通りです。
- **代入文**
```python
x = 5    # 変数xに5を代入する
y = x + 2 # yにxに2を足した値を代入する
```
- **出力文**
```python
print(x)         # 変数xの値を出力する
print("Hello")   # リテラル文字列を出力する
print(x, y)      # 複数の値を出力する(スペース区切り)
```
- **条件分岐文(if文)**
```python
if x > 0:
    print("xは正の値です")  # xが0より大きい場合に実行される
elif x < 0: 
    print("xは負の値です")  # xが0未満の場合に実行される  
else:
    print("xは0です")        # どちらでもない場合に実行される
```
- **反復文(for文)**
```python
for i in range(5):   # 0から4までの数値を繰り返す
    print(i)         # iの値を出力する

fruits = ["apple", "banana", "cherry"]
for fruit in fruits:   # リストの各要素を繰り返す  
    print(fruit)       # 要素の値を出力する
```
- **関数定義文**
```python
def greet(name):   # 関数の定義。nameという引数を取る
    print("Hello, " + name)  # 関数の本体

greet("John")   # 関数greetを呼び出し、結果として"Hello, John"と出力される
```
- **モジュールのインポート文**
```python
import math    # mathモジュールをインポートする
print(math.pi) # 3.141592... (πの値)が出力される
```
これらの命令文を使って、Pythonでプログラムを記述していきます。インデントの深さで構造を表現するため、見やすいコードが書けます。

######
参考)　[東京工業大学情報理工学院 Python早見表](https://chokkan.github.io/python/index.html)

https://qiita.com/Akuuuun/items/84136ba56f71f028174e
KMPにおいて、gradleのlibsでエラーが表示される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517291/60f053bf-df56-c741-89aa-25d53c642033.png)


```build.gradle.kts
'val Project.libs: LibrariesForLibs' can't be called in this context by implicit receiver. Use the explicit one if necessary
```

とエラーが出た。

どうやら、バグらしい

https://github.com/gradle/gradle/issues/22797
> この問題は関連チームのバックログにあり、チームによって優先順位が付けられています。

> Gradle バージョンを更新して抑制を削除するだけで、問題は解決します。 ;-)

ということで、Gradleのバージョンを 8.1.1 まで上げることで解決した


## Gradleのバージョン上げ方
File -> Project Structure でGradle Versionを選択できる
SwiftUIのDatePicker(graphycal)をタップした時にサイズが変わってしまう問題の対処法と備忘録

# **背景**
SwiftUIのDatePickerは何かと扱いが難しいと感じています。
例えば、DatePickerStyleのdefaultまたはcompactで表示されるselectionのラベルはカスタマイズができないようです。SwiftUIのDatePickerを扱ったことのある人であれば必ず通るのではないでしょうか? 
本記事では、ラベルをカスタマイズする方法とその課題についても触れています。

表題の事象にハマった人の一助となれば幸いです。

# **1. graphycalでタップした時にサイズが変わってしまう問題の対処法**
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128814/5449bb39-6f99-1356-7d22-578f98d19349.gif">

このような事象は許容できなくもないですが、できれば解決したいはずです。
以下のように.frame(width: 320)を追加することで回避できます。
widthを指定しなかったり、320以外のサイズにすると表題の事象または、サイズがおかしくなることを確認しています。

```swift
DatePicker(selection: $exhibitDate, displayedComponents: .date) {}
        .datePickerStyle(.graphical)
        .dynamicTypeSize(.large)
        .frame(width: 320) // widthが320ではないとサイズが変わってしまう
```
こちらの記事を参考にしました。
https://stackoverflow.com/questions/73475000/datepicker-with-graphical-style-breaks-layout-constraints-on-ios-16-0


# **2.ラベルをカスタマイズする方法とその課題**

DatePickerStyleのdefaultまたはcompactのスタイルでラベルをカスタマイズするのは簡単ではないようです。
モディファイアであれこれ試行錯誤するのを辞めて楽になりましょう。
解決策としては、DatePicker側のラベルが表示されないようにして、別でラベルのViewを用意すれば良いのです。


```swift
// 1. ラベルのViewを用意する
HStack {
    Image(systemName: "calendar")
        .font(.system(size: 17))
        .foregroundStyle(.white)
    Text(exhibitDate.formatted(.dateTime.year().month().day()))
        .bold()
        .font(.system(size: 17))
        .foregroundStyle(.white)
}
// 2. 用意したViewに対してoverlayする
.overlay {
    DatePicker(selection: $selectedDate, displayedComponents: .date) {}
        .labelsHidden()
        .opacity(0.011)   
 // 3. labelsHidden(),opacity(0.011)付与する。ラベルが見えなくなる   
}
```
こちらの記事を参考にしました。
https://stackoverflow.com/questions/71254763/swiftui-compact-datepicker-with-custom-design

**この実装の課題について**
しかしながら、あくまでDatePickerのラベルは見えないだけで存在はしています。
そのため、見えないラベルがタップできなければカレンダーは表示されません。
ラベルが小さくてがユーザーがタップできない課題が発生します。
ラベルのサイズを大きくする方法は見つかりませんでした。


# **3. 多言語化(ローカライズ方法)について**
.environment(\.locale, Locale)を付与することで、DatePickerのラベルはローカライズされた表示となります。
シミュレータでも地域、言語を日本に設定することで、処理を確認することができます。

```swift
let locale = Locale(identifier: Locale.preferredLanguages[0])

// SwiftUI View内での処理
DatePicker(selection: $exhibitDate, displayedComponents: .date) {}
    .environment(\.locale, locale)
```


言語設定についてはこちらの記事を参考にしました。
https://qiita.com/uhooi/items/a9c9d8b923005028ce4e

# **4.カレンダー(graphycal)をモーダルとして用意する**

```swift
if showCalenderModal {
    Color.black.opacity(0.3)
        .edgesIgnoringSafeArea(.all)
        .onTapGesture { showCalenderModal = false }
    ZStack {
        RoundedRectangle(cornerRadius: 10)
            .foregroundStyle(.white)
            .frame(height: 320)
            .padding(16)
        DatePicker(selection: $exhibitDate, displayedComponents: .date) {}
                .datePickerStyle(.graphical)
                .dynamicTypeSize(.large)
                .frame(width: 320) // widthが320ではないとサイズが変わってしまう
                .padding(20)
                .environment(\.locale, locale)
    }
}
```
<img width=240 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128814/5a4769dd-1a30-f39f-b266-dd4078245d81.png">
rails、importmapの初めの一歩はstimulus

railsのimportmapについて理解し始めたころ、javasprict/controllersはなんだろうという疑問がでてきました。
これまで、controllersというフォルダは使ってこなかったため、使い方もわからず、色々調べた結果stimulusに行きつきました。
これが、controllersを理解するキーでした。

## stimulusとは
stimulusとはjavascriptのフレームワークです。
以下[公式参考](https://stimulus.hotwired.dev/handbook/introduction)
```
Stimulus は、控えめな目標を掲げた JavaScript フレームワークです。他のフロントエンド フレームワークとは異なり、Stimulus は、単純な注釈を使用して JavaScript オブジェクトをページ上の要素に接続することで、静的またはサーバーでレンダリングされたHTML (「既存の HTML」) を強化するように設計されています。

これらの JavaScript オブジェクトはコントローラーと呼ばれ、Stimulus は HTML 属性が表示されるのを待機しながらページを継続的に監視しますdata-controller。各属性について、Stimulus は属性の値を調べて対応するコントローラー クラスを見つけ、そのクラスの新しいインスタンスを作成し、それを要素に接続します。
```
html属性を使用して、JavaScriptやJQueryのコードを減らして、ビューとロジックの分離を促進するものみたいです。

## stimulusの使い方
実際に、使ってみます。
[公式](https://stimulus.hotwired.dev/)を参考にしました。

- まず、controllers配下にsample_controller.jsというファイルを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1328154/97d4eec2-8683-1e07-6fab-652dbb3a8bf4.png)

- js,thmlファイルに以下を記載
```js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller { 
  // コントローラーにターゲットを定義
  static targets = [ "name", "output" ]

  greet() {
    this.outputTarget.textContent =
      `Hello, ${this.nameTarget.value}!`
  }
}
```

```html
<div data-controller="sample">
  <input data-sample-target="name" type="text">

  <button data-action="click->sample#greet">
    Greet
  </button>

  <span data-sample-target="output">
  </span>
</div>
```
## コードの説明
- js部分

`import { Controller } from "@hotwired/stimulus"`
StimulusからControllerクラスをインポート

`static targets = [ "name", "output" ]`
コントローラーにターゲットを定義。この場合、nameターゲットとoutputターゲットが定義

`greet()`
greetメソッドは、clickイベントがボタンに対して発生したときに呼び出される。
このメソッド内で、nameターゲットから入力された値を取得し、outputターゲットに挨拶メッセージとして設定

- html部分

`<div data-controller="sample">`
このdiv要素は、sampleという名前のStimulusコントローラーを指定

`<input data-sample-target="name" type="text">`
このinput要素は、sampleコントローラーのnameターゲットとして指定
ユーザーが入力する名前を受け取る

`<button data-action="click->sample#greet">`
このbutton要素は、クリックイベントが発生したときにsampleコントローラーのgreetアクションを呼び出す

`<span data-sample-target="output">`
このspan要素は、sampleコントローラーのoutputターゲットとして指定
ここに挨拶のメッセージが表示

## 動作
では実際に動かしてみます。
文字を入力すると、右側に表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1328154/d5e4cc4e-996d-7591-054a-fde6339fbf23.png)

## 感想
importmapのjsの使い方がわからず、stimulusに行きつきました。
stimulusを理解して初めて、rails7のjsの使い方がわかった気がします。
誰かの参考になれば幸いです。

## 参考
[【Rails7】Stimulus入門！ | 概要 ~ 使い方まで詳しく解説](https://blog.to-ko-s.com/stimlus-introduce/#i-0)
[【初心者】Stimulus の使い方](https://qiita.com/SAPPOROBEER/items/ce29b3551e65ea901108)
[Stimulusをはじめよう](https://qiita.com/nazomikan/items/4dabc63b883aa71ce83c)
【PowerShell】サイズを指定してファイルを沢山作る方法

# はじめに

以前にLinux環境での[大きなサイズのファイルを沢山作る方法](https://qiita.com/nkojima/items/10dfafdb1dc2aade7a86)を記事としてまとめましたが、今回は同様の処理をPowerShellで実装する方法を記事としてまとめてみました。

（今回の方法はファイル作成が高速かどうかは分からないので、記事のタイトルから`高速`の文言を外しました）

# 作成したコード

* `fsutil`コマンドを使ってファイルを作成する方法は、[こちらのサイト](https://pig-log.com/powershell-create-dummyfile/)を参考にしました。
  * 上記のリンク先のサイトでは`fsutil`コマンドを使ったスクリプトが紹介されていますが、今回は関数としてまとめてみました。
* 以下の`CreateFiles`関数ではデフォルト引数が設定されているため、デフォルトだと「10KBのファイルを100個作る」という設定となります。
  * 引数で指定する必要があるのは出力先フォルダパスのみとなります。

```powershell:CreateFiles.ps1
function CreateFiles{
    param(
        [int]$fileCount = 100,
        [string]$fileSize = 10 * 1024, # 10KB
        [string]$outputPath
    )
    
    if (!(Test-Path -Path $outputPath)) {
        throw "出力先フォルダが存在しません。"
    }
    
    for($i=0; $i -lt $fileCount; $i++) {
        $fileName = Join-Path $outputPath "${i}.txt"
        fsutil file createnew $fileName ($fileSize) | out-null
    }
}
```

```powershell:テストコード
# C:\testに10KBのファイルを100個作る。
CreateFiles -outputPath "C:\test"

# C:\testに10MB（10*1024*1024B）のファイルを10個作る。
CreateFiles -fileCount 10 -fileSize (10 * 1024 * 1024) -outputPath "C:\test"
```

# 注意点

* [こちらのページ](https://atmarkit.itmedia.co.jp/ait/articles/0209/28/news002.html)を見ると、「fsutilで作成されたファイルの内容はゼロデータのみ」と書かれています。
  * そのため、ファイルの読み込み速度の測定などに利用する際には、fsutilで作ったファイルを使うのは不適当だそうです。


# 参考URL

* [サイズを指定してテスト用ファイルを大量に作成する](https://pig-log.com/powershell-create-dummyfile/)
* [大きなサイズのファイルを沢山作る方法](https://qiita.com/nkojima/items/10dfafdb1dc2aade7a86)
* [【Windows 11対応】巨大サイズのファイルをfsutilコマンドで簡単に作る](https://atmarkit.itmedia.co.jp/ait/articles/0209/28/news002.html)
[備忘録]PythonからOracleDatabaseへ接続する

# はじめに
＊備忘録なので荒いです
WindowsからOracleDBへアクセスする際に、手軽にexeからアクセスできるようにする

InstantClientは下記よりダウンロードしておく

https://download.oracle.com/otn_software/nt/instantclient/1918000/instantclient-basiclite-windows.x64-19.18.0.0.0dbru.zip

# スクリプト
## Pythonスクリプト
```python
import oracledb
import os

def get_oracle_info(dsn, user, password):
    try:
        # Oracleデータベースへの接続
        connection = oracledb.connect(user=user, password=password, dsn=dsn)
        cursor = connection.cursor()

        # Oracleのバージョン取得
        cursor.execute("SELECT * FROM v$version")
        version = cursor.fetchone()[0]

        # データベース名取得
        cursor.execute("SELECT sys_context('userenv', 'db_name') FROM dual")
        db_name = cursor.fetchone()[0]

        cursor.close()
        connection.close()

        return version, db_name

    except oracledb.DatabaseError as e:
        print(f"An error occurred: {e}")
        return None, None

def read_config(file_path):
    config = {}
    with open(file_path, 'r') as file:
        for line in file:
            key, value = line.strip().split('=')
            config[key] = value
    return config

if __name__ == "__main__":
    # 設定ファイルのパス
    config_file = 'config.txt'
    
    if not os.path.exists(config_file):
        print(f"Configuration file '{config_file}' not found.")
        exit(1)
    
    config = read_config(config_file)

    dsn = config.get('dsn')
    user = config.get('user')
    password = config.get('password')

    oracledb.init_oracle_client()
    version, db_name = get_oracle_info(dsn, user, password)

    if version and db_name:
        print(f"Oracle Database Version: {version}")
        print(f"Database Name: {db_name}")
    else:
        print("Failed to retrieve database information.")

    input("Press Enter to exit...")

```

## pyinstallerのspecファイル
pyinstallerでexe化
- Oracle Instant Clientは別途インストールしておく

```
# -*- mode: python ; coding: utf-8 -*-


a = Analysis(
    ['oracledb_select2.py'],
    pathex=[],
    binaries=[
        ('C:/path/to/instantclient-basiclite-windows.x64-19.23.0.0.0dbru/instantclient_19_23/*.dll', '.')
    ],
    datas=[],
    hiddenimports=['secrets', 'asyncio', 'uuid'],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    noarchive=False,
    optimize=0,
)
pyz = PYZ(a.pure)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.datas,
    [],
    name='oracledb_select',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=True,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
)

```

# exe化
```powershell
pyinstaller.exe --upx-dir C:\path\to\upx-3.96-win64  .\oracledb_select3.spec
```

upxを指定してあげることでexeの圧縮に繋がる


# ConfigFile
config.txt
```text
dsn=[host]:1521/[service]
user=testuser
password=WelCome123#123#
```

完成されたexeファイルと同じ階層にconfigファイルを置くことでで実行が可能になる
本番環境で、エラーが発生した時の修正フロー

# はじめてのデプロイ
早速エラーが出て苦戦したので、
エラーを修正する手順をまとめておきたいと思います。

 # 修正フロー
 ![スクリーンショット 2024-06-06 21.35.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782860/ce1d77ee-5b43-db8b-dacc-6bed3b6dc024.png)
上記のエラー画面が発生、この画面の場合Railsのエラーの可能性が高いため以下のコマンドを実行しRailsのログを確認します。

```
[ec2-user@ip-172-31-18-108 go_out_planning]$ $ sudo tail -f log/production.log
```

ログなどでエラーの原因を特定したら、該当の箇所を修正します。
その後、Cloud9のターミナルからGitHubにpushします

```
ec2-user:~/environment/アプリ名 (main) $ git add .
ec2-user:~/environment/アプリ名 (main) $ git commit -m "コミットメッセージ"
ec2-user:~/environment/アプリ名 (main) $ git push origin main
```

その後、SSHでインスタンスにログインしたターミナルでpullとkillをします。

```
[ec2-user@ip-172-31-18-108 go_out_planning]$ git pull origin main
[ec2-user@ip-172-31-18-108 go_out_planning]$ sudo kill $(cat tmp/pids/puma.pid)
```

最後に、もう一度サーバーを起動して修正されているか確認します。

```
[ec2-user@ip-172-31-18-108 go_out_planning]$ rails s -e production
```

修正されていればOKです。
今回はモデルがありませんとエラーが出ていたので、

```
$ bundle exec rails db:migrate RAILS_ENV=production
```

を実行すると解決しました！

# 最後に
本番環境でエラーがいっぱい出てきます…
開発環境では問題なくても本番環境でエラーがこんなに起きるのかと驚きました…
すべてのExcelファイルの各シートを倍率100%、A1セルに移動

# はじめに
Excelの資料作成の際の見た目をきれいにするためのマクロを作成しました。

# 作成したマクロ
見た目をきれいにしたいExcelファイルが配置されているパスにxlsmファイルを用意して、こちらのマクロを貼り付けて実行します。
``` xlsm
Sub SetZoomAndMoveToA1ForAllSheetsInAllFiles()
    Dim folderPath As String
    Dim fileName As String
    Dim wb As Workbook
    Dim ws As Worksheet
    Dim currentWorkbookPath As String

    ' 現在のExcelファイルのパスを取得
    currentWorkbookPath = ThisWorkbook.Path
    
    ' フォルダパスを設定
    folderPath = currentWorkbookPath & "\"
    
    ' フォルダ内のすべてのExcelファイルを取得
    fileName = Dir(folderPath & "*.xlsx")
    
    Do While fileName <> ""
        ' 各ファイルを開く
        Set wb = Workbooks.Open(folderPath & fileName, IgnoreReadOnlyRecommended:=True)
        ' 各シートに対して操作を実行
        For Each ws In Worksheets
            ' 表示しているシートを対象
            
            If ws.Visible = True Then
                ws.Select
                Range("A1").Select
                ' 表示位置を左上端に移動
                ActiveWindow.ScrollColumn = 1
                ActiveWindow.ScrollRow = 1
                ' 表示倍率を１００％に戻す
                ActiveWindow.Zoom = 100
            End If
        Next ws
        
        ' 最後に1シート目に移動
        wb.Sheets(1).Select
        
        ' ファイルを保存して閉じる
        wb.Save
        wb.Close
        
        ' 次のファイルに進む
        fileName = Dir
    Loop
    MsgBox "完了しました"
End Sub
```

# このマクロで行う編集内容
■編集対象
このマクロを実行するxlsmファイルと同じパスにあるExcelファイル(*.xlsx)

■編集内容
・すべてのシートに対して、表示率100%にして、A1セルに移動させる（非表示シートは除く）
・最後に1シート目に移動して保存する

■備考
強制的に編集し、保存するので
読み取り専用を促すメッセージは無視されて実行される

# 最後に
複数のExcelファイルの見た目を整えるときは、こちらのマクロ使ってみてください！
source .bashrcを自動的に行う．

* SSH接続が切れるたびに，
```shell
source ~/.bashrc
```
が反映されなくなる．
# 解決法
* SSHで接続した際に.bashrcではなく.bash_profileまたは.profileが読み込まれます。そのため、.bash_profileに.bashrcを読み込むように指示することが有効です。
```
echo -e "\nif [ -f ~/.bashrc ]; then\n   source ~/.bashrc\nfi" >> ~/.bash_profile
```
```
source ~/.bashrc
source ~/.bash_profile
```
SELECT句でつけた別名をORDER BYでは使えてGROUP BYでは使えない理由

### SELECT文の内部的な実行順序
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY

上の実行順序が重要になる。
SELECT句を実行するまでは、別名は付けられていないので、当然WHEREやGROUP BYで別名を使うことはできない。
Bun で p5.js の開発環境を構築する

## TL;DR
```
git clone https://github.com/shinjikuriy/p5js_bun.git
```

## 参考URL
* [VS Code & TypeScriptとp5.jsで始めるモダンなクリエイティブコーディング入門](https://ics.media/entry/210129/)
* [How to use Bun with p5.js](https://bulkan-evcimen.com/bun-p5js/)

## 始めるにあたって必要なもの
- [Bun](https://bun.sh)
- お好きなテキストエディタ
- お好きなWebブラウザ

ここでは Bun `v1.2.12` を使っています。最新のものをお使いください。

## 環境構築手順
### プロジェクトディレクトリを作成し、ディレクトリ下で `bun init`
```sh:sh
mkdir p5js_bun && cd p5js_bun
bun init
```

---
### `p5` と `@types/p5js` をインストールする
それぞれ、 p5.js 本体と型情報です。
```sh:sh
bun add p5@1.1.15
bun add -d @types/p5
```

プロジェクトディレクトリは、以下のようなファイル構成になっているはずです。
```
|--.gitignore
|--README.md
|--bun.lock
|--index.ts
|--node_modules
|--package.json
|--tsconfig.json
```
---
### `src` ディレクトリを作成し、開発用のファイルを置く
```sh:sh
mkdir src
mv index.ts src/
touch src/index.html src/sketch.ts
```

このファイル構成は任意です。
シンプルなプロジェクトの場合 `src` フォルダはなくてもいいと思います。

### `Bun.serve` のための設定
p5.js を実行し、なおおかつホットリローディングするように Bun server の設定を書きます。

```ts:src/index.ts
import { serve } from 'bun'
import homepage from './index.html'

const server = serve({
  routes: {
    '/': homepage,
  },
})

console.log(`Server is running on ${server.url}`)
```

```html:src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style type="text/css">
        html,body{
            margin: 0;
            padding: 0;
        }
    </style>
    <title>p5js</title>
</head>
<body>
    <script type="module" src="sketch.ts"></script>
</body>
</html>
```
これで開発環境が整いました。

なお、以上の環境構築手順をまとめたものが、冒頭に記載した [Git リポジトリ](https://github.com/shinjikuriy/p5js_bun)です。
clone してお使いください。
```
git clone https://github.com/shinjikuriy/p5js_bun.git
```

## コードを書いて動かしてみる
p5.js のコードは `src/sketch.ts` に書きます。
インスタンスモードを使いましょう。補完とアノテーションが効きます。

### コード例
```ts:src/sketch.ts
import p5 from 'p5';

const sketch = function(p: p5) {
  let diameter: number;
  p.setup = function() {
    p.createCanvas(p.windowWidth, p.windowHeight);
    p.noLoop();
    p.noStroke();
    p.fill(255);
    p.background(0);

    diameter = p.width <= p.height ? p.width : p.height;
    diameter /= 2;
  };

  p.draw = function() {
    // draw a circle in the middle of the canvas
    p.circle(p.width/2, p.height/2, diameter);
  };
};

new p5(sketch);
```
p5.js のスケッチを実行するために Bun サーバーを立ち上げます。

```sh:sh
bun src/index.ts
```

`http://localhost:3000` を見に行くと以下が表示されました。
![Screenshot 2025-05-13 at 20.05.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494074/430ae419-7bfb-4464-adda-1c4e708fc993.png)

`Bun.serve` はホットモジュールリローディング機能があるので、コードを変更して保存するとすぐに反映されます。


## おわりに
いったん開発環境の構築のみ行いました。
JavaScriptへコンパイルするスクリプトも追って追加したいです。

設定におかしなところや改善できる点があればご教示くださいますと幸いです。
[初級] C++: スマートポインタの基本

スマートポインタの基本
標準ライブラリの高機能なスマートポインタの話ではなく、スマートポインタのひな型の説明

:::note info
本記事の前提条件は以下の通りです。
* 初心者向け
* とは言っても、何らかのプログラムはそれなりに書けるけど、C とか C++ はちょっと、という人向け
* ざっくり概要しか説明しないので細かいことは気にしないでいただきたい
* Visual Studio 2013 くらい～
* Windowsプログラム (CUI, GUI)
* コードの検証
    * 開発環境: Visual Studio 2022, x64, Release ビルド
    * 実行環境: Windows 10
:::

:::note info
* 本記事は上から順番に読む前提となっている
:::

:::note info
* 「Visual Studio 2013 くらい～」と書いてあるが、本記事の内容だと現在過去未来のどのバージョンでもほぼ同じ
* 「Windowsプログラム (CUI, GUI)」と書いてあるが、本記事の内容だとどの OS でもほぼ同じ
:::

# スマートポインタでない場合

100バイトのメモリをヒープに確保して利用することを考える。
スマートポインタを使わない場合は以下のようになる。

```cpp
// c
char* p = (char*)malloc(100);
strcpy_s(p, 100, "hello");
printf("%s\n", p);
free(P);

// c++
auto* p = new char[100];
strcpy_s(p, 100, "hello");
std::cout << p << "\n";
delete [] p;
```

メモリの確保と解放が別になっているので、解放し忘れ、いわゆるメモリリークを起こしやすい。
また、確保したメモリを別のオブジェクトに渡して使うような場合、解放のタイミングが非常に難しいものとなる。

# RAII に基いてクラス化する

次のようなクラスを考える。

```cpp
class Buffer
{
public:
    Buffer(size_t size)
    {
        p = new char[size];
    }
    ~Buffer()
    {
        delete [] p;
    }
    char* p = nullptr;
};
```

次のように使える。

```cpp
Buffer buf(100);
strcpy_s(buf.p, 100, "hello");
std::cout << p << "\n";
```

スコープから外れるときにデストラクタが呼ばれるため、メモリは適切に解放される。
これをスマートポインタというのもおこがましいが、これがスマートポインタの基本となる。

:::note info
上記の例だと、メモリの解放は自動的に行われるようになったが、他の関数に渡したり、複数のオブジェクト間で共有したりといったことはうまくできない。
標準ライブラリにある、`std::unique_ptr`, `std::shared_ptr` などはもっと便利な機能が備わっており、非常に柔軟に使うことができる。
:::

以上。
Pythonでのコマンドライン引数処理 - `sys.argv` の使い方

## はじめに

Pythonスクリプトを実行する際に、コマンドライン引数を受け取ることができます。これにより、スクリプトに動的な入力を提供し、柔軟な処理を実現することができます。Pythonでは、`sys`モジュールの`argv`を使用してコマンドライン引数を処理します。

## `sys.argv`の概要

`sys.argv`は、Pythonの`sys`モジュールに含まれるリストで、コマンドラインからスクリプトに渡された引数を格納します。このリストの最初の要素（`sys.argv[0]`）はスクリプトの名前で、その後に続く各要素が実際のコマンドライン引数です。

## 基本的な使用方法

まず、`sys`モジュールをインポートする必要があります。次に、`sys.argv`を使って引数を取得し、処理します。

```python
import sys

def main():
    print("スクリプト名:", sys.argv[0])
    print("引数のリスト:", sys.argv[1:])

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

### 実行例

このスクリプトを `args_example.py` として保存し、次のようにコマンドラインから実行します：

```bash
python args_example.py arg1 arg2 arg3
```

出力は次のようになります：

```
スクリプト名: args_example.py
引数のリスト: ['arg1', 'arg2', 'arg3']
```

## 引数の数をチェックする方法

スクリプトが期待する引数の数をチェックすることが重要です。例えば、2つの引数が必要なスクリプトの場合、以下のようにチェックします：

```python
import sys

def main():
    if len(sys.argv) != 3:
        print("Usage: python script.py <arg1> <arg2>")
        sys.exit(1)

    arg1 = sys.argv[1]
    arg2 = sys.argv[2]

    print("引数1:", arg1)
    print("引数2:", arg2)

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

### 実行例

```bash
python script.py hello world
```

出力：

```
引数1: hello
引数2: world
```

## コマンドライン引数を用いた実例

次に、引数を使用して簡単な加算を行うスクリプトを紹介します。

```python
import sys

def main():
    if len(sys.argv) != 3:
        print("Usage: python sum.py <num1> <num2>")
        sys.exit(1)

    try:
        num1 = float(sys.argv[1])
        num2 = float(sys.argv[2])
    except ValueError:
        print("引数は数値である必要があります")
        sys.exit(1)

    result = num1 + num2
    print(f"合計: {result}")

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

### 実行例

```bash
python sum.py 3.5 7.2
```

出力：

```
合計: 10.7
```

## エラー処理

コマンドライン引数が不足している場合や、正しい形式でない場合のエラー処理を行います。

```python
import sys

def main():
    if len(sys.argv) != 3:
        print("Usage: python script.py <num1> <num2>")
        sys.exit(1)

    try:
        num1 = float(sys.argv[1])
        num2 = float(sys.argv[2])
    except ValueError:
        print("引数は数値である必要があります")
        sys.exit(1)

    result = num1 + num2
    print(f"合計: {result}")

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

## まとめ

- **`sys.argv`**: コマンドライン引数をリストとして保持。
- **`sys.argv[0]`**: スクリプトの名前。
- **`sys.argv[1]`以降**: コマンドラインから渡された引数。
- **エラー処理**: 引数の数や型を確認し、適切にエラーメッセージを表示。

`sys.argv`を使うことで、スクリプトに動的な入力を渡し、柔軟な処理を行うことができます。正しい引数の数や型をチェックすることで、スクリプトの信頼性を高めることができます。
【heroku】サブスクを再契約したらアプリが動かなかった時の解決方法

# きっかけ
久しぶりにデプロイしたアプリを動かすために、herokuサブスクを再契約したら以下のエラーが出た。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/17e61094-3cc2-c153-b949-65c8150efe74.png)

# エラーの確認方法
コンソールでアプリのルートディレクトリにアクセスし、`heroku logs --tails`と入力する。→以下のエラーが表示された。
```
 Error: The following error occurred:
 »     Missing required flag app
 »   See more help with --help
 ```
 コンソールでherokuにログインしていなかったので、`heroku login`と入力してherokuにログインする。
再度`heroku logs --tails`を入力するが同じエラーになる。

調べて以下のサイトを参考にしながら、gitとherokuを紐づける。
https://qiita.com/hirokik-0076/items/71c104158fa8b963ba85
1. `git remote -v`を入力すると、herokuがリポジトリ一覧にない。
2. `heroku git:remote -a アプリ名`を入力してgitとherokuを紐づける。
3. `heroku config`と入力してアプリが紐づいているか確認する。

上記をやってから再度、`heroku logs --tails`を入力すると、以下のログが表示された。
```
2024-05-31T12:48:09.473391+00:00 heroku[router]: at=error code=H14 desc="No web processes running" method=GET path="/" host=アプリ名.herokuapp.com request_id=xxxxxxxxxxxx fwd="xxxxx" dyno= connect= service= status=503 bytes= protocol=https
```

# 原因
Eco Dynos がOnになっていなかった。
herokuのアプリのページで、Recources > Eco Dynos を見るとスイッチがOffになっていた。
スイッチをOnにしてサイトにアクセスするとアプリが動いた。
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/f4a49630-2321-224c-6629-ab2f068af8ee.png)

# 参考サイト
https://qiita.com/hirokik-0076/items/71c104158fa8b963ba85
https://devcenter.heroku.com/articles/error-codes#h14-no-web-dynos-running
Top 9 White Label SaaS Platforms To Resell in 2024

White-label SaaS platforms are software solutions developed by one company but sold and branded by another. This arrangement allows resellers to offer these services under their brand, providing a seamless experience to their customers.

The Increasing Relevance of White Label SaaS Solutions for Reselling
In today’s rapidly changing digital environment, white-label SaaS solutions offer businesses the opportunity to diversify their product offerings without the overhead of developing new software from scratch.

Overview of How White Label SaaS Platforms Can Benefit Resellers?
White Label SaaS Platform To Resell

Resellers can leverage white-label SaaS platforms to quickly enter new markets, enhance their product portfolios, and generate additional revenue streams while focusing on their core competencies.

1. White Label Marketing Automation Tools
Features and Benefits of Opting for White Label Marketing Automation

These tools streamline marketing efforts, automate repetitive tasks, and provide detailed analytics, allowing agencies to offer comprehensive solutions to their clients.

Examples of Top White Label Marketing Automation Tools to Consider for Reselling in 2024:

-OnGraph
-Automate.io
-Sendinblue
2. White Label Email Marketing Services
Advantages of White Label Email Marketing Services for Agencies

White-label email marketing services enable agencies to offer customized email marketing solutions to their clients, including campaign management and analytics.

Leading White Label Email Marketing Services Suitable for Reselling in 2024:

Mailchimp White Label
Constant Contact
3. White Label SEO Tools
Importance of SEO Tools in Digital Marketing

SEO tools are essential for analyzing website performance, conducting keyword research, and implementing effective SEO strategies.

Criteria for Selecting the Best White Label SEO Tools to Resell

-Comprehensive feature set
-Scalability
-User-friendly interface
Top White Label SEO Tools for 2024:

-SEMrush
-Ahrefs
Read More: https://www.ongraph.com/white-label-software/
Clipyの環境設定画面が開けなくなってしまった場合のトラブルシューティング

クリップボード拡張Macアプリ「Clipy」のステータスバーのメニューアイコンを非表示に設定したことをきっかけに、メインメニューや環境設定が開けなくなってしまいました。

その時の解決策を備忘録として残します。

https://clipy-app.com/

## 原因
Clipyの環境設定画面を開く動線は、以下2つが用意されています。
1. ステータスバーのメニューアイコンから開く
![img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585443/eeb9a667-9559-9325-32cb-97b179d7a5e9.png)

1. ショートカットキーでメインメニューから開く（デフォルトは`Command`+`Shift`+`V`）
![shortcutkey.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585443/f7447348-01a2-3f5e-a9e4-536f1bae61fd.png)

しかし、1は非表示にしてしまってアクセスできないし、この時の私はメインメニューを開くショートカットキーも覚えておらず...詰みました。

## 解決策
Issue#101で、開発者のEcona77さんが解決策を挙げて下さっていました。

> 初期化の方法は以下の３通りが簡単かと思いますので、どれかをお試し下さい。
> 
> 1. 「AppCleaner」等のアプリ削除ツールを使用してClipyを削除した後に再度インストール
http://itea40.jp/application/mac-utilities/appcleaner/
> 2. ターミナル等をご使用していただける方ですと以下のコマンドを実行して再起動
> `defaults delete com.clipy-app.Clipy`
> 3. ショートカットキーの設定をいじっていないのでしたらデフォルトのメニュー呼び出しが Command + Shift + v ですので、メニューを起動し設定を変更
> 上記の方法で解決しないようでしたら再度御連絡いただけると助かります。

https://github.com/Clipy/Clipy/issues/101

今回は2の方法で初期化を試みました。

## 結果
ターミナルを起動して以下のコマンドを実行すると、スニペットの登録内容は保持されたまま、**無事、メニューアイコンが復活**しました。
```
defaults delete com.clipy-app.Clipy
```
### 注意事項
[一般] > [クリップボード履歴] > [記憶する履歴の数]の設定値が初期化されていることを確認しました。
そのほかの設定も初期化されている可能性があるので、設定をカスタマイズしている人はコマンド実行後に設定内容を見直すことをお勧めします。

以上。それでは。
ChatGPTの学習データのアーキテクチャ・ビジネス活用を解説

![ChatGPTの学習データのアーキテクチャ・ビジネス活用を解説.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3544821/b7415689-e9bd-47a7-8d68-b36c18536f12.png)


ChatGPTはAIの分野で革新的な技術の一つです。性能と利用可能性は学習データの品質と量に依存します。この記事ではChatGPTの学習データ、メリット・デメリット、入手方法、そしてビジネス活用について探ります。

<h2>ChatGPTとは

ChatGPTは、OpenAIによって開発された自然言語処理モデルです。大量のデータを基にトレーニングされ、人間のような自然な対話が可能です。チャットボットや文章生成、言語理解など、さまざまな分野で利用されています。深層学習技術を活用し、幅広いトピックに対応しています。その性能は高く、今後も進化が期待されています。

<h2>ChatGPTのアーキテクチャ

ChatGPTのアーキテクチャは、人工知能の分野における重要な進展の一つです。このアーキテクチャは、多くのステップから成り立っており、その過程には様々な技術が組み込まれています。

![ChatGPTのアーキテクチャ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3544821/a7743a47-b02b-8f1e-605a-c3d600355b5c.jpeg)

写真：ATRIA Innovation

ChatGPTのアーキテクチャは、以下のステップで構成されます：

<h3>ステップ 0: 大規模コーパスを用いた汎用モデルのトレーニング 

ChatGPTの最初のステップは、大量のテキストデータを使って汎用モデルをトレーニングすることです。さまざまなソースから収集されたテキストデータがモデルに提供され、言語理解とパターン抽出が行われます。これにより、モデルは広範なトピックに対応し、一般的な言語処理能力を獲得します。

<h3>ステップ 1: 人間のラベラーによるデータの収集と教師あり学習 

次に、人間のラベラーによってラベリングされたデータが使用されます。これらのデータはモデルに正確な出力を生成するための教師信号として機能し、教師あり学習が適用されます。モデルは人間のラベラーに示されたパターンと規則を学習し、性能と品質が向上します。

<h3>ステップ 2: モデルの出力の人手による評価と報酬モデルの作成 

その後、モデルの出力に対する人間の評価が行われます。人間のランキングに基づいて、モデルの出力の品質が評価され、フィードバックが提供されます。このフィードバックは、報酬モデルの作成に役立ちます。報酬モデルは、モデルの学習と進化を促進するために使用されます。

<h3>ステップ 3: Proximal Policy Optimization(PPO)などの強化学習アルゴリズムを用いた出力生成方策の最適化 

最後のステップでは、報酬モデルに対する出力生成方策の最適化が行われます。強化学習アルゴリズムが使用され、モデルはより効率的に学習し、より優れた出力を生成する能力を向上させます。

ChatGPTのアーキテクチャは、これらのステップを経て進化し、高度な自然言語処理の能力を持つモデルが実現されます。これにより、自然な会話や文章の生成が可能になり、様々な応用分野での活用が期待されます。

<h2>ChatGPTの学習データの入手方法

ChatGPTの学習データを入手する方法は以下の通りです：
公開データセット：オープンソースのコミュニティや研究機関から無料で入手可能です。
・プライベートデータセット：企業や組織が保有しており、協力関係やライセンス契約を通じてアクセスできる場合があります。
・ウェブスクレイピング：ウェブページから情報を収集する方法ですが、法的制限に留意する必要があります。
・データ提供サービス：企業やプラットフォームが提供するカスタマイズされたデータセットを利用できます。
これらの方法を活用して、高品質な学習データを入手し、ChatGPTのトレーニングに利用します。

※関連記事：<a href="https://hblab.co.jp/blog/chat-gpt-the-new-retail-revolution/">チャットGPT：新たな小売業界の革命</a>

<h2>ChatGPTのビジネス活用

ChatGPTはビジネスで幅広く活用されるAIツールです。以下はその一例です：
・カスタマーサポートの強化：顧客とのリアルタイムな対話を可能にし、自動応答システムを構築します。
・マーケティングキャンペーンの支援：ターゲットオーディエンスに合ったパーソナライズされたコンテンツを生成します。
・内部プロセスの効率化：ルーチンワークや業務を自動化し、会議の議事録を要約したり、ドキュメントを生成します。
・顧客データの分析：顧客からのフィードバックやレビューを分析し、傾向やパターンを特定します。
・教育やトレーニング：社内の教育やトレーニングプログラムを強化し、質問に応じて詳細な説明やトレーニング資料を提供します。
これらはChatGPTのビジネス活用の一部に過ぎず、その可能性は拡大しています。ChatGPTを活用することで、顧客満足度の向上や業務効率化が期待できます。

<h2>まとめ

ChatGPTは、現代社会において非常に重要な技術ですが、その利用には慎重さが必要です。適切な注意点や倫理的配慮を持ってChatGPTを活用することで、その潜在能力を最大限に引き出すことができます。

詳しくは下記の記事もご参照ください。
➡ <a href="https://hblab.co.jp/blog/explaining-the-architecture-and-business-utilization-of-chatgpt-learning-data/">ChatGPTの学習データのアーキテクチャ・ビジネス活用を解説</a>

生成AIに関して、弊社には8年以上の研究経験を持つ専門家がおり、カスタマイズされたチャットボット、データ分析などの分野においても、多くの実績の経験があります。
[初級] C++: 純粋仮想関数と抽象クラス

純粋仮想関数、抽象クラス、インターフェース

:::note info
本記事の前提条件は以下の通りです。
* 初心者向け
* とは言っても、何らかのプログラムはそれなりに書けるけど、C とか C++ はちょっと、という人向け
* ざっくり概要しか説明しないので細かいことは気にしないでいただきたい
* Visual Studio 2013 くらい～
* Windowsプログラム (CUI, GUI)
* コードの検証
    * 開発環境: Visual Studio 2022, x64, Release ビルド
    * 実行環境: Windows 10
:::

:::note info
* 本記事は上から順番に読む前提となっている
:::

:::note info
* 「Visual Studio 2013 くらい～」と書いてあるが、本記事の内容だと現在過去未来のどのバージョンでもほぼ同じ
* 「Windowsプログラム (CUI, GUI)」と書いてあるが、本記事の内容だとどの OS でもほぼ同じ
:::

:::note info
前提知識として必要と思われる情報
* [[初級] C++: クラスの基本 - 拙著](https://qiita.com/yasu62347/items/f544e486ea2cc1965c95)
* [[初級] C++: 機能の拡張とは - 拙著](https://qiita.com/yasu62347/items/54e8bbc63fb6a996ff88)
* [[初級] C++: 継承 - 拙著](https://qiita.com/yasu62347/items/8b7aa258fca08ea97c64)
* [[初級] C++: 仮想関数 - 拙著](https://qiita.com/yasu62347/items/a6c193db601f2092c991)
:::

# 純粋仮想関数
以下のようにすると、実装のない仮想関数を宣言することが出来る。
これを、純粋仮想関数という。

```cpp
class Cook
{
public:
    virtual void Wash() = 0;
};
```

# 抽象クラス
純粋仮想関数を1つでも持っているクラスを抽象クラスという。
抽象クラスをインスタンス化することはできない。

:::note info
仮想関数は派生クラスでオーバーライドされたものを呼び出す。したがって、純粋仮想関数をオーバーライドした派生クラスを用意すれば、抽象クラスである基底クラスにキャストした状態でも呼び出すことが出来る、ということになる。
:::

# 純粋仮想関数の実装

そもそも仮想関数は、インスタンス化された派生クラスで継承された関数を呼び出すためのものであるが、それとは別にその抽象クラス自体の関数として実装することもできる。

```cpp
class Base
{
public:
    virtual ~Base() = 0;
};

// inline 関数として、あるいはソースファイルで実装
Base::~Base(){}
```

これは専らデストラクタを念頭においたものであると思われる。デストラクタを純粋仮想関数とした場合でも、基底クラスにはデストラクタの実装が必要なためである。
なお、純粋仮想関数を実装した場合でも、仮想関数として呼び出すことができるわけではないので、依然として抽象クラスであり、インスタンス化することはできない。

# インターフェース
パブリックな純粋仮想関数のみのクラスを「インターフェース」という。
```cpp
class Cook
{
public:
    virtual void Wash() = 0;
    virtual void Cut() = 0;
    virtual void Grill() = 0;
};
```

:::note info
C++ には他言語にあるような `interface` というものはないが、このインターフェースが同様の機能をもつものと考えてよい。
:::

以上。
業界で最も注目されている生成AIのトレンドを5選解説

<h2>はじめに

生成AIが注目され始めたのは、2022年11月のChatGPTリリースからです。生成AIは大量のデータからパターンを学習し、テキストや画像、音楽、動画などを自動で生成します。ユーザーはテキストをAIに送信することで、アイデアの提案や作業効率化が可能です。ビジネスで生成AIを活用する際には、最新のトレンドを把握することが重要です。この記事では、注目の生成AIトレンドを紹介します。

<h2>そもそも生成AIとは？

<a href="https://hblab.co.jp/blog/explaining-the-mechanism-problems-and-future-of-generative-ai/">生成AIとは</a>、深層学習を用いて新しいコンテンツを生み出すAIです。テキスト、画像、動画など多岐にわたり、多くの注目を集めています。従来のAIは既存データから回答を出すのが一般的でしたが、生成AIは新しいコンテンツを創り出すことができます。これにより、アイデア作成や業務効率化に役立ち、ビジネスの現場でも活用が広がっています。

<h2>最新のAIトレンド5選

AIは日々新しい技術が発達しており、その中でChatGPTやチャットボットなどあらゆる製品が注目されています。

生成AIは企業に導入されているツールが幅広く、さまざまな技術がトレンドとなっています。

![2024年に話題になりそうな技術革新・トレンド予想.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3544821/add4ecd7-9168-50d6-6165-b18575f51c62.png)


<a href="https://prtimes.jp/main/html/rd/p/000000291.000030691.html">PR TIMES</a>によると、2024年の技術革新・トレンドは生成AIが最も回答が挙がっていました。

多くのユーザーが生成AIを回答した理由は、実業務で活用できる幅が広がったというのが一つです。

生成AIの急速な進化に伴い、製造業や金融業などの業界や社会に与える影響力が大きいといえます。
ここでは、生成AIの最新のトレンドについて、企業の目的に合ったツールなどを詳しく解説します。

<h3>ChatGPT

![ChatGPT growth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3544821/8d741277-4cbb-1c59-8610-b69601e1cf38.png)


ChatGPTとは、質問に対して適切な文章を生成する自然言語処理モデルです。インターネット上の膨大なテキストデータを基に学習し、文章作成や翻訳など幅広い分野に対応できます。リリース後はカスタマーサポートや自動文章生成に活用され、多くの人気を集めています。
チャットボット
生成AIでは、ユーザーの質問にチャット形式で回答するチャットボットがトレンドです。チャットボットは24時間365日稼働し、オペレーターの負担を減らせるのが大きな特徴です。企業での導入も増え、高精度な回答が可能です。

<h3>ChatGPT-4o

ChatGPT-4oは、2024年5月にOpenAIが発表した最新の生成AI技術です。テキスト、画像、音声を統合的に処理し、感情を持つかのように応答できます。無料から利用でき、リアルタイム翻訳や3Dアバターとの会話に活用されています。

<h3>Gemini

Geminiは、2023年12月にGoogleが開発した高性能生成AIモデルです。テキスト、画像、音声を同時に処理し、最新の情報を提供できます。特定のテーマに関する質問に対して、特性やトレンドを分析して回答を生成します。

<h3>DALL・E3

DALL・E3は、2023年9月にOpenAIがリリースした画像生成技術です。プロンプトに入力するだけでオリジナルな画像を生成できます。Microsoftアカウントを使用すると無料で利用でき、ChatGPTの有料版でも利用可能です。

<h3>Sora

Soraは、2024年にOpenAIが開発した動画生成モデルです。プロンプトに入力するだけで最長1分間の動画を生成できます。背景や被写体を正確に把握し、本格的な動画編集も可能です。

<h3>音声認識

音声認識とは、入力された音声データを解析し、最適な回答を返すシステムです。テキストを入力するだけで音声読み上げができ、コールセンターや新人トレーニングに活用されます。速くてミスが少ないため、注目度が高い技術です。

<h2>生成AIに使われるモデル

生成AIに用いられる代表的なモデルには、VAE、GAN、拡散モデルがあります。
VAEは元の画像を潜在変数に圧縮し、それを元に新しい画像を生成するモデルです。解像度はやや低く、ビジネスでの異常検知などに活用されます。

GANは敵対的生成ネットワークで、生成器と識別器が競い合って精度の高い画像を生成します。画像のアレンジや効率的な生成に利用されます。

拡散モデルはノイズを徐々に除去して元の画像を復元するモデルで、修復や自動生成に効果的です。

<h2>まとめ

生成AIは技術進歩が著しく、音声認識や文章・画像生成など幅広い分野で注目されています。業務効率化や新たなアイデア提案が可能ですが、法的リスクも考慮が必要です。

詳しくは下記の記事もご参照ください。
<a href="https://hblab.co.jp/blog/5-generative-ai-trends/">業界で最も注目されている生成AIのトレンドを5選解説</a>
Scala.jsで将棋学習ツールを作った

# TL;DR

将棋の定跡を学習するための「ShogiTree」というWebアプリを作りました。
この記事では、開発日誌的なテイストでShogiTreeについて共有したいと思います。


# 背景 ｜ 将棋の本は難しい

将棋の本には、次のように符号を駆使した文章が現れることが多々あります。

> ☖９三同玉は☗８五桂(変化図18)と打てば、 ☖９ニ玉は☗９九香☖８ニ玉☗９ニ飛から後手玉が詰むし、☖８ニ玉は☗９三角の打ち込みが厳しく先手勝勢となる。

いかがでしょうか？読者は盤面図を見ながら定跡を学ぶことになりますが、非常に分かりにくいですよね。頭の中で駒を動かしながら盤面の変化を理解する必要があり、将棋を始めたばかりの人には難解です。

また、定跡には「相手がこう指してきた場合は、自分はこう指せば良い」といった条件分岐が多く、本を使った定跡の学習や暗記は難しいと思われます。

# 解決策

将棋の定跡を反復的に学習し、盤面の変化を視覚的に捉えることができるツールを作成しました。
以下のページから利用可能です。



![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/422592/1a3991c7-cfbc-964c-5099-f273fe769a47.gif)

上記の図は、作成したアプリケーションのデモンストレーションでして、
盤面の駒を操作することによって、盤面の変化が樹形図として可視化されます。

また、盤面の操作するダイアログから「棋譜暗記用リンク」が利用可能でして、
棋譜を反復的に暗記するためのトレーニングが可能です。

因みにですが、「棋譜暗記用リンク」の遷移先は、以前Qiita記事でも取り上げた「棋譜暗記Web」になります。
https://qiita.com/tobita_yoshiki/items/068ced648b59af656d1d

# 技術的なところ

## 採用言語

TypeScriptを使った開発が無難かとも思いましたが、
イミュータブルな変数や高階関数を駆使したコーディングスタイルが好きなので、
私が普段業務で使用しているScala言語を採用しました。

## 採用ライブラリ

### React Flow

https://reactflow.dev/

グラフ描画のUIが美しいという理由でReact Flowを採用しました。カスタマイズ性も高く、樹形図の描画をライブラリに任せることもできるので、今回のユースケースにはピッタリだと思いました。

余談ですが、樹形図を綺麗に描画するアルゴリズムは大変奥が深いようです。木を描画する際、ある子要素によって構成されるサブツリーと別の子要素によって構成されるサブツリーが重ならないようにするという難しい課題があります。

参考:

https://llimllib.github.io/pymag-trees/

### slinky

https://slinky.dev/

slinkyとは、ReactアプリケーションをScalaで開発するためのライブラリです。
React Flowを使用するために導入しました。

### ScalablyTyped

https://scalablytyped.org/docs/readme.html

ScalablyTypedは、TypeScriptの型定義をScala.jsプロジェクトで利用できるように変換するツールです。これにより、TypeScriptの型定義を持つJavaScriptライブラリをScala.jsプロジェクトで型安全に利用することができます。

実際に使ってみたところ、TypeScriptの型定義をScala側に取り込めないケースもありますが、自前でJavaScriptのラッパーを書く必要がないので非常に便利でした。

### デプロイ先

[Netlify](https://www.netlify.com/)にデプロイしました。
せっかく作ったので shogitree.com というドメインを取得しました。

生まれて初めてドメインを取得しましたが、Netlify上で画面を操作してクレジットカード情報を入力するだけで簡単に取得できました。思ったより簡単に取得できて、少し高揚しました🤩

## 苦戦したところなど

### 実は将棋のルールは多い

開発当初はオセロより若干複雑そうだなぐらいにしか思っていなかったですが、
ルールを洗い出していくと、かなりルールが多いことに気づきました。

例えば、以下のようなビジネスルールがあります。

* 駒によって動ける場所が異なる
* 「飛車, 龍, 角, 馬, 香車」問題
  * どれも一直線に動ける駒だが、相手の駒があるところまでしか進めない
  * 自分の駒があるとその一歩手前で止まる必要がある
* 相手の成駒を取ると、成る前の状態で持ち駒に加わる
* 相手の陣営に入ると成れる/相手の陣営内にある駒を動かすと成れる
* 持ち駒を相手の駒の上に打てない
* 最上段に香車や歩を移動させる場合に必ず成る必要がある
* その他、禁じ手
  * 手間だったのでShogiTreeではバリデーション等は実装していないですが、二歩や打ち歩詰め、王手放置などがあります

### JavaScriptをラップする問題

ScalablyTypedを使って補助的に型情報を取ることができますが、JavaScriptライブラリによっては型情報を取得できず、自前でJavaScriptをラップする処理を書く必要があります。

また、JavaScriptライブラリをラップする際に`asInstanceOf`のような危険な処理が多く出てくるため、この辺りも気になります。

### TypeScriptを用いた開発と比べるとコンパイルが遅い

これはScalaの問題から受け継いだものですね。

### デバッグの問題

React、JavaScript、TypeScriptの型定義(ScalablyTyped)、Scala.jsなど、多くの依存関係があるため、問題が発生したときにどのレイヤーで問題になっているか特定する必要がありました。

Scala.js越しにReactを遠隔操作している感覚があり、デバッグ時に苦戦することがありました。

# 総括

JavaScriptをラップする問題や依存関係の多さなどの課題はありましたが、総じて開発者体験は良かったです。日頃Scala以外の言語で開発する際、Scalaならこう書けるのにと思うことが多々ありますが、それがないのは快適でした。

全体的に、Scala.jsを使った開発はまだ発展途上だと感じており、今後のエコシステムの発展に期待しています。(余力があれば自分でOSSにコミットします)

---

# 追記: 2024/11/04

Firebaseにサイトを移行しました

https://shogitree-1aca5.web.app/welcome
Blazor Serverでリンクで遷移するページ間で変数を共有する

親と子コンポーネントによるパラメータやり取りはBlazorの醍醐味で入門書通りできると思います。ここではリンクで遷移したページ間で変数を共有する方法を掲載します。
## データクラスの準備
例としてプロパティが一つしかない単純な **UserSessionServiceクラス** を準備します。
```c#:UserSessionService.cs
    public class UserSessionService
    {
        public string UserData { get; set; } = "2600";

    }
```
初期値は2600にしました（なんとなく）
## Program.csを編集
自動生成されたアセットのProgram.csは以下のようになっていると思います。
ここに　**builder.Services.AddScoped<UserSessionService>();**　を追記します。
```c#:Program.cs
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();

builder.Services.AddScoped<UserSessionService>();// ←←　◆追記する◆

var app = builder.Build();
```
詳しくは調べていませんが、例のような単純な値クラスではなく少し複雑なクラスで試したときはbuilder.Build()でエラーが発生しました。

## 元ページ(Page1)
**＠inject UserSessionService UserSession**　と上部に記述すると**UserSession**という名前のインスタンスが使えるようになるイメージです。 
inputに**UserSession**をバインドし、1文字入力するたびにバインドが反映するように記述します。
page2にリンクで飛びましょう
```c#:Page1.cs
@page "/page1"
@inject UserSessionService UserSession

<h3>Page 1</h3>

<p>@UserSession.UserData</p>

<input @bind-value="UserSession.UserData" @bind-value:event="oninput" />

<a href="/page2">Go to Page 2</a>
```
## リンク先ページ(Page2)
Page1同様に上部にinjectの記述をします。
リンクで遷移するとPage1のinputに入力した文字が表示されていると思います。
```c#:Page2.cs
@page "/page2"
@inject UserSessionService UserSession

<h3>Page 2</h3>

<p>@UserSession.UserData</p>
```

## 使いどころ
Blazorはシングルページアプリケーションなのであまりリンクを使って遷移することはないと思うのですが、アセット画面の左側のナビゲーションにユーザIDを入力して、そのまま他のページでも使い回せたらいいな　みたいなことがありましたのでこのような方法が出来るかを試してみました。

ここまで読んでいただきありがとうございました。