OmniAICreator/Qiita-1.07M huggingface dataset:
Streamlitの学習をかねて、自分の研究を可視化してみた話

## はじめに
この記事は「[ただただアウトプットを癖付けるための Advent Calendar 2024](https://qiita.com/advent-calendar/2024/newbie2024)」に投稿した記事です。

[最初の記事](https://qiita.com/yotabouya/items/e63c53c5e18b3cf6a454#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB)にも書いた通り、私は生物物理の実験を専門にしている研究者です。
最近はデータ解析のため機械学習のコード開発も行っており、幸いにもその成果が[NeurIPSに採択されました](https://neurips.cc/virtual/2024/poster/93465)。

研究をする上でWebアプリを触ることはほとんどありませんでした。
ただ、作ったものを人に使ってもらうという視点にたつと、Webアプリは非常に有用だと感じています。
上で開発したコードとの接続が良いWebアプリを作っておくことで、CUIに慣れていない人にも使ってもらいやすくなると思います。
そこで今回は、データを扱ったり、簡単なシミュレーションを走らせてその結果を可視化するためのWebアプリを作ってみました。

## 関連記事

#### 前の記事「[【生物物理屋による論文紹介】EVO - 分子からゲノムまで、マルチスケールで扱うLLM](https://qiita.com/yotabouya/private/8d66a50ce830481863c1)」

#### 次の記事「[生物物理屋がローカルLLMを導入して遊んでみた話](https://qiita.com/yotabouya/private/136a5222f69cd3774e16)」


## Streamlitとは

[Streamlit](https://streamlit.io/)は、Pythonでデータを可視化するためのWebアプリを簡単に作成できるフレームワークです。
Jupyter Notebookのように、コードとその実行結果を同じファイルに書くことができます。

## まずはチュートリアル (と思いましたが、まだやってません)

[Streamlitの公式チュートリアル](https://docs.streamlit.io/develop/tutorials)をやってみました。
各種リモートサーバーへの接続を除き、全部で６つあります。

### [Trigger a full-script rerun from inside a fragment](https://docs.streamlit.io/develop/tutorials/execution-flow/trigger-a-full-script-rerun-from-a-fragment)

Streamlitの特徴的な仕様として、関数を断片に分けることができ、それを部分的に再実行することができます。

## 今回のWebアプリ

今回は、自分の研究で扱っている生物の群れ行動のシミュレーション結果を可視化するWebアプリを作成しました。
以下のような機能を実装しました。

- パラメータを指定して、群れ行動のシミュレーションを走らせる
- シミュレーション結果を可視化する

アプリは[こちら](https://muwamichi-vicsek-tutorial.streamlit.app/)。
また、このアプリは[こちらのリポジトリ](https://github.com/MasahitoUWAMICHI/tutorials_streamlit)からデプロイしています。

なお、これらの実装には、以下のページを参考にしました。
- [【15分で出来る】Streamlit爆速入門](https://qiita.com/papasim824/items/1804bc1bd8d4c195d8a8)
- [Streamlit入門＋応用 ～ データ分析Webアプリを爆速で開発する](https://qiita.com/tamura__246/items/366b5581c03dd74f4508)

また、コーディングにおいて、ローカルLLM+Continue(VSCode)を多用しました。これについては[２つ後の記事](https://qiita.com/yotabouya/items/dae1261fde3989b7dfaf)で詳しく書いています。
qwen2.5-coderを用いたところ、Viscekモデルのシミュレーションもstreamlitのコードも、大部分を書いてくれました。楽。

## 1. パラメータを指定して、群れ行動のシミュレーションを走らせる

今回のモデルは、群れ運動において基盤的であるVicsekモデルです。
Vicsekモデルは、個体が周囲の個体と平均的な方向を合わせることで群れを形成するモデルです。
個体数や、方向合わせに生じる誤差の大きさ、群れの密度などのパラメータを指定することで、群れの振る舞いを変化させることができます。
これらのパラメータを指定するスライダーをサイドパネルに実装しました。
また、シミュレーションを走らせるためのボタンも実装しました。
これは、`if st.toggle('Run simulation'):`というコードで、ボタンを押すとif文の中のコードが実行されるようになります。
ハマったこととして、このボタンを`st.button`で実装したところ、以下で述べるシミュレーション結果の可視化のボタンを押した際にシミュレーション結果がクリアされてしまうという問題がありました。
このため、シミュレーション用のボタンは`st.toggle`で実装しました。

## 2. シミュレーション結果を可視化する

シミュレーション結果を可視化するために、各個体の位置と向きをプロットしました。

最初は、可視化される時刻を指定して、ボタンを押すことでその時刻のシミュレーション結果を表示するという実装をしました。
ハマったのは、ボタンを押すたびにシミュレーションが再度走り、結果が変わってしまうという点です。

この問題を解決するために、シミュレーション結果をキャッシュすることで解決しました。
シミュレーション結果を`st.session_state`に保存し、それを表示することで、ボタンを押すたびにシミュレーションが再度走ることを防ぎました。
また、シミュレーションを走らせるトグルボタンをオフにすることで、キャッシュされたシミュレーション結果をクリアするようにしました。

さらに、実はシミュレーション結果を表示するのに、ボタンを実装しない方が都合がいいことに気づきました。
可視化される時刻を選ぶスライダーを変更すると、それに付随するコードは再度実行されるので、自動的に描画が更新されるからです。
このため、ボタンを押すことなく、スライダーを動かすだけでシミュレーション結果を見ることができるようになりました。

あと欲しいのは、シミュレーション結果を動画で保存したり再生したりする機能です。
これは、今後の課題として取り組んでいきたいと思います。
【AWS】Lambdaで「OSError: [Errno 30] Read-only file system」エラーになった場合

# 概要
AWS Lambdaでpythonコードを実装して動かしていたら以下のエラーに。原因と解決方法を紹介します。

> [ERROR] OSError: [Errno 30] Read-only file system: '/var/task/sample/xxx.json'

# 原因と解決方法
Lambdaのファイルシステムは読み取り専用。
なので書き込みは基本的にできません。

ただし、`tmp`ディレクトリだけは書き込みOKというルールがあります。


```py
# 元々のコード
with open('/sample/xxx.json', 'w') as json_file:
    json.dump(data, json_file, indent=4)

# /tmpディレクトリにファイルを書き込む
with open('/tmp/xxx.json', 'w') as json_file:
    json.dump(data, json_file, indent=4)
```

上記のようにすることで書き込みができるようになり、エラーがなくなりました。

ちなみに、この`tmp`ディレクトリは最大512MBの一時ストレージでしたが、2022年に10GBまで使用できるようになったようです。

https://aws.amazon.com/jp/blogs/news/aws-lambda-now-supports-up-to-10-gb-ephemeral-storage/
S3に保存しているWAV形式の音声ファイルの長さを取得する

# はじめに

とあるコストを見積もるために、S3に保存しているWAV形式の音声ファイルの長さを調べる必要があたったので作成したスクリプトを紹介します

# パッケージのインストール

音声データの処理に[python-soundfile](https://github.com/bastibe/python-soundfile)を使用しています。python-soundfileを使用するには`libsndfile`が必要なため、適宜インストールください。

Ubuntuの場合は以下でインストール可能です。
```bash
sudo apt-get install -y libsndfile1
```

```bash
pip install boto3 soundfile
```

# スクリプト

S3から順番にWAFファイルを取得して、`長さ = 総サンプル数 / サンプリングレート` で計算しています。
ファイル数が多いとS3の通信料が高額になるため気をつけましょう。

```python
import csv
import io

import boto3
import soundfile as sf

s3_client = boto3.client("s3")

BUCKET_NAME = "your bucket name"
PREFIX = "your directory prefix"


def main():
    result = []
    paginator = s3_client.get_paginator("list_objects_v2")
    for page in paginator.paginate(Bucket=BUCKET_NAME, Prefix=PREFIX):
        for content in page["Contents"]:
            key = content["Key"]

            # 音声ファイルの長さを検索
            response = s3_client.get_object(Bucket=BUCKET_NAME, Key=key)
            audio_data = io.BytesIO(response["Body"].read())
            with sf.SoundFile(audio_data) as f:
                duration = len(f) / f.samplerate

            result.append({"key": key, "size": content["Size"], "duration": duration})

    with open("result.csv", "w") as f:
        writer = csv.DictWriter(f, fieldnames=result[0].keys())
        writer.writeheader()

        for row in result:
            writer.writerow(row)


if __name__ == "__main__":
    main()

```
【3Dプリンター】 ELEGOO NEPTUNE 4 を提供いただきました.

# ELEGOO Neptune 4でロボコン用部品を制作してみた

こんにちは，舞鶴高専 創造技術研究会です．

今回，[ELEGOO様](https://www.elegoo.com/)より3Dプリンター「Neptune 4」およびフィラメントを提供いただきました.
これらを活用して，ロボコンの機体制作に取り組みましたので，記事にさせていただきます．

プリンターの性能や使用感，実際に制作した部品についてお伝えしますので，ロボコンや3Dプリンターに興味のある方の参考になれば幸いです.

## 開封・組み立て

Neptune 4は非常にコンパクトな梱包で届きましたが，内容物はしっかり保護されており，のりや，ニッパー，USBなどもついていて簡単に始められます．

![20240826_134100.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3937733/b0af632e-b832-c3be-69de-176ad7f6a3cb.jpeg)

![20240826_134344.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3937733/2b7f9d65-4788-96db-5b70-68ece0aa65a6.jpeg)

![20240826_134627.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3937733/a00b0e06-0fd6-efcc-1598-50651fe55aee.jpeg)

### 組み立て
付属のマニュアルを参考にしながら作業しましたが，特に難しい工程はなく，スムーズに組み立てが完了しました．組み立てに要した時間は約30分程度．3Dプリンター初心者の方でも安心して始められると思います．

![20240826_135317.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3937733/ce0bee72-8209-17a4-7aa8-9574c8785d15.jpeg)
![20240826_140241.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3937733/0a3567fd-f3b9-a769-b243-1239c424e5b9.jpeg)

## 初プリント：テスト印刷

組み立て後、付属のフィラメントを使用してテスト印刷を実施しました。ちょうどロボコンで必要だった部品を印刷してみました．
位置の調整も結構簡単でした．
![20240826_142128.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3937733/bcc46b10-66a1-17ec-f63d-4a6c1c74ade4.jpeg)

そして完成したのがこちら．
![20240827_125824.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3937733/7a78ef6d-82bf-4ab3-c09d-2548748a063c.jpeg)
印刷時間も早くてとても簡単です．

### プリンターの使用感
- **速度**：プリント速度が速く，大型パーツでも短時間で完成する点が非常に便利でした．
- **精度**：特に小型部品のディテール再現性が高く，寸法誤差がほとんど見られませんでした．
- **操作性**：タッチスクリーンの操作が直感的で，簡単に設定を変更できるのも好印象でした．

今年のロボット
![Gbdgv8SaUAAczRc.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3937733/ca05a4e2-5265-a46b-6ac1-736a1b9efd0a.jpeg)


## 最後に

ELEGOO Neptune 4は，初心者の方でも扱いやすい3Dプリンターでありながら，高い精度と速度を兼ね備えています．ロボコンの機体制作のような用途にも十分活用可能で，設計通りの部品を安定して作成できました．

[ELEGOO様](https://www.elegoo.com/)並びに[堀内様](https://x.com/YuTR0N) ，このたびは素晴らしい製品を提供いただきありがとうございました．これからも活用しながら，さらに精度の高いものづくりを目指していきたいと思います．
Javaの2次元配列で、2次元目の要素数を後から代入する形でも各要素によって違う数にできることを初めて知った

現在、黒本でJava Silverを勉強している。
その中で、2次元配列を作成する際は
>int[][] array = new int[3][];

のように、2次元目の要素数を省略した形で宣言及び1次元目のインスタンス代入ができ、その後で2次元目の要素数を後から代入することもできるとわかった。そこで、参考書籍では以下のように1次元目の要素が持つ要素数を同一の値で代入していた。

>array[0] = new int[3];
array[1] = new int[3];
array[2] = new int[3];

ならばこの時に1次元目の各要素が持つ2次元目の要素数を同一の値ではなくバラバラの値にしたら、それぞれが指定した値の数だけ要素数を持つことができるのか気になったため以下のコードで試してみた。

```java
int[][] array = new int[3][];
array[0] = new int[3];
array[1] = new int[5];
array[2] = new int[7];

array[0][2] = 1;
array[1][4] = 2;
array[2][6] = 3;

System.out.println(array[0][2]);
System.out.println(array[1][4]);
System.out.println(array[2][6]);
```
```text:実行結果
1
2
3
```

試してみたところ問題なく動作したことから、Javaでは2次元配列の宣言時に2次元目の要素数を省略し後から代入する形であれば、1次元目の要素が持つ2次元目の要素数を各要素によって違う数にできることがわかった。

2024/11/19 追記
そういえば初期化子を用いる方法でも、1次元目の要素が持つ2次元目の要素数はそれぞれで変えられるのであった。
```Java
int[][] array = { { 1,2,3 }, { 4,5,6,7 }, { 8,9,10,11,12 } };

System.out.println(array[0][2]);
System.out.println(array[1][3]);
System.out.println(array[2][4]);
```

```text:実行結果
3
7
12
```
全然初めて知ることなどではなかったので、タイトルも修正。

参考文献:
- 書籍名: 『徹底攻略Java SE 11 Silver問題集［1Z0-815］対応』  
- 著者: 志賀 澄人　著/株式会社ソキウス・ジャパン　編
- 出版元: インプレス
- リンク: https://book.impress.co.jp/books/1118101186
i3 , i3wm , logout時の字 font フォントが小さい

<h2>小さいんじゃ</h2>
<h3>
~/.config/i3/config
</h3><h3>
の bindsym $mod+Shift+e で始まる部分を
</h3>
<font color="#CCF">
<p/><pre>
bindsym $mod+Shift+e exec --no-startup-id "i3-nagbar -f 'pango:monospace 24' \<br/>
   	-t warning -m 'exit?' \<br/>
	-b 'HALT' 'sudo shutdown -h now'　\
    -b 'REBOOT' 'sudo shutdown -r now' \<br/>
	-b 'LOGOUT' 'i3-msg exit'"<br/>
 </pre>
</font>

<P/>に変更する<br/>
●上の24を好きなサイズに変更する。</br>
<p>
●文字列やフォントはお好みで
</p>
【Laravel】SQLSTATE[HY000] [2002] Connection refused の解消方法

### 取るべき初動
まずはプロジェクトディレクトリの.env ファイルにおいて、以下の環境変数が正しく設定されているか確認してください。
```
DB_HOST
DB_PORT
DB_DATABASE
DB_USERNAME
DB_PASSWORD 
```

これら値が誤っていると、Laravel がデータベースに接続できず`Connection refused`エラーとなる場合があります。
原因はこれ以外の場合もあると思いますが、初動としてはまずここを疑ってみてください。
privateメソッドを呼び出す

>「クラス外から呼び出せず、クラスの内部でのみ使えるメソッド」だと言えます
p246

https://gihyo.jp/book/2017/978-4-7741-9397-7

## 2.7からself付きでもprivateメソッドを呼び出せる

>レシーバをselfとしてprivateメソッドを呼び出すことが許容されるようになりました。 
>```rb
>def foo
>end
>private :foo
>self.foo
>```

https://www.ruby-lang.org/ja/news/2019/12/25/ruby-2-7-0-released/#:~:text=%E3%83%AC%E3%82%B7%E3%83%BC%E3%83%90%E3%82%92self,self.foo

```rb
irb(main):001* class User
irb(main):002*   private
irb(main):003*   def hello
irb(main):004*     "Hello"
irb(main):005*   end
irb(main):006> end
=> :hello
irb(main):007> user = User.new
=> #<User:0x000000011317fcf0>
irb(main):008> user.hello
(irb):8:in `<main>': private method `hello' called for #***********(NoMethodError)
```
```rb
irb(main):001* class User
irb(main):002*   def hello
irb(main):003*     "hello, I am #{name}."
irb(main):004*   end
irb(main):005*
irb(main):006*   private
irb(main):007*
irb(main):008*   def name
irb(main):009*     "Alice"
irb(main):010*   end
irb(main):011> end
=> :name
irb(main):012> user = User.new
=> #<User:0x0000000104feed40>
irb(main):013> user.hello
=> "hello, I am Alice."
```
self有無関係なくprivateメソッドを呼び出せる
Pega初心者がPega Fest 2024 Tokyoに参加してきました！

## はじめに
11/12に東京で開催されたPega Fest 2024 Tokyoに参加してきたので、レポートを書きます！
Pegaの案件に配属されてからおよそ３ヶ月ほどたち、初めてのイベント参加でした。

## 出てくる内容・出てこない内容
出てくる内容
- Festの内容
- Pega初心者の感想

出てこない内容
- 技術的な詳しい内容

## レポート
会場は、JR新橋駅から徒歩５分程度にあるグランベルスクエアという場所で開催されました。
会場に入ってすぐの受付で、名刺を渡し名札をもらいました。
![IMG_0094.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815234/5d99fa57-1c7b-67a8-d6d0-d40af177cd4d.jpeg)

会場はたくさんの人で賑わっていました。むしろ人が多すぎて、ブースを回りきれないほどでした...
![IMG_0096.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815234/89d98044-162c-e627-7f9c-8ebe55ae64ac.jpeg)

ブースでお話を聞いている様子です。このフェストでは生成AIを使った様々な機能が紹介されていました。画像はBlueprintのブースで、人が手作業で一から作成するケースライフサイクルなどを、構築したいものを入力することでテンプレートを生成してくれるというものでした。
![IMG_0106.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815234/a77f1856-725e-1f53-8c94-adbb4275be94.jpeg)

セミナーもあり、Pegaの最高製品責任者ケリム・アゴナルさんによるBlueprintの講演を見ました。逐次通訳していただけるため、英語がさっぱりな私でも聞くことができました。
![IMG_0099.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815234/dca8fb90-ad6d-95ff-a1ea-aadcf0e6a557.jpeg)

画像では伝わりにくいかもしれませんが、相撲のトーナメントをBlueprintで作成するデモなどもあり、会場では大ウケでした。
![IMG_0101.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815234/7dc180d0-b35e-d111-3c51-09a86cc7f263.jpeg)

その後は、ミスミグループさんによる実際のBlueprint活用事例を聞きました。
日本では活用事例がまだ少ないようで、会場の参加者は興味津々でお話を聞いていました。
![IMG_0102.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815234/43cec4f3-1808-dce3-6114-3579680f8ed2.jpeg)

Blueprintは、Pega Academyのチャレンジでしか触ったことがなかったので、理解が深まるいい体験となりました。

会場から帰る際には、ノベルティもいただきました！
![IMG_0107.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815234/16f3f7ee-c64b-1c64-eecd-b135732ce62d.jpeg)


フェストは、飲み物や食べ物もあり、その他にもクイズラリー、抽選会もありお楽しみ要素がたくさんありました。

ブースを回る以外にも、Pega社の方や、複数の企業さんと交流する機会がありました。名刺交換を研修以来ほぼ初めて行なったので、とてもぎこちないものとなってしまいました。どんな環境でもスムーズに名刺交換される皆さんはとてもすごいと感じました。

## おわりに
Pegaを知ったのが、Pegaの案件に配属されてからだったので、Pegaがこんなにも盛り上がっていると知ることができてよかったです。外部発信などで、私も盛り上げていけたらと思います。
初めてのPegaのイベントでしたが、とてもいい経験になりました！ただ、Pegaの経験がまだ浅く、業務にどういかせそうというレベルまでまだ行けていないので、次にイベントに参加する際は、そのレベルまでいけるよう業務と勉強を頑張りたいと思います！
第14回TOPPERS活用アイデア・アプリケーション開発コンテスト 活用アイデア部門 への「箱庭時間管理手法に関する先行研究調査と改良」の提案

第14回TOPPERS活用アイデア・アプリケーション開発コンテスト 活用アイデア部門 へ「箱庭時間管理手法に関する先行研究調査と改良」という表題で応募しまして，銅賞を受賞しました．本記事では，既に公開されている応募内容について改めて共有し，ふりかえりたいと思います．

## 応募内容

### 部門

活用アイデア部門

### 作品のタイトル

箱庭時間管理手法に関する先行研究調査と改良

### 作成者

山崎進

### 共同作業者

山崎進研究室

### 作品の対象者

* 箱庭WG
* 箱庭ラボ

### 使用する開発成果物

箱庭

### 目的・狙い

箱庭では，並行して動作する個々のシミュレータが独立して時間管理しているのを同期することが求められる．
箱庭の時間管理方式は，先行研究としてFMIを挙げた上で，並列化容易な分散制御方式を提案しているが，理論的背景が不足しているとのことである．
そこで，先行研究を徹底調査し，現行方式の妥当性と改良を検討する．

### アイデア／アプリケーションの概要

現時点で我々が着目している先行研究の体系は次の3つである．

1. 1980年代ごろに盛んに研究された，因果律を保持するような並行かつ論理的な時間管理手法
2. メモリ一貫性モデル
3. 分散データベース

これらについて徹底的に先行研究を調査し，現行方式の妥当性を検証し，必要であれば改良を提案する．

### 背景: 箱庭アーキテクチャの現状

箱庭アーキテクチャは次の4系統の機能を有する．

* アセット管理
* 同期・通信
* スケジューリング
* 時間管理

アーキテクチャとしては次のような構成をしている．

* サーバーサイド
    * 機能
        * 箱庭アセットの登録
        * 各シミュレーションの開始・停止・初期化
    * 構成
        * 箱庭コンダクタサーバー
        * 箱庭アセット
        * 箱庭API
        * PDU
        * 箱庭コア機能
* クライアントサイド
    * 機能
        * 箱庭アセットとしてサーバーに接続
    * 構成
        * 箱庭コンダクタクライアント
        * 箱庭アセット

ネットワークの構成として次の4類型ある．

1. サーバーサイドの箱庭コンダクタを中心としてアセットと時間の管理を行い，他の類型のコンピュータに時間を配分する役割を担う．時間周期の異なるコンピュータへはプロキシを介して時間を配信する．
2. クライアントサイドの箱庭コンダクタを中心としてアセットの管理を行い，時間については1と同期する．
3. 1と異なる時間周期で動作するサーバーサイドの箱庭コンダクタによるアセットと時間の管理．1に備わるプロキシを介して接続する．
4. 箱庭アセットのみを備え，1に管理を委ねる．

箱庭では様々なシミュレータが混在しており，それぞれ固有のシミュレーション時間を持つので，シミュレーション時間の同期を取る必要がある．

箱庭が先行事例として踏まえているのは，Functional Mock-up Interface (FMI) である．FMIでは，中央制御方式によって，完全に時間同期が可能であり，かつシミュレータ間でユーザが設定する一定量の遅延時間を許容する．FMIでは，中央制御方式なので，精度調整は容易であるが，システム構成要素が増えると処理オーバーヘッドが大きくなる問題点を有する．

そこで箱庭では，分散制御方式を取り入れ，各シミュレータは箱庭時間を見ながら，シミュレーション時間を調整し時間同期するという方式を取る．箱庭時間より早い場合は，シミュレーション時間を遅くし，箱庭時間より遅い場合は，シミュレーション時間を早くすることで調整する．各シミュレーション時間を可視化して，時間同期の程度を定量化し，環境スペックの妥当性を評価・調整する．

箱庭ラボの森氏によると，箱庭の現行方式について，理論的な背景があるわけではないので，経験的な範囲での妥当性確認に留まっているとのことである．また，時間同期が性能ボトルネックになる可能性が否めない．

そこで本提案では，体系的な先行研究調査を実施し，妥当性確認と，必要であれば改良を図ることを目的とする．

### 手掛かりとなる既存体系

我々が現時点で先行研究調査の手がかりとして把握しているのは次の3つである．

1. 1980年代ごろに盛んに研究された，因果律を保持するような並行かつ論理的な時間管理手法
2. メモリ一貫性モデル
3. 分散データベース

1については，提案者が大学院時代に並列プログラミングに関する授業で学んだ，1980年代ごろの平行プログラミング言語で検討されていた時間管理方式である．提案者の記憶では，本手法の考え方としては，次のとおりである．まず，あるプロセスAの中で因果関係があるようなプログラムの断片があったとする．それぞれのプログラムの断片で，別のプロセスBへの通信が発生していたとしたときに，プロセスBからは，プロセスAの中の因果関係の順番を保った状態で，メッセージを観測することになる．一方，あるプロセスAの中で因果関係のないようなプログラムの断片から，同じようにプロセスBへそれぞれ通信が発生していた場合，プロセスBで観測される順番は特に保証されない．本手法では，この考え方に沿って，束(ラティス)となるような論理的な時間を定義する．

2については，プロセッサを並列化・分散化する過程で，メモリを読み書きするときにどこまでの順序関係の厳密さを求めるかというようなモデルであり，TOPPERSカーネルをはじめとしたRTOSではお馴染みの考え方である．

3については，データベースの基本的な考え方であるコミットとロールバックをいかなる順番で行ってもデータ一貫性を保つように，分散環境で保障するような研究がなされている．

本提案では，これらの手がかりを踏まえて，並行時間管理に関する先行研究での議論を徹底的に調査する．その先行研究調査の内容は箱庭WGにレポートとして報告していき，ディスカッションを踏まえて，箱庭の現行時間管理方式の妥当性について検討し，潜在的な技術的課題を特定することで，箱庭のあるべき並行時間管理を模索する．
初めての登壇！a-blog cms Training Camp 2024でのエピソード・感じたこと

# a-blog cms Training Camp 2024に参加しました！
名古屋に本社がある、CMSの会社、アップルップル:apple:さんが主催する、恒例イベントです。
▼会場の様子。たくさんの人が、a-blog cmsの勉強をしようと集まっている！
私がお話しした方だと、北海道、新潟、富山、大阪、広島...などなど、**全国からa-blog cmsユーザーさんが集結していました**！

https://x.com/kazumich/status/1857282067228496142


▼当日の流れ
ほかのスピーカーの方の感想も載せたいですが、後日にします！！

https://ablogcms.doorkeeper.jp/events/174995




▼自分の発表のようす
緊張したな〜。けど、できる限り頑張りました！

https://x.com/kazumich/status/1857290341826826620

## 登壇の経緯
登壇を募集されていたので、「**経験が浅いですが、やってみたいです！**」と勉強会の際に相談をしましたところ、ありがたいことに登壇させていただけることになりました！

今回、人生で登壇が初ということもあり、右も左も分からなかったですが:sweat:、アップルップル山本さん、データファーム勝又さん、弊社の鈴木さんをはじめ、色々な方にサポートいただきました。
あたらめて、**発表に関して関わっていただいた方に感謝**です。
ありがとうございました:bow:

## 出てよかったこと
### 1.いろんな方と知り合えた！
いつも、名刺交換を自分からするタイミングが難しく（いつ行けばいいんだ？？となって、うろうろして挙動不審になってしまうことも・・・:sweat_smile:）、渡したくても渡しそびれてしまうこともしばしばあるのですが、今回は色んな方と名刺交換できました！
話しかけてくださった方、ありがとうございました。うれしかったです:sparkles:
アンケートにて、**アップデートの際はスライドを参考にしたい**、や、**移行の際はルーコに相談するかも**・・・というような声もいただき、やってよかった〜となりました。

### 2.色んな事をアウトプットできた
「人前で何かを話す」ので、適当なことは話せません。
今までやってきたことの振り返りをすることで、**新しい側面から、今回の発表内容を考える**ことができました。


## うれしかったこと
「**分かりやすい**」を心がけてスライド作成と話す内容を用意したつもりだったので、「分かりやすい」と声をかけていただけたり、アンケートなども嬉しかったです。

## 難しかったこと、反省点
### 1.スピーカーの先輩方、やっぱり凄い
やっぱり、登壇に慣れている他のスピーカーの方の「**ライブ感**」が流石でした。
リアルでの対面なので、**自分も聴講者の方も一緒に楽しみたいな**って思います:raised_hands:。
ですが今回、自分は1人で突っ走ってしまった（会場の様子見る余裕があまり無かった）ところもあり、もう少し、会場とコミュニケーションを取りたかったです。
スピーカーが堅いと、聞いている方も構えちゃいますもんね:sweat:

また、スライド作成はCanvaで行いましたが、発表者ツールとしてパワポを使用しました。
ですが、本番時、パワポの発表者ツールでマウスのポインターが表示できず、ちょっと焦りました！なんとかなったのでよかったですが、本番は何が起きるか分からないものですね:dizzy_face:

### 2.技術的なことを話せるようになりたい
今回、「体験談」として、発表を行いました。
a-blog cms歴がまだ2年（人よりスタートが遅い）ということなので、常に自分の技術力不足を痛感しています！

今回の発表では、「**今の自分で話せる限りのこと**」を詰め込みました。
体験談をお話しできてよかったと思いますが、今後は少しずつ、先輩スピーカーの方のような、具体的な「**役立つこと:point_up:**」を発信できる人になりたいな〜と思いました（いつになるやら、分かりませんが）。

## Tipsについて
Webサイト移行作業に伴うアップデート作業の**Tipsについては、来月アドベントカレンダーに載せたい**と思っています！:sparkles:
NestJSでFastifyを使用した画像アップロードの実装方法

NestJSで画像アップロードの処理をしようとしたところ、ほとんどがExpressを使用している記事で、Fastifyを使っているものが皆無だったので、Fastifyでどのように画像アップロードを行うのかをまとめておきます。

公式ドキュメントにもExpressの方法しか載っていませんでした。

[Documentation | NestJS - A progressive Node.js framework](https://docs.nestjs.com/techniques/file-upload)

---

## 前提条件

フロントからは画像ファイルとそれに紐づくIDやユーザーの情報を`FormData`として送信している前提です。

```javascript
// 例
const formData = new FormData();
formData.append('image', selectedFile);
formData.append('entityId', entityId);
formData.append('entityName', entityName);
```


---

## 必要なライブラリをインストール

使用するのは、`fastify-multipart`というライブラリです。

- [fastify/fastify-multipart](https://github.com/fastify/fastify-multipart)

以下のコマンドでインストールしておきます。

```bash
yarn add fastify-multipart
```

---

## `main.ts`で`fastify-multipart`を登録

```typescript
import { fastifyMultipart } from '@fastify/multipart';

async function bootstrap() {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(),
  );
  const configService = app.get(ConfigService);
  await app.register(fastifyMultipart);
  // その他の設定...
}
```

これで`fastify-multipart`が使えるようになります。

---

## Serviceに実装する

アップロード関数で引数として`req: FastifyRequest`を受け取ります。

```typescript
const parts = req.parts();
```

これを実行することで、`FormData`を取り出します。`parts`は非同期のイテラブルなオブジェクトになっているので、`for await`を使って取り出していきます。

```typescript
for await (const part of parts) {
  if (part.fieldname === 'entityId' && part.type === 'field') {
    entityId = part.value;
  } else if (part.fieldname === 'entityName' && part.type === 'field') {
    entityName = part.value;
  } else if (part.fieldname === 'image' && part.type === 'file') {
    fileBuffer = await part.toBuffer(); // ここはお好きな処理を
  }
}
```

- `fieldname`属性はフロントで設定したものです。
- `type`が`file`の場合、ファイルを取得できます。

上記では取り出したファイルを`Buffer`型に変換していますが、これをS3にアップロードしてパスだけをDBに保存するなど、さまざまな対応が可能です。

これでNestJSで画像をアップロードすることができます。
rubyの公開レベル public

>クラスメソッドはクラスの外部からでも自由に呼び出せるメソッドです。initializeメソッド以外のインスタンスメソッドはデフォルトでpublicメソッドになります。
```rb
irb(main):001* class User
irb(main):002*   def hello
irb(main):003*     'hello'
irb(main):004*   end
irb(main):005> end
=> :hello
irb(main):006> user = User.new
=> #<User:0x000000010be60030>
irb(main):007> user.hello
=> "hello"
```
https://gihyo.jp/book/2017/978-4-7741-9397-7

### railsで確かめてみる
```rb
> User.initialize
:1:in `<main>': private method `initialize called for User:Class (NoMethodError)
garden(dev)> User.all
  User Load 
....
> User.adafa
:3:in `<main>': undefined method `adafa' for User:Class (NoMethodError)
```
* initializeメソッドはprivate methodメソッドだ
* 意味不明なメソッドを書いてみるとundefined methodと出る

# 感想
確かめてみてよかった。
Google CloudをNew Relicにリンクする

# はじめに

どうも、@to-fmakです。最近、New Relicを使用してGoogle Cloudの一部サービスのメトリクスを収集しました。今回は、Google CloudをNew Relicにリンクする手順を簡単にご紹介します。

※New RelicとGoogle Cloudのコンソール画面のキャプチャは、すべて執筆時点（2024/11）のものです。

# Intergrations & Agents

画面左側のメニューから「Integrations & Agents」をクリックし、「Google Cloud Platform」を選択します。

![Screenshot 2024-11-14 at 9.07.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/581fb0dd-cc5d-3758-e812-4537758fad01.png)

「instrumentation method」で「Service account」を選択します。

![Screenshot 2024-11-14 at 9.07.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/6af20191-648e-58da-a760-4d4d5c8d9fe6.png)

# IAMの設定

New Relicの画面で、New Relicが提供するサービスアカウントをGoogle Cloudの対象プロジェクトに追加するよう指示があります（画像の③を参照）。まず、Google CloudのIAMコンソールを開き、対象プロジェクトを選択します。

![Screenshot 2024-11-14 at 9.07.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/7ec2f5e4-cbbb-2efb-0590-f6c65aefb04c.png)

Google CloudのIAMコンソールを開き、対象プロジェクトを選択します。

![Screenshot 2024-11-14 at 16.21.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/ba4f896d-c53b-d75d-823a-b88b6045ff49.png)

「GRANT ACCESS」をクリックします。

![Screenshot 2024-11-14 at 16.21.35 copy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/ef5a72f5-d703-2e8f-624d-abfe91a1e59a.png)

「New principals」欄にNew Relicが提供するサービスアカウント（New Relicの画面の③）を入力します。
Roleは基本対象サービスの閲覧者権限を指定します。今回は「Viewer」を選択します。

![Screenshot 2024-11-14 at 16.25.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/68d1daf7-c3c1-5ba8-c1ac-7cfa259b6bce.png)

# Google Cloudをリンクする

New Relicの画面に戻って、「Fetch data」をクリックして、「Continue」をクリックします。

![Screenshot 2024-11-14 at 16.05.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/0d21f4d9-0149-7e73-c1bc-617eba9e9b17.png)

対象プロジェクトが表示されるので、選択して、「Link projects」をクリックします。

![Screenshot 2024-11-14 at 9.11.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/084dbb47-2d31-8efa-1b58-61b948a23925.png)

対象GCPサービスを選択します。設定は後から変更も可能です。

![Screenshot 2024-11-14 at 9.12.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/0d88703c-aa41-f062-81f8-501b5c0bb7ea.png)

これでリンクが完了しました。

![Screenshot 2024-11-14 at 9.12.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/5ae8f34b-ec6c-d95b-c2dc-f7e4c66081d5.png)

# メトリクスを確認する

画面左側のメニューから「All Capabilities」をクリックし、「Google Cloud Platform」をクリックします。

![Screenshot 2024-11-14 at 16.07.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/8a4e317b-b5de-7dc8-cbdb-73e73ec5ff76.png)

追加したGCPサービスが表示され、各サービスのメトリクス確認、ダッシュボードの作成、サービスの追加・削除、プロジェクトのリンク解除などが可能です。

![Screenshot 2024-11-14 at 15.55.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/347ea02f-b21f-d788-834c-88cf92855adc.png)

# 参考URL

https://docs.newrelic.com/jp/docs/infrastructure/google-cloud-platform-integrations/get-started/connect-google-cloud-platform-services-new-relic/

## エンジニア募集

Gakken LEAP では教育をアップデートしていきたいエンジニアを絶賛大募集しています！！
ぜひお気軽にカジュアル面談へお越しください！！

https://gakken-leap.co.jp/recruit/
[Tableau Desktop Specialist ] 合格体験記

# はじめに
Tableau Advent Calendar 2024　7日目です。

今回は、久しぶりに資格を取ってきたので、合格体験記を書いていきたいと思います。

#  Tableau Desktop Specialist

### Tableau とは

1. **直感的な操作**：ドラッグ＆ドロップで簡単にデータをビジュアル化できます。専門知識がなくても使いやすい設計です。
2. **多彩なグラフやチャート**：複雑なデータを多様なビジュアル形式で表示でき、データの洞察を得やすくします。
3. **柔軟なダッシュボード**：異なる指標を一つの画面にまとめ、リアルタイムで更新することが可能です。
4. **データの共有**：作成したダッシュボードやレポートをWeb上で他のユーザーと共有できます。

Tableauは、ビッグデータを含む社内データを収集・分析し、データドリブンな意思決定を支援するための強力なツールです。

**Tableauの一歩目のような資格です。**

結果は、944/1000 

結構余裕で合格できました。
Tableauを触ったのは１か月ほどで、勉強時間は３０時間－４０時間くらいだと思われます。


![image0.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3296700/794fc4c7-2923-1cba-9988-3749b7a6d939.jpeg)

# 勉強方法

以下の問題集の４セクションを９０％合格まで回す。
正直、問題集の正解の選択肢を覚えるだけでも合格すると思います。

https://www.udemy.com/course/tableau-desktop-specialist-2023/?couponCode=24T2MT111824

動画であれば以下です。

https://www.udemy.com/course/tableau-desktop-specialist-j/?couponCode=24T2MT111824

Tableauの問題集は書籍として存在していない？ため、おそらくこの２つで勉強するのが良いと思います。

また、以下のサイトでTableau の練習ができるので、より理解を深められます。

https://www.tableau.com/ja-jp/community/public

## さいごに
初めて、合格体験記を記載しましたが、あまり、参考にならないかもしれません。
正直、過去問と同じような問題が出ていた気がしたので、あんまり工夫がありません。
取りたいと思ってる人は頑張ってください。
メソッドのオーバーライド、クラスメソッドの継承

### メソッドのオーバーライド
>スーパークラスと同名のメソッドを定義することで、スーパークラスの処理を上書きすることが
出来ます。これをメソッドのオーバーライドといいます。

https://gihyo.jp/book/2017/978-4-7741-9397-7

```rb
irb(main):001* class Product
irb(main):002*   attr_reader :name, :price
irb(main):003*
irb(main):004*   def initialize(name, price)
irb(main):005*     @name = name
irb(main):006*     @price = price
irb(main):007*   end
irb(main):008> end
=> :initialize
irb(main):009* class DVD < Product
irb(main):010*   attr_reader :running_time
irb(main):011*
irb(main):012*   def initialize(name, price, running_time)
irb(main):013*     super(name, price)
irb(main):014*     @running_time = running_time
irb(main):015*   end
irb(main):016> end
=> :initialize
irb(main):017> priduct = Product.new("A great movie", 1000)
=> #<Product:0x000000010e357758 @name="A great movie", @price=1000>
irb(main):018> priduct.to_s
=> "#<Product:0x000000010e357758>"
irb(main):019> dvd = DVD.new("An awesome film", 3000, 120)
=> #<DVD:0x000000010e46ea38 @name="An awesome film", @price=3000, @running_time=120>
irb(main):020> dvd.to_s
=> "#<DVD:0x000000010e46ea38>"
```

```rb
irb(main):021* class Product
irb(main):022*   attr_reader :name, :price
irb(main):023*
irb(main):024*   def initialize(name, price)
irb(main):025*     @name = name
irb(main):026*     @price = price
irb(main):027*   end
irb(main):028*
irb(main):029*   def to_s
irb(main):030*     "name: #{name}, price: #{price}"
irb(main):031*   end
irb(main):032> end
=> :to_s
irb(main):033> dvd = DVD.new("An awesome film", 3000, 120)
=> #<DVD:0x000000010e4868e0 @name="An awesome film", @price=3000, @running_time=120>
irb(main):034> dvd.to_s
=> "name: An awesome film, price: 3000"
```
### クラスメソッドの継承
>クラスを継承すると、クラスメソッドも継承されます。

```rb
irb(main):035* class Foo
irb(main):036*   def self.hello
irb(main):037*     'hello'
irb(main):038*   end
irb(main):039> end
=> :hello

irb(main):041* class Bar < Foo
irb(main):042> end
=> nil
irb(main):043> Bar.hello
=> "hello"
irb(main):045> Foo.hello
=> "hello"
```

## Railsのgithubを見てみる
### メソッドのオーバーライド
```rb
 class UserProvidedDefault < FromUser # :nodoc:
      def initialize(name, value, type, database_default)
        @user_provided_value = value
        super(name, value, type, database_default)
      end
      ...
```
https://github.com/rails/rails/blob/dd8f7185faeca6ee968a6e9367f6d8601a83b8db/activemodel/lib/active_model/attribute/user_provided_default.rb#L11C5-L15C10

FromUserクラスのサブクラスUserProvidedDefaultクラスが継承してる
`super(name, value, type, database_default)`
多分value, type, database_defaultのいずれかがこのクラスで追加されているのだろう。

### クラスメソッドの継承
```rb
      def with_type(type)
        self.class.new(name, user_provided_value, type, original_attribute)
      end
```
https://github.com/rails/rails/blob/dd8f7185faeca6ee968a6e9367f6d8601a83b8db/activemodel/lib/active_model/attribute/user_provided_default.rb#L25C7-L27C10

見つけることはできなかったがこのクラスを継承するとこのメソッドを使える
Tornado SSL(https)で起動させる

# はじめに
MH ソフトウェア & サービスが開発・公開している、Webアプリケーションサーバ AiRの便利かな?と思われるコードの紹介です。
Webアプリケーションサーバ AiRはPython、Tornado(Webフレームワーク、Webサーバ)、JavaScript、その他のモジュールで構成されています。
***
TornadoはSSL(https)で起動できます。
[Let's Encrypt](https://letsencrypt.org/)の例では、RAS秘密鍵が private.key に、fullchain.pem が certificate.crt になります。
private.keyとcertificate.crtをデータフォルダに作成します。
***
SSL(https)用のファイルが存在するか確認し、存在すればTrueとSSLContextを返します。
```python
def _check_ssl() -> tuple[bool, Union[ssl.SSLContext, None]]:
    """SSL Check.

    :sig: () -> tuple(bool, ssl.SSLContext)
    """
    crt_files = glob.glob("./*.crt")
    key_files = glob.glob("./*.key")
    ssl_ctx: Union[ssl.SSLContext, None] = None

    result = False
    if (len(crt_files) > 0) & (len(key_files) > 0):
        ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
        # NOTE: If ssl_ctx.load_cert_chain ahs error, crt or key is wrong format.
        try:
            ssl_ctx.load_cert_chain(crt_files[0], key_files[0])
            result = True
        except ssl.SSLError:
            print("crt or key file is wrong format.\n")
            result = False
    return (result, ssl_ctx)
```

その戻り値を使って、_http_serverからtornado.httpserver.HTTPServerとportを取得して、http_serverを起動します。
```
    ssl_enabled, ssl_ctx = _check_ssl()

    hat = Hat(system_name, __version__, tornado.options.options)
    http_server, port = _http_server(ssl_enabled, hat, ssl_ctx)

    try:
        http_server.listen(port)
    except OSError:
        _alert_message()
        http_server.listen(81)
```
hatは特別なクラスです。

```
def _http_server(
    ssl_enabled: bool, hat_: Hat, ssl_ctx: Union[ssl.SSLContext, None],
) -> tuple[tornado.httpserver.HTTPServer, int]:
    """Retrun http sever.

    # pylint: disable=line-too-long
    :sig: (bool, Hat, Union[ssl.SSLContext, None]) -> tuple[tornado.httpserver.HTTPServer, int]
    """
    result: tornado.httpserver.HTTPServer
    if ssl_enabled:
        result = tornado.httpserver.HTTPServer(
            Application(hat_),
            ssl_options=ssl_ctx,
        )
        # これはhttpsサーバのポート番号です
        port = 443
    else:
        result = tornado.httpserver.HTTPServer(
            Application(hat_),
            decompress_request=True,
        )
        # これはhttpサーバのポート番号です
        port = 80
    return (result, port)
```

***
[Webアプリケーションサーバ AiR](https://qiita.com/MH-SS/items/7a99e799e4988fdad2cc)
***
[弊社webページ: AiR](https://mhss.server-on.net/?f401c=Index&ae504=air)
ABC380備忘録

## はじめに
2か月ぶり人生2回目のABC(Atcoder Beginner Contest)に参加したので、その備忘録を書きます。ABCの3完(52分)でした。

とりあえず茶色を目指します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3929797/35efec59-3f54-2faf-6a42-4f56314d25ee.png)

参考になる綺麗なコードではありませんが、ABC毎週参加へのモチベーションのために投稿しよう
と思った次第です。

## 環境
- C++20(gcc 12.2)
- Visual Studio Code

## 生成AIの使用について
直前でルールが変わったため、github Copilotによるコード補完のみ使用しました。

https://info.atcoder.jp/entry/llm-rules-ja

## A - 123233
### 問題
6桁の整数について、条件を満たしているかを判定しYes/Noで出力

条件 : 各桁に1が1つ、2が2つ、3が3つ含まれているか

###  解答
- 入力値の各桁に0~9の数値がそれぞれいくつ含まれるかのcount配列を作る
- /10で進み、%10で抽出
```c++:A
int main() {
    int N;
    vector<int> count(11);
    cin >> N;
    int t;

    for(int i=0;i<6;i++){
        t=N%10;
        count[t]+=1;
        N/=10;
    }
    if(count[1]==1 && count[2]==2 && count[3]==3){
        cout << "Yes" << endl;
    }else{
        cout << "No" << endl;
    }
}

```

## B - Hurdle Parsing
### 問題
`|--|-|---|`の様な入力に対し、各`|`の間に`-`が何個存在するかを数え、数列で出力する。
### 解答
一つ目の`-`から走査し、`|`が見つかったらインクリメントされていた値をans配列に格納する。
```c++:B
int main() {
    string S;
    cin >> S;
    vector<int> ans;
    int i=1;
    while(i<S.size()){
        int n=0;
        while(S[i]!='|'){
            n++;
            i++;
        }
        ans.push_back(n);
        i++;
    }
    for(int i=0;i<ans.size();i++){
        cout << ans[i] << " ";
    }
}
```

## C - MoveSegment
### 問題
0と1で構成された文字列に対して、K番目の1の塊をK-1番目の1の塊にくっつける
### 解答
i番目の塊は0の塊で、n個あります。というような配列を作る。
➡作った配列から、K番目の1の塊に対応するインデックスを強引に求め、swapで交換。

絶対にもっと単純にできた気がする

```c++:C
int main() {
    int N,K;
    string S;
    cin >> N >> K;
    cin >> S;
    vector<int> ans_count;
    vector<int> ans_bool;
    int i=0;
    while(i<N){
        int n=0;
        while(S[i]==S[i+1]){
            n++;
            i++;
        }
        ans_count.push_back(n+1);
        if(S[i]=='0'){
            ans_bool.push_back(0);
        }else{
            ans_bool.push_back(1);
        }
        i++;
    }
    
    vector<int> temp(2);
    swap(ans_count[2*K-2-ans_bool[0]],ans_count[2*K-1-ans_bool[0]]);
    swap(ans_bool[2*K-2-ans_bool[0]],ans_bool[2*K-1-ans_bool[0]]);
    string ans;
    for(int i=0;i<ans_count.size();i++){
        for(int j=0;j<ans_count[i];j++){
            if(ans_bool[i]==0){
                ans.push_back('0');
            }else{
                ans.push_back('1');
            }
        }
    }
    cout << ans << endl;
}
```
## D - Strange Mirroring
### 問題
与えられた文字列について、大文字小文字を反転させたものを末尾に追加するという操作を繰り返した時のK番目の文字列
### 解答
K番目の文字の種類を    `S[K % S.size() - 1]`で特定するところまではいったものの、大文字小文字の判定が出来ずに断念。

`((K - 1)  / S.size() + 1) % 4`の答えが1 or 4ならそのまま、2 or 3だったら反転という謎の式を導くがAC × 4、WA × 59と惨敗


## まとめ
とりあえずの目標はD完を安定させることですね。競プロ鉄則が半分で止まっているので勉強しなおさなきゃなと思いました。
エンジニアで英語が初めて役に立った話

# はじめに
Advent Calendar 2024　3日目の記事です。
わりかし、この話題に触れてこなかったので、このイベントで消化させていただきたいと思います。

# 英語は必要？
就職活動をされる際にTOEICなどの英語資格を取得された方、結構多く感じます。
実務で英語を使用する経験があるかというと、結論私はあまりありませんでした。
また、英語で記載されている技術の記事は、
今やほとんど生成AIに投げてしまえば、簡単に読むことができるでしょう。
しかし、求人や社内の資格支援制度では、英語を求められることがあります。
では、英語が生きる機会はあるのでしょうか。

# エンジニアで英語が初めて役に立った話
最近、実務で様々な海外SaaS製品についてのシェア率や製品についての調査タスクがとても多いです。
その中で、英語が初めて役に立ちました。
それは以下のような二つの機会です。


# SaaS製品に携わる機会
近年DX化が進められており、
SaaS(Software as a Service)の導入が増えてきています。

・海外のSaaSカンパニーとパートナー契約
・製品情報の不具合の問い合わせ
・日本語対応が遅れている製品
・海外のSaaS展示会
・SaaS製品のログインページ

SaaS事業では、様々なセクションで英語を使用します。
会議では英語が使用されることもあり、英語の一定のレベルがないと会議にすら参加できない可能性があります。

# 海外ベンダーの製品の学習要素が日本が対応していない

例
**Salesforce社**
**BIツール:Tableau**
・試験対策として必要な問題集や対策講座がほぼ英語で作成されている。
・Tableau serverやTableau prepなどのニッチな領域になると、
  もはや日本語での講座を見つけるのが困難

# 英語があれば活躍できる場面が生える
英語ができると認識されると、英語の案件にアサインされる可能性が高くなります。
もちろん、今は生成ＡＩで簡単に翻訳することができるので、その必要性というのは少し薄くなってきたようにも感じます。
しかし、動画の視聴などで字幕が出ない場合やニッチな領域で日本語対応していない場合には英語力というのは必要にも思えます。
話はめちゃくちゃ変わりますが、**英語アレルギー**や**数学アレルギー**など、エンジニアの中でも皆さん苦手な分野はあると思います。
自分の強さが一番出る分野を組み合わせて、エンジニアライフをおくってまいりましょう。
UnityFPSスクリプト歩行モーション込み

```c#
using UnityEngine;

public class fps : MonoBehaviour
{
    public float moveSpeed = 10f;
    public float lookSpeed = 2f;
    public float jumpForce = 5f;
    public float rotationDamping = 0.95f;
    public Transform playerCamera;
    public Camera firstPersonCamera;
    public Camera thirdPersonCamera;
    public Animator animator;
    private Rigidbody rb;
    private float xRotation = 0f;
    private bool isFirstPerson = true;


    void Start()
    {
        rb = GetComponent<Rigidbody>();
        rb.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationZ;
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;

        // 初期状態で一人称視点カメラを有効にする
        firstPersonCamera.enabled = true;
        thirdPersonCamera.enabled = false;
        animator = GetComponent<Animator>();
    }

    void FixedUpdate()
    {
        MovePlayer();
        DampenRotation();
    }

    void Update()
    {
        LookAround();
        Jump();
        SwitchCamera();
    }

    void MovePlayer()
    {
        float moveHorizontal = Input.GetAxis("Horizontal");
        float moveVertical = Input.GetAxis("Vertical");

        Vector3 movement = transform.right * moveHorizontal + transform.forward * moveVertical;
        Vector3 force = movement * moveSpeed;

        rb.AddForce(new Vector3(force.x, 0, force.z));
        if (movement != Vector3.zero) {
            animator.SetBool("isWalking", true);
            Debug.Log("running");
        }
        else{
            Debug.Log("stop");
            animator.SetBool("isWalking", false);
        }
    }

    void LookAround()
    {
        float mouseX = Input.GetAxis("Mouse X") * lookSpeed;
        float mouseY = Input.GetAxis("Mouse Y") * lookSpeed;

        xRotation -= mouseY;
        xRotation = Mathf.Clamp(xRotation, -90f, 90f);

        playerCamera.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
        transform.Rotate(Vector3.up * mouseX);
    }

    void DampenRotation()
    {
        Vector3 angularVelocity = rb.angularVelocity;
        angularVelocity.x *= rotationDamping;
        angularVelocity.z *= rotationDamping;
        rb.angularVelocity = angularVelocity;
    }

    void Jump()
    {
        if (Input.GetButtonDown("Jump"))
        {
            rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
            animator.SetBool("isJump", true);
        }
        else
        {
            animator.SetBool("isJump", false);
        }
    }

    void SwitchCamera()
    {
        // カメラを切り替える
        if (Input.GetKeyDown(KeyCode.C))
        {
            isFirstPerson = !isFirstPerson;
            firstPersonCamera.enabled = isFirstPerson;
            thirdPersonCamera.enabled = !isFirstPerson;

            // プレイヤーのカメラを設定する
            playerCamera = isFirstPerson ? firstPersonCamera.transform : thirdPersonCamera.transform;
        }
    }
}

```
イベントログをpowershellで取得（備忘録）

```
#取得コマンド
$filter = @{LogName="Security";Id=XXXX;StartTime="$startDate";EndTime="$endDate"}
Get-WinEvent -FilterHashtable $filter
```
# イベントビューア取得について
取得方法は（おそらく）２通り。
１、本文から取得し、欲しいデータはSubStringで取得。
２、XML形式のものを取得。

XML形式で取得することもできたが、一部の情報が文字化けのような状態になっていたため
やむなく、イベントログ本文から強引に取得する方向にかじを切った。

本文には行にタイトル情報があるため、それを利用してインデックスを取得し
アカウント名やオブジェクト名、アクセスなどの欲しい情報をSubstringで取得する。
（※保守性が皆無）

powershellをタスクスケジューラに設定して、定期的にCSV形式に出力することが可能！


以上です。
APIセキュリティのベストプラクティス

これまでサイドプロジェクトで遊び感覚でAPIを作り、公開して終わりにしていましたが、実際に数千人や数万人に使われるシステムとなると、それでは非常に危険で問題があると感じました。

この1年間でお客様案件に携わる中で、API周りの設計や実装に触れる機会が多かったため、APIセキュリティについて、自分の経験や感触、さらにネットで調べた知識を整理してまとめたいと思います。

# 1. 認証と認可
### 認証 (Authentication):
・OAuth 2.0やOpenID Connectなどの業界標準プロトコルを使用。

・短期トークンを利用し、長期的なアクセストークンの有効期限を避ける。

・APIキーやトークンをセキュアな方法で保管し、HTTPSでの送信を徹底。

### 認可 (Authorization):
・ロールベースアクセス制御 (RBAC) や属性ベースアクセス制御 (ABAC) を採用。

・ユーザーごとの権限を明確に定義し、必要最小限のアクセス権を付与。

# 2. 通信の暗号化
・API通信はすべてHTTPSを使用し、TLS（Transport Layer Security）で暗号化。

・古い暗号化アルゴリズム（例: SSL/TLS 1.0）を無効化し、TLS 1.2以上を使用。

・証明書の定期更新を自動化。

# 3. 入力データの検証
・APIで受け取るすべてのデータを検証。

・型、長さ、フォーマット（例: 電話番号、メールアドレスなど）を厳密にチェック。

・未検証のデータを直接データベースや内部サービスに渡さない。

・SQLインジェクションやクロスサイトスクリプティング (XSS) 攻撃を防ぐため、特殊文字のエスケープやプリペアードステートメントを使用。

# 4. エラーハンドリング
・エラーメッセージに詳細な情報を含めない。
　例: スタックトレースや内部構造の情報は含めない。

・ユーザーには標準的なエラーコード（例: HTTP 400、403、500など）と適切なメッセージを返す。

# 5. APIレートリミット
・1ユーザーまたは1 IPアドレスごとにリクエストの上限を設定。
　例: 1分あたりのリクエスト数を制限。

・レートリミットを設定することで、サービス妨害攻撃（DoS/DDoS）を緩和。

# 6. 監視とログ記録
・すべてのAPIリクエストとレスポンスをログに記録。

・ログには機密情報を含めない（例: パスワード、トークン）。

・APIへのアクセス状況を監視し、不正アクセスや異常なトラフィックを検知。

・ログはAWS CloudWatch LogsやELKスタックなどを利用して管理。

# 7. バージョン管理
・APIにバージョンを付与し、明確に管理（例: /v1/resource）。

・古いバージョンのAPIは段階的に廃止し、通知を行う。

# 8. セキュリティテスト
・OWASP API Security Top 10に基づき、APIを定期的にセキュリティ診断。

・ペネトレーションテストを実施し、脆弱性を発見して修正。

# 9. CORS（クロスオリジンリソース共有）設定
・必要なオリジン（ドメイン）だけにアクセスを許可。

・Access-Control-Allow-Origin ヘッダーを厳密に設定。

# 10. 秘密情報の管理
・APIキーやトークンは環境変数やAWS Secrets Managerで安全に管理。

・ソースコードに秘密情報をハードコードしない。

・トークンの使い捨て（例: ワンタイムトークン）を活用。

# 参考サイト
https://www.redhat.com/en/topics/security/api-security

https://www.akamai.com/glossary/what-is-api-security
【CI/CD】package-lock.jsonが無いためにnpm ciが失敗した時の解消方法

# 事象

CI/CDを設定しているNext.jsのプロジェクトにおいて
開発用ブランチをmainブランチにマージした際に、「npm ci」に失敗

```
npm error `npm ci` can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync. Please update your lock file with `npm install` before continuing.

# `npm ci` は、package.json と package-lock.json または npm-shrinkwrap.json が同期されている場合にのみパッケージをインストールできます。続行する前に、`npm install` を使用してロック ファイルを更新してください。
```

# 原因
package-lock.jsonが存在しないため

# 解消方法

下記コマンドを実行してpackage-lock.jsonを再作成 & コミットプッシュ

```
npm i --package-lock-only
```


# 参考
https://stackoverflow.com/questions/46653833/is-there-a-way-to-force-npm-to-generate-package-lock-json
cscの作法 その535

# 概要
cscの作法、調べてみた。
練習問題やってみた。

# 練習問題
wpfを1ファイルで書け。

# 方針
- xamlを使わない。
- WebBrowser使う。

# サンプルコード

```

using System;
using System.Windows;
using System.Windows.Controls;

namespace Wpf
{
	public partial class MainWindow: Window {
		WebBrowser wb;
		public MainWindow() {
			wb = new WebBrowser();
			wb.Navigate("https://qiita.com");
			Title = "test";
			Width = 600;
			Height = 600;
			Content = wb;
		}
	}
	class MainApp {
		[STAThread]
		public static void Main() {
			MainWindow mwnd = new MainWindow();
			Application app = new Application();
			app.Run(mwnd);
		}
	}
}




```

# 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/f39193a1-dc64-0de6-1209-a28efec0ea6f.png)


以上。
Tornado 初期化時のオプション

# はじめに
MH ソフトウェア & サービスが開発・公開している、Webアプリケーションサーバ AiRの便利かな?と思われるコードの紹介です。
Webアプリケーションサーバ AiRはPython、Tornado(Webフレームワーク、Webサーバ)、JavaScript、その他のモジュールで構成されています。
***
Tornadoを初期化する時、settingsに設定する値で、高速化・セキュリティの向上が望めます。
```
def __init__(self, hat: Hat):
    """Initialize.

    :sig: (Hat) -> None
    """
    handlers: tornado.routing._RuleList = self._handlers  # type: ignore
    settings: dict[str, Any] = self._settings　　# この値 propertyで呼び出されます
    tornado.web.Application.__init__(
        self,
        handlers,
        default_handler_class=Base,
        **settings,  # ここの値 propertyで呼び出された値です
    )
```

```
@property
def _settings(self) -> dict[str, Any]:
    """Retrun settings.

    :sig: () -> dict[str, Any]
    """
    return {
        "compress_response": True,
        """
        レスポンスを自動的に圧縮するかどうかの設定
        有効にすると、テキスト形式のレスポンスがgzip圧縮されます
        """

        "cookie_secret": tornado.options.options.cookie_secret,
        """
        署名付きクッキーを使用するための秘密鍵 クッキーの内容が改ざんされていない事を保証出来ます
        """

        "login_url": "/",
        "static_handler_class": StaticFileHandler,
        "static_path": os.path.join(os.path.dirname(__file__), "."),
        "template_path": os.path.join(os.path.dirname(__file__), "."),
        "xsrf_cookies": True,
        """
        クロスサイトリクエストフォージェリ(XSRFまたはCSRF)攻撃を防ぐための機能
        これを有効にすると、各リクエストに対してXSRFトークンを検証し、トークンが一致しない場合はリクエストを拒否します
        """
    }
```
***
[Webアプリケーションサーバ AiR](https://qiita.com/MH-SS/items/7a99e799e4988fdad2cc)
***
[弊社webページ: AiR](https://mhss.server-on.net/?f401c=Index&ae504=air)
Webアプリケーションサーバ AiR

# はじめに ![air.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569469/0404a167-69a3-df22-ee0a-211cc63f3466.gif)
MH ソフトウェア & サービスが開発・公開している、WebアプリケーションサーバのAiRの紹介です。  
AiRとは、チャット・時計/カレンダ・スケジュール・トピックス・キャビネット・タスクの構成で自由に使用できるWebアプリケーションサーバです。  
弊社では、「エーアイアール」と呼んでいますが、「エア」でも良いと思います。
内部で育てているAiras(アイラス)の名前にちなんで、AiRと命名されました。
* 2024/11/18 ver1.3.7 言語分析停止中です

AiRはPython、Tornado(Webフレームワーク、Webサーバ)、JavaScript、その他のモジュールで構成されています。  
特に使って欲しい方が、個人事業主で少数の従業員・アルバイトを雇っている方々です。
それなりに機能があって、MITライセンスです。経費を気にする必要がありません。  
Raspberry Piで動作出来ていますので、2~3万円の費用で使用可能です。  

# フレームワーク Tornado
開発初期に、色々とPythonのWebフレームワークを試しました。[Tornado](https://www.tornadoweb.org/)を選択した理由は次の2点です。

1. Webサーバ機能がある
2. Web検索で「高速な動作」の記事が多い

Tornadoを使用する事で、AiR単独でWebアプリケーションサーバとして動作できるのです。  

## 便利かな?のコード集
MH ソフトウェア & サービスが開発・公開している、Webアプリケーションサーバ AiRの便利かな?と思われるコードの紹介です。
## Tornado
* [初期化時のオプション](https://qiita.com/MH-SS/items/e9415efa594c72995581)
* [SSL(https)で起動させる](https://qiita.com/MH-SS/items/8ee788f1b5d735c7a2eb)
* [便利なioloop](https://qiita.com/MH-SS/items/c4e40094b8ce66b3cae4)

# Python
* [Python 暗号化・復号化](https://qiita.com/MH-SS/items/4dc9eea5209b51990ce1)
JavaScriptと同じ暗号化・復号化が可能

# JavaScript
* [JavaScript 暗号化・復号化](https://qiita.com/MH-SS/items/183306ec5c005f3ba1c5)
Pythonと同じ暗号化・復号化が可能

# Visual Studio Code 拡張機能
* [VS VCode - Run on Save](https://qiita.com/MH-SS/items/0d92682adf5014c1a862)
* [VS Code - .d.tsファイル(型定義ファイル)の効用](https://qiita.com/MH-SS/items/e71ed24ca5283756494d)

***
[弊社webページ: AiR](https://mhss.server-on.net/?f401c=Index&ae504=air)
SynologyNASでLet'sEncryptの証明書を使用する

## SynologyのNASでLet's Encryptの証明書を導入した記録
### 証明書のインストール
これはネット上の情報を元にすんなりと進んだ
[コントロールパネル] -> [セキュリティ] -> [証明書]->[追加]をクリック
[新しい証明書を追加]を選択し、[次へ]
![スクリーンショット 2024-11-19 14.36.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45016/caaa9ce7-3ae9-fe18-663d-205492bb6033.png)
[Let's Encryptから証明書を取得する]を選択し、[次へ]
![スクリーンショット 2024-11-19 14.36.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45016/9dc2543b-6ba8-d7a5-b52c-d066d8bd54a1.png)
ドメイン名：Synology DDNSホスト名またはexample.comなどの運用で使用しているドメインを入力する。
![スクリーンショット 2024-11-19 14.37.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45016/fcac434f-2dce-60d0-604b-e16076f159e5.png)
完了をクリックすると証明書の取得が始まる。
カーソルが実行中のマークになって少し待っていると、証明書の取得が終了する。（Let's Encryptから取得は、一瞬では終わらないので慌てずに待とう！）
### 証明書の適用
証明書をLet's Encryptから取得すると、コントロールパネル→セキュリティ→証明書に証明書が追加されている。
「既定値としての証明書」にレを入れればLet's Encryptの証明書が使われるものと考えていたが、
![cretifcate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45016/370929d0-10f0-cfa1-2c3d-5a5ad3cea360.png)

ブラウザ（Chrome）でhttpsでアクセスすると、
「このサイトへの接続は保護されていません」「証明書が無効です」
となってしまった。


対策として、Let's Encryptの証明書を選択して、設定→構成でシステムデフォルトの証明書を「synology」からLet's Encryptから取得した「ドメインの証明書」に変更する。
![SynologyCertificateSetting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45016/62af04cc-93cb-7855-c3da-1a70c05c1770.png)


※ 証明書の取得手順はすんなりできましたが、後日追記します
ilasmでstack machine その48

# 概要
ilasmでstack machineやってみた。
練習問題やってみた。

# 練習問題
ilasmでWindows.Formsを使え。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/fbed0b47-6e8c-5c16-4e9d-852639a27b37.png)

# サンプルコード

```

.assembly extern System.Windows.Forms {
	.publickeytoken = (B7 7A 5C 56 19 34 E0 89)
	.ver 4:0:0:0
}
.assembly extern mscorlib {
	.publickeytoken = (B7 7A 5C 56 19 34 E0 89)
	.ver 4:0:0:0
}
.assembly extern System.Drawing {
	.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A)
	.ver 4:0:0:0
}
.assembly Hello {
	.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = (01 00 08 00 00 00 00 00)
	.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = (01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )
	.hash algorithm 0x00008004
	.ver 0:0:0:0
}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0002
.corflags 0x00000001
.class private auto ansi beforefieldinit HelloForm extends [System.Windows.Forms]System.Windows.Forms.Form {
	.method public hidebysig specialname rtspecialname instance void .ctor() cil managed {
		.maxstack	4
		.locals init (class [System.Windows.Forms]System.Windows.Forms.Label V_0)
		ldarg.0
		call	instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor()
		ldarg.0
		ldc.i4	0x190
		ldc.i4	0x190
		newobj	instance void [System.Drawing]System.Drawing.Size::.ctor(int32, int32)
		call	instance void [System.Windows.Forms]System.Windows.Forms.Form::set_Size(valuetype [System.Drawing]System.Drawing.Size)
		ldarg.0
		ldstr	"Hello, World!"
		callvirt	instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Text(string)
		newobj	instance void [System.Windows.Forms]System.Windows.Forms.Label::.ctor()
		stloc.0
		ldloc.0
		ldc.i4	0x140
		ldc.i4.s	20
		newobj	instance void [System.Drawing]System.Drawing.Size::.ctor(int32, int32)
		callvirt	instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Size(valuetype [System.Drawing]System.Drawing.Size)
		ldloc.0
		ldstr	"Hello, Windows Forms(MSIL) World!"
		callvirt	instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Text(string)
		ldarg.0
		call	instance class [System.Windows.Forms]System.Windows.Forms.Control/ControlCollection [System.Windows.Forms]System.Windows.Forms.Control::get_Controls()
		ldloc.0
		callvirt	instance void [System.Windows.Forms]System.Windows.Forms.Control/ControlCollection::Add(class [System.Windows.Forms]System.Windows.Forms.Control)
		ret
	}
	.method private hidebysig static void Main() cil managed {
		.entrypoint
		.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = (01 00 00 00)
		.maxstack	1
		.locals init (class HelloForm V_0)
		newobj	instance void HelloForm::.ctor()
		stloc.0
		ldloc.0
		call	void [System.Windows.Forms]System.Windows.Forms.Application::Run(class [System.Windows.Forms]System.Windows.Forms.Form)
		ret
	}
}





```

以上。
郵便番号辞書をAPIでアクセスできるようにする

## FastAPIで郵便番号辞書をAPI化
日本郵便から提供されているデータを加工したものを実際に利用できるようにするためにFastAPIを使ってAPI化してみました。とはいえ経験は皆無なのでwebでの情報をもとに見よう見まねです。

### 環境の準備
まずはFastAPIとそれを実行するためのuvicornをインストールします。
```
$ pip install uvicorn pydantic fastapi
```
### API用のスクリプト
作成したFastAPI対応部分を載せておきます。当初はoriginsやapp.add-middleware()の部分は記述していなかったのですが、next.jsのコードからAPIアクセスでエラーが発生していました。全然理由がわからなかったのですが、microsoft edgeの開発者モードでの Copilot からのサジェスチョンに従って追加したところ見事に動作しました。
現状ではnext.jsもこのAPIも同じWSL2のubuntu上で動かしています。originsは実際の環境に合わせて変更が必要になると思います。


```python:postapi.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import postdb

app = FastAPI()

origins = [
    "http://localhost",
    "http://localhost:3000",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.get("/postdb/{pcode}")
async def read_pcode(pcode:str):
    #print(pcode)
    connection = postdb.init()
    result = postdb.search(connection, pcode)
    postdb.close(connection)
    #print(result)
    return result
```
 postdb.init()、postdb.close()はDBとのコネクション、コネクション解除を行っています。postdb.search()は指定された郵便番号に紐づく住所情報を検索しています。

 ### APIの起動
 ```
 $ uvicorn postapi:app --reload --host 0.0.0.0
 ```