OmniAICreator/Qiita-1.07M huggingface dataset:
spreadsheet と Pythonの連携（gspread）

<h1>目的</h1>
以下の流れのツールを作成するため<br>
1. spreadsheetへ出力されたキーワードの情報を検索<br>
2. Pythonで情報処理を行う<br>
3. 処理した情報をspreadsheetへ連携させる<br>
<h1>目標</h1>
spreadsheetの情報をPythonへ出力できるように<br>
Pythonで加工した情報をspreadsheetへ出力できるように

<h1>コード</h1>

事前準備として以下が必要
https://yunifusu.com/programming/python/gspread_setting/

完了したら以下のコードを記載する
~~~
import gspread
from oauth2client.service_account import ServiceAccountCredentials 
#各種のツールをインポートする

scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive']
#たぶんスプレッドシートとgoogledriveの利用許可を取るための土台
Keyfile = 'python-key.json'
#上記に秘密鍵（JSONファイル）のファイル名を入力
#ただしそのファイルはコードを動かすPythonファイルと同じ配下にする

credentials = ServiceAccountCredentials.from_json_keyfile_name(Keyfile, scope)
gc = gspread.authorize(credentials)
~~~

次にシートの指定をしていく
~~~
SP_id = "〇〇〇〇"
#スプレッドシートのURLを記載
wb = gc.open_by_key(SP_id)
print(wb)

ws = wb.worksheet('シート1')
print(ws)

ws_id = ws.id
print(ws_id)
~~~

この後に様々な処理が可能に
~~~
#リストをA9~B10セルへ格納する
cell_list = [["a","b"],["c","d"]]
ws.update('A9:B10', cell_list)

#セル7,2へappleを記入
cell2 = ws.update_cell(7, 2, 'Apple')

#3,2セルの内容を表示
value_1 = ws.cell(3,2).value
~~~

参考URL
https://yunifusu.com/programming/python/gspread_manual/#google_vignette
PDOでデータベースと接続 （基本）

# PDOクラスで接続する方法

- 参考: [PDO::__construct](https://www.php.net/manual/ja/pdo.construct)  ※ 一番初めに呼ばれる  

## `db_connection.php` を作成及び編集

```php:db_connection.php
<?php

// 直書きでも良いが定数として定義
const DB_HOST = 'mysql:dbname=hoge_db;host=127.0.0.1;port=8889;charset=utf8';
const DB_USER = 'hoge_user';
const DB_PASSWORD = 'hoge123';


// 例外処理 Exception try catch構文
try {
    $pdo = new PDO(DB_HOST, DB_USER, DB_PASSWORD); // PDOクラスのインスタンス化
    echo '接続成功';
} catch (PDOException $e) {
    echo '接続失敗' . $e->getMessage() . "\n";
    exit(); // 接続失敗時には処理を抜ける
}
```

- `db_connection.php` にアクセスすると成功時には `接続成功` とブラウザに表示される 。

# オプションを付ける

- `db_connection.php`を編集

```php:db_connection.php
<?php

const DB_HOST = 'mysql:dbname=hoge_db;host=127.0.0.1;port=8889;charset=utf8';
const DB_USER = 'hoge_user';
const DB_PASSWORD = 'hoge123';

try {
    $pdo = new PDO(DB_HOST, DB_USER, DB_PASSWORD, [
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // 連動配列で取得する
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // 例外を表示する
        PDO::ATTR_EMULATE_PREPARES => false // SQLインジェクション対策
    ]); 
    echo '接続成功';
} catch (PDOException $e) {
    echo '接続失敗' . $e->getMessage() . "\n";
    exit();
}
```

`PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC`をもう少し詳しく説明すると  
PDOがデータベースからデータを取得する際のデフォルトのフェッチモードを設定します。  
PDO::FETCH_ASSOCは、結果セットの各行をカラム名をキーとする連想配列として返すモードを指定します。  

つまり、この設定により、データベースから取得したデータは以下のような形式で返されます。

```php:sample.php
[
    'column_name1' => 'value1',
    'column_name2' => 'value2',
    // ...
]
```

`PDO::ATTR_EMULATE_PREPARES => false` に関しては chatGPT先生に聞いてみると。。。

PDO::ATTR_EMULATE_PREPARESをfalseに設定するかどうかは、使用しているデータベースやアプリケーションのニーズによって異なります。

通常、PDO::ATTR_EMULATE_PREPARESをfalseに設定することは、プリペアドステートメントをサーバーサイドで実行し、SQLインジェクションなどのセキュリティ上のリスクを軽減するために推奨されます。これにより、PDOは実際にバックエンドデータベースにプリペアドステートメントを送信し、データベースがプリペアドステートメントをサポートしている場合にはそれを使用します。ただし、一部のデータベースや状況では、この機能が正常に機能しないことがあります。

一方、一部のデータベースやアプリケーションでは、PDO::ATTR_EMULATE_PREPARESをtrueに設定することが推奨される場合もあります。これは、特定のデータベースやプリペアドステートメントの動作に関する問題がある場合や、プリペアドステートメントのエミュレーションが必要な場合に該当します。

そのため、PDO::ATTR_EMULATE_PREPARESをtrueまたはfalseに設定するかどうかは、特定の状況や要件に基づいて決定されるべきです。データベースのタイプやバージョン、セキュリティの要件、パフォーマンスの要求などを考慮して、適切な設定を選択する必要があります。


以上です。
monaca+Apple Developer ProgramでiOSデバイスを追加する手順

# 前提
前回記事「[monacaでiOSアプリをデバックビルドするまでの手順](URL "https://qiita.com/saba_uni_toro_/items/94459b552fb5d75bdb30")」の続きです。
テスト用に複数のデバイスを後から追加したい場合の手順を備忘録として記載します。

# 手順1：デバイスを追加
1.[Apple Developer Program](URL "https://developer.apple.com/jp/programs/")にログイン
2.サイドメニューの「Device」を選択し、「+ボタン」を押下
![スクリーンショット 2024-04-06 21.59.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224077/3c3e9bec-4a1f-dedb-23be-8ba42ff4884a.png)
3.追加したいデバイスの情報を登録
![スクリーンショット 2024-04-06 21.59.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224077/3a05e159-d6c1-5877-6daa-1730882ba3f9.png)

# 手順2：プロビジョニングファイルの編集
手順1で追加したデバイスをプロビジョニングファイルに紐づけます。

1.サイドメニューの「Profile」を選択し、紐づけたいプロファイルを選択
![スクリーンショット 2024-04-06 22.05.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224077/760f4af1-9765-a7ed-9720-73a614315c49.png)

2.「Editボタン」を押下
![スクリーンショット 2024-04-06 22.07.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224077/c54c89a2-bf90-01c7-4fe8-9d24f513ebe8.png)

3.追加したいデバイスを選択し、保存
![スクリーンショット 2024-04-06 22.08.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224077/192a6c8c-84a8-5911-3668-314de08c8fb2.png)

4.追加したデバイスが反映されていることを確認した上で「Downloadボタン」を押下
これは手順3で使う最新のプロビジョニングファイルなため保管しておく
![スクリーンショット 2024-04-06 22.09.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224077/1de2f9b7-2810-672b-3b00-73db5eb73f22.png)

# 手順3：プロビジョニングファイルの更新
1.monacaにログインし、iOSビルド設定の画面を開く
2.「プロファイルのアップロードボタン」を押下し、「手順2の4」でダウンロードしたファイルをアップロードする
![スクリーンショット 2024-04-06 22.13.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224077/c79e42fe-52e1-1468-4b16-7d5b55ef3109.png)

この時前回アップロードしたプロビジョニングファイルは削除してください。
（※以下の赤枠箇所のように１つだけ設定されている状態にしてください）
![スクリーンショット 2024-04-06 22.16.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224077/83ff4c66-7656-ddfd-94c5-fbd6ecbfff0c.png)
私の場合、前回・今回の２つ分のファイルがアップロードされている状況ですと
ビルドがうまくいきませんでした。

3.「ビルドを開始する」ボタンを押下し完了
![スクリーンショット 2024-04-06 22.20.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224077/c029ac36-e80d-3f0f-7da0-bc0913c622db.png)
ITパスポート 電子メール

・電子メールのアドレスの構造
xyz@abc.co.jp @の左側がユーザ名で右側がドメイン名
・同報メール
複数の宛先に一度にメールを送信すること
・BCC欄に入力したメールアドレス
受信者全員に通知されない
・メーリングリスト
あらかじめ登録されているメンバーに同報メールを送信できるサービス
・電子メールの送受信の方法
専用のメールソフトを使う方法とWebブラウザを使う方法がある
・電子メールの形式
テキスト形式とHTML形式がある
Go の第一印象が Cっぽくてなんか懐かしい、と思った。

# 変数型

```
int int8, int16, int32, int64

uint uint8, uint16, uint32, uint64
```
**符号無し8ビット整数**
とか
で uint8 で byte の別名を表すところもCっぽい。
あれは確か Windows の MFC だったかな。

# 構造体
『構造体❣』と来ました。

## C
```
struct Player {
	char* string;
	int age;
};
typedef struct Palyer;
```


## Go
```
type Player struct {
	name string
	age int
}
```
Godot4で3D風２D縦スクロールシューティングゲームを作る 19回目 ボスの攻撃 前方にバズーカ発射

Godotのバージョンを4.2.1にしました。
Godot4.2.1でシューティングゲームを作っていきます。

# ボスキャラBigFireにバズーカを発射させる
　ボスキャラBigFireが、バズーカを前方に発射するように実装します。

# 方針　
　17回目で全方位弾を追加した時と同じように、ボスキャラBigFileシーンにバズーカ生成用シーンを子ノードとして追加するだけで、一定周期でバズーカを発射するようにします。 追加するバズーカ生成用シーンはボスキャラBigFireの位置情報のみ使用します。
　以下の画像で、ボスキャラBigFireの前方にある大きな白い球がバズーカのつもりのものです。そのうちGPUParticles3Dを使って格好よくしたいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/6111a279-e5b3-0379-b9b1-42be0ffe0e94.png)

