OmniAICreator/Qiita-1.07M huggingface dataset:
【Flutter】Firebaseを利用したApple Sign Inに失敗しまくった話

タイトルのとおりです。
FlutterでFirebaseを利用したAppleサインインをしようとしたところ、ずーっと`[firebase_auth/invalid-credential] Invalid OAuth response from apple.com`のエラーが発生していました。

なまじ認証には成功しているのでApple Developer側のミスなのか、Firebase側のミスなのか、Xcodeのミスなのかコードの間違いなのかが判別つかずものすごく苦労しました・・・。

基本的にはこちらの記事の通りにやれば問題なしです。
大変参考になりました。ありがとうございます。

https://qiita.com/ninoko1995/items/51f9dd75b32522476342

ライブラリバージョンの関係なのか（私の理解の問題も多分にありますが）どこかから仕入れたサンプルコードでは動かなかったので解決法を共有です。

### バージョン等

```
$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.22.2, on macOS 14.1.1 23B81 darwin-arm64, locale ja-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 15.4)
[✓] Android Studio (version 2024.1)
```

```
  firebase_auth: ^5.1.4
  sign_in_with_apple: ^6.1.1
```

### コード

```dart
Future<MyApiResponse> signInWithApple() async {
  final rawNonce = generateNonce();

  final appleCredential = await SignInWithApple.getAppleIDCredential(
    scopes: [
      AppleIDAuthorizationScopes.email,
      AppleIDAuthorizationScopes.fullName,
    ],
    nonce: sha256ofString(rawNonce), // ←追加
  );

  try {
    final credential = OAuthProvider('apple.com').credential(
      idToken: appleCredential.identityToken,
      rawNonce: rawNonce,
      accessToken: appleCredential.authorizationCode, // ←追加
    );
    UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(credential);

  } on FirebaseAuthException catch (e) {
    ... エラー処理
  }
}

String sha256ofString(String input) {
  final bytes = utf8.encode(input);
  final digest = sha256.convert(bytes);
  return digest.toString();
}
```

これでいけるはず。

参考：

https://stackoverflow.com/questions/79034405/unhandled-exception-firebase-auth-invalid-credential-invalid-oauth-response-f


## 2024.10.10追記
コメントで「もっと簡単になったよ！」と教えていただき参考サイトをもとにやってみました。
なんとこれだけで実装できました。良い世の中になったものだ。

```dart
Future<MyApiResponse> signInWithApple() async {
  try {
    final appleProvider = AppleAuthProvider();
    UserCredential userCredential = await FirebaseAuth.instance.signInWithProvider(appleProvider);

  } on FirebaseAuthException catch (e) {
    ... エラー処理
  }
}
```

※余談
同じやり方でGoogleサインインもやれるのでは！？と思ったのですが
動くは動くのですが（おそらく）いろいろと設定をしないといけないようだったので今回は見送りとしました。

参考：

https://medium.com/flutter-jp/sign-in-with-apple-d0d123cbbe17
7日間でハッキングを始める本 - 5日目 - 

## 本記事の目的
7日間でハッキングを始める本をやっていましたが、前日までの内容が整理しきれていないことを感じたため、本日（Day5）から内容を整理する。

基本的には、使うコマンド・ツール・Webサイトや新規の用語などを載せる予定。

## Day5

### ftp
- ファイル転送用のプロトコル
- anonymousオプションがあり、これが有効になっていると、ユーザ名：anonymous、パスワード：<ブランク>でFTPサーバーにログインができる

### nmap
- Port Scanに利用

### dirb
- Webサーバーのディレクトリ構成を確認する
- TryHackMeのルームではGobusterというツールを使って同様のタスクをしている

### Burp Suite
- http通信の監視ができる（クライアント側のブラウザとWebサーバーの仲介になる）
- http通信の一部を変数化してパスワードリスト攻撃とかもできる（Intruder）

### nc
- ncコマンド（netcat）は、ネットワーク接続を作成し、データを送受信するための多目的ネットワークユーティリティツール
- nc -lvnp <port> で指定したポートでの接続待ちができる

### GTFOBins
- システム内の誤った設定から特権昇格に利用できるテクニックを検索できるサイト

### linuxのディレクトリルール
| ディレクトリ | 意味 |
|:-|:-|
| /bin | 一般ユーザーでも実行可能なコマンドを置く |
| /sbin | ルートユーザーまたは特権を持つユーザー専用のコマンドを置く |
| /usr/bin  | ユーザーが一般的に使うコマンドで緊急時のシステム保守に必須でないものを置く |
| /usr/lib  | プログラムに必要な共有ライブラリを置く |

### 用語集
- リバースシェル：ターゲットマシン側から外側に接続する仕組み
- シェルをとる：ターゲットマシンの操作権限を得ること
- レピュテーションリスク：企業などの評判・信頼が損なわれることによって、経済的損失やブランド価値の低下を招くリスクのこと
- SUID：「Set User ID」のこと、誰が実行しても所有者権限で実行できる特殊な権限。実行権限が"s"になっている
元利均等方式の利息計算(2) - 分割払いの利息って合計いくら？

