OmniAICreator/Qiita-1.07M huggingface dataset:
個人的な備忘録：FizzBuzz で学ぶ Python の条件分岐とループの使い方をアウトプットしてみた

## はじめに
FizzBuzz は、プログラミング初心者が条件分岐やループ処理を学ぶのに最適な問題の一つです。

:::note note
**本記事では、Python を使って FizzBuzz を実装し、そのコードの流れや仕組みを詳しく解説します。**
:::

実際に動作させる手順も紹介するので、Python に触れたばかりの方でも理解しやすい内容になっています。

## 書こうと思ったきっかけ

Python といったプログラミングの学習を始めるまで、条件分岐やループを使いこなすには、シンプルながらも簡単なプログラムを作ってみるのがお勧めです。

:::note warn
***今回は、その中で代表的な FizzBuzz について、Python を使って実装し、処理の流れなどを整理していきます。***
:::

この内容については、自分自身の振り返りの意味を込めて、走り書きのメモ程度となりますが、ご容赦ください。

## 完成したコード

1から100までの数を順に表示し、3の倍数のときは"Fizz"、5の倍数のときは"Buzz"、両方の倍数のときは"FizzBuzz"と表示します。

```test.py
for i in range(1, 101):
    if i % 3 == 0 and i % 5 == 0:
        print("FizzBuzz")
    elif i % 3 == 0:
        print("Fizz")
    elif i % 5 == 0:
        print("Buzz")
    else:
        print(i)
```

## コードの流れ

- `1` から `100` までの数値を順に処理  
- `i` が `15` の倍数なら `"FizzBuzz"` を出力  
- `i` が `3` の倍数なら `"Fizz"` を出力  
- `i` が `5` の倍数なら `"Buzz"` を出力  
- それ以外の `i` はそのまま出力  

## 実際に実行してみる
まず、以下のコマンドを実行して FizzBuzz の動作を確認します。

```bash
python test.py
```

**実行結果**

プログラムを実行すると、1 から 100 までの数が順に出力され、ルールに従って "Fizz" や "Buzz" が表示されます。

```bash
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
・・・（省略）
89
FizzBuzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz
```

## コードの解説

### 1. ループ処理

```py
for i in range(1, 101):
```

- `range(1, 101)` は 1 から 100 までの整数を順番に取得する。（101 は含まれない）  
- `for` ループを使い、`i` に 1 から 100 までの値を順番に代入し、以下の処理を繰り返す。

### 2. 15 の倍数（FizzBuzz）

```py
    if i % 3 == 0 and i % 5 == 0:
        print("FizzBuzz")
```

- `i % 3 == 0` → `i` が 3 の倍数であるかを判定  
- `i % 5 == 0` → `i` が 5 の倍数であるかを判定  
- 両方の条件を満たす場合（15 の倍数のとき）、`"FizzBuzz"` を出力  

**例：**

- `i = 15` → `15 % 3 == 0` かつ `15 % 5 == 0` → `"FizzBuzz"`  
- `i = 30` → `30 % 3 == 0` かつ `30 % 5 == 0` → `"FizzBuzz"`  

### 3. 3 の倍数（Fizz）

```py
    elif i % 3 == 0:
        print("Fizz")
```

- `i % 3 == 0` のとき `"Fizz"` を出力  
- `i % 5 == 0` が `False` の場合のみこの処理が実行される（つまり 15 の倍数は `"FizzBuzz"` で処理される）  

**例：**

- `i = 3` → `3 % 3 == 0` → `"Fizz"`  
- `i = 6` → `6 % 3 == 0` → `"Fizz"`  

### 4. 5 の倍数（Buzz）

```py
    elif i % 5 == 0:
        print("Buzz")
```

- `i % 5 == 0` のとき `"Buzz"` を出力  
- `i % 3 == 0` が `False` の場合のみこの処理が実行される（つまり 15 の倍数は `"FizzBuzz"` で処理される）  

**例：**

- `i = 5` → `5 % 5 == 0` → `"Buzz"`  
- `i = 10` → `10 % 5 == 0` → `"Buzz"`  

### 5. それ以外（そのまま数値を出力）

```py
    else:
        print(i)
```

- 上記のどの条件にも当てはまらない場合、そのまま `i` を出力  

**例：**

- `i = 1` → `1 % 3 != 0` かつ `1 % 5 != 0` → `1`  
- `i = 2` → `2 % 3 != 0` かつ `2 % 5 != 0` → `2`  

## まとめ

ここまで読んでいただきありがとうございました。***今回の内容は基本的な部分でしたが、私自身も条件分岐や繰り返しを振り返ることができました。***

今後もこのような基礎的な部分については丁寧にまとめていこうと思っています。
「エンジニアのためのマネジメントキャリアパス」を読んで、マネジメントってすごいなと改めて思うなど

エンジニアのためのマネジメントキャリアパス。割と定番本だと思われる。