# github
　本記事で実装したものをGitHubで公開しています。

https://github.com/footinglow/woden/tree/019_boss_bigfile_bazooka

# 修正および新規追加ファイル
　生成されると、ただまっすぐ進むだけのバズーカ用のシーン(boss_bazooka.tscn)とスクリプトを新規追加します。また、そのバズーカ用シーンを生成するためのシーン(boss_bazooka_periodically.tscn)とスクリプトを新規追加して、ボスBigFileシーン(boss_bigfile.tscn)に子ノードとして追加します。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/23be64d0-972e-36e9-ff0b-78dcfdd6ec3a.png)

# バズーカ生成用シーンをボスキャラBigFireシーンに追加する
　ボスキャラBigFileは大きなエンジンを左右に2つ持っています。それぞれのエンジンの前方からバズーカを発射するので、バズーカ生成用シーン(boss_bazooka_periodically.tscn)を２つ子ノードとして、ボスキャラBigfireシーン(boss_bigfile.tscn)に追加します。子ノードの名称には左右のどちらかがわかるように、RとLの字を追加しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/26e2cdd4-b96c-3d8e-f3d5-afc260cf8a2c.png)
　バズーカ生成用シーンのルートノードのMarker3Dは、3Dエディタ上で十字のマークで表示されるため、位置の確認がしやすいという特徴があります。十字の大きさ（線の長さ）はMarker3DのGizmo Extentsプロパティを変更することで調整可能です。初期値の0.25mでは小さくて見にくいので、2.5mに変更しました。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/9f636c9d-2ea8-40d4-4935-6ed54e94f25c.png)

　ボスキャラBigFireシーンの3Dエディタを開き、表示を上面図に変更して、追加した２つのバズーカ生成用シーンを大きなエンジンの前方にそれぞれ移動します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/73aab475-433f-2983-b9f5-c4dc4a5842ca.png)
　Marker3Dは上面から見ると十字マークですが、X,Y,Z軸方向に線が伸びています。3Dエディタの視点を少し変更すると確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/bb508842-2088-db87-d0fe-49c5944db8c5.png)

# その他の実装について
　あまり新しいことはやっていないので説明は省略します。
　ただ前回までの実装では隕石とアイテムとボスが同時に出現するため、敵の攻撃を避けながらアイテムを取るのが非常に難しかったので、ステージシナリオ「res://scenario/scenario_stage01.tscn」を修正して、アイテムを表示して全て消えてからボスのみが出現するようにしました。

# 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/4bf44433-971b-3307-5fc2-2a564d509c1a.png)

 以上です。
Firebase Functionsへのデプロイが突然エラーになってはまった

# 事象
FirebaseのFunctionsにaxiosで外部APIからデータを取得する関数を書いてデプロイしようとしたところ下記のエラーが発生した。
`
Could not create or update Cloud Run service 「関数名」, Container Healthcheck failed. Revision 'getinstagramdata-00004-pud' is not ready and cannot serve traffic. The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable. Logs for this revision might contain more information.
`
# 原因
**functionsにaxiosがインストールされていなかった**という初歩的なオチでした。
axiosがないよ！というエラーはでないため、前述のエラーメッセージからは推測できず。

コード上にaxiosのimportが記述されていているのですが、プロジェクト本体にはaxiosはインストールされており、Functionsに**別途インストールしなければいけない**ことに気づいていませんでした。


エラー文にPORT=8080に関する記述もあり、CloudRunのポート周りの設定を調べるなど、関係ないことに時間を費やしてしまいかなりハマりました。

# 解決方法
```
firebase init functions
```
で作成されたfunctionsディレクトリに移動してaxiosをインストール

```
npm i axios
```
その後下記でデプロイしたところ問題なく動作させることができました
```
firebase deploy --only functions
```
xammpでmysqlが起動できない場合の対処方法

自分の勉強も兼ねています。

xammpでmysqlを起動した際に以下のようなエラーがでて、起動できない場合の対処方法
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764791/5234aa19-b102-09b7-1a3c-5980fc9493d8.png)


1. ファイアウォールでport3306が解放されていない。
画面右側のLogs を確認すると、port 3306 が解放されてないというエラーが表示される場合があるので、ファイアウォールで設定

詳細設定を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764791/cfe443b1-5b9a-dbb9-3be0-d866028626cb.png)

送信の規則、受信の規則両方でport3306の設定

新しい規則を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764791/8e9ba621-f60f-7b10-18c0-9a0248d12425.png)

ポートを選択し、つぎへ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764791/87973e87-fbdd-b23e-e7b8-6707bfe4085c.png)

tcpと特定のポートで3306を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764791/3f139d68-04b9-39ab-68b8-cd899a91212d.png)

接続を許可する、次へを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764791/5b6da63b-8fb1-4778-57f5-747e7d75cbf6.png)

必要なものをチェック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764791/6fc4b3c8-6684-eb6e-014d-e5e9b28ff2a4.png)

名前を入力し、完了

上記の設定を行っても、mysqlを起動できない場合。
同じポートを使っているプロセスがないかを確認

管理者権限でパワーシェルを起動、以下のコマンドを実行
.\netstat -nao|find "3306"
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764791/05af8298-e317-e1dd-f932-df6ea0aec398.png)


コマンドの実行でエラーになる場合は、.\netstat -naoで　ip アドレス:3306になってるプロセスのpidを確認

タスクマネージャーを起動して、詳細にpidを入力、停止
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764791/1dc342c8-963b-c40c-b254-9de35b43d884.png)

それでも無理な場合、
configのmy.ini を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764791/70feeb29-78e7-84f5-9b85-04969dd5a043.png)

port=3306のせんとうに#を追加、コメントアウトして、port=3307を追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764791/9c794369-8236-a857-4b89-5da4b8e866d5.png)
【Java基本編】データ型について

こんにちは！
今回はJavaのデータ型、そして使用する際の注意点を載せていきたいと思います！
Javaの勉強を始めたばかりなので、どう使い分けるかそもそもどんなデータ型があるか知る必要があると思い、まとめてみたのでJava初心者の方の参考になると幸いです！

# データ型
データ型の中でも整数、小数、真偽値、文字、文字列などの分類が存在します。分類の中では使い分けが分かっていないと適切に使えないものもあるので、簡単に解説していけたらと思います。また、データ型を指定することでメモリを確保することができます。

## 整数型
数字の大きさによって、使うデータ型を変えます。また、小数とは扱いが別なので注意です！
| 型名| 説明 | 数値の範囲 | 使用例 | 頻度 |
|:-:|:-:|:-:|:-:|:-:|
| long | 8バイト符号付き整数  | -9223372036854775808～9223372036854775807  | 売上高など数字の大きいもの |   |
|  int | 4バイト符号付き整数  |  -2147483648～2147483647 |  一般的な数字の計算など |  高 |
|  short |  2バイト符号付き整数  |  -32768～32767 | 年齢など  |   |
|  byte |  1バイト符号付き整数 | -128～127  | データなど |   |

**この中でよく使うのは`int`です。**`byte`はデータを表すための型なので、整数を表すための用途であればint型, short型, long型を利用すべきだそうです。また、`int`, `short`, `long`の違いは表現できる値の範囲(表でいう数値の範囲)が異なるのみで、基本は`int`を用い、それより大きい数字は`long`を使うそうです。

ここまでくると使い分け方法が理解できてきました。

### 2進数、8進数、16進数の表し方
変数に代入する値の接頭辞に、2進数は`0b`、8進数は`0`、16進数は`0x`を付けることで何進数か表すことができます。
```java:2進数の表し方
int binaryNumber = 0b1011;
```
```java:8進数の表し方
int octalNumber = 010;
```
```java:16進数の表し方
int hexadecimal = 0xFF;
```

### 桁を区切る表記
JavaSE 7以降ですと、値に`_`(アンダースコア)を含めることで、処理には影響を与えませんが見やすくすることができます。
```java:区切り
int spanNumber = 1_150;
```
整数のデータ型の説明はここまでです。

## 浮動小数点型(小数に使うデータ型)
小数のデータ型は小数点(`.`)のつく数字を扱う際に用いられます。
| 型名| 中身 | 数値の範囲 | 使用例 | 頻度 |
|:-:|:-:|:-:|:-:|:-:|
| double  |  8バイト浮動小数点数 | ±4.94065645841246544×10^-324～±1.79769313486231570×10^308  | 普通の小数  |   |
|  float | 4バイト浮動小数点数  |  ±1.40239846×10^-45～±3.40282347×10^38 | 少し曖昧でいい小数  |  中 |

基本的には`double`を優先して使います。`double`は厳密、`float`はそれより曖昧な表現になります。