[元利均等方式の利息計算(1) - ローンの公式の導出](https://qiita.com/Hiraku/items/3c843c02a7a8ea5335b8) の続きです。

前回の記事で、ローン(分割払い)の月々の返済額を計算する公式を解説しました。もう一度載せておきましょう。

* $x$: 月々の返済金額
* $s$: 月利。実質年率15%なら12で割って1.25%
* $a$: 最初に借りた元金額
* $n$: 返済回数

$$
x = \frac{as}{1-(1+s)^{-n}}
$$

この公式を元に、式変形をしていくことで、派生公式を作ることができます。有用と思われるものをまとめていきます。

## n回払いの利息合計

分割払いの場合、利息の合計を公式でざっくり概算することができます。
冒頭のローンの公式は、 **n回払いでx円ずつ毎月支払っていくと、ぴったり利息+元金を払い終わる** ということです。つまりxにnを掛ければ支払い総額が出るわけですから、そこから元金を引けば、差分が利息の総額ということになりますね。

* $f$: 利息の合計

 $f = nx - a$ を展開して、

$$
f = nx - a = \frac{nas}{1-(1+s)^{-n}} - a
$$

※実際のロジックでは日割していたり、小数点以下の四捨五入/切り捨てなど細かい仕様があるため、完全に合致するわけではありません。

ちなみに、ローンの公式はExcelやSpreadsheetではPMT関数として組み込まれていましたが、この利息合計は [CUMIPMT](https://support.google.com/docs/answer/3093211?hl=ja) という関数で計算ができます。

```
=-CUMIPMT(月利, 分割回数, 元金, 1, 分割回数, 0)
```

## 利息合計は元金の何%になるのか (アドオン率換算)

利息の合計の公式を、両辺$a$で割ると、元金と利息合計の比率になります。

* $r$: アドオン率

$$
r = \frac{f}{a} = \frac{ns}{1-(1+s)^{-n}} - 1
$$

実質年率は利息が高いのか安いのかを比較しやすいのですが、具体的な利息総額がいくらになるのかはパッとわかりにくいです。
一方、 `元金に対してr%が利息である` と表示する方式を**アドオン方式**と呼びます。貸金業法や割販法では実質年率での表示を義務付けており、どの事業者も実質年率で利息を表示しています。

しかし、アドオン方式は利息をイメージしやすいメリットがあります。

たとえば、`1%の実質年率で35年の住宅ローンを組んだとき、利息がいくらになるのか？` と言われると、とても計算が難しそうですよね。この公式に当てはめると…

* n = 420 (35年 x 12ヶ月)
* s = 0.0008333... (1%/12)


$$
r = \frac{420 \times 0.0008333...}{1-(1+0.0008333...)^{-420}} - 1 = 0.1855999...
$$

ということで、`元金のおおよそ18.6%ぐらいが利息総額`になるとわかります。これならだいぶ利息についてイメージがつきやすいのではないでしょうか。

アドオン率 (事業者によっては割賦係数(かっぷけいすう)などと呼んでいることもあります)は、支払いの回数nと、実質年率だけで決まるため、事前に計算して表にしておくことで、利息の感覚がよくわかるようになります。

ExcelやSpreadsheetでは、CUMIPMT関数に現在価値=1として入力すると、アドオン率を計算できます。こんな感じでしょうか。結果は負の数で出てくるので、マイナスをつけて打ち消しておくとわかりやすいです。

```
=-CUMIPMT(月利, 分割回数, 1, 1, 分割回数, 0)
```


### アドオン率の計算例

せっかくなのでいくつかアドオン率の換算表を書いておきます。

#### 住宅ローンを35年(420回払い)で組む場合の実質年率からアドオン率の対応表

|実質年率|アドオン率(利息総額は元本の何%？)|
| -- | -- |
|	0.10%	|	1.76%	|
|	0.20%	|	3.55%	|
|	0.40%	|	7.18%	|
|	1.00%	|	18.56%	|
|	1.50%	|	28.60%	|

仮に5000万円を実質年率1.5%で借りたら、総額1429万円ぐらい利息を払わないといけないわけですね。

#### 一般的なクレジットカードでの分割払い回数からアドオン率の対応表

クレジットカードによって分割払いの実質年率は様々なので、ここでは13%, 15%, 18%の3パターンで計算してみました。

|分割回数|年率13%|年率15%|年率18%|
| -- | -- | -- | -- |
|	3	|	2.17%	|	2.51%	|	3.01%	|
|	5	|	3.27%	|	3.78%	|	4.54%	|
|	6	|	3.83%	|	4.42%	|	5.32%	|
|	10	|	6.05%	|	7.00%	|	8.43%	|
|	12	|	7.18%	|	8.31%	|	10.02%	|
|	18	|	10.61%	|	12.29%	|	14.85%	|
|	20	|	11.76%	|	13.64%	|	16.49%	|
|	24	|	14.10%	|	16.37%	|	19.82%	|
|	36	|	21.30%	|	24.80%	|	30.15%	|

クレカの分割払いはカード契約さえできていれば特に購入時は審査などなく気軽に利用できますが、その分、年率が高いですよね。

実質年率に関する初歩的な誤解として、「実質年率15%ということは、1年に渡って返すと元金の15%ぐらいの利息を取られるんじゃないか」というものがあります。実際は毎月返している分もっと安くなるので、22ヶ月ぐらいでおおよそアドオン率 = 実質年率になります。

金融業界に身をおいていれば、この辺のテーブルを暗記しておくと格好いいかもしれませんね。
個人的には15%10回払いはアドオン率7%で覚えやすいので、説明のサンプルとしてよく使います。
分析で利用するpandasのDataFrame(データの選択と抽出編)

前記事からの続きです。
前の記事はこちら

https://qiita.com/y_haruki/items/054b70fb5f30a3751aa6

利用するデータは説明のため以下のデータを利用します。
今回AMZNの値はすべて数字を入れています。
``` py:
import pandas as pd

st = pd.DataFrame({'GOOG':[158.56,157.21,167.31,168.42,167.19,165.29,168.83],
                   'AMZN':[186.61,181.96,184.76,185.13,186.33,187.97,188.07]
                   })
```

行と列の値の関係が見やすいように、df.head(7)の実行結果を表示させます。
``` :実行結果
     GOOG    AMZN
0  158.56  186.61
1  157.21  181.96
2  167.31  184.76
3  168.42  185.13
4  167.19  186.33
5  165.29  187.97
6  168.83  188.07

```



### データの選択と抽出
#### 1\. df['column_name']
指定した列のデータを取得します。

``` py:
print(df['AMZN'])
```

``` :実行結果
0    186.61
1    181.96
2    184.76
3    185.13
4    186.33
5    187.97
6    188.07
Name: AMZN, dtype: float64
```
AMAN列のデータが抽出されて表示されます。


#### 2\. df.loc[]
ラベル（行名、列名）でデータを選択・抽出します。
``` py:
# 特定の行と列のデータ
print(df.loc[0,'GOOG'])
```
``` :実行結果
158.56
```
0番行目、'GOOG'列の158.56が取得できました。

列の範囲をキーの値を利用して指定ができます。

``` py:
# 特定の行と列のデータ
print(df.loc[0,'GOOG':'AMZN'])
```
``` :実行結果
GOOG    158.56
AMZN    186.61
Name: 0, dtype: float64
```
0番行目のGOOGとAMZNの列の値が取得できました。

もちろん行数の範囲を指定できます。
``` py:
# 特定の行と列のデータ（行の範囲指定）
print(df.loc[0:2,'GOOG'])
```
``` :実行結果
0    158.56
1    157.21
2    167.31
Name: GOOG, dtype: float64
```

loc()はキーの値（カラム名）を指定して値を取得できます。
行についてもキーの値を指定することができます。
※今回行に関して、キーの値を設定がなかったため、Indexの
値を指定しています。



#### 3\. df.iloc[]
インデックス（数値）でデータを選択・抽出します。

``` py:
# 特定の行と列のデータ
print(df.iloc[0, 1])  # 1行目、2列目
```
``` :実行結果
186.61
``` 
0行番目の1番列目の186.61が取得できました。

``` py:
# 行の範囲を指定
print(df.iloc[1:4])
```
``` :実行結果
     GOOG    AMZN
1  157.21  181.96
2  167.31  184.76
3  168.42  185.13
``` 
1番行目から4番目業手前の3番行目までの範囲が取得できました。

::: note info
loc[]とiloc[]の違い
loc[] : キーの値を指定することができます。
loc[] :　インデックスの値の指定になります。（キーの値は使えません）
:::
[DNS] キャッシュDNSサーバ、権威DNSサーバ

# Image
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/3396bc81-a6af-f1f4-71ec-20604881d44c.png)

# 参考リンク
- [権威サーバー（権威DNSサーバー）](https://jprs.jp/glossary/index.php?ID=0145)
- [令和3春1_午後](https://www.ap-siken.com/kakomon/03_haru/pm01.html)
書籍の内容を独自の視点でまとめ直すには

# はじめに
書籍を読んだ後、まとめる際、どうしても書籍の構成に引っ張られ、うまくまとめられないことが多くありました。
改めて、アウトプットの仕方を整理し、実践してきているので、その手順を紹介してみます。

# 1. キーポイントの抽出（10-15分）
- 書籍の目次や各章の冒頭、まとめを素早く読む
- 重要そうな部分に付箋やマーカーを付ける
- 5-7個の主要なポイントをメモする

# 2. 構成の設計（5-10分）
- 抽出したキーポイントを使って、記事の大まかな構成を考える
- 導入、本論（2-3つの主要セクション）、結論の形式を意識する
- 各セクションに仮のタイトルをつける

### キーポイントから記事の構成を考える具体的な方法
**1. キーポイントの整理**
まず、抽出したキーポイントを一覧にする。
（例）
1. プロダクトオーナーの役割の重要性
2. ビジネス価値の最大化
3. プロダクトバックログの管理
4. ステークホルダーとの連携
5. スプリント計画と受け入れ
6. 継続的な品質管理

**2. 関連性の分析**
キーポイント間の関連性を考える。似たトピックや、論理的に繋がるものをグループ化する。
（例）
- グループA：役割と責任全般（1）
- グループB：具体的な業務（2, 3, 4, 5）
- グループC：継続的な取り組み（6）

**3. 順序の決定**
グループ化したポイントを、読者にとって理解しやすい順序に並べ替える。
一般的には、以下でまとめる。
1. 導入（全体像）
2. 主要な内容（詳細説明）
3. 補足情報や応用
4. まとめ

**4. 構成の骨格作り**
決定した順序に基づいて、記事の骨格を作る。
（例）
```
1. はじめに
   - プロダクトオーナーとは
   - なぜプロダクトオーナーが重要か

2. プロダクトオーナーの主要な責任
   2.1 ビジネス価値の最大化
   2.2 プロダクトバックログの管理
   2.3 ステークホルダーとの連携
   2.4 スプリント計画と受け入れ

3. 継続的な取り組み
   - 品質管理の重要性
   - 常に改善を続けるマインドセット

4. まとめ
   - プロダクトオーナーの役割の再確認
   - 成功するためのアドバイス
```

**5. 各セクションの充実**
各セクションに、以下の要素を含めることを考える。
- 説明：キーポイントの詳細
- 例：具体的な状況や事例
- ヒント：実践的なアドバイス
- 注意点：よくある課題や対処法

**6. 導入と結論の設計**
- 導入：記事の目的、対象読者、主要なポイントの予告
- 結論：主要ポイントの要約、読者への行動喚起

**実践例**
```
# プロダクトオーナーの役割と責任：成功するプロダクト開発の鍵

## はじめに
アジャイル開発、特にスクラムにおいて、プロダクトオーナーは成功の要となる重要な役割です。
本記事では、プロダクトオーナーの主要な責任と、その役割がプロダクト開発にもたらす価値について解説します！

### 本記事の内容
1. プロダクトオーナーの定義と重要性
2. 主要な責任領域
   - ビジネス価値の最大化
   - プロダクトバックログの管理
   - ステークホルダーとの連携
   - スプリント計画と受け入れ
3. 継続的な品質管理と改善の取り組み
4. 成功するプロダクトオーナーになるためのヒント
```

# 3. 内容の展開（20-30分）
- 各セクションについて、以下の質問に答える形で内容を膨らませる。
  - このポイントはなぜ重要か？
  - 実際にどう適用できるか？
  - 自分の経験や知識とどう結びつくか？
- 具体例や自分の意見を積極的に盛り込む

:::note warn
セクションに分かれている場合は、各セクションで、「キーポイントを抜き出し、自身の言葉で言い換えて、つなげる」のもあり。
ただし、構成は変えた上で、やらないといけない。
:::

# 4. 独自の視点の追加（10-15分）
- 各セクションに、以下のいずれかを追加する
  - 「実践のヒント」：読者が即実行できるアドバイス
  - 「注意点」：よくある落とし穴や誤解
  - 「事例」：架空でも実例でも良い、具体的な適用例

# 5. 導入と結論の作成（10分）
- 導入：記事の主題と重要性を簡潔に説明
- 結論：主要なポイントを要約し、読者への呼びかけを含める

# 6. 見直しと編集（10-15分）
- 文章全体を読み返し、流れが自然か確認
- 不要な部分を削除し、説明が足りない部分を補足
- 専門用語の説明や具体例の追加

# 7. タイトルとサブタイトルの調整（5分）
- 記事の内容を反映した魅力的なタイトルを考える
- 各セクションのサブタイトルを、内容を端的に表すものに調整
【自分用の単語メモ】レイテンシとスループット

## はじめに

レイテンシとスループットという2つの用語の理解が曖昧だったため、備忘録としてまとめます。

## レイテンシとスループット

レイテンシとスループットはどちらもWebサービスのパフォーマンスを測る上で最も基本的な指標です。

### レイテンシ

レイテンシは1つのリクエストを送信してからレスポンスを受信するまでの**時間**を指します。
<br>

- 単位はmsec(ミリ秒)で、1msecは1/1000秒を表す
- 低ければ低いほど良い
<br>

レイテンシが低いということは、1つのリクエストがシステムのリソースを占有する時間が短いことを意味します。
<br>

その結果、同じ時間内でより多くのリクエストを処理できるようになります。

#### レイテンシの改善方法の例

1. クエリの最適化
2. キャッシュの使用
3. ネットワーク遅延の軽減

### スループット

スループットは、システムが一定時間で処理できるリクエストの**数**を表します。
<br>

- 単位はrps(requests per second)
- 高ければ高いほど良い

<br>

スループットが高いということは、システムが同時並行でより多くのリクエストを処理できることを意味します。

#### スループットの改善方法の例

1. 水平スケーリング
2. 非同期処理の導入
3. バッチ処理の改善
4. リソースのボトルネック（CPU, メモリ, I/O）の解消

## まとめ

- レイテンシ: リクエスト送信〜レスポンス受信までの時間
- スループット: 一定時間に同時並行で処理できるリクエストの数

パフォーマンス改善の勉強をコツコツ進めていきます。

### 参考資料

https://www.amazon.co.jp/dp/4297128462
ABC374回答メモ

# 0.はじめに
　急に涼しくなり過ごしやすくなってきた今日この頃のABC。
　Ａ～Ｃが順調にとけたので、行けるかと思いきやＤはちょっと解けそう
　にないので飛ばして、Ｅに取り掛かるも解決に至らず
　結局３問ＡＣで終わり。
　解説を見てなんとかＤＥも解けましたが、コンテスト内に特には
　まだまだ地力がたりなさそうでした。
　レートは微減で-3の693。700の壁が高いです。


# 1. A - Takahashi san 2
　ちょっとめんどい問題。
　文字列の後ろから3文字がnasになっていればOKということなので
　Sの添え字を-1，-2，-3をつけたもので比較。
　スライスして～とかも今考えると楽だった気もしますが
　2分弱でのACでした。

　https://atcoder.jp/contests/abc374/submissions/58430137


# 2.B - Unvarnished Report
　記事を書くまで記憶に残ってなかったですが、ちょっとめんどい問題。
　SとTの長さに応じて場合分けして実装
　Tが長い場合
　　Sの長さ分比較しその中で差異があればその位置を出力して終了
　　その中に差異が無ければ、Sの長さ+1を出力して終了
　Sが長い場合
　　Tの長さ分比較しその中で差異があればその位置を出力して終了
　　その中に差異が無ければ、Tの長さ+1を出力して終了
　TとSの長さが同じ場合
　　Tの長さ分比較しその中で差異があればその位置を出力して終了
　　その中に差異が無ければ、0を出力して終了

　直感的に解けて、コーディングで間違いが少ないと思える方法を選択しました。

　https://atcoder.jp/contests/abc374/submissions/58444587


# 3.C - Separated Lunch
　問題を読んでbit全探索で行けそう。と分かりました。
　N組をビット全探索で0組と1組にわけて
　分け方毎のメンバー合計の大きい方をその他の組の小さい方と比べ
　最終的に小さくなる組合わせの分け方毎のメンバー合計の大きい方を
　出力して終了しました。日本語で書くと分かりにくいですね・・・。
　説明がへたなだけな気もしますが。

　https://atcoder.jp/contests/abc374/submissions/58453226


# 4.D - Laser Marking
　コンテスト中は以下の理由が頭に浮かんでスルーしてEに進みました。
　　1)答え小数点になるとかめんどくさそう
　　2)2点間の距離を求めるとかぱっと出てこない。
　　3)Nの最大が６なら組み合わせ全列挙ではあるがTLEをだしそう。
　　4)座標問題なので苦手
　判断が正しかったのかはわかりませんが、コンテスト後に
　考えると、苦手意識を持たずに取り掛かっても良かったかなと思いました。