[Amazon.co.jp: エンジニアのためのマネジメントキャリアパス ―テックリードからCTOまでマネジメントスキル向上ガイド : Camille Fournier, 及川 卓也(まえがき), 武舎 広幸, 武舎 るみ: 本](https://www.amazon.co.jp/dp/4873118484/)

![](https://m.media-amazon.com/images/I/71GdBMCppUL._SY466_.jpg)

過去にも読みかじっている。しかししっかり読んでいなかった気がする。

[「ヒューマンスキル」が無いのでマネジメントは無理です #ポエム - Qiita](https://qiita.com/e99h2121/items/99cda4721cb09696161f)
[エンジニアはどこまで勉強すればよいのか - スキルマップと生存戦略を考えた #ポエム - Qiita](https://qiita.com/e99h2121/items/a41339815d9aea87bdb4)
[エンジニアはどこまで "出世" すればよいのか - キャリアパスと定年を考えた #ポエム - Qiita](https://qiita.com/e99h2121/items/89ec37a049adda24db2a)

そして率直な感想として表題の通りということで、その感想文です。

## 感想

読みながら見かけた感想文にて、読んでいると「落ち込む」という話を読んだ。確かに落ち込むというか、読んでるとマネジメントはすごいなという気持ちが高まっている...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/ad7c8e68-eb52-ce6e-788f-58d7c9049047.png)
(「マネジメントはすごい」ということを示す絵を生成してもらいました。)

「もしも誰かに正面切って、できる上司に何を期待しますかと訊かれたら、答えられますか？」などとあるのだが、確かにこの問いも難しい。何もしなくて良い、休暇の承認とか野暮用の細かいお願いだけ聞いてくれれば良い、飲み会の支払いだけしてくれれば良いって感じなんだけど果たしてそれで良いんだろうか。

### 上司に求めるべきこと

上司に求めるべきこと、答えとしては以下だそうです。

1. 1on1
2. フィードバックの提供

いわゆるマネジャーとしてのマネジャー論以前、メンターの話も書いてある。傾聴 や 自身の対応の調整 など、意外とマネジメント業務というのは誰もが経験せざるを得ない。

### 優秀なテックリード

優秀なテックリードとは:
- アーキテクチャを把握している
- チームプレイの大切さを心得ている

「面白い作業は全部自分がやっている、という人。やめてください。」

- 技術的な意思決定を主導する
- コミュニケーションの達人である

ということだそうだ。

### 重要と緊急の違いを見抜く

そして重要と緊急の違いを見抜くには:

- 重要かつ緊急: 明らかにやるべきこと
- 重要だが緊急ではない: 必須。時間を作る
- 重要ではないが緊急: ついつい注目しがちな「気の散る要因」
- 重要ではなくて緊急ではない: 明らかに回避すべきこと

ということ。


### 兆候

- 日頃仕事熱心であるはずの部下が突然、退社時刻きっかりに帰ってしまう。
- 順調と言いながら、管理者との 1on1 を度々キャンセルし、ステータスアップデートでも詳細を明かそうとしない。
- チーム会議に出席しているメンバーに活気がない。
- プロジェクトリストが顧客の気分次第で毎週変わる。

こんな状況でマネジメントの出番となる。そう、マネジメントとは誰かが担わなければならないもの。誰しもがマネジメントになりたくないのは当然であるとして、マネジメントを担ってくれているマネジャーには尊敬せざるを得ない。それは当然のことだった。


## まとめ

「エンジニアのためのマネジメントキャリアパス」は、ブリリアントジャーク の話、労働負荷が高いことによる過労にどう対処するか、元同僚を部下とすることはどのようか、秘密主義者、無礼者へどう対処するか などなどの難しいシチュエーションとともに、コード書きの仕事が恋しい という気持ちに対して「あなたはどちらか (マネジメントたるか、そうならざるか) を選ばざるを得ない」と突きつける。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/522c2490-f143-09b2-0b58-29c157cb1f94.png)
(「マネジメントはすごい」ということを示す絵を生成してもらいました。その 2 )

[【読んでみた】エンジニアのためのマネジメントキャリアパス ―テックリードからCTOまでマネジメントスキル向上ガイド - どこにでもいるSEの備忘録](https://www.nogawanogawa.work/entry/management_career)
[マネジメントに興味がなくても騙されたと思って『エンジニアのためのマネジメントキャリアパス』を読んでくれ - STEAM PLACE](https://steam.place/entry/2018/10/04/094034)

以上です～
読書感想文「内部構造から学ぶ　PostgreSQL　設計運用計画の鉄則」　監視

# 書籍名「内部構造から学ぶ　POstgreSQL　設計運用計画の鉄則」
改訂３版
上原一樹、勝俣智成、佐伯昌樹、原田登志
技術評論社

# 読もうと思った経緯
Postgresqlの監視について見識を深めたいと思ったため。
　背景としては業務で監視を担当することがあり、理解不足を実感したため。

# 対象読者
データベース管理システムの監視について概要を知りたい方

# 印象に残った部分

## p134 監視計画

監視とは、「postgreSQLがデータベースとして健全に動作しているか」を確認すること

監視計画では以下３点を決める。
１．監視項目の選定
２．監視する間隔
３．何をもって異常とするかの閾値

## p134 監視項目について　設計
### Linux 
CPU、メモリ、HDD、ネットワークなどのリソースを監視する。

### postgres項目　設計
・データベース
　コミット/ロールバック数
　データベースのキャッシュヒット率
　デッドロック発生有無

・テーブルとインデックス
　テーブルのキャッシュヒット率
　インデックスとキャッシュヒット率

・活動中のプロセㇲエンド
　トランザクションからの実行時間
　実行中のクエリ

### p137 サーバーログの設定　設計
ログ出力箇所・・ログを出力するタイミング（時間）
ログ内容・・保持期間


## p213 サーバの死活監視　


### 死活監視とは
```
サーバの死活監視
サーバーの稼働状態を監視することです。
サーバーがダウンしてトラブルが起きないように監視すること

```
ManageEngine OpManager
https://www.manageengine.jp/products/OpManager/solution_server-availability-monitoring.html

### 項目
項目|コマンド
---|-----|
サーバーが動作していること|ping -c 
PostgreSQLのプロセス確認|ps | grep postgres  もしくは　pg_isready
SQLが実行できるか確認| SELECT now()


## p217 正常動作の監視
・正常動作・・「想定する性能でサービスを提供すること」
・サーバーの正常動作の監視
　サーバーがリソースを効率よく利用し
　想定どおりに処理できているか、確認CPU,I/O,ネットワーク


### 項目
#### サーバー側
p221
項目|コマンド
---|-----|
サーバー全体の動向を確認|vmstat
TCP/IP接続の利用状況| netstat
I/Oに関する情報|iostat
IO,CPU,ネットワークの詳細| sar -u 1 or d -1 or -n ALL 1




#### PostgreSQL側
基本的にビューの値から情報を取得します。
確認項目|ビュー名|実際のコマンド
------|--------|------
|コミット/ロールバックの回数 </br> データベース単位のキャッシュ率 </br>デッドロック発生回数|pg_stat_database|---
各テーブルに対する実行された処理について</br>例：シーケンススキャン、件数、挿入、更新 </br> 削除・・HOT更新の回数（よくわかんね＞＜）|pg_stat_user_tables|---
インデックステーブルキャッシュ？？|pg_statio_user_tables </br> pg_statio_user_indexes| ---
プロセス、トランザクション、クエリ|pg_stat_activity |---
ロック待ちのプロセスを確認する|pg_locks|----

# 実践できること or 感想

## 感想
監視の大まかな流れについて把握できてよかったです。
監視は業務で必ず必要な要素なので知れて良かったです。

Postgresqlに限らず、mysql,oracle,SQLServerに問わず何でも応用できる方法なのでコスパの良い知識だと思います。
・　本書にはコマンドの結果なども記述されており　とてもわかりやすいです。



## 実践できること
・postgresql on dockerで監視方法を作る。
監視項目をドキュメントにして残しておく。

・実際にコマンドを打って監視を経験する。



# 参考
富士通のサイトにしっかり書かれてますね。これ参考にしたら良さそうですね。
https://www.fujitsu.com/jp/products/software/resources/feature-stories/postgres/article-index/monitoring/


公式ドキュメント
https://www.postgresql.jp/docs/9.4/monitoring.html
This is a placeholder. Flows don't run in the canvas




+ [Help: Email flow not launching on the donations](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000KCtlp0AD)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/994edaea-a5c1-1707-8616-547bbf7b3a13.png)


Make sure this home page is the default for either the org, the app or the profile you're testing with

It's working fine for me. I just added a screen flow to my home page and I can see it.
 

This message only means that it won't run in the canvas, in builder mode (when editing the lightning page)


# communityの場合

+ [How to add screen flow to community](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000A8A4jSAF)

:::note
It's all right. Try the preview mode, or impersonate a community user.

To do that, take a user that can access the Community, go to his user's details page, then go to his Contact record.

From the Contact page, click on Login To Community as User 

大丈夫です。プレビュー モードを試すか、コミュニティ ユーザーになりすましてください。
 
これを行うには、コミュニティにアクセスできるユーザーを選択し、そのユーザーの詳細ページに移動して、連絡先レコードに移動します。
 
お問い合わせページから、ユーザーとしてコミュニティにログインをクリックします。 
:::

+ [Flows don't run in the canvas. So they don't accidentally do something in your org. When I try to add a flow (when creating case) to the home page layout. How to fix it?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000JgRNkSAN)

:::note
 Are you embedding a screen flow onto a home page? When adding the flow in the app builder, it will show this message because it will not run in the builder- if you save the page and return to the home page, you should see the flow embedded on the page. 

画面フローをホームページに埋め込んでいますか? アプリ ビルダーでフローを追加すると、ビルダーでは実行されないためこのメッセージが表示されます。ページを保存してホームページに戻ると、ページに埋め込まれたフローが表示されます。 
:::

# トレイルヘッド？

+ [フローがキャンバスで実行されないまま止まってしまいました。連絡先ページにフローを表示するという課題を完了できません。ありがとうございます!](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000J8FXISA3)
後輩のためのFigma入門（Step4）

# 後輩のためのFigmaの使い方

後輩のためにFigmaに関して書きました。

Step4は「図形を使いこなそう」です。

今回は、様々な図形に共通している機能について書きました。
**枠線・影**などは次回行います。
以下の機能ごとに書いたため、知りたい機能をご覧ください。

# 目次
- [透過](#透過)
- [すべての角を丸める](#角を丸める)
- [頂点の編集](#頂点の編集)
- [頂点の追加](#頂点の追加)
- [頂点の削除](#頂点の削除)
- [一つの頂点を丸める](#頂点を丸める)

## 透過
透過させるパラメーターは複数ありますが、主に使われるのは以下の2つです。
**「オブジェクトの透過」** と **「色の透過」** の違いは影や枠線などに反映されるかどうかです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/5b08a6a4-d699-20aa-ff9d-45b3a5238835.png)

<br> <!-- 空行を追加 -->

## 角を丸める

角は、以下の部分で丸めることができます。角からの距離をpx単位で設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/65528a37-4961-9fbe-160c-ea1cf101b5e7.png)

<br> <!-- 空行を追加 -->

## 頂点の編集

**Step1** 頂点の編集は、以下のボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/81ae2153-9611-04aa-a784-a154f0ac2913.png)

<br> <!-- 空行を追加 -->

**Step2** すると、図形が以下の画像のように選択されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/e19f8989-ae49-9326-36c8-b1010f036edd.png)

<br> <!-- 空行を追加 -->

**Step3** 角になっている部分を移動して、特殊な図形を作ることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/fd17519d-8070-b4d5-9a76-9c1e88897b81.png)

<br> <!-- 空行を追加 -->

## 頂点の追加

**Step1** 以下のボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/81ae2153-9611-04aa-a784-a154f0ac2913.png)

<br> <!-- 空行を追加 -->

**Step2** 頂点を増やしたい場合は、辺の中点にカーソルを合わせると、白丸が出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/040bca20-b086-4fb1-b2db-5512da88576d.png)

<br> <!-- 空行を追加 -->

**Step3** 白丸をクリックすると、新しく頂点が増えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/97425bf2-f8d6-ec71-84b1-4a7612c3b9df.png)

<br> <!-- 空行を追加 -->

## 頂点の削除

**Step1** 以下のボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/81ae2153-9611-04aa-a784-a154f0ac2913.png)

<br> <!-- 空行を追加 -->

**Step2** 頂点を削除したい場合は、２つの頂点を合わせると一つになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/8aaff661-5507-434c-158a-8a56e3933e0d.png)

<br> <!-- 空行を追加 -->

## 頂点を丸める

**Step1** 以下のボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/81ae2153-9611-04aa-a784-a154f0ac2913.png)

<br> <!-- 空行を追加 -->

**Step2** 以下のボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/e557c4c1-244c-0caa-5b56-0ea1faccfc76.png)

**Step3** 丸めたい頂点をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/1fe68912-b3b3-849a-3f74-c03ad0b957e9.png)



## 続き
今回は、図形の詳細設定を解説しました。
次回は影・枠線を解説しようと思います。

https://qiita.com/ko-tarou/items/58a14354018c36d03650
重機用タープを使ってDIY池ライナーを作る方法

# 静かな池を作るためのガイド