### 指数表現
小数のデータ型(浮動小数点型)では指数表現もでき、`E`を用いることで表現できます。
`1.3332E5`は`1.3332×10^5`と同じ意味になります。

## 論理型
論理型には`boolean`があり、`true`(真)か`false`(偽)しか入らない特別なデータ型です。

## 文字型
`char`と`String`(Sは大文字なので注意！)が存在し、

`char`:1文字だけ代入(`''`シングルクォーテーションで囲む！)
`String`:文字列を代入(`""`ダブルクォーテーションで囲む！)

のように使い分けます。
```java:char型の使用例
char color;
color = '白';
```
```java:String型の使用例
String name;
name = "ハム太郎";
```

:::note warn
char型で""を使用するとString型として扱われ、エラーが出るので使い分けに注意！
:::

## 最後に
ここ最近就活や勉強を理由に技術ブログ更新が疎かになっていたので、Javaを学び始めたことをきっかけに頻度を上げられるように頑張ろうと思います！(意気込み)
もし間違いなどありましたら、お気軽にコメントや修正提案いただけますと幸いです。
AWSのALB + EC2の構成でサイト管理画面へのIP制限をする(WAF無し)

## webサイトで管理画面へのアクセスはIP制限を行いたい場合の方法メモ
### 経緯
料金等を考えずにALB + EC2で特定URLへのアクセス制限をしたい場合はAWS WAFを利用すれば良いのですが、コストの都合上などで使用しない方針になったのでEC2のapacheのconfigで制限を実施しました。

### Apacheでのアクセス元IP制限について
ALBを挟まずにEC2のみでサイトを運用している場合はhttpd設定ファイルに
```
<Directory /xxx/yyy>
  Require <IP adress>
</Directory>
```
の記載で対象サイトにアクセス元のIP制限をかけることができるのですが、ALBを挟んでいる場合はEC2と通信するのは常にALBとなるのでこの書式ではIP制限を行うことができません。

### 設定した内容
なので今回はX-Forwarded-Forヘッダの値を見て以下のような記述でアクセス制限をします。apacheの設定ファイルに記載します。
```
<Directory /xxx/yyy>
  SetEnvIf X-Forwarded-For "^192\.168\.xxx\.xxx" allowed_ip
  Require env allowed_ip
</Directory>
```
X-Forwarded-ForはクライアントやALB、CloudFrontなどの経由したサーバのIPアドレスが記録されるヘッダーなので、正規表現でここにアクセス元のIPがあるかどうかで許可を行なっています。

CloudFront + EC2などでもこの記載でアクセス制限可能ですね。

### 以下参考サイト
- https://ymyk.wordpress.com/2010/02/25/x-forwarded-for%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E3%80%81ip%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%A7%E3%81%AE%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%88%B6%E9%99%90/
社内有志勉強会を始めて1年を振り返る

## この記事について

- 丁度１年ほど前から、社内で有志の勉強会の主催を始めました
- 当時考えていた事や振り返りを記事として残します
- 社内での勉強会開催の参考になれば幸いです

## 自己紹介

- 簡単に私の紹介をすると、SaaSの自社開発企業に所属しています
- 開発メンバーは40名弱で、その中のSREチームの一員として働いています

## 勉強会の概要

- テーマ
  - インフラ関連の技術や概念の紹介が中心
- メンバー
  - 開発メンバー向けに開催
  - 有志参加でテーマ毎に参加者を募集する形
- 形式
  - 座学中心で、場合によってはハンズオンも

勉強会の資料は[GitHubのPublicリポジトリ](https://github.com/yoyoyo-pg/infra-study)で公開しています

## 勉強会実施の経緯と目的

当時の課題感としては主に以下です

1. サーバレスな構成やコンテナ化など、プロダクトにおけるAWSの利活用が進んでおり、運用に関しての勉強会を実施する事はあるものの、SREチームの取り組みを伝える機会を中々持てていなかった
2. SREチーム以外の開発メンバーがインフラに関与する事は殆どなく、インフラリソースを考慮しての開発や、SREチームへの業務依頼がしにくい状況であった

この状況に加え、私自身アウトプットを通して学習していきたいという考えもあり、個人・組織ともに、スキマ知識を埋めつつ成長していく事を目的として、有志での勉強会を立ち上げることにしました

### アウトプットの効果

- 2022年のアドベントカレンダーに記載していますので、よければ以下の記事もご覧ください

https://qiita.com/yoyoyo_pg/items/ceedd35ae4d192c7db6a

## 勉強会設計のポイント

- ここからは、勉強会を仕組み化する過程での工夫や検討事項と、その効果について記載します

## 企画段階：有志参加とするかどうか

- 開発チーム全体向け or 有志参加 の内、有志参加の勉強会とする事を当初から考えていました
- 後に記載しますが、業務に直接役立つとも限らないテーマも盛り込もうと考えていたからこそ、各々が必要に応じて参加頂ければという想いもありました

## 企画段階：勉強会の予算をどう確保するか

- 業務内で使える工数の目安が決められているので、具体的にどの枠組みとして実施するかの検討が必要でした
- 当初は「最悪、業務外の勉強会という形で有志を募ってみよう」と考えていたのですが、マネージャー陣に相談した所、快く業務時間内での開催にOKを出してくれました
- 結果として、社内で決められている学習工数の範囲内でどなたでも参加可能な勉強会とする事が出来ました

## 企画段階：継続開催の仕組みをどう作るか

- 相談の中で勉強会の大枠が固まってきた所で、最後に検討したのは勉強会の継続開催です
- 今後継続してチームを跨いだ勉強会を開催する事を考えると、開催側（私）としても、承認側（マネージャー陣）としても、手間が無いように事前に取り決めをしておきました

### 勉強会のフォーマット

事前に取り決めをした勉強会のフォーマットについて、部分的に記載します

- テーマ
  - インフラ関連の技術や概念の紹介が中心
- メンバー
  - 開発メンバー向けに開催
  - 有志参加でテーマ毎に参加者を募集する形
- その他
  - 社内で決められている学習工数の範囲内での参加
  - 参加前に上長承認を頂く形での参加

おかげで、都度の勉強会の実施承認はマネージャー陣への軽い告知のみで済む状態となりました

## 実施段階：テーマをどうするか

- こちらに関しては、主に上記の「課題感」に基づいたテーマを都度、選定する事にしました
- 改めて整理すると主に3つの観点です
  - 今まで実施した勉強会の実例（全九回）とセットで記載します

### AWSの基本的なサービスの紹介

- 第一回：AWSことはじめ　～アカウント開設時にやっておきたい事～
- 第二回：AWSの基盤、ネットワーク関連のサービス（VPC、サブネット等）について
- 第三回：AWSのロードバランサー（ALB、NLB）について
- 第八回：AWSのIAM（権限回りの仕組み）について

### 直近のSREチームの取り組みの内、マストでは無いが意識頂けると嬉しい内容

- 第五回：Gradleについて（ハンズオン）
- 第六回：IaCについて
- 第七回：メールの送信ドメイン認証について

### 今後利用を検討している技術や概念

- 第四回：マイクロサービスについて
- 第九回：Node.jsの紹介

## 1年を振り返ってみて

### 課題の解決に至ったかどうか

- まず振り返りたいのは「課題解決に至ったか」ですが、これについては「部分的に貢献できた」程度かなと思っています
  - 事前に資料公開 & 勉強会の意図は記載するようにしているので、有志参加のメンバーが知りたい事 ⇔ 自分の話す内容 の期待値調整は多少出来ているとは思います
  - とはいえ、スポット開催の勉強会に過ぎないので、少しばかりの知識補完が出来た程度だと捉えています

### 関心は人により全く異なるという事

- これは参加者の人数や実施後アンケートから改めて感じた点です
  - 参加者は少ない時は数人～多い時は十数人で、特にSREチームの取り組みとしてタイムリーな話題の時には人数が多い印象でした
  - また、アンケートで「勉強会としてやって欲しい内容」を聞く事もしますが、私が全く触れていない領域などもあり、関心の高いテーマはメンバーにより様々だと改めて感じます

### 副次的な効果

- 有志勉強会以外の取り組みとして、定期的に技術情報や勉強会情報を共有するようにしています
  - 結果としてJAWS-UG（Japan AWS User Group）のイベントに会社の後輩が参加してくれたりと、AWSに対する開発メンバーの関心が以前より高くなって来ていると感じます
  - これについては他のSREメンバーで外部の情報共有を積極的に行っている方のお陰でもあるので、チームとして引き続きの情報共有に取り組んでいきたい内容だと改めて感じます

## 今後に向けて

- 勉強会を主催する自分自身が勉強になっている事もあり、取り組みとしての需要がある限りは継続していきたいと考えています
  - SRE視点で知ってもらいたい事 ⇔ 開発チームが知りたい事 ⇔ 自分自身が深掘りしたい事 のバランスを取りつつ、無理なく継続して実施が出来ればと思います
- また、開発チームの考えている事を知る為にも、アンケートの実施とその内容に基づいて勉強会の改善はしていければと考えています
- 将来的な所としては、この有志勉強会は社内コミュニティの一つの形だと捉えているので、私以外にも、他メンバーの何かしらの実現の場としても活用出来るようにしていければと考えています
【Supabase】Prisma Migration エラー発生時の対処方法

開発時にPrismaのマイグレーションを実行したところ、このようなエラーが発生しました。
~~~
Error: P1001: Can't reach database server at `aws-0-ap-northeast-1.pooler.supabase.com`:`5432'
~~~

## 原因
supabaseは無料プランの場合1週間以上未使用となった場合に一時停止となるようです。
メールで通知は来てましたが、スルーしていました、、、。

![スクリーンショット 2024-04-06 20.38.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116193/62953ad6-1437-f59f-3801-04189765f7fd.png)


## 解消方法
supabaseにログインを行い、復旧を行うことで解除できました。
CLIで実行環境を構築している方は少し手順が違うかもしれません。


* supabaseのホーム画面でRestore Projectをクリック

![スクリーンショット 2024-04-06 20.09.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116193/f2ec0aa4-0274-5001-3b09-6a7a0ba0dfe4.png)


* 復旧中

![スクリーンショット 2024-04-06 20.09.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116193/94e0f3f6-faf8-06d3-9e9d-cbacfa8740be.png)

* 復旧完了

![スクリーンショット 2024-04-06 20.22.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116193/39079e50-6e61-3a02-39f5-dd2a4bf90aaa.png)

開発初期でデータは入れていなかったため、1分かからず復旧は完了しました。

この状態で再度マイグレーションを実行すると、、、

~~~
he following migration(s) have been created and applied from new schema changes:

migrations/
  └─ *****/
    └─ migration.sql

Your database is now in sync with your schema.

✔ Generated Prisma Client (v5.11.0) to ./node_modules/@prisma/client in 569ms
~~~

無事マイグレーションできました！


## 参考
https://supabase.com/pricing

https://qiita.com/jnchito/items/f041b87ec2e23dab9613
AndroidデバイスをLinuxサーバーに変える (4) チャットサーバーをウィジェットから起動する

# はじめに

前回までにAndroidデバイスを使ってLinux環境を構築しチャットサーバーを動作させるところまで進めた。

https://qiita.com/rairaii/items/cc3771cdb3bff42d9da4

この記事ではTermuxで動作するチャットサーバーをAndroidのウィジェットから直接起動する方法について解説する。この方法を用いることで、デバイスの画面をタップするだけでサーバーを起動できるようになり、より迅速かつ便利にサービスを利用することが可能となる。

これでデモを実行するときにターミナルを開いてコマンドを入力するといった手間を省くことができる。

## Termux:Widgetのインストール

AndroidのウィジェットからTermuxのスクリプトを実行するために[F-Droidアプリ](https://f-droid.org/ja/)からTermuxのプラグインの１つである`Termux:Widget`をインストールする

## ウィジェットを使ったチャットサーバーの起動

Termuxを用いて、チャットサーバーを簡単に起動するためのシェルスクリプトを作成し、そのスクリプトをAndroidのウィジェットから実行する手順を紹介する。

### スクリプトの準備

シェルスクリプトをTerminalを開いて実行する場合には`~/.shortcuts`に保存される必要がある。Terminalを開く必要がない場合には`~/.shortcuts/tasks`に保存する。



```terminal
cd ~
mkdir .shortcuts
```

チャットサーバーを起動するスクリプトを作成する。

```terminal
vi .shortcuts/test_langchain.sh
```

```shell:.shortcuts/test_langchain.sh
#!/data/data/com.termux/files/usr/bin/bash
cd ~/work/test_langchain/
poetry run python app.py
```

このスクリプトは、`~/work/test_langchain/`ディレクトリに移動し、`poetry`を用いて`app.py`を実行する。この`app.py`は、チャットサーバーの実行ファイルである。

### スクリプトの実行権限設定

スクリプトを実行可能にするために、以下のコマンドを実行し、実行権限を付与する。

```terminal
chmod +x .shortcuts/test_langchain.sh
```

この操作により、スクリプトが実行可能な状態となる。

### ウィジェットの設定

ウィジェットを通じてスクリプトを実行するには、Termuxのウィジェット機能を活用する。Androidのホーム画面にTermuxウィジェットを追加し、作成したスクリプトをウィジェットに関連付ける。ウィジェットの設定が完了すると、そのウィジェットをタップするだけで、チャットサーバーが起動するようになる。

#### ホーム画面でスクリーンを長押しする
画面下部ににあるウィジェットボタンからウィジェット選択画面へ

![add_widget.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/8fa1bd32-155c-034f-8a7d-6e1f49b61e3b.png)

Termux:Widgetを選択する（Widgetを長押しする)

![select_widget.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/c63318ae-e3b5-1134-f115-0ea0c0736b8a.png)

ホーム画面にTermux:Widgetを配置する

![widget.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/f7b69c31-1b03-0178-8d93-e4c4e5271b67.png)

`test_langchain.sh`をタップして`app.py`を起動する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/a10bc3e6-5ac8-8d73-c3a9-d154881fe81a.png)