　コンテスト後解説を見たところ、線分を描く始点と終点を全組み合わせ
　見る必要とあり、コンテスト中にそこに思い至る自信はありませんでした・・・。

　https://atcoder.jp/contests/abc374/submissions/58505870


# 5.E - Sensor Optimization Dilemma 2
　コンテスト中に1時間以上かけて取り組みましたが、WA12個が消えませんでした。
　コンテスト中も製造力の決め打ち2分探索で行けるとふんで取り掛かりましたが
　工程ごとの最適機械数を求めるのに失敗しました。
　
　コンテスト中は、目標製造力を目いっぱい機械SかTの効率のいいほうで
　作り、余りをSとTのコストが少なくなる方で作ると考えましたが失敗。
　コンテスト後に解説を読むと、SとTが相互入れ替えが可能な分＝A×Bの
　倍数分は効率がいい方でうめ、残った分をSとTの比率を調整して
　細かく見る必要があることが分かりました。

　ここらへんは、覚えておけば、後で応用が利く気がします。

　https://atcoder.jp/contests/abc374/submissions/58501935


以上
UbuntuOSに変更後の詳細設定（都度追記）

[ターミナルのメッセージや出力を恒久的に英語に直す](#ターミナルのメッセージや出力を恒久的に英語に直す)
[Gitのデフォルトエディタをvimに変更](#gitのデフォルトエディタをvimに変更)
[トップバーにインジケーター表示](#トップバーにインジケーター表示)
[辞書のインポート](#辞書のインポート)
[デスクトップの詳細設定を日本語に](#デスクトップの詳細設定を日本語に)
[Dockを自動的に隠すをオフ](#dockを自動的に隠すをオフ)
[Vimのクリップボード使用許可](#vimのクリップボード使用許可)
[GitHubリポジトリをcloneするためのSSHキー作成](#githubリポジトリをcloneするためのsshキー作成)
[キーリングにパスワードを設定しない](#キーリングにパスワードを設定しない)




## ターミナルのメッセージや出力を恒久的に英語に直す

```bash:bash
# `~/.bashrc`を編集
vim ~/.bashrc

# ファイルの末尾に記述
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
export LC_ALL=en_US.UTF-8

# 設定を反映
source ~/.bashrc
```
<br>

## Gitのデフォルトエディタをvimに変更
https://qiita.com/yusuke62/items/bb32b5a5e94d6f7ef29a#git%E3%81%AE%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%82%A8%E3%83%87%E3%82%A3%E3%82%BF%E3%82%92vim%E3%81%AB%E5%A4%89%E6%9B%B4


## トップバーにインジケーター表示
簡単に辞書ツールや設定にアクセスするため
```bash
ibus restart
```


## 辞書のインポート
手順１：Windowsの辞書を`.txt`形式でエクスポート
手順２：Ubuntuの「Mozc辞書ツール」でインポートを行う
形式は.txtで新しいグループを作る。


## デスクトップの詳細設定を日本語に
設定　→　地域と言語　→　言語(L)を日本語　→　再起動選択


## Dockを自動的に隠すをオフ
設定　→　Dockを自動的に隠すを　→　オフ





## Vimのクリップボード使用許可

https://qiita.com/yusuke62/items/b2b20a6f17b6f713e1f8



## GitHubリポジトリをcloneするためのSSHキー作成

GitHubのリモートリポジトリを新しいローカル開発環境にfetchする必要があります。
その際SSH公開鍵を新規で作る必要があります。

https://qiita.com/yusuke62/items/cda76c42fba3a112add1


## キーリングにパスワードを設定しない
1. アプリケーションメニューから「パスワードと鍵 (Passwords and Keys)」を開きます。
1. 左側の「ログイン」キーリングを右クリックし、パスワードの変更を選択します。
1. 現在のパスワードを入力します。
1. 新しいパスワードとして何も入力せず、空欄のまま保存をクリックします。
システムテストについて理解を深める

# はじめに

エンジニアのみなさま、日々の学習本当にお疲れ様です！
また本記事まで足を運んでいただき本当に感謝です。
最後まで読んでもらえると幸いです。

---


# システムテストとは

#### ソフトウェア開発の最終段階に行われるテスト


システム全体が要件を満たし、正しく機能するかを確認するプロセスです。各モジュールを統合して実際の運用環境に近い状態でテストを行うため、単体テストや結合テストで検証できなかった問題も発見しやすいのが特徴です。特に、非機能要件（可用性・パフォーマンス・セキュリティなど）の観点で検証することが重要です。

**『非機能要件』** の詳細についてまとめた記事も投稿してます。
もし良かったら読んでみてください。

https://qiita.com/ho_na/items/a84f9a0db793cb0411db

システムテストの工程後に **『受け入れテスト』** があります。違いとしてはシステムテストが **『開発者』の観点** でテストをするのに対し、受け入れテストは **『発注元であるクライアント』の観点** でテストをします。

# テストを疎かにするとどのような影響があるか？

#### 開発者・発注元であるクライアント共に不幸になる

そもそもシステムテストの工程では、リリースがかなり近づいてます。そのため、万が一問題が発生した場合、開発者側としては **調査 → 原因特定 → 修正対応 → 動作確認 → 修正に伴う関連機能のリグレッションテスト → システムテスト用の開発環境へのデプロイ → 再テスト** を短期間で行う可能性が高くなります。その結果、対応に追われて高稼動が続きます。

一方で発注元であるクライアント側としてはリリースに向けた準備を行います。テストの時に発生した問題の大きさにもよりますが、最悪の場合リリースを延期しなければいけない事にも繋がります。

双方で不幸にならないため、テストのスコープ、目標、テスト項目、環境、スケジュール、リソースを早い段階で明確にすることが肝要です。特にシナリオテストの期待値（何を持ってクリアとするか？）は綿密に協議・合意をしましょう。検討時期としては、要件定義や設計段階からテスト観点を盛り込み、システムの複雑さに応じてテスト計画を練ることが重要です。


# システムテストの検証方法

#### リリース前に潜在的な問題を発見することが可能

![スクリーンショット 2024-10-06 15.41.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3744730/5bc020dc-291c-9d36-456b-142a19abecee.png)

理解を深めるためにさまざまな記事を読みましたが、記事によって検証する項目が異なります。個人的には上記内容でカバーできている認識ですが、上記の項目以外で『実務でこれチェックしてるよ』があれば教えて欲しいですm(_ _)m

# テストツールのご紹介

| ツール名       | 用途                           | 主な特徴 |
| -------------- | ------------------------------ | -------- |
| **Selenium**   | Webアプリケーションの自動化テスト | ブラウザ操作の自動化、リグレッションテスト |
| **JMeter**     | 負荷テスト、パフォーマンステスト | WebアプリケーションやAPIの負荷テスト |
| **Postman**    | APIのテスト                    | REST APIの機能・パフォーマンステスト、自動化 |
| **Burp Suite** | セキュリティテスト             | 脆弱性診断、XSSやSQLインジェクション対応 |


正直に話すと、ツールの良し悪しが判断できるほどの場数を踏んでないです。こちらについても上記の項目以外で『このケースではこのツール使ってるよ』があればぜひ教えて欲しいです...！

# 参考記事（勉強になりました。ありがとうございます）

https://service.shiftinc.jp/column/4740/

https://products.sint.co.jp/obpm/blog/system_test

https://plus.cmknet.co.jp/systemtest/




# おまけ

弊社のご紹介もさせてください！

### 「日本で一番エンジニアが成長できる会社を創る」

https://prum.jp/

### エンジニアリングの募集

https://www.wantedly.com/projects/1808638

### PM・Webディレクションの募集

https://www.wantedly.com/projects/1355235

### セールス・事業開発の募集

https://www.wantedly.com/projects/1792065

### コーポレート系の募集

https://www.wantedly.com/projects/1752874

### コンサルティングの募集

https://www.wantedly.com/projects/1794481

弊社メンバーは日々学習した内容をアウトプットしております！
少しでもご興味を持たれた方は求人を見てみてください！
ご応募もお待ちしております！

### 最後までご覧いただき、ありがとうございました！
【PHP】array_filterの使い方

## array_filterとは

```php
array_filter(array $array, ?callable $callback = null, int $mode = 0): array
```

> (PHP 4 >= 4.0.6, PHP 5, PHP 7, PHP 8)
> array_filter — コールバック関数を使用して、配列の要素をフィルタリングする

https://www.php.net/manual/ja/function.array-filter.php

配列を破壊することなくフィルタリングしてくれる関数です。
【DOP-02】AWS Certified DevOps Engineer - Professional 試験問題集の勉強法・試験対策

# 勉強法について

受験体験記や受験の仕方などは他の方々も語られているため、
今回は「資格取得のために具体的にこれだけすればOK」ということを解説します。

最短での試験合格を目標とすると、やることは以下の5点だけです。

**1. 模擬試験を用意する**
【シンプル要点解説】AWS DevOps Engineer professional 試験問題集 (6回分480問)

https://www.udemy.com/course/aws-devops-engineer-professional-6480/?couponCode=DOP_01

:::note info
こちらのページ（https://qiita.com/t-h345/items/c448b44a73450eb738ba
）にてクーポンコードを配布しています。
割引価格で購入できるので是非ご活用ください！
:::

DOP教材は多々ありますが、本教材をお勧めする理由は以下です。
- 安い。クーポン価格だと1500円前後で購入できます。
- どのUdemy講座よりも多い480問の問題が収録されている。
- 最新のAWS DevOps試験問題に対応していて試験範囲を網羅している。また、要点を抑えた解説でスムーズに理解できる。

**2. 初見でまず問題を解いて全体像を掴む**
最初は分からなくて当たり前です。頻出用語に慣れることが大事です。(英語を勉強するのに、まずは単語を覚えるのと一緒です)

**3. 解説を確認して理解する**
ここが資格勉強の肝となる部分です。
よくわからなかった部分は解説・Web・ChatGPTなどを駆使して頭に入れていきましょう！
この資格に限らずですが、資格取得はパターンプラクティスです。
ハンズオンで手を動かして理解したくなったりしますが、最短で合格するためには「資格取得すること」だけに時間を使うことに集中しましょう。

**4. 反復で解き直す**
脳に定着させるためです。

**5. 9割以上安定して取れるようになったら試験に望む**
模擬試験で安定して9割取れるようになれば、本番対策は概ねOKと言えるでしょう。

# さいごに
SESさんやSierさんなど、モダンなDevOpsやCI/CD案件に入りたい方にとって、本資格は大きな武器になります。
取っておいて損はない資格なので、ぜひ資格取得してみてください！
[SwiftUI] iOSバージョンごとにSF Symbolsを変更する方法


# はじめに

iOS 18から新しいSF Symbolsが登場しましたが、アップデートしていない端末ではアイコンが何も表示されない問題に直面しました。ここでは、iOSバージョンごとに異なるSF Symbolsを表示する方法を紹介します。実装自体かなり簡単なので、役に立てていただければと思います。

# 実装

```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        // iOSのバージョンによって使用するSF Symbolsを変更
        if #available(iOS 18, *) {
            // iOS 18以上の場合
            Image(systemName: "numbers")
                .font(.largeTitle)
        } else {
            // iOS 18未満の場合
            Image(systemName: "arrow.2.circlepath")
                .font(.largeTitle)
        }
    }
}
#Preview {
    ContentView()
}
```

・`if #available(iOS 18, *) { ... } else { ... }:` 
この条件分岐は、現在のデバイスがiOS 18以上かどうかを確認します。iOS 18以上の場合は、新しいSF Symbols「numbers」を使用し、そうでない場合は古いシンボル「arrow.2.circlepath」を表示します。

## シミュレーターで確認

シミュレーターで異なるiOSバージョン、`iOS 18`と`iOS 17.4`でのアイコンの表示を比較します。

<div style="display: flex; justify-content: center;">
    <div style="margin-right: 20px; text-align: center;">
        <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3892118/43fb84cc-5866-439f-5679-bc4dbcc88f68.png" width="350">
        <p>iOS 18</p>
    </div>
    <div style="text-align: center;">
        <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3892118/22edc0de-b011-04da-a392-9b55d4f06515.png" width="350">
        <p>iOS 17.4</p>
    </div>
</div>

## まとめ

この実装により、iOS 18未満の端末でも別のアイコンを表示することができます。
rustで255 as i8をすると？

ちまちまと[100 Exercises To Learn Rust](https://rust-exercises.com/100-exercises/)に取り組んでいて、よくわからないところがあったので、メモ。

## 255 as i8すると？
エクササイズの中で、
``` rust
#[allow(overflowing_literals)]
let x = { 255 as i8 };
```
xには何が入るのかといった問題があり、これがよくわからなかった。

### #[allow(overflowing_literals)]について

``` rust
#[allow(overflowing_literals)]
```
は、オーバーフローする際の警告を無視するもの。
もし、上記を書かないと
```
error: literal out of range for `i8`
 --> src/main.rs:2:15
  |
2 |     let x = { 255 as i8 };
  |               ^^^
  |
  = note: the literal `255` does not fit into the type `i8` whose range is `-128..=127`
  = help: consider using the type `u8` instead
  = note: `#[deny(overflowing_literals)]` on by default
```
のようなエラーが発生する。

### xには-1が入る

xには-1が入るらしい。
i8の範囲は`-128～127`なので、型変換しようとしている`255`は範囲外。
なので、異なる数字になるのは理解できるけれど、なぜ-1なんだろう。


わからなかったので、chat-gptに質問してみると、

> このコードを実行すると、xの値は-1になります。これは、i8の最大値を超えた場合にラップアラウンドが発生するためです。

とのこと。
ラップアラウンドとは、範囲を超えたときに、最小値から始まる現象。
（最小値より下回ったときは最大値から。最大値より上回ったときは最小値から。）
255 - 127 = 128だから、0ではないの？と次は思った。

どうやら、255を2進数表すと、`11111111`となり、i8として解釈されると、符号ビットが1になるため、負の数として扱われる。
なので、-1になるっぽい。

## 終わり

2進数とかあまり理解できていないと思ったので、何時かの機会に理解を深めていきたいですね。
MybatisのSQLで不等号を記載する方法

Mybatisを用いた開発の場合、基本的にMapperXMLにSQLを記載することになる。
しかし、XMLファイルでは、不等号を表すのに利用する``<``や``>``は特別な意味を持ち、タグの開始や終了として解釈されてしまう。


## 改善策１.使用箇所をCDATAセクションで囲む
CDATAとは、「Character Data（文字データ）」の略で、CDATAセクション内の内容は通常のXMLパースルールを無視して、そのまま文字列として扱われる。

例：価格が300円未満の商品を抽出する
```xml:
<select id="selectGoods" resultType="goodsResultmap">
    SELECT
        *
    FROM
        goods
    WHERE
        price <![CDATA[ < ]]> 300;
</select>
```
## 改善策２.SQL全体をCDATAセクションで囲む
```xml:
<select id="selectGoods" resultType="goodsResultmap">
<![CDATA[
    SELECT
        *
    FROM
        goods
    WHERE
        price < 300;
]]>
</select>
```

## 改善策３：エンティティ参照を使用する
| 文字| エンティティ参照 |
|:-:|:-:|
| < | ``&lt;``|
| > | ``&gt;``|
| & | ``&amp;``|
| '(シングルクォーテーション) | ``&apos;``|
| "(ダブルクォーテーション) | ``&quot;``|

```xml:
<select id="selectGoods" resultType="goodsResultmap">
    SELECT
        *
    FROM
        goods
    WHERE
        price &lt; 300;
</select>
```
blastengineのC# SDKを使ってメール送信を行う

blastengine（ブラストエンジン）はシンプルに使える開発者向けメールサービスを提供しています。何かと面倒なメール配信をシンプルに、かつ確実に送信先に届くようになります。

現在、C#向けに、blastengine SDKを開発しています。.NET Standard 2.0をターゲットにしているので、macOSを含め幅広い環境で実行できるはずです。

今回は、即時配信メール（トランザクションメール）の送信方法を解説します。

## ユーザ登録する

blastengineにユーザ登録します。管理画面に入るためのユーザID、パスワードが手に入るので、ログインします（ユーザIDは後で使います）。


## 送信元ドメインのSPFを設定する

送信元として利用するドメイン（自分で持っているもの）の設定をします。これは任意のドメイン管理サービスで設定できますが、TXTレコードに以下のSPFを追加します。

```
txt @ v=spf1 include:spf.besender.jp ~all
```

## APIキーを取得する

ログイン後、管理画面の右上にある設定メニューに移動します。

![getting-started-6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/47b2b2ac-2e41-77fe-d84f-0ae0b7541f36.jpeg)

そして設定の中で、APIキーを取得します。

![getting-started-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/2b5ca124-3020-1d39-84e4-911cd4db27e2.png)

## 必要な情報について

SDKを使う上で必要なのは、先ほどのAPIキーとユーザIDになります。

## SDKのインストール

SDKはNuGetでリリースしています。Visual StudioのNuGetパッケージの管理よりインストールしてください。

[NuGet Gallery \| Blastengine 0\.1\.0](https://www.nuget.org/packages/Blastengine/)

依存ライブラリは以下の通りです。

- Newtonsoft.Json

## 初期化

先ほどのAPIキーとユーザIDを使って初期化します。

```csharp
new Blastengine.Client(DotNetEnv.Env.GetString("API_USER"), DotNetEnv.Env.GetString("API_KEY"));
```

## トランザクションオブジェクトの作成

メールを即時配信する際にはトランザクションオブジェクトを使います。

```csharp
var transaction = new Transaction();
```

## 必要な情報をセットする

続けて、トランザクションオブジェクトに必要なオブジェクトをセットします。

```csharp
transaction.To = "user@example.jp";
transaction.Subject = "テストメール";
transaction.TextPart = "本文";
transaction.From = new Blastengine.From("admin@example.com", "Admin"); // 2つ目の引数はオプション

// 以下は任意
transaction.HtmlPart = "<h1>これはテストメールです to __name__</h1>";
transaction.Cc.Add("cc@example.jp");
transaction.Bcc.Add("bcc@example.jp");
// 置き換え文字列の設定方法
transaction.InsertCode("name", "Test");
transaction.InsertCode("code", "001");
// List-Unsubscribeの設定
transaction.ListUnsubscribe = new Blastengine.ListUnsubscribe(Url: "https://example.com", Email: "unsub__code__@example.com");
```

後は `Send` メソッドで送信できます。

```csharp
try {
	if (await transaction.Send())
	{
		// 送信成功
	}
} catch (error) {
	// 送信失敗
}
```

送信成功した場合は `transaction.DeliveryId` に送信IDが入ります。失敗した場合には、例外処理になります。

```csharp
Console.WriteLine(error.message); // エラーメッセージ
```

## コードについて

コードはGitHubにアップしてあります。ライセンスはMIT Licenseになります。

[blastengineMania/blastengine-csharp: blastengineのC# SDKです](https://github.com/blastengineMania/blastengine-csharp)

## まとめ

blastengineには他にも一括メール配信を行ったり、添付ファイル付きのメール配信機能などもあります。これらの機能も随時実装していきますので、ぜひ皆さんのシステム開発に役立ててください。

[エンジニア向けメール配信システム「ブラストエンジン」](https://blastengine.jp/)
基本情報技術者試験に合格できなかった話。

# 概要

基本情報技術者試験、合格出来ませんでした...。
原因はB問題です。完全に舐めていたので、ここに記録を残します...。

# 受験したきっかけ
私はファーストキャリアとして、SEの道を選びました。

しかし、私は特にプログラミングなどしたことないし、なんならパソコンど素人の部類、俗にいう「文系でSEになった奴」です。

研修中では、ありがたいことに沢山の技術に触れる機会がありましたが、常に思っていたのは、

「やること多すぎるだろっ」でした。

そこで、一旦散りばめられた知識を整理するために、SEの登竜門ともいわれている基本情報技術者試験の受験を決めました。

# 学習法

参考書はキタミ式イラストIT塾のものを使用しました。本自体は分厚いものの、イラストが豊富だったり、キャラクター達が分かりやすく(そして、可愛く)説明してくれたりするので、とても読みやすかったです。

https://www.amazon.co.jp/%E3%82%AD%E3%82%BF%E3%83%9F%E5%BC%8F%E3%82%A4%E3%83%A9%E3%82%B9%E3%83%88IT%E5%A1%BE-%E5%9F%BA%E6%9C%AC%E6%83%85%E5%A0%B1%E6%8A%80%E8%A1%93%E8%80%85-%E4%BB%A4%E5%92%8C06%E5%B9%B4-%E6%83%85%E5%A0%B1%E5%87%A6%E7%90%86%E6%8A%80%E8%A1%93%E8%80%85%E8%A9%A6%E9%A8%93-%E3%81%8D%E3%81%9F%E3%81%BF%E3%82%8A%E3%82%85%E3%81%86%E3%81%98/dp/4297138077/ref=asc_df_4297138077/?tag=jpgo-22&linkCode=df0&hvadid=707442440799&hvpos=&hvnetw=g&hvrand=1540427689552732000&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=9198216&hvtargid=pla-2247804171118&psc=1&mcid=a32f62274e343784980ba6e36a9cf404&th=1&psc=1&gad_source=1

参考書を何周かしたあと、問題集としては、巷で話題の、
**過去問道場**を解きまくりました。

https://www.fe-siken.com/fekakomon.php

これで、A問題の対策は終わり。

B問題の対策はというと、

全くしていなかったです...。(ここが問題。)


# 本番

試験はCBT受験でした。

問題Aはある程度解けた自信があったのですが、問題Bはボロボロ...。
あ、これ落ちたなーって即座に思いました。舐めてた...。

# 結果

最終的な結果は翌月の中旬になるのですが、得点はすぐに知ることが出来ました。

科目A **605点**/1000
科目B **430点**/1000

想像通り、科目Bはボロ負け、そして自信があった科目Aも結構ギリギリでした（笑）

# 感想

今回の教訓は、 **試験を軽く見てはいけない** ということに尽きます(-_-;)
次回は、科目Bもしっかり勉強して挑みたいと思います...!
JestとPHPUnitの比較

## はじめに
筆者はフリーランスエンジニアになってしばらく、PHPの案件をやっていたのですが
直近の案件ではTypescriptに触れる機会がありました。
Typescript(npm)の世界ではJestがデファクトスタンダードかと思われますが
例に漏れず、その現場でも利用されています。

今まではPHPUnitでテストすることが多かったですので、少々の違いに戸惑うこともあり
各ライフサイクルメソッドの比較をしてみようかなと思いました。

## JestとPHPUnitの比較

|ライフサイクル| PHPUnit | Jest |
|:--------|:--------|:-----|
|テスト全体で開始時に1度実行|setUpBeforeClass()|beforeAll()|
|テスト全体で終了時に1度実行|tearDownAfterClass()|afterAll()|
|各テスト開始時に実行|setUp()|beforeEach()|
|各テスト終了時に実行|tearDown()|afterEach()|

名前から大体予測できそうな感じですね。

その他の特徴についても比較してみます。

| 特徴 | PHPUnit | Jest |
|:-----|:-------|:------|
|テスト開始時のDBマイグレーション|RefreshDatabase等のTraitで可能|自前でロジックを書く必要がある|
|DBアサーション|assertDatabaseHas等のアサーションが可能|なし(カスタムアサーションを作れば実現可能|
|JSON(オブジェクト)アサーション|assertJSONStructure等のアサーションがある|expect(Object).toMatchObject(diffrenceObject)で可能|
|クラス、オブジェクトのmock|Mockeryで実装が必要|jest.fn()でモック可能|
|ダミーデータ作成|LaravelであればFactory::faker()またはfake()ヘルパーで作成可能|faker-jsを導入すれば可能|
|テスト時の環境変数設定|Laravelであれば.env.testingを用意すれば半自動的に読み込む(PHPUnit.xmlの設定も必要)|jest.config.jsを用意し、setupFilesで読み込むファイルを指定。ここで環境変数を設定することができる|

ざっと並べてみました。
個人的な感触ですが、JestはDBマイグレーション、DBアサーションは少し弱そうだなという印象を受けました。
まぁそれもカスタムアサーションなどで回避できることなので、大きな差では無い様に思えます。

Jestはまだ触り始めたばかりなので、上記の内容に間違いがあるかもしれませんが
その場合はコメントなどでアドバイス頂けると幸いです。
ブラウザのコンソールからウェブストレージの値を変更するサンプルコード


## 概要


ブラウザのコンソールからウェブストレージの値を変更する用のサンプルコードのメモです。


## セッションストレージ

- 新規追加

	```javascript
	const data = {sample: "hoge"}
	sessionStorage.setItem('sample_key', JSON.stringify(data))
	```

- 変更

	```javascript
	const data = JSON.parse(sessionStorage.getItem("sample_key"))
	data.sample = "foo"
	sessionStorage.setItem("sample_key", JSON.stringify(data))
	```


## ローカルストレージ

- 新規追加

	```javascript
	const data = {sample_key: "hoge"}
	localStorage.setItem('sample_key', JSON.stringify(data))
	```

- 変更

	```javascript
	const data = JSON.parse(localStorage.getItem('sample_key'))
	data.sample = "foo"
	localStorage.setItem('sample_key', JSON.stringify(data))
	```
Cloud Composer 2 で CLI から DAG を操作する

# dag trigger

```
gcloud composer environments run \
${COMPOSER_ENV} \
--location asia-northeast1 \
dags trigger -- -e '2025-02-28' 'dag_id'

```

- $COMPOSER_ENV : composer の環境名
- task_id はいらない

# task clear


```
gcloud composer environments run \
${COMPOSER_ENV} \
--location asia-northeast1 \
tasks clear -- -t 'クリアしたいtask名' -s '2024-10-02' -e '2024-10-03' -d 'dag_id.task_id'
```

- $COMPOSER_ENV : composer の環境名
- ポイントとしては、task の latest を指定するオプションがないので、start_date と end_date を使って latest なタスクを指定する

# 参考

https://cloud.google.com/composer/docs/composer-2/access-airflow-cli?hl=ja

https://airflow.apache.org/docs/apache-airflow/stable/cli-and-env-variables-ref.html
Oracle Database: Data Pumpを使ったエクスポート/インポートの手順

## はじめに

Oracle DatabaseのData Pumpは、データベース間でデータを移動させるための強力なツールです。この記事では、エクスポートとインポートの基本的な手順と、よくあるエラーの解決方法を説明します。

## 環境

- Oracle Database 18c Express Edition
- OS: Windows 11

## 1. エクスポート手順

### 1.1 ディレクトリオブジェクトの確認

まず、データの出力先となるディレクトリオブジェクトを確認します。

```sql
CONNECT / AS SYSDBA
SELECT * FROM DBA_DIRECTORIES WHERE DIRECTORY_NAME = 'DATA_PUMP_DIR';
```

このコマンドで結果が返ってこない場合は、1.2の後に1.3を実行してください。

### 1.2 ユーザーへの権限付与

エクスポートを実行するユーザーに必要な権限を与えます。

```sql
GRANT READ, WRITE ON DIRECTORY DATA_PUMP_DIR TO EXPORT_USER;
```

### 1.3 ディレクトリオブジェクトの作成（必要な場合）

ディレクトリオブジェクトが存在しない場合は、以下のコマンドで作成します。

```sql
CREATE OR REPLACE DIRECTORY DATA_PUMP_DIR AS 'C:\app\YourUserName\admin\XE\dpdump';
```

※ パスは実際のOracleインストールディレクトリに合わせて変更してください。

### 1.4 エクスポートの実行

以下のコマンドでエクスポートを実行します。

```
expdp EXPORT_USER/password@//localhost:1521/XEPDB1 TABLES=employees DIRECTORY=DATA_PUMP_DIR DUMPFILE=employees_export.dmp LOGFILE=employees_export.log
```

## 2. インポート手順

### 2.1 インポート先テーブルの準備

インポート先のテーブルを作成します。この方法では、元のテーブル構造だけをコピーし、データは含めません。

```sql
CREATE TABLE employees_copy AS SELECT * FROM employees WHERE 1=0;
```

### 2.2 インポートの実行

以下のコマンドでインポートを実行します。

```
impdp IMPORT_USER/password@//localhost:1521/XEPDB1 TABLES=employees REMAP_TABLE=employees:employees_copy DIRECTORY=DATA_PUMP_DIR DUMPFILE=employees_export.dmp LOGFILE=employees_import.log
```

## 3. よくあるエラーと解決方法

### 3.1 エクスポート時のエラー

**エラーメッセージ:**
```
ORA-39002: 操作が無効です
ORA-39070: ログ・ファイルをオープンできません。
ORA-39087: ディレクトリ名DATA_PUMP_DIRは無効です
```

**解決方法:**
1. 1.3のステップでディレクトリオブジェクトを作成してください。
2. 作成後、1.2のステップで権限を付与してください。
3. Windowsのエクスプローラーで、指定したパスにフォルダが実際に存在することを確認してください。

### 3.2 インポート時のエラー

**エラーメッセージ:**
```
ORA-39151: 表"IMPORT_USER"."EMPLOYEES_COPY"が存在します。スキップのtable_exists_actionのため、すべての依存メタデータおよびデータはスキップされます
```

**解決方法:**
インポートコマンドに`TABLE_EXISTS_ACTION=REPLACE`オプションを追加します。

```
impdp IMPORT_USER/password@//localhost:1521/XEPDB1 TABLES=employees REMAP_TABLE=employees:employees_copy DIRECTORY=DATA_PUMP_DIR DUMPFILE=employees_export.dmp LOGFILE=employees_import.log TABLE_EXISTS_ACTION=REPLACE
```

## まとめ

テーブルのエクスポートとインポートの勉強の結果をまとめてみました。色々と調べてみたけど、このやり方が分かりやすかったです。
Python3: GATT で String データを送受信

通信相手のアドレスと Characteristic UUID　を与えて、String を送受信する方法です。

## プログラム

```py:send_get_data.py
#! /usr/bin/python
#	send_get_data.py
#
#					Oct/02/2024
# ------------------------------------------------------------------
import asyncio
from bleak import BleakClient

DEVICE_ADDRESS = "2C:BC:BB:65:E8:5A"  # デバイスのMACアドレスを入力
CHARACTERISTIC_UUID_READ = "7DEF8317-7301-4EE6-8849-46FACE74CA2A"  # 通知を受信するキャラクタリスティックのUUID
CHARACTERISTIC_UUID_WRITE = "7DEF8317-7302-4EE6-8849-46FACE74CA2A"  # 書き込みを行うキャラクタリスティックのUUID

# ------------------------------------------------------------------
# 通知を処理するコールバック関数
def notification_handler(sender, data):
	print(f"{data.decode()}")
#	print(f"Notification from {sender}: {data.decode()}")

# ------------------------------------------------------------------
# 通知を受信する関数
async def receive_notifications(client, char_uuid):
	await client.start_notify(char_uuid, notification_handler)
	print(f"Started notifications on {char_uuid}")

	# 通知を受け取り続ける（別のタスクで中断されるまで）
	while True:
		await asyncio.sleep(1)

# ------------------------------------------------------------------
# データを書き込む関数
async def write_data(client, char_uuid):
#	commands = ["MR\r","SV\r","SU\r","ST\r","SC\r"]
	commands = ["MB\r","SV\r","SU\r","ST\r","SC\r"]
	for i in range(5):  # 5回データを書き込む
		data = bytearray(commands[i].encode('utf-8'))  # 書き込むデータ
		await client.write_gatt_char(char_uuid, data)
		print(f"Written data to {char_uuid}: {data}")
		await asyncio.sleep(2)  # 2秒間隔で書き込む

# ------------------------------------------------------------------
# メイン関数
async def main():
	async with BleakClient(DEVICE_ADDRESS) as client:
		print(f"Connected: {client.is_connected}")

		# 並行して通知受信とデータ書き込みを行う
		notify_task = asyncio.create_task(receive_notifications(client, CHARACTERISTIC_UUID_READ))
		write_task = asyncio.create_task(write_data(client, CHARACTERISTIC_UUID_WRITE))

		# 5秒後にデータの書き込みが終了するので、その後も通知を受信する
		await write_task

		# 通知受信をしばらく続ける（ここでは5秒間）
		await asyncio.sleep(5)

		# 通知の停止
		await client.stop_notify(CHARACTERISTIC_UUID_READ)
		print(f"Stopped notifications on {CHARACTERISTIC_UUID_READ}")

		# 通知タスクの終了
		notify_task.cancel()
#
# ------------------------------------------------------------------
# 非同期タスクの実行
asyncio.run(main())
# ------------------------------------------------------------------
```

## 実行結果

```text
$ ./send_get_data.py 
Connected: True
Started notifications on 7DEF8317-7301-4EE6-8849-46FACE74CA2A
Written data to 7DEF8317-7302-4EE6-8849-46FACE74CA2A: bytearray(b'MB\r')
Written data to 7DEF8317-7302-4EE6-8849-46FACE74CA2A: bytearray(b'SV\r')
Oct/06/2024 PM 14:09
Written data to 7DEF8317-7302-4EE6-8849-46FACE74CA2A: bytearray(b'SU\r')
UCHIDA
Written data to 7DEF8317-7302-4EE6-8849-46FACE74CA2A: bytearray(b'ST\r')
ABCDEFGH
Written data to 7DEF8317-7302-4EE6-8849-46FACE74CA2A: bytearray(b'SC\r')
Stopped notifications on 7DEF8317-7301-4EE6-8849-46FACE74CA2A
```
【Laravel】クエリビルダでlatest()->first()やoldest()->first()と書いてはいけない

https://readouble.com/laravel/9.x/ja/queries.html#latest-oldest
> latestおよびoldestメソッドを使用すると、結果を日付順に簡単に並べ替えできます。デフォルトでは、結果をテーブルのcreated_atカラムによって順序付けします。もしくは、並べ替えるカラム名を渡すこともできます。

`latest()->first()`や`oldest()->first()`だと、`created_at`を基準にレコードを見に行ってしまうため、もしバルクインサートしたデータを取得したい場合、意図しないデータを取得してしまう場合があります。

### 【結論】
`latest()`と`oldest()`の引数に`id`を指定でOK
```php
latest('id')->first();
oldest('id')->first();
```
[DB]Non-repeatable ReadとPhantom Readの違い

# はじめに
Non-repeatable ReadとPhantom Readに関して、違いがわからなかったので整理しました。
どちらも同じトランザクション間で2回の同じデータ取得を行う際に、その間で別トランザクションでデータ更新が加わったとき、データをの整合性が取れなくなるという点で似ていると感じました。

# 違い
主に違いはデータ取得の対象です。
Non-repeatable Readは同じ行に対する取得を対象としていますが、Phantom Readに関してはある一定の範囲を対象としています。ある一定の範囲はクエリでの検索対象となる範囲です。

|                   | Non-repeatable Read              | Phantom Read                    |
|------------------------|------------------------------------------------------------|----------------------------------------------------|
| **対象**      | 同じ行                                | 特定の検索条件に一致する範囲                       |
| **シナリオ**      | 同じトランザクション内で、同じ行を2回読み取った際に異なる結果が返される | 同じトランザクション内で、1回目と2回目の検索で、行の数や内容が変わる              |
| **原因**                | 他のトランザクションによる対象の行データの更新                        | 他のトランザクションによる行の挿入や削除                |
| **防げる分離レベル**      | Repeatable Read以上                                       | Serializableのみ                                    |
| **例** | **①**: トランザクションA内で商品Aの価格を取得する。商品Aは100円。<br> **②**: トランザクションBが商品Aの価格を120円に更新し、コミットする。<br> **③**: トランザクションAが再度商品Aの価格を取得する。商品Aは120円となってしまう。 | **①**: トランザクションAが「価格が100円以上の商品」を検索し、商品A（100円）と商品B（120円）を取得する。<br> **②**: トランザクションBが商品C（価格110円）を挿入し、コミットする。<br> **③**: トランザクションAが再度同じ条件で検索すると、商品Aと商品Bに加えて商品Cも結果に含まれてしまう. |
【PHP】多次元配列内の値に変更を加えたい時

array_walk、array_walk_recursiveを使うとスッキリ書けます。
```php
// forEach
$array = [
	'hoge1' => null,
	'hoge2' => null,
	'hoge3' => null
];
foreach ($array as $key => &$value) {
    if ($value === null) {
        $value = 0;
    }
}
var_dump($array);
// array(3) {
//   ["hoge1"]=>
//   int(0)
//   ["hoge2"]=>
//   int(0)
//   ["hoge3"]=>
//   &int(0)
// }

// array_walk
$array2 = [
	'hoge1' => null,
	'hoge2' => null,
	'hoge3' => null
	];
array_walk($array2, function (&$value) {
    if ($value === null) {
        $value = 0;
    }
});
var_dump($array2);
// array(3) {
//   ["hoge1"]=>
//   int(0)
//   ["hoge2"]=>
//   int(0)
//   ["hoge3"]=>
//   int(0)
// }


// array_walk_recursive
$array3 = [
	'hoge1' => [
		'key1' => null
	],
	'hoge2' => [
		'key2' => null
	],
	'hoge3' => [
		'key3' => null
	],
];
array_walk_recursive($array3, function (&$value) {
    if ($value === null) {
        $value = 0;
    }
});

// アロー関数でもかける。
array_walk_recursive($array3, fn (&$value) => $value ??= 0);

var_dump($array3);
// array(3) {
//   ["hoge1"]=>
//   array(1) {
//     ["key1"]=>
//     int(0)
//   }
//   ["hoge2"]=>
//   array(1) {
//     ["key2"]=>
//     int(0)
//   }
//   ["hoge3"]=>
//   array(1) {
//     ["key3"]=>
//     int(0)
//   }
// }

```
AZ-900は合格できた話。

# 概要

AZ-900に合格できました！純粋に嬉しかったです(o^―^o)

社会人になり、初めての試験合格であり、“合格”の文字を見たときはすごくテンションが上がりました。
勉強の仕方を試行錯誤しながら挑んだので、勉強録をここにまとめたいと思います。

# 受験のきっかけ

業務でAzureを使うことになり、Azureの基本知識を整理したいなという思いで受験することを決めました。

# AZ-900学習法

AZ-900合格記を調べると、Udemyでの勉強が人気でしたが、私はなるだけ費用を抑えて勉強をしたいと思っていたので、Udemyは利用しない方向で勉強しました。
(いつか、Udemyも使ってみたい...！)

コスパ重視で選んだ参考書＆テキストは、以下の2つです。

- **合格対策Microsoft認定 AZ-900:Microsoft Azure Fundamentals テキスト＆問題集第2版**
こちらは、参考書として購入しました。セクションごとに章末問題があるため、インプットとアウトプットを細かい単位で繰り返すことができました。そのため、一分野ごとに理解しながら進めることができ、私にとってはとても分かりやすい参考書でした。

https://www.amazon.co.jp/%E5%90%88%E6%A0%BC%E5%AF%BE%E7%AD%96-Microsoft%E8%AA%8D%E5%AE%9A-AZ-900%EF%BC%9AMicrosoft-Azure-Fundamentals%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%EF%BC%86%E5%95%8F%E9%A1%8C%E9%9B%86/dp/4865943463

-  **IT Concepts JAPAN AZ-900: Microsoft Azure Fundamentals 問題集**
こちらは、無料でAZ-900の対策問題を解くことができるサイトです。無料会員登録をするだけで、90問の対策問題をすることができるため、とてもおすすめです！この問題を解くことで1つ目の参考書に足りない知識だったり、見落としてしまっていた知識を再確認することができました。最初は、1つ目の参考書のみで受験しようとしていたのですが、徐々に不安になった結果、こちらのサイトを発見しました。受験が終わってみて、1つ目の参考書だけでは足りなかったところもあったため、サイトでの問題集もやっておいてよかったなと思います。

https://it-concepts-japan.com/az-900-microsoft-azure-fundamentals

教材は以上の2つですが、参考書を見ながら、実際のAzureに触ってみるということもしていました。Azureでは30日間無料で試せるサービスがあるため、文章だけではわかりにくい機能などは手を動かして、なんとなくでも理解するようにしていました。文字だけでは分かりにくかったり、文字だけだと眠くなってしまうことがあるため、だいぶ助かりました。

# AZ-900本番

試験会場は自宅でした。リビングで受験したため、冷蔵庫や食器棚など生活用品がたくさんある状態でしたが、しょうがないため、受験する机(ダイニングテーブル)だけ綺麗にしました。少し心配でしたが、特に問題を指摘されることなく、試験に進めることが出来ました。

試験開始時間の30分前にはテスト準備をするようにということだったので、30分前には席について準備をしていたのですが、準備は20分もしない程度で終わり、試験開始予定時間より少し早く受験が開始しました。

試験時間は45分間で、問題数は36問(時によって問題数は変わるらしい)。ひと通り全問題を解き、全問題を再確認して、気になる問題だけ再々確認、という手順で行いましたが、10分くらい余ってしまい、時間には余裕がある試験だと思います。残りの10分は、分からない問題もありましたが、あがいても何も出てこないと思ったので、早めに試験終了しました。

# 結果

結果は、試験終了直後に分かりました。

**842点**/1000 (合格ラインは700点)

私自身、受験してから結果発表までの時間がとても苦手なので、直後の発表はすごく有り難かったです。点数は、合格すれば、何でもいいと思っていたので、とりまいぇーいって感じです。

# 感想

AZ-900を受験したことで、業務以外の機能を知ったり、Azureの様々な機能について整理したり、出来ました。また、クラウドの基礎知識も学ぶことが出来たため、Azureだけでないクラウドサービスに対する理解が深まったことは、駆け出し中エンジニアとして一歩前に進めたかなと思っています。

知識面だけでなく、この試験合格は、自分の自信につながりました。実は、平行して基本情報技術者試験も受験したのですが、合格できず、資格なんて...と思っていたところだったので、ここで一回資格に対するやる気を取り戻せた気がします。私にとって資格は勉強のモチベとなるので、これからも色々な資格を挑戦したいと思います。
共有シーケンサー(Shared Sequencer)とロールアップ

この記事は、以下の動画の内容のまとめです。
https://youtu.be/l7FSZligBDM?si=qpXGSrwOoc4c-3yx

## はじめに

共有シーケンサーは、複数のロールアップが利用できる共通のトランザクション順序付けレイヤーです。この記事では、共有シーケンサーの重要な技術的側面と、それがブロックチェーン生態系にもたらす影響について解説します。

## 共有シーケンサーとは

共有シーケンサーは以下の特徴を持つシステムです：

- 複数のロールアップに対して、トランザクションの順序付けサービスを提供
- 高速なファイナリティを実現
- トランザクションの順序付けを分散化
- MEV（Maximal Extractable Value）の制御を可能にする

```mermaid
graph TD
    A[ユーザー] --> B[共有シーケンサー]
    B --> C[ロールアップA]
    B --> D[ロールアップB]
    B --> E[ロールアップC]
    F[L1] --> B
```

## なぜ共有シーケンサーが必要か

従来のロールアップでは、以下のような課題がありました：

1. 各ロールアップが独自のシーケンサーを必要とする
2. トランザクションの順序付けが中央集権化されている
3. ユーザー体験（特にレイテンシー）の最適化が困難

共有シーケンサーは、これらの課題に対する解決策として登場しました。

## 共有シーケンサーの主要な技術的特徴

### 1. コンセンサスメカニズム

共有シーケンサーは、独自のコンセンサスメカニズムを持ち、以下の特徴があります：

- 高速なファイナリティ（数秒レベル）
- 大規模なバリデーターセット（数千ノード）をサポート
- 可用性よりも高速性を重視

### 2. MEVの制御

共有シーケンサーは、MEVの制御に関して重要な役割を果たします：

- オーダーフローオークションの実装が可能
- トランザクションの順序付けを公平に行うメカニズムの提供
- プログラマブルなMEV捕捉メカニズムの実装

### 3. Base Rollupとの関係

Base Rollupは共有シーケンサーの重要なコンポーネントです：

```mermaid
graph TD
    A[共有シーケンサー] --> B[トランザクション順序付け]
    B --> C[Base Rollup]
    C --> D[任意の実行環境]
    D --> E[状態遷移関数]
```

## 重要な考慮点

1. **決定論的な処理**
   - ロールアップの状態遷移関数は決定論的である必要がある
   - トランザクションの順序付けルールは明確に定義される必要がある

2. **価値捕捉メカニズム**
   - ロールアップ自体が価値を捕捉する方法の設計が重要
   - MEVの再分配メカニズムの実装が必要

3. **セキュリティとプライバシー**
   - 閾値暗号化などのプライバシー保護機能の実装
   - 検証可能なシーケンシングルールの適用

## 今後の展望

共有シーケンサーは、以下のような可能性を秘めています：

- より効率的なクロスロールアップ通信
- 改善されたユーザー体験（低レイテンシー）
- より公平なMEV分配メカニズム
- スケーラビリティの向上

## まとめ

共有シーケンサーは、ロールアップの実装をより簡単にし、ユーザー体験を向上させる重要な技術です。MEVの制御や効率的なトランザクション処理など、多くの利点をもたらす一方で、実装には慎重な設計と考慮が必要です。
zkRollupとMEV

## はじめに

Ethereumの大きな課題の1つであるスケーラビリティ。その解決策として注目されているzkRollupについて、仕組みからMEVまで詳しく解説します。

## 1. zkRollupとは

### オフチェーン実行の仕組み

zkRollupは、トランザクションの処理をオフチェーンで実行する Layer 2 ソリューションです。この「オフチェーン」は以下のような特徴を持っています：

1. **分散型の実行環境**
   - 複数のノード（Sequencer/Validator）で構成
   - トランザクションの収集、実行、検証を分散処理

2. **Sequencerの役割**
   - ユーザーからのトランザクション受付
   - トランザクションの順序付けと処理
   - バッチ処理と零知識証明の生成

3. **Validatorの役割**
   - 証明の検証
   - 不正検知

```mermaid
graph TB
    U[ユーザー] --> S[Sequencer]
    S --> |1. トランザクション収集| P[処理層]
    P --> |2. バッチ処理| Z[ZK Proof生成]
    Z --> |3. 証明生成| V[Validator]
    V --> |4. 検証| E[イーサリアムL1]
    S -.-> |状態同期| V
    
    subgraph "オフチェーン (L2)"
        S
        P
        Z
        V
    end
    
    subgraph "メインチェーン"
        E
    end
```

## 2. トランザクション処理の違い：L1 vs L2

### Mempoolの違い

L1（Ethereum）とL2（zkRollup）では、トランザクションの処理フローが大きく異なります。

```mermaid
graph TB
    subgraph "L1 Transaction Lifecycle"
        A1[ユーザー] --> B1[L1 Mempool]
        B1 --> C1[バリデーター]
        C1 --> |ブロック生成| D1[ブロックチェーン]
        D1 --> E1[確定]
    end

    subgraph "L2 zkRollup Transaction Lifecycle"
        A2[ユーザー] --> B2[L2 Mempool]
        B2 --> C2[Sequencer]
        C2 --> D2[バッチ処理]
        D2 --> E2[ZK Proof生成]
        E2 --> F2[L1に提出]
        F2 --> G2[L1で確定]
        G2 --> H2[L2で確定]
    end
```

### 主な違いのポイント

1. **Mempool管理**
   - L1：分散的なpublic mempool
   - L2：Sequencer管理下のプール

2. **処理速度**
   - L1：ブロック時間（約12-14秒）に依存
   - L2：Sequencerのバッチ処理タイミング

3. **最終性**
   - L1：ブロック確定で完了
   - L2：L1確定を待つ必要あり

4. **コスト効率**
   - L1：各トランザクションに高いガス代
   - L2：バッチ処理による大幅なコスト削減

## 3. MEVの比較：L1（PoS）vs L2

### MEVの構造的違い

```mermaid
graph TB
    subgraph "L1 MEV構造 (PoS)"
        U1[ユーザー] --> M1[MEVブースト]
        M1 --> B1[ブロックビルダー]
        B1 --> R1[リレー]
        R1 --> V1[バリデーター]
        V1 --> C1[ブロック確定]
    end

    subgraph "L2 MEV構造 (zkRollup)"
        U2[ユーザー] --> S2[Sequencer]
        S2 --> B2[バッチ作成]
        B2 --> P2[ZKプルーフ生成]
        P2 --> L2[L1への提出]
    end
```

### MEVの主な違い

1. **MEV抽出者**
   - L1：複数アクター（ブロックビルダー、バリデーター、リレー）
   - L2：主にSequencer

2. **抽出方法**
   - L1：多様な戦略（サンドイッチ、フロントランニング等）
   - L2：Sequencerによる取引順序操作

3. **規模と特徴**
   - L1：大規模な流動性、多様な機会
   - L2：比較的小規模、Sequencer主導

### 課題と対策

**L1の課題：**
- バリデーター間の競争激化
- リレーの中央集権化リスク
- PBS実装の複雑さ

**L2の課題：**
- Sequencer権限の集中
- 透明性の欠如
- ユーザー選択肢の制限

## 4. 今後の展望

### L1（PoS）の方向性
- PBSの継続的改善
- MEVブーストの分散化促進
- フェアネスメカニズムの強化

### L2の発展
- 分散型Sequencerの実装
- 順序付けオークションの導入
- 透明性向上への取り組み

## まとめ

zkRollupは、Ethereumのスケーラビリティ問題に対する有効な解決策として期待されています。しかし、MEVの観点からは新たな課題も存在します。L1とL2それぞれの特性を理解し、適切に活用していくことが重要です。
AWS DataSyncについて

## AWS DataSyncとは
AWS DataSyncはオンプレミスからAWS、またはAWSストレージ間のデータ転送を行うサービスです。対応しているストレージサービスはS3やAmazon EFS、Amazon FSxなどがあります。移行元としてオンプレミス側のファイルサーバー(NFS、SMB)もサポートしています。

## 主な特性
### フルマネージド型サービス
ユーザーがサーバーを管理する必要がありません。
### 高速なデータ転送
データ転送には、AWS設計の転送プロトコルを利用します。ネットワークの状況を検証しながら調整し最適な転送方法を提供します。
### データ検証
転送が完了した後に、ソースとターゲットのデータが一致することを検証します。DataSyncではデータの一貫性と安全性が保証されています。
### 料金
移行するデータ分だけの支払いなのでコスト効率が良いです。
PHPのバージョンを変更する方法

こんにちは！
Laravelのバージョンによって求められるPHPのバージョンが異なることはみなさんご存知だと思います。
この記事では、Laravel Sail、Dockerを用いて現在のPHPのバージョンの確認方法と変更方法について記載したいと思います！

初めての投稿で拙い文章ですが、温かい目で読んでやってください！
# LaravelのバージョンとPHPのバージョンの依存関係
(2024/10 現在)
| Laravelのバージョン | PHPのバージョン |
|:-----------|------------|
| Laravel 8      | PHP 7.3以上        |
| Laravel 9      | PHP 8.0以上        |
| Laravel 10    | PHP 8.1以上      |
| Laravel 11    | PHP 8.2以上      |


上の表のようにLaravelのバージョンによっては必要とされるPHPのバージョンも異なります。
PHPのバージョンが求められているバージョンを満たしていない場合、意図していた動作になりません。

# PHPのバージョンの確認方法
まずは、以下のコマンドを実行し現在のPHPバージョンを確認します！
```
$ sail php --version
```
```
$ sail php --version
PHP 8.1.12 (cli) (built: Sep 27 2024 03:53:05) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.12, Copyright (c) Zend Technologies
    with Zend OPcache v8.3.12, Copyright (c), by Zend Technologies
    with Xdebug v3.3.2, Copyright (c) 2002-2024, by Derick Rethans
```
ここではPHP8.1が使われていることが確認できました！

# ymlファイルの修正
docker-compose.ymlファイルを開き以下記述がある部分を修正してください！
```
services:
    laravel.test:
        build:
            context: './vendor/laravel/sail/runtimes/8.3'　// 8.3に変更
            dockerfile: Dockerfile
            args:
                WWWGROUP: '${WWWGROUP}'
        image: 'sail-8.3/app'　// 8.3に変更
```
修正が済んだら保存するのをお忘れなく！

残りはターミナルでコマンドを打つだけなのでささっといきます！

# 残対応
コンテナの再構築
```
$ sail build --no-catch
$ sail up -d
```
パッケージの更新
```
$ sail composer update
```
コンテナの再起動
```
$ sail restart
```

ここまででバージョンが変更できているはずです、あとはバージョンを確認するだけ！
# 最後に
※ちなみにエイリアスを設定していない場合は以下のようにコマンドを入力してください。
例：sail up コマンドの場合
```
$ ./vendor/bin/sail up -d
```

記事を読んでくださりありがとうございました！
【React】zustandのpersistで独自のstorageを使用したい

## 概要
状態管理のライブラリzustandでは、[Persisting store data](https://zustand.docs.pmnd.rs/integrations/persisting-store-data)のドキュメントにある通り、状態の値を永続化する機能があります。標準だとlocalStorage、sessionStorageが用意されているようですが、cookieなど他のstorageを使用したい場合はどうすればよいかのメモ書きです。

## 前提
* 使用したzustandのバージョンは`4.5.5`です。

## 対応方針
[Is it possible to use cookies for as a persist storage?](https://github.com/pmndrs/zustand/discussions/1716)のdiscussionsにある通り、別途StateStorageのinterfaceの実装を用意して、それを設定することで実現できます。

## 実装サンプル
上記の記事と同様に、cookieで実装する場合のサンプルは以下の通りです。

```ts
import { getCookie, setCookie, removeCookie } from "typescript-cookie";
import { create } from "zustand";
import { createJSONStorage, persist, StateStorage } from "zustand/middleware";

const cookiesStorage: StateStorage = {
  getItem: (name: string) => {
    return getCookie(name) ?? null;
  },
  setItem: (name: string, value: string) => {
    setCookie(name, value, { expires: 1 });
  },
  removeItem: (name: string) => {
    removeCookie(name);
  },
};

type SampleTokenType = {
  sampleToken: string | undefined;
  updateSampleToken: (token: string) => void;
  removeSampleToken: () => void;
};

export const useSampleTokenStore = create(
  persist<SampleTokenType>(
    (set) => ({
      sampleToken: undefined,
      updateSampleToken: (token) => set({ sampleToken: token }),
      removeSampleToken: () => set({ sampleToken: undefined }),
    }),
    {
      name: "test-storage",
      storage: createJSONStorage(() => cookiesStorage),
    }
  )
);
```
LINQの説明とサンプルコード


前回の記事から日があいてしまいましたが、今回はLINQを取り上げます。

型DataTableに対して、言ってみれば、SQLのように指定したデータを取得するものです。

FruitsDataTableのイメージ
| No         | Name        | Color        |
|:-----------|------------:|:------------:|
| 1          | Apple       | Red          |
| 2          | Banana      | Yellow       |
| 3          | Grape       | Purple       |
| 4          | Orange      | Orange       |


```
'配列を用意
Dim array1() As String = {"Apple","Banana","Grape","Orange"}
Dim array2() As String = {"Red","Yellow","Purple","Orange"}
Dim dt As New DataTable

dt.Columns.Add("No", GetType(Integer))
dt.Columns.Add("Name", GetType(String))
dt.Columns.Add("Color", GetType(String))

For i = 0 To 3

    Dim dr As DataRow = dt.Rows.Add()
    dr("No") = i + 1
    dr("Name") = array1(i)
    dr("Color") = array2(i)

Next i

```

以上が、サンプルデータテーブル(dt)の作成です。

では、本題のLINQを記述します。
例えば、NameのAppleのデータのみを取り出す例です。

```

        Dim appleRows = From row In dt.AsEnumerable() Where row.Field(Of String)("Name") = "Apple" Select row



```

LINQを記述することで、データを集合演算のように抽出することができます。
複数のデータを扱うことができるため、重宝しています。

LINQのいくつかのバリエーションを記載しておきます。
ChatGPTで生成しました。

1.単純なWhere句でのフィルタリング
```
'特定の条件に合致する行を取り出す場合
Dim table As DataTable = GetYourDataTable()

Dim result = From row In table.AsEnumerable()
             Where row.Field(Of String)("ColumnName") = "YourValue"
             Select row

For Each r As DataRow In result
    ' 行に対する処理
Next

```

2.Select句で特定の列だけを取り出す
```
`特定の列のデータだけを取得したい場合
Dim table As DataTable = GetYourDataTable()

Dim result = From row In table.AsEnumerable()
             Select row.Field(Of String)("ColumnName")

For Each value In result
    Console.WriteLine(value)
Next

```

3.複数の列を匿名型で取得
4.OrderByでのソート
5.Distinctで重複排除
等々
データのフィルタリング、選択、ソート、集計に使用できます。

「一部のコードは、OpenAIのChatGPTを使用して生成しました。」

## まとめ
LINQを利用することで、データをSQLのように取得することが可能です。