静かな池は、どんなアウトドアスペースでも美しさを提供し、地域の野生動物にとっての避難所にもなります。池を作る際の大きな障害の一つは、プロフェッショナルな池用ライナーの価格です。しかし、[**heavy-duty tarps**](https://www.tarpsnow.com/heavy-duty-tarps.html) をライナーとして使用することで、コストを抑えることができます。このガイドでは、タープを使って耐久性のある池用ライナーを作成する方法を、素材選びから適切な設置方法まで詳しく説明します。

## なぜ重機用タープを選ぶのか？

重機用タープは池作りに多くの利点をもたらします：

- **コスト効率**：タープは専門的な池用ライナーよりもはるかに手頃な価格で、予算を気にするプロジェクトに最適です。
- **広く手に入る**：[heavy-duty tarps](https://www.tarpsnow.com/heavy-duty-tarps.html) は、ほとんどのホームセンターやオンラインで、さまざまなサイズや厚さで手に入ります。
- **多用途で耐久性が高い**：準備が整えば、タープは不規則な池の形に適応し、防水シールを確保できます。

タープは池用に明示的に製造されたものではありませんが、その頑丈さと適応性により、DIYプロジェクトには最適な選択肢となります。

## ステップ1：池の計画

適切な計画を立てることが、成功した池作りには欠かせません。以下の要素を考慮しましょう：

### 場所の選定

日光と陰影のバランスを取った場所を選びましょう。日光が強すぎると藻の成長を促進し、陰影が過剰だと植物の成長が妨げられます。

### サイズと形の決定

池の寸法とレイアウトを決めます。小さな池は維持が簡単ですが、大きな池はより豊かな生態系とランドスケープの可能性を提供します。

### 地域の規則確認

一部の地域では掘削や水の使用に規制があります。プロジェクトを開始する前に、地元の行政機関でガイドラインを確認してください。

## ステップ2：材料の準備

実用的で耐久性のあるライナーを作成するために、以下のものを集めましょう：

- **重機用タープ**：UV耐性、防水性のあるタープを選び、厚さは最低20ミル以上のものを選びましょう。
- **アンダーレイメント素材**：古いカーペットや毛布、ランドスケープ用布、または [**clear tarps**](https://www.tarpsnow.com/clear-tarps.html) を再利用して、タープを鋭利な物から守ります。
- **シャベル**：掘削と形状作りに必須です。
- **石と砂利**：タープを固定し、自然な美観を作り出すために使用します。
- **ガーデンホース**：池の輪郭をマーキングするのに便利で、その後水を入れる際にも使います。
- **砂**：タープの下にスムーズで保護的な基盤を提供します。

## ステップ3：池を掘る

### 形のアウトラインを作る

ガーデンホースやスプレーペイントで池のデザインをマーキングします。必要に応じてレイアウトを調整してビジョンに合うようにしましょう。

### 掘削

シャベルを使って掘り、崩れるのを防ぐためにスロープ状の側面を作ります。深さは**18〜36インチ程度**を目安に、目的や使用方法に合わせて決めましょう。

### 植物棚の追加

池の縁に水生植物用の棚を作ります。深さは約**6〜12インチ**で、植物の鉢や砂利を置けるようにします。

### 破片の除去

鋭い石や根などを取り除いて、ライナーにダメージを与えないようにします。

## ステップ4：アンダーレイメントの設置

### 基盤のレベルを整える

池の底に**2〜3インチの砂**を広げます。このスムーズな層がライナーをクッションします。

### アンダーレイメントの設置

古いカーペットや毛布、ランドスケープ布、またはキャンバスのタープを砂の上に敷いて、タープを穴から守ります。

## ステップ5：タープライナーの設置

### タープの配置

タープを池の上に慎重に広げます。ライナーを固定し、漏れを防ぐために、**周囲に少なくとも2フィートのオーバーハング**を確保します。

### 調整と折りたたみ

特に角の部分でシワや折り目を平らにします。調整中は石を使ってタープを仮に固定します。

### 端の固定

大きな石を使って、オーバーハングしたタープを重しにして安定させ、固定します。

## ステップ6：池に水を入れる

### 水をゆっくり加える

ガーデンホースを使って池に水を少しずつ入れます。水の重さがタープを押し込み、調整が必要な部分が見えるようになります。

### 監視と調整

池に水が入っている間、シワを平らにし、安定させるために石を再配置します。

## ステップ7：仕上げとランドスケープ

### 余分なタープのトリミング

池が満たされたら、余分なタープを切り取り、長期的な安定性のために**数インチのオーバーハング**を残します。

### 石と砂利の追加

池の底に砂利を敷き、池の縁に大きな石を配置して美観を高めます。

### 植物と装飾の追加

水生植物（スイレンやガマ）を導入し、生物多様性を促進します。噴水や彫像などの装飾を加えて、池を個性的に仕上げましょう。

## 結論

重機用タープを使って池を作ることは、手頃な価格で満足感のあるプロジェクトであり、アウトドアスペースを美しくし、生態系を支えます。適切な計画とメンテナンスを行えば、あなたの池は長く楽しめる空間となるでしょう！
さくらVPSで複数ドメインでそれぞれのメール設定について

さくらのVPSでドメインを複数使ってます。それぞれのドメインでメールを設定したいと思います。
postfix、dovecotの設定で困ってます。受信ソフトはサンダーバードを使ってるのですが送信は出来ても受信ができない状態です。

バーチャルアカウント設定にしてから設定で困ってます。

今までは１つのドメインでアカウントメールのもuseraddで作成してました。

複数ドメインを使うことになってバーチャルユーザーを使いました。
ここではまってしまいました。
メールソフトはpostfix+dovecotです。OSはalmalinux８です。

基本的なバーチャルユーザーでの設定方法が知りたいです。

よろしくお願いいたします。
TypeORM の data-source.ts 設定

TypeORM がうまくいかないなら prisma でもいいか、と思ったけどプレーンなオブジェクトを扱えないっぽいので TypeORM に戻ってきた。

https://qiita.com/okadabasso/items/2bc2ed4bd1405179f263 ではディレクトリ指定ができずに諦めたのだが、最近 github copilot を入れて色々調べていたらヒントが見つかった。

現在のバージョンでの設定

```typescript
import { DataSource } from 'typeorm';
import { join } from 'path';


export const AppDataSource = new DataSource({
    type: 'postgres', // or your preferred database type
    host: 'pg',
    port: 5432,
    username: 'testuser',
    password: 'password',
    database: 'testdb',
    synchronize: false,
    logging: true,
    logger: 'advanced-console',
    entities: [
        join(__dirname, 'entities/**/*.{ts,js}'),

    ], // Add your entities here
    migrations: [
        join(__dirname, 'data/migrations/**/*.{ts,js}'),
    ],
    subscribers: [],
});

AppDataSource.initialize()
    .then(() => {
        console.log('Data Source has been initialized!');
    })
    .catch((err) => {
        console.error('Error during Data Source initialization:', err);
    });
```

entities に `join(__dirname, 'entities/**/*.ts')` と `join(__dirname, 'entities/**/*.js')` を並べているのは前者が migration の変更検出用、後者が実行時のエンティティ検出用。前者がないとmigration:generate が機能せず、後者がないと実行時にエンティティクラスが検出できない。

これで心置きなく TypeORM で遊べる。
データポイントのばらつき（標準偏差）とサンプル平均のばらつき（標準誤差）

# データポイントのばらつきとサンプル平均のばらつき

## 例
あるクラスの学生のテストの点数を考える。以下のデータがあるとする：

$$
\{85, 90, 88, 92, 87\}
$$

### 1. データポイントのばらつき（標準偏差）
まず、データポイントのばらつきを計算する。これがサンプルの標準偏差 \( s \)。

1. 平均（\(\bar{X}\)）を計算：
$$
\bar{X} = \frac{85 + 90 + 88 + 92 + 87}{5} = 88.4
$$

2. 各データポイントと平均の差を二乗し、その平均を取る（分散）：
$$
\text{分散} = \frac{(85 - 88.4)^2 + (90 - 88.4)^2 + (88 - 88.4)^2 + (92 - 88.4)^2 + (87 - 88.4)^2}{5} = 6.64
$$

3. 分散の平方根を取る（標準偏差）：
$$
s = \sqrt{6.64} \approx 2.58
$$

この標準偏差 \( s \) は、個々のデータポイントのばらつきを示している。

### 2. サンプル平均のばらつき（標準誤差）
次に、`サンプル平均が母平均がからどれくらいばらつくか`を計算する。これが標準誤差。


1. 標準誤差の公式を使う：
$$
\text{標準誤差} = \frac{s}{\sqrt{n}}
$$

ここで、\( s \) はサンプルの標準偏差、\( n \) はサンプルサイズ。この例では、\( s = 2.58 \) で、\( n = 5 \)。

2. 標準誤差を計算：
$$
\text{標準誤差} = \frac{2.58}{\sqrt{5}} \approx 1.15
$$

この標準誤差は、サンプル平均のばらつきを示している。サンプルサイズが大きくなると、標準誤差は小さくなり、サンプル平均が母平均に近づくことを示す。

## まとめ
- **データポイントのばらつき**: 個々のデータポイントが平均からどれだけ離れているかを示す（標準偏差 \( s \)）。
- **サンプル平均のばらつき**: サンプル平均が母平均からどれだけ離れているかを示す（標準誤差）。

標準偏差をサンプルサイズの平方根で割ることで、サンプル平均のばらつきを正確に示すことができる。
Discord サーバーを守る ロール認証アプリを作成した話


## はじめに

私は通信高校に通っており、同好会の運営を行っています
しかし、昨日サーバーの招待リンクが学園外に漏れてしまい、第三者が不正に参加する事態が発生しました
この問題を解決するために、特定のメールアドレスを持つユーザーだけがサーバーに参加できるようにする認証機能を実装しました

本記事では、このアプリケーションの実装内容や、開発において工夫した点を紹介します

## アプリの概要

このアプリは、Cloudflare Workers と Hono を使用して、Discord サーバーのメンバーに特定のロールを付与する仕組みを提供します
認証には Discord OAuth2 と Google OAuth2 を利用し、指定したメールアドレスのドメインを持つユーザーのみが認証を通過できるようにしています

### 主な機能

- Discord OAuth2 を利用したユーザー認証
- Google OAuth2 でメールアドレスを取得し、ドメインをチェック
- 許可されたメールアドレスのユーザーに対して Discord の特定のロールを付与
- JWT と CSRF 対策を施し、セキュリティを強化

## 実装で頑張った部分

### 1. CSRF 対策

OAuth2 の `state` パラメータを利用し、CSRF 攻撃を防ぐ仕組みを実装しました
具体的には、認証開始時にランダムな `state` 値を生成し、クッキーに保存しておき
認証後に返ってきた `state` 値と照合し、一致しない場合は認証を拒否するようにしました
[index.ts (Lines 21 to 36 in 9e3c108)](https://github.com/minagishl/discord-email-auth/blob/9e3c1084053218d76aacd9b596fd9ddd0ef4dda1/src/index.ts#L21-L36)

```ts
// Function to generate state for CSRF protection
async function generateState(): Promise<string> {
  const buffer = new Uint8Array(32);
  crypto.getRandomValues(buffer);
  const state = Array.from(buffer)
    .map((b) => b.toString(16).padStart(2, "0"))
    .join("");
  return state;
}

// Validate the CSRF token
function validateState(c: Context, state: string): boolean {
  const savedState = getCookie(c, "oauth_state");
  deleteCookie(c, "oauth_state");
  return savedState === state;
}
```

### 2. JWT によるセッション管理

Discord ユーザー ID を安全に保存するため、JWT を使用しました
JWT の署名には環境変数 `JWT_SECRET` を用いることで、安全性を確保しています
[index.ts (Lines 118 to 125 in 9e3c108)](https://github.com/minagishl/discord-email-auth/blob/9e3c1084053218d76aacd9b596fd9ddd0ef4dda1/src/index.ts#L118-L125)

```ts
// Save discordUserId safely with JWT
const jwt = await sign({ discordUserId }, c.env.JWT_SECRET);
setCookie(c, "discord_user", jwt, {
  httpOnly: true,
  secure: true,
  sameSite: "Lax",
  maxAge: 600,
});
```

### 3. メールドメインのチェック

Google OAuth2 を使用して取得したメールアドレスのドメインをチェックし、特定のドメインを持つユーザーのみを許可します
[index.ts (Lines 212 to 216 in 9e3c108)](https://github.com/minagishl/discord-email-auth/blob/9e3c1084053218d76aacd9b596fd9ddd0ef4dda1/src/index.ts#L212-L216)

```ts
const allowedDomains = ["nnn.ed.jp", "n-jr.jp", "nnn.ac.jp"];
const emailDomain = email.split("@")[1];
if (!allowedDomains.includes(emailDomain)) {
  return c.json({ error: "Email domain not allowed" }, 403);
}
```

### 4. Discord ロールの付与

認証を通過したユーザーには、Discord の API を用いて特定のロールを付与します
[index.ts (Lines 245 to 255 in 9e3c108)](https://github.com/minagishl/discord-email-auth/blob/9e3c1084053218d76aacd9b596fd9ddd0ef4dda1/src/index.ts#L245-L255)

```ts
// Assign a role
const roleResponse = await fetch(
  `${c.env.DISCORD_API_BASE}/guilds/${c.env.DISCORD_GUILD_ID}/members/${discordUserId}/roles/${c.env.DISCORD_ROLE_ID}`,
  {
    method: "PUT",
    headers: {
      Authorization: `Bot ${c.env.DISCORD_BOT_TOKEN}`,
      "Content-Type": "application/json",
    },
  },
);
```

## まとめ

今回、Discord サーバーの安全性を向上させるために、ロール認証システムを実装しました
私にとって初めての JWT や CSRF 対策の実装でしたが、セキュリティの重要性を実感しながら学ぶ良い機会となりました
今後もより安全で使いやすい仕組みを考え、改善を続けていきたいと思います
Go言語(プログラミング)入門メモ㉓

## パッケージ単位でのコード管理
Goのコードは一つまたは複数のファイルで構成されるパッケージという単位で管理する。
以下のようなフォルダ構成とする。
~~~
awesomeProject
    ┣main.go
    ┣mylib
        ┣math.go
        ┣human.go
        ┣under
            ┣sub.go
~~~
math.goではint型のスライスを引数として平均値を返すAverage関数を作成する。
~~~
package mylib

func Average(s []int) int {
	total := 0
	for _, i := range s {
		total += i
	}
	return int(total / len(s))
}
~~~
human.goでは名前と年齢をフィールドに持つ構造体と文字列を出力するSay関数を作成する
~~~
package mylib

import "fmt"

type Person struct {
	Name string
	Age  int
}

func Say() {
	fmt.Println("Human!")
}
~~~
sub.goでは文字列を出力する関数を作成する。
~~~
package under

import "fmt"

func Hello() {
	fmt.Println("Hello!")
}
~~~

上記のように別フォルダで定義した関数や構造体を使用するときは、その関数が属しているパッケージをインポートする必要がある。
また、別パッケージに属する関数を利用する際は、関数の呼び出し時に「パッケージ名.関数名」としなければならない。
~~~
package main

import (
	"fmt"
	"your-module-name/awesomeProject/mylib" 
	"your-module-name/awesomeProject/mylib/under"
)

func main() {
	s := []int{1, 2, 3, 4, 5}
	fmt.Println(mylib.Average(s))

	mylib.Say()
	under.Hello()
	person := mylib.Person{Name: "Mike", Age: 20}
	fmt.Println(person)
}

//以下のように出力される
3
Human!
Hello!
{Mike 20}
~~~

関数名や構造体名、変数名など小文字にするとほかのパッケージから呼び出すことができない。そのため、ほかのパッケージから呼び出したいときは大文字で書き始めるということを忘れないようにする。

## 学習に使用した教材
・『入門】Golang基礎入門 + 各種ライブラリ + 簡単なTodoWebアプリケーション開発(Go言語)』M.A EduTech
https://www.udemy.com/course/golang-webgosql/?utm_medium=udemyads&utm_source=bene-msa&utm_campaign=responsive&utm_content=top-1&utm_term=general&msclkid=81e2f24a32cc185d275d953d60760226&couponCode=NEWYEARCAREERJP

・『シリコンバレー一流プログラマーが教える Goプロフェッショナル大全』酒井 潤 (著)
https://www.amazon.co.jp/%E3%82%B7%E3%83%AA%E3%82%B3%E3%83%B3%E3%83%90%E3%83%AC%E3%83%BC%E4%B8%80%E6%B5%81%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%83%BC%E3%81%8C%E6%95%99%E3%81%88%E3%82%8B-Go%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E5%A4%A7%E5%85%A8-%E9%85%92%E4%BA%95-%E6%BD%A4/dp/4046070897
OSバージョンの取得方法

OSバージョンを取得するにはAPIレベルを取得します。APIレベルを使用すれば、端末のバージョンによって処理を分岐したり、Google Playに公開するバージョンを指定できます。

```kotlin
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
    // OS15以上の時の処理
} else {
    // OS14以下の時の処理
}
```
`Build.VERSION.SDK_INT`は自身の端末のOSバージョンを取得できます。

```gradle
minSdkVersion 28 // アプリが動作する最小バージョン
targetSdkVersion 34 // アプリの対象バージョン
```
DELTALLM: Transformerモデルの圧縮を革新する低ランクデルタ手法

# DELTALLM: Transformerモデルの新たな圧縮手法

今回は、最新の研究成果である **"DELTALLM: Compress LLMs with Low-Rank Deltas between Shared Weights"** という論文をご紹介します。本研究では、大規模言語モデル（LLM）のメモリフットプリントを削減するための新しい後処理型圧縮技術を提案しています。従来の圧縮手法と異なり、本手法では **Transformerブロック間の重みを共有しつつ、低ランクな差分行列（デルタ）を追加する** ことで、性能を大幅に劣化させることなくモデルのパラメータを削減する点が特徴です。

## 論文情報

- **タイトル**: DELTALLM: Compress LLMs with Low-Rank Deltas between Shared Weights
- **リンク**: [arXiv:2501.18596v1](https://arxiv.org/abs/2501.18596v1)
- **発表日**: 2025年1月30日
- **著者**: Liana Mikaelyan, Ayyoob Imani, Mathew Salvaris, Parth Pathak, Mohsen Fayyaz
- **DOI**: 未公開（arXiv論文）

## 背景と目的

### **Transformerの成長と圧縮の必要性**

近年、大規模言語モデル（LLM）は指数関数的に増加しており、その性能はモデルサイズに依存する傾向があります（Kaplan et al., 2020）。特に、GPT-3（175B）、Llama-3（70B）などの巨大なモデルは、数百GBのメモリを消費し、推論コストも高騰しています。

一方で、エッジデバイスや低リソース環境での運用には、モデルの圧縮が不可欠です。従来の圧縮手法には以下のようなものがあります：

1. **蒸留（Knowledge Distillation）**: 大モデルの知識を小モデルに転移（Hinton et al., 2015）。
2. **剪定（Pruning）**: 重要でない重みを削除（Han et al., 2015）。
3. **量子化（Quantization）**: 重みを低精度（例: 8-bit, 4-bit）で表現（Frantar et al., 2022）。
4. **重み共有（Weight Sharing）**: レイヤー間でパラメータを共有（Dehghani et al., 2019）。

しかし、これらの手法には性能劣化や計算コストの増加といった課題がありました。DELTALLMは、Transformerブロック間の冗長性を利用し、**低ランクなデルタ行列を用いることで高い圧縮率を実現しつつ、精度を維持する** ことを目的としています。

## 研究の焦点

### **DELTALLMの技術的概要**

DELTALLMは、以下の3つの主要な要素で構成されています。

#### **1. Transformerブロック間の重み共有**
- 連続するTransformer層間で同じ重みを再利用する。
- これにより、パラメータ数を削減。

#### **2. 低ランクなデルタ行列の導入**
- 共有された重みの小さな違いを補正するため、低ランクなデルタ行列を導入。
- $$ W_{l+i} = W_l + \delta_{l, l+i} $$
- ここで $$ \delta_{l, l+i} $$ は $$ W_{l+i} - W_l $$ の低ランク近似。
- 特異値分解（SVD）を用いて低ランク構造を抽出し、最適な近似を実現。

#### **3. 進行的モジュール置換（Progressive Module Replacement, PMR）**
- 圧縮中もモデルのパフォーマンスを維持するため、徐々にオリジナルの重みを圧縮版に置換。
- 段階的な置換により、学習の安定性を確保。

## 実験の概要と結果

### **実験設定**

- **ベースモデル**: Llama-3.2B, Phi-3.5B
- **圧縮モデル**: DELTALLAMA, DELTAPHI
- **学習データ**: Alpaca, Ultrachat
- **評価指標**: MMLU, Winogrande, HellaSwag, ARC-Challenge
- **圧縮率**: 12%～25%
- **推論速度比較**: 圧縮後の速度改善

### **結果**

| モデル | パラメータ数 | MMLU | Winogrande | ARC-Challenge | HellaSwag | 推論速度向上 |
|--------|------------|------|------------|--------------|-----------|------------|
| Phi 3.5B | 3.8B | 0.36 | 0.75 | 0.61 | 0.77 | 1.0x |
| DELTAPHI 3.35B | 3.35B | 0.32 | 0.70 | 0.51 | 0.70 | 1.3x |
| DELTAPHI 2.9B | 2.9B | 0.31 | 0.71 | 0.44 | 0.61 | 1.5x |

DELTAPHI 3.35Bは、Phi 3.5Bより12%圧縮しながら、推論速度が1.3倍向上しました。

## まとめと今後の課題

### **DELTALLMの優位性**
- **高い圧縮率と精度維持**
- **既存の圧縮手法（JointDrop, SliceGPT, ShortGPT, LaCo）を上回る性能**
- **推論速度の向上に貢献**

### **今後の展望**
- **さらなる低ランク分解技術の活用**（Tucker分解、CP分解など）
- **適用可能なモデル範囲の拡大（T5, BERT, GPT-4）**
- **量子化技術との組み合わせによるさらなる圧縮**

DELTALLMは、**低リソース環境でのLLM運用に適した圧縮技術** であり、今後の発展が期待されます。
C++のラムダ式でthisをキャプチャし忘れてエラーを吐かれた件

ゲームのコードを書いてたら std::remove_if を使ったところでコンパイルエラーが出たので、備忘録としてまとめておく！

発生したエラー
--
とりあえずエラーメッセージはこんな感じ。
```
error C3493: 既定のキャプチャ モードが指定されていないため、'this' を暗黙的にキャプチャできません
error C2327: 'EnemyBullets::m_pEnemy': 型名、スタティック、または列挙子ではありません。
error C2065: 'm_pEnemy': 定義されていない識別子です。
```
いやいや、なんで m_pEnemy が未定義って言われるの！？🤔
ちゃんとクラスのメンバ変数として定義してるのに…

問題のコード
--
エラーが出たコードはこんな感じ。

```cpp
m_bullets.erase(std::remove_if(m_bullets.begin(), m_bullets.end(),
    [](const std::unique_ptr<EnemyBullet>& bullet) { 
        return bullet->IsExpired() ||
               (bullet->GetBulletPosition().y < 0.0f && bullet->GetBulletType() != EnemyBullet::BulletType::VERTICAL) ||
               m_pEnemy->GetPlayerHitByEnemyBullet(); // ここでエラー発生
    }),
m_bullets.end());

```
弾が画面外に出たときや、プレイヤーに当たったときに削除する処理なんだけど、
m_pEnemy が見つからないって言われる。

原因：ラムダ式のキャプチャリストに this がない！
--
C++のラムダ式では、外部の変数を使うときにキャプチャしないとダメ。
今回 m_pEnemy は EnemyBullets クラスのメンバ変数だから、
ラムダの外側にある this をキャプチャしないとアクセスできない。

キャプチャリストとは？
ラムダ式の [] の中に何を入れるかで、外部変数をどう扱うか決まる。
| キャプチャ | 説明 |
|:-:|:-:|
| []  | 何もキャプチャしない（今回のエラー原因）  |
|  [=] |  すべての外部変数を値渡しでキャプチャ |
|  [&]| すべての外部変数を参照渡しでキャプチャ |
| [this]	 |this ポインタをキャプチャ（今回の解決策）  |
|  [m_pEnemy]| m_pEnemy だけをコピーキャプチャ|

解決策：this をキャプチャする！
--
this をキャプチャすればOK！
修正後のコードがこちら👇
```cpp
m_bullets.erase(std::remove_if(m_bullets.begin(), m_bullets.end(),
    [this](const std::unique_ptr<EnemyBullet>& bullet) { // `this` をキャプチャ
        return bullet->IsExpired() ||
               (bullet->GetBulletPosition().y < 0.0f && bullet->GetBulletType() != EnemyBullet::BulletType::VERTICAL) ||
               this->m_pEnemy->GetPlayerHitByEnemyBullet(); // `this->` をつけると明示的になる
    }),
m_bullets.end());
```
これでコンパイルが通るようになった！🎉
	
まとめ
--
ラムダ式の中でクラスのメンバ変数を使うときは this をキャプチャしないとエラーになる！
キャプチャリスト [] を [this] にするだけで解決！
this-> をつけると、より明示的にメンバ変数を使ってるのがわかる！
C++のラムダって便利だけど、キャプチャの仕組みをちゃんと理解してないとハマるな〜💦
また同じエラーで悩まないように、備忘録として残しておく！🚀
【書評】クラウドアプリケーション 10の設計原則

## 読んだ本

https://book.impress.co.jp/books/1122101082

## 感想

Azureのアプリケーションアーキテクチャガイドを参考に、クラウドアプリケーションで気を付けたい原則についで学べる本だった。Azureを触り始めたので良いきっかけだと思い読み始めたが、AWSやGCPなどIaaSを触っていれば読み始められる内容だった。自分はAWSの資格取得時にWell-architectedフレームワークを学んでいたので重複する内容が多く、復習になる点も多かった。

特に10章の「ビジネスニーズを忘れない」がとても重要で、ベストプラクティスを実務に反映するにあたり、調節の重要さを再認識した。また、付録にかかれていた「シフトレフト」という考え方は初耳で、今読んでいる他の本でも言及されていた。レフトとは開発工程で言う上流のことで、なるべく早いうちから検討し、問題が発生したときも工程を再度戻して対応しようという考え方だ。これは忘れないようにしたい。

## おすすめの人

- AWSなどを業務で使用しているが、何となく触れている人
- クラウドを使用したアプリケーションの設計を任された人

## 次に読むなら

- それぞれのクラウドの資格取得など、具体的な構築方法に進む
- 「アーキテクトの教科書」などで他工程の設計について学ぶ
GO言語：備忘録（学習記録）①

## はじめに

・こちらはGO言語の個人学習の備忘録となっております。
　参考にした情報が古いものであったり、誤った情報であることもあるかもしれませんので
  そういった場合は、ご教示いただけると幸いです。

## GO言語 文字列操作
　Go言語では正規表現「regexp」パッケージを使用するよりも、「strings」パッケージを使用する方が良いとのこと

 理由：「regexp」パッケージのパフォーマンスが非常に悪いため

 そのため、文字列操作をしたい場合は、「regexp」ではなく「strings」パッケージが良いらしい

※2019年発刊の書籍にて学習
※go version:1.12
 
## 「strings」パッケージ
``` :よく使うパターン 
// 対象の文字列が指定した文字列で始まるか
HasPrefix(s, prefix string) bool

//　対象の文字列が指定した文字列で終わるか
HasSuffix(s, suffix string) bool

//対象の文字列が指定した文字列を含むか
Contains(s, substr string) bool

//文字列を空白区切りで分割
Fields(s string) []string

//指定した文字（セパレータ）で文字列を分割
Split(s, sep string) []string

//指定した文字（セパレータ）で文字列を分割（最大nの長さで戻す）
SplitN(s, sep string, n int) []string

//対象の文字列の前後の空白を除去
TrimSpace(s string) string

//対象の文字列の前後からcutsetに含まれる文字を除去
Trim(s string, cutset string) string

//対象の文字列を置換する
Replace(s, old, new string, n int) string
```

どうしても正規表現を使用したい場合は、可能な限り初期化時に生成する。
その際、正規表現パターンの生成には「regexp.MustCompile」を使用する。
また、正規表現の文字列は「" "」ではなく「' '」を使用することで、
余計なエスケープを省き可読性を上げる意識を持つこと。

## 「regexp」パッケージ　その１
``` :どうしても正規表現を使う場合
// regexp.MustComile
var worReg = regexp.MustCompile('¥w+')
```
※Must※※※という関数の命名規則は、絶対に引数を間違う可能性がない場合に使われる。
万が一引数が間違っていた場合には、panicを発生させることが慣例となっている。
そのため、実行中の関数の中で使用してはならないということを意識して使うように。

関数の実行中に動的に正規表現を使用したい場合は、「regexp.Compile」を使用すること。

## 「regexp」パッケージ　その２
```:動的に正規表現を使用したい場合
reg, err := regexp.Compile('SSS')
if err != nil {
    //エラーチェック
    }
```

## まとめ
GO言語において文字列操作は、基本的には「strings」パッケージを使用し、
正規表現の「regexp」パッケージは最終兵器的な扱いとすること。
Ruby + BigQueryで既存のテーブルのスキーマを流用してテーブルロードをするときの罠

意外とハマったのでメモ

こんな感じにスキーマを取得して、

```rb
bigquery = Google::Cloud::Bigquery.new(project_id: PROJECT_ID)
template_table = bigquery.dataset(DATASET_ID).table(source_table_id)
schema = template_table.schema
```

こんな感じにそのスキーマを指定してもなぜかschemaを認識してくれない。

```rb
bigquery.dataset(DATASET_ID).dataset.load_job(destination_table_id, "GCSのパス", schema: schema)
```

取得したスキーマを一旦シリアライズしてからデシリアライズするとうまくいく。

```rb
sio = StringIO.new
Google::Cloud::Bigquery::Schema.dump(schema, sio)
schema2 = Google::Cloud::Bigquery::Schema.load(sio)

bigquery.dataset(DATASET_ID).dataset.load_job(destination_table_id, "GCSのパス", schema: schema2)
```

このあたりが影響していそうだが、詳細なメカニズムは不明。

https://github.com/googleapis/google-cloud-ruby/blob/google-cloud-bigquery/v1.51.1/google-cloud-bigquery/lib/google/cloud/bigquery/load_job.rb#L1670-L1675
[ODC]QRコードをサーバ側で生成するForgeコンポーネント「QRCoder」

2025/02/01時点で、QRコードを出力するODC向けForgeコンポーネントは既にいくつかある。
多くはクライアント側で生成するだが、QRCoderはサーバ側でQRコードを生成する。その概要と使い方を見ていく。

# 環境情報
ODC Studio(Version 1.5.5)
[QRCoder - Overview (ODC) | OutSystems](https://www.outsystems.com/forge/component-overview/18610/qrcoder-odc) (Version 1.1.0)
[QRCoder Payload - Documentation (ODC) | OutSystems](https://www.outsystems.com/forge/component-documentation/18612/qrcoder-payload-odc/0) (Version 1.0.0)

# 使い方
## インストール
ODC Portal > FORGE > All assetsページを開き、「QRCoder」で検索。
QRCoderとQRCoder PayloadをInstall。

QRCoder Payloadは後述するが必須ではない。
QRコードに埋め込みたいのがシンプルな文字列であれば不要。

## 文字列を埋め込んだQRコードを生成する
サーバー側のAction（Server/Service/Data Actionなど）で、QRCoder/GeneratePngCode Actionを呼ぶだけでよい。
payloadパラメータに埋め込みたい文字列を設定する。その他のパラメータは必須指定ではないので、生成されるQRコード画像をカスタマイズしたい時に調べればよさそう。
![スクリーンショット 2025-02-01 18.45.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/31dae8d9-75df-4a61-50fc-51fd20b46693.png)

結果は、QRコードの画像バイナリ（Binary Data型）として出力される。

## フォーマット付きのデータを埋め込んだQRコードを生成する
例えば、座標情報は、緯度と経度を「geo:緯度,経度」フォーマットの文字列にすることで、読み込み時に地図アプリで指定座標を開かせることができる（iPhoneで確認した）。
対応するフォーマットの文字列に詰め替えをするのが、QRCoder PayloadのAction群。

座標情報の場合の利用例。
座標の変換にはQRCoder Payload/GenerateGeoLocationを使う。このActionのOutput ParameterをQRCoder/GeneratePngCode Actionのpayloadに渡せばよい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/e2487e5c-92a5-2617-3291-83198dd5ddb2.png)

# ライセンスチェック
Forgeのコンポーネントページによると、QRCoderはMIT、QRCoder PayloadはBSD-3。
ForgeコンポーネントはデフォルトではBSD-3なのだが、QRCoderはExternal Logicであり、.NETのライブラリを参照している。このライブラリにライセンスを合わせたものと思われる。

参照しているライブラリとは、同名のQRCoder。
[codebude/QRCoder: A pure C# Open Source QR Code implementation](https://github.com/codebude/QRCoder)

# 実装チェック
## QRCoder
External Logicの.NETソリューションは、レポジトリが公開されている。
[stefan-d-p/odc-qrcoder-library: OutSystems Developer Cloud External Logic Library to generate QR codes](https://github.com/stefan-d-p/odc-qrcoder-library/tree/master?tab=readme-ov-file)

シンプルな実装なので、あまり気にすることはなさそう。
NUnit3によるユニットテストプロジェクトが含まれている。
ODCのForgeコンポーネント、かつExternal Logicの場合、インストールしたコンポーネントから実装を取り出すことができない。そのため、ライセンス等で確実を期したいなら、上記の.NETレポジトリから自分でビルドしたものを利用する手もある。

## QRCoder Payload
シンプルなODCのLibrary。外部ライブラリは使っていない。
使い方で見た通り、受け取った情報をQRコードに埋め込むための文字列にフォーマットするActionを多数公開している。
OpenSearchで急に "401, 'Unauthorized'" エラーになった原因と解決方法メモ

## これは何？
* WebアプリケーションがOpenSearchとの接続でいきなりエラーになった時の原因と解消方法のメモ
* OpenSearchは(ElasticSearchも)日本語の情報が少なく、同様のトラブルシューティングで困っている人の助けになれば幸いです。

### 経緯
* 開発していたWebアプリケーションにて、急に、エラーが発生。
* ログを見たところ、Web アプリケーションとOpenSearchとの接続にて、`401, 'Unauthorized'` エラーを発見。
* OpenSearh自体は特になんの設定変更もしていないため、原因の特定に時間がかかりました。

### 結論
OpenSearchをシングルノードで稼働していたことにより、障害発生？時に内部データベースが失われ、内部ユーザーデータベースと HTTP基本認証を用いた接続ができなくなっていた模様。


### 調査詳細
1.  まずはWebアプリケーション側のエラーを疑ったが、同様のコードベースで動いている環境が存在 && エラー前にこれといった変更が見られませんでした。

1.  続いて OpenSearchに何か変更が加わり、エラーとなった可能性を検討。CloudTrail と CloudWatch にてログを確認するも、OpenSearch自体への設定変更は特になかった。またWebアプリケーションからOpenSearchに変更をかけるようなリクエストなども見つけることができませんでした。

1.  とすると、OpenSearch自体に何かエラーが起きているのではないかと思い、AWSコンソールから　OpenSearchのヘルスチェックを確認。その結果、エラーが起き始めたタイミングから内部ドキュメントが消失していることが判明しました。

![Screenshot 2025-02-01 at 12.16.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386347/962ca4b7-0966-d31a-24ee-bbde5c5f456c.png)

詳細を見ると、約1時間半ほど、ログデータ自体が取得できておらず、その後、ドキュメントが失われた状態となっていました。
![Screenshot 2025-02-01 at 12.40.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386347/457b0b72-b12d-a454-6daf-7ba5613a2e62.png)


ログが失われる原因としては、CPU/RAM/IO枯渇、ネットワークエラーなど色々考えられるが、ドキュメント自体が消失しているため、内部でハードウェア or OpenSearch自体に障害が発生した可能性が高いと推測。ここで初めて、原因と思われる事象を特定できました。
その場合、内部ユーザーデータベースのデータも失われたのではないかと思い、コンソール画面から、新しいマスターユーザーを追加で登録。新しく登録した認証情報を使用したところ、再接続が可能となりました.

### その後
調べたところ、同様の事象を経験している記事が1つだけ見つかりました。
https://blog.ecbeing.tech/entry/2024/01/09/080000#OpenSearch%E7%A0%B4%E6%90%8D
この記事によると、
* ノードに問題が発生した場合、新しいノードに入れ替えが行われる。
* シングルノードで起動していたため、レプリカが存在せず問題が発生したノードのデータが失われた。
* 内部ユーザーデータベースもその際に失われる可能性がある。

とのことです。
今回は開発中のものだったため、大事にはなりませんでしたが、シングルノードを使う時はデータが消失する可能性を考慮した使用が大切だと実感しました。最低限、スタンバイノードを1つ作っておき、障害時にフェールオーバーさせるようにしておくのが良さそうです。

なお、AWSのベストプラクティスでは、スタンバイ込みのマルチAZ設定が推奨となっています。
https://docs.aws.amazon.com/ja_jp/opensearch-service/latest/developerguide/bp.html

### 最後に
今回は、AWSの内部リソースのエラーが原因と推論を出しました。OpenSearchのエラーを調べると、どうしてもOpenSearchのアプリケーション起因のエラーについての情報が多く、今回の事象について情報はあまり見つかりませんでした。
個人的には開発でシングルノードを利用する機会は割と多いと思ったため、そういった方たちの役立つ情報になればと思っています。
最後まで読んでいただきありがとうございました。
StringIOとGzipWriterを組み合わせるときのIOError対策

以下のコードはIOErrorを引き起こします。

```rb
sio = StringIO.new
Zlib::GzipWriter.wrap(sio) do |gz|
  gz.puts("hoge")
end

sio.rewind
sio.read
# => IOError: not opened for reading (IOError)
```

これはGzipWriter#wrapのブロックを抜けるときにGzWriter#closeメソッドが呼ばれ、そのメソッド内でStringIOもcloseするからです。

既にclose済みのStringIOに対するreadはできないので、以下のように新たなStringIOオブジェクトを作成すると良いです。

```rb
sio = StringIO.new
Zlib::GzipWriter.wrap(sio) do |gz|
  gz.puts("hoge")
end

new_sio = StringIO.new(sio)
new_sio.read
```
Unityで一時停止処理を作成したい！

# はじめに
- Unityで一時停止機能を作成したので備忘録として残しておきます。**正直めっちゃ簡単です。（自分が作成しているゲームが単純だということもありますが・・・）**

# 目次
1. どんな機能を作成したかの概要
1. 全体の処理のプロセス
1. 実際のコード

# どんな機能を作成したかの概要
- 作成した機能は下記のGIF画像の通りです。再生されていたアニメーションやタイマーが右上のメニューボタンを押すと停止されています。そしてメニューが開き４つのボタンが出現しています。

![画面録画-2025-02-01-232418.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758326/1965e06d-bd6b-415c-c314-198155d66937.gif)

# 全体の処理のプロセス
- 大まかな流れとしては下記の図のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758326/80cac694-93b6-2738-962f-df07591ddeac.png)

# 実際のコード
- 実際のコードは下記の関数を使用します。
```c#:MenuManager.cs
public void OnMenuButtonClicked()
{
    if (!isPaused)
    {
        // ポーズ処理
        Time.timeScale = 0f;
        playerInput.enabled = false; // プレイヤーの入力を無効化
        isPaused = true;

        // パネルと4つのボタンをアクティブにする
        pausePanel.SetActive(true);
        continueButton.SetActive(true);
        howToPlayButton.SetActive(true);
        hintButton.SetActive(true);
        goTitleButton.SetActive(true);
    }
}
```

- **Time.timeScaleでゲーム時間の進行を完全に停止する**
    - 以下のコードでこの処理を行っています。**設定が有効になると、基本的にすべての物理演算やアニメーションが停止します**。
    - しかし、**Updateメソッドは引き続き、呼び出されるため、時間の進行に依存しないロジックは引き続き実行されます**。
    - また、Time.timeScaleの値を**1fにしたら通常の速度**で時間が流れ、**0.5fにしたら時間が半分の速度**で流れることを意味します。（スローモーションのようにもできる）
    ```c#:MenuManager.cs
    Time.timeScale = 0f;
    ```

- **Playerの入力を打ち切る**
    - 以下のコードでプレイヤーの入力を打ち切ります。playerInputは私が独自で作成したプレイヤーの入力を検知するためだけのスクリプトなので、**デフォルトで搭載されているものなどではありません**。
    ```c#:MenuManager.cs
     playerInput.enabled = false; // プレイヤーの入力を無効化
    ```

- **4つのボタンをアクティブにする**
    - 以下のコードでボタンをアクティブ化しています。これは正直、今回の記事の本質とは関係ないかもしれません。
    ```c#:MenuManager.cs
    // パネルと4つのボタンをアクティブにする
    pausePanel.SetActive(true);
    continueButton.SetActive(true);
    howToPlayButton.SetActive(true);
    hintButton.SetActive(true);
    goTitleButton.SetActive(true);
    ```

## 一時停止を解除して再生させるには
- 一時停止をして、その後に再生させるのは**一時停止の時と全く逆のことを行えばいいだけです**。
- 具体的には以下のコードでその機能を実装しています。

```c#:MenuManager.cs
public void OnContinueButtonClicked()
{
    // ポーズ解除
    Time.timeScale = 1f;
    playerInput.enabled = true; // プレイヤーの入力を有効化
    isPaused = false;

    // パネルとボタンを非アクティブに
    pausePanel.SetActive(false);
    continueButton.SetActive(false);
    howToPlayButton.SetActive(false);
    hintButton.SetActive(false);
    goTitleButton.SetActive(false);
}
```

- Time.timeScaleもプレイヤーの入力管理も**すべて一時停止の時と全く逆のことをしている**のが分かると思います。これで再生機能も実装できています。

# まとめ
- 今回は一時停止機能に関してまとめました。しかし、そもそも私が作成したゲームが単純であるという前提がこの機能にはあるため、もしかしたら大規模ゲーム開発ではより複雑な一時停止機能の実装が待っているものと思われます。
【Ontap】SVM-DRでSnapmirrorを構成する場合の"-identity-preserve"に関する注意点

Snapmirrorには幾つかの種類がありますが、ここではSVM-DR(VSERVER間での同期)を構成する場合の"-identity-preserve"オプションに関する注意点を記載します。

"-identity-preserve"オプションとは、SVMの設定情報を同期するかどうかのオプションです。同期される情報は下記ナレッジから確認できます。
https://docs.netapp.com/ja-jp/ontap/data-protection/snapmirror-svm-replication-concept.html#サポートの詳細
=>Configurations replicated in SVM disaster recovery relationships

冒頭に記載しましたが、"-identity-preserve"オプションは後から変更できないらしいです。
詳細は下記ナレッジ参照。
https://kb.netapp.com/on-prem/ontap/DP/SnapMirror/SnapMirror-KBs/How_to_change_a_misconfigured_SVMDR_-identity-preserve_setting_to_either_True_or_False

もし設定を間違えてしまった場合はベースライン転送=初期転送からやり直す必要があるとの事。

ただし、ベースライン転送を回避する方法もあるよう。方法は調査中。
RPAの出番ではなかった話

【結論】
RPAで基幹システムのUIから1件ずつ抽出するより、ファイルサーバーの権限をもらってスクリプトで処理した方が圧倒的に速いことがある

【条件】
業務で利用するシステムでは、1申請に対して複数の参考資料を保存できるようになっている。

【業務の流れ】
1.申請者が申請の説明に必要とされる資料を保存する。
2.申請部門の承認者がチェックする。
3.承認者の決裁が終わったものを、申請部門の担当者が申請と参考資料を印刷し、支払部門に送付する。
4.紙の書類に基づき、支払部門が対応する。

このような流れで業務が進むのだが、「1日約60件の申請があり、申請および紙の参考資料を1件ずつダウンロードして印刷している。」と聞き、うわぁ~面倒くさ~と思った。そこでRPAのフローを提供して改善した。
<br><br><br><br><br>
（相談を受けてRPAのフロー提供した私の心の中では、( *｀ω´) ﾄﾞﾔｧ って思っていた。）
<br><br><br><br><br>
しかし、よく考えたら、ファイルサーバーのアクセス権限をもらえれば、そこから欲しい条件でPowerShellを利用し、該当案件だけ担当者の作業フォルダにコピーするだけで済む。ほんの数秒で処理が終わる瞬殺案件じゃん、ということに気づいてしまった。
TypeScriptでDeepSeek R1を実装するのが大変だった話

DeepSeek R1をTypeScriptで実装する際に直面した具体的な課題と、その解決方法について共有します。

## 主な実装上の課題

### 1. Transformers.jsの型定義への対応

`generate`関数の実装において、以下のような型の問題に遭遇しました：

```typescript
// Transformers.jsのGenerationFunctionParametersには
// max_new_tokensが定義されていない
const output = await model.generate({
  ...inputs,
  streamer,
  stopping_criteria: stopping_criteria_list,
  // @ts-ignore - Property 'max_new_tokens' does not exist
  max_new_tokens: 2048,  // この設定は必須
});
```

max_new_tokensを設定しないと、推論がすぐに終わってしまい、正しい答えに辿り着きません。

### 2. 推論フェーズの制御

この問題からもわかったことですが、

DeepSeek R1は`<think></think>`タグを使用して推論フェーズを制御しています：

```typescript
// トークンIDの取得
const [_, END_THINKING_TOKEN_ID] = tokenizer.encode("<think></think>", {
  add_special_tokens: false,
});

// 状態管理
let state: "thinking" | "answering" = "thinking";

// </think>を受信したら回答フェーズに移行する
const token_callback_function = (tokens: bigint[]): void => {
  if (tokens[0] === BigInt(END_THINKING_TOKEN_ID)) {
    state = "answering";
  }
};
```

1. 推論フェーズは明示的なトークン（`</think>`）で終了を検知
2. トークンコールバックで状態を管理
3. ストリーミング出力で進捗を監視します

**重要** :`</think>`が登場し、そして回答を得るまで推論を繰り返さないといけません。

### 3. DeepSeekの推論メカニズム

DeepSeek R1の特徴として、明示的な思考フェーズを持つ推論メカニズムがあります：

1. **二段階の推論プロセス**
   - `thinking`フェーズ: 問題の分析と思考過程
   - `answering`フェーズ: 最終的な回答の生成

2. **明示的な状態管理**
   - `<think></think>`タグによるフェーズの区切り
   - トークンベースでの状態遷移の検出
   - パフォーマンス計測（トークン生成速度など）

3. **UIフィードバック**
   - 現在の状態をリアルタイムで通知
   - トークン生成の進捗表示
   - パフォーマンス指標の共有

このような実装により、モデルは問題に対して「考えてから答える」という人間らしい推論プロセスを実現していますし、思考の過程が見やすくなっています。

## まとめ

DeepSeek R1の実装において、特に以下の点が重要でした：

1. `max_new_tokens`の設定（型定義の問題はあるものの必須）
2. 二段階の推論プロセスの実装（thinking/answering）
3. 推論状態の適切な制御とUIフィードバック

これらの特徴を理解し適切に実装することで、DeepSeek R1の「考えてから答える」という特徴的な推論能力を効果的に活用できます。
C++ vector の最大値・最小値を取得する方法

:::note info
AtCoder に挑戦した際，ベクターの要素から最小値を求める方法を忘れていたので備忘録として残しておきます．
:::

# ベクターの最大値・最小値

ベクターの最大値・最小値はmax_element, min_element 関数を用いて取得できます．
max((last - first) - 1, 0) 回の比較を行うため，計算量は O(n)になります．
* ベクターの要素が数値(int型，float型などの時)の時

```c++
# 最大値の取得
std::vector<int> v = {3, 1, 4};
auto max_iterator = std::max_element(v.begin(), b.end());
int max = *max_iterator;

# 最小値の取得
std::vector<int> v = {3, 1, 4};
auto mix_iterator = std::mix_element(v.begin(), b.end());
int mix = *mix_iterator;
```

* ベクターの要素がペアの時

```c++
std::vector<std::pair<int, int>> v = {{0, 3}, {1, 1}, {2, 4}};

# 一つ目の要素に関して最大値・最小値を求めたい場合
auto max_iterator = std::max_element(v.begin(), b.end());
std::cout << max_iterator->first << std::endl;
std::cout << max_iterator->second << std::endl;

# 二つ目の要素に関して最大値・最小値を求めたい場合
auto max_iterator = std::max_element(v.begin(), v.end(), [](const auto& a, const auto& b) {
		return a.second < b.second;
});
std::cout << max_iterator->first << std::endl;
std::cout << max_iterator->second << std::endl;
```

# 参考サイト
https://cpprefjp.github.io/reference/algorithm/max_element.html

# 備考
不備などございましたら，教えていただけると幸いです．
Macbook（AppleSilicon）のUTMでMetasploitable2を起動する

# 概要

MacbookにMetasploitable2をインストールする手順。日本語記事だけではできなかったので備忘録として記事にしました。この手順を使えばMetasplotable２に限らずイメージをUTMに取り込むことが可能となります。

# 手順

## 1. Metasploitable2のイメージをダウンロードする

https://sourceforge.net/projects/metasploitable/

## 2. ターミナルでqemuをインストールする

![Screenshot 2025-02-01 at 22.03.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667133/cbf926eb-9f43-9cdc-d907-05a93227dc2a.png)


## 3. ダウンロードしたMetasploitable2のzipファイルを解凍する

![Screenshot 2025-02-01 at 22.34.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667133/20407817-6fb7-0dbe-5864-f9efc2b33536.png)


## 4. ファイルをコンバートする

![Screenshot 2025-02-01 at 22.41.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667133/3ebce80f-1157-cc10-873d-583e029566be.png)


## 5. UTMを起動し設定する

![Screenshot 2025-02-01 at 22.47.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667133/6ae95b23-cee9-cca5-77c1-091adfeb4ac8.png)

![Screenshot 2025-02-01 at 22.47.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667133/ef1c83a1-675b-f4fd-b0be-947386b6ae31.png)

![Screenshot 2025-02-01 at 22.48.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667133/8d63daff-8648-f9b2-9442-79723c7316f1.png)

![Screenshot 2025-02-01 at 22.48.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667133/f8677a42-a9ba-459a-586d-c3a909abba09.png)

設定は特に変更することなく（好みに合わせてお好きにどうぞ）名前をつける段階まで進めていく。

![Screenshot 2025-02-01 at 22.52.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667133/efd89db4-7326-ab69-4d80-f31cad52536f.png)


セーブすると設定画面が開くので設定を進めていく

![Screenshot 2025-02-01 at 22.53.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667133/79f27b54-688f-1afc-83a8-47bc9abd42bd.png)


![Screenshot 2025-02-01 at 22.54.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667133/5f7092f5-a405-5a3d-6dc6-e3e76b693b1c.png)


![Screenshot 2025-02-01 at 22.56.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667133/d205e9c4-417c-fdc1-64fd-5c59736efadc.png)


![Screenshot 2025-02-01 at 22.57.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667133/60dd5f9d-8fa7-b45d-5aac-1a21098994a4.png)

![Screenshot 2025-02-01 at 22.58.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667133/0ca38301-b534-4794-4c13-1094b1750005.png)

![Screenshot 2025-02-01 at 22.59.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667133/01f9f604-181a-1ded-d1a7-b17bd7612b30.png)

作成したイメージを起動する

![Screenshot 2025-02-01 at 23.02.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3667133/9fdc80b7-0e9e-d8d6-bfd9-22c04e9a7997.png)


ID、パスワードともにmsfadminを入力しログインする

# 最後に


普段は自分が詰まったことの備忘録で、最低限のことしか書かず短時間で終わらせますが、今回は自分以外にもUTMにイメージを入れたい人がいるかもしれないと思い写真付きにしました！
今回の記事を通して感じたのは、記事を書いている人たちはすごい‼️ってこと！
あんな量と質の記事を作りだすことができるなんて...
wasm32-unknown-emscriptenとbindgenでつまづいた

C/C++ライブラリをRustプロジェクトでビルド&bindgenしつつwasm32-unknown-emscripten targetでビルドする際につまづいたのでメモ。

C/C++ライブラリは*-sys crateとして分離、build.rsでC/C++をビルドしつつbindgenも動かす構成。
C/C++のビルドはccを使いライブラリのMakefileなどを参考にファイルとオプションを設定すればよい。

macOSビルドや、Windowsビルドは手元で成功し、LinuxビルドもCI上で成功している状態からスタート。

## つまづき1

bindgenが `memory.h` を見つけられないという。 `memory.h` 以外の可能性もある。

```
fatal error: 'memory.h' file not found
```

emscriptenでは独自のヘッダーを持っているのでそれをインクルードさせる必要がある。build.rs内でbindgenの `.clang_arg("-I/emscripten/.../include")` などを利用してもいいが、これをやると他targetのビルドがやりづらくなる。
ここでの正解は `BINDGEN_EXTRA_CLANG_ARGS=--sysroot=/emscripten/.../sysroot` など `sysroot` をemscriptenのものにすること。

## つまづき2

emscriptenのbindgenが関数を出力しないことがあった。これは可視性の設定が影響している。
こちらは、他targetのビルドに影響しないためbuild.rsのbindgenに **`.clang_arg("-fvisibility=default")`** することで解決した。

## 参考

https://github.com/ssssota/libraw-rust/pull/6/files#diff-bd6164f1e71d8210925644975fe4d99df6fe33fa979173396b3a441481d2e8c4
🚀 MastodonでElasticsearchとコンソールからアカウントを作成する際のエラーとその解消

## 🗂️ **概要**

Mastodonを構築した際、Elasticsearchが正しく動作していなかったり、Web UIからアカウント作成ができないケースがあります。本記事では、以下の手順を解説します。

1. **Elasticsearchのインストールと設定**  
2. **Mastodonのコンソールを使用したユーザー作成方法**  
3. **発生するエラーとその解決方法**

---

## ✅ **1️⃣ Elasticsearchのインストール**

### 1. Elasticsearchのインストール確認

```bash
which elasticsearch
```

何も表示されない場合は未インストールです。以下の手順でインストールします。

### 2. 依存パッケージのインストール

```bash
sudo apt-get update
sudo apt-get install -y openjdk-11-jdk
```

### 3. Elasticsearchの公式リポジトリ追加

```bash
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
sudo sh -c 'echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" > /etc/apt/sources.list.d/elastic-7.x.list'
```

### 4. Elasticsearchのインストール

```bash
sudo apt-get update
sudo apt-get install -y elasticsearch
```

### 5. Elasticsearchの起動と有効化

```bash
sudo systemctl start elasticsearch
sudo systemctl enable elasticsearch
```

### 6. 起動確認

```bash
curl http://localhost:9200
```

正常に起動していれば、バージョン情報が表示されます。

---

## 🚀 **2️⃣ Mastodonコンソールからのユーザー作成**

### 1. コンソールの起動

```bash
RAILS_ENV=development rails c
```

### 2. アカウントの作成

```ruby
account = Account.create!(
  username: 'newuser',
  domain: nil,               # ローカルユーザーなら nil
  display_name: 'New User',
  note: 'This is a new account'
)
```

### 3. ユーザーの作成

```ruby
user = User.create!(
  email: 'newuser@example.com',
  password: 'password123',
  confirmed_at: Time.now,    # メール確認をスキップ
  account_id: account.id
)
```

---

## ⚠️ **3️⃣ 発生したエラーと解決方法**

### ❌ **エラー: Service agreement must be accepted**

```
Validation failed: Service agreement must be accepted (ActiveRecord::RecordInvalid)
```

### ✅ **解決方法**

ユーザー作成時に利用規約への同意が必要です。以下のように `agreement` を追加します。

```ruby
user = User.create!(
  email: 'newuser@example.com',
  password: 'password123',
  confirmed_at: Time.now,
  account_id: account.id,
  agreement: true   # 利用規約への同意
)
```

これで正常にユーザーが作成されます。