# まとめ

AndroidデバイスにTermuxをインストールし、Linux環境を構築することは、多くの開発者やテクノロジー愛好家にとって魅力的な選択肢である。さらに、Termuxのショートカット機能を用いてウィジェットからサーバーを起動する方法を利用すれば、開発やテストの効率が大幅に向上する。この記事で紹介した方法を活用することで、どこでも簡単にサーバーを起動し、作業を進めることができるようになるだろう。AndroidデバイスをLinuxサーバーに変えるこのシリーズを通じて、より多くの可能性を探求してみてはいかがだろうか。

# 参考サイト

https://github.com/termux/termux-widget?tab=readme-ov-file#script-icon-directory-optional
上から下、下から上、中から上下

物事には、いろいろなやり方があある。

上から下へ進む　Top　Down
下から上に進む　Bottom Up
中間から上下に進む　Up and Down

これらを、さまざまな分野、手法でどんな感じかを記録する。

１　経済学
２　安全分析

<この項は書きかけです。順次追記します。>
This article is not completed. I will add some words in order.


# Top Down
上から下へ

## 巨視経済学(Macro Economics)

# Bottom Up

## 微視経済学(micro Economics)

# Up and Down




＜この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。＞
This article is an individual impression based on the individual's experience. It has nothing to do with the organization or business to which I currently belong.


# 文書履歴(document history)
ver. 0.01 初稿 　20240306
### 最後までおよみいただきありがとうございました。
いいね　💚、フォローをお願いします。
#### Thank you very much for reading to the last sentence.
Please press the like icon 💚　and follow me for your happy life.
【AWS CLI】指定ユーザーの許可ポリシーの一覧取得スクリプト(bash)

# 目的
AWS CLIで指定ユーザーにアタッチされているポリシーの一覧を取得する。
※AWS CLIでは`aws iam get-user --user-name xxxxx`や`aws iam list-attached-group-policies --group-name yyyyy`でユーザー名やグループ名を指定して、許可ポリシーを確認することはできる。
しかし、一発でそのユーザーに許可されている全ポリシーを取得することはできない。（たぶん）

# スクリプト
## 1.ヒアドキュメントでスクリプトを作成
```bash:get_user_policies.sh
cat << 'EOT' > get_user_policies.sh

#!/bin/bash

# 使用方法
# ./get_user_policies.sh ユーザー名

# ユーザー名を取得
user_name=$(aws iam get-user --user-name $1 --query 'User.UserName' --output text)

if [ $? -ne 0 ]; then
  echo "ユーザー $1 は存在しません"
  exit 1
fi

# ユーザーに直接アタッチされているポリシーを取得
user_policies=$(aws iam list-attached-user-policies --user-name ${user_name} --query 'AttachedPolicies[].PolicyArn' --output text)

# ユーザーに直接アタッチされているインラインポリシーを取得
user_inline_policies=$(aws iam list-user-policies --user-name ${user_name} --query 'PolicyNames' --output text)

# 結果を出力
echo "## ユーザー ${user_name} に直接アタッチされているポリシー"
if [ -z "${user_policies}" ]; then
  echo "なし"
else
  for policy in ${user_policies}; do
    echo ${policy}
  done
fi

echo ""
echo "## ユーザー ${user_name} に直接アタッチされているインラインポリシー"
if [ -z "${user_inline_policies}" ]; then
  echo "なし"
else
  for policy in ${user_inline_policies}; do
    echo ${policy}
  done
fi

# ユーザーが所属しているグループを取得
groups=$(aws iam list-groups-for-user --user-name ${user_name} --query 'Groups[].GroupName' --output text)

echo ""
echo "## ユーザー ${user_name} が所属しているグループにアタッチされているポリシー"
# グループにアタッチされているポリシーを取得
for group in ${groups}; do
  group_policies=$(aws iam list-attached-group-policies --group-name ${group} --query 'AttachedPolicies[].PolicyArn' --output text)
  echo "### グループ ${group}"
  if [ -z "${group_policies}" ]; then
    echo "なし"
  else
    for policy in ${group_policies}; do
      echo ${policy}
    done
  fi
done

echo ""
echo "## ユーザー ${user_name} が所属しているグループにアタッチされているインラインポリシー"
# グループにアタッチされているポリシーを取得
for group in ${groups}; do
  group_policies=$(aws iam list-group-policies --group-name ${group} --query 'PolicyNames' --output text)
  echo "### グループ ${group}"
  if [ -z "${group_policies}" ]; then
    echo "なし"
  else
    for policy in ${group_policies}; do
      echo ${policy}
    done
  fi
done
EOT
```
## 2. 実行権限付与
```
chmod +x get_user_policies.sh
```
# 使用方法
```
get_user_policies.sh <ユーザー名>
```
# 実行例
```bash:
[cloudshell-user@ip-10-134-8-207 ~]$ ./get_user_policies.sh user20240406
## ユーザー user20240406 に直接アタッチされているポリシー
arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess
arn:aws:iam::aws:policy/IAMUserChangePassword

## ユーザー user20240406 に直接アタッチされているインラインポリシー
なし

## ユーザー user20240406 が所属しているグループにアタッチされているポリシー
### グループ greup-test02
arn:aws:iam::aws:policy/IAMReadOnlyAccess
### グループ group-test01
arn:aws:iam::aws:policy/AWSCloudFormationReadOnlyAccess
arn:aws:iam::aws:policy/AWSCloudShellFullAccess

## ユーザー user20240406 が所属しているグループにアタッチされているインラインポリシー
### グループ greup-test02
なし
### グループ group-test01
S3_ListAllMyBuckets
S3_ListBucket
```
下記、マネージメントコンソールと同等の出力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3297641/2547d32d-2bc3-b6ec-3f00-9f08b850beb2.png)

※ポリシーは検証のために適当にアタッチしてある
RAG (Retrieval-Augmented Generation)とは？

RAGとは、一言で言うと、ChatBotなどの言語モデルに外部情報（知識データベース）の参照機能を追加することで回答の信頼性を高める技術のことです。2020年のMeta社の[論文](https://arxiv.org/abs/2005.11401v4 "Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks")で提唱された概念です。

LinkedInにすごくよくまとまっている[RAGの紹介](https://www.linkedin.com/posts/abhinav-kimothi_retrieval-augmented-generation-a-simple-activity-7182248160734453762-FwqZ?utm_source=share&utm_medium=member_desktop)がありました。

## 検索と生成の２つのフェーズ
名前にある通り情報検索（Retrieval）と情報生成（Generation）の2つのフェーズがあります。最初の検索フェーズでは、質問テキストと外部文書（知識データベース）の相関性により上位k位の文書を取り出します。その後、その上位の文書と質問テキストをつなげて、言語モデルを使って回答文を生成します。

## オープンブック方式とは？
オープンブック方式とは大学などで行われる辞書や教科書の持ち込み可の試験のことです。外部の情報を取り入れることで学生は暗記する労力を少なくすることができます。RAGはこのオープンブック方式をとっています。

## RAGは回答の信頼性を高める
RAGでは、外部の知識データベースから最新の情報を取得するので、回答の信頼性を高めることができます。更に、元の言語モデルを頻繁に更新する必要性が減るので、更新コストが削減できます。

RAGのシステムを利用することで、ChatBotなどの言語モデルは、低コストで回答の信頼性を高めることできるのです。
AndroidデバイスをLinuxサーバーに変える (3) chatgptを使ったチャットサーバーを動作させる

# はじめに

前回はAndroidでLinux環境を実現するTermux上でflaskを用いてWebサーバーを動作させた。

https://qiita.com/rairaii/items/183bab10869ab52c0531


この記事では、langchainライブラリを使ったchatgptとのチャットサーバーを構築し動作させる。

# Termuxでチャットサーバを構築する

シンプルなチャットサーバ[githubに用意しておいた](https://github.com/aRaikoFunakami/test_langchain/tree/main)。
## Gitのインストール

チャットサーバのソースコードをgithubからダウンロードするために`git`コマンドをインストールする

```terminal
$ pkg install git
```

このコマンドにより、GitがAndroidデバイス上のTermux環境にインストールされる。

## 作業フォルダの作成

プロジェクト管理のための作業フォルダを作成し、そこに移動する。

```terminal
$ mkdir work
$ cd work
```

## プロジェクトのクローン

サンプルプロジェクト`test_langchain`をGitHubからクローンする。このプロジェクトには、OpenAIのAPIを利用したサンプルアプリケーションが含まれている。

```terminal
$ git clone https://github.com/aRaikoFunakami/test_langchain.git
$ cd test_langchain/
```

## ライブラリのインストール

プロジェクトに必要なライブラリのインストールは、`poetry`を使用して行われる。Rustでのコンパイルが必要なためAndroidのSoCの種類にもよるがインストールには結構な時間が掛かる。気長に待つ。

```terminal
$ pkg install -y rust
$ pkg install -y binutils
$ poetry install
```


## 設定ファイルの作成

OpenAI APIを利用するためには、自分のAPIキーを`config.py`に設定する。

```terminal
cp config_sample.py config.py
vi config.py
```

`config.py`には以下のように記述する。

```python
keys = {
    "openai_api_key": "<YOUR OPENAI ID>",
    "model_name": "gpt-3.5-turbo",
}
```

`<YOUR OPENAI ID>`の部分に[OpenAIのAPIキー](https://platform.openai.com/api-keys)を設定する。

## チャットサーバの実行

設定が完了したら、チャットサーバ`app.py`を実行する。

```terminal
$ poetry run python app.py
```

実行後、AndroidのChromeブラウザから http://localhost:8080/?text=mt.fuji でチャットサーバーにアクセスするとChatGPTからの回答を確認できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/3c38b48e-f784-9dcd-185d-9d8db24790b8.png)


# まとめ
Androidデバイス上で完結する開発環境の構築が可能となった。
これでクライアントアプリとWebサーバーを組み合わせたサービスのデモ環境をAndroid単体で準備することができそうだ。
Railsを使ってアプリを作る(基礎中の基礎)

# はじめに
今回は、railsをつかってアプリをつくり、デプロイまでの基本的な流れをまとめました。
基礎中の基礎という通り、画面にHello,worldを表示するだけのアプリになります。
エディタはVSCodeを用いて、バージョン管理をGitで行い、Renderへデプロイします。
使用ハードはmacbook m2です。
Rubyはデフォルトで入ってるので、Railsのインストールから始めます。

# Railsをインストール
```
$ gem install rails
```

-vを行うことでバージョンの指定もできます。

```
$ gem install rails -v 7.0.4.3
```

次にbundlerをインストールします。

```
$ gem install bundler
```

# アプリを作る

Railsプロジェクト用のenvironmentディレクトリを作ります。

```
$ cd         
$ mkdir environment
$ cd environment/
```

rails newを実行する。
このとき、PCにインストールされているバージョンを指定することで、同じバージョンのrailsで作成できます。

```
$ rails _7.0.4.3_ new hello_app
```

# Bundler
railsアプリを新規作成したあとは、bundlerを実行し、アプリに必要なGemをインストールします。

gemfileに使用するgemを追加したり、バージョン指定するなど変更を行ったあとは、bundle installを忘れずに。

```
$ bundle install
$ bundle lock --add-platform x86_64-linux
```
２行目は、追加されることで、bundle installする際に、Linux用(x86_64-linux)のnokogiri gemが入るようになる。これをしないとデプロイした際、エラーになることがあるみたい・・・。

# rails serverを立ち上げる
```
$ rails server
```

上記コマンドを実行することでローカルサーバーが立ち上がる。
Chromeでlocalhost:3000を検索。

# Hello,worldを表示してみよう

app/controllers/application_controller.rbに以下を追記。

```
class ApplicationController < ActionController::Base

  def hello
    render html: "hello, world!"
  end
end
```

routesのrootを更新。

```
Rails.application.routes.draw do
  root "application#hello"
end
```
これで画面にhello,worldの文字が出てくる。

# Githubでソースコードを管理

いろいろな変更を行った際は、こまめにgithubにpushしよう。
まずはgithub公式にいき、レポジトリを新たに作成。

作成後、エディタへ戻り、
```
$ git init
$ git add -A
$ git commit -m "first commit"
```
上記のコマンドで、ローカルレポジトリを作成するのと、いわゆるセーブをします。

あとはいまの開発環境と、Githubで先程作成したレポジトリを連携させます。

```
$ git remote add origin https://github.com/ユーザーID/アプリケーション名.git
```

これで連携完了。
あとはリモートでcommitした内容をgithubにpushする。

```
$ git push origin main
```

# デプロイする

ここまで来たら、本番環境にデプロイする作業。
今回はRenderを使用してデプロイします。

まずはmaster.keyとcredentialを作成する。

```
# master.keyがすでにあるかどうか確認する
$ ls config/master.key

#　既存のcredentialsを削除する
$ rm config/credentials.yml.enc

# 新しいcredentialsとmaster.keyを作成
$ rails credentials:edit
```

新たに出来上がったmaster.keyの中身をコピーします。

Renderに移動し、新たにWeb　serviceを作成し、githubで作ったアプリと同期します。
最後に環境変数のRAILS_MASTER_KEYに先ほどコピーしたものを貼り付け、create web serviceします。

エラーが出なければ完成！
目的と具体例で理解する「クライアントセキュリティ」【試験対策】

## はじめに

◆この記事は何？
クライアントセキュリティについて概要を説明する記事

◆対象は？
試験対策したい人

◆この記事のねらい
目的と具体例によって、理解のハードルを下げるのが狙いです。

## パーソナルファイアウォール

パーソナルファイアウォールは、クライアントにインストールして利用するソフトウェア型のファイアウォールです。

◆目的
内部で発生した攻撃を防御する

◆できること
- プロセス単位で通信を監視して攻撃を防ぐ
- ステートフルインスペクション
    - 通信の前後関係を含めて整合性を確認する

◆問題点
- ユーザーがオフにする可能性がある
- セキュリティソフトなどと併用するとうまく動作しないことがある
    - お互いが干渉して正常な監視ができない、CPU負荷が高くなるなど

◆具体例
次の記事では、WindowsおよびMacでパーソナルファイアウォールを設定する手順が紹介されています。

https://cybersecurity-jp.com/column/35443

## サンドボックス

サンドボックスは安全な領域で不審なプログラムを動作させることができる機能です。
サンドボックスは「砂場」を意味します。

◆目的
未知のソフトウェアや信頼できないコードがシステムに悪影響を及ぼすリスクを減らすため。

◆具体例
[Windows サンドボックス](https://learn.microsoft.com/ja-jp/windows/security/application-security/application-isolation/windows-sandbox/windows-sandbox-overview)が参考になります。

## コードサイニング

コードサイニングとは、プログラムのハッシュ値にデジタル署名をつけることです。

◆目的
プログラムの改変有無や作成者のなりすましを確認するため

◆具体例
次の記事では、コードサイニングを付与する流れがわかりやすくまとまっています。

https://qiita.com/Chitama/items/915abc7b872b1e086800

## BIOSパスワード

BIOSパスワードによって、第三者はシステムを起動できなくなります。

BIOS:Basic Input/Output System

◆目的
不正アクセスの防止

◆具体例
富士通社のFAQに、BIOSのパスワードについての説明があります。

https://www.fmworld.net/cs/azbyclub/qanavi/jsp/qacontents.jsp?PID=0306-2313

## HDD/SSD暗号化

HDDやSSDの情報流出を防ぐために、HDD/SSD暗号化を行います。

◆目的
データ保護のため
権限のない者がデータにアクセスしたとしても、内容を解読することが非常に難しくなります。

◆具体例
[BitLocker](https://learn.microsoft.com/ja-jp/windows/security/operating-system-security/data-protection/bitlocker/)

## TPM(Trusted Platform Module)

TPMは、鍵ペアの作成、ハッシュ値の計算、デジタル署名の生成検証を行うセキュリティチップです。

◆目的
鍵ペアの作成や暗号鍵を安全に保管するため

◆できること
公開鍵暗号方式の鍵ペアの作成、ハッシュ値の計算、デジタル署名の生成検証を行う。

対タンパ性がある
内部のデータや動作などを外部から解析や改変されることに対する耐性

◆具体例
私は[Google画像検索](https://www.google.com/search?q=Trusted+Platform+Module&sca_esv=64568e91d4c772e8&udm=2&biw=1629&bih=910&sxsrf=ACQVn08g3JzVjjXtsGqKQ42jpIvRRqUTrQ%3A1712394618106&ei=ehERZsqSBoTBvr0P6aelqA8&ved=0ahUKEwjKt7WHn62FAxWEoK8BHelTCfUQ4dUDCBA&uact=5&oq=Trusted+Platform+Module&gs_lp=Egxnd3Mtd2l6LXNlcnAiF1RydXN0ZWQgUGxhdGZvcm0gTW9kdWxlMgUQABiABDIEEAAYHjIEEAAYHjIEEAAYHjIEEAAYHjIEEAAYHjIEEAAYHjIEEAAYHjIEEAAYHjIEEAAYHki8AVAAWABwAHgAkAEAmAGuAaABrgGqAQMwLjG4AQPIAQD4AQL4AQGYAgGgArgBmAMAkgcDMC4xoAfvAw&sclient=gws-wiz-serp)して、ハードウェアを見ることでイメージが湧きました。

## BYOD(Bring Your Own Device)

BYODとは、授業員の個人所有の端末を業務に利用することです。

◆メリット
- 設備投資を削減できること
- 使い慣れた機器で業務できる
- 特定の脆弱性の影響範囲が小さくなる

◆問題点
- 一元管理が難しい
- 脆弱性の一括対応が難しい
- プライベートと業務のデータが混在する

◆具体例
私はNTTデータ社の事例で理解が容易になりました。

https://www.nttdata.com/global/ja/news/release/2013/041500/

## おわりに
この記事では、クライアントセキュリティについて概要を説明しました。

試験対策の一助になれば幸いです。

## 参考

[「ゼロからスタート! 教育系YouTuberまさるの情報処理安全確保支援士1冊目の教科書」](https://amzn.asia/d/dSYLc7n)
リクエスト間でクラスインスタンスが共有されてしまう

# 困ったこと

fastAPI でリクエストでは異なるデータを受け取っているのに、内部で作成されるインスタンスはずっと同じインスタンスが参照されていた

# 原因

Python においてクラスのデフォルト引数が None 以外の場合、初期化されるタイミングは、クラスインスタンスが作成される 1 度のみであるため

そのため、リクエスト間でインスタンスが共有されていたのです

これは fastAPI の仕様ではなく、Python 言語の仕様です

## 例

```python
class ApplicationAggregate:
    def __init__(self, id: str, secret_key: str = "") -> None:
        self.__id = ApplicationId(id) # ULIDを生成
        self.__secret_key = secret_key

    def get_id_of_private_value(self) -> str:
        return self.__id.get_id_of_private_value()

    def get_secret_key_of_private_value(self) -> str:
        return self.__secret_key

app = ApplicationAggregate()
```

以上のようなクラスを fastAPI 上のリクエスト間で生成する場合、サーバを再実行するまでインスタンスである app は同じ ULID を保持することになります

# 対処法

デフォルト引数を None にしてインスタンス定義のたびに初期化を行うようにする

```python
class ApplicationAggregate:
    def __init__(self, id: str, secret_key: Optional[str] = None) -> None:
        self.__id = ApplicationId(id) # ULIDを生成
        self.__secret_key = secret_key if secret_key is not None else ""

    def get_id_of_private_value(self) -> str:
        return self.__id.get_id_of_private_value()

    def get_secret_key_of_private_value(self) -> str:
        return self.__secret_key

app = ApplicationAggregate()
```

こうすることにより、インスタンスが定義されるたびに初期化され、リクエスト間でインスタンスが共有されることはなくなります
今更だけどCSSのclip-pathが便利すぎる

# はじめに
とても便利なCSSのプロパティ、`clip-path`のお話です。
これを知っているかどうかでCSSで図形を描く時の手間が**非常に**変わるやつです。
別に最近追加された訳ではないので、既に知っているよ！という方も多いとは思いますが、もし知らない人が居たら是非知ってほしいと思います。

# clip-pathで何ができるのか？
公式の説明を借りると、「要素のどの部分を表示するかを設定するクリッピング領域を作る」となります。
要は要素における描画領域を設定することが出来るので、これを使用することで様々な図形に切り取って表示できます。
具体的には、下記のような図形が描画できます。
- 三角形等の多角形
- 矢印
- 円や半円、楕円
などを簡単に描画することができます。

`clip-path`を使わない方法だと、三角形なら`border`を使ってーleftはtransparentでーって書いたり、円だったら`border-radius`使ってーといろんなプロパティを使わなければいけない感じでした。
さらに複雑な図形になると複数の要素や疑似要素を設定して組み合わせるなど、正直いってかなり煩雑になっていきます。
でも`clip-path`なら一つの要素だけで完結させることができちゃいます。これを知った日には三角形を`border`で書くなんてありえないですね。
~~未だに最近の記事でborder使う方法を紹介している某プログラミングスクールのサイトもありますが~~

# 実際の使用例
普通の三角形ならこんな感じです。
```scss
.shape {
  clip-path: polygon(0 100%, 50% 0, 100% 100%);
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690817/d24ce3b8-dbe1-3eb2-78de-b6a961919046.png)
矢印ならこんな感じ。
```scss
.shape {
  clip-path: polygon(40% 0%, 40% 20%, 100% 20%, 100% 80%, 40% 80%, 40% 100%, 0% 50%);
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690817/c18dc2ef-c177-9eb9-d49e-9b12ddf70a22.png)

`plygon()`が非常に便利で、切り取りの角の位置を自由に複数指定することができます。
これを応用すれば三角形や矢印の向きや大きさ、角度などは自由自在にすることができます。

**また、この`polygon()`で設定する数は無制限です。**
つまりこういうことです。
```scss
.shape {
  clip-path: polygon(7% 0%, 99% 47%, 70% 84%, 78% 90%, 60% 91%, 58% 77%, 63% 80%, 84% 51%, 0% 5%);
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690817/50259225-81ff-c8ca-4d50-7b266d8179ad.png)
```scss
.shape {
  clip-path: polygon(0% 0%, 0% 100%, 15% 100%, 15% 15%, 85% 15%, 85% 45%, 45% 45%, 45% 15%, 55% 15%, 55% 45%, 15% 45%, 15% 55%, 85% 55%, 85% 100%, 100% 100%, 100% 0);
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690817/de739927-20d3-b38c-d6d5-4e73c0443dcc.png)

制約が全くないわけではありませんが、かなりやりたい放題できますね。
また、円を含む図形を描く場合は`polygon()`以外を使って描画できます。

```scss
.shape {
  clip-path: circle(50% at 50% 50%);
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690817/ef360cdb-979b-ee36-7d48-7e05fa1d51b9.png)

```scss
.shape {
  clip-path: ellipse(47% 24% at 50% 50%);
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690817/f452692f-07c5-3864-d8f1-90f68ceeba30.png)

角が一部だけ丸い長方形とかもできます。
```scss
.shape {
  clip-path: xywh(100px 30px 100% 100% round 100px);
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690817/5a0e2eb9-38cb-ef4f-24bf-6467bed57fe4.png)

これでも紹介したのはほんの極一部で、様々な図形を描くことが可能です。
何よりも**一つの要素のみ**でここまで描画出来るのがありがたいですね。要素を複数組み合わせようとすると位置関係の問題で色々とありますし…
当然、`clip-path`を設定した要素を複数組み合わせてさらに複雑なものを書くことも可能です。
一度覚えるともう以前の書き方には戻れません。

ということで知らなかった皆さんは今後是非使っていきましょう！

# 参考リンク
- [clip-path - CSS: カスケーディングスタイルシート | MDN](https://developer.mozilla.org/ja/docs/Web/CSS/clip-path)
- [Clippy — CSS clip-path maker](https://bennettfeely.com/clippy/)
↑ `clip-path`を簡単に試せるサイトです。便利なのでぜひ。
Java Silver向け 例題 型推論 var

次のコード 1 ~ 5 でコンパイルエラーとなる場所をすべて答えてください


<br>

```java
public class Example5 {
   	
1)    var number = 1;
    
2)    public method(var number) {
3)        var name;
4)        var final weight = 65;
5)        var age = 20;
    }
}
   ```
<br>
<br>
<br>


正解

↓

↓

↓

↓

↓

↓

↓

↓

↓

↓

[1, 2, 3, 4]


　　
1，2，3
クラスのフィールド、メソッドの引数では使用できません。
メソッド内でのローカル変数の宣言には、具体的な型が必要です。

4
final修飾子の位置が間違っている
正) final var age = 10;

<br>
<br>
<br>


拡張for文で様々な型が混在しているリストにおけるvarの使用例
```java
        (略)
        
        ArrayList<Object> myList = new ArrayList<>();
		
		myList.add("A");
		myList.add("BCDEF");
		myList.add('c');
		myList.add(10);
        myList.add(0b1010);
		myList.add(0xF9);
		myList.add(0_10);
		myList.add(0.0009);
		myList.add(1000000000000000000L);
		myList.add(true);

        //コンパイルも実行も可能
		for (var item : myList) { 
		    System.out.println(item);
		}

        /*下記はコンパイルエラー
		for (String item : myList) { 
		    System.out.println(item);
		}
        */
  ```

出力結果
  ```java
A
BCDEF
c
10
10
249
8
9.0E-4
1000000000000000000
true
```
AndroidデバイスをLinuxサーバーに変える (2) flaskでWebサーバーを動作させる

# はじめに

前回はAndroid上でLinux環境を提供するTermuxのインストールとsshでのリモートアクセスまでを確認した。

https://qiita.com/rairaii/items/c45d19179cda01054a0e

今回はAndroid上でLinux環境を提供するTermuxを用いて、PythonとFlaskをインストールし、簡単なWebアプリケーションを作成・実行するプロセスを解説する。Termuxを介して、Androidデバイスを使って、開発環境を構築し、ローカルでWebサーバーを動作させる方法を紹介する。この記事では、Pythonのインストールから、Flaskを使ったWebアプリケーションの開発、実行までをカバーする。

## Pythonのインストール

まず、TermuxでPythonをインストールする。以下のコマンドを実行し、Pythonをセットアップする。

```terminal
$ pkg install -y python
$ python -V
Python 3.11.8
```

インストール後、Pythonのバージョンを確認して、正しくインストールされたことを確かめる。

## Poetryのインストール

次に、Pythonのパッケージ管理ツールであるPoetryをインストールする。Poetryは依存関係の管理とパッケージの配布を簡単にするツールだ。Poetryのインストール前に、`python-cryptography`パッケージをインストールし、その後Poetryをセットアップする。

```terminal
$ pkg install python-cryptography
$ pip install poetry
```

## Flaskのセットアップ

Poetryを使ってFlaskをプロジェクトに追加する。FlaskはPythonで書かれた軽量なWebアプリケーションフレームワークである。

```terminal
$ poetry init
$ poetry add flask
```

これで、Flaskがプロジェクトに追加される。

## サンプルWebアプリケーションの作成

以下のFlaskアプリケーションを`app.py`という名前で作成する。このコードは、ルートURLにアクセスした際に「Hello, World!」と表示する単純なWebサーバーを定義する。

```python: app.py
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
   return 'Hello, World!'

if __name__ == '__main__':
    app.debug = True
    app.run(host='0.0.0.0', port=8080)
```

## Webアプリケーションの実行

Poetryを用いて`app.py`を実行し、Flask Webサーバーを起動する。

```terminal
$ poetry run python app.py
 * Serving Flask app 'app'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:8080
 * Running on http://192.168.1.81:8080
```

実行後、同一のネットワーク内の任意のデバイスからブラウザを用いて`http://192.168.1.81:8080`にアクセスし、「Hello, World!」のメッセージを表示させる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/a799424c-44c1-8d21-57ff-39ada7c873c0.png)

また、Termuxを動作させているAndroidデバイス自身でChromeブラウザから`http://localhost:8080`にアクセスすると、同じく「Hello, World!」が表示される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/0c7ea56b-1b7f-af7a-ef9f-29c8436f5bd5.png)


## 参考サイト

この記事作成に参考にさせて頂いたサイト

https://bosq-log.hatenablog.com/entry/2019/09/03/171045

https://zenn.dev/mtkn1/scraps/020d25406c877c
AndroidデバイスをLinuxサーバーに変える (1) Termuxとsshで作業を開始

# はじめに

Androidで動作するクライアントアプリとWebサーバーとの組み合わせで動作するサービスを構築したときに、WebサーバーをAWSなどで公開してデモ環境を構築するのは一手間かかる。また、そのデモ用のWebサーバーのセキュリティーやメンテナンスなどもあまり考えたくない。

デモのための環境は手元でサクッと構築できるのが一番である。そのデモ環境を人に渡す場合もAndroid機器を渡すだけで終了するのであればシンプルに終了する。このよう要求を満たすデモ環境を用意するために、Androidで動作するLinux環境を用意し、そこにデモ用のWebサーバーを構築することにした。

Androidデバイスを手軽にLinux環境に変える方法として、Termuxのインストールと設定、さらにはMacや他のPCからのSSH接続設定までのプロセスを解説する。この記事では、Androidデバイス上でTermuxを使ってLinux環境を構築し、OpenSSHをインストールして外部からのSSH接続を可能にするまでの手順を紹介する。

## AndroidにTermuxをインストールし、Linux環境を構築する

まず、AndroidデバイスにTermuxアプリをインストールする。Google PlayストアまたはF-DroidからダウンロードできるがGoogle PlayストアのTermuxの更新はストップしているため最新のTermuxをインストールするためにはF-Droidからインストールするのが良いだろう。

https://f-droid.org/ja/

1. F-Drodアプリをインストールする
1. F-Droidアプリから Termux をインストールする

Termuxのインストールが完了したら、Androidのアプリ一覧でTermuxを選択してアプリを開き、以下の初期設定コマンドを実行する。

```terminal
$ pkg up
$ termux-setup-storage
```

これらのコマンドは、Termuxのパッケージを最新状態に更新し、ストレージへのアクセス権を設定するものである。

## SSHサーバーの設定と接続

### ユーザーIDの確認

Termuxで作業を進めるにあたり、まず現在のユーザーIDを確認する。

```terminal
$　id
uid=10177(u0_a177) gid=10177(u0_a177) groups=10177(u0_a177),3003(inet),9997(everybody),20177(u0_a177_cache),50177(all_a177)
```

このコマンドは、Termuxが割り当てたユーザーID(`u0_a177`)を表示する。このIDは後ほどSSH接続時に使用する。

### パスワードの設定

次に、SSH接続に必要なパスワードを設定する。

```
passwd
```

この手順により、SSH接続時の認証情報を確立する。

### ネットワークアドレスの確認

SSH接続を行うには、ネットワーク上のデバイスアドレスを知る必要がある。

```terminal
$ ifconfig
dummy0: flags=195<UP,BROADCAST,RUNNING,NOARP>  mtu 1500
        inet6 fe80::3ceb:aeff:fe44:3956  prefixlen 64  scopeid 0x20<link>
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 1000  ...
...
wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.81  netmask 255.255.255.0  broadcast 192.168.1.255
...
```

このコマンドは、デバイスのIPアドレスを含むネットワーク情報を表示する。ここで表示されるIPアドレス(`192.168.1.81`)をメモしておく。

### OpenSSHのインストール

TermuxにOpenSSHをインストールすることで、SSHサーバー機能を追加する。

```terminal
$ pkg install openssh
```

この操作により、SSHサーバーの設定と鍵の生成が自動で行われる。

### sshdの起動

インストール後、SSHサーバーデーモンを起動する。

```terminal
$ sshd
```

このコマンドは、TermuxがSSH接続を受け入れるようになる。

### ホストからのSSH接続

Macや他のPCからTermuxのSSHサーバーに接続するには、以下のコマンドを使用する。

```terminal
$ ssh -p 8022 ユーザーID@デバイスのIPアドレス
```

今回の場合なら

```terminal
$ ssh -p 8022 u0_a177@192.168.1.81
```

ユーザーIDとデバイスのIPアドレスは、前の手順で確認したものを使用する。

### sshdの自動起動設定

Termuxを起動するたびに自動でsshdを起動させるため、`.bashrc`に起動コマンドを追記する。

```
pkg install vim
vi ~/.bashrc
```

ファイルの末尾に`sshd`と追記し、保存する。

### スリープモード時の接続
Androidがスリープモードに入った場合はSSH接続が切れてしまう。SSH接続を維持するためには、以下のコマンドを実行する。

```terminal
$ termux-wake-lock
```

この設定を解除したい場合は、下記のコマンドを実行する。
```terminal
$ termux-wake-unlock
```


## 参考情報

この記事で紹介した内容に関するさらなる情報は、以下のリンクから参照できる。

- [Termuxの初期設定](https://rfriends.hatenablog.com/entry/2022/02/14/071248#%EF%BC%91Termux%E3%81%AE%E5%88%9D%E6%9C%9F%E8%A8%AD%E5%AE%9A)
- [SSH接続の設定](https://qiita.com/dev100kg/items/11fdaac265c35e777664)
- [Termuxパッケージの問題解決](https://github.com/termux/termux-packages/issues/15155)

Androidデバイスを用いてLinux環境を構築し、外部からのSSH接続を可能にするこのプロセスを通じて、リモート作業の幅が大きく広がるだろう。
Git 登録　Github連携 ubuntu 用　

git登録とgithub連携を行う手順

参考にした記事:
Ubuntu git ~ github連携まで

# ユーザー設定:
これはローカルのgitを登録するための設定です。
```
$ git config --global user.name [名前]
$ git config --global user.email [メールアドレス]
```
# Github連携:
既存のGithubのアカウントと連携します。

## ssh-keyの作成:
Githubを連携させるには公開鍵が必要ですので、以下のコマンドで作成します。

```
ssh-keygen -t rsa -C "メールアドレス"
```
このコマンドを実行すると、~/.ssh/id_rsa というファイルが作成されます。

## Githubに公開鍵を設定:
作成した公開鍵をGithubに登録します。

まず、公開鍵をクリップボードにコピーします。xclip はUbuntuで使用するコマンドです。
```
$ cat ~/.ssh/id_rsa.pub | xclip -selection clipboard
```
次に、Githubのページに移動してアカウント設定の"SSH and GPG keys"を選択します。右上の"New SSH key"をクリックし、以下の情報を入力します。

Title: 自分が分かる名前
Key: クリップボードから公開鍵をペースト
"Add SSH key"をクリックして登録完了です。
## 接続確認:
Ubuntuに戻り、以下のコマンドを入力してGithubとの接続を確認します。
```
$ ssh -T git@github.com
```
接続確認時に yes と聞かれたら yes と入力してください。
## 連携確認:
最後に、Github上のリポジトリをクローンしてきたローカルのリポジトリに変更を加えて、以下のコマンドでGithubに反映させます。
```
git add -A
git commit -m "コミットメッセージ"
git push -u origin master
```
これで正しくpushできていたら完了です。

# Git チートシート
Gitの基本コマンドです。

リポジトリの作成
```
git init
```
ファイルのステージング
```
git add ファイル名
```
ステージングされたファイルのコミット
```
git commit -m "コミットメッセージ"
```
リモートリポジトリの追加
```
git remote add origin リモートリポジトリのURL
```
ローカルの変更をリモートリポジトリにプッシュ
```
git push -u origin master
```
リモートリポジトリの変更をローカルにプル
```
git pull origin master
```
ローカルの変更をリモートリポジトリからフェッチ
```
git fetch origin master
```
ローカルの変更を取り消す
```
git checkout -- ファイル名
```
ブランチの作成と切り替え
```
git checkout -b 新しいブランチ名
```
ブランチの削除
```
git branch -d ブランチ名
```
ログの表示
```
git log
```
ファイルの変更をステージから取り消す
```
git reset HEAD ファイル名
```
直前のコミットを修正
```
git commit --amend
```

使いながらもっと覚えていきます。
【JavaScript】オブジェクトの値を変更不可にする方法

## はじめに

JavaScriptでオブジェクトを`const`で宣言したとしてもオブジェクトのプロパティは変更できてしまいます。

```js
const person = {
  name: 'John',
  age: 30
}

person.age = 31 // ageを31に変更
console.log(person.age) // 31 変更されてしまう

```

## オブジェクトの値を変更できなくする方法

`Object.freeze()`を使用するとオブジェクトの値を変更できなくできます。

```js
const person = {
  name: 'John',
  age: 30
}

Object.freeze(person);

person.age = 31 // ageを31に変更
console.log(person.age) // 30 変更されていない

```

:::note warn
`Object.freeze()`は、オブジェクトのトップレベルのプロパティのみを凍結します。つまり、ネストされたオブジェクトのプロパティは凍結されません。
:::

```js
const person = {
  name: 'John',
  age: 30,
  address: {
    city: 'New York',
    country: 'USA'
  }
}

Object.freeze(person)

person.age = 31 // ageを31に変更
console.log(person.age) // 30 変更されていない

person.address.city = 'Los Angeles' // cityを'Los Angeles'に変更
console.log(person.address.city) // 'Los Angeles'　変更されている
```

## 参考

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
【C#】サーバー側でAndroidのレシートを署名検証する

C#（.NET）での実装が調べてもあまり出てこないので残しておきます。

:::note warn
コピペで使う場合でも必ずドキュメントを読んだ上で使用してください。
課金に関わることなので重大な問題が発生する可能性もあります。
発生する問題については一切の責任を負いかねます。
:::

## はじめに
Androidのレシート検証は2つあります。

1. 自分のアプリのレシートか検証(ローカルでの署名検証)
1. Googleのサーバーにレシート情報があるかを検証（APIでの検証）

どちらも行うことが推奨されています。（どちらかしかやってない人が多いのではないでしょうか）
今回は1. 自分のアプリのレシートか検証の部分を書きます。

## 環境
.NET8

## 用意するもの
サーバー側で実装しているとレシートの現物が手に入らない、そもそも何を使用するのかというところで最初躓く可能性があるのでまとめておきます。

サーバー側 : 公開鍵
クライアント側 : 発行されたレシートと署名

## コード
```csharp
    public bool Verify(string receiptJson, string publicKey, string signature)
    {
        // 署名
        var sha1Managed = SHA1.Create();
        var hash = sha1Managed.ComputeHash(RemoveNewLinesAndSpaces(receiptJson));

        var rsa = new RSACryptoServiceProvider();
        rsa.ImportSubjectPublicKeyInfo(ConvertPublicKey(publicKey), out _);

        // 署名を検証する
        return rsa.VerifyHash(hash,
            Convert.FromBase64String(signature),
            HashAlgorithmName.SHA1,
            RSASignaturePadding.Pkcs1);
    }

    private static byte[] RemoveNewLinesAndSpaces(string receiptJson)
    {
        return Encoding.UTF8.GetBytes(receiptJson
            .Replace("\n", "")
            .Replace("\r", "")
            .Replace(" ", ""));
    }

    private static byte[] ConvertPublicKey(string publicKey)
    {
        var cleanedKey = publicKey
            .Replace("-----BEGIN PUBLIC KEY-----", "")
            .Replace("-----END PUBLIC KEY-----", "")
            .Replace("\n", "")
            .Replace("\r", "");
    
        return Convert.FromBase64String(cleanedKey);
    }
```

## 解説
クライアントから送られてくるレシート（json）の**改行コードとスペース**を取り除いて、SHA1でハッシュ化します。

```csharp
var sha1Managed = SHA1.Create();
var hash = sha1Managed.ComputeHash(RemoveNewLinesAndSpaces(receiptJson));
```

公開鍵をRSACryptoServiceProvider()のImportSubjectPublicKeyInfo()を使用して読み込ませます。

```csharp
var rsa = new RSACryptoServiceProvider();
rsa.ImportSubjectPublicKeyInfo(ConvertPublicKey(publicKey), out _);
```

この際、公開鍵の接頭語と接尾語、及び改行コードは取り除かれている必要があります。
ですので、以下のように余分な部分をバリデーションしてあげないといけません。

```csharp
    private static byte[] ConvertPublicKey(string publicKey)
    {
        var cleanedKey = publicKey
            .Replace("-----BEGIN PUBLIC KEY-----", "")
            .Replace("-----END PUBLIC KEY-----", "")
            .Replace("\n", "")
            .Replace("\r", "");
    
        return Convert.FromBase64String(cleanedKey);
    }
```

さらにC#のデフォルトのbase64エンコードは4の倍数文字数ではないとエンコードしてくれないので、もっとかっちり作るなら以下の記事のような処理も必要です。

https://qiita.com/chanchanko/items/d2a23e8a569eea98d04f#%E5%8E%9F%E5%9B%A0

最後にVerifyHash()で署名検証してあげて終わりです。
第1引数から
1. SHA1でハッシュ化したレシート
1. クライアントから送られてきた署名をbase64エンコードしたバイト配列
1. 検証に使用するアルゴリズム（AndroidではSHA1）
1. 検証で使用するパディングモード（AndroidではPkcs1）
署名検証が成功すればtrueが返ります。

```csharp
return rsa.VerifyHash(hash,
    Convert.FromBase64String(signature),
    HashAlgorithmName.SHA1,
    RSASignaturePadding.Pkcs1);
```

## 感想
他言語では上述のような色々細かいことしなくてもできている印象。
C#だけドキュメントもなければ、使い方も難しい。
私はレシートのjsonのスペースを取り除き忘れていて1日無駄にしました。